From 52eded4a9ce612a978ae15d5b606784bcf671c69 Mon Sep 17 00:00:00 2001 From: Alexander Zuev Date: Wed, 9 Oct 2024 20:31:02 +0000 Subject: [PATCH 001/118] 8341170: Open source several Choice related tests (part 2) Reviewed-by: honkar --- .../awt/Choice/ChoiceDragEventsInside.java | 210 ++++++++++++++++++ .../java/awt/Choice/ChoiceMouseEventTest.java | 123 ++++++++++ .../jdk/java/awt/Choice/ChoiceRemoveTest.java | 111 +++++++++ .../awt/Choice/PopupMenuOnChoiceArea.java | 106 +++++++++ .../java/awt/Choice/ScrollbarFlickers.java | 85 +++++++ 5 files changed, 635 insertions(+) create mode 100644 test/jdk/java/awt/Choice/ChoiceDragEventsInside.java create mode 100644 test/jdk/java/awt/Choice/ChoiceMouseEventTest.java create mode 100644 test/jdk/java/awt/Choice/ChoiceRemoveTest.java create mode 100644 test/jdk/java/awt/Choice/PopupMenuOnChoiceArea.java create mode 100644 test/jdk/java/awt/Choice/ScrollbarFlickers.java diff --git a/test/jdk/java/awt/Choice/ChoiceDragEventsInside.java b/test/jdk/java/awt/Choice/ChoiceDragEventsInside.java new file mode 100644 index 0000000000000..dde773f19289c --- /dev/null +++ b/test/jdk/java/awt/Choice/ChoiceDragEventsInside.java @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * 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 6251983 6722236 + * @summary MouseDragged events not triggered for Choice when dragging it with left mouse button + * @key headful + * @run main ChoiceDragEventsInside + */ + +import java.awt.Choice; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionAdapter; +import java.lang.reflect.InvocationTargetException; + +public class ChoiceDragEventsInside extends Frame { + Robot robot; + Choice choice1; + Point pt; + Dimension size; + volatile boolean mouseDragged = false; + volatile boolean mouseDraggedOutside = false; + + public void setupUI() { + setTitle("Choce Drag Events Inside"); + choice1 = new Choice(); + for (int i = 1; i < 50; i++) { + choice1.add("item-0" + i); + } + choice1.setForeground(Color.red); + choice1.setBackground(Color.red); + choice1.addMouseMotionListener(new MouseMotionAdapter() { + public void mouseMoved(MouseEvent me) { + System.out.println(me); + } + + public void mouseDragged(MouseEvent me) { + System.out.println(me); + mouseDragged = true; + if (me.getY() < 0) { + mouseDraggedOutside = true; + } + } + } + ); + add(choice1); + setLayout(new FlowLayout()); + setSize(200, 200); + setLocationRelativeTo(null); + setVisible(true); + validate(); + } + + public void start() { + try { + robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.setAutoDelay(50); + robot.delay(100); + EventQueue.invokeAndWait(() -> { + pt = choice1.getLocationOnScreen(); + size = choice1.getSize(); + }); + testDragInsideChoice(InputEvent.BUTTON1_MASK); + testDragInsideChoiceList(InputEvent.BUTTON1_MASK); + testDragOutsideChoice(InputEvent.BUTTON1_MASK); + } catch (Throwable e) { + throw new RuntimeException("Test failed. Exception thrown: " + e); + } + } + + public void testDragInsideChoice(int button) { + robot.mouseMove(pt.x + size.width / 2, pt.y + size.height / 2); + robot.delay(100); + robot.mousePress(button); + robot.mouseRelease(button); + robot.delay(200); + robot.mousePress(button); + robot.mouseRelease(button); + robot.delay(200); + + //close opened choice + robot.keyPress(KeyEvent.VK_ESCAPE); + robot.keyRelease(KeyEvent.VK_ESCAPE); + robot.delay(200); + + robot.mouseMove(pt.x + size.width / 4, pt.y + size.height / 2); + robot.mousePress(button); + + dragMouse(pt.x + size.width / 4, pt.y + size.height / 2, + pt.x + size.width * 3 / 4, pt.y + size.height / 2); + robot.mouseRelease(button); + robot.delay(200); + if (!mouseDragged) { + throw new RuntimeException("Test failed. Choice should generate MouseDragged events inside Choice itself"); + } else { + System.out.println("Stage 1 passed. Choice generates MouseDragged events inside Choice itself"); + } + mouseDragged = false; + //close opened choice + robot.keyPress(KeyEvent.VK_ESCAPE); + robot.keyRelease(KeyEvent.VK_ESCAPE); + robot.delay(200); + } + + public void testDragInsideChoiceList(int button) { + robot.mouseMove(pt.x + size.width / 2, pt.y + size.height / 2); + robot.delay(100); + robot.mousePress(button); + robot.mouseRelease(button); + robot.delay(200); + + robot.mouseMove(pt.x + size.width / 2, pt.y + 5 * size.height); + robot.delay(200); + robot.mousePress(button); + + dragMouse(pt.x + size.width / 2, pt.y + 5 * size.height, + pt.x + size.width / 2, pt.y + 8 * size.height); + robot.mouseRelease(button); + robot.delay(200); + if (mouseDragged) { + throw new RuntimeException("Test failed. Choice shouldn't generate MouseDragged events inside Choice's list"); + } else { + System.out.println("Stage 2 passed. Choice doesn't generate MouseDragged events inside Choice's list"); + } + robot.keyPress(KeyEvent.VK_ESCAPE); + robot.keyRelease(KeyEvent.VK_ESCAPE); + robot.delay(200); + mouseDragged = false; + } + + public void testDragOutsideChoice(int button) { + pt = choice1.getLocationOnScreen(); + robot.mouseMove(pt.x + size.width / 2, pt.y + size.height / 2); + robot.delay(100); + + robot.mousePress(button); + //drag mouse outside of Choice + dragMouse(pt.x + size.width / 2, pt.y + size.height / 2, + pt.x + size.width / 2, pt.y - 3 * size.height); + robot.mouseRelease(button); + robot.delay(200); + if (!mouseDragged || !mouseDraggedOutside) { + throw new RuntimeException("Test failed. Choice should generate MouseDragged events outside Choice"); + } else { + System.out.println("Stage 3 passed. Choice generates MouseDragged events outside Choice"); + } + robot.keyPress(KeyEvent.VK_ESCAPE); + robot.keyRelease(KeyEvent.VK_ESCAPE); + robot.delay(200); + mouseDragged = false; + } + + public void dragMouse(int x0, int y0, int x1, int y1) { + int curX = x0; + int curY = y0; + int dx = x0 < x1 ? 1 : -1; + int dy = y0 < y1 ? 1 : -1; + + while (curX != x1) { + curX += dx; + robot.mouseMove(curX, curY); + } + while (curY != y1) { + curY += dy; + robot.mouseMove(curX, curY); + } + } + + public static void main(final String[] args) throws InterruptedException, + InvocationTargetException { + ChoiceDragEventsInside app = new ChoiceDragEventsInside(); + try { + EventQueue.invokeAndWait(app::setupUI); + app.start(); + } finally { + EventQueue.invokeAndWait(app::dispose); + } + } +} diff --git a/test/jdk/java/awt/Choice/ChoiceMouseEventTest.java b/test/jdk/java/awt/Choice/ChoiceMouseEventTest.java new file mode 100644 index 0000000000000..9603d5c763de4 --- /dev/null +++ b/test/jdk/java/awt/Choice/ChoiceMouseEventTest.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * 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 4319246 + * @summary Tests that MouseReleased, MouseClicked and MouseDragged are triggered on choice + * @key headful + * @run main ChoiceMouseEventTest + */ + +import java.awt.AWTException; +import java.awt.BorderLayout; +import java.awt.Choice; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.lang.reflect.InvocationTargetException; + + +public class ChoiceMouseEventTest extends Frame { + static volatile boolean mousePressed = false; + static volatile boolean mouseReleased = false; + static volatile boolean mouseClicked = false; + Choice choice = new Choice(); + static Point location; + static Dimension size; + + public void setupGUI() { + setTitle("Choice Mouse Event Test"); + this.setLayout(new BorderLayout()); + choice.add("item-1"); + choice.add("item-2"); + choice.add("item-3"); + choice.add("item-4"); + add("Center", choice); + choice.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + mouseClicked = true; + } + + @Override + public void mousePressed(MouseEvent e) { + mousePressed = true; + } + + @Override + public void mouseReleased(MouseEvent e) { + mouseReleased = true; + } + }); + setLocationRelativeTo(null); + setSize(400, 200); + setVisible(true); + } + + public Point _location() { + return choice.getLocationOnScreen(); + } + + public Dimension _size() { + return choice.getSize(); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException { + ChoiceMouseEventTest test = new ChoiceMouseEventTest(); + try { + EventQueue.invokeAndWait(test::setupGUI); + Robot robot = new Robot(); + robot.setAutoDelay(50); + robot.delay(1000); + robot.waitForIdle(); + EventQueue.invokeAndWait(() -> { + location = test._location(); + size = test._size(); + }); + robot.waitForIdle(); + robot.mouseMove(location.x + size.width - 10, location.y + (size.height / 2)); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(2000); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(2000); + robot.waitForIdle(); + if (!mouseClicked || !mousePressed || !mouseReleased) { + throw new RuntimeException(String.format("One of the events not arrived: " + + "mouseClicked = %b, mousePressed = %b, mouseReleased = %b", + mouseClicked, mousePressed, mouseReleased)); + } + } finally { + if (test != null) { + EventQueue.invokeAndWait(test::dispose); + } + } + } +} + diff --git a/test/jdk/java/awt/Choice/ChoiceRemoveTest.java b/test/jdk/java/awt/Choice/ChoiceRemoveTest.java new file mode 100644 index 0000000000000..6de66db936276 --- /dev/null +++ b/test/jdk/java/awt/Choice/ChoiceRemoveTest.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * 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 4079027 + * @summary Removing an item dynamically from a Choice object breaks lower items. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ChoiceRemoveTest + */ + +import java.awt.Choice; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Label; +import java.awt.Panel; +import java.awt.event.ItemEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.lang.reflect.InvocationTargetException; + +public class ChoiceRemoveTest extends Frame { + Choice selector; + static final String INSTRUCTIONS = """ + After window 'Choice Remove Test' appears wait for three seconds + and then click on the choice. In popup there should be no + 'Choice A' variant. Try selecting each variant with mouse + and verify by the log that the correct variant gets selected. + If after selecting item in the list the correct item gets selected + and correct item name appears in the log press Pass otherwise press Fail. + """; + + public static void main(String[] argv) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Test Instructions") + .testUI(ChoiceRemoveTest::new) + .instructions(INSTRUCTIONS) + .columns(40) + .logArea() + .build() + .awaitAndCheck(); + } + + public ChoiceRemoveTest() { + super("Choice Remove Test"); + Panel p; + Label prompt; + + addWindowListener(new WindowAdapter() { + @Override + public void windowOpened(WindowEvent e) { + super.windowOpened(e); + new Thread(() -> { + try { + Thread.sleep(2000); + } catch (InterruptedException ignore) { + } + removeFirst(); + }).start(); + } + }); + + setLayout(new GridLayout()); + p = new Panel(); + + prompt = new Label("Select different items including the last one"); + p.add(prompt); + + selector = new Choice(); + selector.add("Choice A"); + selector.add("Choice B"); + selector.add("Choice C"); + selector.add("Choice D"); + selector.add("Choice E"); + selector.addItemListener(e -> { + if (e.getStateChange() == ItemEvent.SELECTED) { + Object selected = e.getItem(); + PassFailJFrame.log(selected.toString()); + } + }); + p.add(selector); + add(p); + pack(); + } + + public void removeFirst() { + selector.remove("Choice A"); + } +} diff --git a/test/jdk/java/awt/Choice/PopupMenuOnChoiceArea.java b/test/jdk/java/awt/Choice/PopupMenuOnChoiceArea.java new file mode 100644 index 0000000000000..2a56d7281ee44 --- /dev/null +++ b/test/jdk/java/awt/Choice/PopupMenuOnChoiceArea.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * 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 6240046 + * @summary REG:Choice's Drop-down does not disappear when clicking somewhere, after popup menu is disposed-XTkt + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual PopupMenuOnChoiceArea + */ + + +import java.awt.CheckboxMenuItem; +import java.awt.Choice; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.PopupMenu; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.lang.reflect.InvocationTargetException; + +public class PopupMenuOnChoiceArea extends Frame { + static final String INSTRUCTIONS = """ + You would see a window named 'Popup menu on choice area' + with Choice in it. Move the mouse pointer to the choice. + Click right mouse button on it. + You should see a popup menu with 'File' in it. + Close this popup menu by pressing Esc. + Click the left mouse button on the Choice. + You should see a Choice drop-down menu. + Move mouse pointer into drop-down menu. + Click right mouse button on any item in it. + If you see a 'File' popup menu press Fail. + If Choice drop-down closes instead press Pass. + """; + + public PopupMenuOnChoiceArea() { + super("Popup menu on choice area"); + this.setLayout(new FlowLayout()); + Choice choice = new Choice(); + choice.add("item-1"); + choice.add("item-2"); + choice.add("item-3"); + choice.add("item-4"); + add("Center", choice); + Menu fileMenu = new Menu("File"); + Menu open = new Menu("Open"); + Menu save = new Menu("save"); + CheckboxMenuItem exit = new CheckboxMenuItem("Exit"); + fileMenu.add(open); + fileMenu.add(save); + fileMenu.add(exit); + final PopupMenu pop = new PopupMenu(); + pop.setLabel("This is a popup menu"); + pop.setName("a menu"); + pop.add(fileMenu); + choice.add(pop); + choice.addMouseListener(new MouseAdapter() { + public void mousePressed(MouseEvent me) { + if (me.isPopupTrigger()) { + pop.show(me.getComponent(), me.getX(), me.getY()); + } + } + + public void mouseReleased(MouseEvent me) { + if (me.isPopupTrigger()) { + pop.show(me.getComponent(), me.getX(), me.getY()); + } + } + }); + setSize(200, 200); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Test Instructions") + .testUI(PopupMenuOnChoiceArea::new) + .instructions(INSTRUCTIONS) + .columns(40) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/Choice/ScrollbarFlickers.java b/test/jdk/java/awt/Choice/ScrollbarFlickers.java new file mode 100644 index 0000000000000..c35d4900134fa --- /dev/null +++ b/test/jdk/java/awt/Choice/ScrollbarFlickers.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * 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 6405707 + * @summary Choice popup & scrollbar gets Flickering when mouse is pressed & drag on the scrollbar + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ScrollbarFlickers + */ + +import java.awt.BorderLayout; +import java.awt.Choice; +import java.awt.Frame; +import java.lang.reflect.InvocationTargetException; + +public class ScrollbarFlickers extends Frame { + static final String INSTRUCTIONS = """ + Open the choice popup. Select any item in it and + drag it with the mouse above or below the choice. + Keep the choice opened. + Continue dragging the mouse outside of the choice + making content of the popup scroll. + If you see that scrollbar flickers press Fail. + Otherwise press Pass. + """; + + public ScrollbarFlickers() { + super("Scrollbar Flickering Test"); + Choice ch = new Choice(); + setLayout(new BorderLayout()); + ch.add("Praveen"); + ch.add("Mohan"); + ch.add("Rakesh"); + ch.add("Menon"); + ch.add("Girish"); + ch.add("Ramachandran"); + ch.add("Elancheran"); + ch.add("Subramanian"); + ch.add("Raju"); + ch.add("Pallath"); + ch.add("Mayank"); + ch.add("Joshi"); + ch.add("Sundar"); + ch.add("Srinivas"); + ch.add("Mandalika"); + ch.add("Suresh"); + ch.add("Chandar"); + add(ch); + setSize(200, 200); + validate(); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Test Instructions") + .testUI(ScrollbarFlickers::new) + .instructions(INSTRUCTIONS) + .columns(40) + .build() + .awaitAndCheck(); + } +} From 49c7148d3770c1ba2cd291f7b55ad471577ee151 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Wed, 9 Oct 2024 21:45:47 +0000 Subject: [PATCH 002/118] 8341366: Suspicious check in Locale.getDisplayName(Locale inLocale) Reviewed-by: naoto --- src/java.base/share/classes/java/util/Locale.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/java.base/share/classes/java/util/Locale.java b/src/java.base/share/classes/java/util/Locale.java index 73132b81c09a6..5550d399a7fbd 100644 --- a/src/java.base/share/classes/java/util/Locale.java +++ b/src/java.base/share/classes/java/util/Locale.java @@ -2324,12 +2324,11 @@ public String getDisplayName(Locale inLocale) { // If we cannot get the message format pattern, then we use a simple // hard-coded pattern. This should not occur in practice unless the // installation is missing some core files (FormatData etc.). - StringBuilder result = new StringBuilder(); - result.append((String)displayNames[1]); - if (displayNames.length > 2) { - result.append(" ("); - result.append((String)displayNames[2]); - result.append(')'); + StringBuilder result = new StringBuilder((String) displayNames[1]); + if (displayNames[2] != null) { + result.append(" (") + .append((String) displayNames[2]) + .append(')'); } return result.toString(); } From e7045e9399c5bca0592afc5769432414ecae7219 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Wed, 9 Oct 2024 21:46:50 +0000 Subject: [PATCH 003/118] 8341684: Typo in External Specifications link of java.util.Currency Reviewed-by: liach, naoto, srl --- src/java.base/share/classes/java/util/Currency.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/util/Currency.java b/src/java.base/share/classes/java/util/Currency.java index 14d1cf4351d97..b11b774e6142a 100644 --- a/src/java.base/share/classes/java/util/Currency.java +++ b/src/java.base/share/classes/java/util/Currency.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -108,7 +108,7 @@ * with {@code Currency} or monetary values as it provides better handling of floating * point numbers and their operations. * - * @spec http://www.iso.org/iso/home/standards/currency_codes.htm ISO - ISO 4217 - Currency codes + * @spec https://www.iso.org/iso-4217-currency-codes.html ISO - ISO 4217 - Currency codes * @see java.math.BigDecimal * @since 1.4 */ From 172f74466fe59ece816764112dba98e4604706b7 Mon Sep 17 00:00:00 2001 From: Alexander Zuev Date: Wed, 9 Oct 2024 22:10:32 +0000 Subject: [PATCH 004/118] 8340985: Open source some Desktop related tests Reviewed-by: abhiscxk --- .../java/awt/Desktop/ActionSupportTest.java | 201 ++++++++++++++++++ test/jdk/java/awt/Desktop/BrowseTest.java | 90 ++++++++ .../java/awt/Desktop/DesktopSupportTest.java | 59 +++++ test/jdk/java/awt/Desktop/MailTest.java | 116 ++++++++++ test/jdk/java/awt/Desktop/OpenTest.java | 114 ++++++++++ 5 files changed, 580 insertions(+) create mode 100644 test/jdk/java/awt/Desktop/ActionSupportTest.java create mode 100644 test/jdk/java/awt/Desktop/BrowseTest.java create mode 100644 test/jdk/java/awt/Desktop/DesktopSupportTest.java create mode 100644 test/jdk/java/awt/Desktop/MailTest.java create mode 100644 test/jdk/java/awt/Desktop/OpenTest.java diff --git a/test/jdk/java/awt/Desktop/ActionSupportTest.java b/test/jdk/java/awt/Desktop/ActionSupportTest.java new file mode 100644 index 0000000000000..e5cdec0e42246 --- /dev/null +++ b/test/jdk/java/awt/Desktop/ActionSupportTest.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * 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 6255196 + * @key headful + * @summary Verifies the supported actions on different platforms. + * @library /test/lib + * @run main/othervm ActionSupportTest + */ + +import java.awt.Desktop; +import java.io.File; +import java.net.URI; +import javax.swing.JMenuBar; +import jtreg.SkippedException; + +import static java.awt.desktop.QuitStrategy.NORMAL_EXIT; + +public class ActionSupportTest { + + public static void main(String[] args) { + final File file = new File("nonExistentFile"); + final URI uri = URI.create("nonExistentSchema:anything"); + final StringBuilder error = new StringBuilder(); + + if (!Desktop.isDesktopSupported()) { + throw new SkippedException("Class java.awt.Desktop is not supported on " + + "current platform. Farther testing will not be performed"); + } + + Desktop desktop = Desktop.getDesktop(); + for (Desktop.Action action : Desktop.Action.values()) { + boolean supported = desktop.isSupported(action); + + try { + switch (action) { + case OPEN: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.open(file); + break; + case EDIT: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.edit(file); + break; + case PRINT: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.print(file); + break; + case MAIL: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.mail(uri); + break; + case BROWSE: + if (supported) { + continue; // prevent native message about strange schema + } + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.browse(uri); + break; + case APP_EVENT_FOREGROUND: + case APP_EVENT_HIDDEN: + case APP_EVENT_REOPENED: + case APP_EVENT_SCREEN_SLEEP: + case APP_EVENT_SYSTEM_SLEEP: + case APP_EVENT_USER_SESSION: + continue; // Has no effect if SystemEventListener's sub-type + // is unsupported on the current platform. + case APP_ABOUT: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.setAboutHandler(e -> { + }); + break; + case APP_PREFERENCES: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.setPreferencesHandler(e -> { + }); + break; + case APP_OPEN_FILE: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.setOpenFileHandler(e -> { + }); + break; + case APP_PRINT_FILE: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.setPrintFileHandler(e -> { + }); + break; + case APP_OPEN_URI: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.setOpenURIHandler(e -> { + }); + break; + case APP_QUIT_HANDLER: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.setQuitHandler((e, response) -> { + }); + break; + case APP_QUIT_STRATEGY: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.setQuitStrategy(NORMAL_EXIT); + break; + case APP_SUDDEN_TERMINATION: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.enableSuddenTermination(); + break; + case APP_REQUEST_FOREGROUND: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.requestForeground(true); + break; + case APP_HELP_VIEWER: + if (supported) { + continue; // prevent open separate window + } + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.openHelpViewer(); + break; + case APP_MENU_BAR: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.setDefaultMenuBar(new JMenuBar()); + break; + case BROWSE_FILE_DIR: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.browseFileDirectory(file); + break; + case MOVE_TO_TRASH: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.moveToTrash(file); + break; + } + // no exception has been thrown. + if (!supported) { + error.append("Action " + action.name() + " is an " + + "unsupported operation, but no exception has been thrown\n"); + } + } catch (UnsupportedOperationException uoe) { + if (!supported) { + System.out.println("Action " + action.name() + "is not supported."); + } else { + error.append("Action " + action.name() + " is a " + + "supported operation, " + + "but UnsupportedOperationException has been thrown\n"); + } + } catch (Exception e) { + if (supported) { + System.out.println("Action " + action.name() + "supported."); + } else { + error.append("Action " + action.name() + " is an " + + "unsupported operation, but " + + "UnsupportedOperationException has not been thrown\n"); + } + } + } + + if (!error.isEmpty()) { + System.err.println(error); + throw new RuntimeException("One or more tests failed. " + + "Look at the error output for details"); + } + System.out.println("Test completed"); + } +} diff --git a/test/jdk/java/awt/Desktop/BrowseTest.java b/test/jdk/java/awt/Desktop/BrowseTest.java new file mode 100644 index 0000000000000..1bdccace3fc87 --- /dev/null +++ b/test/jdk/java/awt/Desktop/BrowseTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * 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 6255196 + * @summary Verifies the function of method browse(java.net.URI uri). + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual BrowseTest + */ + +import java.awt.Desktop; +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.net.URI; +import javax.swing.JPanel; + +public class BrowseTest extends JPanel { + static final String INSTRUCTIONS = """ + This test could launch default file manager to open user's home + directory, and default web browser to show the URL of java vendor. + After test execution close the native file manager and web browser + windows if they were launched by test. + Also check output for any unexpected EXCEPTIONS, + if you see any failure messages press Fail otherwise press Pass. + """; + + public BrowseTest() { + if (!Desktop.isDesktopSupported()) { + PassFailJFrame.log("Class java.awt.Desktop is not supported on " + + "current platform. Farther testing will not be performed"); + PassFailJFrame.forcePass(); + } + + Desktop desktop = Desktop.getDesktop(); + + URI dirURI = new File(System.getProperty("user.home")).toURI(); + URI webURI = URI.create(System.getProperty("java.vendor.url", "http://www.java.com")); + boolean failed = false; + try { + PassFailJFrame.log("Try to browse " + dirURI + " ..."); + desktop.browse(dirURI); + PassFailJFrame.log("Succeed.\n"); + } catch (Exception e) { + PassFailJFrame.log("EXCEPTION: " + e.getMessage()); + } + + try { + PassFailJFrame.log("Try to browse " + webURI + " ..."); + desktop.browse(webURI); + PassFailJFrame.log("Succeed.\n"); + } catch (Exception e) { + PassFailJFrame.log("EXCEPTION: " + e.getMessage()); + } + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Browser Test") + .splitUI(BrowseTest::new) + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 1) + .columns(40) + .logArea() + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/Desktop/DesktopSupportTest.java b/test/jdk/java/awt/Desktop/DesktopSupportTest.java new file mode 100644 index 0000000000000..ec8b82ba5ef21 --- /dev/null +++ b/test/jdk/java/awt/Desktop/DesktopSupportTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * 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 6255196 + * @key headful + * @summary Verifies if class Desktop is supported on current platform. + * @run main DesktopSupportTest + */ + +import java.awt.Desktop; + +public class DesktopSupportTest { + public static void main(String[] args) { + boolean supported = Desktop.isDesktopSupported(); + try { + Desktop desktop = Desktop.getDesktop(); + if (!supported) { + throw new RuntimeException("UnsupportedOperationException " + + "should be thrown, as this class is not supported " + + "on current platform."); + } + } catch (UnsupportedOperationException uoe) { + if (supported) { + throw new RuntimeException("UnsupportedOperationException " + + "should NOT be thrown, as this class is supported " + + "on current platform."); + } + } catch (Exception e) { + if (!supported) { + throw new RuntimeException("UnsupportedOperationException " + + "should be thrown, as this class is not supported " + + "on current platform. But " + e.getClass().getName() + + " has been thrown instead."); + } + } + } +} diff --git a/test/jdk/java/awt/Desktop/MailTest.java b/test/jdk/java/awt/Desktop/MailTest.java new file mode 100644 index 0000000000000..15e5c0769a0dc --- /dev/null +++ b/test/jdk/java/awt/Desktop/MailTest.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * 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 6255196 + * @summary Verifies the function of methods mail() and mail(java.net.URI uri). + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MailTest + */ + +import java.awt.Desktop; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.net.URI; +import javax.swing.JPanel; + +public class MailTest extends JPanel { + + static final String INSTRUCTIONS = """ + This test could launch the mail client to compose mail + with and without filling the message fields. + After test execution close the mail composing windows if they + were launched by test. + If you see any unexpected EXCEPTION messages in the output + press Fail. Otherwise press Pass. + """; + + private MailTest() { + if (!Desktop.isDesktopSupported()) { + PassFailJFrame.log("Class java.awt.Desktop is not supported on " + + "current platform. Farther testing will not be performed"); + PassFailJFrame.forcePass(); + } + + Desktop desktop = Desktop.getDesktop(); + if (!desktop.isSupported(Desktop.Action.MAIL)) { + PassFailJFrame.log("Action.MAIL is not supported."); + PassFailJFrame.forcePass(); + } + + /* + * Part 1: launch the mail composing window without a mailto URI. + */ + try { + desktop.mail(); + } catch (IOException e) { + PassFailJFrame.log("EXCEPTION: " + e.getMessage()); + } + + /* + * Part 2: launch the mail composing window with a mailto URI. + */ + URI testURI = null; + try { + testURI = new URI("mailto", "foo@bar.com?subject=test subject" + + "&cc=foocc@bar.com&body=test body", null); + desktop.mail(testURI); + } catch (IOException e) { + PassFailJFrame.log("EXCEPTION: " + e.getMessage()); + } catch (java.net.URISyntaxException use) { + // Should not reach here. + PassFailJFrame.log("EXCEPTION: " + use.getMessage()); + } + + /* + * Part 3: try to launch the mail composing window with a URI with a + * scheme which is not "mailto": + * http://java.net. + * An IOException should be thrown in this case. + */ + try { + testURI = URI.create("http://java.com"); + PassFailJFrame.log("Try to mail: " + testURI); + desktop.mail(testURI); + } catch (IllegalArgumentException e) { + PassFailJFrame.log("Caught expected IllegalArgumentException"); + } catch (IOException ioe) { + PassFailJFrame.log("EXCEPTION: " + ioe.getMessage()); + } + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Mail Test") + .splitUI(MailTest::new) + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 1) + .columns(40) + .logArea() + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/Desktop/OpenTest.java b/test/jdk/java/awt/Desktop/OpenTest.java new file mode 100644 index 0000000000000..1ed29067d50e1 --- /dev/null +++ b/test/jdk/java/awt/Desktop/OpenTest.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * 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 6255196 + * @summary Verifies the function of method open(java.io.File file). + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual/othervm OpenTest + */ + +import java.awt.Desktop; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import javax.swing.JPanel; + +public class OpenTest extends JPanel { + + static final String INSTRUCTIONS = """ + This test could open the user's home directory and a .txt file. + After test execution, close the native application windows that + are used to open the directory and .txt file if they were launched + by the test. + If you see any unexpected EXCEPTION messages in the output press Fail. + Otherwise press Pass. + """; + + public OpenTest() { + if (!Desktop.isDesktopSupported()) { + PassFailJFrame.log("Class java.awt.Desktop is not supported on " + + "current platform. Further testing will not be performed"); + PassFailJFrame.forcePass(); + } + + Desktop desktop = Desktop.getDesktop(); + + /* + * Part 1: open a directory, which should launch the system default + * file explorer. + * + * On Windows platforms, the default file explorer is explorer; + * on UNIX platforms with Gnome installed and running, the default + * file explorer is Nautilus. + */ + File userHome = new File(System.getProperty("user.home")); + + try { + PassFailJFrame.log("Try to open " + userHome); + desktop.open(userHome); + PassFailJFrame.log("Succeed."); + } catch (IOException e) { + PassFailJFrame.log("EXCEPTION: " + e.getMessage()); + } + + /* + * Part 2: open a normal .txt file, which should launch the registered + * application for .txt files. + */ + // Create a temp .txt file for test. + File testFile = null; + try { + PassFailJFrame.log("Creating temporary file"); + testFile = File.createTempFile("JDIC-test", ".txt", + new File(System.getProperty("java.io.tmpdir"))); + testFile.deleteOnExit(); + } catch (java.io.IOException ioe) { + PassFailJFrame.log("EXCEPTION: " + ioe.getMessage()); + PassFailJFrame.log("Failed to create test file"); + } + + try { + PassFailJFrame.log("Try to open " + testFile); + desktop.open(testFile); + PassFailJFrame.log("Succeed."); + } catch (IOException e) { + PassFailJFrame.log("EXCEPTION: " + e.getMessage()); + } + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Mail Test") + .splitUI(OpenTest::new) + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 1) + .columns(40) + .logArea() + .build() + .awaitAndCheck(); + } +} From c850ecb20a095cb69da81f6fbe5da9c4bce66e77 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Wed, 9 Oct 2024 23:50:18 +0000 Subject: [PATCH 005/118] 8341755: Optimize argNames in InnerClassLambdaMetafactory Co-authored-by: Chen Liang Reviewed-by: liach, redestad --- .../invoke/InnerClassLambdaMetafactory.java | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java b/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java index 884f27796e7aa..10f282065fd8f 100644 --- a/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java +++ b/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java @@ -34,12 +34,10 @@ import java.lang.classfile.ClassBuilder; import java.lang.classfile.ClassFile; import java.lang.classfile.CodeBuilder; -import java.lang.classfile.FieldBuilder; import java.lang.classfile.MethodBuilder; import java.lang.classfile.Opcode; import java.lang.classfile.TypeKind; import java.lang.constant.ClassDesc; -import java.lang.constant.DynamicConstantDesc; import java.lang.constant.MethodTypeDesc; import java.lang.reflect.Modifier; import java.util.LinkedHashSet; @@ -51,16 +49,15 @@ import java.lang.classfile.attribute.ExceptionsAttribute; import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.constantpool.ConstantPoolBuilder; -import java.lang.classfile.constantpool.MethodRefEntry; + import static java.lang.constant.ConstantDescs.*; import static java.lang.invoke.MethodHandleNatives.Constants.NESTMATE_CLASS; import static java.lang.invoke.MethodHandleNatives.Constants.STRONG_LOADER_LINK; -import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE; -import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG; import static java.lang.invoke.MethodType.methodType; import jdk.internal.constant.ConstantUtils; import jdk.internal.constant.MethodTypeDescImpl; import jdk.internal.constant.ReferenceClassDescImpl; +import jdk.internal.vm.annotation.Stable; import sun.invoke.util.Wrapper; /** @@ -71,7 +68,7 @@ */ /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory { private static final String LAMBDA_INSTANCE_FIELD = "LAMBDA_INSTANCE$"; - private static final String[] EMPTY_STRING_ARRAY = new String[0]; + private static final @Stable String[] ARG_NAME_CACHE = {"arg$1", "arg$2", "arg$3", "arg$4", "arg$5", "arg$6", "arg$7", "arg$8"}; private static final ClassDesc[] EMPTY_CLASSDESC_ARRAY = ConstantUtils.EMPTY_CLASSDESC; // For dumping generated classes to disk, for debugging purposes @@ -96,7 +93,6 @@ private final MethodTypeDesc implMethodDesc; // Type descriptor for implementation methods "(I)Ljava/lang/String;" private final MethodType constructorType; // Generated class constructor type "(CC)void" private final MethodTypeDesc constructorTypeDesc;// Type descriptor for the generated class constructor type "(CC)void" - private final String[] argNames; // Generated names for the constructor arguments private final ClassDesc[] argDescs; // Type descriptors for the constructor arguments private final String lambdaClassName; // Generated name for the generated class "X$$Lambda$1" private final ConstantPoolBuilder pool = ConstantPoolBuilder.of(); @@ -174,18 +170,24 @@ public InnerClassLambdaMetafactory(MethodHandles.Lookup caller, implKind == MethodHandleInfo.REF_invokeSpecial || implKind == MethodHandleInfo.REF_invokeStatic && implClass.isHidden(); int parameterCount = factoryType.parameterCount(); + ClassDesc[] argDescs; + MethodTypeDesc constructorTypeDesc; if (parameterCount > 0) { - argNames = new String[parameterCount]; argDescs = new ClassDesc[parameterCount]; for (int i = 0; i < parameterCount; i++) { - argNames[i] = "arg$" + (i + 1); argDescs[i] = classDesc(factoryType.parameterType(i)); } + constructorTypeDesc = MethodTypeDescImpl.ofValidated(CD_void, argDescs); } else { - argNames = EMPTY_STRING_ARRAY; argDescs = EMPTY_CLASSDESC_ARRAY; + constructorTypeDesc = MTD_void; } - constructorTypeDesc = MethodTypeDescImpl.ofValidated(CD_void, argDescs); + this.argDescs = argDescs; + this.constructorTypeDesc = constructorTypeDesc; + } + + private static String argName(int i) { + return i < ARG_NAME_CACHE.length ? ARG_NAME_CACHE[i] : "arg$" + (i + 1); } private static String lambdaClassName(Class targetClass) { @@ -313,7 +315,7 @@ public void accept(ClassBuilder clb) { .withInterfaceSymbols(interfaces); // Generate final fields to be filled in by constructor for (int i = 0; i < argDescs.length; i++) { - clb.withField(argNames[i], argDescs[i], ACC_PRIVATE | ACC_FINAL); + clb.withField(argName(i), argDescs[i], ACC_PRIVATE | ACC_FINAL); } generateConstructor(clb); @@ -396,7 +398,7 @@ public void accept(CodeBuilder cob) { for (int i = 0; i < parameterCount; i++) { cob.aload(0) .loadLocal(TypeKind.from(factoryType.parameterType(i)), cob.parameterSlot(i)) - .putfield(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(argNames[i], argDescs[i]))); + .putfield(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(argName(i), argDescs[i]))); } cob.return_(); } @@ -448,7 +450,7 @@ public void accept(CodeBuilder cob) { cob.dup() .loadConstant(i) .aload(0) - .getfield(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(argNames[i], argDescs[i]))); + .getfield(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(argName(i), argDescs[i]))); TypeConvertingMethodAdapter.boxIfTypePrimitive(cob, TypeKind.from(argDescs[i])); cob.aastore(); } @@ -505,9 +507,9 @@ public void accept(CodeBuilder cob) { cob.ldc(cp.constantDynamicEntry(cp.bsmEntry(cp.methodHandleEntry(BSM_CLASS_DATA), List.of()), cp.nameAndTypeEntry(DEFAULT_NAME, CD_MethodHandle))); } - for (int i = 0; i < argNames.length; i++) { + for (int i = 0; i < argDescs.length; i++) { cob.aload(0) - .getfield(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(argNames[i], argDescs[i]))); + .getfield(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(argName(i), argDescs[i]))); } convertArgumentTypes(cob, methodType); From 475f8f94e038e10c796b5d56f939384d7b84da54 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Thu, 10 Oct 2024 00:03:08 +0000 Subject: [PATCH 006/118] 8341859: Optimize ClassFile Benchmark Write Reviewed-by: liach --- .../org/openjdk/bench/jdk/classfile/Write.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/test/micro/org/openjdk/bench/jdk/classfile/Write.java b/test/micro/org/openjdk/bench/jdk/classfile/Write.java index 5a966afaebff3..6e041cf64361e 100644 --- a/test/micro/org/openjdk/bench/jdk/classfile/Write.java +++ b/test/micro/org/openjdk/bench/jdk/classfile/Write.java @@ -62,6 +62,15 @@ "--enable-preview", "--add-exports", "java.base/jdk.internal.classfile.impl=ALL-UNNAMED"}) public class Write { + static final int REPEATS = 40; + static final String[] METHOD_NAMES; + static { + var names = new String[REPEATS]; + for (int xi = 0; xi < REPEATS; ++xi) { + names[xi] = "main" + ((xi == 0) ? "" : "" + xi); + } + METHOD_NAMES = names; + } static String checkFileAsm = "/tmp/asw/MyClass.class"; static String checkFileBc = "/tmp/byw/MyClass.class"; static boolean writeClassAsm = Files.exists(Paths.get(checkFileAsm).getParent()); @@ -90,8 +99,8 @@ public byte[] asmStream() { mv.visitEnd(); } - for (int xi = 0; xi < 40; ++xi) { - MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC+Opcodes.ACC_STATIC, "main"+ ((xi==0)? "" : ""+xi), "([Ljava/lang/String;)V", null, null); + for (int xi = 0; xi < REPEATS; ++xi) { + MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC+Opcodes.ACC_STATIC, METHOD_NAMES[xi], "([Ljava/lang/String;)V", null, null); mv.visitCode(); Label loopTop = new Label(); Label loopEnd = new Label(); @@ -146,8 +155,8 @@ public byte[] jdkTree() { .return_() ) ); - for (int xi = 0; xi < 40; ++xi) { - cb.withMethod("main" + ((xi == 0) ? "" : "" + xi), MTD_void_StringArray, + for (int xi = 0; xi < REPEATS; ++xi) { + cb.withMethod(METHOD_NAMES[xi], MTD_void_StringArray, ACC_PUBLIC | ACC_STATIC, mb -> mb.withCode(c0 -> { java.lang.classfile.Label loopTop = c0.newLabel(); From 9d621d3914b39cfdcda97274a7af5ca0fe062d35 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Thu, 10 Oct 2024 01:04:02 +0000 Subject: [PATCH 007/118] 8338884: java/nio/file/attribute/BasicFileAttributeView/CreationTime.java#tmp fails on alinux3 Reviewed-by: sgehwolf, bpb --- make/test/JtregNativeJdk.gmk | 2 + .../BasicFileAttributeView/CreationTime.java | 38 +++--- .../CreationTimeHelper.java | 61 +++++++++ .../libCreationTimeHelper.c | 117 ++++++++++++++++++ 4 files changed, 200 insertions(+), 18 deletions(-) create mode 100644 test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTimeHelper.java create mode 100644 test/jdk/java/nio/file/attribute/BasicFileAttributeView/libCreationTimeHelper.c diff --git a/make/test/JtregNativeJdk.gmk b/make/test/JtregNativeJdk.gmk index d9f1e334a5cf8..90055cb5c0114 100644 --- a/make/test/JtregNativeJdk.gmk +++ b/make/test/JtregNativeJdk.gmk @@ -115,6 +115,8 @@ ifeq ($(call isTargetOs, linux), true) # stripping during the test libraries' build. BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libFib := -g BUILD_JDK_JTREG_LIBRARIES_STRIP_SYMBOLS_libFib := false + # nio tests' libCreationTimeHelper native needs -ldl linker flag + BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libCreationTimeHelper := -ldl endif ifeq ($(ASAN_ENABLED), true) diff --git a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java index ad85da7ae63b1..65e801b0a9f35 100644 --- a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java +++ b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024 Alibaba Group Holding 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 @@ -25,18 +26,18 @@ * @bug 8011536 8151430 8316304 8334339 * @summary Basic test for creationTime attribute on platforms/file systems * that support it, tests using /tmp directory. - * @library ../.. /test/lib - * @build jdk.test.lib.Platform - * @run main CreationTime + * @library ../.. /test/lib /java/foreign + * @build jdk.test.lib.Platform NativeTestHelper + * @run main/othervm/native --enable-native-access=ALL-UNNAMED CreationTime */ /* @test id=cwd * @summary Basic test for creationTime attribute on platforms/file systems * that support it, tests using the test scratch directory, the test * scratch directory maybe at diff disk partition to /tmp on linux. - * @library ../.. /test/lib - * @build jdk.test.lib.Platform - * @run main CreationTime . + * @library ../.. /test/lib /java/foreign + * @build jdk.test.lib.Platform NativeTestHelper + * @run main/othervm/native --enable-native-access=ALL-UNNAMED CreationTime . */ import java.lang.foreign.Linker; @@ -51,8 +52,6 @@ public class CreationTime { - private static final java.io.PrintStream err = System.err; - /** * Reads the creationTime attribute */ @@ -78,14 +77,9 @@ static void test(Path top) throws IOException { FileTime creationTime = creationTime(file); Instant now = Instant.now(); if (Math.abs(creationTime.toMillis()-now.toEpochMilli()) > 10000L) { - System.out.println("creationTime.toMillis() == " + creationTime.toMillis()); - // If the file system doesn't support birth time, then skip this test - if (creationTime.toMillis() == 0) { - throw new SkippedException("birth time not support for: " + file); - } else { - err.println("File creation time reported as: " + creationTime); - throw new RuntimeException("Expected to be close to: " + now); - } + System.err.println("creationTime.toMillis() == " + creationTime.toMillis()); + System.err.println("File creation time reported as: " + creationTime); + throw new RuntimeException("Expected to be close to: " + now); } /** @@ -107,7 +101,12 @@ static void test(Path top) throws IOException { } } else if (Platform.isLinux()) { // Creation time read depends on statx system call support - supportsCreationTimeRead = Linker.nativeLinker().defaultLookup().find("statx").isPresent(); + try { + supportsCreationTimeRead = CreationTimeHelper. + linuxIsCreationTimeSupported(file.toAbsolutePath().toString()); + } catch (Throwable e) { + supportsCreationTimeRead = false; + } // Creation time updates are not supported on Linux supportsCreationTimeWrite = false; } @@ -122,8 +121,11 @@ static void test(Path top) throws IOException { Instant plusHour = Instant.now().plusSeconds(60L * 60L); Files.setLastModifiedTime(file, FileTime.from(plusHour)); FileTime current = creationTime(file); - if (!current.equals(creationTime)) + if (!current.equals(creationTime)) { + System.err.println("current = " + current); + System.err.println("creationTime = " + creationTime); throw new RuntimeException("Creation time should not have changed"); + } } /** diff --git a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTimeHelper.java b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTimeHelper.java new file mode 100644 index 0000000000000..592aeba322dd0 --- /dev/null +++ b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTimeHelper.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024 Alibaba Group Holding 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. + */ + +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; + +public class CreationTimeHelper extends NativeTestHelper { + + static { + System.loadLibrary("CreationTimeHelper"); + } + + final static Linker abi = Linker.nativeLinker(); + static final SymbolLookup lookup = SymbolLookup.loaderLookup(); + final static MethodHandle methodHandle = abi. + downcallHandle(lookup.findOrThrow("linuxIsCreationTimeSupported"), + FunctionDescriptor.of(C_BOOL, C_POINTER)); + + // Helper so as to determine birth time support or not on Linux. + // Support is determined in a two-step process: + // 1. Determine if `statx` system call is available. If available proceed, + // otherwise return false. + // 2. Perform an actual `statx` call on the given file and check for birth + // time support in the mask returned from the call. This is needed, + // since some file systems, like nfs/tmpfs etc., don't support birth + // time even though the `statx` system call is available. + static boolean linuxIsCreationTimeSupported(String file) throws Throwable { + if (!abi.defaultLookup().find("statx").isPresent()) { + return false; + } + try (var arena = Arena.ofConfined()) { + MemorySegment s = arena.allocateFrom(file); + return (boolean)methodHandle.invokeExact(s); + } + } +} diff --git a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/libCreationTimeHelper.c b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/libCreationTimeHelper.c new file mode 100644 index 0000000000000..d4c41d8cf917a --- /dev/null +++ b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/libCreationTimeHelper.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2024 Alibaba Group Holding 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. + */ +#include "export.h" +#include +#if defined(__linux__) +#include +#include +#include +#include +#include +#include +#ifndef STATX_BASIC_STATS +#define STATX_BASIC_STATS 0x000007ffU +#endif +#ifndef STATX_BTIME +#define STATX_BTIME 0x00000800U +#endif +#ifndef RTLD_DEFAULT +#define RTLD_DEFAULT RTLD_LOCAL +#endif + +/* + * Timestamp structure for the timestamps in struct statx. + */ +struct my_statx_timestamp { + __int64_t tv_sec; + __uint32_t tv_nsec; + __int32_t __reserved; +}; + +/* + * struct statx used by statx system call on >= glibc 2.28 + * systems + */ +struct my_statx +{ + __uint32_t stx_mask; + __uint32_t stx_blksize; + __uint64_t stx_attributes; + __uint32_t stx_nlink; + __uint32_t stx_uid; + __uint32_t stx_gid; + __uint16_t stx_mode; + __uint16_t __statx_pad1[1]; + __uint64_t stx_ino; + __uint64_t stx_size; + __uint64_t stx_blocks; + __uint64_t stx_attributes_mask; + struct my_statx_timestamp stx_atime; + struct my_statx_timestamp stx_btime; + struct my_statx_timestamp stx_ctime; + struct my_statx_timestamp stx_mtime; + __uint32_t stx_rdev_major; + __uint32_t stx_rdev_minor; + __uint32_t stx_dev_major; + __uint32_t stx_dev_minor; + __uint64_t __statx_pad2[14]; +}; + +typedef int statx_func(int dirfd, const char *restrict pathname, int flags, + unsigned int mask, struct my_statx *restrict statxbuf); + +static statx_func* my_statx_func = NULL; +#endif //#defined(__linux__) + +// static boolean linuxIsCreationTimeSupported(char* file) +EXPORT bool linuxIsCreationTimeSupported(char* file) { +#if defined(__linux__) + struct my_statx stx = {0}; + int ret, atflag = AT_SYMLINK_NOFOLLOW; + unsigned int mask = STATX_BASIC_STATS | STATX_BTIME; + + my_statx_func = (statx_func*) dlsym(RTLD_DEFAULT, "statx"); + if (my_statx_func == NULL) { + return false; + } + + if (file == NULL) { + printf("input file error!\n"); + return false; + } + + ret = my_statx_func(AT_FDCWD, file, atflag, mask, &stx); + if (ret != 0) { + return false; + } + // On some systems where statx is available but birth time might still not + // be supported as it's file system specific. The only reliable way to + // check for supported or not is looking at the filled in STATX_BTIME bit + // in the returned statx buffer mask. + if ((stx.stx_mask & STATX_BTIME) != 0) + return true; + return false; +#else + return false; +#endif +} From 313f4a962148331c9958618054109284470d1c9f Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Thu, 10 Oct 2024 05:40:21 +0000 Subject: [PATCH 008/118] 8340809: Open source few more AWT PopupMenu tests Reviewed-by: prr, aivanov --- .../awt/PopupMenu/ActivePopupCrashTest.java | 220 ++++++++++++++++++ .../java/awt/PopupMenu/KeyTraversalCrash.java | 126 ++++++++++ .../awt/PopupMenu/MultiplePopupMenusTest.java | 86 +++++++ .../java/awt/PopupMenu/PopupMenuCrash.java | 106 +++++++++ test/jdk/java/awt/PopupMenu/StressTest.java | 142 +++++++++++ 5 files changed, 680 insertions(+) create mode 100644 test/jdk/java/awt/PopupMenu/ActivePopupCrashTest.java create mode 100644 test/jdk/java/awt/PopupMenu/KeyTraversalCrash.java create mode 100644 test/jdk/java/awt/PopupMenu/MultiplePopupMenusTest.java create mode 100644 test/jdk/java/awt/PopupMenu/PopupMenuCrash.java create mode 100644 test/jdk/java/awt/PopupMenu/StressTest.java diff --git a/test/jdk/java/awt/PopupMenu/ActivePopupCrashTest.java b/test/jdk/java/awt/PopupMenu/ActivePopupCrashTest.java new file mode 100644 index 0000000000000..51c12964e6295 --- /dev/null +++ b/test/jdk/java/awt/PopupMenu/ActivePopupCrashTest.java @@ -0,0 +1,220 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * 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.Button; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.Point; +import java.awt.PopupMenu; +import java.awt.Robot; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import java.util.Hashtable; + +/* + * @test + * @bug 4214550 + * @summary Tests that there is no seg fault on repeatedly showing + * PopupMenu by right-clicking Label, Panel or Button + * @key headful + * @run main ActivePopupCrashTest + */ + +public class ActivePopupCrashTest { + private static Frame f; + private static Label l; + private static Button b; + private static Panel p; + + private static volatile Point labelCenter; + private static volatile Point buttonCenter; + private static volatile Point panelCenter; + + public static void main(String[] args) throws Exception { + final int REPEAT_COUNT = 5; + try { + Robot robot = new Robot(); + robot.setAutoDelay(50); + EventQueue.invokeAndWait(ActivePopupCrashTest::createAndShowUI); + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + labelCenter = getCenterPoint(l); + buttonCenter = getCenterPoint(b); + panelCenter = getCenterPoint(p); + }); + + for (int i = 0; i < REPEAT_COUNT; i++) { + robot.mouseMove(labelCenter.x, labelCenter.y); + robot.mousePress(InputEvent.BUTTON3_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK); + + robot.mouseMove(buttonCenter.x, buttonCenter.y); + robot.mousePress(InputEvent.BUTTON3_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK); + + robot.mouseMove(panelCenter.x, panelCenter.y); + robot.mousePress(InputEvent.BUTTON3_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK); + } + + // To close the popup, otherwise test fails on windows with timeout error + robot.mouseMove(panelCenter.x - 5, panelCenter.y - 5); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + } finally { + EventQueue.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } + + private static Point getCenterPoint(Component component) { + Point p = component.getLocationOnScreen(); + Dimension size = component.getSize(); + return new Point(p.x + size.width / 2, p.y + size.height / 2); + } + + public static void createAndShowUI() { + f = new Frame("ActivePopupCrashTest Test"); + MenuItem item = new MenuItem("file-1"); + item.addActionListener(ActivePopupCrashTest::logActionEvent); + Menu m = new Menu("file"); + m.add(item); + item = new MenuItem("file-2"); + m.add(item); + MenuBar mb = new MenuBar(); + mb.add(m); + + f.setMenuBar(mb); + f.setSize(200, 200); + f.setLayout(new BorderLayout()); + + l = new Label("label"); + addPopup(l, "label"); + f.add(l, BorderLayout.NORTH); + + p = new Panel(); + addPopup(p, "panel"); + f.add(p, BorderLayout.CENTER); + + b = new Button("button"); + addPopup(b, "button"); + f.add(b, BorderLayout.SOUTH); + + f.setSize(400, 300); + f.setLocationRelativeTo(null); + f.setVisible(true); + } + + static void addPopup(Component c, String name) { + PopupMenu pm = new PopupMenu(); + MenuItem mi = new MenuItem(name + "-1"); + mi.addActionListener(ActivePopupCrashTest::logActionEvent); + pm.add(mi); + + mi = new MenuItem(name + "-2"); + pm.add(mi); + + setHash(c, pm); + c.add(pm); + c.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + mouseAction("mouseClicked", e); + } + + @Override + public void mousePressed(MouseEvent e) { + mouseAction("mousePressed", e); + } + + @Override + public void mouseReleased(MouseEvent e) { + mouseAction("mouseReleased", e); + } + }); + } + + static void logActionEvent(ActionEvent e) { + System.out.println("actionPerformed, event=" + e + ", mod=" + getMods(e)); + System.out.println("command=" + e.getActionCommand()); + System.out.println("param=" + e.paramString()); + System.out.println("source=" + e.getSource()); + } + + static String getMods(ActionEvent e) { return getMods(e.getModifiers()); } + + static String getMods(MouseEvent e) { return getMods(e.getModifiers()); } + + static String getMods(int mods) { + String modstr = ""; + if ((mods & ActionEvent.SHIFT_MASK) == ActionEvent.SHIFT_MASK) { + modstr += (" SHIFT"); + } else if ((mods & ActionEvent.ALT_MASK) == ActionEvent.ALT_MASK) { + modstr += (" ALT"); + } else if ((mods & ActionEvent.CTRL_MASK) == ActionEvent.CTRL_MASK) { + modstr += (" CTRL"); + } else if ((mods & ActionEvent.META_MASK) == ActionEvent.META_MASK) { + modstr += (" META"); + } + return modstr; + } + + static void mouseAction(String which, MouseEvent e) { + Component c = e.getComponent(); + System.out.println(which + " e = " + e + " , mods = " + getMods(e) + + " , component = " + c); + if (e.isPopupTrigger()) { + System.out.println("isPopup"); + PopupMenu pm = getHash(c); + pm.show(c, c.getWidth() / 2, c.getHeight() / 2); + } + } + + static Hashtable popupTable = new Hashtable<>(); + + static void setHash(Component c, PopupMenu p) { + popupTable.put(c, p); + } + + static PopupMenu getHash(Component c) { + return popupTable.get(c); + } + +} diff --git a/test/jdk/java/awt/PopupMenu/KeyTraversalCrash.java b/test/jdk/java/awt/PopupMenu/KeyTraversalCrash.java new file mode 100644 index 0000000000000..4d1d4e8f8319b --- /dev/null +++ b/test/jdk/java/awt/PopupMenu/KeyTraversalCrash.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. + * 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.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Menu; +import java.awt.MenuItem; +import java.awt.Point; +import java.awt.PopupMenu; +import java.awt.Robot; + +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/* + * @test + * @bug 5021183 + * @summary Tests Key Traversal doesn't crash PopupMenu + * @key headful + * @run main KeyTraversalCrash + */ + +public class KeyTraversalCrash { + private static Frame f; + private static Label label; + + private static volatile Point loc; + private static volatile Dimension dim; + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + robot.setAutoDelay(100); + EventQueue.invokeAndWait(KeyTraversalCrash::createAndShowUI); + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + loc = label.getLocationOnScreen(); + dim = label.getSize(); + }); + + robot.mouseMove(loc.x + 20, loc.y + 20); + robot.mousePress(InputEvent.BUTTON3_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK); + + robot.mouseMove(loc.x + 25, loc.y + 25); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + robot.keyPress(KeyEvent.VK_LEFT); + robot.keyRelease(KeyEvent.VK_LEFT); + + robot.keyPress(KeyEvent.VK_DOWN); + robot.keyRelease(KeyEvent.VK_DOWN); + + // To close the popup, otherwise test fails on windows with timeout error + robot.mouseMove(loc.x + dim.width - 20, loc.y + dim.height - 20); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + } finally { + EventQueue.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } + + public static void createAndShowUI() { + f = new Frame("KeyTraversalCrash Test"); + final PopupMenu popup = new PopupMenu(); + for (int i = 0; i < 10; i++) { + Menu menu = new Menu("Menu " + i); + for(int j = 0; j < 10; j++) { + MenuItem menuItem = new MenuItem("MenuItem " + j); + menu.add(menuItem); + } + popup.add(menu); + } + label = new Label("Label"); + f.add(label); + f.add(popup); + label.addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent me) { + if (me.isPopupTrigger()) { + popup.show(me.getComponent(), me.getX(), me.getY()); + } + } + + @Override + public void mouseReleased(MouseEvent me) { + if (me.isPopupTrigger()) { + popup.show(me.getComponent(), me.getX(), me.getY()); + } + } + }); + f.setSize(200, 200); + f.setLocationRelativeTo(null); + f.setVisible(true); + } +} diff --git a/test/jdk/java/awt/PopupMenu/MultiplePopupMenusTest.java b/test/jdk/java/awt/PopupMenu/MultiplePopupMenusTest.java new file mode 100644 index 0000000000000..f939186ca072e --- /dev/null +++ b/test/jdk/java/awt/PopupMenu/MultiplePopupMenusTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * 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.AWTEvent; +import java.awt.Button; +import java.awt.Frame; +import java.awt.MenuItem; +import java.awt.PopupMenu; + +import java.awt.event.MouseEvent; + +/* + * @test + * @bug 4186663 4265525 + * @summary Tests that multiple PopupMenus cannot appear at the same time + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MultiplePopupMenusTest + */ + +public class MultiplePopupMenusTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Click the right mouse button on the button + If multiple popups appear at the same time the + test fails else passes. + """; + + PassFailJFrame.builder() + .title("MultiplePopupMenusTest Instruction") + .instructions(INSTRUCTIONS) + .columns(30) + .testUI(MultiplePopupMenusTest::createUI) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame fr = new Frame("MultiplePopupMenusTest Test"); + TestButton button = new TestButton("button"); + fr.add(button); + fr.setSize(200, 200); + return fr; + } + + static class TestButton extends Button { + public TestButton(String title) { + super(title); + enableEvents(AWTEvent.MOUSE_EVENT_MASK); + } + + @Override + public void processMouseEvent(MouseEvent e) { + if (e.isPopupTrigger()) { + for (int i = 0; i < 10; i++) { + PopupMenu pm = new PopupMenu("Popup " + i); + pm.add(new MenuItem("item 1")); + pm.add(new MenuItem("item 2")); + add(pm); + pm.show(this, e.getX() + i * 5, e.getY() + i * 5); + } + } + super.processMouseEvent(e); + } + } +} diff --git a/test/jdk/java/awt/PopupMenu/PopupMenuCrash.java b/test/jdk/java/awt/PopupMenu/PopupMenuCrash.java new file mode 100644 index 0000000000000..7ba738b21d276 --- /dev/null +++ b/test/jdk/java/awt/PopupMenu/PopupMenuCrash.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * 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.FlowLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.MenuItem; +import java.awt.PopupMenu; + +import java.awt.event.InputEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/* + * @test + * @bug 4281273 + * @summary PopupMenu crashed in Java. Simplified testcase. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @requires (os.family == "windows") + * @run main/manual PopupMenuCrash + */ + +public class PopupMenuCrash { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + This tests a windows specific problem. + When you see a frame titled "PopupMenuCrash Test", right-click on it + several times for a few seconds. Then wait about 10 seconds before the + PopupMenus start to appear. Then dispose them one by one by clicking on them. + When PopupMenus do not appear anymore, press Pass. + In case of a failure, you'll see a crash. + """; + + PassFailJFrame.builder() + .title("PopupMenuCrash Instruction") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(PopupMenuCrash::createUI) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + final Frame f = new Frame("PopupMenuCrash Test"); + f.setLayout(new FlowLayout()); + f.add(new Label("Press right mouse button inside this frame.")); + f.add(new Label("A pop-up menu should appear.")); + f.addMouseListener(new MouseAdapter() { + PopupMenu popup; + boolean firstPress = true; + + @Override + public void mousePressed(MouseEvent evt) { + if (firstPress) { + firstPress = false; + try { + Thread.sleep(10000); + } catch (InterruptedException ignored) { + } + } + + if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { + popup = new PopupMenu("Popup Menu Title"); + MenuItem mi = new MenuItem("MenuItem"); + popup.add(mi); + f.add(popup); + popup.show(evt.getComponent(), evt.getX(), evt.getY()); + } + } + + @Override + public void mouseReleased(MouseEvent evt) { + if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { + if (popup != null) { + f.remove(popup); + popup = null; + } + } + } + }); + + f.setSize(400, 350); + return f; + } +} diff --git a/test/jdk/java/awt/PopupMenu/StressTest.java b/test/jdk/java/awt/PopupMenu/StressTest.java new file mode 100644 index 0000000000000..221aa252aa0b7 --- /dev/null +++ b/test/jdk/java/awt/PopupMenu/StressTest.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * 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.Component; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.Point; +import java.awt.PopupMenu; +import java.awt.Robot; + +import java.awt.event.InputEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/* + * @test + * @bug 4083400 + * @key headful + * @summary Tests that excessive popping up and down does not crash or + * throw an exception. + * @run main StressTest + */ + +public class StressTest { + private static Frame fr; + private static PopupTestPanel panel; + + private static volatile Point panelCenter; + + public static void main(String[] args) throws Exception { + final int REPEAT_COUNT = 5; + try { + Robot robot = new Robot(); + robot.setAutoDelay(50); + EventQueue.invokeAndWait(StressTest::createAndShowUI); + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + Point loc = panel.getLocationOnScreen(); + Dimension dim = panel.getSize(); + panelCenter = new Point(loc.x + dim.width / 2, loc.y + dim.height / 2); + }); + + for (int i = 0; i < REPEAT_COUNT; i++) { + robot.mouseMove(panelCenter.x + i * 2, panelCenter.y + i * 2); + + robot.mousePress(InputEvent.BUTTON3_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK); + + robot.mouseMove(panelCenter.x - i * 2, panelCenter.y - i * 2); + + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (fr != null) { + fr.dispose(); + } + }); + } + } + + public static void createAndShowUI() { + fr = new Frame("PopupMenu Test"); + panel = new PopupTestPanel(); + fr.add(panel); + fr.setSize(300, 200); + fr.setVisible(true); + } + + static class PopupTestPanel extends Panel { + + static class Item extends MenuItem { + public Item(String text) { + super(text); + } + + public boolean isEnabled() { + try { + Thread.sleep(100); + } catch (InterruptedException ignored) { + } + return super.isEnabled(); + } + } + + final PopupMenu popup; + + public PopupTestPanel() { + popup = new PopupMenu(); + popup.add(new Item("Soap")); + popup.add(new Item("Sponge")); + popup.add(new Item("Flannel")); + popup.add(new Item("Mat")); + popup.add(new Item("Towel")); + add(popup); + addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + if (e.isPopupTrigger()) { + showPopup(e); + } + } + + @Override + public void mouseReleased(MouseEvent e) { + if (e.isPopupTrigger()) { + showPopup(e); + } + } + + private void showPopup(MouseEvent e) { + popup.show((Component) e.getSource(), e.getX(), e.getY()); + } + }); + } + } +} From 780de009224b048fa51a119e1db6cc52daddaaf8 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Thu, 10 Oct 2024 05:57:39 +0000 Subject: [PATCH 009/118] 8051591: Test javax/swing/JTabbedPane/8007563/Test8007563.java fails Reviewed-by: honkar, dnguyen, psadhukhan --- test/jdk/ProblemList.txt | 1 - .../JTabbedPane/8007563/Test8007563.java | 137 ------------------ .../TestJTabbedPaneBackgroundColor.java | 137 ++++++++++++++++++ 3 files changed, 137 insertions(+), 138 deletions(-) delete mode 100644 test/jdk/javax/swing/JTabbedPane/8007563/Test8007563.java create mode 100644 test/jdk/javax/swing/JTabbedPane/TestJTabbedPaneBackgroundColor.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 55ab722e34fd9..8f6b0c7466413 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -677,7 +677,6 @@ javax/swing/AbstractButton/6711682/bug6711682.java 8060765 windows-all,macosx-al javax/swing/JFileChooser/6396844/TwentyThousandTest.java 8198003 generic-all javax/swing/JFileChooser/8194044/FileSystemRootTest.java 8327236 windows-all javax/swing/JPopupMenu/6800513/bug6800513.java 7184956 macosx-all -javax/swing/JTabbedPane/8007563/Test8007563.java 8051591 generic-all javax/swing/JTabbedPane/4624207/bug4624207.java 8064922 macosx-all javax/swing/SwingUtilities/TestBadBreak/TestBadBreak.java 8160720 generic-all javax/swing/JFileChooser/6798062/bug6798062.java 8146446 windows-all diff --git a/test/jdk/javax/swing/JTabbedPane/8007563/Test8007563.java b/test/jdk/javax/swing/JTabbedPane/8007563/Test8007563.java deleted file mode 100644 index 25d3ad41eca59..0000000000000 --- a/test/jdk/javax/swing/JTabbedPane/8007563/Test8007563.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) 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. - */ - -import java.awt.*; -import java.util.ArrayList; -import java.util.concurrent.CountDownLatch; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JTabbedPane; - -import static javax.swing.UIManager.*; -import static javax.swing.SwingUtilities.*; - -/* - * @test - * @key headful - * @bug 8007563 - * @summary Tests JTabbedPane background - * @author Sergey Malenkov - */ - -public class Test8007563 implements Runnable { - private static final ArrayList LIST = new ArrayList<>(); - private static final LookAndFeelInfo[] INFO = getInstalledLookAndFeels(); - private static final CountDownLatch LATCH = new CountDownLatch(INFO.length); - private static Robot ROBOT; - - public static void main(String[] args) throws Exception { - ROBOT = new Robot(); - invokeLater(new Test8007563()); - LATCH.await(); - if (!LIST.isEmpty()) { - throw new Error(LIST.toString()); - } - } - - private static void addOpaqueError(boolean opaque) { - LIST.add(getLookAndFeel().getName() + " opaque=" + opaque); - } - - private static boolean updateLookAndFeel() { - int index = (int) LATCH.getCount() - 1; - if (index >= 0) { - try { - LookAndFeelInfo info = INFO[index]; - System.err.println("L&F: " + info.getName()); - setLookAndFeel(info.getClassName()); - return true; - } catch (Exception exception) { - exception.printStackTrace(); - } - } - return false; - } - - private JFrame frame; - private JTabbedPane pane; - - public void run() { - if (this.frame == null) { - if (!updateLookAndFeel()) { - return; - } - this.pane = new JTabbedPane(); - this.pane.setOpaque(false); - this.pane.setBackground(Color.RED); - for (int i = 0; i < 3; i++) { - this.pane.addTab("Tab " + i, new JLabel("Content area " + i)); - } - this.frame = new JFrame(getClass().getSimpleName()); - this.frame.getContentPane().setBackground(Color.BLUE); - this.frame.add(this.pane); - this.frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - this.frame.setSize(400, 200); - this.frame.setLocationRelativeTo(null); - this.frame.setVisible(true); - } else { - Point point = new Point(this.pane.getWidth() - 2, 2); - convertPointToScreen(point, this.pane); - Color actual = ROBOT.getPixelColor(point.x, point.y); - - boolean opaque = this.pane.isOpaque(); - Color expected = opaque - ? this.pane.getBackground() - : this.frame.getContentPane().getBackground(); - - if (!expected.equals(actual)){ - addOpaqueError(opaque); - } - if (!opaque) { - this.pane.setOpaque(true); - this.pane.repaint(); - } else { - this.frame.dispose(); - this.frame = null; - this.pane = null; - LATCH.countDown(); - } - - } - SecondaryLoop secondaryLoop = - Toolkit.getDefaultToolkit().getSystemEventQueue() - .createSecondaryLoop(); - new Thread() { - @Override - public void run() { - try { - Thread.sleep(200); - } catch (InterruptedException e) { - } - secondaryLoop.exit(); - invokeLater(Test8007563.this); - } - }.start(); - secondaryLoop.enter(); - } -} diff --git a/test/jdk/javax/swing/JTabbedPane/TestJTabbedPaneBackgroundColor.java b/test/jdk/javax/swing/JTabbedPane/TestJTabbedPaneBackgroundColor.java new file mode 100644 index 0000000000000..d4bed5ac2dafa --- /dev/null +++ b/test/jdk/javax/swing/JTabbedPane/TestJTabbedPaneBackgroundColor.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * 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.Dimension; +import java.awt.Point; +import java.awt.Robot; +import java.util.ArrayList; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JTabbedPane; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; + +/* + * @test + * @key headful + * @bug 8007563 + * @summary Tests JTabbedPane background + */ + +public class TestJTabbedPaneBackgroundColor { + private static ArrayList lafList = new ArrayList<>(); + private static JFrame frame; + private static JTabbedPane pane; + private static Robot robot; + private static volatile Dimension dim; + private static volatile Point loc; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + + for (UIManager.LookAndFeelInfo laf : + UIManager.getInstalledLookAndFeels()) { + System.out.println("Testing: " + laf.getName()); + setLookAndFeel(laf); + + try { + SwingUtilities.invokeAndWait(TestJTabbedPaneBackgroundColor::createAndShowUI); + robot.waitForIdle(); + robot.delay(500); + + SwingUtilities.invokeAndWait(() -> { + loc = pane.getLocationOnScreen(); + dim = pane.getSize(); + }); + + loc = new Point(loc.x + dim.width - 2, loc.y + 2); + doTesting(loc, laf); + + if (!pane.isOpaque()) { + pane.setOpaque(true); + pane.repaint(); + } + robot.waitForIdle(); + robot.delay(500); + + doTesting(loc, laf); + + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + if (!lafList.isEmpty()) { + throw new RuntimeException(lafList.toString()); + } + } + + private static void setLookAndFeel(UIManager.LookAndFeelInfo laf) { + try { + UIManager.setLookAndFeel(laf.getClassName()); + } catch (UnsupportedLookAndFeelException ignored) { + System.out.println("Unsupported LAF: " + laf.getClassName()); + } catch (ClassNotFoundException | InstantiationException + | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + private static void createAndShowUI() { + pane = new JTabbedPane(); + pane.setOpaque(false); + pane.setBackground(Color.RED); + for (int i = 0; i < 3; i++) { + pane.addTab("Tab " + i, new JLabel("Content area " + i)); + } + frame = new JFrame("Test Background Color"); + frame.getContentPane().setBackground(Color.BLUE); + frame.add(pane); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.setSize(400, 200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private static void doTesting(Point p, UIManager.LookAndFeelInfo laf) { + boolean isOpaque = pane.isOpaque(); + Color actual = robot.getPixelColor(p.x, p.y); + Color expected = isOpaque + ? pane.getBackground() + : frame.getContentPane().getBackground(); + + if (!expected.equals(actual)) { + addOpaqueError(laf.getName(), isOpaque); + } + } + + private static void addOpaqueError(String lafName, boolean opaque) { + lafList.add(lafName + " opaque=" + opaque); + } +} From 36fca5d19d6c0eb0391b4a36db689d9c3aae09b1 Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Thu, 10 Oct 2024 06:40:55 +0000 Subject: [PATCH 010/118] 8341882: [BACKOUT] java/nio/file/attribute/BasicFileAttributeView/CreationTime.java#tmp fails on alinux3 Reviewed-by: thartmann --- make/test/JtregNativeJdk.gmk | 2 - .../BasicFileAttributeView/CreationTime.java | 38 +++--- .../CreationTimeHelper.java | 61 --------- .../libCreationTimeHelper.c | 117 ------------------ 4 files changed, 18 insertions(+), 200 deletions(-) delete mode 100644 test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTimeHelper.java delete mode 100644 test/jdk/java/nio/file/attribute/BasicFileAttributeView/libCreationTimeHelper.c diff --git a/make/test/JtregNativeJdk.gmk b/make/test/JtregNativeJdk.gmk index 90055cb5c0114..d9f1e334a5cf8 100644 --- a/make/test/JtregNativeJdk.gmk +++ b/make/test/JtregNativeJdk.gmk @@ -115,8 +115,6 @@ ifeq ($(call isTargetOs, linux), true) # stripping during the test libraries' build. BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libFib := -g BUILD_JDK_JTREG_LIBRARIES_STRIP_SYMBOLS_libFib := false - # nio tests' libCreationTimeHelper native needs -ldl linker flag - BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libCreationTimeHelper := -ldl endif ifeq ($(ASAN_ENABLED), true) diff --git a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java index 65e801b0a9f35..ad85da7ae63b1 100644 --- a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java +++ b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java @@ -1,6 +1,5 @@ /* * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2024 Alibaba Group Holding 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 @@ -26,18 +25,18 @@ * @bug 8011536 8151430 8316304 8334339 * @summary Basic test for creationTime attribute on platforms/file systems * that support it, tests using /tmp directory. - * @library ../.. /test/lib /java/foreign - * @build jdk.test.lib.Platform NativeTestHelper - * @run main/othervm/native --enable-native-access=ALL-UNNAMED CreationTime + * @library ../.. /test/lib + * @build jdk.test.lib.Platform + * @run main CreationTime */ /* @test id=cwd * @summary Basic test for creationTime attribute on platforms/file systems * that support it, tests using the test scratch directory, the test * scratch directory maybe at diff disk partition to /tmp on linux. - * @library ../.. /test/lib /java/foreign - * @build jdk.test.lib.Platform NativeTestHelper - * @run main/othervm/native --enable-native-access=ALL-UNNAMED CreationTime . + * @library ../.. /test/lib + * @build jdk.test.lib.Platform + * @run main CreationTime . */ import java.lang.foreign.Linker; @@ -52,6 +51,8 @@ public class CreationTime { + private static final java.io.PrintStream err = System.err; + /** * Reads the creationTime attribute */ @@ -77,9 +78,14 @@ static void test(Path top) throws IOException { FileTime creationTime = creationTime(file); Instant now = Instant.now(); if (Math.abs(creationTime.toMillis()-now.toEpochMilli()) > 10000L) { - System.err.println("creationTime.toMillis() == " + creationTime.toMillis()); - System.err.println("File creation time reported as: " + creationTime); - throw new RuntimeException("Expected to be close to: " + now); + System.out.println("creationTime.toMillis() == " + creationTime.toMillis()); + // If the file system doesn't support birth time, then skip this test + if (creationTime.toMillis() == 0) { + throw new SkippedException("birth time not support for: " + file); + } else { + err.println("File creation time reported as: " + creationTime); + throw new RuntimeException("Expected to be close to: " + now); + } } /** @@ -101,12 +107,7 @@ static void test(Path top) throws IOException { } } else if (Platform.isLinux()) { // Creation time read depends on statx system call support - try { - supportsCreationTimeRead = CreationTimeHelper. - linuxIsCreationTimeSupported(file.toAbsolutePath().toString()); - } catch (Throwable e) { - supportsCreationTimeRead = false; - } + supportsCreationTimeRead = Linker.nativeLinker().defaultLookup().find("statx").isPresent(); // Creation time updates are not supported on Linux supportsCreationTimeWrite = false; } @@ -121,11 +122,8 @@ static void test(Path top) throws IOException { Instant plusHour = Instant.now().plusSeconds(60L * 60L); Files.setLastModifiedTime(file, FileTime.from(plusHour)); FileTime current = creationTime(file); - if (!current.equals(creationTime)) { - System.err.println("current = " + current); - System.err.println("creationTime = " + creationTime); + if (!current.equals(creationTime)) throw new RuntimeException("Creation time should not have changed"); - } } /** diff --git a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTimeHelper.java b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTimeHelper.java deleted file mode 100644 index 592aeba322dd0..0000000000000 --- a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTimeHelper.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2024 Alibaba Group Holding 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. - */ - -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.Linker; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; - -public class CreationTimeHelper extends NativeTestHelper { - - static { - System.loadLibrary("CreationTimeHelper"); - } - - final static Linker abi = Linker.nativeLinker(); - static final SymbolLookup lookup = SymbolLookup.loaderLookup(); - final static MethodHandle methodHandle = abi. - downcallHandle(lookup.findOrThrow("linuxIsCreationTimeSupported"), - FunctionDescriptor.of(C_BOOL, C_POINTER)); - - // Helper so as to determine birth time support or not on Linux. - // Support is determined in a two-step process: - // 1. Determine if `statx` system call is available. If available proceed, - // otherwise return false. - // 2. Perform an actual `statx` call on the given file and check for birth - // time support in the mask returned from the call. This is needed, - // since some file systems, like nfs/tmpfs etc., don't support birth - // time even though the `statx` system call is available. - static boolean linuxIsCreationTimeSupported(String file) throws Throwable { - if (!abi.defaultLookup().find("statx").isPresent()) { - return false; - } - try (var arena = Arena.ofConfined()) { - MemorySegment s = arena.allocateFrom(file); - return (boolean)methodHandle.invokeExact(s); - } - } -} diff --git a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/libCreationTimeHelper.c b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/libCreationTimeHelper.c deleted file mode 100644 index d4c41d8cf917a..0000000000000 --- a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/libCreationTimeHelper.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2024 Alibaba Group Holding 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. - */ -#include "export.h" -#include -#if defined(__linux__) -#include -#include -#include -#include -#include -#include -#ifndef STATX_BASIC_STATS -#define STATX_BASIC_STATS 0x000007ffU -#endif -#ifndef STATX_BTIME -#define STATX_BTIME 0x00000800U -#endif -#ifndef RTLD_DEFAULT -#define RTLD_DEFAULT RTLD_LOCAL -#endif - -/* - * Timestamp structure for the timestamps in struct statx. - */ -struct my_statx_timestamp { - __int64_t tv_sec; - __uint32_t tv_nsec; - __int32_t __reserved; -}; - -/* - * struct statx used by statx system call on >= glibc 2.28 - * systems - */ -struct my_statx -{ - __uint32_t stx_mask; - __uint32_t stx_blksize; - __uint64_t stx_attributes; - __uint32_t stx_nlink; - __uint32_t stx_uid; - __uint32_t stx_gid; - __uint16_t stx_mode; - __uint16_t __statx_pad1[1]; - __uint64_t stx_ino; - __uint64_t stx_size; - __uint64_t stx_blocks; - __uint64_t stx_attributes_mask; - struct my_statx_timestamp stx_atime; - struct my_statx_timestamp stx_btime; - struct my_statx_timestamp stx_ctime; - struct my_statx_timestamp stx_mtime; - __uint32_t stx_rdev_major; - __uint32_t stx_rdev_minor; - __uint32_t stx_dev_major; - __uint32_t stx_dev_minor; - __uint64_t __statx_pad2[14]; -}; - -typedef int statx_func(int dirfd, const char *restrict pathname, int flags, - unsigned int mask, struct my_statx *restrict statxbuf); - -static statx_func* my_statx_func = NULL; -#endif //#defined(__linux__) - -// static boolean linuxIsCreationTimeSupported(char* file) -EXPORT bool linuxIsCreationTimeSupported(char* file) { -#if defined(__linux__) - struct my_statx stx = {0}; - int ret, atflag = AT_SYMLINK_NOFOLLOW; - unsigned int mask = STATX_BASIC_STATS | STATX_BTIME; - - my_statx_func = (statx_func*) dlsym(RTLD_DEFAULT, "statx"); - if (my_statx_func == NULL) { - return false; - } - - if (file == NULL) { - printf("input file error!\n"); - return false; - } - - ret = my_statx_func(AT_FDCWD, file, atflag, mask, &stx); - if (ret != 0) { - return false; - } - // On some systems where statx is available but birth time might still not - // be supported as it's file system specific. The only reliable way to - // check for supported or not is looking at the filled in STATX_BTIME bit - // in the returned statx buffer mask. - if ((stx.stx_mask & STATX_BTIME) != 0) - return true; - return false; -#else - return false; -#endif -} From e7c5bf45f753ad6459c666a4dd4a31197b69e05e Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 10 Oct 2024 07:21:05 +0000 Subject: [PATCH 011/118] 8341722: Fix some warnings as errors when building on Linux with toolchain clang Reviewed-by: cjplummer, lucy --- make/modules/jdk.hotspot.agent/Lib.gmk | 2 -- .../linux/native/libsaproc/LinuxDebuggerLocal.cpp | 1 - src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c | 4 ++-- src/jdk.jpackage/share/native/common/Log.cpp | 4 ---- test/hotspot/gtest/runtime/test_os_linux.cpp | 4 ++-- 5 files changed, 4 insertions(+), 11 deletions(-) diff --git a/make/modules/jdk.hotspot.agent/Lib.gmk b/make/modules/jdk.hotspot.agent/Lib.gmk index f0ede594d0ce8..12f1c1f2a9077 100644 --- a/make/modules/jdk.hotspot.agent/Lib.gmk +++ b/make/modules/jdk.hotspot.agent/Lib.gmk @@ -59,9 +59,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBSAPROC, \ OPTIMIZATION := HIGH, \ EXTRA_HEADER_DIRS := java.base:libjvm, \ DISABLED_WARNINGS_gcc := sign-compare, \ - DISABLED_WARNINGS_gcc_LinuxDebuggerLocal.cpp := unused-variable, \ DISABLED_WARNINGS_gcc_ps_core.c := pointer-arith, \ - DISABLED_WARNINGS_gcc_symtab.c := unused-but-set-variable, \ DISABLED_WARNINGS_clang := sign-compare, \ DISABLED_WARNINGS_clang_libproc_impl.c := format-nonliteral, \ DISABLED_WARNINGS_clang_MacosxDebuggerLocal.m := unused-variable, \ diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.cpp b/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.cpp index 962b1ae51722b..0ad95d0eac7cf 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.cpp +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.cpp @@ -420,7 +420,6 @@ JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLo jboolean isCopy; jlongArray array; jlong *regs; - int i; struct ps_prochandle* ph = get_proc_handle(env, this_obj); if (get_lwp_regs(ph, lwp_id, &gregs) != true) { diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c b/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c index d3b4d3d1af927..c36b9e5707e61 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c @@ -356,7 +356,6 @@ static struct symtab* build_symtab_internal(int fd, const char *filename, bool t if (shdr->sh_type == sym_section) { ELF_SYM *syms; - int rslt; size_t size, n, j, htab_sz; // FIXME: there could be multiple data buffers associated with the @@ -390,7 +389,8 @@ static struct symtab* build_symtab_internal(int fd, const char *filename, bool t goto bad; } - rslt = hcreate_r(htab_sz, symtab->hash_table); + // int rslt = + hcreate_r(htab_sz, symtab->hash_table); // guarantee(rslt, "unexpected failure: hcreate_r"); // shdr->sh_link points to the section that contains the actual strings diff --git a/src/jdk.jpackage/share/native/common/Log.cpp b/src/jdk.jpackage/share/native/common/Log.cpp index 66154ee8247e2..8227bb1cce4dd 100644 --- a/src/jdk.jpackage/share/native/common/Log.cpp +++ b/src/jdk.jpackage/share/native/common/Log.cpp @@ -40,10 +40,6 @@ namespace { // variables are initialized if any. This will result in AV. To avoid such // use cases keep logging module free from static variables that require // initialization with functions called by CRT. - // - - // by default log everything - const Logger::LogLevel defaultLogLevel = Logger::LOG_TRACE; char defaultLogAppenderMemory[sizeof(StreamLogAppender)] = {}; diff --git a/test/hotspot/gtest/runtime/test_os_linux.cpp b/test/hotspot/gtest/runtime/test_os_linux.cpp index 69c3d991b2a4f..387940afdf296 100644 --- a/test/hotspot/gtest/runtime/test_os_linux.cpp +++ b/test/hotspot/gtest/runtime/test_os_linux.cpp @@ -360,10 +360,10 @@ TEST_VM(os_linux, pretouch_thp_and_use_concurrent) { EXPECT_TRUE(os::commit_memory(heap, size, false)); { - auto pretouch = [heap, size](Thread*, int) { + auto pretouch = [heap](Thread*, int) { os::pretouch_memory(heap, heap + size, os::vm_page_size()); }; - auto useMemory = [heap, size](Thread*, int) { + auto useMemory = [heap](Thread*, int) { int* iptr = reinterpret_cast(heap); for (int i = 0; i < 1000; i++) *iptr++ = i; }; From 16042556f394adfa93e54173944198397ad29dea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Casta=C3=B1eda=20Lozano?= Date: Thu, 10 Oct 2024 08:34:10 +0000 Subject: [PATCH 012/118] 8341619: C2: remove unused StoreCM node Reviewed-by: chagedorn, thartmann, kvn --- src/hotspot/cpu/aarch64/aarch64.ad | 30 ------------ src/hotspot/cpu/arm/arm.ad | 12 ----- src/hotspot/cpu/ppc/ppc.ad | 17 ------- src/hotspot/cpu/riscv/riscv.ad | 35 -------------- src/hotspot/cpu/s390/s390.ad | 22 --------- src/hotspot/cpu/x86/x86_32.ad | 11 ----- src/hotspot/cpu/x86/x86_64.ad | 26 ----------- src/hotspot/share/adlc/forms.cpp | 1 - src/hotspot/share/adlc/formssel.cpp | 1 - src/hotspot/share/opto/classes.hpp | 1 - src/hotspot/share/opto/compile.cpp | 58 ------------------------ src/hotspot/share/opto/compile.hpp | 1 - src/hotspot/share/opto/escape.cpp | 9 +--- src/hotspot/share/opto/gcm.cpp | 18 +++----- src/hotspot/share/opto/idealKit.cpp | 20 -------- src/hotspot/share/opto/idealKit.hpp | 9 ---- src/hotspot/share/opto/lcm.cpp | 17 ------- src/hotspot/share/opto/loopTransform.cpp | 2 +- src/hotspot/share/opto/memnode.cpp | 48 +------------------- src/hotspot/share/opto/memnode.hpp | 33 +------------- src/hotspot/share/opto/output.cpp | 25 +--------- src/hotspot/share/opto/superword.cpp | 3 -- src/hotspot/share/runtime/vmStructs.cpp | 1 - 23 files changed, 12 insertions(+), 388 deletions(-) diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index c7cae54d14c0a..4049ab1fe8073 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -6892,36 +6892,6 @@ instruct loadConD(vRegD dst, immD con) %{ // Store Instructions -// Store CMS card-mark Immediate -instruct storeimmCM0(immI0 zero, memory1 mem) -%{ - match(Set mem (StoreCM mem zero)); - - ins_cost(INSN_COST); - format %{ "storestore (elided)\n\t" - "strb zr, $mem\t# byte" %} - - ins_encode(aarch64_enc_strb0(mem)); - - 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, memory1 mem) -%{ - match(Set mem (StoreCM mem zero)); - - ins_cost(INSN_COST * 2); - format %{ "storestore\n\t" - "dmb ishst" - "\n\tstrb zr, $mem\t# byte" %} - - ins_encode(aarch64_enc_strb0_ordered(mem)); - - ins_pipe(istore_mem); -%} - // Store Byte instruct storeB(iRegIorL2I src, memory1 mem) %{ diff --git a/src/hotspot/cpu/arm/arm.ad b/src/hotspot/cpu/arm/arm.ad index 716f6d87230e1..bb81f2af5999b 100644 --- a/src/hotspot/cpu/arm/arm.ad +++ b/src/hotspot/cpu/arm/arm.ad @@ -4226,18 +4226,6 @@ instruct storeB(memoryB mem, store_RegI src) %{ ins_pipe(istore_mem_reg); %} -instruct storeCM(memoryB mem, store_RegI src) %{ - match(Set mem (StoreCM mem src)); - ins_cost(MEMORY_REF_COST); - - size(4); - format %{ "STRB $src,$mem\t! CMS card-mark byte" %} - ins_encode %{ - __ strb($src$$Register, $mem$$Address); - %} - ins_pipe(istore_mem_reg); -%} - // Store Char/Short diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index d15f9929671ba..b5bfdf5067a12 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -6482,23 +6482,6 @@ instruct storeD(memory mem, regD src) %{ ins_pipe(pipe_class_memory); %} -//----------Store Instructions With Zeros-------------------------------------- - -instruct storeCM(memory mem, immI_0 zero) %{ - match(Set mem (StoreCM mem zero)); - ins_cost(MEMORY_REF_COST); - - format %{ "STB #0, $mem \t// CMS card-mark byte store" %} - size(8); - ins_encode %{ - __ li(R0, 0); - // No release barrier: Oops are allowed to get visible after marking. - guarantee($mem$$base$$Register != R1_SP, "use frame_slots_bias"); - __ stb(R0, $mem$$disp, $mem$$base$$Register); - %} - ins_pipe(pipe_class_memory); -%} - // Convert oop pointer into compressed form. // Nodes for postalloc expand. diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index a76d172267004..30b8ff77be809 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -5039,41 +5039,6 @@ instruct loadConD0(fRegD dst, immD0 con) %{ 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) %{ diff --git a/src/hotspot/cpu/s390/s390.ad b/src/hotspot/cpu/s390/s390.ad index 8181e96ecfc55..ebb2ca36a6458 100644 --- a/src/hotspot/cpu/s390/s390.ad +++ b/src/hotspot/cpu/s390/s390.ad @@ -4226,28 +4226,6 @@ instruct storeB(memory mem, iRegI src) %{ ins_pipe(pipe_class_dummy); %} -instruct storeCM(memory mem, immI_0 src) %{ - match(Set mem (StoreCM mem src)); - ins_cost(MEMORY_REF_COST); - // TODO: s390 port size(VARIABLE_SIZE); - format %{ "STC(Y) $src,$mem\t # CMS card-mark byte (must be 0!)" %} - ins_encode %{ - guarantee($mem$$index$$Register != Z_R0, "content will not be used."); - if ($mem$$index$$Register != noreg) { - // Can't use clear_mem --> load const zero and store character. - __ load_const_optimized(Z_R0_scratch, (long)0); - if (Immediate::is_uimm12($mem$$disp)) { - __ z_stc(Z_R0_scratch, $mem$$Address); - } else { - __ z_stcy(Z_R0_scratch, $mem$$Address); - } - } else { - __ clear_mem(Address($mem$$Address), 1); - } - %} - ins_pipe(pipe_class_dummy); -%} - // CHAR/SHORT // Store Char/Short diff --git a/src/hotspot/cpu/x86/x86_32.ad b/src/hotspot/cpu/x86/x86_32.ad index 7aa4f6a29a116..7c9695571daec 100644 --- a/src/hotspot/cpu/x86/x86_32.ad +++ b/src/hotspot/cpu/x86/x86_32.ad @@ -6322,17 +6322,6 @@ instruct storeImmB(memory mem, immI8 src) %{ ins_pipe( ialu_mem_imm ); %} -// Store CMS card-mark Immediate -instruct storeImmCM(memory mem, immI8 src) %{ - match(Set mem (StoreCM mem src)); - - ins_cost(150); - format %{ "MOV8 $mem,$src\t! CMS card-mark imm0" %} - opcode(0xC6); /* C6 /0 */ - ins_encode( SetInstMark, OpcP, RMopc_Mem(0x00,mem), Con8or32(src), ClearInstMark); - ins_pipe( ialu_mem_imm ); -%} - // Store Double instruct storeDPR( memory mem, regDPR1 src) %{ predicate(UseSSE<=1); diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index fee265473befe..c3fa4c16e553f 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -5298,32 +5298,6 @@ instruct storeImmB(memory mem, immI8 src) ins_pipe(ialu_mem_imm); %} -// Store CMS card-mark Immediate -instruct storeImmCM0_reg(memory mem, immI_0 zero) -%{ - predicate(UseCompressedOops && (CompressedOops::base() == nullptr)); - match(Set mem (StoreCM mem zero)); - - ins_cost(125); // XXX - format %{ "movb $mem, R12\t# CMS card-mark byte 0 (R12_heapbase==0)" %} - ins_encode %{ - __ movb($mem$$Address, r12); - %} - ins_pipe(ialu_mem_reg); -%} - -instruct storeImmCM0(memory mem, immI_0 src) -%{ - match(Set mem (StoreCM mem src)); - - ins_cost(150); // XXX - format %{ "movb $mem, $src\t# CMS card-mark byte 0" %} - ins_encode %{ - __ movb($mem$$Address, $src$$constant); - %} - ins_pipe(ialu_mem_imm); -%} - // Store Float instruct storeF(memory mem, regF src) %{ diff --git a/src/hotspot/share/adlc/forms.cpp b/src/hotspot/share/adlc/forms.cpp index 068d745254e3d..c34a73ea1e13f 100644 --- a/src/hotspot/share/adlc/forms.cpp +++ b/src/hotspot/share/adlc/forms.cpp @@ -276,7 +276,6 @@ Form::DataType Form::is_load_from_memory(const char *opType) const { Form::DataType Form::is_store_to_memory(const char *opType) const { if( strcmp(opType,"StoreB")==0) return Form::idealB; - if( strcmp(opType,"StoreCM")==0) return Form::idealB; if( strcmp(opType,"StoreC")==0) return Form::idealC; if( strcmp(opType,"StoreD")==0) return Form::idealD; if( strcmp(opType,"StoreF")==0) return Form::idealF; diff --git a/src/hotspot/share/adlc/formssel.cpp b/src/hotspot/share/adlc/formssel.cpp index 15bc7ddc67d60..ac2d3d94153f7 100644 --- a/src/hotspot/share/adlc/formssel.cpp +++ b/src/hotspot/share/adlc/formssel.cpp @@ -3654,7 +3654,6 @@ int MatchNode::needs_ideal_memory_edge(FormDict &globals) const { #if INCLUDE_SHENANDOAHGC "ShenandoahCompareAndSwapN", "ShenandoahCompareAndSwapP", "ShenandoahWeakCompareAndSwapP", "ShenandoahWeakCompareAndSwapN", "ShenandoahCompareAndExchangeP", "ShenandoahCompareAndExchangeN", #endif - "StoreCM", "GetAndSetB", "GetAndSetS", "GetAndAddI", "GetAndSetI", "GetAndSetP", "GetAndAddB", "GetAndAddS", "GetAndAddL", "GetAndSetL", "GetAndSetN", "ClearArray" diff --git a/src/hotspot/share/opto/classes.hpp b/src/hotspot/share/opto/classes.hpp index 8bee6279446ef..215e48ef9da9c 100644 --- a/src/hotspot/share/opto/classes.hpp +++ b/src/hotspot/share/opto/classes.hpp @@ -341,7 +341,6 @@ macro(Start) macro(StartOSR) macro(StoreB) macro(StoreC) -macro(StoreCM) macro(StoreD) macro(StoreF) macro(StoreI) diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index fa0d39057cb12..c6b316e527760 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -3061,52 +3061,6 @@ struct Final_Reshape_Counts : public StackObj { int get_inner_loop_count() const { return _inner_loop_count; } }; -// Eliminate trivially redundant StoreCMs and accumulate their -// precedence edges. -void Compile::eliminate_redundant_card_marks(Node* n) { - assert(n->Opcode() == Op_StoreCM, "expected StoreCM"); - if (n->in(MemNode::Address)->outcnt() > 1) { - // There are multiple users of the same address so it might be - // possible to eliminate some of the StoreCMs - Node* mem = n->in(MemNode::Memory); - Node* adr = n->in(MemNode::Address); - Node* val = n->in(MemNode::ValueIn); - Node* prev = n; - bool done = false; - // Walk the chain of StoreCMs eliminating ones that match. As - // long as it's a chain of single users then the optimization is - // safe. Eliminating partially redundant StoreCMs would require - // cloning copies down the other paths. - while (mem->Opcode() == Op_StoreCM && mem->outcnt() == 1 && !done) { - if (adr == mem->in(MemNode::Address) && - val == mem->in(MemNode::ValueIn)) { - // redundant StoreCM - if (mem->req() > MemNode::OopStore) { - // Hasn't been processed by this code yet. - n->add_prec(mem->in(MemNode::OopStore)); - } else { - // Already converted to precedence edge - for (uint i = mem->req(); i < mem->len(); i++) { - // Accumulate any precedence edges - if (mem->in(i) != nullptr) { - n->add_prec(mem->in(i)); - } - } - // Everything above this point has been processed. - done = true; - } - // Eliminate the previous StoreCM - prev->set_req(MemNode::Memory, mem->in(MemNode::Memory)); - assert(mem->outcnt() == 0, "should be dead"); - mem->disconnect_inputs(this); - } else { - prev = mem; - } - mem = prev->in(MemNode::Memory); - } - } -} - //------------------------------final_graph_reshaping_impl---------------------- // Implement items 1-5 from final_graph_reshaping below. void Compile::final_graph_reshaping_impl(Node *n, Final_Reshape_Counts& frc, Unique_Node_List& dead_nodes) { @@ -3276,18 +3230,6 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f } break; } - - case Op_StoreCM: - { - // Convert OopStore dependence into precedence edge - Node* prec = n->in(MemNode::OopStore); - n->del_req(MemNode::OopStore); - n->add_prec(prec); - eliminate_redundant_card_marks(n); - } - - // fall through - case Op_StoreB: case Op_StoreC: case Op_StoreI: diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index 1ccfedd0d460f..6568828125fe2 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -1244,7 +1244,6 @@ class Compile : public Phase { void final_graph_reshaping_impl(Node *n, Final_Reshape_Counts& frc, Unique_Node_List& dead_nodes); void final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& frc, uint nop, Unique_Node_List& dead_nodes); void final_graph_reshaping_walk(Node_Stack& nstack, Node* root, Final_Reshape_Counts& frc, Unique_Node_List& dead_nodes); - void eliminate_redundant_card_marks(Node* n); void handle_div_mod_op(Node* n, BasicType bt, bool is_unsigned); // Logic cone optimization. diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index 6ab28eaa6eeba..b26480ba9b39a 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -4009,10 +4009,6 @@ void ConnectionGraph::move_inst_mem(Node* n, GrowableArray &orig_phi --i; #ifdef ASSERT } else if (use->is_Mem()) { - if (use->Opcode() == Op_StoreCM && use->in(MemNode::OopStore) == n) { - // Don't move related cardmark. - continue; - } // Memory nodes should have new memory input. tp = igvn->type(use->in(MemNode::Address))->isa_ptr(); assert(tp != nullptr, "ptr type"); @@ -4564,7 +4560,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 (!(op == Op_CmpP || op == Op_Conv2B || - op == Op_CastP2X || op == Op_StoreCM || + op == Op_CastP2X || op == Op_FastLock || op == Op_AryEq || op == Op_StrComp || op == Op_CountPositives || op == Op_StrCompressedCopy || op == Op_StrInflatedCopy || @@ -4703,9 +4699,6 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, if (use->is_Phi() || use->is_ClearArray()) { memnode_worklist.append_if_missing(use); } else if (use->is_Mem() && use->in(MemNode::Memory) == n) { - if (use->Opcode() == Op_StoreCM) { // Ignore cardmark stores - continue; - } memnode_worklist.append_if_missing(use); } else if (use->is_MemBar() || use->is_CallLeaf()) { if (use->in(TypeFunc::Memory) == n) { // Ignore precedent edge diff --git a/src/hotspot/share/opto/gcm.cpp b/src/hotspot/share/opto/gcm.cpp index 9ba571b926d0d..dd51bb4709452 100644 --- a/src/hotspot/share/opto/gcm.cpp +++ b/src/hotspot/share/opto/gcm.cpp @@ -216,19 +216,13 @@ void PhaseCFG::schedule_pinned_nodes(VectorSet &visited) { for (uint i = node->len()-1; i >= node->req(); i--) { Node* m = node->in(i); if (m == nullptr) continue; - - // Only process precedence edges that are CFG nodes. Safepoints and control projections can be in the middle of a block - if (is_CFG(m)) { - node->rm_prec(i); - if (n == nullptr) { - n = m; - } else { - assert(is_dominator(n, m) || is_dominator(m, n), "one must dominate the other"); - n = is_dominator(n, m) ? m : n; - } + assert(is_CFG(m), "must be a CFG node"); + node->rm_prec(i); + if (n == nullptr) { + n = m; } else { - assert(node->is_Mach(), "sanity"); - assert(node->as_Mach()->ideal_Opcode() == Op_StoreCM, "must be StoreCM node"); + assert(is_dominator(n, m) || is_dominator(m, n), "one must dominate the other"); + n = is_dominator(n, m) ? m : n; } } if (n != nullptr) { diff --git a/src/hotspot/share/opto/idealKit.cpp b/src/hotspot/share/opto/idealKit.cpp index 80c4791cfd5cc..baa055bc60aeb 100644 --- a/src/hotspot/share/opto/idealKit.cpp +++ b/src/hotspot/share/opto/idealKit.cpp @@ -381,26 +381,6 @@ Node* IdealKit::store(Node* ctl, Node* adr, Node *val, BasicType bt, return st; } -// Card mark store. Must be ordered so that it will come after the store of -// the oop. -Node* IdealKit::storeCM(Node* ctl, Node* adr, Node *val, Node* oop_store, int oop_adr_idx, - BasicType bt, - int adr_idx) { - assert(adr_idx != Compile::AliasIdxTop, "use other store_to_memory factory" ); - const TypePtr* adr_type = nullptr; - debug_only(adr_type = C->get_adr_type(adr_idx)); - Node *mem = memory(adr_idx); - - // Add required edge to oop_store, optimizer does not support precedence edges. - // Convert required edge to precedence edge before allocation. - Node* st = new StoreCMNode(ctl, mem, adr, adr_type, val, oop_store, oop_adr_idx); - - st = transform(st); - set_memory(st, adr_idx); - - return st; -} - //---------------------------- do_memory_merge -------------------------------- // The memory from one merging cvstate needs to be merged with the memory for another // join cvstate. If the join cvstate doesn't have a merged memory yet then we diff --git a/src/hotspot/share/opto/idealKit.hpp b/src/hotspot/share/opto/idealKit.hpp index 20acec4721118..727b70129ef90 100644 --- a/src/hotspot/share/opto/idealKit.hpp +++ b/src/hotspot/share/opto/idealKit.hpp @@ -234,15 +234,6 @@ class IdealKit: public StackObj { bool require_atomic_access = false, bool mismatched = false); - // Store a card mark ordered after store_oop - Node* storeCM(Node* ctl, - Node* adr, - Node* val, - Node* oop_store, - int oop_adr_idx, - BasicType bt, - int adr_idx); - // Trivial call Node* make_leaf_call(const TypeFunc *slow_call_type, address slow_call, diff --git a/src/hotspot/share/opto/lcm.cpp b/src/hotspot/share/opto/lcm.cpp index 87be6a76eb202..2a40cf000d849 100644 --- a/src/hotspot/share/opto/lcm.cpp +++ b/src/hotspot/share/opto/lcm.cpp @@ -191,7 +191,6 @@ void PhaseCFG::implicit_null_check(Block* block, Node *proj, Node *val, int allo break; case Op_StoreB: case Op_StoreC: - case Op_StoreCM: case Op_StoreD: case Op_StoreF: case Op_StoreI: @@ -723,7 +722,6 @@ void PhaseCFG::adjust_register_pressure(Node* n, Block* block, intptr_t* recalc_ switch (iop) { case Op_StoreB: case Op_StoreC: - case Op_StoreCM: case Op_StoreD: case Op_StoreF: case Op_StoreI: @@ -1004,21 +1002,6 @@ bool PhaseCFG::schedule_local(Block* block, GrowableArray& ready_cnt, Vecto local++; // One more block-local input } ready_cnt.at_put(n->_idx, local); // Count em up - -#ifdef ASSERT - if (UseG1GC) { - if( n->is_Mach() && n->as_Mach()->ideal_Opcode() == Op_StoreCM ) { - // Check the precedence edges - for (uint prec = n->req(); prec < n->len(); prec++) { - Node* oop_store = n->in(prec); - if (oop_store != nullptr) { - assert(get_block_for_node(oop_store)->_dom_depth <= block->_dom_depth, "oop_store must dominate card-mark"); - } - } - } - } -#endif - // A few node types require changing a required edge to a precedence edge // before allocation. if( n->is_Mach() && n->req() > TypeFunc::Parms && diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index 0bed38e5fb068..c3cc8532e7d30 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -3817,7 +3817,7 @@ bool PhaseIdealLoop::match_fill_loop(IdealLoopTree* lpt, Node*& store, Node*& st break; } int opc = n->Opcode(); - if (opc == Op_StoreP || opc == Op_StoreN || opc == Op_StoreNKlass || opc == Op_StoreCM) { + if (opc == Op_StoreP || opc == Op_StoreN || opc == Op_StoreNKlass) { msg = "oop fills not handled"; break; } diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index 6613918826057..27c0d16fac1b6 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -3462,9 +3462,7 @@ Node *StoreNode::Ideal(PhaseGVN *phase, bool can_reshape) { Node* address = in(MemNode::Address); Node* value = in(MemNode::ValueIn); // Back-to-back stores to same address? Fold em up. Generally - // unsafe if I have intervening uses... Also disallowed for StoreCM - // since they must follow each StoreP operation. Redundant StoreCMs - // are eliminated just before matching in final_graph_reshape. + // unsafe if I have intervening uses. { Node* st = mem; // If Store 'st' has more than one use, we cannot fold 'st' away. @@ -3474,7 +3472,7 @@ Node *StoreNode::Ideal(PhaseGVN *phase, bool can_reshape) { // require exactly ONE user until such time as we clone 'mem' for // each of 'mem's uses (thus making the exactly-1-user-rule hold // true). - while (st->is_Store() && st->outcnt() == 1 && st->Opcode() != Op_StoreCM) { + while (st->is_Store() && st->outcnt() == 1) { // Looking at a dead closed cycle of memory? assert(st != st->in(MemNode::Memory), "dead loop in StoreNode::Ideal"); assert(Opcode() == st->Opcode() || @@ -3781,48 +3779,6 @@ Node *StoreCNode::Ideal(PhaseGVN *phase, bool can_reshape){ return StoreNode::Ideal(phase, can_reshape); } -//============================================================================= -//------------------------------Identity--------------------------------------- -Node* StoreCMNode::Identity(PhaseGVN* phase) { - // No need to card mark when storing a null ptr - Node* my_store = in(MemNode::OopStore); - if (my_store->is_Store()) { - const Type *t1 = phase->type( my_store->in(MemNode::ValueIn) ); - if( t1 == TypePtr::NULL_PTR ) { - return in(MemNode::Memory); - } - } - return this; -} - -//============================================================================= -//------------------------------Ideal--------------------------------------- -Node *StoreCMNode::Ideal(PhaseGVN *phase, bool can_reshape){ - Node* progress = StoreNode::Ideal(phase, can_reshape); - if (progress != nullptr) return progress; - - Node* my_store = in(MemNode::OopStore); - if (my_store->is_MergeMem()) { - Node* mem = my_store->as_MergeMem()->memory_at(oop_alias_idx()); - set_req_X(MemNode::OopStore, mem, phase); - return this; - } - - return nullptr; -} - -//------------------------------Value----------------------------------------- -const Type* StoreCMNode::Value(PhaseGVN* phase) const { - // Either input is TOP ==> the result is TOP (checked in StoreNode::Value). - // If extra input is TOP ==> the result is TOP - const Type* t = phase->type(in(MemNode::OopStore)); - if (t == Type::TOP) { - return Type::TOP; - } - return StoreNode::Value(phase); -} - - //============================================================================= //----------------------------------SCMemProjNode------------------------------ const Type* SCMemProjNode::Value(PhaseGVN* phase) const diff --git a/src/hotspot/share/opto/memnode.hpp b/src/hotspot/share/opto/memnode.hpp index 323ab3dba7d65..1ca3a4b16ce1e 100644 --- a/src/hotspot/share/opto/memnode.hpp +++ b/src/hotspot/share/opto/memnode.hpp @@ -55,8 +55,7 @@ class MemNode : public Node { enum { Control, // When is it safe to do this load? Memory, // Chunk of memory is being loaded from Address, // Actually address, derived from base - ValueIn, // Value to store - OopStore // Preceding oop store, only in StoreCM + ValueIn // Value to store }; typedef enum { unordered = 0, acquire, // Load has to acquire or be succeeded by MemBarAcquire. @@ -777,36 +776,6 @@ class StoreNKlassNode : public StoreNNode { virtual BasicType memory_type() const { return T_NARROWKLASS; } }; -//------------------------------StoreCMNode----------------------------------- -// Store card-mark byte to memory for CM -// The last StoreCM before a SafePoint must be preserved and occur after its "oop" store -// Preceding equivalent StoreCMs may be eliminated. -class StoreCMNode : public StoreNode { - private: - virtual uint hash() const { return StoreNode::hash() + _oop_alias_idx; } - virtual bool cmp( const Node &n ) const { - return _oop_alias_idx == ((StoreCMNode&)n)._oop_alias_idx - && StoreNode::cmp(n); - } - virtual uint size_of() const { return sizeof(*this); } - int _oop_alias_idx; // The alias_idx of OopStore - -public: - StoreCMNode( Node *c, Node *mem, Node *adr, const TypePtr* at, Node *val, Node *oop_store, int oop_alias_idx ) : - StoreNode(c, mem, adr, at, val, oop_store, MemNode::release), - _oop_alias_idx(oop_alias_idx) { - assert(_oop_alias_idx >= Compile::AliasIdxRaw || - (_oop_alias_idx == Compile::AliasIdxBot && !Compile::current()->do_aliasing()), - "bad oop alias idx"); - } - virtual int Opcode() const; - virtual Node* Identity(PhaseGVN* phase); - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual const Type* Value(PhaseGVN* phase) const; - virtual BasicType memory_type() const { return T_VOID; } // unspecific - int oop_alias_idx() const { return _oop_alias_idx; } -}; - //------------------------------SCMemProjNode--------------------------------------- // This class defines a projection of the memory state of a store conditional node. // These nodes return a value, but also update memory. diff --git a/src/hotspot/share/opto/output.cpp b/src/hotspot/share/opto/output.cpp index eda0f65d6bc1f..2865cf674295b 100644 --- a/src/hotspot/share/opto/output.cpp +++ b/src/hotspot/share/opto/output.cpp @@ -1665,30 +1665,7 @@ void PhaseOutput::fill_buffer(C2_MacroAssembler* masm, uint* blk_starts) { } } } - } -#ifdef ASSERT - // Check that oop-store precedes the card-mark - else if (mach->ideal_Opcode() == Op_StoreCM) { - uint storeCM_idx = j; - int count = 0; - for (uint prec = mach->req(); prec < mach->len(); prec++) { - Node *oop_store = mach->in(prec); // Precedence edge - if (oop_store == nullptr) continue; - count++; - uint i4; - for (i4 = 0; i4 < last_inst; ++i4) { - if (block->get_node(i4) == oop_store) { - break; - } - } - // Note: This test can provide a false failure if other precedence - // edges have been added to the storeCMNode. - assert(i4 == last_inst || i4 < storeCM_idx, "CM card-mark executes before oop-store"); - } - assert(count > 0, "storeCM expects at least one precedence edge"); - } -#endif - else if (!n->is_Proj()) { + } else if (!n->is_Proj()) { // Remember the beginning of the previous instruction, in case // it's followed by a flag-kill and a null-check. Happens on // Intel all the time, with add-to-memory kind of opcodes. diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index bb5fed78b0274..20c8dfbff1776 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -657,9 +657,6 @@ void VLoopMemorySlices::get_slice_in_reverse_order(PhiNode* head, MemNode* tail, // or need to run igvn.optimize() again before SLP } else if (out->is_memory_phi() && !_vloop.in_bb(out)) { // Ditto. Not sure what else to check further. - } else if (out->Opcode() == Op_StoreCM && out->in(MemNode::OopStore) == n) { - // StoreCM has an input edge used as a precedence edge. - // Maybe an issue when oop stores are vectorized. } else { assert(out == prev || prev == nullptr, "no branches off of store slice"); } diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index e0a36330687dc..3060e225427a8 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -1590,7 +1590,6 @@ declare_c2_type(StorePNode, StoreNode) \ declare_c2_type(StoreNNode, StoreNode) \ declare_c2_type(StoreNKlassNode, StoreNode) \ - declare_c2_type(StoreCMNode, StoreNode) \ declare_c2_type(SCMemProjNode, ProjNode) \ declare_c2_type(LoadStoreNode, Node) \ declare_c2_type(CompareAndSwapNode, LoadStoreConditionalNode) \ From e9327b6e3c1fcc47ec790fa4e4019f7651a8f912 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Thu, 10 Oct 2024 14:32:32 +0000 Subject: [PATCH 013/118] 8339205: Optimize StackMapGenerator Reviewed-by: liach --- .../classfile/impl/StackMapGenerator.java | 434 +++++++++++++----- 1 file changed, 309 insertions(+), 125 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java index 9bd5084061a1d..3007c8ca40a7e 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java @@ -44,6 +44,7 @@ import java.util.Objects; import java.util.stream.Collectors; import jdk.internal.constant.ReferenceClassDescImpl; +import jdk.internal.constant.PrimitiveClassDescImpl; import jdk.internal.util.Preconditions; import static java.lang.classfile.ClassFile.*; @@ -349,6 +350,7 @@ private void removeRangeFromExcTable(int rangeStart, int rangeEnd) { var it = handlers.listIterator(); while (it.hasNext()) { var e = it.next(); + var labelContext = this.labelContext; int handlerStart = labelContext.labelToBci(e.tryStart()); int handlerEnd = labelContext.labelToBci(e.tryEnd()); if (rangeStart >= handlerEnd || rangeEnd <= handlerStart) { @@ -390,14 +392,15 @@ public Attribute stackMapTableAttribute() { return framesCount == 0 ? null : new UnboundAttribute.AdHocAttribute<>(Attributes.stackMapTable()) { @Override public void writeBody(BufWriterImpl b) { - b.writeU2(framesCount); - Frame prevFrame = new Frame(classHierarchy); - prevFrame.setLocalsFromArg(methodName, methodDesc, isStatic, thisType); + var gen = StackMapGenerator.this; + b.writeU2(gen.framesCount); + Frame prevFrame = gen.new Frame(gen.classHierarchy); + prevFrame.setLocalsFromArg(gen.methodName, gen.methodDesc, gen.isStatic, gen.thisType); prevFrame.trimAndCompress(); - for (int i = 0; i < framesCount; i++) { - var fr = frames[i]; + for (int i = 0; i < gen.framesCount; i++) { + var fr = gen.frames[i]; fr.trimAndCompress(); - fr.writeTo(b, prevFrame, cp); + fr.writeTo(b, prevFrame, gen.cp); prevFrame = fr; } } @@ -460,6 +463,7 @@ private boolean processBlock(RawBytecodeHelper bcs) { processExceptionHandlerTargets(bci, this_uninit); verified_exc_handlers = true; } + var currentFrame = this.currentFrame; switch (opcode) { case NOP -> {} case RETURN -> { @@ -500,27 +504,27 @@ private boolean processBlock(RawBytecodeHelper bcs) { case ALOAD_0, ALOAD_1, ALOAD_2, ALOAD_3 -> currentFrame.pushStack(currentFrame.getLocal(opcode - ALOAD_0)); case IALOAD, BALOAD, CALOAD, SALOAD -> - currentFrame.decStack(2).pushStack(Type.INTEGER_TYPE); + currentFrame.decStack2PushStack(Type.INTEGER_TYPE); case LALOAD -> - currentFrame.decStack(2).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); + currentFrame.decStack2PushStack(Type.LONG_TYPE, Type.LONG2_TYPE); case FALOAD -> - currentFrame.decStack(2).pushStack(Type.FLOAT_TYPE); + currentFrame.decStack2PushStack(Type.FLOAT_TYPE); case DALOAD -> - currentFrame.decStack(2).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); + currentFrame.decStack2PushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); case AALOAD -> - currentFrame.pushStack((type1 = currentFrame.decStack(1).popStack()) == Type.NULL_TYPE ? Type.NULL_TYPE : type1.getComponent()); + currentFrame.pushStack((type1 = currentFrame.decStack().popStack()) == Type.NULL_TYPE ? Type.NULL_TYPE : type1.getComponent()); case ISTORE -> - currentFrame.decStack(1).setLocal(bcs.getIndex(), Type.INTEGER_TYPE); + currentFrame.decStack().setLocal(bcs.getIndex(), Type.INTEGER_TYPE); case ISTORE_0, ISTORE_1, ISTORE_2, ISTORE_3 -> - currentFrame.decStack(1).setLocal(opcode - ISTORE_0, Type.INTEGER_TYPE); + currentFrame.decStack().setLocal(opcode - ISTORE_0, Type.INTEGER_TYPE); case LSTORE -> currentFrame.decStack(2).setLocal2(bcs.getIndex(), Type.LONG_TYPE, Type.LONG2_TYPE); case LSTORE_0, LSTORE_1, LSTORE_2, LSTORE_3 -> currentFrame.decStack(2).setLocal2(opcode - LSTORE_0, Type.LONG_TYPE, Type.LONG2_TYPE); case FSTORE -> - currentFrame.decStack(1).setLocal(bcs.getIndex(), Type.FLOAT_TYPE); + currentFrame.decStack().setLocal(bcs.getIndex(), Type.FLOAT_TYPE); case FSTORE_0, FSTORE_1, FSTORE_2, FSTORE_3 -> - currentFrame.decStack(1).setLocal(opcode - FSTORE_0, Type.FLOAT_TYPE); + currentFrame.decStack().setLocal(opcode - FSTORE_0, Type.FLOAT_TYPE); case DSTORE -> currentFrame.decStack(2).setLocal2(bcs.getIndex(), Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); case DSTORE_0, DSTORE_1, DSTORE_2, DSTORE_3 -> @@ -534,98 +538,75 @@ private boolean processBlock(RawBytecodeHelper bcs) { case IASTORE, BASTORE, CASTORE, SASTORE, FASTORE, AASTORE -> currentFrame.decStack(3); case POP, MONITORENTER, MONITOREXIT -> - currentFrame.decStack(1); + currentFrame.decStack(); case POP2 -> currentFrame.decStack(2); case DUP -> - currentFrame.pushStack(type1 = currentFrame.popStack()).pushStack(type1); - case DUP_X1 -> { - type1 = currentFrame.popStack(); - type2 = currentFrame.popStack(); - currentFrame.pushStack(type1).pushStack(type2).pushStack(type1); - } - case DUP_X2 -> { - type1 = currentFrame.popStack(); - type2 = currentFrame.popStack(); - type3 = currentFrame.popStack(); - currentFrame.pushStack(type1).pushStack(type3).pushStack(type2).pushStack(type1); - } - case DUP2 -> { - type1 = currentFrame.popStack(); - type2 = currentFrame.popStack(); - currentFrame.pushStack(type2).pushStack(type1).pushStack(type2).pushStack(type1); - } - case DUP2_X1 -> { - type1 = currentFrame.popStack(); - type2 = currentFrame.popStack(); - type3 = currentFrame.popStack(); - currentFrame.pushStack(type2).pushStack(type1).pushStack(type3).pushStack(type2).pushStack(type1); - } - case DUP2_X2 -> { - type1 = currentFrame.popStack(); - type2 = currentFrame.popStack(); - type3 = currentFrame.popStack(); - type4 = currentFrame.popStack(); - currentFrame.pushStack(type2).pushStack(type1).pushStack(type4).pushStack(type3).pushStack(type2).pushStack(type1); - } - case SWAP -> { - type1 = currentFrame.popStack(); - type2 = currentFrame.popStack(); - currentFrame.pushStack(type1); - currentFrame.pushStack(type2); - } + currentFrame.dup(); + case DUP_X1 -> + currentFrame.dup_x1(); + case DUP_X2 -> + currentFrame.dup_x2(); + case DUP2 -> + currentFrame.dup2(); + case DUP2_X1 -> + currentFrame.dup2_x1(); + case DUP2_X2 -> + currentFrame.dup2_x2(); + case SWAP -> + currentFrame.swap(); case IADD, ISUB, IMUL, IDIV, IREM, ISHL, ISHR, IUSHR, IOR, IXOR, IAND -> - currentFrame.decStack(2).pushStack(Type.INTEGER_TYPE); + currentFrame.decStack2PushStack(Type.INTEGER_TYPE); case INEG, ARRAYLENGTH, INSTANCEOF -> - currentFrame.decStack(1).pushStack(Type.INTEGER_TYPE); + currentFrame.decStack1PushStack(Type.INTEGER_TYPE); case LADD, LSUB, LMUL, LDIV, LREM, LAND, LOR, LXOR -> - currentFrame.decStack(4).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); + currentFrame.decStack4PushStack(Type.LONG_TYPE, Type.LONG2_TYPE); case LNEG -> - currentFrame.decStack(2).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); + currentFrame.decStack2PushStack(Type.LONG_TYPE, Type.LONG2_TYPE); case LSHL, LSHR, LUSHR -> - currentFrame.decStack(3).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); + currentFrame.decStack3PushStack(Type.LONG_TYPE, Type.LONG2_TYPE); case FADD, FSUB, FMUL, FDIV, FREM -> - currentFrame.decStack(2).pushStack(Type.FLOAT_TYPE); + currentFrame.decStack2PushStack(Type.FLOAT_TYPE); case FNEG -> - currentFrame.decStack(1).pushStack(Type.FLOAT_TYPE); + currentFrame.decStack1PushStack(Type.FLOAT_TYPE); case DADD, DSUB, DMUL, DDIV, DREM -> - currentFrame.decStack(4).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); + currentFrame.decStack4PushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); case DNEG -> - currentFrame.decStack(2).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); + currentFrame.decStack2PushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); case IINC -> currentFrame.checkLocal(bcs.getIndex()); case I2L -> - currentFrame.decStack(1).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); + currentFrame.decStack1PushStack(Type.LONG_TYPE, Type.LONG2_TYPE); case L2I -> - currentFrame.decStack(2).pushStack(Type.INTEGER_TYPE); + currentFrame.decStack2PushStack(Type.INTEGER_TYPE); case I2F -> - currentFrame.decStack(1).pushStack(Type.FLOAT_TYPE); + currentFrame.decStack1PushStack(Type.FLOAT_TYPE); case I2D -> - currentFrame.decStack(1).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); + currentFrame.decStack1PushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); case L2F -> - currentFrame.decStack(2).pushStack(Type.FLOAT_TYPE); + currentFrame.decStack2PushStack(Type.FLOAT_TYPE); case L2D -> - currentFrame.decStack(2).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); + currentFrame.decStack2PushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); case F2I -> - currentFrame.decStack(1).pushStack(Type.INTEGER_TYPE); + currentFrame.decStack1PushStack(Type.INTEGER_TYPE); case F2L -> - currentFrame.decStack(1).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); + currentFrame.decStack1PushStack(Type.LONG_TYPE, Type.LONG2_TYPE); case F2D -> - currentFrame.decStack(1).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); + currentFrame.decStack1PushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); case D2L -> - currentFrame.decStack(2).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); + currentFrame.decStack2PushStack(Type.LONG_TYPE, Type.LONG2_TYPE); case D2F -> - currentFrame.decStack(2).pushStack(Type.FLOAT_TYPE); + currentFrame.decStack2PushStack(Type.FLOAT_TYPE); case I2B, I2C, I2S -> - currentFrame.decStack(1).pushStack(Type.INTEGER_TYPE); + currentFrame.decStack1PushStack(Type.INTEGER_TYPE); case LCMP, DCMPL, DCMPG -> - currentFrame.decStack(4).pushStack(Type.INTEGER_TYPE); + currentFrame.decStack4PushStack(Type.INTEGER_TYPE); case FCMPL, FCMPG, D2I -> - currentFrame.decStack(2).pushStack(Type.INTEGER_TYPE); + currentFrame.decStack2PushStack(Type.INTEGER_TYPE); case IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE -> checkJumpTarget(currentFrame.decStack(2), bcs.dest()); case IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IFNULL, IFNONNULL -> - checkJumpTarget(currentFrame.decStack(1), bcs.dest()); + checkJumpTarget(currentFrame.decStack(), bcs.dest()); case GOTO -> { checkJumpTarget(currentFrame, bcs.dest()); ncf = true; @@ -643,7 +624,7 @@ private boolean processBlock(RawBytecodeHelper bcs) { ncf = true; } case IRETURN, FRETURN, ARETURN, ATHROW -> { - currentFrame.decStack(1); + currentFrame.decStack(); ncf = true; } case GETSTATIC, PUTSTATIC, GETFIELD, PUTFIELD -> @@ -653,17 +634,16 @@ private boolean processBlock(RawBytecodeHelper bcs) { case NEW -> currentFrame.pushStack(Type.uninitializedType(bci)); case NEWARRAY -> - currentFrame.decStack(1).pushStack(getNewarrayType(bcs.getIndex())); + currentFrame.decStack1PushStack(getNewarrayType(bcs.getIndex())); case ANEWARRAY -> processAnewarray(bcs.getIndexU2()); case CHECKCAST -> - currentFrame.decStack(1).pushStack(cpIndexToType(bcs.getIndexU2(), cp)); + currentFrame.decStack1PushStack(cpIndexToType(bcs.getIndexU2(), cp)); case MULTIANEWARRAY -> { type1 = cpIndexToType(bcs.getIndexU2(), cp); - int dim = bcs.getU1Unchecked(bcs.bci() + 3); - for (int i = 0; i < dim; i++) { - currentFrame.popStack(); - } + currentFrame.decStack( + bcs.getU1Unchecked(bcs.bci() + 3) /* dim */ + ); currentFrame.pushStack(type1); } case JSR, JSR_W, RET -> @@ -678,6 +658,7 @@ private boolean processBlock(RawBytecodeHelper bcs) { } private void processExceptionHandlerTargets(int bci, boolean this_uninit) { + var currentFrame = this.currentFrame; for (var ex : rawHandlers) { if (bci == ex.start || (currentFrame.localsChanged && bci > ex.start && bci < ex.end)) { int flags = currentFrame.flags; @@ -690,7 +671,10 @@ private void processExceptionHandlerTargets(int bci, boolean this_uninit) { } private void processLdc(int index) { - switch (cp.entryByIndex(index).tag()) { + var e = cp.entryByIndex(index); + byte tag = e.tag(); + var currentFrame = this.currentFrame; + switch (tag) { case TAG_UTF8 -> currentFrame.pushStack(Type.OBJECT_TYPE); case TAG_STRING -> @@ -710,9 +694,9 @@ private void processLdc(int index) { case TAG_METHOD_TYPE -> currentFrame.pushStack(Type.METHOD_TYPE); case TAG_DYNAMIC -> - currentFrame.pushStack(cp.entryByIndex(index, ConstantDynamicEntry.class).asSymbol().constantType()); + currentFrame.pushStack(ClassReaderImpl.checkType(e, index, ConstantDynamicEntry.class).asSymbol().constantType()); default -> - throw generatorError("CP entry #%d %s is not loadable constant".formatted(index, cp.entryByIndex(index).tag())); + throw generatorError("CP entry #%d %s is not loadable constant".formatted(index, tag)); } } @@ -721,7 +705,7 @@ private void processSwitch(RawBytecodeHelper bcs) { int alignedBci = RawBytecodeHelper.align(bci + 1); int defaultOffset = bcs.getIntUnchecked(alignedBci); int keys, delta; - currentFrame.popStack(); + currentFrame.decStack(); if (bcs.opcode() == TABLESWITCH) { int low = bcs.getIntUnchecked(alignedBci + 4); int high = bcs.getIntUnchecked(alignedBci + 2 * 4); @@ -765,8 +749,7 @@ private void processFieldInstructions(RawBytecodeHelper bcs) { currentFrame.decStack(Util.isDoubleSlot(desc) ? 2 : 1); } case GETFIELD -> { - currentFrame.decStack(1); - currentFrame.pushStack(desc); + currentFrame.dec1PushStack(desc); } case PUTFIELD -> { currentFrame.decStack(Util.isDoubleSlot(desc) ? 3 : 2); @@ -804,7 +787,7 @@ private boolean processInvokeInstructions(RawBytecodeHelper bcs, boolean inTryBl throw generatorError("Bad operand type when invoking "); } } else { - currentFrame.decStack(1); + currentFrame.decStack(); } } currentFrame.pushStack(mDesc.returnType()); @@ -817,10 +800,17 @@ private Type getNewarrayType(int index) { } private void processAnewarray(int index) { - currentFrame.popStack(); + currentFrame.decStack(); currentFrame.pushStack(cpIndexToType(index, cp).toArray()); } + /** + * {@return the generator error with stack underflow} + */ + private IllegalArgumentException stackUnderflow() { + return generatorError("Operand stack underflow"); + } + /** * {@return the generator error with attached details} * @param msg error message @@ -900,6 +890,7 @@ private void detectFrames() { } catch (IllegalArgumentException iae) { throw generatorError("Detected branch target out of bytecode range", bci); } + for (int i = 0; i < rawHandlers.size(); i++) try { addFrame(rawHandlers.get(i).handler()); } catch (IllegalArgumentException iae) { @@ -968,44 +959,214 @@ public String toString() { return (dirty ? "frame* @" : "frame @") + offset + " with locals " + (locals == null ? "[]" : Arrays.asList(locals).subList(0, localsSize)) + " and stack " + (stack == null ? "[]" : Arrays.asList(stack).subList(0, stackSize)); } + Frame dup() { + int stackSize = this.stackSize; + if (stackSize < 1) throw stackUnderflow(); + checkStack(stackSize + 1); + stack[stackSize] = stack[stackSize - 1]; + this.stackSize = stackSize + 1; + return this; + } + + Frame dup_x1() { + int stackSize = this.stackSize; + if (stackSize < 2) throw stackUnderflow(); + checkStack(stackSize + 1); + var stack = this.stack; + Type type0 = stack[stackSize - 2]; + Type type1 = stack[stackSize - 1]; + stack[stackSize - 2] = type1; + stack[stackSize - 1] = type0; + stack[stackSize ] = type1; + this.stackSize = stackSize + 1; + return this; + } + + Frame dup_x2() { + int stackSize = this.stackSize; + if (stackSize < 3) throw stackUnderflow(); + checkStack(stackSize + 1); + var stack = this.stack; + Type type0 = stack[stackSize - 3]; + Type type1 = stack[stackSize - 2]; + Type type2 = stack[stackSize - 1]; + stack[stackSize - 3] = type2; + stack[stackSize - 2] = type0; + stack[stackSize - 1] = type1; + stack[stackSize ] = type2; + this.stackSize = stackSize + 1; + return this; + } + + Frame dup2() { + int stackSize = this.stackSize; + if (stackSize < 2) throw stackUnderflow(); + checkStack(stackSize + 2); + stack[stackSize ] = stack[stackSize - 2]; + stack[stackSize + 1] = stack[stackSize - 1]; + this.stackSize = stackSize + 2; + return this; + } + + Frame dup2_x1() { + int stackSize = this.stackSize; + if (stackSize < 3) throw stackUnderflow(); + checkStack(stackSize + 2); + var stack = this.stack; + Type type0 = stack[stackSize - 3]; + Type type1 = stack[stackSize - 2]; + Type type2 = stack[stackSize - 1]; + stack[stackSize - 3] = type1; + stack[stackSize - 2] = type2; + stack[stackSize - 1] = type0; + stack[stackSize ] = type1; + stack[stackSize + 1] = type2; + this.stackSize = stackSize + 2; + return this; + } + + Frame dup2_x2() { + int stackSize = this.stackSize; + if (stackSize < 4) throw stackUnderflow(); + checkStack(stackSize + 2); + var stack = this.stack; + Type type0 = stack[stackSize - 4]; + Type type1 = stack[stackSize - 3]; + Type type2 = stack[stackSize - 2]; + Type type3 = stack[stackSize - 1]; + stack[stackSize - 4] = type2; + stack[stackSize - 3] = type3; + stack[stackSize - 2] = type0; + stack[stackSize - 1] = type1; + stack[stackSize ] = type2; + stack[stackSize + 1] = type3; + this.stackSize = stackSize + 4; + return this; + } + + Frame swap() { + int stackSize = this.stackSize - 2; + if (stackSize < 0) throw stackUnderflow(); + var stack = this.stack; + Type type = stack[stackSize]; + stack[stackSize] = stack[stackSize + 1]; + stack[stackSize + 1] = type; + return this; + } + Frame pushStack(ClassDesc desc) { - return switch (desc.descriptorString().charAt(0)) { - case 'J' -> - pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); - case 'D' -> - pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); - case 'I', 'Z', 'B', 'C', 'S' -> - pushStack(Type.INTEGER_TYPE); - case 'F' -> - pushStack(Type.FLOAT_TYPE); - case 'V' -> - this; - default -> - pushStack(Type.referenceType(desc)); - }; + if (desc == CD_long) return pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); + if (desc == CD_double) return pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); + return desc == CD_void ? this + : pushStack( + desc instanceof PrimitiveClassDescImpl + ? (desc == CD_float ? Type.FLOAT_TYPE : Type.INTEGER_TYPE) + : Type.referenceType(desc)); + } + + Frame dec1PushStack(ClassDesc desc) { + if (desc == CD_long) return decStack1PushStack(Type.LONG_TYPE, Type.LONG2_TYPE); + if (desc == CD_double) return decStack1PushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); + return desc == CD_void ? this + : decStack1PushStack( + desc instanceof PrimitiveClassDescImpl + ? (desc == CD_float ? Type.FLOAT_TYPE : Type.INTEGER_TYPE) + : Type.referenceType(desc)); } Frame pushStack(Type type) { + int stackSize = this.stackSize; checkStack(stackSize); - stack[stackSize++] = type; + stack[stackSize] = type; + this.stackSize = stackSize + 1; return this; } Frame pushStack(Type type1, Type type2) { + int stackSize = this.stackSize; checkStack(stackSize + 1); - stack[stackSize++] = type1; - stack[stackSize++] = type2; + stack[stackSize] = type1; + stack[stackSize + 1] = type2; + this.stackSize = stackSize + 2; return this; } Type popStack() { - if (stackSize < 1) throw generatorError("Operand stack underflow"); - return stack[--stackSize]; + int stackSize = this.stackSize - 1; + if (stackSize < 0) throw stackUnderflow(); + this.stackSize = stackSize; + return stack[stackSize]; + } + + Frame decStack() { + if (--stackSize < 0) throw stackUnderflow(); + return this; } Frame decStack(int size) { stackSize -= size; - if (stackSize < 0) throw generatorError("Operand stack underflow"); + if (stackSize < 0) throw stackUnderflow(); + return this; + } + + Frame decStack1PushStack(Type type1, Type type2) { + int stackSize = this.stackSize - 1; + if (stackSize < 0) throw stackUnderflow(); + checkStack(stackSize + 2); + stack[stackSize ] = type1; + stack[stackSize + 1] = type2; + this.stackSize = stackSize + 2; + return this; + } + + Frame decStack1PushStack(Type type) { + int stackSize = this.stackSize - 1; + if (stackSize < 0) throw stackUnderflow(); + stack[stackSize] = type; + return this; + } + + Frame decStack2PushStack(Type type) { + int stackSize = this.stackSize - 2; + if (stackSize < 0) throw stackUnderflow(); + stack[stackSize] = type; + this.stackSize = stackSize + 1; + return this; + } + + Frame decStack2PushStack(Type type1, Type type2) { + int stackSize = this.stackSize - 2; + if (stackSize < 0) throw stackUnderflow(); + var stack = this.stack; + stack[stackSize ] = type1; + stack[stackSize + 1] = type2; + return this; + } + + Frame decStack3PushStack(Type type1, Type type2) { + int stackSize = this.stackSize - 3; + if (stackSize < 0) throw stackUnderflow(); + stack[stackSize ] = type1; + stack[stackSize + 1] = type2; + this.stackSize = stackSize + 2; + return this; + } + + Frame decStack4PushStack(Type type) { + int stackSize = this.stackSize - 4; + if (stackSize < 0) throw stackUnderflow(); + stack[stackSize] = type; + this.stackSize = stackSize + 1; + return this; + } + + Frame decStack4PushStack(Type type1, Type type2) { + int stackSize = this.stackSize - 4; + if (stackSize < 0) throw stackUnderflow(); + var stack = this.stack; + stack[stackSize ] = type1; + stack[stackSize + 1] = type2; + this.stackSize = stackSize + 2; return this; } @@ -1034,34 +1195,59 @@ void initializeObject(Type old_object, Type new_object) { Frame checkLocal(int index) { if (index >= frameMaxLocals) frameMaxLocals = index + 1; if (locals == null) { - locals = new Type[index + FRAME_DEFAULT_CAPACITY]; - Arrays.fill(locals, Type.TOP_TYPE); + initLocals(index); } else if (index >= locals.length) { - int current = locals.length; - locals = Arrays.copyOf(locals, index + FRAME_DEFAULT_CAPACITY); - Arrays.fill(locals, current, locals.length, Type.TOP_TYPE); + growLocals(index); } return this; } + private void initLocals(int index) { + locals = new Type[index + FRAME_DEFAULT_CAPACITY]; + Arrays.fill(locals, Type.TOP_TYPE); + } + + private void growLocals(int index) { + int current = locals.length; + locals = Arrays.copyOf(locals, index + FRAME_DEFAULT_CAPACITY); + Arrays.fill(locals, current, locals.length, Type.TOP_TYPE); + } + private void checkStack(int index) { if (index >= frameMaxStack) frameMaxStack = index + 1; if (stack == null) { - stack = new Type[index + FRAME_DEFAULT_CAPACITY]; - Arrays.fill(stack, Type.TOP_TYPE); + initStack(index); } else if (index >= stack.length) { - int current = stack.length; - stack = Arrays.copyOf(stack, index + FRAME_DEFAULT_CAPACITY); - Arrays.fill(stack, current, stack.length, Type.TOP_TYPE); + growStack(index); } } + private void initStack(int index) { + stack = new Type[index + FRAME_DEFAULT_CAPACITY]; + Arrays.fill(stack, Type.TOP_TYPE); + } + + private void growStack(int index) { + int current = stack.length; + stack = Arrays.copyOf(stack, index + FRAME_DEFAULT_CAPACITY); + Arrays.fill(stack, current, stack.length, Type.TOP_TYPE); + } + private void setLocalRawInternal(int index, Type type) { checkLocal(index); + var locals = this.locals; localsChanged |= !type.equals(locals[index]); locals[index] = type; } + private void setLocalRawInternal(int index, Type type1, Type type2) { + checkLocal(index + 1); + var locals = this.locals; + localsChanged |= !type1.equals(locals[index]) || !type2.equals(locals[index + 1]); + locals[index ] = type1; + locals[index + 1] = type2; + } + void setLocalsFromArg(String name, MethodTypeDesc methodDesc, boolean isStatic, Type thisKlass) { int localsSize = 0; // Pre-emptively create a locals array that encompass all parameter slots @@ -1162,8 +1348,7 @@ void setLocal(int index, Type type) { Type old = getLocalRawInternal(index); if (old == Type.DOUBLE_TYPE || old == Type.LONG_TYPE) { setLocalRawInternal(index + 1, Type.TOP_TYPE); - } - if (old == Type.DOUBLE2_TYPE || old == Type.LONG2_TYPE) { + } else if (old == Type.DOUBLE2_TYPE || old == Type.LONG2_TYPE) { setLocalRawInternal(index - 1, Type.TOP_TYPE); } setLocalRawInternal(index, type); @@ -1181,8 +1366,7 @@ void setLocal2(int index, Type type1, Type type2) { if (old == Type.DOUBLE2_TYPE || old == Type.LONG2_TYPE) { setLocalRawInternal(index - 1, Type.TOP_TYPE); } - setLocalRawInternal(index, type1); - setLocalRawInternal(index + 1, type2); + setLocalRawInternal(index, type1, type2); if (index >= localsSize - 1) { localsSize = index + 2; } From 6e0138450ab4b0af917cbf61701b0d1d17eeaa44 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Thu, 10 Oct 2024 15:13:39 +0000 Subject: [PATCH 014/118] 8341136: Optimize StackMapGenerator::trimAndCompress Reviewed-by: liach --- .../jdk/internal/classfile/impl/StackMapGenerator.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java index 3007c8ca40a7e..4bc4e259f5a52 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java @@ -1387,7 +1387,10 @@ private static int trimAndCompress(Type[] types, int count) { int compressed = 0; for (int i = 0; i < count; i++) { if (!types[i].isCategory2_2nd()) { - types[compressed++] = types[i]; + if (compressed != i) { + types[compressed] = types[i]; + } + compressed++; } } return compressed; From 2d8fcc4271802b211c4718c6abae3ce9c99eafbd Mon Sep 17 00:00:00 2001 From: Tejesh R Date: Thu, 10 Oct 2024 15:34:39 +0000 Subject: [PATCH 015/118] 8340193: Open source several AWT Dialog tests - Batch 1 Reviewed-by: psadhukhan --- .../Dialog/DialogIconTest/DialogIconTest.java | 91 ++++++ .../awt/Dialog/DialogIconTest/swing.small.gif | Bin 0 -> 1136 bytes .../jdk/java/awt/Dialog/DialogResizeTest.java | 118 ++++++++ .../FileDialogIconTest.java | 258 ++++++++++++++++++ .../java/awt/Dialog/FileDialogIconTest/T1.gif | Bin 0 -> 2553 bytes .../java/awt/Dialog/FileDialogIconTest/T2.gif | Bin 0 -> 2704 bytes .../java/awt/Dialog/FileDialogIconTest/T3.gif | Bin 0 -> 2523 bytes .../java/awt/Dialog/FileDialogIconTest/T4.gif | Bin 0 -> 2721 bytes .../Dialog/FileDialogIconTest/loading-msg.gif | Bin 0 -> 1518 bytes .../awt/Dialog/FileDialogWrongNameCrash.java | 72 +++++ .../java/awt/Dialog/GetLocationTest_1.java | 129 +++++++++ 11 files changed, 668 insertions(+) create mode 100644 test/jdk/java/awt/Dialog/DialogIconTest/DialogIconTest.java create mode 100644 test/jdk/java/awt/Dialog/DialogIconTest/swing.small.gif create mode 100644 test/jdk/java/awt/Dialog/DialogResizeTest.java create mode 100644 test/jdk/java/awt/Dialog/FileDialogIconTest/FileDialogIconTest.java create mode 100644 test/jdk/java/awt/Dialog/FileDialogIconTest/T1.gif create mode 100644 test/jdk/java/awt/Dialog/FileDialogIconTest/T2.gif create mode 100644 test/jdk/java/awt/Dialog/FileDialogIconTest/T3.gif create mode 100644 test/jdk/java/awt/Dialog/FileDialogIconTest/T4.gif create mode 100644 test/jdk/java/awt/Dialog/FileDialogIconTest/loading-msg.gif create mode 100644 test/jdk/java/awt/Dialog/FileDialogWrongNameCrash.java create mode 100644 test/jdk/java/awt/Dialog/GetLocationTest_1.java diff --git a/test/jdk/java/awt/Dialog/DialogIconTest/DialogIconTest.java b/test/jdk/java/awt/Dialog/DialogIconTest/DialogIconTest.java new file mode 100644 index 0000000000000..06debe28fc551 --- /dev/null +++ b/test/jdk/java/awt/Dialog/DialogIconTest/DialogIconTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * 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.Dialog; +import java.awt.Frame; +import java.awt.Image; +import java.awt.Label; +import java.awt.MediaTracker; +import java.awt.Toolkit; +import java.awt.Window; +import java.util.List; + +/* + * @test + * @bug 4779641 + * @summary Test to verify that Non-resizable dialogs should not show icons + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DialogIconTest + */ + +public class DialogIconTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. This is a Windows-only test of Dialog icons + 2. You can see a frame with a swing icon and two dialogs that it + owns. The resizable dialog should have the same icon as the + frame. The non-resizable dialog should have no icon at all + 3. Press PASS if this is true, press FAIL otherwise + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .build() + .awaitAndCheck(); + } + + public static List initialize() { + Frame f = new Frame("Parent frame"); + f.setBounds(50, 50, 200, 200); + + Dialog dr = new Dialog(f, "Resizable Dialog"); + dr.setLocation(100, 100); + dr.add(new Label("Should inherit icon from parent")); + dr.pack(); + + Dialog dn = new Dialog(f, "NON Resizable Dialog"); + dn.setLocation(150, 150); + dn.add(new Label("Should have no icon")); + dn.pack(); + dn.setResizable(false); + + String fileName = System.getProperty("test.src") + + System.getProperty("file.separator") + "swing.small.gif"; + + Image icon = Toolkit.getDefaultToolkit().createImage(fileName); + MediaTracker tracker = new MediaTracker(f); + tracker.addImage(icon, 0); + try { + tracker.waitForAll(); + } catch (InterruptedException ie) { + throw new RuntimeException("MediaTracker addImage Interrupted!"); + } + f.setIconImage(icon); + return List.of(f, dn, dr); + } +} diff --git a/test/jdk/java/awt/Dialog/DialogIconTest/swing.small.gif b/test/jdk/java/awt/Dialog/DialogIconTest/swing.small.gif new file mode 100644 index 0000000000000000000000000000000000000000..14a489ff4e7df0b4a268582701a1e7ef655047fa GIT binary patch literal 1136 zcmV-$1dsbiNk%w1VL$*t0QCR>_xJa}z`*bC@8{>|*4EagrKOCFjD&=QeSLjeT3Tac zW0aJXwY9ZrX=zeYQZX?xDJdx!7#Ii$2mk;85D*X{AtA=b#@^oEb8~Y_N=iaPLanW> zoSdAhs;ZWjmSb94)6>&TOiV%u7-I+_F&GGx5HWKYDV!lftvOoo@bFR?5PKL1jD&=* zudk()gq(X?j9M{!N-29vA%ts6b5c2DLLr=lbG@aU|Ns9|LNQt~5K=J^LLmrBDF{+2 z5IG?TA^8LW00031EC2ui06+jh000L5z<_W_EE5BEk63?u2XB#Ki+2bU6B-(+VV7|Ys1pivl9>%6B$wrjDnqEyr{Dp!$}Mc z5q+OT$x<1{$I(T95vY$GhC{0riB}G>s0vLRtEdn~23A8DvlIaa4GtL%!A%USvl8w~ z2qch8P-K)KW8_eUW0I!9g9!wcFqoEb;ie)R5+;1`Pv3(G8?13CmawCiA__Dnl=oy` zL?i|TYGgU&3y}laRFZ?jL4p1+m^x_{DK%uAN}0N#EWq&72!^1&3O<^qVUYm?9MEuB zB>~C-bVnLcpddkni4h`@HYjpS2!{#glyzj1NkP6%5dt(AQKD~&6EYW`^j1sFEezcP z9FV{O2L!);Q+Pm?j{zGY4Io&f(w4&k&k{HQ!0`ie2^1(qOxVWAK!wdyo(b7Ep#hHD z8CI+?o%Ye?1r+Xv;Z_8~g8{d3bReM{@`MTn11zW@oK!vx5(p&60RRE>z9vW{m4g6T zAXfo6gx;RKfQAYxG;GMQZU}=1l?)SkpkXxo+W`27Lk5M-lYvF1z_Azz|1~(^I^2*^ zoqlIjfPjDwCKtj4bN-}(-X4FXVL$}hWyoF#_3@!e05$~x0S6}jmqSw*X)?)l7sSZk zjP@ZIM>_#zfB|wkCYM79LrkK{8w|WwLkzIM!~WoH0h(A==?pdK;DgH_f84{v zJVYF@nJd~?K)E!u{IbVA$jrmc5r2>~6D_z images; + static String fileBase; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Select the Image for a Dialog and Frame using either + Load/Save/Just Dialog. + 2. Set the Icon Image/s to Frame and Dialog. Verify that the + Icon is set for the respective Frame and Dialog. + If selected Icon is set to Frame and Dialog press PASS + else FAIL. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .logArea(8) + .build() + .awaitAndCheck(); + } + + public static void setImagesToFD(java.util.List listIcon) { + FileDialogIconTest.images = listIcon; + } + + public static void setImagesToFrame(java.util.List listIcon) { + frame.setIconImages(listIcon); + } + + public static void setImageToFD(Image img) { + FileDialogIconTest.image = img; + } + + public static void setImageToFrame(Image img) { + frame.setIconImage(img); + } + + public static Frame initialize() { + frame = new Frame("FileDialogIconTest"); + Button setImageButton1 = new Button("setIconImageToFrame"); + Button setImageButton2 = new Button("setIconImageToDialog"); + Button setImageButton3 = new Button("setIconImagesToFrame"); + Button setImageButton4 = new Button("setIconImagesToDialog"); + Button setImageButton5 = new Button("setIconBufferedImagesToDialog"); + Button setImageButton6 = new Button("setIconBufferedImagesToFrame"); + + if (System.getProperty("test.src") == null) { + fileBase = ""; + } else { + fileBase = System.getProperty("test.src") + System.getProperty("file.separator"); + } + + final String fileName = fileBase + "loading-msg.gif"; + + setImageButton1.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + try { + Image image = Toolkit.getDefaultToolkit().getImage(fileName); + setImageToFrame(image); + PassFailJFrame.log("Loaded image . setting to frame"); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + + setImageButton2.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + try { + Image image = Toolkit.getDefaultToolkit().getImage(fileName); + setImageToFD(image); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + + setImageButton3.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + try { + Image image; + java.util.List list = new java.util.ArrayList(); + for (int i = 1; i <= 4; i++) { + String fileName = fileBase + "T" + i + ".gif"; + image = Toolkit.getDefaultToolkit().getImage(fileName); + PassFailJFrame.log("Loaded image " + fileName + ". setting to the list for frame"); + list.add(image); + } + setImagesToFrame(list); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + + + setImageButton4.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + try { + Image image; + List list = new ArrayList<>(); + for (int i = 1; i <= 4; i++) { + String fileName = fileBase + "T" + i + ".gif"; + image = Toolkit.getDefaultToolkit().getImage(fileName); + PassFailJFrame.log("Loaded image " + fileName + ". setting to the list for dialog"); + list.add(image); + } + setImagesToFD(list); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + + + setImageButton5.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + List list = new ArrayList<>(); + try { + Robot robot = new Robot(); + Rectangle rectangle; + for (int i = 1; i <= 4; i++) { + rectangle = new Rectangle(i * 10, i * 10, i * 10 + 40, i * 10 + 40); + java.awt.image.BufferedImage image = robot.createScreenCapture(rectangle); + robot.delay(100); + list.add(image); + } + } catch (Throwable t) { + t.printStackTrace(); + } + PassFailJFrame.log("Captured images and set to the list for dialog"); + } + }); + + setImageButton6.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + List list = new ArrayList<>(); + try { + Robot robot = new Robot(); + Rectangle rectangle; + for (int i = 1; i <= 4; i++) { + rectangle = new Rectangle(i * 10, i * 10, i * 10 + 40, i * 10 + 40); + java.awt.image.BufferedImage image = robot.createScreenCapture(rectangle); + robot.delay(100); + list.add(image); + } + } catch (Throwable t) { + t.printStackTrace(); + } + PassFailJFrame.log("Captured images and set to the list for frame"); + } + }); + + Button buttonLoad = new Button("Load Dialog"); + Button buttonSave = new Button("Save Dialog"); + Button buttonSimple = new Button("Just Dialog"); + buttonLoad.addActionListener(new MyActionListener(FileDialog.LOAD, "LOAD")); + buttonSave.addActionListener(new MyActionListener(FileDialog.SAVE, "SAVE")); + buttonSimple.addActionListener(new MyActionListener(-1, "")); + + frame.setSize(400, 400); + frame.setLayout(new FlowLayout()); + frame.add(buttonLoad); + frame.add(buttonSave); + frame.add(buttonSimple); + frame.add(setImageButton1); + frame.add(setImageButton2); + frame.add(setImageButton3); + frame.add(setImageButton4); + frame.pack(); + return frame; + } +} + +class MyActionListener implements ActionListener { + int id; + String name; + + public MyActionListener(int id, String name) { + this.id = id; + this.name = name; + } + + public void actionPerformed(ActionEvent ae) { + try { + FileDialog filedialog; + if (id == -1 && Objects.equals(name, "")) { + filedialog = new FileDialog(FileDialogIconTest.frame); + } else { + filedialog = new FileDialog(FileDialogIconTest.frame, name, id); + } + if (FileDialogIconTest.image != null) { + filedialog.setIconImage(FileDialogIconTest.image); + } + + if (FileDialogIconTest.images != null) { + filedialog.setIconImages(FileDialogIconTest.images); + } + filedialog.setVisible(true); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/test/jdk/java/awt/Dialog/FileDialogIconTest/T1.gif b/test/jdk/java/awt/Dialog/FileDialogIconTest/T1.gif new file mode 100644 index 0000000000000000000000000000000000000000..24a7dea299fd1c877792ce09a5b64d1f57c1b323 GIT binary patch literal 2553 zcmVUj1S&E~Ljg3aD)&M9tGcT}~(d!To zlU7%}Yinx^3Su-gH3WCA1!a_IXvTzu&NP_DCyBIcy4y`oPqntT1%$p&YjviUU=Ge8LEq* zb)s9PMTG?}I-MCfA~Ole$_X>g%@sGbxw?`uzCx!AoW;w@&fm}96$a9YyOWh#hqw+I zBHhmw@&@$uE%*2>755Xj7CL?cS#y&G2OV7Qmd%)V!@z_I6evJ^NKuBpd@cI@i_{Cu zsbRSYC>(bqB83ttA*fVY;=uz95oJuUSdX5G40j}vqLL+tF#kpj-g$!tG3AD%NRw_@ z=@Nqg8Bk@kusFd4ADvaQ1Ow^7#WJENAs_`nmh1)qAI>IK`Je;_3>Krxw8{W0A%k3T zD4TJksMxb*(SG>Afy3azC)Pq}`c$qA3axliio)jSBE89=MHEZ+0DvAJB7hhTB7$hs z3pgwojFj!$#!(^vVIxJ3w#!2eoCHiZGzbY2NSj8zVEBU6BhtEd+W0AjKck??aluF= zvkDM7fBx`0cxmFteHN03RJ;JOUpGAV5Qa z0s`oRcnFSQ!%~brr5*+**tG-~hb*!JG7H(q*#Q}JSO3}q2LdP{4J6XgL5T$Z_uqjd zFqoct0=z}Qdjn0l&LZz*NP%|x1=rt!0(KzekVF!RVu~Z6$6SmUJg~-OSjYjANHd6_ z8;`)D24Im~c6lO+1k#{jQ_Q{fz$+bLaYzpiSa8ff6p#Q|k3W)Fqyj=Jfajih771p6 z11|PfnN5xYr4bZP`AkG}`Uql>TwFehFR;73fO?F znGl$8=r3|?VnGEuLO>P=sfH=ual@5sZgJ!R3IAxVdY%BmYcW2ck_e!Rn!!T4m2m25 z2evAnY2J+%oCM~c8y=w0;%UQ@Z>dCpnzsQv&afP4=`X;*k--BG9(aI44Fe2NgU2ZF zV8#ypJv!^8LPFqRlk$>q?GV0NaKkwEor_-s_;l3!)!h{0S65)$my& zNI(5LE7X(o2P1%}Dwj1F+0b;*f#Zct1BobI$ZFsK8VF5*pGzClNZ>pSa0Ul3$RN#v z!3ui#Wdr>K(6cJlffppg0xQr{3Kr;q(BUZr3oKrn7y&v7HlPC~sNe-NXuls&F9X(t z$O9@TqGzS8eI4+@09}YD2ZoFV#RDDtQs=(nQBZz6)F2$T0z~=U#|9(lml4x;A|LcE zWK6^p0$@0R5a=n5%X^~&C};o~$p4Eh1>oTZ8L)y3Kt+fp03(6=q&gD*X91dXBNCBS zfT0ENh=zM(14u9v8CZ}kI0%3ifABau__2-@kQW5PI3OZj>X17i8q+XWoCxq>XewaZ z4Gp)v2E2d-Q<(q;j>kXtIY~@Z=w#HpCIMie*DOq$`QGf)4yA0^T8C4Qfcjghg?V zb(Dd=0C0d9z(A8jxPVU>;Kx5UNsuElrH~G}0P+!TK*jlu0f%-rT9WXMFL(h3>NtTR za#IAq4CizhP|0{bzy|3gBjrPybQ;0PQU4tpoJno15h1I89K&CP5&f)l4agR?1SMg}|kI zk|pRy;K3bnGXt6gC(Wi~g7p~G26qZ-rBqPVq8-(qN_|1yY`1{}93Ybcy^p!q)opm zRU%Nx6@xuzAunZE#VVGJl59W^CQv*3aPt5zh^k+)A-7<_Yfuj`k^AmxSUI9Cu4r4D z>g4*^j8Nb#X8l25O+khNm|##$!hj75yS#hGv5={2ZX9bnMVaDEUuK2sa2OsxtN-Z%Ji1-(lEDOIg3$vCOGf9CSDm#D-2r;58xovWyOkv_8Crte z#nIQWDCLuaIeS;oU2Pu_0j>jt+ukU}fB=hmk%5aB-k`qpqBfK(5Fz{9)26nss}-;b zGRz#Pkl+MJ%`Jl$d|SDGfLjyuuUUKW(F#w93-@WzQ|8NIi%PJzN1W@`W^g?@?U=m* z7K7ZF;*_XNzy`LAtC4G4OY?%R2a;PzNw8~HwEEZy7a+h=1XX1hpJ0kL#BFH3tY3FD zgC21zt65KcW+L>~IEn?u6VnJ4c$ z#aGZE0RnRrRF{C;6R1f&8Uhh#%gNEYK6fdkm%$5UpaRjqm P7x~0Bcm#DS1OWg$YOidd literal 0 HcmV?d00001 diff --git a/test/jdk/java/awt/Dialog/FileDialogIconTest/T2.gif b/test/jdk/java/awt/Dialog/FileDialogIconTest/T2.gif new file mode 100644 index 0000000000000000000000000000000000000000..1f3fd66328ba678811608133a189ae76837cb7db GIT binary patch literal 2704 zcmV;B3UBpCNk%w1VN3u`0M-8hu_Q{*Ol?k0x$Nxh|K0$RjE`e1PgeyW%`jQtbd9MB zG7t@wAP5mAB_^qhn%91U%H|a zhI4xj2yP7sPJ3%H&ax>&Btmg+v>_Ofb#07rKU{BBV^&U-H8pNE5pPaObi!kMhICkd ze$TyzmLeELG%%EufF2-rlvfwZjEA=Y*Wz#t{Gi|Cm8t?amE_F;YS~ zg#Z8lA^!_OL{CCRI!RJ7E-(V#?EoS91OWg5KL9KM0000?08Ib@2LHgHa7Zi~kI1BQ z$!t2G(5Q4uty+&Zn`7%Jbh(b~b*$8O3k42j&1Q4Z-Y}VLMz19jl%&D$>+vRQaAI>( zT6QLTd<=|@j*NYHf?kA$ONV!hkB)ttkrEJZa+XMkYI~jy5`i2Rtr#pOC5nxFl4zr( zLuU}EoF*JD6~hz76FA7o2?;9~1`Uv^foPS5S!uqI5*!o5#Ky(RI0@q`%gv|_dJwoa zmYCTMCc@qo$Km4%8O!|q0n7oMMG8e}jtw*>P&krMpq{;A8TLs$x1!>T02ea`*oZ(8 z9#QVD9OMv>L%nbjmszl|0>gz17-DXmN%JDd9wAh1D_G@V0sj-w7)i+B%~(noD=(Nx zRHA7K6FV*hq=^7Q0IO9IJX^&sSCo<2Ae@{K5osU;FJ5?1>!GcO6fZ)cD6s=UkE>X- zRxJ^ND^Dngd^Irnt*nKFY~6b3u$XbcKZx(gCv${;(F{Y*Fg#t zOnBdmC3NM$B@XlgO#?0%GnxekFo2qQ2`0$kf(;U>po8u$ha3g=y?6r!Cg8F}7oRck z-!UH!_#=BI8hK=qCZhMCk`y>;n*s)4mxLDFb(aA|2^_{2kY9RfCy8E?s2q!C-k?B~ z84__&mE4e(fD0JRY2FB7-U;TTUZS`_3NGHKfC4>GlSCJ&gpf>}D}>k>mtvxqB!o)J zrzCQWp0~h($&GM8rDswAfo@oA=N~frh^JP84$hDwbHpCED1s!i$LEU*P>^YMMR0m! z2KiJ}+@h|=$J%M9F~%IL$T~us}1;C+Pja)(^nI zqKjZtV1wXoTFdrLTbU_a(6v!y!BbdN~1}tzuLgx=mOm*i1kU)Y48aSXq1eP1GHwrB#@9zNx zH2*`5C^QfPMjP!=LiGy^SGIV-gWwT>128Zk2)w5`it*qC5fC2%2~dFc&A@nkiw*$5 zMnC&KZ+|oC!T*58AO+=(1m3IN3|Qbm2vUw~!OOt|$_IxEwl8mb6M(E@n4=RRi72%z8v2I#?Tz{vm`3;>lsI9VR- zQyrc;azXlvPbTYTvmE3uj{l&OVp@Lrq%nrTj6fv9c6!l+`kd(i>>*W&oVHSyy7Prp z%$ps35SJ3n1_1m#+5kR^$omECIm{~PNlWOe6&m$sAh;tObr%7PdcXjb0Vf%USykR7 z!ZuB!0M8EkrB^YrtSx9kS@(+9yyms6f1F`iPw)Z;OlCIxJU~aM3R33DvX@0F6R{|Q5QSg|SAnWxLom$7VnP;Xk}I+(YQoLh5sR>uB5XC=#|X55uty6( zUHrv>13+M^1E{JHd;$Rz(5i=w!rLQ__rlycS9j2@r2DX_*9LeX1Q)1_XnX5XstOkq z5HNt5#E4RCeo||nOaE%#&WlIT`2eq-^?+eH(yZP}fU%7of+d?43J&Kj*$TlV61S_WrrRdw^_<`pK|lmDA3t4uL`~{Xaitj#WJ7-z|F6q zc)_o%rT~Y!L}{I33CC?lKm;HzYy)5t+Qc59yTP5XpnTGU7ST$KBiN+-E{Dxs_K~`I zRR{xKz+-(zl>xt%FlT(?FVcOD0xuYWAKSO&CBGKIEg*q)r_AH4MD+kSm9UUawgnOh z&C5`Q3n$0?T<2CUi+&Y>3e>^?>|$UeMSk$|Qaoo3*?_-BhAUKY;sF@wF1D|=<6iyR z0zt3&Xl>r7V*kmg137=i1|_(&i}u;0wV>bxl+$Zjaco;0iy#6g$e(-*T>=cWgv9mj zZI-o6g(7!Z0UC@APT=AJ6gc|?(8e{iPoRSQ6&4Z(h{>U!I%+Ecm#SAV!2wha9c6dZ zM{G$;TI9>_DTkm0Fu4c@9Nb$g)qv4t5I4D@1Dn?vASY7}_>}c$0C>kl-c{l4s7>(g zAU3)Qf};Th5^H2+%SJYJ*})E8QvwmHEh^eR^i^Q<=H7B(0HyZs7$RPP5R7r$M*d}1 zHWCvA$VB8;8M$b?9RdfWe5zz4!`RL!?w8+rptRBLRn%w~sFqyVHTb#13lVW3I=}#< z9wR^f#hdSPlU!(uu6GG+@N<=0qUt~_0M>i^a-(k@>^80Us3j2LZ=0PIX#c1KOb`OO z*PHE)==P{XV1ggm{qDL5oZyBD^cp?G#3ly3VjGYqf9jy@h)=u_7SH&52XQ2xS;{oR zaPLxMe(IV>0_Qz{_^Fm1^Y{&V>Xm?YAh!PYA9eV{XJ3Sf43n3VVR-D8sHgXUyp~kIBhkv1JVwC^? z|NsC0A^!_OL{CCRI!RJ7E-(V#?EoS91OWg5KL9KM0000?08Ib@2LHgHa7Zi~kI1BQ z$!t2G(5Q4uty+_qYz(vAX0PC;HfAWB&*hl<8*cy9v<{*v1zC z?(gmK0PO%3-kEA{S!KF~=+wpl;HX!@fx&_ZE68{^@0~phHNepd;|Z39X~2rPGw5K% zhzB4;HW<-hgFzW68E(`NF%6q4YCtKwknvbSj}JKL+{u%J$o~co3MgC%U||IiEhkpN zkjoH>U^YAEa-3;?@OFsA?naC@jO0lBq;=g_0eeoosq z-vWKHkKhrmEEA@{&k4g(;iFp&Nb(_xIn0s4znU zqd8C-0xG1&Tx;ze;GlyaeDL6e@45G!1SrsO*>(Cg5dT0pVw6*eF9nt+00_&;HerM; zMo8g{?O}-DZP)=7z#2<@R>%tkw&Q?tIiR?p0`Rri;)@WnNMVM1?Y99?N?{?Q1=s-4 zky|OO_F9rgx=3GiTq^nC2OM~%-;*A0a)e-okbq5jSgN+=0bP12A8fL*xWEEO()oc7 zdU04lR}SPOC2$sGQiYIfvt6BN`t2$1(3w3 z4v1?UYCV{15&@tEIJ5&NTzJkm@Ps`? zfF}>p643C&eA0QY#CzVGTLHYD;H?o{$fQ9)S8~wk1nrIdU6kns=TO#%Y3Kk5X6ib5X{LI}^bwy??sL_q7j3pf}fkz;;fE5$YD1j3pz z0M{{FIhg>Pz{+M20)4Gza5Mo*GtfZ?IWS$HxqfDfLUx1Zu0{?@?nQvZ!#T=k;;maJeHyo^X z${j=?f!vuwz=8uPRjyMEx8p8}3h!Jg*Y6{%P&V;LAAP*7dlId}`lHvnz|#vr@WBaS zZD3pgFyuePZ=`JAv+sZtQ@~*3fx{s#UMxeO1*XNP7Dx+y@}l4DN`pWB34wna@SnxL z7dNIk$OQy6;0hQ}I<}$j1`)88${@G^3Cf^r0;pj2-jIt7ilqS>dJdPCWdJ;l4r%c! z9sJO@rxa$Y0|c;@>0HRIs>pB%;8B4FP*MiC_-wCU;H3& zgA)`*1{OO`0N^-7rhI~q6&RGo@JON18NdTYdshvP$2N3bNCFX3K;Gn{jPY*(1urVQSPscOCKwkKO#!cahtda%5 z4C*me%VL(En!QCF%(NdG(Dqu^vMq9<7d_L(kRArIECZ+sTr8-;0Pu`$hjeh%YSq@e z$-NbLn+pL1qyV}jQ2#AXtE&WDkc38q(t!zY06p-c@mjSFuM$nCf`Al+0}OC0Yg>!A z7zCgz@O^-MyL(?fHJG{Nl~;eEYtzeSHn^Qo!$B?p+!vgW=Fe4Cmx|*1^n!ec5vg>9b<>7{5JvMkwK>8OkDMUX=U%o32HfaoNIQQqFgKX1T^XKSCBVzRDZSa-3?bx?uoxhL2>>4O zhBw>-B$%h2SImifW0amTAb|=j;P8OI*=iFfc)^Px?VM(o3#u@M%46WIkgIs)ODMU^ lXC87W!`uk>ra8^ycylM@T<4V3?A3bCgxgtM+O`M+06SJcV>kc+ literal 0 HcmV?d00001 diff --git a/test/jdk/java/awt/Dialog/FileDialogIconTest/T4.gif b/test/jdk/java/awt/Dialog/FileDialogIconTest/T4.gif new file mode 100644 index 0000000000000000000000000000000000000000..67876264d8f7f4d350815a4e08f6eb1ec6f1bb0e GIT binary patch literal 2721 zcmV;S3SRX`Nk%w1VN3u`0M-8h+uPd)OKmeRut%%b1&+)A-T-Zurw|d6O-8tt((P<) zYz_@)Gcz*;cdh~~KPiZ@1!t2pn8s_m+m@J_dV0=4NK3e)FSWL|o{U1!v?7X#hXsVa z23d`eeNRtob!~@{7#O8&Z@wCJo}8_&OK_A%PmxkbYh(#A^!_OL{CCRI!RJ7E-(V#?EoS91OWg5KL9KM0000?08Ib@2LHgHa7Zi~kI1BQ z$!t2G(5Q4uty+_pY<6_vX0PDpwl*ni&S*_}QuBu2!qLbKgDH55*NgYMD-?BVY+rCv zTXcLC6%34xjf#4BFlse57llrT8Ze2Do{Ec(kdl;ym`7a`8hN3j9xxvUva=r~9<7Rh zlM`I0MO`(kFRcs}9tJ20%FD_&&d)mrx5azAZN5UOoW#e;%+KJ@5;o&5J3GS_)oQ(k zS;2XZ9wW>N&Jy?%1N;0g{{HyeM-4X9N;J*^IC%=BG!8da)WsVUw{y$Ye`gRNb4 zKKR3qq#>d_8l_Z*&!UL7QXRAi&?7~P5-dtQPJx(i-3IHPr?~|b#0y7$%U};MT zZWTZF5F!Kx3aw+uhymI0)R_%1XWr^_mnkv9L^BvnZa~Yn4g#bg;rcaf*|TSdh=Cx+ z3d*>3?hEcfrn-iTvVO| z=s5=)dk6@Spa2Xm_?~+u;BZxa_u)4PaG^2sLNer7g#TO#=}p%jgAA&0!-*=WprC^8 zu_(X_IMkIJ0W{LM!3P?&@f|7?C=d#V5?J(QVRPduf6YC3Q%GfTEI4a*&&LS2kdPB|8pr0hgmGb(~Zz1d2e4QNCBAlPt!7K><3H zZ~zFao_NEOEjSA4l_Xq)MURVAfC5Ahlvm(%47%E22o|8KfB>Yjs6hc46kx%s2dt{- z4T|D0V~sRHV1SlHjIatLA2?&2pUTM=ER!j=Xa7MC9W;A_p{3?v!3`Z05G@EYNXulj z)Sg}gIN`fqgHt!QXnX`YpPg42PbBb!!9$5Um0= zGgz+*2k=k;4?X)Fx5hZ!cjZ$f3tW^jysFH?+i*WEt(rPuK&=2dWWeCgte%>$#*%;C zLId_49stos@OKgk5_qI^3nj1@xz|rSS^sYdn-@?50yQ&<^8$h2E3MB5kd7^CB=8u| z4r})cmF%#0>Vg}>l}w9hDnc22v}D21b{cJMGI%dd*8mG zwSdtD5GGO?fdRWEj2EmV0uA6m3J~QquSttd(J26`GEl6C;h|>48{XHV)w2fZ1cl`> zzzl|HsZ|(bA2e_YR8}w|2YSs(?x|O^P;~+fSYV1W%)kj`z`vjIumvm#;0A&?#1a0$ zTY2yRM=X-U6fm(w8e~$bBsj$raR04m3+RCfPSC6z^uT-2+9B5tz=FJp&jAxCV-bs@ zMjEj3c?)8gz97h~8|bV67|5Z<{ANecxex@vTR<3fvVo{LK!`+)LyunI0p7p_2XBnt zn%?s;R?(~gJqRT6tT?=0a*&WYp#ca3paB4+@(27;KqG1JfE03I1#gODgQydOD{8D* z>?(l+H<>d)4sHQ55Ty(BVoC!T(~O`|<`2h~LTI*-W2CAM267-nyMaJ^nUkSDad`lm zaZixIlYs~ZkdqXerv@`HrlnM&&L7g`nQ4-wq8fCn4)7ocIxvv{>eT}kG)o6O$Ynn> z=1D-_@c~^)nRxayg9yY(6C9xErpdxu)SRU^8DapO3uqEA_xHX~rT~dbb3g?WddxGb z0tQp1DhH6Y&51H7W-!nwJ#}ybdh!f-lgmLT_ouN?7LuU7a)1LoV9cjx%^lg%W*TAr~T@+SXKTLTv1;Z0Mj?f|})^1UM~# z-7p4P5?NqsgA|@o7mxzfi;T z1n+Pi@Bs2AHo53M@Gs^tfo7&yY%K_!Nee3j9#~PI7U;ld??}AQMVSOBNS}`vo8=`a zWCAbw*x2~iwJ{sj!+`BC_dM)@)**JO4j^%m?OX{1&_vG-2(y^;HRiwtI>*BWo(XN> zI^;T_z^v6W$^S-B1E)}EvJFr{C_6kzOG`P^3wS{}jKhMZp101KxRj|sCd@FinbpB1 zUX(*wXikp{(aKHlelB1DtYBs<5m>>c@yJ6>4m-*W_&_;!&=N#X0KLij2984d)R<>_X`YQFvQN8&fo^axbJq&Fa7VLbrJ}<-wJn$9{xCA3R z;YdeZ(5$+EsJtb$-gyO*z34ZT@d6`H&Rk4>k&N(UBN5;>TUzjRP)8jTWgM7dI^ozT;}AyxgPqI8EmesNq6<&z?dR6nbZ literal 0 HcmV?d00001 diff --git a/test/jdk/java/awt/Dialog/FileDialogIconTest/loading-msg.gif b/test/jdk/java/awt/Dialog/FileDialogIconTest/loading-msg.gif new file mode 100644 index 0000000000000000000000000000000000000000..6c7570a6d84358d4c81bbb4177d50410bd464674 GIT binary patch literal 1518 zcmV6ciK{6%`g178e&67#J8C85tTH8XFrM z92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021EG#T7 zEiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!-Jv}}? zK0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)WtPESuy zP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5dU|?Wj zVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&OadC2T za&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8f`fyD zgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@l$4Z} zm6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*!rKP5( zrl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dkwzs#p zxVX5vxw*Q!y1To(yu7@dCU$jHda z$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~>g((4 z?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF){QUg= z{r&#_{{R2~EC2ui06YLZ000R80RIUbNU)&6g9sBUT*$DY!-o(fN}NcsqQ#3CGiuz( zv7^U`zbbzF_U_rofdDH0`ST0NNr5R1h8+0r*EfRCzO5|y&E&wG7h?|m1mh2kPyc=u zg#zc_Hy~hu6m9tr2oN|-ox+G(w4zXf5Z?WJ2jL$}m}Z;)o9YtCpRr~CsCDZVCyaqW zp1u2IG$oLkE2;iPJJ{@7ieI0(6bM5xlvm&U0%qBEreuLT5f=;#_a6YU&r&{8%eJcJ zf1?FLIXn@7YuCSs8bulvD~M0;U|=m>IAw0ztToOQ_{(HZfg=}=90}&p%Zf^40}=b2 z;9Thm|F@*k8Xu@W?NLE#{eLzw~I6Q;%2$qiHe<^p{+!y~SB*_{{{zJJWS`+Fx%5j+0GxNxH@}D#=ZD{vMchpT{Wu<8H@di| zLwlX|=b(gg4%z~`~_*$hJV2UfR1hU=%r!*fFRa84hrhmhGsQsq)!IA z1Vv-t+y#Z4F_ya0AIz?_<+dQ`#g~|%Ph_X-%#bg35vaQyPhye1a3ld)qpMIn<>lI83_PZIP9yTv-Flt4ieS*k%h z$p*rPwLx*4QLv&%rkMmqW>S7*Z3PAxAhZ Date: Thu, 10 Oct 2024 15:50:19 +0000 Subject: [PATCH 016/118] 8340366: Open source several AWT Dialog tests - Batch 3 Reviewed-by: prr, dnguyen --- test/jdk/ProblemList.txt | 2 + .../java/awt/Dialog/DialogModalityTest.java | 114 +++++++++++++ .../java/awt/Dialog/DialogResizeTest2.java | 105 ++++++++++++ .../awt/Dialog/FileDialogUserFilterTest.java | 150 ++++++++++++++++++ test/jdk/java/awt/Dialog/HideDialogTest.java | 138 ++++++++++++++++ test/jdk/java/awt/Dialog/ModalDialogTest.java | 147 +++++++++++++++++ 6 files changed, 656 insertions(+) create mode 100644 test/jdk/java/awt/Dialog/DialogModalityTest.java create mode 100644 test/jdk/java/awt/Dialog/DialogResizeTest2.java create mode 100644 test/jdk/java/awt/Dialog/FileDialogUserFilterTest.java create mode 100644 test/jdk/java/awt/Dialog/HideDialogTest.java create mode 100644 test/jdk/java/awt/Dialog/ModalDialogTest.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 8f6b0c7466413..fb20eb1f63de9 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -473,6 +473,8 @@ java/awt/KeyboardFocusmanager/ConsumeNextMnemonicKeyTypedTest/ConsumeNextMnemoni java/awt/Window/GetScreenLocation/GetScreenLocationTest.java 8225787 linux-x64 java/awt/Dialog/MakeWindowAlwaysOnTop/MakeWindowAlwaysOnTop.java 8266243 macosx-aarch64 +java/awt/Dialog/FileDialogUserFilterTest.java 8001142 generic-all + java/awt/dnd/BadSerializationTest/BadSerializationTest.java 8277817 linux-x64,windows-x64 java/awt/dnd/DragSourceMotionListenerTest.java 8225131 windows-all java/awt/dnd/RejectDragTest.java 7124259 macosx-all diff --git a/test/jdk/java/awt/Dialog/DialogModalityTest.java b/test/jdk/java/awt/Dialog/DialogModalityTest.java new file mode 100644 index 0000000000000..d8ac9e4620b42 --- /dev/null +++ b/test/jdk/java/awt/Dialog/DialogModalityTest.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * 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.Button; +import java.awt.Component; +import java.awt.Dialog; +import java.awt.Event; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.Window; +import java.util.List; + +/* + * @test + * @bug 4058370 + * @summary Test to verify Modality of Dialog + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DialogModalityTest + */ + +public class DialogModalityTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. When the test is running, there will be a Frame, a Modal Dialog + and a Window that is Modal Dialog's parent. + 2. Verify that it is impossible to bring up the menu in Frame before + closing the Modal Dialog. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .build() + .awaitAndCheck(); + } + + public static List initialize() { + Frame f = new Frame("Parent Frame"); + DialogTest dlg = new DialogTest(f, "Modal Dialog"); + f.add(new Button("push me")); + f.setSize(200, 200); + f.setLocation(210, 1); + dlg.setBounds(210, 203, 200, 200); + return List.of(f, dlg); + } +} + +class DialogTest extends Dialog { + Button closeButton; + Frame parent; + + public DialogTest(Frame parent, String title) { + this(parent, title, true); + } + + public DialogTest(Frame parent, String title, boolean modal) { + super(parent, title, modal); + this.parent = parent; + setLayout(new BorderLayout()); + Panel buttonPanel = new Panel(); + closeButton = new Button("Close"); + buttonPanel.add(closeButton); + add("Center", buttonPanel); + pack(); + } + + public boolean action(Event e, Object arg) { + if (e.target == closeButton) { + Dialog dialog = null; + Component c = (Component) e.target; + + while (c != null && !(c instanceof Dialog)) { + c = c.getParent(); + } + + if (c != null) { + dialog = (Dialog) c; + } + + if (dialog == null) { + return false; + } + + dialog.setVisible(false); + dialog.dispose(); + return true; + } + return false; + } +} diff --git a/test/jdk/java/awt/Dialog/DialogResizeTest2.java b/test/jdk/java/awt/Dialog/DialogResizeTest2.java new file mode 100644 index 0000000000000..3124719637a1d --- /dev/null +++ b/test/jdk/java/awt/Dialog/DialogResizeTest2.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * 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.Button; +import java.awt.Dialog; +import java.awt.Frame; +import java.awt.GridLayout; + +/* + * @test + * @bug 4172302 + * @summary Test to make sure non-resizable Dialogs can be resized with the + * setSize() method. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DialogResizeTest2 + */ + +public class DialogResizeTest2 { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + This tests the programmatic resizability of non-resizable Dialogs + Even when a Dialog is set to be non-resizable, it should be + programmatically resizable using the setSize() method. + + 1. Initially the Dialog will be resizable. Try using the \\"Smaller\\" + and \\"Larger\\" buttons to verify that the Dialog resizes correctly + 2. Then, click the \\"Toggle\\" button to make the Dialog non-resizable + 3. Again, verify that clicking the \\"Larger\\" and \\"Smaller\\" buttons + causes the Dialog to get larger and smaller. If the Dialog does + not change size, or does not re-layout correctly, the test FAILS + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .logArea(8) + .build() + .awaitAndCheck(); + } + + public static Frame initialize() { + Frame frame = new Frame("Parent Frame"); + frame.add(new Button("Button")); + frame.setSize(100, 100); + new dlg(frame).setVisible(true); + return frame; + } + + static class dlg extends Dialog { + public dlg(Frame f_) { + super(f_, "Dialog", false); + setSize(200, 200); + Button bLarger = new Button("Larger"); + bLarger.addActionListener(e -> setSize(400, 400)); + Button bSmaller = new Button("Smaller"); + bSmaller.addActionListener(e -> setSize(200, 100)); + Button bCheck = new Button("Resizable?"); + bCheck.addActionListener(e -> { + if (isResizable()) { + PassFailJFrame.log("Dialog is resizable"); + } else { + PassFailJFrame.log("Dialog is not resizable"); + } + }); + Button bToggle = new Button("Toggle"); + bToggle.addActionListener(e -> { + if (isResizable()) { + setResizable(false); + PassFailJFrame.log("Dialog is now not resizable"); + } else { + setResizable(true); + PassFailJFrame.log("Dialog is now resizable"); + } + }); + setLayout(new GridLayout(1, 4)); + add(bSmaller); + add(bLarger); + add(bCheck); + add(bToggle); + } + } +} diff --git a/test/jdk/java/awt/Dialog/FileDialogUserFilterTest.java b/test/jdk/java/awt/Dialog/FileDialogUserFilterTest.java new file mode 100644 index 0000000000000..80ff9ed0bde60 --- /dev/null +++ b/test/jdk/java/awt/Dialog/FileDialogUserFilterTest.java @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * 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.Button; +import java.awt.Checkbox; +import java.awt.Component; +import java.awt.Container; +import java.awt.Event; +import java.awt.FileDialog; +import java.awt.Frame; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Label; +import java.awt.Panel; +import java.awt.TextField; +import java.io.File; +import java.io.FilenameFilter; + +/* + * @test + * @bug 4293697 4416433 4417139 4409600 + * @summary Test to verify that user filter always gets called on changing the + * directory in FileDialog + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FileDialogUserFilterTest + */ + +public class FileDialogUserFilterTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Enter a mask into the field, a directory into + the field (or leave the default values). + 2. Then click the button, file dialog will appear. + Output of the user filter will be shown in the output + area. Enter several different directories to the file dialog + via double-clicking on the directory list. The output + area should show some filtering output on each directory + change. If any output was only given on dialog startup, + the test is FAILED. + 3. Look at the list of files accepted by the filter. + If some files do not match the filter, + the test is FAILED. + 4. Open dialog with an empty filter. + Enter some directories with a lot of files (like /usr/bin). + If dialog crashes the test is FAILED. + Enter the directory that contain files and other directories. + If the directories are shown in the files box along with files + then the test is FAILED. + 5. Click in checkbox 'do not use filter', make it checked. + Open dialog, enter the directory with some files. + If no files is shown in the File list box (while you are sure + there are some files there) the test is FAILED + Otherwise it is PASSED." + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(new DialogFilterTest()) + .build() + .awaitAndCheck(); + } +} + +class DialogFilterTest extends Frame implements FilenameFilter { + FileDialog fd; + static TextField tfDirectory = new TextField(); + static TextField tfFile = new TextField(); + static TextField tfFilter = new TextField(); + static Checkbox useFilterCheck = new Checkbox("do not use filter"); + + public DialogFilterTest() { + setTitle("File Dialog User Filter test"); + add("North", new Button("Load")); + Panel p = new Panel(); + p.setLayout(new GridBagLayout()); + addRow(p, new Label("directory:", Label.RIGHT), tfDirectory); + addRow(p, new Label("file:", Label.RIGHT), tfFile); + addRow(p, new Label("filter:", Label.RIGHT), tfFilter); + addRow(p, new Label(""), useFilterCheck); + tfFilter.setText(".java"); + tfDirectory.setText("."); + add("Center", p); + setSize(300, 200); + } + + static void addRow(Container cont, Component c1, Component c2) { + GridBagLayout gbl = (GridBagLayout) cont.getLayout(); + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.BOTH; + cont.add(c1); + gbl.setConstraints(c1, c); + + c.gridwidth = GridBagConstraints.REMAINDER; + c.weightx = 1.0; + cont.add(c2); + gbl.setConstraints(c2, c); + } + + public boolean accept(File dir, String name) { + System.out.println("File " + dir + " String " + name); + if (fd.getMode() == FileDialog.LOAD) { + return name.lastIndexOf(tfFilter.getText()) > 0; + } + return true; + } + + public boolean action(Event evt, Object what) { + boolean load = "Load".equals(what); + + if (load || "Save".equals(what)) { + fd = new FileDialog(new Frame(), null, + load ? FileDialog.LOAD : FileDialog.SAVE); + fd.setDirectory(tfDirectory.getText()); + fd.setFile(tfFile.getText()); + if (!useFilterCheck.getState()) { + fd.setFilenameFilter(this); + } + fd.setVisible(true); + tfDirectory.setText(fd.getDirectory()); + tfFile.setText(fd.getFile()); + + return true; + } + return false; + } +} diff --git a/test/jdk/java/awt/Dialog/HideDialogTest.java b/test/jdk/java/awt/Dialog/HideDialogTest.java new file mode 100644 index 0000000000000..78d0344a6cf8e --- /dev/null +++ b/test/jdk/java/awt/Dialog/HideDialogTest.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * 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.Button; +import java.awt.Color; +import java.awt.Dialog; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Panel; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 4048664 4065506 4122094 4171979 + * @summary Test if Dialog can be successfully hidden, see that no other app + * comes to front, see if hide + dispose causes assertion failure + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual HideDialogTest + */ + +public class HideDialogTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. A Frame should appear with a "test" button in it + 2. Click on the "test" button. A Dialog will appear with a "dismiss" button + and a "dismiss-with-dispose" button + 3. First, click on the "dismiss-with-dispose" button. Verify that + no assertion failure appears. + 4. Now, click on the "dismiss" button. The Dialog should go away. + 5. Repeat from (2) 10-20 times. + 6. When the dialog goes away check that the frame window does not briefly + get obscured by another app or repaint it's entire area. There should be + no flicker at all in areas obscured by the dialog. (4065506 4122094) + If there is the test fails. + 7. If the Dialog is successfully hidden each time, the test passed. If the + Dialog did not hide, the test failed (4048664). + + NOTE: When the dialog does not go away (meaning the bug has manifested itself), + the "dismiss-with-dispose" button can be used to get rid of it. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(40) + .testUI(new MyFrame()) + .build() + .awaitAndCheck(); + } +} + +class MyDialog extends Dialog { + public MyDialog(Frame f) { + super(f, "foobar", true); + setSize(200, 200); + setLayout(new BorderLayout()); + Panel p = new Panel(); + p.setLayout(new FlowLayout(FlowLayout.CENTER)); + Button okButton; + okButton = new Button("dismiss"); + p.add(okButton); + okButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + System.out.println("Calling setVisible(false)"); + setVisible(false); + } + }); + Button newButton; + p.add(newButton = new Button("dismiss-with-dispose")); + newButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + System.out.println("Calling setVisible(false) + dispose()"); + setVisible(false); + dispose(); + } + }); + add("South", p); + pack(); + } +} + +class MyFrame extends Frame implements ActionListener { + public MyFrame() { + super(); + setSize(600, 400); + setTitle("HideDialogTest"); + setLayout(new BorderLayout()); + Panel toolbar = new Panel(); + toolbar.setLayout(new FlowLayout(FlowLayout.LEFT)); + Button testButton = new Button("test"); + testButton.addActionListener(this); + toolbar.add(testButton); + add("North", toolbar); + } + + public void actionPerformed(ActionEvent e) { + String s = e.getActionCommand(); + if (s.equals("test")) { + System.out.println("Begin test"); + MyDialog d = new MyDialog(this); + d.setVisible(true); + System.out.println("End test"); + } + } + + public void paint(Graphics g) { + for (int i = 0; i < 10; i++) { + g.setColor(Color.red); + g.fillRect(0, 0, 2000, 2000); + g.setColor(Color.blue); + g.fillRect(0, 0, 2000, 2000); + } + } +} diff --git a/test/jdk/java/awt/Dialog/ModalDialogTest.java b/test/jdk/java/awt/Dialog/ModalDialogTest.java new file mode 100644 index 0000000000000..aceacc9209a80 --- /dev/null +++ b/test/jdk/java/awt/Dialog/ModalDialogTest.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * 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.Button; +import java.awt.Checkbox; +import java.awt.Dialog; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; + +/* + * @test + * @bug 4078176 + * @summary Test to verify Modal dialogs don't act modal if addNotify() + * is called before setModal(true). + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ModalDialogTest + */ + +public class ModalDialogTest implements ActionListener { + public boolean modal = true; + Button closeBtn = new Button("Close me"); + Button createBtn = new Button("Create Dialog"); + Button createNewBtn = new Button("Create Modal Dialog"); + Button lastBtn = new Button("Show Last Dialog"); + Dialog dialog; + Dialog newDialog; + Frame testFrame; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Use 'Modal' checkbox to select which dialog you're + going to create - modal or non-modal. + (this checkbox affects only new created dialog but + not existing one) + 2. Use 'Create Dialog' button to create a dialog. + If you have selected 'Modal' checkbox then dialog has to + be created modal - you can make sure of that clicking + on any other control (i.e. 'Modal' checkbox) - they + should not work. + 3. Use 'Show Last Dialog' button to bring up last + created dialog - to make sure that if you show/hide + modal dialog several times it stays modal. + 4. On the appearing dialog there are two buttons: + 'Close Me' which closes the dialog, + and 'Create Modal Dialog' which creates one more + MODAL dialog just to make sure that + in situation with two modal dialogs all is fine. + 5. If created modal dialogs are really modal + (which means that they blocks the calling app) + then test is PASSED, otherwise it's FAILED." + """; + ModalDialogTest test = new ModalDialogTest(); + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(test.initialize()) + .build() + .awaitAndCheck(); + } + + public Frame initialize() { + testFrame = new Frame("Parent Frame"); + Frame frame = new Frame("Modal Dialog test"); + Panel panel = new Panel(); + panel.setLayout(new BorderLayout()); + + createBtn.addActionListener(this); + createNewBtn.addActionListener(this); + closeBtn.addActionListener(this); + lastBtn.addActionListener(this); + panel.add("Center", createBtn); + panel.add("South", lastBtn); + Checkbox cb = new Checkbox("Modal", modal); + cb.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + modal = ((Checkbox) e.getSource()).getState(); + } + }); + panel.add("North", cb); + panel.setSize(200, 100); + + frame.add(panel); + frame.pack(); + return frame; + } + + public void actionPerformed(ActionEvent e) { + if (e.getSource() == createBtn) { + if (dialog != null) { + dialog.dispose(); + } + dialog = new Dialog(testFrame, "Modal Dialog"); + dialog.add("North", closeBtn); + dialog.add("South", createNewBtn); + createBtn.setEnabled(false); + dialog.pack(); + dialog.setModal(modal); + dialog.setVisible(true); + } else if (e.getSource() == closeBtn && dialog != null) { + createBtn.setEnabled(true); + dialog.setVisible(false); + } else if (e.getSource() == lastBtn && dialog != null) { + dialog.setVisible(true); + } else if (e.getSource() == createNewBtn && newDialog == null) { + newDialog = new Dialog(testFrame, "New Modal Dialog"); + Button clsBtn = new Button("Close Me"); + clsBtn.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + newDialog.dispose(); + newDialog = null; + } + }); + newDialog.add("North", clsBtn); + newDialog.pack(); + newDialog.setModal(true); + newDialog.setVisible(true); + } + } +} From 4beb77192f54f27183285400d7cae7528df64e43 Mon Sep 17 00:00:00 2001 From: Aleksei Efimov Date: Thu, 10 Oct 2024 15:56:04 +0000 Subject: [PATCH 017/118] 8339538: Wrong timeout computations in DnsClient 8220213: com/sun/jndi/dns/ConfigTests/Timeout.java failed intermittent Reviewed-by: dfuchs, msheppar, djelinski --- .../classes/com/sun/jndi/dns/DnsClient.java | 132 +++++++++--- .../classes/com/sun/jndi/dns/DnsContext.java | 8 +- .../com/sun/jndi/dns/ConfigTests/Timeout.java | 40 ++-- .../TimeoutWithEmptyDatagrams.java | 196 ++++++++++++++++++ 4 files changed, 324 insertions(+), 52 deletions(-) create mode 100644 test/jdk/com/sun/jndi/dns/ConfigTests/TimeoutWithEmptyDatagrams.java diff --git a/src/jdk.naming.dns/share/classes/com/sun/jndi/dns/DnsClient.java b/src/jdk.naming.dns/share/classes/com/sun/jndi/dns/DnsClient.java index 0d5ca39c6f74b..3d55186bac882 100644 --- a/src/jdk.naming.dns/share/classes/com/sun/jndi/dns/DnsClient.java +++ b/src/jdk.naming.dns/share/classes/com/sun/jndi/dns/DnsClient.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * 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,11 +46,15 @@ import javax.naming.OperationNotSupportedException; import javax.naming.ServiceUnavailableException; +import java.time.Duration; import java.util.Arrays; import java.util.Collections; import java.util.Map; import java.util.HashMap; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.ReentrantLock; +import java.util.stream.IntStream; import jdk.internal.ref.CleanerFactory; import sun.security.jca.JCAUtil; @@ -95,7 +99,7 @@ public class DnsClient { private static final int DEFAULT_PORT = 53; private static final int TRANSACTION_ID_BOUND = 0x10000; - private static final int MIN_TIMEOUT = 50; // msec after which there are no retries. + private static final int MIN_TIMEOUT = 0; // msec after which there are no retries. private static final SecureRandom random = JCAUtil.getSecureRandom(); private InetAddress[] servers; private int[] serverPorts; @@ -223,20 +227,28 @@ ResourceRecords query(DnsName fqdn, int qclass, int qtype, Exception caughtException = null; boolean[] doNotRetry = new boolean[servers.length]; - + // Holder for unfulfilled timeouts left for each server + AtomicLong[] unfulfilledUdpTimeouts = IntStream.range(0, servers.length) + .mapToObj(_ -> new AtomicLong()) + .toArray(AtomicLong[]::new); try { // // The UDP retry strategy is to try the 1st server, and then // each server in order. If no answer, double the timeout // and try each server again. // - for (int retry = 0; retry < retries; retry++) { - + for (int retry = 0; retry <= retries; retry++) { + boolean isLastRetry = retry == retries; // Try each name server. for (int i = 0; i < servers.length; i++) { if (doNotRetry[i]) { continue; } + // unfulfilledServerTimeout is always >= 0 + AtomicLong unfulfilledServerTimeout = unfulfilledUdpTimeouts[i]; + if (isLastRetry && unfulfilledServerTimeout.get() == 0) { + continue; + } // send the request packet and wait for a response. try { @@ -245,7 +257,7 @@ ResourceRecords query(DnsName fqdn, int qclass, int qtype, } byte[] msg = doUdpQuery(pkt, servers[i], serverPorts[i], - retry, xid); + retry, xid, unfulfilledServerTimeout, isLastRetry); assert msg != null; Header hdr = new Header(msg, msg.length); @@ -259,7 +271,12 @@ ResourceRecords query(DnsName fqdn, int qclass, int qtype, // Try each server, starting with the one that just // provided the truncated message. - int retryTimeout = (timeout * (1 << retry)); + long retryTimeout = Math.clamp( + timeout * (1L << (isLastRetry + ? retry - 1 + : retry)), + 0L, Integer.MAX_VALUE); + ; for (int j = 0; j < servers.length; j++) { int ij = (i + j) % servers.length; if (doNotRetry[ij]) { @@ -301,15 +318,23 @@ ResourceRecords query(DnsName fqdn, int qclass, int qtype, if (debug) { dprint("Caught Exception:" + ex); } - if (caughtException == null) { + if (caughtException == null || servers.length == 1) { + // If there are several servers we continue trying with other + // servers, otherwise this exception will be reported caughtException = ex; + } else { + // Best reporting effort + caughtException.addSuppressed(ex); } doNotRetry[i] = true; } catch (IOException e) { if (debug) { dprint("Caught IOException:" + e); } - if (caughtException == null) { + if (caughtException instanceof CommunicationException ce) { + e.addSuppressed(ce); + caughtException = e; + } else if (caughtException == null) { caughtException = e; } } catch (ClosedSelectorException e) { @@ -327,8 +352,13 @@ ResourceRecords query(DnsName fqdn, int qclass, int qtype, caughtException = e; } } catch (NamingException e) { - if (caughtException == null) { + if (caughtException == null || servers.length == 1) { + // If there are several servers we continue trying with other + // servers, otherwise this exception will be reported caughtException = e; + } else { + // Best reporting effort + caughtException.addSuppressed(e); } doNotRetry[i] = true; } @@ -339,8 +369,8 @@ ResourceRecords query(DnsName fqdn, int qclass, int qtype, reqs.remove(xid); // cleanup } - if (caughtException instanceof NamingException) { - throw (NamingException) caughtException; + if (caughtException instanceof NamingException ne) { + throw ne; } // A network timeout or other error occurred. NamingException ne = new CommunicationException("DNS error"); @@ -424,10 +454,32 @@ ResourceRecords queryZone(DnsName zone, int qclass, boolean recursion) * is enqueued with the corresponding xid in 'resps'. */ private byte[] doUdpQuery(Packet pkt, InetAddress server, - int port, int retry, int xid) + int port, int retry, int xid, + AtomicLong unfulfilledTimeout, + boolean unfulfilledOnly) throws IOException, NamingException { udpChannelLock.lock(); + + + // use 1L below to ensure conversion to long and avoid potential + // integer overflow (timeout is an int). + // no point in supporting timeout > Integer.MAX_VALUE, clamp if needed + // timeout remaining after successive 'blockingReceive()'. + long thisIterationTimeout = unfulfilledOnly + ? 0L + : Math.clamp(timeout * (1L << retry), 0L, Integer.MAX_VALUE); + + // Compensate with server's positive unfulfilled timeout. + // Calling method never supplies zero 'unfulfilledTimeout' when + // 'unfulfilledOnly' is 'true', therefore 'thisIterationTimeout' + // will always be a positive number, ie infinite timeout + // is not possible. + thisIterationTimeout += unfulfilledTimeout.get(); + + // Track left timeout for the current retry + long timeoutLeft = thisIterationTimeout; + long start = 0; try { try (DatagramChannel udpChannel = getDatagramChannel()) { ByteBuffer opkt = ByteBuffer.wrap(pkt.getData(), 0, pkt.length()); @@ -436,13 +488,11 @@ private byte[] doUdpQuery(Packet pkt, InetAddress server, // Packets may only be sent to or received from this server address InetSocketAddress target = new InetSocketAddress(server, port); udpChannel.connect(target); - int pktTimeout = (timeout * (1 << retry)); udpChannel.write(opkt); - // timeout remaining after successive 'blockingReceive()' - int timeoutLeft = pktTimeout; int cnt = 0; boolean gotData = false; + start = System.nanoTime(); do { // prepare for retry if (gotData) { @@ -456,9 +506,7 @@ private byte[] doUdpQuery(Packet pkt, InetAddress server, ") for:" + xid + " sock-timeout:" + timeoutLeft + " ms."); } - long start = System.currentTimeMillis(); - gotData = blockingReceive(udpChannel, ipkt, timeoutLeft); - long end = System.currentTimeMillis(); + gotData = blockingReceive(udpChannel, target, ipkt, timeoutLeft); assert gotData || ipkt.position() == 0; if (gotData && isMatchResponse(data, xid)) { return data; @@ -471,17 +519,23 @@ private byte[] doUdpQuery(Packet pkt, InetAddress server, return cachedMsg; } } - timeoutLeft = pktTimeout - ((int) (end - start)); + long elapsedMillis = TimeUnit.NANOSECONDS + .toMillis(System.nanoTime() - start); + timeoutLeft = thisIterationTimeout - elapsedMillis; } while (timeoutLeft > MIN_TIMEOUT); // no matching packets received within the timeout throw new SocketTimeoutException(); } } finally { + long carryoverTimeout = thisIterationTimeout - + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start); + unfulfilledTimeout.set(Math.max(0, carryoverTimeout)); udpChannelLock.unlock(); } } - boolean blockingReceive(DatagramChannel dc, ByteBuffer buffer, long timeout) throws IOException { + boolean blockingReceive(DatagramChannel dc, InetSocketAddress target, + ByteBuffer buffer, long timeout) throws IOException { boolean dataReceived = false; // The provided datagram channel will be used by the caller only to receive data after // it is put to non-blocking mode @@ -491,10 +545,15 @@ boolean blockingReceive(DatagramChannel dc, ByteBuffer buffer, long timeout) thr udpChannelSelector.select(timeout); var keys = udpChannelSelector.selectedKeys(); if (keys.contains(selectionKey) && selectionKey.isReadable()) { - dc.receive(buffer); - dataReceived = true; + int before = buffer.position(); + var senderAddress = dc.receive(buffer); + // Empty packets are ignored + dataReceived = target.equals(senderAddress) && buffer.position() > before; + } + // Avoid contention with Selector.close() if called by a clean-up thread + synchronized (keys) { + keys.clear(); } - keys.clear(); } finally { selectionKey.cancel(); // Flush the canceled key out of the selected key set @@ -750,14 +809,19 @@ class Tcp { private final Socket sock; private final java.io.InputStream in; final java.io.OutputStream out; - private int timeoutLeft; + private long timeoutLeft; - Tcp(InetAddress server, int port, int timeout) throws IOException { + Tcp(InetAddress server, int port, long timeout) throws IOException { sock = new Socket(); try { - long start = System.currentTimeMillis(); - sock.connect(new InetSocketAddress(server, port), timeout); - timeoutLeft = (int) (timeout - (System.currentTimeMillis() - start)); + long start = System.nanoTime(); + // It is safe to cast to int since the value is + // clamped by the caller + int intTimeout = (int) timeout; + sock.connect(new InetSocketAddress(server, port), intTimeout); + timeoutLeft = Duration.ofMillis(timeout) + .minus(Duration.ofNanos((System.nanoTime() - start))) + .toMillis(); if (timeoutLeft <= 0) throw new SocketTimeoutException(); @@ -785,14 +849,16 @@ private interface SocketReadOp { private int readWithTimeout(SocketReadOp reader) throws IOException { if (timeoutLeft <= 0) throw new SocketTimeoutException(); - - sock.setSoTimeout(timeoutLeft); - long start = System.currentTimeMillis(); + // It is safe to cast to int since the value is clamped + int intTimeout = (int) timeoutLeft; + sock.setSoTimeout(intTimeout); + long start = System.nanoTime(); try { return reader.read(); } finally { - timeoutLeft -= (int) (System.currentTimeMillis() - start); + timeoutLeft -= TimeUnit.NANOSECONDS.toMillis( + System.nanoTime() - start); } } diff --git a/src/jdk.naming.dns/share/classes/com/sun/jndi/dns/DnsContext.java b/src/jdk.naming.dns/share/classes/com/sun/jndi/dns/DnsContext.java index 028108494af87..fe35a4979cc3b 100644 --- a/src/jdk.naming.dns/share/classes/com/sun/jndi/dns/DnsContext.java +++ b/src/jdk.naming.dns/share/classes/com/sun/jndi/dns/DnsContext.java @@ -176,13 +176,13 @@ public Object addToEnvironment(String propName, Object propVal) } else if (propName.equals(INIT_TIMEOUT)) { int val = Integer.parseInt((String) propVal); if (timeout != val) { - timeout = val; + timeout = Math.max(val, 0); resolver = null; } } else if (propName.equals(RETRIES)) { int val = Integer.parseInt((String) propVal); if (retries != val) { - retries = val; + retries = Math.clamp(val, 1, 30); resolver = null; } } @@ -257,11 +257,11 @@ private void initFromEnvironment() val = (String) environment.get(INIT_TIMEOUT); timeout = (val == null) ? DEFAULT_INIT_TIMEOUT - : Integer.parseInt(val); + : Math.max(Integer.parseInt(val), 0); val = (String) environment.get(RETRIES); retries = (val == null) ? DEFAULT_RETRIES - : Integer.parseInt(val); + : Math.clamp(Integer.parseInt(val), 1, 30); } private CT getLookupCT(String attrId) diff --git a/test/jdk/com/sun/jndi/dns/ConfigTests/Timeout.java b/test/jdk/com/sun/jndi/dns/ConfigTests/Timeout.java index 90a2a7b981565..e03923b6c3442 100644 --- a/test/jdk/com/sun/jndi/dns/ConfigTests/Timeout.java +++ b/test/jdk/com/sun/jndi/dns/ConfigTests/Timeout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ import java.net.InetSocketAddress; import java.net.SocketTimeoutException; import java.time.Duration; -import java.time.Instant; import jdk.test.lib.net.URIBuilder; @@ -40,7 +39,7 @@ * number of retries. * @library ../lib/ /test/lib * @modules java.base/sun.security.util - * @run main Timeout + * @run main/othervm Timeout */ public class Timeout extends DNSTestBase { @@ -48,8 +47,12 @@ public class Timeout extends DNSTestBase { private static final int TIMEOUT = 250; // try 5 times per server private static final int RETRIES = 5; + // DnsClient retries again with increased timeout if left + // timeout is less than this value, and max retry attempts + // is not reached + private static final int DNS_CLIENT_MIN_TIMEOUT = 0; - private Instant startTime; + private long startTime; public Timeout() { setLocalServer(false); @@ -81,7 +84,7 @@ public void runTest() throws Exception { setContext(new InitialDirContext(env())); // Any request should fail after timeouts have expired. - startTime = Instant.now(); + startTime = System.nanoTime(); context().getAttributes(""); throw new RuntimeException( @@ -92,28 +95,35 @@ public void runTest() throws Exception { @Override public boolean handleException(Exception e) { if (e instanceof CommunicationException) { - Duration elapsedTime = Duration.between(startTime, Instant.now()); + Duration elapsedTime = Duration.ofNanos(System.nanoTime() - startTime); if (!(((CommunicationException) e) .getRootCause() instanceof SocketTimeoutException)) { return false; } - Duration expectedTime = Duration.ofMillis(TIMEOUT) - .multipliedBy((1 << RETRIES) - 1); + Duration minAllowedTime = Duration.ofMillis(TIMEOUT) + .multipliedBy((1 << RETRIES) - 1) + .minus(Duration.ofMillis(DNS_CLIENT_MIN_TIMEOUT * RETRIES)); + Duration maxAllowedTime = Duration.ofMillis(TIMEOUT) + .multipliedBy((1 << RETRIES) - 1) + // max allowed timeout value is set to 2 * expected timeout + .multipliedBy(2); + DNSTestUtils.debug("Elapsed (ms): " + elapsedTime.toMillis()); - DNSTestUtils.debug("Expected (ms): " + expectedTime.toMillis()); + String expectedRangeMsg = "%s - %s" + .formatted(minAllowedTime.toMillis(), maxAllowedTime.toMillis()); + DNSTestUtils.debug("Expected range (ms): " + expectedRangeMsg); // Check that elapsed time is as long as expected, and - // not more than 50% greater. - if (elapsedTime.compareTo(expectedTime) >= 0 && - elapsedTime.multipliedBy(2) - .compareTo(expectedTime.multipliedBy(3)) <= 0) { + // not more than 2 times greater. + if (elapsedTime.compareTo(minAllowedTime) >= 0 && + elapsedTime.compareTo(maxAllowedTime) <= 0) { System.out.println("elapsed time is as long as expected."); return true; } throw new RuntimeException( - "Failed: timeout in " + elapsedTime.toMillis() - + " ms, expected" + expectedTime.toMillis() + "ms"); + "Failed: timeout in " + elapsedTime.toMillis() + + " ms, expected to be in a range (ms): " + expectedRangeMsg); } return super.handleException(e); diff --git a/test/jdk/com/sun/jndi/dns/ConfigTests/TimeoutWithEmptyDatagrams.java b/test/jdk/com/sun/jndi/dns/ConfigTests/TimeoutWithEmptyDatagrams.java new file mode 100644 index 0000000000000..9fb8954c99c54 --- /dev/null +++ b/test/jdk/com/sun/jndi/dns/ConfigTests/TimeoutWithEmptyDatagrams.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.test.lib.net.URIBuilder; + +import javax.naming.CommunicationException; +import javax.naming.Context; +import javax.naming.directory.InitialDirContext; +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.SocketTimeoutException; +import java.time.Duration; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; + +/* + * @test + * @bug 8339538 + * @summary Tests that DnsClient correctly calculates left timeout in + * presence of empty datagram packets. + * @library ../lib /test/lib + * @modules java.base/sun.security.util + * @run main/othervm TimeoutWithEmptyDatagrams + */ + +public class TimeoutWithEmptyDatagrams extends DNSTestBase { + // initial timeout = 1/4 sec + private static final int TIMEOUT = 250; + // try 5 times per server + private static final int RETRIES = 5; + // DnsClient retries again with increased timeout if left + // timeout is less than this value, and max retry attempts + // is not reached + private static final int DNS_CLIENT_MIN_TIMEOUT = 0; + + public TimeoutWithEmptyDatagrams() { + setLocalServer(false); + } + + public static void main(String[] args) throws Exception { + new TimeoutWithEmptyDatagrams().run(args); + } + + /* + * Tests that we can set the initial UDP timeout interval and the + * number of retries. + */ + @Override + public void runTest() throws Exception { + // Create a DatagramSocket and bind it to the loopback address to simulate + // UDP DNS server that doesn't respond + try (DatagramSocket ds = new DatagramSocket(new InetSocketAddress( + InetAddress.getLoopbackAddress(), 0))) { + CountDownLatch gotClientAddress = new CountDownLatch(1); + AtomicReference clientAddress = new AtomicReference<>(); + AtomicBoolean stopTestThreads = new AtomicBoolean(); + + String allQuietUrl = URIBuilder.newBuilder() + .scheme("dns") + .loopback() + .port(ds.getLocalPort()) + .build() + .toString(); + + // Run a virtual thread that receives client request packets and extracts + // sender address from them. + Thread receiverThread = Thread.ofVirtual().start(() -> { + while (!stopTestThreads.get()) { + try { + DatagramPacket packet = new DatagramPacket(new byte[1024], 1024); + ds.receive(packet); + System.err.println("Got packet from " + packet.getSocketAddress()); + boolean hasClientAddress = clientAddress.get() != null; + clientAddress.set(packet.getSocketAddress()); + if (!hasClientAddress) { + gotClientAddress.countDown(); + } + } catch (IOException e) { + if (!stopTestThreads.get()) { + throw new RuntimeException(e); + } else { + return; + } + } + } + }); + + // Run a virtual thread that will send an empty packets via server socket + // that should wake up the selector on a client side. + Thread wakeupThread = Thread.ofVirtual().start(() -> { + try { + long timeout = Math.max(1, TIMEOUT / 4); + // wait for a first packet on a server socket + gotClientAddress.await(); + + // Now start sending empty packets until we get a notification + // from client part to stop sending + while (!stopTestThreads.get()) { + System.err.println("Server timeout = " + timeout); + TimeUnit.MILLISECONDS.sleep(timeout); + System.err.println("Sending wakeup packet to " + clientAddress.get()); + var wakeupPacket = new DatagramPacket(new byte[0], 0); + wakeupPacket.setSocketAddress(clientAddress.get()); + ds.send(wakeupPacket); + timeout += Math.max(1, timeout / 2); + } + } catch (IOException ioe) { + throw new RuntimeException("Test machinery failure", ioe); + } catch (InterruptedException e) { + throw new RuntimeException("Interrupted during wakeup packets sending"); + } finally { + System.err.println("Server thread exiting"); + } + }); + + long startTime = 0; + try { + env().put(Context.PROVIDER_URL, allQuietUrl); + env().put("com.sun.jndi.dns.timeout.initial", String.valueOf(TIMEOUT)); + env().put("com.sun.jndi.dns.timeout.retries", String.valueOf(RETRIES)); + setContext(new InitialDirContext(env())); + + startTime = System.nanoTime(); + context().getAttributes(""); + + // Any request should fail after timeouts have expired. + throw new RuntimeException("Failed: getAttributes succeeded unexpectedly"); + } catch (CommunicationException ce) { + // We need to catch CommunicationException outside the test framework + // flow because wakeupThread.join() can take some time that could + // increase measured timeout + long endTime = System.nanoTime(); + Duration elapsedTime = Duration.ofNanos(endTime - startTime); + if (ce.getRootCause() instanceof SocketTimeoutException) { + + Duration minAllowedTime = Duration.ofMillis(TIMEOUT) + .multipliedBy((1 << RETRIES) - 1) + .minus(Duration.ofMillis(DNS_CLIENT_MIN_TIMEOUT * RETRIES)); + Duration maxAllowedTime = Duration.ofMillis(TIMEOUT) + .multipliedBy((1 << RETRIES) - 1) + // max allowed timeout value is set to 2 * expected timeout + .multipliedBy(2); + + DNSTestUtils.debug("Elapsed (ms): " + elapsedTime.toMillis()); + String expectedRangeMsg = "%s - %s" + .formatted(minAllowedTime.toMillis(), maxAllowedTime.toMillis()); + DNSTestUtils.debug("Expected range (ms): " + expectedRangeMsg); + + // Check that elapsed time is as long as expected, and + // not more than 2 times greater. + if (elapsedTime.compareTo(minAllowedTime) >= 0 && + elapsedTime.compareTo(maxAllowedTime) <= 0) { + System.out.println("elapsed time is as long as expected."); + } else { + throw new RuntimeException( + "Failed: timeout in " + elapsedTime.toMillis() + + " ms, expected to be in a range (ms): " + expectedRangeMsg); + } + } else { + throw ce; + } + } finally { + stopTestThreads.set(true); + wakeupThread.join(); + ds.close(); + receiverThread.join(); + } + } + } +} From 6fad6af0de5e749aa60038d70ae196b5f666286f Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Thu, 10 Oct 2024 17:02:54 +0000 Subject: [PATCH 018/118] 8341819: LightweightSynchronizer::enter_for races with deflation Reviewed-by: pchilanomate, rkennke --- .../share/runtime/lightweightSynchronizer.cpp | 7 +++++-- test/jdk/com/sun/jdi/EATests.java | 13 +++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/runtime/lightweightSynchronizer.cpp b/src/hotspot/share/runtime/lightweightSynchronizer.cpp index 5037bb9607b5d..7cf7c201faf74 100644 --- a/src/hotspot/share/runtime/lightweightSynchronizer.cpp +++ b/src/hotspot/share/runtime/lightweightSynchronizer.cpp @@ -635,8 +635,11 @@ void LightweightSynchronizer::enter_for(Handle obj, BasicLock* lock, JavaThread* bool entered = monitor->enter_for(locking_thread); assert(entered, "recursive ObjectMonitor::enter_for must succeed"); } else { - // It is assumed that enter_for must enter on an object without contention. - monitor = inflate_and_enter(obj(), ObjectSynchronizer::inflate_cause_monitor_enter, locking_thread, current); + do { + // It is assumed that enter_for must enter on an object without contention. + monitor = inflate_and_enter(obj(), ObjectSynchronizer::inflate_cause_monitor_enter, locking_thread, current); + // But there may still be a race with deflation. + } while (monitor == nullptr); } assert(monitor != nullptr, "LightweightSynchronizer::enter_for must succeed"); diff --git a/test/jdk/com/sun/jdi/EATests.java b/test/jdk/com/sun/jdi/EATests.java index adeb21741438f..b2a2cad49db7f 100644 --- a/test/jdk/com/sun/jdi/EATests.java +++ b/test/jdk/com/sun/jdi/EATests.java @@ -158,6 +158,19 @@ * -XX:+DoEscapeAnalysis -XX:+EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks * -XX:LockingMode=0 * -XX:GuaranteedAsyncDeflationInterval=1000 + * + * @bug 8341819 + * @comment Regression test for re-locking racing with deflation with LM_LIGHTWEIGHT. + * @run driver EATests + * -XX:+UnlockDiagnosticVMOptions + * -Xms256m -Xmx256m + * -Xbootclasspath/a:. + * -XX:CompileCommand=dontinline,*::dontinline_* + * -XX:+WhiteBoxAPI + * -Xbatch + * -XX:+DoEscapeAnalysis -XX:+EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks + * -XX:LockingMode=2 + * -XX:GuaranteedAsyncDeflationInterval=1 */ /** From 76541b0646d27e79948d73759f21383c099e2436 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Thu, 10 Oct 2024 17:22:45 +0000 Subject: [PATCH 019/118] 8341792: Fix ExceptionOccurred in java.security.jgss Reviewed-by: jlu, mullan --- .../macosx/native/libosxkrb5/SCDynamicStoreConfig.m | 2 +- .../windows/native/libw2k_lsa_auth/NativeCreds.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/java.security.jgss/macosx/native/libosxkrb5/SCDynamicStoreConfig.m b/src/java.security.jgss/macosx/native/libosxkrb5/SCDynamicStoreConfig.m index 11645d152cdfa..43cab418e1700 100644 --- a/src/java.security.jgss/macosx/native/libosxkrb5/SCDynamicStoreConfig.m +++ b/src/java.security.jgss/macosx/native/libosxkrb5/SCDynamicStoreConfig.m @@ -51,7 +51,7 @@ void _SCDynamicStoreCallBack(SCDynamicStoreRef store, CFArrayRef changedKeys, vo jmethodID jm_Config_refresh = (*env)->GetStaticMethodID(env, jc_Config, "refresh", "()V"); CHECK_NULL(jm_Config_refresh); (*env)->CallStaticVoidMethod(env, jc_Config, jm_Config_refresh); - if ((*env)->ExceptionOccurred(env) != NULL) { + if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionClear(env); } if (createdFromAttach) { diff --git a/src/java.security.jgss/windows/native/libw2k_lsa_auth/NativeCreds.c b/src/java.security.jgss/windows/native/libw2k_lsa_auth/NativeCreds.c index 221aaccbf2bab..fe71f334617e1 100644 --- a/src/java.security.jgss/windows/native/libw2k_lsa_auth/NativeCreds.c +++ b/src/java.security.jgss/windows/native/libw2k_lsa_auth/NativeCreds.c @@ -877,13 +877,13 @@ jobject BuildTicket(JNIEnv *env, PUCHAR encodedTicket, ULONG encodedTicketSize) (*env)->SetByteArrayRegion(env, ary, (jsize) 0, encodedTicketSize, (jbyte *)encodedTicket); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { (*env)->DeleteLocalRef(env, ary); return (jobject) NULL; } ticket = (*env)->NewObject(env, ticketClass, ticketConstructor, ary); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { (*env)->DeleteLocalRef(env, ary); return (jobject) NULL; } @@ -993,7 +993,7 @@ jobject BuildEncryptionKey(JNIEnv *env, PKERB_CRYPTO_KEY cryptoKey) { } (*env)->SetByteArrayRegion(env, ary, (jsize) 0, cryptoKey->Length, (jbyte *)cryptoKey->Value); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { (*env)->DeleteLocalRef(env, ary); } else { encryptionKey = (*env)->NewObject(env, encryptionKeyClass, @@ -1018,7 +1018,7 @@ jobject BuildTicketFlags(JNIEnv *env, PULONG flags) { } (*env)->SetByteArrayRegion(env, ary, (jsize) 0, sizeof(*flags), (jbyte *)&nlflags); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { (*env)->DeleteLocalRef(env, ary); } else { ticketFlags = (*env)->NewObject(env, ticketFlagsClass, From 7eb55357ab169c21dd5d0ed1738155e794e5faaf Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Thu, 10 Oct 2024 17:33:22 +0000 Subject: [PATCH 020/118] 8341789: Fix ExceptionOccurred in java.base Reviewed-by: bpb, jpai, dfuchs, lancea, rriggs, naoto --- .../share/native/libjava/ClassLoader.c | 6 ++--- src/java.base/share/native/libjava/System.c | 6 ++--- src/java.base/share/native/libjava/io_util.c | 4 +-- src/java.base/share/native/libjava/jni_util.c | 6 ++--- src/java.base/share/native/libjli/java.c | 6 ++--- src/java.base/share/native/libjli/java.h | 4 +-- .../unix/native/libjava/io_util_md.c | 4 +-- .../unix/native/libnet/NetworkInterface.c | 26 +++++++++---------- src/java.base/unix/native/libnet/SdpSupport.c | 2 +- .../unix/native/libnio/ch/UnixDomainSockets.c | 4 +-- 10 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/java.base/share/native/libjava/ClassLoader.c b/src/java.base/share/native/libjava/ClassLoader.c index 927432d15091a..4519a4777f84f 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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -114,7 +114,7 @@ Java_java_lang_ClassLoader_defineClass1(JNIEnv *env, (*env)->GetByteArrayRegion(env, data, offset, length, body); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { goto free_body; } @@ -259,7 +259,7 @@ Java_java_lang_ClassLoader_defineClass0(JNIEnv *env, (*env)->GetByteArrayRegion(env, data, offset, length, body); - if ((*env)->ExceptionOccurred(env)) + if ((*env)->ExceptionCheck(env)) goto free_body; if (name != NULL) { diff --git a/src/java.base/share/native/libjava/System.c b/src/java.base/share/native/libjava/System.c index 098b943cc40b8..7b038a6a9d59b 100644 --- a/src/java.base/share/native/libjava/System.c +++ b/src/java.base/share/native/libjava/System.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved. * 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 @@ Java_java_lang_System_identityHashCode(JNIEnv *env, jobject this, jobject x) if (jval == NULL) \ return NULL; \ (*env)->SetObjectArrayElement(env, array, jdk_internal_util_SystemProps_Raw_##prop_index, jval); \ - if ((*env)->ExceptionOccurred(env)) \ + if ((*env)->ExceptionCheck(env)) \ return NULL; \ (*env)->DeleteLocalRef(env, jval); \ } @@ -86,7 +86,7 @@ Java_java_lang_System_identityHashCode(JNIEnv *env, jobject this, jobject x) if (jval == NULL) \ return NULL; \ (*env)->SetObjectArrayElement(env, array, jdk_internal_util_SystemProps_Raw_##prop_index, jval); \ - if ((*env)->ExceptionOccurred(env)) \ + if ((*env)->ExceptionCheck(env)) \ return NULL; \ (*env)->DeleteLocalRef(env, jval); \ } diff --git a/src/java.base/share/native/libjava/io_util.c b/src/java.base/share/native/libjava/io_util.c index 3fb7675d2771e..76ff58ec632be 100644 --- a/src/java.base/share/native/libjava/io_util.c +++ b/src/java.base/share/native/libjava/io_util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -175,7 +175,7 @@ writeBytes(JNIEnv *env, jobject this, jbyteArray bytes, (*env)->GetByteArrayRegion(env, bytes, off, len, (jbyte *)buf); - if (!(*env)->ExceptionOccurred(env)) { + if (!(*env)->ExceptionCheck(env)) { off = 0; while (len > 0) { fd = getFD(env, this, fid); diff --git a/src/java.base/share/native/libjava/jni_util.c b/src/java.base/share/native/libjava/jni_util.c index 3d9004d969cb8..ce23d16043068 100644 --- a/src/java.base/share/native/libjava/jni_util.c +++ b/src/java.base/share/native/libjava/jni_util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -117,7 +117,7 @@ JNU_ThrowByNameWithLastError(JNIEnv *env, const char *name, (*env)->Throw(env, x); } } - if (!(*env)->ExceptionOccurred(env)) { + if (!(*env)->ExceptionCheck(env)) { JNU_ThrowByName(env, name, defaultDetail); } } @@ -166,7 +166,7 @@ JNU_ThrowByNameWithMessageAndLastError } } - if (!(*env)->ExceptionOccurred(env)) { + if (!(*env)->ExceptionCheck(env)) { if (messagelen > 0) { JNU_ThrowByName(env, name, message); } else { diff --git a/src/java.base/share/native/libjli/java.c b/src/java.base/share/native/libjli/java.c index d4e20fb21fe75..355ac4b9e289b 100644 --- a/src/java.base/share/native/libjli/java.c +++ b/src/java.base/share/native/libjli/java.c @@ -351,7 +351,7 @@ JLI_Launch(int argc, char ** argv, /* main argc, argv */ #define CHECK_EXCEPTION_NULL_LEAVE(CENL_exception) \ do { \ - if ((*env)->ExceptionOccurred(env)) { \ + if ((*env)->ExceptionCheck(env)) { \ JLI_ReportExceptionDescription(env); \ LEAVE(); \ } \ @@ -363,7 +363,7 @@ JLI_Launch(int argc, char ** argv, /* main argc, argv */ #define CHECK_EXCEPTION_LEAVE(CEL_return_value) \ do { \ - if ((*env)->ExceptionOccurred(env)) { \ + if ((*env)->ExceptionCheck(env)) { \ JLI_ReportExceptionDescription(env); \ ret = (CEL_return_value); \ LEAVE(); \ @@ -1522,7 +1522,7 @@ NewPlatformString(JNIEnv *env, char *s) if (ary != 0) { jstring str = 0; (*env)->SetByteArrayRegion(env, ary, 0, len, (jbyte *)s); - if (!(*env)->ExceptionOccurred(env)) { + if (!(*env)->ExceptionCheck(env)) { if (makePlatformStringMID == NULL) { NULL_CHECK0(makePlatformStringMID = (*env)->GetStaticMethodID(env, cls, "makePlatformString", "(Z[B)Ljava/lang/String;")); diff --git a/src/java.base/share/native/libjli/java.h b/src/java.base/share/native/libjli/java.h index ce5224a7da346..19493fedaaef9 100644 --- a/src/java.base/share/native/libjli/java.h +++ b/src/java.base/share/native/libjli/java.h @@ -246,14 +246,14 @@ typedef struct { #define CHECK_EXCEPTION_RETURN_VALUE(CER_value) \ do { \ - if ((*env)->ExceptionOccurred(env)) { \ + if ((*env)->ExceptionCheck(env)) { \ return CER_value; \ } \ } while (JNI_FALSE) #define CHECK_EXCEPTION_RETURN() \ do { \ - if ((*env)->ExceptionOccurred(env)) { \ + if ((*env)->ExceptionCheck(env)) { \ return; \ } \ } while (JNI_FALSE) diff --git a/src/java.base/unix/native/libjava/io_util_md.c b/src/java.base/unix/native/libjava/io_util_md.c index 28659b3a1c256..9895ac3b73f1d 100644 --- a/src/java.base/unix/native/libjava/io_util_md.c +++ b/src/java.base/unix/native/libjava/io_util_md.c @@ -135,7 +135,7 @@ void fileDescriptorClose(JNIEnv *env, jobject this) { FD fd = (*env)->GetIntField(env, this, IO_fd_fdID); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { return; } @@ -150,7 +150,7 @@ fileDescriptorClose(JNIEnv *env, jobject this) * taking extra precaution over here. */ (*env)->SetIntField(env, this, IO_fd_fdID, -1); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { return; } /* diff --git a/src/java.base/unix/native/libnet/NetworkInterface.c b/src/java.base/unix/native/libnet/NetworkInterface.c index 0cd69399d9181..61267ec13d537 100644 --- a/src/java.base/unix/native/libnet/NetworkInterface.c +++ b/src/java.base/unix/native/libnet/NetworkInterface.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -374,7 +374,7 @@ JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_boundInetAddress0 if (family == AF_INET) { sock = openSocket(env, AF_INET); - if (sock < 0 && (*env)->ExceptionOccurred(env)) { + if (sock < 0 && (*env)->ExceptionCheck(env)) { return JNI_FALSE; } @@ -383,7 +383,7 @@ JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_boundInetAddress0 ifs = enumIPv4Interfaces(env, sock, ifs); close(sock); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { goto cleanup; } } @@ -401,7 +401,7 @@ JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_boundInetAddress0 ifs = enumIPv6Interfaces(env, sock, ifs); close(sock); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { goto cleanup; } @@ -856,7 +856,7 @@ static netif *enumInterfaces(JNIEnv *env) { int sock; sock = openSocket(env, AF_INET); - if (sock < 0 && (*env)->ExceptionOccurred(env)) { + if (sock < 0 && (*env)->ExceptionCheck(env)) { return NULL; } @@ -865,7 +865,7 @@ static netif *enumInterfaces(JNIEnv *env) { ifs = enumIPv4Interfaces(env, sock, ifs); close(sock); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { freeif(ifs); return NULL; } @@ -884,7 +884,7 @@ static netif *enumInterfaces(JNIEnv *env) { ifs = enumIPv6Interfaces(env, sock, ifs); close(sock); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { freeif(ifs); return NULL; } @@ -1237,7 +1237,7 @@ static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) { &addr, broadaddrP, AF_INET, prefix); // in case of exception, free interface list and buffer and return NULL - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { free(buf); freeif(ifs); return NULL; @@ -1281,7 +1281,7 @@ static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) { NULL, AF_INET6, (short)prefix); // if an exception occurred then return the list as is - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { break; } } @@ -1478,7 +1478,7 @@ static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) { &addr, broadaddrP, AF_INET, prefix); // in case of exception, free interface list and buffer and return NULL - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { free(buf); freeif(ifs); return NULL; @@ -1552,7 +1552,7 @@ static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) { NULL, AF_INET6, prefix); // if an exception occurred then free the list - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { free(buf); freeif(ifs); return NULL; @@ -1717,7 +1717,7 @@ static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) { ifa->ifa_netmask)); // if an exception occurred then free the list - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { freeifaddrs(origifa); freeif(ifs); return NULL; @@ -1757,7 +1757,7 @@ static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) { ifa->ifa_netmask)); // if an exception occurred then free the list - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { freeifaddrs(origifa); freeif(ifs); return NULL; diff --git a/src/java.base/unix/native/libnet/SdpSupport.c b/src/java.base/unix/native/libnet/SdpSupport.c index 6729170efb4cb..b56f16905fa23 100644 --- a/src/java.base/unix/native/libnet/SdpSupport.c +++ b/src/java.base/unix/native/libnet/SdpSupport.c @@ -106,7 +106,7 @@ Java_sun_net_sdp_SdpSupport_convert0(JNIEnv *env, jclass cls, int fd) if (res < 0) JNU_ThrowIOExceptionWithLastError(env, "dup2"); res = close(s); - if (res < 0 && !(*env)->ExceptionOccurred(env)) + if (res < 0 && !(*env)->ExceptionCheck(env)) JNU_ThrowIOExceptionWithLastError(env, "close"); } } diff --git a/src/java.base/unix/native/libnio/ch/UnixDomainSockets.c b/src/java.base/unix/native/libnio/ch/UnixDomainSockets.c index 73db22a917620..c43c3b9069529 100644 --- a/src/java.base/unix/native/libnio/ch/UnixDomainSockets.c +++ b/src/java.base/unix/native/libnio/ch/UnixDomainSockets.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * 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,7 +62,7 @@ jbyteArray sockaddrToUnixAddressBytes(JNIEnv *env, struct sockaddr_un *sa, sockl jbyteArray name = (*env)->NewByteArray(env, namelen); if (namelen != 0) { (*env)->SetByteArrayRegion(env, name, 0, namelen, (jbyte*)sa->sun_path); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { return NULL; } } From a5cad0ee1e86285b7d2561dfce37f2b22067c9e6 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Thu, 10 Oct 2024 17:33:38 +0000 Subject: [PATCH 021/118] 8341791: Fix ExceptionOccurred in java.prefs Reviewed-by: bpb, jpai, naoto --- .../native/libprefs/MacOSXPreferencesFile.m | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/java.prefs/macosx/native/libprefs/MacOSXPreferencesFile.m b/src/java.prefs/macosx/native/libprefs/MacOSXPreferencesFile.m index eb2338ca94491..bc3d9aaf68242 100644 --- a/src/java.prefs/macosx/native/libprefs/MacOSXPreferencesFile.m +++ b/src/java.prefs/macosx/native/libprefs/MacOSXPreferencesFile.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * 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 @@ static void throwOutOfMemoryError(JNIEnv *env, const char *msg) c = exceptionClass; } else { c = (*env)->FindClass(env, "java/lang/OutOfMemoryError"); - if ((*env)->ExceptionOccurred(env)) return; + if ((*env)->ExceptionCheck(env)) return; exceptionClass = (*env)->NewGlobalRef(env, c); } @@ -211,7 +211,7 @@ static jarray createJavaStringArray(JNIEnv *env, CFIndex count) c = stringClass; } else { c = (*env)->FindClass(env, "java/lang/String"); - if ((*env)->ExceptionOccurred(env)) return NULL; + if ((*env)->ExceptionCheck(env)) return NULL; stringClass = (*env)->NewGlobalRef(env, c); } @@ -892,7 +892,7 @@ static void createTreeForPath(CFStringRef path, CFStringRef name, result = NULL; } else { CFStringRef cfString = copyToCFString(env, value); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { // memory error in copyToCFString result = NULL; } else if (cfString == NULL) { @@ -940,10 +940,10 @@ static void BuildJavaArrayFn(const void *key, const void *value, void *context) CFStringRef cfString = NULL; JNIEnv *env = args->env; - if ((*env)->ExceptionOccurred(env)) return; // already failed + if ((*env)->ExceptionCheck(env)) return; // already failed cfString = copyToCFString(env, propkey); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { // memory error in copyToCFString } else if (!cfString) { // bogus value type in prefs file - no Java errors available @@ -960,9 +960,9 @@ static void BuildJavaArrayFn(const void *key, const void *value, void *context) } if (CFStringGetLength(cfString) <= 0) goto bad; // ignore empty javaString = toJavaString(env, cfString); - if ((*env)->ExceptionOccurred(env)) goto bad; + if ((*env)->ExceptionCheck(env)) goto bad; (*env)->SetObjectArrayElement(env, args->result,args->used,javaString); - if ((*env)->ExceptionOccurred(env)) goto bad; + if ((*env)->ExceptionCheck(env)) goto bad; args->used++; } @@ -1003,7 +1003,7 @@ static jarray getStringsForNode(JNIEnv *env, jobject klass, jobject jpath, args.used = 0; args.allowSlash = allowSlash; CFDictionaryApplyFunction(node, BuildJavaArrayFn, &args); - if (!(*env)->ExceptionOccurred(env)) { + if (!(*env)->ExceptionCheck(env)) { // array construction succeeded if (args.used < count) { // finished array is smaller than expected. From 32f817a46068b61d599b714a4480e3ea5d6e9050 Mon Sep 17 00:00:00 2001 From: Harshitha Onkar Date: Thu, 10 Oct 2024 17:55:26 +0000 Subject: [PATCH 022/118] 8340978: Open source few DnD tests - Set6 Reviewed-by: prr --- test/jdk/ProblemList.txt | 1 + .../java/awt/dnd/CustomDragCursorTest.java | 289 ++++++++++++++++++ .../DnDAcceptanceTest/DnDAcceptanceTest.java | 87 ++++++ .../awt/dnd/DnDAcceptanceTest/DnDSource.java | 155 ++++++++++ .../awt/dnd/DnDAcceptanceTest/DnDTarget.java | 115 +++++++ 5 files changed, 647 insertions(+) create mode 100644 test/jdk/java/awt/dnd/CustomDragCursorTest.java create mode 100644 test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDAcceptanceTest.java create mode 100644 test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDSource.java create mode 100644 test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDTarget.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index fb20eb1f63de9..66ba244a6e2aa 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -131,6 +131,7 @@ java/awt/dnd/URIListBetweenJVMsTest/URIListBetweenJVMsTest.java 8171510 macosx-a java/awt/dnd/MissingDragExitEventTest/MissingDragExitEventTest.java 8288839 windows-x64 java/awt/dnd/DragExitBeforeDropTest.java 8242805 macosx-all java/awt/dnd/DragThresholdTest.java 8076299 macosx-all +java/awt/dnd/CustomDragCursorTest.java 8242805 macosx-all java/awt/Focus/ChoiceFocus/ChoiceFocus.java 8169103 windows-all,macosx-all java/awt/Focus/ClearLwQueueBreakTest/ClearLwQueueBreakTest.java 8198618 macosx-all java/awt/Focus/ConsumeNextKeyTypedOnModalShowTest/ConsumeNextKeyTypedOnModalShowTest.java 6986252 macosx-all diff --git a/test/jdk/java/awt/dnd/CustomDragCursorTest.java b/test/jdk/java/awt/dnd/CustomDragCursorTest.java new file mode 100644 index 0000000000000..9e5e006b31c81 --- /dev/null +++ b/test/jdk/java/awt/dnd/CustomDragCursorTest.java @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * 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.Button; +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.DragSourceListener; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetContext; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetEvent; +import java.awt.dnd.DropTargetListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +/* + * @test + * @bug 4451328 + * @summary tests that a custom drag cursor is not changed + to the default drag cursor + * @key headful + * @run main CustomDragCursorTest + */ + +public class CustomDragCursorTest { + private static Frame frame; + private static final DragSourcePanel dragSourcePanel = new DragSourcePanel(); + private static final DropTargetPanel dropTargetPanel = new DropTargetPanel(); + + private static volatile Point srcPoint; + private static volatile Point dstPoint; + private static volatile boolean passed = true; + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + EventQueue.invokeAndWait(CustomDragCursorTest::createAndShowUI); + robot.waitForIdle(); + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + Point p = dragSourcePanel.getLocationOnScreen(); + Dimension d = dragSourcePanel.getSize(); + p.translate(d.width / 2, d.height / 2); + srcPoint = p; + + p = dropTargetPanel.getLocationOnScreen(); + d = dropTargetPanel.getSize(); + p.translate(d.width / 2, d.height / 2); + dstPoint = p; + }); + + robot.mouseMove(srcPoint.x, srcPoint.y); + robot.keyPress(KeyEvent.VK_CONTROL); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + for (; !srcPoint.equals(dstPoint); + srcPoint.translate(sign(dstPoint.x - srcPoint.x), + sign(dstPoint.y - srcPoint.y))) { + robot.mouseMove(srcPoint.x, srcPoint.y); + robot.delay(10); + } + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.keyRelease(KeyEvent.VK_CONTROL); + robot.waitForIdle(); + robot.delay(1000); + + if (!passed) { + throw new RuntimeException("Custom drag cursor changed to default."); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void createAndShowUI() { + frame = new Frame("CustomDragCursorTest"); + frame.setLayout(new GridLayout(2, 1)); + frame.add(dragSourcePanel); + frame.add(dropTargetPanel); + frame.setLocationRelativeTo(null); + frame.setSize(300, 400); + frame.setVisible(true); + } + + public static void failed() { + passed = false; + } + + private static int sign(int n) { + return Integer.compare(n, 0); + } + + private static class DragSourceButton extends Button implements Serializable, + Transferable, + DragGestureListener, + DragSourceListener { + private final DataFlavor dataflavor = + new DataFlavor(Button.class, "DragSourceButton"); + private final Cursor dragCursor = new Cursor(Cursor.HAND_CURSOR); + + public DragSourceButton() { + this("DragSourceButton"); + } + + public DragSourceButton(String str) { + super(str); + + DragSource ds = DragSource.getDefaultDragSource(); + ds.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY, + this); + } + + public void dragGestureRecognized(DragGestureEvent dge) { + dge.startDrag(dragCursor, this, this); + } + + public void dragEnter(DragSourceDragEvent dsde) { + if (!dragCursor.equals(dsde.getDragSourceContext().getCursor())) { + CustomDragCursorTest.failed(); + } + } + + public void dragExit(DragSourceEvent dse) { + if (!dragCursor.equals(dse.getDragSourceContext().getCursor())) { + CustomDragCursorTest.failed(); + } + } + + public void dragOver(DragSourceDragEvent dsde) { + if (!dragCursor.equals(dsde.getDragSourceContext().getCursor())) { + CustomDragCursorTest.failed(); + } + } + + public void dragDropEnd(DragSourceDropEvent dsde) { + if (!dragCursor.equals(dsde.getDragSourceContext().getCursor())) { + CustomDragCursorTest.failed(); + } + } + + public void dropActionChanged(DragSourceDragEvent dsde) { + if (!dragCursor.equals(dsde.getDragSourceContext().getCursor())) { + CustomDragCursorTest.failed(); + } + } + + public Object getTransferData(DataFlavor flavor) + throws UnsupportedFlavorException, IOException { + + if (!isDataFlavorSupported(flavor)) { + throw new UnsupportedFlavorException(flavor); + } + + Object retObj; + + ByteArrayOutputStream baoStream = new ByteArrayOutputStream(); + ObjectOutputStream ooStream = new ObjectOutputStream(baoStream); + ooStream.writeObject(this); + + ByteArrayInputStream baiStream = new ByteArrayInputStream(baoStream.toByteArray()); + ObjectInputStream ois = new ObjectInputStream(baiStream); + try { + retObj = ois.readObject(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + throw new RuntimeException(e.toString()); + } + + return retObj; + } + + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[] { dataflavor }; + } + + public boolean isDataFlavorSupported(DataFlavor dflavor) { + return dataflavor.equals(dflavor); + } + } + + private static class DragSourcePanel extends Panel { + + final Dimension preferredDimension = new Dimension(200, 100); + + public DragSourcePanel() { + setLayout(new GridLayout(1, 1)); + add(new DragSourceButton()); + } + + public Dimension getPreferredSize() { + return preferredDimension; + } + } + + private static class DropTargetPanel extends Panel implements DropTargetListener { + + final Dimension preferredDimension = new Dimension(200, 100); + + public DropTargetPanel() { + setDropTarget(new DropTarget(this, this)); + } + + public Dimension getPreferredSize() { + return preferredDimension; + } + + public void dragEnter(DropTargetDragEvent dtde) {} + + public void dragExit(DropTargetEvent dte) {} + + public void dragOver(DropTargetDragEvent dtde) {} + + public void dropActionChanged(DropTargetDragEvent dtde) {} + + public void drop(DropTargetDropEvent dtde) { + DropTargetContext dtc = dtde.getDropTargetContext(); + + if ((dtde.getSourceActions() & DnDConstants.ACTION_COPY) != 0) { + dtde.acceptDrop(DnDConstants.ACTION_COPY); + } else { + dtde.rejectDrop(); + } + + DataFlavor[] dfs = dtde.getCurrentDataFlavors(); + Component comp = null; + + if(dfs != null && dfs.length >= 1) { + Transferable transfer = dtde.getTransferable(); + + try { + comp = (Component)transfer.getTransferData(dfs[0]); + } catch (Throwable e) { + e.printStackTrace(); + dtc.dropComplete(false); + } + } + dtc.dropComplete(true); + add(comp); + } + } +} diff --git a/test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDAcceptanceTest.java b/test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDAcceptanceTest.java new file mode 100644 index 0000000000000..700187f9dce49 --- /dev/null +++ b/test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDAcceptanceTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * 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.Component; +import java.awt.Frame; +import java.awt.Panel; + +/* + * @test + * @bug 4166541 4225247 4297663 + * @summary Tests Basic DnD functionality + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DnDAcceptanceTest + */ + +public class DnDAcceptanceTest { + private static final String INSTRUCTIONS = """ + When test runs a Frame which contains a yellow button labeled + "Drag ME!" and a RED Panel will appear. + + Click on the button and drag to the red panel. + When the mouse enters the red panel + during the drag the panel should turn yellow. + + Release the mouse button, panel should turn red again and + a yellow button labeled Drag ME! should appear inside the panel. + You should be able to repeat this operation multiple times. + + If above is true press PASS, else press FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(38) + .testUI(DnDAcceptanceTest::createUI) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame frame = new Frame("DnDAcceptanceTest"); + Panel mainPanel; + Component dragSource, dropTarget; + + frame.setSize(400, 400); + frame.setLayout(new BorderLayout()); + + mainPanel = new Panel(); + mainPanel.setLayout(new BorderLayout()); + + mainPanel.setBackground(Color.BLACK); + + dropTarget = new DnDTarget(Color.RED, Color.YELLOW); + dragSource = new DnDSource("Drag ME!"); + + mainPanel.add(dragSource, "North"); + mainPanel.add(dropTarget, "Center"); + frame.add(mainPanel, BorderLayout.CENTER); + frame.setAlwaysOnTop(true); + return frame; + } +} diff --git a/test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDSource.java b/test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDSource.java new file mode 100644 index 0000000000000..a35ccd9ee12cb --- /dev/null +++ b/test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDSource.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * 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.Button; +import java.awt.Color; +import java.awt.Container; +import java.awt.Toolkit; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.MouseDragGestureRecognizer; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.DragSourceListener; +import java.awt.dnd.InvalidDnDOperationException; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +class DnDSource extends Button implements Transferable, + DragGestureListener, + DragSourceListener { + private DataFlavor df; + private transient int dropAction; + + DnDSource(String label) { + super(label); + Toolkit.getDefaultToolkit().createDragGestureRecognizer(MouseDragGestureRecognizer.class, + DragSource.getDefaultDragSource(), + this, DnDConstants.ACTION_COPY, this); + setBackground(Color.yellow); + setForeground(Color.blue); + df = new DataFlavor(DnDSource.class, "DnDSource"); + } + + public void dragGestureRecognized(DragGestureEvent dge) { + System.err.println("starting Drag"); + try { + dge.startDrag(null, this, this); + } catch (InvalidDnDOperationException e) { + e.printStackTrace(); + } + } + + public void dragEnter(DragSourceDragEvent dsde) { + System.err.println("[Source] dragEnter"); + dsde.getDragSourceContext().setCursor(DragSource.DefaultCopyDrop); + } + + public void dragOver(DragSourceDragEvent dsde) { + System.err.println("[Source] dragOver"); + dropAction = dsde.getDropAction(); + System.out.println("dropAction = " + dropAction); + } + + public void dragGestureChanged(DragSourceDragEvent dsde) { + System.err.println("[Source] dragGestureChanged"); + dropAction = dsde.getDropAction(); + System.out.println("dropAction = " + dropAction); + } + + public void dragExit(DragSourceEvent dsde) { + System.err.println("[Source] dragExit"); + dsde.getDragSourceContext().setCursor(null); + } + + public void dragDropEnd(DragSourceDropEvent dsde) { + System.err.println("[Source] dragDropEnd"); + } + + public void dropActionChanged(DragSourceDragEvent dsde) { + System.err.println("[Source] dropActionChanged"); + dropAction = dsde.getDropAction(); + System.out.println("dropAction = " + dropAction); + } + + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[] {df}; + } + + public boolean isDataFlavorSupported(DataFlavor sdf) { + return df.equals(sdf); + } + + public Object getTransferData(DataFlavor tdf) throws UnsupportedFlavorException, IOException { + + Object copy = null; + + if (!df.equals(tdf)) { + throw new UnsupportedFlavorException(tdf); + } + Container parent = getParent(); + switch (dropAction) { + case DnDConstants.ACTION_COPY: + try { + copy = this.clone(); + } catch (CloneNotSupportedException e) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + + oos.writeObject(this); + ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + ObjectInputStream ois = new ObjectInputStream(bais); + try { + copy = ois.readObject(); + } catch (ClassNotFoundException cnfe) { + // do nothing + } + } + + parent.add(this); + return copy; + + case DnDConstants.ACTION_MOVE: + synchronized(this) { + if (parent != null) parent.remove(this); + } + return this; + + case DnDConstants.ACTION_LINK: + return this; + + default: + //throw new IOException("bad operation"); + return this; // workaround for: 4135456 getDropAction() always return 0 + } + } +} diff --git a/test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDTarget.java b/test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDTarget.java new file mode 100644 index 0000000000000..d147741f0d225 --- /dev/null +++ b/test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDTarget.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * 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.Button; +import java.awt.Color; +import java.awt.Panel; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetContext; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetEvent; +import java.awt.dnd.DropTargetListener; +import java.io.IOException; + +class DnDTarget extends Panel implements DropTargetListener { + Color bgColor; + Color htColor; + + DnDTarget(Color bgColor, Color htColor) { + super(); + this.bgColor = bgColor; + this.htColor = htColor; + setBackground(bgColor); + setDropTarget(new DropTarget(this, this)); + } + + public void dragEnter(DropTargetDragEvent e) { + System.err.println("[Target] dragEnter"); + e.acceptDrag(DnDConstants.ACTION_COPY); + setBackground(htColor); + repaint(); + } + + public void dragOver(DropTargetDragEvent e) { + System.err.println("[Target] dragOver"); + e.acceptDrag(DnDConstants.ACTION_COPY); + } + + public void dragExit(DropTargetEvent e) { + System.err.println("[Target] dragExit"); + setBackground(bgColor); + repaint(); + } + + public void drop(DropTargetDropEvent dtde) { + System.err.println("[Target] drop"); + DropTargetContext dtc = dtde.getDropTargetContext(); + + if ((dtde.getSourceActions() & DnDConstants.ACTION_COPY) != 0) { + dtde.acceptDrop(DnDConstants.ACTION_COPY); + } else { + dtde.rejectDrop(); + return; + } + + DataFlavor[] dfs = dtde.getCurrentDataFlavors(); + if (dfs != null && dfs.length >= 1) { + Transferable transfer = dtde.getTransferable(); + Object obj; + try { + obj = transfer.getTransferData(dfs[0]); + } catch (IOException | UnsupportedFlavorException ex) { + System.err.println(ex.getMessage()); + dtc.dropComplete(false); + return; + } + + if (obj != null) { + Button button; + try { + button = (Button) obj; + } catch (Exception e) { + System.err.println(e.getMessage()); + dtc.dropComplete(false); + return; + } + add(button); + repaint(); + } + } + setBackground(bgColor); + invalidate(); + validate(); + repaint(); + dtc.dropComplete(true); + } + + public void dropActionChanged(DropTargetDragEvent e) { + System.err.println("[Target] dropActionChanged"); + } +} From 2a6f0307e8d287fc9177e9454386e63faf8e61a0 Mon Sep 17 00:00:00 2001 From: Daniel Gredler Date: Thu, 10 Oct 2024 18:00:33 +0000 Subject: [PATCH 023/118] 8339974: Graphics2D.drawString doesn't always work with Font derived from AffineTransform Reviewed-by: prr, azvegint --- .../classes/java/awt/font/TextLayout.java | 11 +- .../share/classes/java/awt/font/TextLine.java | 6 +- .../FontScaling/RotatedScaledFontTest.java | 149 +++++++++++++ .../PostScriptRotatedScaledFontTest.java | 211 ++++++++++++++++++ 4 files changed, 371 insertions(+), 6 deletions(-) create mode 100644 test/jdk/java/awt/font/FontScaling/RotatedScaledFontTest.java create mode 100644 test/jdk/javax/print/PostScriptRotatedScaledFontTest.java 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 352d3c81df247..855097b6a26b0 100644 --- a/src/java.desktop/share/classes/java/awt/font/TextLayout.java +++ b/src/java.desktop/share/classes/java/awt/font/TextLayout.java @@ -2663,11 +2663,20 @@ static byte getBaselineFromGraphic(GraphicAttribute graphic) { */ public Shape getOutline(AffineTransform tx) { ensureCache(); - Shape result = textLine.getOutline(tx); + Shape result = textLine.getOutline(); LayoutPathImpl lp = textLine.getLayoutPath(); if (lp != null) { result = lp.mapShape(result); } + if (tx != null) { + if (result instanceof GeneralPath gp) { + // transform in place + gp.transform(tx); + } else { + // create a transformed copy + result = tx.createTransformedShape(result); + } + } return result; } diff --git a/src/java.desktop/share/classes/java/awt/font/TextLine.java b/src/java.desktop/share/classes/java/awt/font/TextLine.java index 9d5da23bfe76a..1e4b9c784a69c 100644 --- a/src/java.desktop/share/classes/java/awt/font/TextLine.java +++ b/src/java.desktop/share/classes/java/awt/font/TextLine.java @@ -864,19 +864,15 @@ public Rectangle2D getItalicBounds() { return new Rectangle2D.Float(left, top, right-left, bottom-top); } - public Shape getOutline(AffineTransform tx) { + public Shape getOutline() { GeneralPath dstShape = new GeneralPath(GeneralPath.WIND_NON_ZERO); for (int i=0, n = 0; i < fComponents.length; i++, n += 2) { TextLineComponent tlc = fComponents[getComponentLogicalIndex(i)]; - dstShape.append(tlc.getOutline(locs[n], locs[n+1]), false); } - if (tx != null) { - dstShape.transform(tx); - } return dstShape; } diff --git a/test/jdk/java/awt/font/FontScaling/RotatedScaledFontTest.java b/test/jdk/java/awt/font/FontScaling/RotatedScaledFontTest.java new file mode 100644 index 0000000000000..3e17bbd92c18d --- /dev/null +++ b/test/jdk/java/awt/font/FontScaling/RotatedScaledFontTest.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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.Font; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.io.File; + +import javax.imageio.ImageIO; + +/* + * @test + * @bug 8339974 + * @summary Verifies that text draws correctly using scaled and rotated fonts. + */ +public class RotatedScaledFontTest { + + public static void main(String[] args) throws Exception { + test(0); + test(1); + test(2); + test(3); + test(4); + } + + private static void test(int quadrants) throws Exception { + + int size = 2000; + int center = size / 2; + Font base = new Font("SansSerif", Font.PLAIN, 10); + BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_BYTE_BINARY); + Graphics2D g2d = image.createGraphics(); + + try { + for (int scale = 1; scale <= 100; scale++) { + AffineTransform at = AffineTransform.getQuadrantRotateInstance(quadrants); + at.scale(scale, scale); + Font font = base.deriveFont(at); + g2d.setColor(Color.WHITE); + g2d.fillRect(0, 0, image.getWidth(), image.getHeight()); + g2d.setColor(Color.BLACK); + g2d.setFont(font); + g2d.drawString("TEST", center, center); + Rectangle bounds = findTextBoundingBox(image); + if (bounds == null) { + saveImage("bounds", image); + throw new RuntimeException("Text missing: scale=" + scale + + ", quadrants=" + quadrants + ", center=" + center); + } + boolean horizontal = (bounds.width > bounds.height); + boolean expectedHorizontal = (quadrants % 2 == 0); + if (horizontal != expectedHorizontal) { + saveImage("orientation", image); + throw new RuntimeException("Wrong orientation: scale=" + scale + + ", quadrants=" + quadrants + ", center=" + center + + ", bounds=" + bounds + ", horizontal=" + horizontal + + ", expectedHorizontal=" + expectedHorizontal); + } + if (!roughlyEqual(center, bounds.x, scale) && !roughlyEqual(center, bounds.x + bounds.width, scale)) { + saveImage("xedge", image); + throw new RuntimeException("No x-edge at center: scale=" + scale + + ", quadrants=" + quadrants + ", center=" + center + + ", bounds=" + bounds); + } + if (!roughlyEqual(center, bounds.y, scale) && !roughlyEqual(center, bounds.y + bounds.height, scale)) { + saveImage("yedge", image); + throw new RuntimeException("No y-edge at center: scale=" + scale + + ", quadrants=" + quadrants + ", center=" + center + + ", bounds=" + bounds); + } + } + } finally { + g2d.dispose(); + } + } + + private static Rectangle findTextBoundingBox(BufferedImage image) { + int minX = Integer.MAX_VALUE; + int minY = Integer.MAX_VALUE; + int maxX = Integer.MIN_VALUE; + int maxY = Integer.MIN_VALUE; + int width = image.getWidth(); + int height = image.getHeight(); + int[] rowPixels = new int[width]; + for (int y = 0; y < height; y++) { + image.getRGB(0, y, width, 1, rowPixels, 0, width); + for (int x = 0; x < width; x++) { + boolean white = (rowPixels[x] == -1); + if (!white) { + if (x < minX) { + minX = x; + } + if (y < minY) { + minY = y; + } + if (x > maxX) { + maxX = x; + } + if (y > maxY) { + maxY = y; + } + } + } + } + if (minX != Integer.MAX_VALUE) { + return new Rectangle(minX, minY, maxX - minX, maxY - minY); + } else { + return null; + } + } + + private static boolean roughlyEqual(int x1, int x2, int scale) { + return Math.abs(x1 - x2) <= Math.ceil(scale / 2d) + 1; // higher scale = higher allowed variance + } + + private static void saveImage(String name, BufferedImage image) { + try { + String dir = System.getProperty("test.classes", "."); + String path = dir + File.separator + name + ".png"; + File file = new File(path); + ImageIO.write(image, "png", file); + } catch (Exception e) { + // we tried, and that's enough + } + } +} diff --git a/test/jdk/javax/print/PostScriptRotatedScaledFontTest.java b/test/jdk/javax/print/PostScriptRotatedScaledFontTest.java new file mode 100644 index 0000000000000..e6e274f7cac42 --- /dev/null +++ b/test/jdk/javax/print/PostScriptRotatedScaledFontTest.java @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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.Font; +import java.awt.Graphics; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.print.PageFormat; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.io.ByteArrayOutputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +import javax.print.Doc; +import javax.print.DocFlavor; +import javax.print.DocPrintJob; +import javax.print.SimpleDoc; +import javax.print.StreamPrintService; +import javax.print.StreamPrintServiceFactory; +import javax.print.event.PrintJobAdapter; +import javax.print.event.PrintJobEvent; + +/* + * @test + * @bug 8339974 + * @summary Verifies that text prints correctly using scaled and rotated fonts. + */ +public class PostScriptRotatedScaledFontTest { + + public static void main(String[] args) throws Exception { + test(0); + test(1); + test(2); + test(3); + test(4); + } + + private static void test(int quadrants) throws Exception { + + DocFlavor flavor = DocFlavor.SERVICE_FORMATTED.PRINTABLE; + String mime = "application/postscript"; + StreamPrintServiceFactory[] factories = StreamPrintServiceFactory.lookupStreamPrintServiceFactories(flavor, mime); + if (factories.length == 0) { + throw new RuntimeException("Unable to find PostScript print service factory"); + } + + StreamPrintServiceFactory factory = factories[0]; + + // required to trigger "text-as-shapes" code path in + // PSPathGraphics.drawString(String, float, float, Font, FontRenderContext, float) + // for *all* text, not just text that uses a transformed font + String shapeText = "sun.java2d.print.shapetext"; + System.setProperty(shapeText, "true"); + + try { + for (int scale = 1; scale <= 100; scale++) { + + ByteArrayOutputStream output = new ByteArrayOutputStream(); + StreamPrintService service = factory.getPrintService(output); + DocPrintJob job = service.createPrintJob(); + + PrintJobMonitor monitor = new PrintJobMonitor(); + job.addPrintJobListener(monitor); + + Printable printable = new TestPrintable(scale, quadrants); + Doc doc = new SimpleDoc(printable, flavor, null); + job.print(doc, null); + monitor.waitForJobToFinish(); + + byte[] ps = output.toByteArray(); + Rectangle2D.Double bounds = findTextBoundingBox(ps); + if (bounds == null) { + throw new RuntimeException("Text missing: scale=" + scale + + ", quadrants=" + quadrants); + } + + boolean horizontal = (bounds.width > bounds.height); + boolean expectedHorizontal = (quadrants % 2 == 0); + if (horizontal != expectedHorizontal) { + throw new RuntimeException("Wrong orientation: scale=" + scale + + ", quadrants=" + quadrants + ", bounds=" + bounds + + ", expectedHorizontal=" + expectedHorizontal + + ", horizontal=" + horizontal); + } + } + } finally { + System.clearProperty(shapeText); + } + } + + // very basic, uses moveto ("x y M"), lineto ("x y L"), and curveto ("x1 y1 x2 y2 x3 y3 C") + private static Rectangle2D.Double findTextBoundingBox(byte[] ps) { + double minX = Double.MAX_VALUE; + double minY = Double.MAX_VALUE; + double maxX = Double.MIN_VALUE; + double maxY = Double.MIN_VALUE; + boolean pastPageClip = false; + List< String > lines = new String(ps, StandardCharsets.ISO_8859_1).lines().toList(); + for (String line : lines) { + if (!pastPageClip) { + pastPageClip = "WC".equals(line); + continue; + } + String[] values = line.split(" "); + if (values.length == 3 || values.length == 7) { + String cmd = values[values.length - 1]; + if ("M".equals(cmd) || "L".equals(cmd) || "C".equals(cmd)) { + String sx = values[values.length - 3]; + String sy = values[values.length - 2]; + double x = Double.parseDouble(sx); + double y = Double.parseDouble(sy); + if (x < minX) { + minX = x; + } + if (y < minY) { + minY = y; + } + if (x > maxX) { + maxX = x; + } + if (y > maxY) { + maxY = y; + } + } + } + } + if (minX != Double.MAX_VALUE) { + return new Rectangle2D.Double(minX, minY, maxX - minX, maxY - minY); + } else { + return null; + } + } + + private static final class TestPrintable implements Printable { + private final int scale; + private final int quadrants; + public TestPrintable(int scale, int quadrants) { + this.scale = scale; + this.quadrants = quadrants; + } + @Override + public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException { + if (pageIndex > 0) { + return NO_SUCH_PAGE; + } + AffineTransform at = AffineTransform.getQuadrantRotateInstance(quadrants); + at.scale(scale, scale); + Font base = new Font("SansSerif", Font.PLAIN, 10); + Font font = base.deriveFont(at); + graphics.setFont(font); + graphics.drawString("TEST", 300, 300); + return PAGE_EXISTS; + } + } + + private static class PrintJobMonitor extends PrintJobAdapter { + private boolean finished; + @Override + public void printJobCanceled(PrintJobEvent pje) { + finished(); + } + @Override + public void printJobCompleted(PrintJobEvent pje) { + finished(); + } + @Override + public void printJobFailed(PrintJobEvent pje) { + finished(); + } + @Override + public void printJobNoMoreEvents(PrintJobEvent pje) { + finished(); + } + private synchronized void finished() { + finished = true; + notify(); + } + public synchronized void waitForJobToFinish() { + try { + while (!finished) { + wait(); + } + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } +} From 97ee8bbda2c7d7f76866690a34a5021fade2f438 Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Thu, 10 Oct 2024 18:17:55 +0000 Subject: [PATCH 024/118] 8340173: Open source some Component/Panel/EventQueue tests - Set2 Reviewed-by: honkar --- test/jdk/ProblemList.txt | 1 + .../PushPopDeadlock/PushPopDeadlock.java | 97 ++++ .../MultipleAddNotifyTest.java | 118 +++++ .../PopupTest/PopupTest.java | 93 ++++ .../awt/Panel/PanelRepaint/PanelRepaint.java | 455 ++++++++++++++++++ 5 files changed, 764 insertions(+) create mode 100644 test/jdk/java/awt/EventQueue/PushPopDeadlock/PushPopDeadlock.java create mode 100644 test/jdk/java/awt/LightweightComponent/MultipleAddNotifyTest/MultipleAddNotifyTest.java create mode 100644 test/jdk/java/awt/LightweightComponent/PopupTest/PopupTest.java create mode 100644 test/jdk/java/awt/Panel/PanelRepaint/PanelRepaint.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 66ba244a6e2aa..db48c24cd7e63 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -144,6 +144,7 @@ java/awt/Focus/TestDisabledAutoTransferSwing.java 6962362 windows-all java/awt/Focus/ActivateOnProperAppContextTest.java 8136516 macosx-all java/awt/Focus/FocusPolicyTest.java 7160904 linux-all java/awt/EventQueue/6980209/bug6980209.java 8198615 macosx-all +java/awt/EventQueue/PushPopDeadlock/PushPopDeadlock.java 8024034 generic-all java/awt/grab/EmbeddedFrameTest1/EmbeddedFrameTest1.java 7080150 macosx-all java/awt/event/InputEvent/EventWhenTest/EventWhenTest.java 8168646 generic-all java/awt/Mixing/AWT_Mixing/HierarchyBoundsListenerMixingTest.java 8049405 macosx-all diff --git a/test/jdk/java/awt/EventQueue/PushPopDeadlock/PushPopDeadlock.java b/test/jdk/java/awt/EventQueue/PushPopDeadlock/PushPopDeadlock.java new file mode 100644 index 0000000000000..82ca54871848e --- /dev/null +++ b/test/jdk/java/awt/EventQueue/PushPopDeadlock/PushPopDeadlock.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * 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 4212687 + * @summary Verifies that calling EventQueue.push() and EventQueue.pop() + * does not deadlock. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual PushPopDeadlock + */ + +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Robot; +import java.awt.Toolkit; + +public class PushPopDeadlock { + static int counter = 0; + static Robot robot; + static Frame f; + static Label l; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + String INSTRUCTIONS = """ + Click rapidly in the Frame labeled 'Click Here!'. + The number in the Frame should continue to increase. If the number + stops increasing (remains at a constant value), the test fails. + """; + + PassFailJFrame pfJFrame = PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(PushPopDeadlock::createUI) + .build(); + PushPopDeadlock.test(); + pfJFrame.awaitAndCheck(); + } + + public static Frame createUI() { + f = new Frame("Click Here!"); + l = new Label("Counter: " + counter); + f.add(l); + f.setSize(200, 200); + return f; + } + + public static void test() { + EventQueue q = new EventQueue() { + public void push(EventQueue queue) { + super.push(queue); + pop(); + } + }; + EventQueue q2 = new EventQueue(); + + Toolkit.getDefaultToolkit().getSystemEventQueue().push(q); + + new Thread(() -> { + while (true) { + robot.delay(500); + l.setText("Counter: " + ++counter); + q.push(q2); + try { + Thread.currentThread().sleep(500); + } catch (InterruptedException e) { + return; + } + } + }).start(); + } +} diff --git a/test/jdk/java/awt/LightweightComponent/MultipleAddNotifyTest/MultipleAddNotifyTest.java b/test/jdk/java/awt/LightweightComponent/MultipleAddNotifyTest/MultipleAddNotifyTest.java new file mode 100644 index 0000000000000..fbbc2ae61854a --- /dev/null +++ b/test/jdk/java/awt/LightweightComponent/MultipleAddNotifyTest/MultipleAddNotifyTest.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * 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 4058400 + * @summary Tests that calling addNotify on a lightweight component more than + * once does not break event dispatching for that component. + * @key headful + * @run main MultipleAddNotifyTest + */ + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +public class MultipleAddNotifyTest { + static volatile boolean passFlag; + static volatile int posX; + static volatile int posY; + static Frame f; + static LightComponent l; + + public static void main(String[] args) throws Exception { + Robot r; + try { + r = new Robot(); + r.setAutoWaitForIdle(true); + passFlag = false; + + EventQueue.invokeAndWait(() -> { + f = new Frame("Multiple addNotify Test"); + l = new LightComponent(); + f.setLayout(new FlowLayout()); + l.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + System.out.println("Mouse Clicked"); + passFlag = true; + } + }); + f.add(l); + f.addNotify(); + f.addNotify(); + + if (!l.isVisible()) { + throw new RuntimeException("Test failed. LW Component " + + "not visible."); + } + f.setSize(200, 200); + f.setLocationRelativeTo(null); + f.setVisible(true); + }); + r.waitForIdle(); + r.delay(1000); + + EventQueue.invokeAndWait(() -> { + posX = f.getX() + l.getWidth() + (l.getWidth() / 2); + posY = f.getY() + l.getHeight(); + }); + + r.mouseMove(posX, posY); + r.delay(500); + + r.mousePress(InputEvent.BUTTON1_DOWN_MASK); + r.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + r.delay(500); + + if (!passFlag) { + throw new RuntimeException("Test failed. MouseClicked event " + + "not working properly."); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } +} + +class LightComponent extends Component { + public void paint(Graphics g) { + setSize(100, 100); + Dimension d = getSize(); + g.setColor(Color.red); + g.fillRect(0, 0, d.width, d.height); + } +} diff --git a/test/jdk/java/awt/LightweightComponent/PopupTest/PopupTest.java b/test/jdk/java/awt/LightweightComponent/PopupTest/PopupTest.java new file mode 100644 index 0000000000000..beae4b4d9042e --- /dev/null +++ b/test/jdk/java/awt/LightweightComponent/PopupTest/PopupTest.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * 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 4476083 + * @summary Disabled components do not receive MouseEvent in Popups + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual PopupTest + */ + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Frame; + +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; + +public class PopupTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + PopupMenus should disappear when a disabled component is + clicked. + + Step 1. Pop down the popup menu by clicking on it. + Step 2. Click on the disabled component to make the menu + disappear. + + If the menu disappears when the disabled component is clicked, + the test passes, otherwise, the test fails. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(PopupTest::createUI) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame f = new Frame("Disabled Component in Popup Test"); + f.setLayout(new BorderLayout()); + + JButton b = new JButton("step 1: press me to display menu"); + b.addActionListener(e -> { + JPopupMenu m = new JPopupMenu(); + m.add(new JMenuItem("item 1")); + m.add(new JMenuItem("item 2")); + m.add(new JMenuItem("item 3")); + m.add(new JMenuItem("item 4")); + m.add(new JMenuItem("item 5")); + m.add(new JMenuItem("item 6")); + m.show((Component) e.getSource(), 0, 10); + }); + + JLabel disabled = new JLabel("step 2: click me. the menu should be " + + "dismissed"); + disabled.setEnabled(false); + + JLabel enabled = new JLabel("step 3: there is no step 3"); + + f.add(BorderLayout.NORTH, b); + f.add(BorderLayout.CENTER, disabled); + f.add(BorderLayout.SOUTH, enabled); + f.setSize(300, 200); + return f; + } +} diff --git a/test/jdk/java/awt/Panel/PanelRepaint/PanelRepaint.java b/test/jdk/java/awt/Panel/PanelRepaint/PanelRepaint.java new file mode 100644 index 0000000000000..da8de3947be9a --- /dev/null +++ b/test/jdk/java/awt/Panel/PanelRepaint/PanelRepaint.java @@ -0,0 +1,455 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * 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 4148078 + * @summary Repainting problems in scrolled panel + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual PanelRepaint + */ + +import java.awt.Button; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Scrollbar; +import java.awt.TextField; +import java.awt.event.AdjustmentEvent; +import java.awt.event.AdjustmentListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; + +public class PanelRepaint extends Panel implements FocusListener { + static ScrollPanel sPanel; + static Panel panel; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Using scrollbars or tab keys to scroll the panel and + the panel is messy sometimes, e.g. one row bumps into + another. If all components painted correctly, the test passes. + Otherwise, the test fails. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(PanelRepaint::createUI) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame f = new Frame("Panel Repaint Test"); + f.setLayout(new FlowLayout()); + f.setSize(620, 288); + PanelRepaint pr = new PanelRepaint(); + + panel = new Panel(); + panel.setLayout(null); + panel.setSize(500, 500); + sPanel = new ScrollPanel(panel); + + Button btn = new Button("Open"); + pr.addComp(btn); + btn.setBounds(400, 10, 60, 20); + btn.setActionCommand("OPEN"); + + Button btn1 = new Button("Close"); + pr.addComp(btn1); + btn1.setBounds(400, 50, 60, 20); + btn1.setActionCommand("CLOSE"); + + TextField t1 = new TextField("1"); + pr.addComp(t1); + t1.setBounds(10, 10, 100, 20); + TextField t2 = new TextField("2"); + pr.addComp(t2); + t2.setBounds(10, 50, 100, 20); + TextField t3 = new TextField("3"); + pr.addComp(t3); + t3.setBounds(10, 90, 100, 20); + TextField t4 = new TextField("4"); + pr.addComp(t4); + t4.setBounds(10, 130, 100, 20); + TextField t5 = new TextField("5"); + pr.addComp(t5); + t5.setBounds(10, 170, 100, 20); + TextField t6 = new TextField("6"); + pr.addComp(t6); + t6.setBounds(10, 210, 100, 20); + TextField t7 = new TextField("7"); + pr.addComp(t7); + t7.setBounds(10, 250, 100, 20); + TextField t8 = new TextField("8"); + pr.addComp(t8); + t8.setBounds(10, 290, 100, 20); + TextField t9 = new TextField("9"); + pr.addComp(t9); + t9.setBounds(10, 330, 100, 20); + + TextField t11 = new TextField("1"); + pr.addComp(t11); + t11.setBounds(120, 10, 100, 20); + TextField t12 = new TextField("2"); + pr.addComp(t12); + t12.setBounds(120, 50, 100, 20); + TextField t13 = new TextField("3"); + pr.addComp(t13); + t13.setBounds(120, 90, 100, 20); + TextField t14 = new TextField("4"); + pr.addComp(t14); + t14.setBounds(120, 130, 100, 20); + TextField t15 = new TextField("5"); + pr.addComp(t15); + t15.setBounds(120, 170, 100, 20); + TextField t16 = new TextField("6"); + pr.addComp(t16); + t16.setBounds(120, 210, 100, 20); + TextField t17 = new TextField("7"); + pr.addComp(t17); + t17.setBounds(120, 250, 100, 20); + TextField t18 = new TextField("8"); + pr.addComp(t18); + t18.setBounds(120, 290, 100, 20); + TextField t19 = new TextField("9"); + pr.addComp(t19); + t19.setBounds(120, 330, 100, 20); + + + TextField t21 = new TextField("1"); + pr.addComp(t21); + t21.setBounds(240, 10, 100, 20); + TextField t22 = new TextField("2"); + pr.addComp(t22); + t22.setBounds(240, 50, 100, 20); + TextField t23 = new TextField("3"); + pr.addComp(t23); + t23.setBounds(240, 90, 100, 20); + TextField t24 = new TextField("4"); + pr.addComp(t24); + t24.setBounds(240, 130, 100, 20); + TextField t25 = new TextField("5"); + pr.addComp(t25); + t25.setBounds(240, 170, 100, 20); + TextField t26 = new TextField("6"); + pr.addComp(t26); + t26.setBounds(240, 210, 100, 20); + TextField t27 = new TextField("7"); + pr.addComp(t27); + t27.setBounds(240, 250, 100, 20); + TextField t28 = new TextField("8"); + pr.addComp(t28); + t28.setBounds(240, 290, 100, 20); + TextField t29 = new TextField("9"); + pr.addComp(t29); + t29.setBounds(240, 330, 100, 20); + + pr.add(sPanel); + f.add(pr); + sPanel.setBounds(100, 100, 500, 250); + sPanel.doLayout(); + return f; + } + + public void addComp(Component c) { + panel.add(c); + c.addFocusListener(this); + } + + public void focusGained(FocusEvent e) { + sPanel.showComponent(e.getComponent()); + } + + public void focusLost(FocusEvent e) { + } +} + +class ScrollPanel extends Panel implements AdjustmentListener { + /** + * Constructor + */ + public ScrollPanel(Component c) { + setLayout(null); + setBackground(Color.lightGray); + add(hScroll = new Scrollbar(Scrollbar.HORIZONTAL)); + add(vScroll = new Scrollbar(Scrollbar.VERTICAL)); + add(square = new Panel()); + square.setBackground(Color.lightGray); + add(c); + } + + /** + * Scroll up/down/left/right to show the component specified + * + * @param comp is the component to be shown + */ + public void showComponent(Component comp) { + Component view = getComponent(3); + Rectangle viewRect = view.getBounds(); + Rectangle scrollRect = getBounds(); + Rectangle rect = comp.getBounds(); + while (comp != null) { + Component parent = comp.getParent(); + if (parent == null || parent == view) { + break; + } + Point p = parent.getLocation(); + rect.x += p.x; + rect.y += p.y; + comp = parent; + } + + int i = viewRect.y + rect.y; + int j = (viewRect.y + rect.y + rect.height + ScrollPanel.H_HEIGHT) + - (scrollRect.height); + + if (i < 0) { + vertUpdate(i); + } else if (j > 0) { + vertUpdate(j); + } + + i = viewRect.x + rect.x; + j = (viewRect.x + rect.x + rect.width + (V_WIDTH * 2)) - (scrollRect.width); + + if (i < 0) { + horzUpdate(i); + } else if (j > 0) { + horzUpdate(j); + } + } + + /** + * Returns the panel component of ScrollPanel + * + * @return the panel component of ScrollPanel + */ + public Component getScrolled() { + return getComponent(3); + } + + /** + * updates the scroll panel vertically with value i passed + * + * @param i the value to be updated with + */ + public void vertUpdate(int i) { + update(true, vScroll.getValue() + i); + } + + /** + * updates the scroll panel horizontally with value i passed + * + * @param i the value to be updated with + */ + public void horzUpdate(int i) { + update(false, hScroll.getValue() + i); + } + + /** + * updates the scroll panel vertically if bVert is true else horizontally + * + * @param n is the value + */ + public void update(boolean bVert, int n) { + if (n < 0) n = 0; + if (bVert) { + if (n > max.height) { + n = max.height; + } + if (offset.y != n) { + offset.y = n; + vScroll.setValue(n); + } + } else { + if (n > max.width) { + n = max.width; + } + if (offset.x != n) { + offset.x = n; + hScroll.setValue(n); + } + } + getScrolled().setLocation(-offset.x, -offset.y); + } + + /** + * Implementation of AdjustmentListener + */ + public void adjustmentValueChanged(AdjustmentEvent e) { + boolean bVert = e.getSource() == vScroll; + update(bVert, e.getValue()); + } + + /** + * Reimplementation of Component Methods + */ + public void addNotify() { + super.addNotify(); + vScroll.addAdjustmentListener(this); + hScroll.addAdjustmentListener(this); + } + + public void removeNotify() { + super.removeNotify(); + vScroll.removeAdjustmentListener(this); + hScroll.removeAdjustmentListener(this); + } + + public void setBounds(int x, int y, int w, int h) { + super.setBounds(x, y, w, h); + doLayout(); + } + + public void doLayout() { + Component c = getScrolled(); + Dimension d = c.getSize(); + if (d.width == 0 || d.height == 0) { + d = c.getPreferredSize(); + } + vert = 0; + horz = 0; + Dimension m = getSize(); + if (d.height > m.height || isScroll(true, m.height - horz, 0, d.height)) { + vert = V_WIDTH; + } + if (d.width + vert > m.width || isScroll(false, m.width - vert, 0, d.width)) { + horz = H_HEIGHT; + } + if (d.height + horz > m.height || isScroll(true, m.height - horz, 0, d.height)) { + vert = V_WIDTH; + } + if (d.width + vert > m.width || isScroll(false, m.width - vert, 0, d.width)) { + horz = H_HEIGHT; + } + if (horz != 0) { + if (m.width <= 0) { + m.width = 1; + } + hScroll.setBounds(0, m.height - H_HEIGHT, m.width - vert, H_HEIGHT); + hScroll.setValues(offset.x, m.width - vert, 0, d.width); + int i = d.width / 10; + if (i < 2) { + i = 2; + } + hScroll.setBlockIncrement(i); + i = d.width / 50; + if (i < 1) { + i = 1; + } + hScroll.setUnitIncrement(i); + max.width = d.width; + hScroll.setVisible(true); + } else { + offset.x = 0; + } + if (vert != 0) { + if (m.height <= 0) { + m.height = 1; + } + vScroll.setBounds(m.width - V_WIDTH, 0, V_WIDTH, m.height - horz); + vScroll.setValues(offset.y, m.height - horz, 0, d.height); + int i = d.height / 10; + if (i < 2) i = 2; + vScroll.setBlockIncrement(i); + i = d.height / 50; + if (i < 1) i = 1; + vScroll.setUnitIncrement(i); + max.height = d.height; + vScroll.setVisible(true); + } else { + offset.y = 0; + } + if (horz != 0 && vert != 0) { + square.setBounds(m.width - V_WIDTH, m.height - H_HEIGHT, V_WIDTH, H_HEIGHT); + square.setVisible(true); + } else { + square.setVisible(false); + } + c.setBounds(-offset.x, -offset.y, d.width, d.height); + c.repaint(); + updateScroll(true, offset.y); + updateScroll(false, offset.x); + } + + public Dimension getPreferredSize() { + return getScrolled().getPreferredSize(); + } + + public Dimension getMinimumSize() { + return getScrolled().getMinimumSize(); + } + + boolean isScroll(boolean bVert, int visible, int min, int max) { + int tot = max - min; + int net = tot - visible; + if (net <= 0) { + return false; + } + return true; + } + + void updateScroll(boolean bVert, int n) { + Component c = getScrolled(); + Dimension d = c.getSize(); + Dimension m = getSize(); + m.width -= vert; + m.height -= horz; + if (bVert) { + if (n >= 0 && d.height > m.height) { + if (n + m.height > d.height) + n = d.height - m.height; + } else + n = 0; + update(true, n); + } else { + if (n >= 0 && d.width > m.width) { + if (n + m.width > d.width) + n = d.width - m.width; + } else + n = 0; + update(false, n); + } + } + + static Scrollbar hScroll; + static Scrollbar vScroll; + static int vert = 0; + static int horz = 0; + + static Point offset = new Point(); + static Dimension max = new Dimension(); + // ScrollTimer timer; + static Component square; + final static int V_WIDTH = 17; + final static int H_HEIGHT = 17; +} From 06f34d7ed2ac77e30b2a891b7a0549055ed40da3 Mon Sep 17 00:00:00 2001 From: William Kemper Date: Thu, 10 Oct 2024 18:45:10 +0000 Subject: [PATCH 025/118] 8339651: ShenandoahPacer::setup_for_mark, ShenandoahPacer::setup_for_updaterefs and ShenandoahPacer::setup_for_evac runtime error: division by zero Reviewed-by: shade, mli --- src/hotspot/share/gc/shenandoah/shenandoahPacer.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahPacer.cpp b/src/hotspot/share/gc/shenandoah/shenandoahPacer.cpp index e67d3d197d42d..8d10b7cbfcfaf 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahPacer.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahPacer.cpp @@ -65,6 +65,7 @@ void ShenandoahPacer::setup_for_mark() { size_t non_taxable = free * ShenandoahPacingCycleSlack / 100; size_t taxable = free - non_taxable; + taxable = MAX2(1, taxable); double tax = 1.0 * live / taxable; // base tax for available free space tax *= 1; // mark can succeed with immediate garbage, claim all available space @@ -88,6 +89,7 @@ void ShenandoahPacer::setup_for_evac() { size_t non_taxable = free * ShenandoahPacingCycleSlack / 100; size_t taxable = free - non_taxable; + taxable = MAX2(1, taxable); double tax = 1.0 * used / taxable; // base tax for available free space tax *= 2; // evac is followed by update-refs, claim 1/2 of remaining free @@ -112,6 +114,7 @@ void ShenandoahPacer::setup_for_updaterefs() { size_t non_taxable = free * ShenandoahPacingCycleSlack / 100; size_t taxable = free - non_taxable; + taxable = MAX2(1, taxable); double tax = 1.0 * used / taxable; // base tax for available free space tax *= 1; // update-refs is the last phase, claim the remaining free From cd4981c29245b4ddd37b49aef1a051e29a1001f9 Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Thu, 10 Oct 2024 21:42:23 +0000 Subject: [PATCH 026/118] 8341257: Open source few DND tests - Set1 Reviewed-by: honkar, prr --- test/jdk/ProblemList.txt | 2 + .../awt/dnd/DnDClipboardDeadlockTest.java | 441 ++++++++++++++++++ test/jdk/java/awt/dnd/DnDCursorCrashTest.java | 231 +++++++++ .../awt/dnd/DnDRemoveFocusOwnerCrashTest.java | 234 ++++++++++ test/jdk/java/awt/dnd/DnDToWordpadTest.java | 237 ++++++++++ test/jdk/java/awt/dnd/NonAsciiFilenames.java | 158 +++++++ 6 files changed, 1303 insertions(+) create mode 100644 test/jdk/java/awt/dnd/DnDClipboardDeadlockTest.java create mode 100644 test/jdk/java/awt/dnd/DnDCursorCrashTest.java create mode 100644 test/jdk/java/awt/dnd/DnDRemoveFocusOwnerCrashTest.java create mode 100644 test/jdk/java/awt/dnd/DnDToWordpadTest.java create mode 100644 test/jdk/java/awt/dnd/NonAsciiFilenames.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index db48c24cd7e63..db0794f8f2dab 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -201,6 +201,8 @@ java/awt/event/KeyEvent/ExtendedKeyCode/ExtendedKeyCodeTest.java 8169476 windows java/awt/event/KeyEvent/KeyChar/KeyCharTest.java 8169474,8224055 macosx-all,windows-all java/awt/event/KeyEvent/KeyTyped/CtrlASCII.java 8298910 linux-all +java/awt/dnd/DnDCursorCrashTest.java 8242805 macosx-all +java/awt/dnd/DnDClipboardDeadlockTest.java 8079553 linux-all java/awt/dnd/URIListToFileListBetweenJVMsTest/URIListToFileListBetweenJVMsTest.java 8194947 generic-all java/awt/Frame/FramesGC/FramesGC.java 8079069 macosx-all java/awt/TrayIcon/ActionCommand/ActionCommand.java 8150540 windows-all diff --git a/test/jdk/java/awt/dnd/DnDClipboardDeadlockTest.java b/test/jdk/java/awt/dnd/DnDClipboardDeadlockTest.java new file mode 100644 index 0000000000000..ab2bff8ecc5a5 --- /dev/null +++ b/test/jdk/java/awt/dnd/DnDClipboardDeadlockTest.java @@ -0,0 +1,441 @@ +/* + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * 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 4388802 + * @summary tests that clipboard operations during drag-and-drop don't deadlock + * @key headful + * @run main DnDClipboardDeadlockTest + */ + +import java.awt.AWTEvent; +import java.awt.AWTException; +import java.awt.Button; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.GridLayout; +import java.awt.List; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.Transferable; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.DragSourceListener; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetContext; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetEvent; +import java.awt.dnd.DropTargetListener; +import java.awt.event.AWTEventListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; + +public class DnDClipboardDeadlockTest { + + public static final int CODE_NOT_RETURNED = -1; + public static final int CODE_OK = 0; + public static final int CODE_FAILURE = 1; + + private int returnCode = CODE_NOT_RETURNED; + + final Frame frame = new Frame(); + Robot robot = null; + Panel panel = null; + + public static void main(String[] args) throws Exception { + DnDClipboardDeadlockTest test = new DnDClipboardDeadlockTest(); + if (args.length == 4) { + test.run(args); + } else { + test.start(); + } + } + + public void run(String[] args) throws InterruptedException, AWTException { + try { + if (args.length != 4) { + throw new RuntimeException("Incorrect command line arguments."); + } + + int x = Integer.parseInt(args[0]); + int y = Integer.parseInt(args[1]); + int w = Integer.parseInt(args[2]); + int h = Integer.parseInt(args[3]); + + Transferable t = new StringSelection("TEXT"); + panel = new DragSourcePanel(t); + + frame.setTitle("DragSource frame"); + frame.setLocation(300, 200); + frame.add(panel); + frame.pack(); + frame.setVisible(true); + + Util.waitForInit(); + + Point sourcePoint = panel.getLocationOnScreen(); + Dimension d = panel.getSize(); + sourcePoint.translate(d.width / 2, d.height / 2); + + Point targetPoint = new Point(x + w / 2, y + h / 2); + + robot = new Robot(); + + if (!Util.pointInComponent(robot, sourcePoint, panel)) { + throw new RuntimeException("WARNING: Cannot locate source panel"); + } + + robot.mouseMove(sourcePoint.x, sourcePoint.y); + robot.keyPress(KeyEvent.VK_CONTROL); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + for (; !sourcePoint.equals(targetPoint); + sourcePoint.translate(sign(targetPoint.x - sourcePoint.x), + sign(targetPoint.y - sourcePoint.y))) { + robot.mouseMove(sourcePoint.x, sourcePoint.y); + Thread.sleep(10); + } + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.keyRelease(KeyEvent.VK_CONTROL); + if (frame != null) { + frame.dispose(); + } + + } catch (Throwable e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } // run() + + public static int sign(int n) { + return n < 0 ? -1 : n == 0 ? 0 : 1; + } + + public void start() { + panel = new DropTargetPanel(); + + frame.setTitle("DropTarget frame"); + frame.setLocation(10, 200); + frame.add(panel); + + frame.pack(); + frame.setVisible(true); + + try { + Util.waitForInit(); + + Point p = panel.getLocationOnScreen(); + Dimension d = panel.getSize(); + + try { + Robot robot = new Robot(); + Point center = new Point(p); + center.translate(d.width / 2, d.height / 2); + if (!Util.pointInComponent(robot, center, panel)) { + System.err.println("WARNING: Cannot locate target panel"); + return; + } + } catch (AWTException awte) { + awte.printStackTrace(); + return; + } + + String javaPath = System.getProperty("java.home", ""); + String command = javaPath + File.separator + "bin" + + File.separator + "java -cp " + + System.getProperty("java.class.path", ".") + + " DnDClipboardDeadlockTest " + + p.x + " " + p.y + " " + d.width + " " + d.height; + + Process process = Runtime.getRuntime().exec(command); + returnCode = process.waitFor(); + + InputStream errorStream = process.getErrorStream(); + int count = errorStream.available(); + if (count > 0) { + byte[] b = new byte[count]; + errorStream.read(b); + System.err.println("========= Child VM System.err ========"); + System.err.print(new String(b)); + System.err.println("======================================"); + } + + } catch (Throwable e) { + e.printStackTrace(); + } + switch (returnCode) { + case CODE_NOT_RETURNED: + System.err.println("Child VM: failed to start"); + break; + case CODE_OK: + System.err.println("Child VM: normal termination"); + break; + case CODE_FAILURE: + System.err.println("Child VM: abnormal termination"); + break; + } + if (returnCode != CODE_OK) { + throw new RuntimeException("The test failed."); + } + if (frame != null) { + frame.dispose(); + } + } // start() +} // class DnDClipboardDeadlockTest + +class Util implements AWTEventListener { + private static final Toolkit tk = Toolkit.getDefaultToolkit(); + private static final Object SYNC_LOCK = new Object(); + private Component clickedComponent = null; + private static final int PAINT_TIMEOUT = 10000; + private static final int MOUSE_RELEASE_TIMEOUT = 10000; + private static final Util util = new Util(); + + static { + tk.addAWTEventListener(util, 0xFFFFFFFF); + } + + private void reset() { + clickedComponent = null; + } + + public void eventDispatched(AWTEvent e) { + if (e.getID() == MouseEvent.MOUSE_RELEASED) { + clickedComponent = (Component) e.getSource(); + synchronized (SYNC_LOCK) { + SYNC_LOCK.notifyAll(); + } + } + } + + public static boolean pointInComponent(Robot robot, Point p, Component comp) + throws InterruptedException { + return util.isPointInComponent(robot, p, comp); + } + + private boolean isPointInComponent(Robot robot, Point p, Component comp) + throws InterruptedException { + tk.sync(); + robot.waitForIdle(); + reset(); + robot.mouseMove(p.x, p.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + synchronized (SYNC_LOCK) { + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + SYNC_LOCK.wait(MOUSE_RELEASE_TIMEOUT); + } + + Component c = clickedComponent; + + while (c != null && c != comp) { + c = c.getParent(); + } + + return c == comp; + } + + public static void waitForInit() throws InterruptedException { + final Frame f = new Frame() { + public void paint(Graphics g) { + dispose(); + synchronized (SYNC_LOCK) { + SYNC_LOCK.notifyAll(); + } + } + }; + f.setBounds(600, 400, 200, 200); + synchronized (SYNC_LOCK) { + f.setVisible(true); + SYNC_LOCK.wait(PAINT_TIMEOUT); + } + tk.sync(); + } +} + +class DragSourceButton extends Button implements Serializable, + DragGestureListener, + DragSourceListener { + static final Clipboard systemClipboard = + Toolkit.getDefaultToolkit().getSystemClipboard(); + final Transferable transferable; + + public DragSourceButton(Transferable t) { + super("DragSourceButton"); + + this.transferable = t; + DragSource ds = DragSource.getDefaultDragSource(); + ds.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY, + this); + } + + public void dragGestureRecognized(DragGestureEvent dge) { + dge.startDrag(null, transferable, this); + } + + public void dragEnter(DragSourceDragEvent dsde) { + } + + public void dragExit(DragSourceEvent dse) { + } + + public void dragOver(DragSourceDragEvent dsde) { + try { + Transferable t = systemClipboard.getContents(null); + if (t.isDataFlavorSupported(DataFlavor.stringFlavor)) { + String str = (String) t.getTransferData(DataFlavor.stringFlavor); + } + systemClipboard.setContents(new StringSelection("SOURCE"), null); + } catch (IOException ioe) { + ioe.printStackTrace(); + if (!ioe.getMessage().equals("Owner failed to convert data")) { + throw new RuntimeException("Owner failed to convert data"); + } + } catch (IllegalStateException e) { + // IllegalStateExceptions do not indicate a bug in this case. + // They result from concurrent modification of system clipboard + // contents by the parent and child processes. + // These exceptions are numerous, so we avoid dumping their + // backtraces to prevent blocking child process io, which + // causes test failure on timeout. + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void dragDropEnd(DragSourceDropEvent dsde) { + System.exit(DnDClipboardDeadlockTest.CODE_OK); + } + + public void dropActionChanged(DragSourceDragEvent dsde) { + } +} + +class DragSourcePanel extends Panel { + + final Dimension preferredDimension = new Dimension(200, 200); + + public DragSourcePanel(Transferable t) { + setLayout(new GridLayout(1, 1)); + add(new DragSourceButton(t)); + } + + public Dimension getPreferredSize() { + return preferredDimension; + } +} + +class DropTargetPanel extends Panel implements DropTargetListener { + + static final Clipboard systemClipboard = + Toolkit.getDefaultToolkit().getSystemClipboard(); + final Dimension preferredDimension = new Dimension(200, 200); + + public DropTargetPanel() { + setBackground(Color.green); + setDropTarget(new DropTarget(this, this)); + setLayout(new GridLayout(1, 1)); + } + + public Dimension getPreferredSize() { + return preferredDimension; + } + + public void dragEnter(DropTargetDragEvent dtde) { + dtde.acceptDrag(DnDConstants.ACTION_COPY); + } + + public void dragExit(DropTargetEvent dte) { + } + + public void dragOver(DropTargetDragEvent dtde) { + dtde.acceptDrag(DnDConstants.ACTION_COPY); + try { + Transferable t = systemClipboard.getContents(null); + if (t.isDataFlavorSupported(DataFlavor.stringFlavor)) { + String str = (String) t.getTransferData(DataFlavor.stringFlavor); + } + systemClipboard.setContents(new StringSelection("TARGET"), null); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void drop(DropTargetDropEvent dtde) { + DropTargetContext dtc = dtde.getDropTargetContext(); + + if ((dtde.getSourceActions() & DnDConstants.ACTION_COPY) != 0) { + dtde.acceptDrop(DnDConstants.ACTION_COPY); + } else { + dtde.rejectDrop(); + return; + } + + removeAll(); + final List list = new List(); + add(list); + + Transferable t = dtde.getTransferable(); + DataFlavor[] dfs = t.getTransferDataFlavors(); + + for (int i = 0; i < dfs.length; i++) { + + DataFlavor flavor = dfs[i]; + String str = null; + + if (DataFlavor.stringFlavor.equals(flavor)) { + try { + str = (String) t.getTransferData(flavor); + } catch (Exception e) { + e.printStackTrace(); + } + } + + list.add(str + ":" + flavor.getMimeType()); + } + + dtc.dropComplete(true); + validate(); + } + + public void dropActionChanged(DropTargetDragEvent dtde) { + } +} diff --git a/test/jdk/java/awt/dnd/DnDCursorCrashTest.java b/test/jdk/java/awt/dnd/DnDCursorCrashTest.java new file mode 100644 index 0000000000000..7b1f4483ef991 --- /dev/null +++ b/test/jdk/java/awt/dnd/DnDCursorCrashTest.java @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * 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 4343300 + * @summary tests that drag attempt doesn't cause crash when + * custom cursor is used + * @key headful + * @run main DnDCursorCrashTest + */ + +import java.awt.Button; +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Panel; +import java.awt.Robot; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.DragSourceListener; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetContext; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetEvent; +import java.awt.dnd.DropTargetListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +public class DnDCursorCrashTest { + static final Frame frame = new Frame(); + static final DragSourcePanel dragSourcePanel = new DragSourcePanel(); + static final DropTargetPanel dropTargetPanel = new DropTargetPanel(); + + public static void main(String[] args) throws Exception { + try { + EventQueue.invokeAndWait(() -> { + frame.setTitle("DnD Cursor Test Frame"); + frame.setLocation(200, 200); + frame.setLayout(new GridLayout(2, 1)); + frame.add(dragSourcePanel); + frame.add(dropTargetPanel); + frame.pack(); + frame.setVisible(true); + }); + + Robot robot = new Robot(); + robot.delay(1000); + robot.mouseMove(250, 250); + robot.keyPress(KeyEvent.VK_CONTROL); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + for (int y = 250; y < 350; y += 5) { + robot.mouseMove(250, y); + robot.delay(100); + } + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.keyRelease(KeyEvent.VK_CONTROL); + } finally { + if (frame != null) { + EventQueue.invokeAndWait(() -> frame.dispose()); + } + } + } +} + +class DragSourceButton extends Button implements Serializable, + Transferable, + DragGestureListener, + DragSourceListener { + private final DataFlavor dataflavor = + new DataFlavor(Button.class, "DragSourceButton"); + + public DragSourceButton() { + this("DragSourceButton"); + } + + public DragSourceButton(String str) { + super(str); + + DragSource ds = DragSource.getDefaultDragSource(); + ds.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY, + this); + } + + public void dragGestureRecognized(DragGestureEvent dge) { + dge.startDrag(new Cursor(Cursor.HAND_CURSOR), this, this); + } + + public void dragEnter(DragSourceDragEvent dsde) {} + + public void dragExit(DragSourceEvent dse) {} + + public void dragOver(DragSourceDragEvent dsde) {} + + public void dragDropEnd(DragSourceDropEvent dsde) {} + + public void dropActionChanged(DragSourceDragEvent dsde) {} + + public Object getTransferData(DataFlavor flavor) + throws UnsupportedFlavorException, IOException { + + if (!isDataFlavorSupported(flavor)) { + throw new UnsupportedFlavorException(flavor); + } + + Object retObj; + + ByteArrayOutputStream baoStream = new ByteArrayOutputStream(); + ObjectOutputStream ooStream = new ObjectOutputStream(baoStream); + ooStream.writeObject(this); + + ByteArrayInputStream baiStream = new ByteArrayInputStream(baoStream.toByteArray()); + ObjectInputStream ois = new ObjectInputStream(baiStream); + try { + retObj = ois.readObject(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + throw new RuntimeException(e.toString()); + } + + return retObj; + } + + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[] { dataflavor }; + } + + public boolean isDataFlavorSupported(DataFlavor dflavor) { + return dataflavor.equals(dflavor); + } +} + +class DragSourcePanel extends Panel { + + final Dimension preferredDimension = new Dimension(200, 100); + + public DragSourcePanel() { + setLayout(new GridLayout(1, 1)); + add(new DragSourceButton()); + } + + public Dimension getPreferredSize() { + return preferredDimension; + } +} + +class DropTargetPanel extends Panel implements DropTargetListener { + + final Dimension preferredDimension = new Dimension(200, 100); + + public DropTargetPanel() { + setDropTarget(new DropTarget(this, this)); + } + + public Dimension getPreferredSize() { + return preferredDimension; + } + + public void dragEnter(DropTargetDragEvent dtde) {} + + public void dragExit(DropTargetEvent dte) {} + + public void dragOver(DropTargetDragEvent dtde) {} + + public void dropActionChanged(DropTargetDragEvent dtde) {} + + public void drop(DropTargetDropEvent dtde) { + DropTargetContext dtc = dtde.getDropTargetContext(); + + if ((dtde.getSourceActions() & DnDConstants.ACTION_COPY) != 0) { + dtde.acceptDrop(DnDConstants.ACTION_COPY); + } else { + dtde.rejectDrop(); + } + + DataFlavor[] dfs = dtde.getCurrentDataFlavors(); + Component comp = null; + + if (dfs != null && dfs.length >= 1) { + Transferable transfer = dtde.getTransferable(); + + try { + comp = (Component)transfer.getTransferData(dfs[0]); + } catch (Throwable e) { + e.printStackTrace(); + dtc.dropComplete(false); + } + } + dtc.dropComplete(true); + + add(comp); + } +} diff --git a/test/jdk/java/awt/dnd/DnDRemoveFocusOwnerCrashTest.java b/test/jdk/java/awt/dnd/DnDRemoveFocusOwnerCrashTest.java new file mode 100644 index 0000000000000..27cf54e184558 --- /dev/null +++ b/test/jdk/java/awt/dnd/DnDRemoveFocusOwnerCrashTest.java @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * 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 4357905 + * @summary Tests that removal of the focus owner component during + * drop processing doesn't cause crash + * @key headful + * @run main DnDRemoveFocusOwnerCrashTest + */ + +import java.awt.Button; +import java.awt.Component; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.DragSourceListener; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetContext; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetEvent; +import java.awt.dnd.DropTargetListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.io.Serializable; + +public class DnDRemoveFocusOwnerCrashTest { + public static final int FRAME_ACTIVATION_TIMEOUT = 1000; + public static Frame frame; + public static Robot robot; + public static DragSourceButton dragSourceButton; + + public static void main(String[] args) throws Exception { + try { + robot = new Robot(); + EventQueue.invokeAndWait(() -> { + frame = new Frame(); + dragSourceButton = new DragSourceButton(); + DropTargetPanel dropTargetPanel = + new DropTargetPanel(dragSourceButton); + frame.add(new Button("Test")); + frame.setTitle("Remove Focus Owner Test Frame"); + frame.setLocation(200, 200); + frame.add(dropTargetPanel); + frame.pack(); + frame.setVisible(true); + + try { + robot.delay(FRAME_ACTIVATION_TIMEOUT); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException("The test failed."); + } + + Point p = dragSourceButton.getLocationOnScreen(); + p.translate(10, 10); + + try { + Robot robot = new Robot(); + robot.mouseMove(p.x, p.y); + robot.keyPress(KeyEvent.VK_CONTROL); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + for (int dy = 0; dy < 50; dy++) { + robot.mouseMove(p.x, p.y + dy); + robot.delay(10); + } + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.keyRelease(KeyEvent.VK_CONTROL); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException("The test failed."); + } + }); + } finally { + if (frame != null) { + EventQueue.invokeAndWait(() -> frame.dispose()); + } + } + } + + static class DragSourceButton extends Button implements Serializable, + Transferable, + DragGestureListener, + DragSourceListener { + + private static DataFlavor dataflavor; + + static { + try { + dataflavor = + new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType); + dataflavor.setHumanPresentableName("Local Object Flavor"); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + throw new ExceptionInInitializerError(); + } + } + + public DragSourceButton() { + this("DragSourceButton"); + } + + public DragSourceButton(String str) { + super(str); + + DragSource ds = DragSource.getDefaultDragSource(); + ds.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY, + this); + } + + public void dragGestureRecognized(DragGestureEvent dge) { + dge.startDrag(null, this, this); + } + + public void dragEnter(DragSourceDragEvent dsde) { + } + + public void dragExit(DragSourceEvent dse) { + } + + public void dragOver(DragSourceDragEvent dsde) { + } + + public void dragDropEnd(DragSourceDropEvent dsde) { + } + + public void dropActionChanged(DragSourceDragEvent dsde) { + } + + public Object getTransferData(DataFlavor flavor) + throws UnsupportedFlavorException { + + if (!isDataFlavorSupported(flavor)) { + throw new UnsupportedFlavorException(flavor); + } + + return this; + } + + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[]{dataflavor}; + } + + public boolean isDataFlavorSupported(DataFlavor dflavor) { + return dataflavor.equals(dflavor); + } + } + + static class DropTargetPanel extends Panel implements DropTargetListener { + + public DropTargetPanel(DragSourceButton button) { + setLayout(new FlowLayout(FlowLayout.CENTER, 50, 50)); + add(button); + setDropTarget(new DropTarget(this, this)); + } + + public void dragEnter(DropTargetDragEvent dtde) { + } + + public void dragExit(DropTargetEvent dte) { + } + + public void dragOver(DropTargetDragEvent dtde) { + } + + public void dropActionChanged(DropTargetDragEvent dtde) { + } + + public void drop(DropTargetDropEvent dtde) { + removeAll(); + + DropTargetContext dtc = dtde.getDropTargetContext(); + + if ((dtde.getSourceActions() & DnDConstants.ACTION_COPY) != 0) { + dtde.acceptDrop(DnDConstants.ACTION_COPY); + } else { + dtde.rejectDrop(); + } + + DataFlavor[] dfs = dtde.getCurrentDataFlavors(); + Component comp = null; + + if (dfs != null && dfs.length >= 1) { + Transferable transfer = dtde.getTransferable(); + + try { + comp = (Component) transfer.getTransferData(dfs[0]); + } catch (Throwable e) { + e.printStackTrace(); + dtc.dropComplete(false); + } + } + dtc.dropComplete(true); + + add(comp); + validate(); + } + } +} diff --git a/test/jdk/java/awt/dnd/DnDToWordpadTest.java b/test/jdk/java/awt/dnd/DnDToWordpadTest.java new file mode 100644 index 0000000000000..181a6ee873a85 --- /dev/null +++ b/test/jdk/java/awt/dnd/DnDToWordpadTest.java @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * 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 6362095 + * @summary Tests basic DnD functionality to a wordpad + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DnDToWordpadTest + */ + +import java.awt.Button; +import java.awt.Color; +import java.awt.Component; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Panel; +import java.awt.Toolkit; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.DragSourceListener; +import java.awt.dnd.InvalidDnDOperationException; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; + +import javax.imageio.ImageIO; + +import static java.awt.image.BufferedImage.TYPE_INT_ARGB; + +public class DnDToWordpadTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + The test window contains a yellow button. Click on the button + to copy image into the clipboard or drag the image. + Paste or drop the image over Wordpad (when the mouse + enters the Wordpad during the drag, the application + should change the cursor to indicate that a copy operation is + about to happen; release the mouse button). + An image of a red rectangle should appear inside the document. + You should be able to repeat this operation multiple times. + Please, click "Pass" if above conditions are true, + otherwise click "Fail". + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(DnDToWordpadTest::createUI) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame f = new Frame("DnD To WordPad Test"); + Panel mainPanel; + Component dragSource; + + mainPanel = new Panel(); + mainPanel.setLayout(null); + + mainPanel.setBackground(Color.black); + try { + dragSource = new DnDSource("Drag ME!"); + mainPanel.add(dragSource); + f.add(mainPanel); + } catch (IOException e) { + e.printStackTrace(); + } + + f.setSize(200, 200); + return f; + } +} + +class DnDSource extends Button implements Transferable, + DragGestureListener, + DragSourceListener { + private DataFlavor m_df; + private transient int m_dropAction; + private Image m_img; + + DnDSource(String label) throws IOException { + super(label); + + setBackground(Color.yellow); + setForeground(Color.blue); + setSize(200, 120); + + m_df = DataFlavor.imageFlavor; + + DragSource dragSource = new DragSource(); + dragSource.createDefaultDragGestureRecognizer( + this, + DnDConstants.ACTION_COPY_OR_MOVE, + this + ); + dragSource.addDragSourceListener(this); + + // Create test gif image to drag + Path p = Path.of(System.getProperty("test.classes", ".")); + BufferedImage bImg = new BufferedImage(79, 109, TYPE_INT_ARGB); + Graphics2D cg = bImg.createGraphics(); + cg.setColor(Color.RED); + cg.fillRect(0, 0, 79, 109); + ImageIO.write(bImg, "png", new File(p + java.io.File.separator + + "DnDSource_Red.gif")); + + m_img = Toolkit.getDefaultToolkit() + .getImage(System.getProperty("test.classes", ".") + + java.io.File.separator + "DnDSource_Red.gif"); + + addActionListener( + ae -> Toolkit.getDefaultToolkit().getSystemClipboard().setContents( + (Transferable) DnDSource.this, + null + ) + ); + } + + public void paint(Graphics g) { + g.drawImage(m_img, 10, 10, null); + } + + /** + * a Drag gesture has been recognized + */ + + public void dragGestureRecognized(DragGestureEvent dge) { + System.err.println("starting Drag"); + try { + dge.startDrag(null, this, this); + } catch (InvalidDnDOperationException e) { + e.printStackTrace(); + } + } + + /** + * as the hotspot enters a platform dependent drop site + */ + + public void dragEnter(DragSourceDragEvent dsde) { + System.err.println("[Source] dragEnter"); + } + + /** + * as the hotspot moves over a platform dependent drop site + */ + + public void dragOver(DragSourceDragEvent dsde) { + System.err.println("[Source] dragOver"); + m_dropAction = dsde.getDropAction(); + System.out.println("m_dropAction = " + m_dropAction); + } + + /** + * as the operation changes + */ + + public void dragGestureChanged(DragSourceDragEvent dsde) { + System.err.println("[Source] dragGestureChanged"); + m_dropAction = dsde.getDropAction(); + System.out.println("m_dropAction = " + m_dropAction); + } + + /** + * as the hotspot exits a platform dependent drop site + */ + + public void dragExit(DragSourceEvent dsde) { + System.err.println("[Source] dragExit"); + } + + /** + * as the operation completes + */ + + public void dragDropEnd(DragSourceDropEvent dsde) { + System.err.println("[Source] dragDropEnd"); + } + + public void dropActionChanged(DragSourceDragEvent dsde) { + System.err.println("[Source] dropActionChanged"); + m_dropAction = dsde.getDropAction(); + System.out.println("m_dropAction = " + m_dropAction); + } + + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[]{m_df}; + } + + public boolean isDataFlavorSupported(DataFlavor sdf) { + System.err.println("[Source] isDataFlavorSupported" + m_df.equals(sdf)); + return m_df.equals(sdf); + } + + public Object getTransferData(DataFlavor tdf) throws UnsupportedFlavorException { + if (!m_df.equals(tdf)) { + throw new UnsupportedFlavorException(tdf); + } + System.err.println("[Source] Ok"); + return m_img; + } +} diff --git a/test/jdk/java/awt/dnd/NonAsciiFilenames.java b/test/jdk/java/awt/dnd/NonAsciiFilenames.java new file mode 100644 index 0000000000000..b508350c05ef3 --- /dev/null +++ b/test/jdk/java/awt/dnd/NonAsciiFilenames.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * 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 4187490 + * @summary Verify that Non-ASCII file names can be dragged and dropped + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual NonAsciiFilenames + */ + +import java.awt.Color; +import java.awt.datatransfer.DataFlavor; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetEvent; +import java.awt.dnd.DropTargetListener; +import java.io.File; +import java.util.AbstractList; + +import javax.swing.JFrame; +import javax.swing.JLabel; + +public class NonAsciiFilenames { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + This test must be run on an OS which does not use ISO 8859-1 + as its default encoding. + + Open a native file browsing application, such as Windows + Explorer. Try to find a file whose name uses non-ISO 8859-1 + characters. Create a file and name it such that it contains + non-ISO 8859-1 characters (For ex. é, à, ö, €, ¥). Drag + the file from the native application and drop it on the test + Frame. If the file name appears normally, then the test passes. + If boxes or question marks appear for characters, or if you see + the word "Error", then the test fails. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(NonAsciiFilenames::createUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createUI() { + JFrame frame = new JFrame(); + frame.setTitle("DropLabel test"); + frame.getContentPane().add(new DropLabel("Drop here")); + frame.setSize(300, 100); + return frame; + } +} + +class DropLabel extends JLabel implements DropTargetListener { + public DropLabel(String s) { + setText(s); + new DropTarget(this, DnDConstants.ACTION_COPY, this, true); + showDrop(false); + } + + private void showDrop(boolean b) { + setForeground(b ? Color.white : Color.black); + } + + /** + * Configure to desired flavor of dropped data. + */ + private DataFlavor getDesiredFlavor() { + return DataFlavor.javaFileListFlavor; + } + + /** + * Check to make sure that the contains the expected object types. + */ + private void checkDroppedData(Object data) { + System.out.println("Got data: " + data.getClass().getName()); + if (data instanceof AbstractList) { + AbstractList files = (AbstractList) data; + if (((File) files.get(0)).isFile()) + setText(((File) files.get(0)).toString()); + else + setText("Error: not valid file: " + + ((File) files.get(0)).toString()); + } else { + System.out.println("Error: wrong type of data dropped"); + } + } + + private boolean isDragOk(DropTargetDragEvent e) { + boolean canDrop = false; + try { + canDrop = e.isDataFlavorSupported(getDesiredFlavor()); + } catch (Exception ex) { + } + + if (canDrop) + e.acceptDrag(DnDConstants.ACTION_COPY); + else + e.rejectDrag(); + showDrop(canDrop); + return canDrop; + } + + public void dragEnter(DropTargetDragEvent e) { + isDragOk(e); + } + + + public void dragOver(DropTargetDragEvent e) { + isDragOk(e); + } + + public void dropActionChanged(DropTargetDragEvent e) { + isDragOk(e); + } + + public void dragExit(DropTargetEvent e) { + showDrop(false); + } + + public void drop(DropTargetDropEvent e) { + try { + e.acceptDrop(DnDConstants.ACTION_COPY); + checkDroppedData(e.getTransferable(). + getTransferData(getDesiredFlavor())); + } catch (Exception err) { + } + e.dropComplete(true); + showDrop(false); + } +} From 24eb360147a5ca548abc89eb6480f46b89e11d19 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Fri, 11 Oct 2024 00:29:14 +0000 Subject: [PATCH 027/118] 8341906: Optimize ClassFile writing BufBuffer Reviewed-by: liach --- .../impl/AbstractAttributeMapper.java | 100 +++++++++--------- .../impl/AbstractBoundLocalVariable.java | 9 +- .../impl/AbstractPseudoInstruction.java | 7 +- .../classfile/impl/AnnotationReader.java | 7 +- .../classfile/impl/BufWriterImpl.java | 36 ++++++- .../classfile/impl/DirectClassBuilder.java | 8 +- .../classfile/impl/DirectCodeBuilder.java | 9 +- .../classfile/impl/DirectFieldBuilder.java | 4 +- .../internal/classfile/impl/FieldImpl.java | 6 +- .../internal/classfile/impl/MethodImpl.java | 6 +- .../classfile/impl/StackMapDecoder.java | 20 ++-- .../classfile/impl/StackMapGenerator.java | 12 +-- .../jdk/internal/classfile/impl/Util.java | 6 +- 13 files changed, 119 insertions(+), 111 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java index 50c0bdc2a9fc0..b29b9f6f9551e 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java @@ -140,14 +140,13 @@ public CharacterRangeTableAttribute readAttribute(AttributedElement e, ClassRead } @Override - protected void writeBody(BufWriter buf, CharacterRangeTableAttribute attr) { + protected void writeBody(BufWriter bufWriter, CharacterRangeTableAttribute attr) { List ranges = attr.characterRangeTable(); + BufWriterImpl buf = (BufWriterImpl) bufWriter; buf.writeU2(ranges.size()); for (CharacterRangeInfo info : ranges) { - buf.writeU2(info.startPc()); - buf.writeU2(info.endPc()); - buf.writeInt(info.characterRangeStart()); - buf.writeInt(info.characterRangeEnd()); + buf.writeU2U2(info.startPc(), info.endPc()); + buf.writeIntInt(info.characterRangeStart(), info.characterRangeEnd()); buf.writeU2(info.flags()); } } @@ -238,9 +237,10 @@ public EnclosingMethodAttribute readAttribute(AttributedElement e, ClassReader c } @Override - protected void writeBody(BufWriter buf, EnclosingMethodAttribute attr) { - buf.writeIndex(attr.enclosingClass()); - buf.writeIndexOrZero(attr.enclosingMethod().orElse(null)); + protected void writeBody(BufWriter bufWriter, EnclosingMethodAttribute attr) { + BufWriterImpl buf = (BufWriterImpl) bufWriter; + buf.writeU2U2(buf.cpIndex(attr.enclosingClass()), + buf.cpIndexOrZero(attr.enclosingMethod().orElse(null))); } } @@ -275,13 +275,14 @@ public InnerClassesAttribute readAttribute(AttributedElement e, ClassReader cf, } @Override - protected void writeBody(BufWriter buf, InnerClassesAttribute attr) { + protected void writeBody(BufWriter bufWriter, InnerClassesAttribute attr) { List classes = attr.classes(); + BufWriterImpl buf = (BufWriterImpl) bufWriter; buf.writeU2(classes.size()); for (InnerClassInfo ic : classes) { - buf.writeIndex(ic.innerClass()); - buf.writeIndexOrZero(ic.outerClass().orElse(null)); - buf.writeIndexOrZero(ic.innerName().orElse(null)); + buf.writeU2U2U2(buf.cpIndex(ic.innerClass()), + buf.cpIndexOrZero(ic.outerClass().orElse(null)), + buf.cpIndexOrZero(ic.innerName().orElse(null))); buf.writeU2(ic.flagsMask()); } } @@ -300,12 +301,12 @@ public LineNumberTableAttribute readAttribute(AttributedElement e, ClassReader c } @Override - protected void writeBody(BufWriter buf, LineNumberTableAttribute attr) { + protected void writeBody(BufWriter bufWriter, LineNumberTableAttribute attr) { List lines = attr.lineNumbers(); + BufWriterImpl buf = (BufWriterImpl) bufWriter; buf.writeU2(lines.size()); for (LineNumberInfo line : lines) { - buf.writeU2(line.startPc()); - buf.writeU2(line.lineNumber()); + buf.writeU2U2(line.startPc(), line.lineNumber()); } } } @@ -323,15 +324,13 @@ public LocalVariableTableAttribute readAttribute(AttributedElement e, ClassReade } @Override - protected void writeBody(BufWriter buf, LocalVariableTableAttribute attr) { + protected void writeBody(BufWriter bufWriter, LocalVariableTableAttribute attr) { List infos = attr.localVariables(); + BufWriterImpl buf = (BufWriterImpl) bufWriter; buf.writeU2(infos.size()); for (LocalVariableInfo info : infos) { - buf.writeU2(info.startPc()); - buf.writeU2(info.length()); - buf.writeIndex(info.name()); - buf.writeIndex(info.type()); - buf.writeU2(info.slot()); + buf.writeU2U2(info.startPc(), info.length()); + buf.writeU2U2U2(buf.cpIndex(info.name()), buf.cpIndex(info.type()), info.slot()); } } } @@ -349,15 +348,13 @@ public LocalVariableTypeTableAttribute readAttribute(AttributedElement e, ClassR } @Override - protected void writeBody(BufWriter buf, LocalVariableTypeTableAttribute attr) { + protected void writeBody(BufWriter bufWriter, LocalVariableTypeTableAttribute attr) { List infos = attr.localVariableTypes(); + BufWriterImpl buf = (BufWriterImpl) bufWriter; buf.writeU2(infos.size()); for (LocalVariableTypeInfo info : infos) { - buf.writeU2(info.startPc()); - buf.writeU2(info.length()); - buf.writeIndex(info.name()); - buf.writeIndex(info.signature()); - buf.writeU2(info.slot()); + buf.writeU2U2(info.startPc(), info.length()); + buf.writeU2U2U2(buf.cpIndex(info.name()), buf.cpIndex(info.signature()), info.slot()); } } } @@ -375,12 +372,13 @@ public MethodParametersAttribute readAttribute(AttributedElement e, ClassReader } @Override - protected void writeBody(BufWriter buf, MethodParametersAttribute attr) { + protected void writeBody(BufWriter bufWriter, MethodParametersAttribute attr) { List parameters = attr.parameters(); + BufWriterImpl buf = (BufWriterImpl) bufWriter; buf.writeU1(parameters.size()); for (MethodParameterInfo info : parameters) { - buf.writeIndexOrZero(info.name().orElse(null)); - buf.writeU2(info.flagsMask()); + buf.writeU2U2(buf.cpIndexOrZero(info.name().orElse(null)), + info.flagsMask()); } } } @@ -398,26 +396,27 @@ public ModuleAttribute readAttribute(AttributedElement e, ClassReader cf, int p) } @Override - protected void writeBody(BufWriter buf, ModuleAttribute attr) { - buf.writeIndex(attr.moduleName()); - buf.writeU2(attr.moduleFlagsMask()); - buf.writeIndexOrZero(attr.moduleVersion().orElse(null)); + protected void writeBody(BufWriter bufWriter, ModuleAttribute attr) { + BufWriterImpl buf = (BufWriterImpl) bufWriter; + buf.writeU2U2U2(buf.cpIndex(attr.moduleName()), + attr.moduleFlagsMask(), + buf.cpIndexOrZero(attr.moduleVersion().orElse(null))); buf.writeU2(attr.requires().size()); for (ModuleRequireInfo require : attr.requires()) { - buf.writeIndex(require.requires()); - buf.writeU2(require.requiresFlagsMask()); - buf.writeIndexOrZero(require.requiresVersion().orElse(null)); + buf.writeU2U2U2(buf.cpIndex(require.requires()), + require.requiresFlagsMask(), + buf.cpIndexOrZero(require.requiresVersion().orElse(null))); } buf.writeU2(attr.exports().size()); for (ModuleExportInfo export : attr.exports()) { - buf.writeIndex(export.exportedPackage()); - buf.writeU2(export.exportsFlagsMask()); + buf.writeU2U2(buf.cpIndex(export.exportedPackage()), + export.exportsFlagsMask()); Util.writeListIndices(buf, export.exportsTo()); } buf.writeU2(attr.opens().size()); for (ModuleOpenInfo open : attr.opens()) { - buf.writeIndex(open.openedPackage()); - buf.writeU2(open.opensFlagsMask()); + buf.writeU2U2(buf.cpIndex(open.openedPackage()), + open.opensFlagsMask()); Util.writeListIndices(buf, open.opensTo()); } Util.writeListIndices(buf, attr.uses()); @@ -442,13 +441,13 @@ public ModuleHashesAttribute readAttribute(AttributedElement e, ClassReader cf, } @Override - protected void writeBody(BufWriter buf, ModuleHashesAttribute attr) { - buf.writeIndex(attr.algorithm()); + protected void writeBody(BufWriter bufWriter, ModuleHashesAttribute attr) { List hashes = attr.hashes(); - buf.writeU2(hashes.size()); + BufWriterImpl buf = (BufWriterImpl) bufWriter; + buf.writeU2U2(buf.cpIndex(attr.algorithm()), hashes.size()); for (ModuleHashInfo hash : hashes) { - buf.writeIndex(hash.moduleName()); - buf.writeU2(hash.hash().length); + buf.writeU2U2(buf.cpIndex(hash.moduleName()), + hash.hash().length); buf.writeBytes(hash.hash()); } } @@ -593,13 +592,14 @@ public RecordAttribute readAttribute(AttributedElement e, ClassReader cf, int p) } @Override - protected void writeBody(BufWriter buf, RecordAttribute attr) { + protected void writeBody(BufWriter bufWriter, RecordAttribute attr) { List components = attr.components(); + BufWriterImpl buf = (BufWriterImpl) bufWriter; buf.writeU2(components.size()); for (RecordComponentInfo info : components) { - buf.writeIndex(info.name()); - buf.writeIndex(info.descriptor()); - Util.writeAttributes((BufWriterImpl) buf, info.attributes()); + buf.writeU2U2(buf.cpIndex(info.name()), + buf.cpIndex(info.descriptor())); + Util.writeAttributes(buf, info.attributes()); } } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractBoundLocalVariable.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractBoundLocalVariable.java index dcbd8c8fee83d..71b08c1915f63 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractBoundLocalVariable.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractBoundLocalVariable.java @@ -88,15 +88,12 @@ public boolean writeLocalTo(BufWriterImpl b) { return false; } int length = endBci - startBci; - b.writeU2(startBci); - b.writeU2(length); + b.writeU2U2(startBci, length); if (b.canWriteDirect(code.constantPool())) { - b.writeU2(nameIndex()); - b.writeU2(secondaryIndex()); + b.writeU2U2(nameIndex(), secondaryIndex()); } else { - b.writeIndex(name()); - b.writeIndex(secondaryEntry()); + b.writeU2U2(b.cpIndex(name()), b.cpIndex(secondaryEntry())); } b.writeU2(slot()); return true; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java index dc170ce72b501..ffba8ec7a5d27 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java @@ -200,11 +200,8 @@ public boolean writeLocalTo(BufWriterImpl b) { return false; } int length = endBci - startBci; - b.writeU2(startBci); - b.writeU2(length); - b.writeIndex(name); - b.writeIndex(descriptor); - b.writeU2(slot()); + b.writeU2U2(startBci, length); + b.writeU2U2U2(b.cpIndex(name), b.cpIndex(descriptor), slot()); return true; } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java index 02f6167d436a7..9724cff35ad6d 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java @@ -282,9 +282,8 @@ private static int skipTypeAnnotation(ClassReader classReader, int p) { } public static void writeAnnotation(BufWriterImpl buf, Annotation annotation) { - buf.writeIndex(annotation.className()); var elements = annotation.elements(); - buf.writeU2(elements.size()); + buf.writeU2U2(buf.cpIndex(annotation.className()), elements.size()); for (var e : elements) { buf.writeIndex(e.name()); AnnotationReader.writeAnnotationValue(buf, e.value()); @@ -332,8 +331,8 @@ public static void writeTypeAnnotation(BufWriterImpl buf, TypeAnnotation ta) { case TypeAnnotation.CatchTarget ct -> buf.writeU2(ct.exceptionTableIndex()); case TypeAnnotation.OffsetTarget ot -> buf.writeU2(labelToBci(lr, ot.target(), ta)); case TypeAnnotation.TypeArgumentTarget tat -> { - buf.writeU2(labelToBci(lr, tat.target(), ta)); - buf.writeU1(tat.typeArgumentIndex()); + buf.writeU2U1(labelToBci(lr, tat.target(), ta), + tat.typeArgumentIndex()); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java index cf5b98dafb122..91b3b32190b81 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java @@ -168,6 +168,16 @@ public void writeU1U2U2(int x1, int x2, int x3) { this.offset = offset + 5; } + public void writeU2U1(int x1, int x2) { + reserveSpace(3); + byte[] elems = this.elems; + int offset = this.offset; + elems[offset ] = (byte) (x1 >> 8); + elems[offset + 1] = (byte) x1; + elems[offset + 2] = (byte) x2; + this.offset = offset + 3; + } + public void writeU2U2(int x1, int x2) { reserveSpace(4); byte[] elems = this.elems; @@ -204,6 +214,21 @@ public void writeInt(int x) { this.offset = offset + 4; } + public void writeIntInt(int x1, int x2) { + reserveSpace(8); + byte[] elems = this.elems; + int offset = this.offset; + elems[offset ] = (byte) (x1 >> 24); + elems[offset + 1] = (byte) (x1 >> 16); + elems[offset + 2] = (byte) (x1 >> 8); + elems[offset + 3] = (byte) x1; + elems[offset + 4] = (byte) (x2 >> 24); + elems[offset + 5] = (byte) (x2 >> 16); + elems[offset + 6] = (byte) (x2 >> 8); + elems[offset + 7] = (byte) x2; + this.offset = offset + 8; + } + @Override public void writeFloat(float x) { writeInt(Float.floatToIntBits(x)); @@ -355,6 +380,12 @@ public int cpIndex(PoolEntry entry) { return idx; } + public int cpIndexOrZero(PoolEntry entry) { + if (entry == null || entry.index() == 0) + return 0; + return cpIndex(entry); + } + @ForceInline @Override public void writeIndex(PoolEntry entry) { @@ -371,10 +402,7 @@ static IllegalArgumentException invalidIndex(int idx, PoolEntry entry) { @Override public void writeIndexOrZero(PoolEntry entry) { - if (entry == null || entry.index() == 0) - writeU2(0); - else - writeIndex(entry); + writeU2(cpIndexOrZero(entry)); } /** diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java index b599f2b61aa93..afa7ebac8ba6c 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java @@ -219,12 +219,10 @@ else if ((flags & ClassFile.ACC_MODULE) == 0 && !"java/lang/Object".equals(thisC } // Now we can make the head - head.writeLong((((long) ClassFile.MAGIC_NUMBER) << 32) - | ((minorVersion & 0xFFFFL) << 16) - | (majorVersion & 0xFFFFL)); + head.writeInt(ClassFile.MAGIC_NUMBER); + head.writeU2U2(minorVersion, majorVersion); constantPool.writeTo(head); - head.writeU2U2(flags, head.cpIndex(thisClassEntry)); - head.writeIndexOrZero(superclass); + head.writeU2U2U2(flags, head.cpIndex(thisClassEntry), head.cpIndexOrZero(superclass)); head.writeU2(interfaceEntriesSize); for (int i = 0; i < interfaceEntriesSize; i++) { head.writeIndex(ies[i]); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java index 72c37ade9ac2e..6f2a9cc125a79 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java @@ -257,8 +257,7 @@ public void writeBody(BufWriterImpl b) { } } else { b.writeU2U2(start, end - 1); - b.writeInt(cr.characterRangeStart()); - b.writeInt(cr.characterRangeEnd()); + b.writeIntInt(cr.characterRangeStart(), cr.characterRangeEnd()); b.writeU2(cr.flags()); } } @@ -640,8 +639,7 @@ public void writeTableSwitch(int low, int high, Label defaultTarget, List(cases.size()); for (var c : cases) { caseMap.put(c.caseValue(), c.target()); @@ -668,8 +666,7 @@ public void writeInvokeInterface(Opcode opcode, } public void writeInvokeDynamic(InvokeDynamicEntry ref) { - bytecodesBufWriter.writeIndex(INVOKEDYNAMIC, ref); - bytecodesBufWriter.writeU2(0); + bytecodesBufWriter.writeU1U2U2(INVOKEDYNAMIC, bytecodesBufWriter.cpIndex(ref), 0); } public void writeNewObject(ClassEntry type) { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectFieldBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectFieldBuilder.java index 15547924cf37f..d1fafc626f926 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectFieldBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectFieldBuilder.java @@ -80,9 +80,7 @@ void setFlags(int flags) { @Override public void writeTo(BufWriterImpl buf) { - buf.writeU2(flags); - buf.writeIndex(name); - buf.writeIndex(desc); + buf.writeU2U2U2(flags, buf.cpIndex(name), buf.cpIndex(desc)); attributes.writeTo(buf); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/FieldImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/FieldImpl.java index 30bb8136e45ab..205e36588b421 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/FieldImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/FieldImpl.java @@ -84,9 +84,9 @@ public void writeTo(BufWriterImpl buf) { reader.copyBytesTo(buf, startPos, endPos - startPos); } else { - buf.writeU2(flags().flagsMask()); - buf.writeIndex(fieldName()); - buf.writeIndex(fieldType()); + buf.writeU2U2U2(flags().flagsMask(), + buf.cpIndex(fieldName()), + buf.cpIndex(fieldType())); Util.writeAttributes(buf, attributes()); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java index 8467152504ee5..4f7799d1fa7d5 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java @@ -103,9 +103,9 @@ public void writeTo(BufWriterImpl buf) { reader.copyBytesTo(buf, startPos, endPos - startPos); } else { - buf.writeU2(flags().flagsMask()); - buf.writeIndex(methodName()); - buf.writeIndex(methodType()); + buf.writeU2U2U2(flags().flagsMask(), + buf.cpIndex(methodName()), + buf.cpIndex(methodType())); Util.writeAttributes(buf, attributes()); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java index 54b4139a9e01e..2cad163b17720 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java @@ -135,8 +135,7 @@ private static void writeFrame(BufWriterImpl out, int offsetDelta, List l1, List - {} + bw.writeU1(tag); case ITEM_OBJECT -> - bw.writeIndex(((ObjectVerificationTypeInfo)vti).className()); + bw.writeU1U2(tag, bw.cpIndex(((ObjectVerificationTypeInfo)vti).className())); case ITEM_UNINITIALIZED -> - bw.writeU2(bw.labelContext().labelToBci(((UninitializedVerificationTypeInfo)vti).newTarget())); + bw.writeU1U2(tag, bw.labelContext().labelToBci(((UninitializedVerificationTypeInfo)vti).newTarget())); default -> throw new IllegalArgumentException("Invalid verification type tag: " + vti.tag()); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java index 4bc4e259f5a52..1af13267c8094 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java @@ -1432,8 +1432,7 @@ void writeTo(BufWriterImpl out, Frame prevFrame, ConstantPoolBuilder cp) { return; } //full frame - out.writeU1U2(255, offsetDelta); - out.writeU2(localsSize); + out.writeU1U2U2(255, offsetDelta, localsSize); for (int i=0; i - bw.writeU2(cp.classEntry(sym).index()); + bw.writeU1U2(tag, cp.classEntry(sym).index()); case ITEM_UNINITIALIZED -> - bw.writeU2(bci); + bw.writeU1U2(tag, bci); + default -> + bw.writeU1(tag); } } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java index 7a097775dadb4..0c4410bb5ea1c 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java @@ -287,12 +287,10 @@ public static void dumpMethod(SplitConstantPool cp, ((DirectMethodBuilder)mb).writeAttribute(new UnboundAttribute.AdHocAttribute(Attributes.code()) { @Override public void writeBody(BufWriterImpl b) { - b.writeU2(-1);//max stack - b.writeU2(-1);//max locals + b.writeU2U2(-1, -1);//max stack & locals b.writeInt(bytecode.length()); b.writeBytes(bytecode.array(), 0, bytecode.length()); - b.writeU2(0);//exception handlers - b.writeU2(0);//attributes + b.writeU2U2(0, 0);//exception handlers & attributes } })))); ClassPrinter.toYaml(clm.methods().get(0).code().get(), ClassPrinter.Verbosity.TRACE_ALL, dump); From 472db922fabfb8942f15d39ebd58125189bc8600 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Fri, 11 Oct 2024 02:17:37 +0000 Subject: [PATCH 028/118] 8341900: Optimize DirectCodeBuilder writeBody Reviewed-by: liach --- .../classfile/impl/DirectCodeBuilder.java | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java index 6f2a9cc125a79..b3c106c461d03 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java @@ -373,24 +373,19 @@ public void writeBody(BufWriterImpl buf) { dcb.methodInfo.methodTypeSymbol().displayDescriptor())); } + boolean codeMatch = dcb.original != null && codeAndExceptionsMatch(codeLength); var context = dcb.context; - if (dcb.original != null && codeAndExceptionsMatch(codeLength)) { - if (context.stackMapsWhenRequired()) { + if (context.stackMapsWhenRequired()) { + if (codeMatch) { dcb.attributes.withAttribute(dcb.original.findAttribute(Attributes.stackMapTable()).orElse(null)); writeCounters(true, buf); - } else if (context.generateStackMaps()) { - generateStackMaps(buf); - } else if (context.dropStackMaps()) { - writeCounters(true, buf); - } - } else { - if (context.stackMapsWhenRequired()) { + } else { tryGenerateStackMaps(false, buf); - } else if (context.generateStackMaps()) { - generateStackMaps(buf); - } else if (context.dropStackMaps()) { - writeCounters(false, buf); } + } else if (context.generateStackMaps()) { + generateStackMaps(buf); + } else if (context.dropStackMaps()) { + writeCounters(codeMatch, buf); } buf.writeInt(codeLength); From ace44e564ffe67af5fc25a0f126cf48da0eca078 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Fri, 11 Oct 2024 07:29:11 +0000 Subject: [PATCH 029/118] 8341806: Gcc version detection failure on Alinux3 Reviewed-by: ihse, jwaters --- make/autoconf/toolchain.m4 | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4 index 75c8d2b61d084..5b3ef98c7364b 100644 --- a/make/autoconf/toolchain.m4 +++ b/make/autoconf/toolchain.m4 @@ -358,6 +358,11 @@ AC_DEFUN([TOOLCHAIN_EXTRACT_COMPILER_VERSION], # Copyright (C) 2013 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + # or look like + # gcc (GCC) 10.2.1 20200825 (Alibaba 10.2.1-3.8 2.32) + # Copyright (C) 2020 Free Software Foundation, Inc. + # This is free software; see the source for copying conditions. There is NO + # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. COMPILER_VERSION_OUTPUT=`$COMPILER --version 2>&1` # Check that this is likely to be GCC. $ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "Free Software Foundation" > /dev/null @@ -371,7 +376,8 @@ AC_DEFUN([TOOLCHAIN_EXTRACT_COMPILER_VERSION], COMPILER_VERSION_STRING=`$ECHO $COMPILER_VERSION_OUTPUT | \ $SED -e 's/ *Copyright .*//'` COMPILER_VERSION_NUMBER=`$ECHO $COMPILER_VERSION_OUTPUT | \ - $SED -e 's/^.* \(@<:@1-9@:>@<:@0-9@:>@*\.@<:@0-9.@:>@*\)@<:@^0-9.@:>@.*$/\1/'` + $AWK -F ')' '{print [$]2}' | \ + $AWK '{print [$]1}'` elif test "x$TOOLCHAIN_TYPE" = xclang; then # clang --version output typically looks like # Apple clang version 15.0.0 (clang-1500.3.9.4) From ae41daf9a780f8fd29b2af984e9aa60ae9b10937 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Fri, 11 Oct 2024 08:12:37 +0000 Subject: [PATCH 030/118] 8341880: RISC-V: riscv_vector.h native build fails with gcc13 after JDK-8320500 Co-authored-by: Fei Yang Reviewed-by: mli, fyang --- .../linux/native/libsleef/lib/vector_math_rvv.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/jdk.incubator.vector/linux/native/libsleef/lib/vector_math_rvv.c b/src/jdk.incubator.vector/linux/native/libsleef/lib/vector_math_rvv.c index 4515457fa899a..438ca0c92ba0f 100644 --- a/src/jdk.incubator.vector/linux/native/libsleef/lib/vector_math_rvv.c +++ b/src/jdk.incubator.vector/linux/native/libsleef/lib/vector_math_rvv.c @@ -31,6 +31,8 @@ // At run-time, if the library is found and the bridge functions are available in the // library, then the java vector API will call into the bridge functions and sleef. +#if __GNUC__ >= 14 || (defined(__clang_major__) && __clang_major__ >= 17) + #ifdef __riscv_v_intrinsic #include @@ -117,4 +119,6 @@ DEFINE_VECTOR_MATH_BINARY_RVV(hypotdx_u05, vdouble_rvvm1_sleef) #undef DEFINE_VECTOR_MATH_BINARY_RVV -#endif /* __riscv_v_intrinsic */ +#endif /* __riscv_v_intrinsic */ + +#endif /* check gcc and clang version */ From 7c0dbf8e9c69d51aa8e06305e4483002116019f4 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Fri, 11 Oct 2024 08:22:27 +0000 Subject: [PATCH 031/118] 8341820: Check return value of hcreate_r Reviewed-by: cjplummer, lucy --- src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c b/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c index c36b9e5707e61..4cb791111bcf6 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c @@ -389,9 +389,9 @@ static struct symtab* build_symtab_internal(int fd, const char *filename, bool t goto bad; } - // int rslt = - hcreate_r(htab_sz, symtab->hash_table); - // guarantee(rslt, "unexpected failure: hcreate_r"); + if (hcreate_r(htab_sz, symtab->hash_table) == 0) { + goto bad; + } // shdr->sh_link points to the section that contains the actual strings // for symbol names. the st_name field in ELF_SYM is just the From 519544c1d72bccb4528953adb054ea3ee97e35b9 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Fri, 11 Oct 2024 09:12:16 +0000 Subject: [PATCH 032/118] 8341909: G1: Add region index to region printer output Reviewed-by: kbarrett, lkorinth --- src/hotspot/share/gc/g1/g1HeapRegionPrinter.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1HeapRegionPrinter.hpp b/src/hotspot/share/gc/g1/g1HeapRegionPrinter.hpp index d7b1a6da92c17..577a8552091f6 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionPrinter.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionPrinter.hpp @@ -35,8 +35,8 @@ class G1HeapRegionPrinter : public AllStatic { // Print an action event. static void print(const char* action, G1HeapRegion* hr) { - log_trace(gc, region)("G1HR %s(%s) [" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT "]", - action, hr->get_type_str(), p2i(hr->bottom()), p2i(hr->top()), p2i(hr->end())); + log_trace(gc, region)("G1HR %4u %s(%s) [" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT "]", + hr->hrm_index(), action, hr->get_type_str(), p2i(hr->bottom()), p2i(hr->top()), p2i(hr->end())); } public: From 6133866150cf6131ab578f1537f84c239703fa67 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Fri, 11 Oct 2024 10:07:34 +0000 Subject: [PATCH 033/118] 8341070: javac fails with an exception when compiling import module under source level 8 Reviewed-by: asotona --- .../com/sun/tools/javac/code/Symtab.java | 36 +++++++-------- test/langtools/tools/javac/ImportModule.java | 46 +++++++++++++++++++ 2 files changed, 63 insertions(+), 19 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java index 4e62828c42658..cee6a16a10fc6 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java @@ -420,6 +420,23 @@ protected Symtab(Context context) throws CompletionFailure { missingInfoHandler, target.runtimeUseNestAccess()); + noModule = new ModuleSymbol(names.empty, null) { + @Override public boolean isNoModule() { + return true; + } + }; + addRootPackageFor(noModule); + + Source source = Source.instance(context); + if (Feature.MODULES.allowedInSource(source)) { + java_base = enterModule(names.java_base); + //avoid completing java.base during the Symtab initialization + java_base.completer = Completer.NULL_COMPLETER; + java_base.visiblePackages = Collections.emptyMap(); + } else { + java_base = noModule; + } + // create the basic builtin symbols unnamedModule = new ModuleSymbol(names.empty, null) { { @@ -427,7 +444,6 @@ protected Symtab(Context context) throws CompletionFailure { exports = List.nil(); provides = List.nil(); uses = List.nil(); - ModuleSymbol java_base = enterModule(names.java_base); com.sun.tools.javac.code.Directive.RequiresDirective d = new com.sun.tools.javac.code.Directive.RequiresDirective(java_base, EnumSet.of(com.sun.tools.javac.code.Directive.RequiresFlag.MANDATED)); @@ -447,7 +463,6 @@ public String toString() { exports = List.nil(); provides = List.nil(); uses = List.nil(); - ModuleSymbol java_base = enterModule(names.java_base); com.sun.tools.javac.code.Directive.RequiresDirective d = new com.sun.tools.javac.code.Directive.RequiresDirective(java_base, EnumSet.of(com.sun.tools.javac.code.Directive.RequiresFlag.MANDATED)); @@ -456,13 +471,6 @@ public String toString() { }; addRootPackageFor(errModule); - noModule = new ModuleSymbol(names.empty, null) { - @Override public boolean isNoModule() { - return true; - } - }; - addRootPackageFor(noModule); - noSymbol = new TypeSymbol(NIL, 0, names.empty, Type.noType, rootPackage) { @Override @DefinedBy(Api.LANGUAGE_MODEL) public R accept(ElementVisitor v, P p) { @@ -526,16 +534,6 @@ public R accept(ElementVisitor v, P p) { // Enter symbol for the errSymbol scope.enter(errSymbol); - Source source = Source.instance(context); - if (Feature.MODULES.allowedInSource(source)) { - java_base = enterModule(names.java_base); - //avoid completing java.base during the Symtab initialization - java_base.completer = Completer.NULL_COMPLETER; - java_base.visiblePackages = Collections.emptyMap(); - } else { - java_base = noModule; - } - // Get the initial completer for ModuleSymbols from Modules moduleCompleter = Modules.instance(context).getCompleter(); diff --git a/test/langtools/tools/javac/ImportModule.java b/test/langtools/tools/javac/ImportModule.java index f38b77062e224..dc1ed9bd0c12d 100644 --- a/test/langtools/tools/javac/ImportModule.java +++ b/test/langtools/tools/javac/ImportModule.java @@ -797,4 +797,50 @@ public class C {} } } + + @Test + public void testImportModuleNoModules(Path base) throws Exception { + Path current = base.resolve("."); + Path src = current.resolve("src"); + Path classes = current.resolve("classes"); + tb.writeJavaFiles(src, + """ + package test; + import module java.base; + public class Test { + List l; + } + """); + + Files.createDirectories(classes); + + List actualErrors = new JavacTask(tb) + .options("--release", "8", + "-XDshould-stop.at=FLOW", + "-XDdev", + "-XDrawDiagnostics") + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + List expectedErrors = List.of( + "- compiler.warn.option.obsolete.source: 8", + "- compiler.warn.option.obsolete.target: 8", + "- compiler.warn.option.obsolete.suppression", + "Test.java:2:8: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.module.imports)", + "Test.java:2:1: compiler.err.import.module.not.found: java.base", + "Test.java:4:5: compiler.err.cant.resolve.location: kindname.class, List, , , (compiler.misc.location: kindname.class, test.Test, null)", + "3 errors", + "3 warnings" + ); + + if (!Objects.equals(expectedErrors, actualErrors)) { + throw new AssertionError("Incorrect Output, expected: " + expectedErrors + + ", actual: " + out); + + } + } + } From 7276a1bec0d90f63e9e433fdcdfd6564b70dc9bb Mon Sep 17 00:00:00 2001 From: Quan Anh Mai Date: Fri, 11 Oct 2024 15:28:15 +0000 Subject: [PATCH 034/118] 8341784: Refactor TypeVect to use a BasicType instead of a const Type* Reviewed-by: kvn, jkarthikeyan --- src/hotspot/cpu/aarch64/aarch64.ad | 4 - src/hotspot/cpu/arm/arm.ad | 4 - src/hotspot/cpu/ppc/ppc.ad | 4 - src/hotspot/cpu/riscv/riscv.ad | 4 - src/hotspot/cpu/s390/s390.ad | 4 - src/hotspot/cpu/x86/x86.ad | 4 - src/hotspot/share/opto/loopopts.cpp | 3 +- src/hotspot/share/opto/matcher.hpp | 1 - .../share/opto/superwordVTransformBuilder.cpp | 4 +- src/hotspot/share/opto/type.cpp | 137 ++++++++---------- src/hotspot/share/opto/type.hpp | 67 ++++----- src/hotspot/share/opto/vectorIntrinsics.cpp | 49 +++---- src/hotspot/share/opto/vectornode.cpp | 23 ++- src/hotspot/share/opto/vectornode.hpp | 2 +- src/hotspot/share/opto/vtransform.cpp | 3 +- src/hotspot/share/opto/vtransform.hpp | 4 +- .../compiler/lib/ir_framework/IRNode.java | 14 +- .../checkattribute/parsing/RawIRNode.java | 5 +- 18 files changed, 131 insertions(+), 205 deletions(-) diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 4049ab1fe8073..d9c77a2f52926 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -2307,10 +2307,6 @@ const RegMask* Matcher::predicate_reg_mask(void) { return &_PR_REG_mask; } -const TypeVectMask* Matcher::predicate_reg_type(const Type* elemTy, int length) { - return new TypeVectMask(elemTy, length); -} - // Vector calling convention not yet implemented. bool Matcher::supports_vector_calling_convention(void) { return false; diff --git a/src/hotspot/cpu/arm/arm.ad b/src/hotspot/cpu/arm/arm.ad index bb81f2af5999b..bfca986f350cb 100644 --- a/src/hotspot/cpu/arm/arm.ad +++ b/src/hotspot/cpu/arm/arm.ad @@ -1003,10 +1003,6 @@ const RegMask* Matcher::predicate_reg_mask(void) { return nullptr; } -const TypeVectMask* Matcher::predicate_reg_type(const Type* elemTy, int length) { - return nullptr; -} - // Vector calling convention not yet implemented. bool Matcher::supports_vector_calling_convention(void) { return false; diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index b5bfdf5067a12..f74dde0f97e6e 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -2154,10 +2154,6 @@ const RegMask* Matcher::predicate_reg_mask(void) { return nullptr; } -const TypeVectMask* Matcher::predicate_reg_type(const Type* elemTy, int length) { - return nullptr; -} - // Vector calling convention not yet implemented. bool Matcher::supports_vector_calling_convention(void) { return false; diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 30b8ff77be809..54d1f1c05736d 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -1966,10 +1966,6 @@ const RegMask* Matcher::predicate_reg_mask(void) { return &_VMASK_REG_mask; } -const TypeVectMask* Matcher::predicate_reg_type(const Type* elemTy, int length) { - return new TypeVectMask(elemTy, length); -} - // Vector calling convention not yet implemented. bool Matcher::supports_vector_calling_convention(void) { return EnableVectorSupport && UseVectorStubs; diff --git a/src/hotspot/cpu/s390/s390.ad b/src/hotspot/cpu/s390/s390.ad index ebb2ca36a6458..8b897033aa55d 100644 --- a/src/hotspot/cpu/s390/s390.ad +++ b/src/hotspot/cpu/s390/s390.ad @@ -1477,10 +1477,6 @@ const RegMask* Matcher::predicate_reg_mask(void) { return nullptr; } -const TypeVectMask* Matcher::predicate_reg_type(const Type* elemTy, int length) { - return nullptr; -} - // Vector calling convention not yet implemented. bool Matcher::supports_vector_calling_convention(void) { return false; diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index b55a1208cf2df..c88fa1ec5ce15 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -2231,10 +2231,6 @@ const RegMask* Matcher::predicate_reg_mask(void) { return &_VECTMASK_REG_mask; } -const TypeVectMask* Matcher::predicate_reg_type(const Type* elemTy, int length) { - return new TypeVectMask(elemTy, length); -} - // Max vector size in bytes. 0 if not supported. int Matcher::vector_width_in_bytes(BasicType bt) { assert(is_java_primitive(bt), "only primitive type vectors"); diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index 7f42d2d4beb42..654262d21cb71 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -4548,7 +4548,6 @@ void PhaseIdealLoop::move_unordered_reduction_out_of_loop(IdealLoopTree* loop) { const TypeVect* vec_t = last_ur->vect_type(); uint vector_length = vec_t->length(); BasicType bt = vec_t->element_basic_type(); - const Type* bt_t = Type::get_const_basic_type(bt); // Convert opcode from vector-reduction -> scalar -> normal-vector-op const int sopc = VectorNode::scalar_opcode(last_ur->Opcode(), bt); @@ -4628,7 +4627,7 @@ void PhaseIdealLoop::move_unordered_reduction_out_of_loop(IdealLoopTree* loop) { Node* identity_scalar = ReductionNode::make_identity_con_scalar(_igvn, sopc, bt); set_ctrl(identity_scalar, C->root()); - VectorNode* identity_vector = VectorNode::scalar2vector(identity_scalar, vector_length, bt_t); + VectorNode* identity_vector = VectorNode::scalar2vector(identity_scalar, vector_length, bt); register_new_node(identity_vector, C->root()); assert(vec_t == identity_vector->vect_type(), "matching vector type"); VectorNode::trace_new_vector(identity_vector, "Unordered Reduction"); diff --git a/src/hotspot/share/opto/matcher.hpp b/src/hotspot/share/opto/matcher.hpp index 257628350881a..de3b23aa6d2a1 100644 --- a/src/hotspot/share/opto/matcher.hpp +++ b/src/hotspot/share/opto/matcher.hpp @@ -342,7 +342,6 @@ class Matcher : public PhaseTransform { static bool vector_needs_partial_operations(Node* node, const TypeVect* vt); static const RegMask* predicate_reg_mask(void); - static const TypeVectMask* predicate_reg_type(const Type* elemTy, int length); // Vector width in bytes static int vector_width_in_bytes(BasicType bt); diff --git a/src/hotspot/share/opto/superwordVTransformBuilder.cpp b/src/hotspot/share/opto/superwordVTransformBuilder.cpp index b0a0c97cb1676..6c2d3a3be35c3 100644 --- a/src/hotspot/share/opto/superwordVTransformBuilder.cpp +++ b/src/hotspot/share/opto/superwordVTransformBuilder.cpp @@ -228,8 +228,8 @@ VTransformNode* SuperWordVTransformBuilder::get_or_make_vtnode_vector_input_at_i return shift_count; } else { // Replicate the scalar same_input to every vector element. - const Type* element_type = _vloop_analyzer.types().velt_type(p0); - if (index == 2 && VectorNode::is_scalar_rotate(p0) && element_type->isa_long()) { + BasicType element_type = _vloop_analyzer.types().velt_basic_type(p0); + if (index == 2 && VectorNode::is_scalar_rotate(p0) && element_type == T_LONG) { // Scalar rotate has int rotation value, but the scalar rotate expects longs. assert(same_input->bottom_type()->isa_int(), "scalar rotate expects int rotation"); VTransformNode* conv = new (_vtransform.arena()) VTransformConvI2LNode(_vtransform); diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index 73f852c0f047d..828cea88d8339 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -679,7 +679,7 @@ void Type::Initialize_shared(Compile* current) { // get_zero_type() should not happen for T_CONFLICT _zero_type[T_CONFLICT]= nullptr; - TypeVect::VECTMASK = (TypeVect*)(new TypeVectMask(TypeInt::BOOL, MaxVectorSize))->hashcons(); + TypeVect::VECTMASK = (TypeVect*)(new TypeVectMask(T_BOOLEAN, MaxVectorSize))->hashcons(); mreg2type[Op_RegVectMask] = TypeVect::VECTMASK; if (Matcher::supports_scalable_vector()) { @@ -687,20 +687,20 @@ void Type::Initialize_shared(Compile* current) { } // Vector predefined types, it needs initialized _const_basic_type[]. - if (Matcher::vector_size_supported(T_BYTE,4)) { - TypeVect::VECTS = TypeVect::make(T_BYTE,4); + if (Matcher::vector_size_supported(T_BYTE, 4)) { + TypeVect::VECTS = TypeVect::make(T_BYTE, 4); } - if (Matcher::vector_size_supported(T_FLOAT,2)) { - TypeVect::VECTD = TypeVect::make(T_FLOAT,2); + if (Matcher::vector_size_supported(T_FLOAT, 2)) { + TypeVect::VECTD = TypeVect::make(T_FLOAT, 2); } - if (Matcher::vector_size_supported(T_FLOAT,4)) { - TypeVect::VECTX = TypeVect::make(T_FLOAT,4); + if (Matcher::vector_size_supported(T_FLOAT, 4)) { + TypeVect::VECTX = TypeVect::make(T_FLOAT, 4); } - if (Matcher::vector_size_supported(T_FLOAT,8)) { - TypeVect::VECTY = TypeVect::make(T_FLOAT,8); + if (Matcher::vector_size_supported(T_FLOAT, 8)) { + TypeVect::VECTY = TypeVect::make(T_FLOAT, 8); } - if (Matcher::vector_size_supported(T_FLOAT,16)) { - TypeVect::VECTZ = TypeVect::make(T_FLOAT,16); + if (Matcher::vector_size_supported(T_FLOAT, 16)) { + TypeVect::VECTZ = TypeVect::make(T_FLOAT, 16); } mreg2type[Op_VecA] = TypeVect::VECTA; @@ -2482,58 +2482,59 @@ bool TypeAry::ary_must_be_exact() const { //==============================TypeVect======================================= // Convenience common pre-built types. -const TypeVect *TypeVect::VECTA = nullptr; // vector length agnostic -const TypeVect *TypeVect::VECTS = nullptr; // 32-bit vectors -const TypeVect *TypeVect::VECTD = nullptr; // 64-bit vectors -const TypeVect *TypeVect::VECTX = nullptr; // 128-bit vectors -const TypeVect *TypeVect::VECTY = nullptr; // 256-bit vectors -const TypeVect *TypeVect::VECTZ = nullptr; // 512-bit vectors -const TypeVect *TypeVect::VECTMASK = nullptr; // predicate/mask vector +const TypeVect* TypeVect::VECTA = nullptr; // vector length agnostic +const TypeVect* TypeVect::VECTS = nullptr; // 32-bit vectors +const TypeVect* TypeVect::VECTD = nullptr; // 64-bit vectors +const TypeVect* TypeVect::VECTX = nullptr; // 128-bit vectors +const TypeVect* TypeVect::VECTY = nullptr; // 256-bit vectors +const TypeVect* TypeVect::VECTZ = nullptr; // 512-bit vectors +const TypeVect* TypeVect::VECTMASK = nullptr; // predicate/mask vector //------------------------------make------------------------------------------- -const TypeVect* TypeVect::make(const Type *elem, uint length, bool is_mask) { +const TypeVect* TypeVect::make(BasicType elem_bt, uint length, bool is_mask) { if (is_mask) { - return makemask(elem, length); + return makemask(elem_bt, length); } - BasicType elem_bt = elem->array_element_basic_type(); assert(is_java_primitive(elem_bt), "only primitive types in vector"); assert(Matcher::vector_size_supported(elem_bt, length), "length in range"); int size = length * type2aelembytes(elem_bt); switch (Matcher::vector_ideal_reg(size)) { case Op_VecA: - return (TypeVect*)(new TypeVectA(elem, length))->hashcons(); + return (TypeVect*)(new TypeVectA(elem_bt, length))->hashcons(); case Op_VecS: - return (TypeVect*)(new TypeVectS(elem, length))->hashcons(); + return (TypeVect*)(new TypeVectS(elem_bt, length))->hashcons(); case Op_RegL: case Op_VecD: case Op_RegD: - return (TypeVect*)(new TypeVectD(elem, length))->hashcons(); + return (TypeVect*)(new TypeVectD(elem_bt, length))->hashcons(); case Op_VecX: - return (TypeVect*)(new TypeVectX(elem, length))->hashcons(); + return (TypeVect*)(new TypeVectX(elem_bt, length))->hashcons(); case Op_VecY: - return (TypeVect*)(new TypeVectY(elem, length))->hashcons(); + return (TypeVect*)(new TypeVectY(elem_bt, length))->hashcons(); case Op_VecZ: - return (TypeVect*)(new TypeVectZ(elem, length))->hashcons(); + return (TypeVect*)(new TypeVectZ(elem_bt, length))->hashcons(); } ShouldNotReachHere(); return nullptr; } -const TypeVect *TypeVect::makemask(const Type* elem, uint length) { - BasicType elem_bt = elem->array_element_basic_type(); +const TypeVect* TypeVect::makemask(BasicType elem_bt, uint length) { if (Matcher::has_predicated_vectors() && Matcher::match_rule_supported_vector_masked(Op_VectorLoadMask, length, elem_bt)) { - return TypeVectMask::make(elem, length); + return TypeVectMask::make(elem_bt, length); } else { - return make(elem, length); + return make(elem_bt, length); } } //------------------------------meet------------------------------------------- -// Compute the MEET of two types. It returns a new Type object. -const Type *TypeVect::xmeet( const Type *t ) const { +// Compute the MEET of two types. Since each TypeVect is the only instance of +// its species, meeting often returns itself +const Type* TypeVect::xmeet(const Type* t) const { // Perform a fast test for common case; meeting the same types together. - if( this == t ) return this; // Meeting same type-rep? + if (this == t) { + return this; + } // Current "this->_base" is Vector switch (t->base()) { // switch on original type @@ -2543,13 +2544,7 @@ const Type *TypeVect::xmeet( const Type *t ) const { default: // All else is a mistake typerr(t); - case VectorMask: { - const TypeVectMask* v = t->is_vectmask(); - assert( base() == v->base(), ""); - assert(length() == v->length(), ""); - assert(element_basic_type() == v->element_basic_type(), ""); - return TypeVect::makemask(_elem->xmeet(v->_elem), _length); - } + case VectorMask: case VectorA: case VectorS: case VectorD: @@ -2557,10 +2552,10 @@ const Type *TypeVect::xmeet( const Type *t ) const { case VectorY: case VectorZ: { // Meeting 2 vectors? const TypeVect* v = t->is_vect(); - assert( base() == v->base(), ""); + assert(base() == v->base(), ""); assert(length() == v->length(), ""); assert(element_basic_type() == v->element_basic_type(), ""); - return TypeVect::make(_elem->xmeet(v->_elem), _length); + return this; } case Top: break; @@ -2569,26 +2564,26 @@ const Type *TypeVect::xmeet( const Type *t ) const { } //------------------------------xdual------------------------------------------ -// Dual: compute field-by-field dual -const Type *TypeVect::xdual() const { - return new TypeVect(base(), _elem->dual(), _length); +// Since each TypeVect is the only instance of its species, it is self-dual +const Type* TypeVect::xdual() const { + return this; } //------------------------------eq--------------------------------------------- // Structural equality check for Type representations -bool TypeVect::eq(const Type *t) const { - const TypeVect *v = t->is_vect(); - return (_elem == v->_elem) && (_length == v->_length); +bool TypeVect::eq(const Type* t) const { + const TypeVect* v = t->is_vect(); + return (element_basic_type() == v->element_basic_type()) && (length() == v->length()); } //------------------------------hash------------------------------------------- // Type-specific hashing function. uint TypeVect::hash(void) const { - return (uint)(uintptr_t)_elem + (uint)(uintptr_t)_length; + return (uint)base() + (uint)(uintptr_t)_elem_bt + (uint)(uintptr_t)_length; } //------------------------------singleton-------------------------------------- -// TRUE if Type is a singleton type, FALSE otherwise. Singletons are simple +// TRUE if Type is a singleton type, FALSE otherwise. Singletons are simple // constants (Ldi nodes). Vector is singleton if all elements are the same // constant value (when vector is created with Replicate code). bool TypeVect::singleton(void) const { @@ -2598,52 +2593,36 @@ bool TypeVect::singleton(void) const { } bool TypeVect::empty(void) const { - return _elem->empty(); + return false; } //------------------------------dump2------------------------------------------ #ifndef PRODUCT -void TypeVect::dump2(Dict &d, uint depth, outputStream *st) const { +void TypeVect::dump2(Dict& d, uint depth, outputStream* st) const { switch (base()) { case VectorA: - st->print("vectora["); break; + st->print("vectora"); break; case VectorS: - st->print("vectors["); break; + st->print("vectors"); break; case VectorD: - st->print("vectord["); break; + st->print("vectord"); break; case VectorX: - st->print("vectorx["); break; + st->print("vectorx"); break; case VectorY: - st->print("vectory["); break; + st->print("vectory"); break; case VectorZ: - st->print("vectorz["); break; + st->print("vectorz"); break; case VectorMask: - st->print("vectormask["); break; + st->print("vectormask"); break; default: ShouldNotReachHere(); } - st->print("%d]:{", _length); - _elem->dump2(d, depth, st); - st->print("}"); + st->print("<%c,%u>", type2char(element_basic_type()), length()); } #endif -bool TypeVectMask::eq(const Type *t) const { - const TypeVectMask *v = t->is_vectmask(); - return (element_type() == v->element_type()) && (length() == v->length()); -} - -const Type *TypeVectMask::xdual() const { - return new TypeVectMask(element_type()->dual(), length()); -} - -const TypeVectMask *TypeVectMask::make(const BasicType elem_bt, uint length) { - return make(get_const_basic_type(elem_bt), length); -} - -const TypeVectMask *TypeVectMask::make(const Type* elem, uint length) { - const TypeVectMask* mtype = Matcher::predicate_reg_type(elem, length); - return (TypeVectMask*) const_cast(mtype)->hashcons(); +const TypeVectMask* TypeVectMask::make(const BasicType elem_bt, uint length) { + return (TypeVectMask*) (new TypeVectMask(elem_bt, length))->hashcons(); } //============================================================================= diff --git a/src/hotspot/share/opto/type.hpp b/src/hotspot/share/opto/type.hpp index 902155e975d16..f6b7efcae3bcc 100644 --- a/src/hotspot/share/opto/type.hpp +++ b/src/hotspot/share/opto/type.hpp @@ -784,94 +784,79 @@ class TypeAry : public Type { //------------------------------TypeVect--------------------------------------- // Class of Vector Types class TypeVect : public Type { - const Type* _elem; // Vector's element type - const uint _length; // Elements in vector (power of 2) + const BasicType _elem_bt; // Vector's element type + const uint _length; // Elements in vector (power of 2) protected: - TypeVect(TYPES t, const Type* elem, uint length) : Type(t), - _elem(elem), _length(length) {} + TypeVect(TYPES t, BasicType elem_bt, uint length) : Type(t), + _elem_bt(elem_bt), _length(length) {} public: - const Type* element_type() const { return _elem; } - BasicType element_basic_type() const { return _elem->array_element_basic_type(); } + BasicType element_basic_type() const { return _elem_bt; } uint length() const { return _length; } uint length_in_bytes() const { - return _length * type2aelembytes(element_basic_type()); + return _length * type2aelembytes(element_basic_type()); } - virtual bool eq(const Type *t) const; + virtual bool eq(const Type* t) const; virtual uint hash() const; // Type specific hashing virtual bool singleton(void) const; // TRUE if type is a singleton virtual bool empty(void) const; // TRUE if type is vacuous - static const TypeVect *make(const BasicType elem_bt, uint length, bool is_mask = false) { - // Use bottom primitive type. - return make(get_const_basic_type(elem_bt), length, is_mask); - } - // Used directly by Replicate nodes to construct singleton vector. - static const TypeVect *make(const Type* elem, uint length, bool is_mask = false); - - static const TypeVect *makemask(const BasicType elem_bt, uint length) { - // Use bottom primitive type. - return makemask(get_const_basic_type(elem_bt), length); - } - static const TypeVect *makemask(const Type* elem, uint length); - + static const TypeVect* make(const BasicType elem_bt, uint length, bool is_mask = false); + static const TypeVect* makemask(const BasicType elem_bt, uint length); - virtual const Type *xmeet( const Type *t) const; - virtual const Type *xdual() const; // Compute dual right now. + virtual const Type* xmeet( const Type *t) const; + virtual const Type* xdual() const; // Compute dual right now. - static const TypeVect *VECTA; - static const TypeVect *VECTS; - static const TypeVect *VECTD; - static const TypeVect *VECTX; - static const TypeVect *VECTY; - static const TypeVect *VECTZ; - static const TypeVect *VECTMASK; + static const TypeVect* VECTA; + static const TypeVect* VECTS; + static const TypeVect* VECTD; + static const TypeVect* VECTX; + static const TypeVect* VECTY; + static const TypeVect* VECTZ; + static const TypeVect* VECTMASK; #ifndef PRODUCT - virtual void dump2(Dict &d, uint, outputStream *st) const; // Specialized per-Type dumping + virtual void dump2(Dict& d, uint, outputStream* st) const; // Specialized per-Type dumping #endif }; class TypeVectA : public TypeVect { friend class TypeVect; - TypeVectA(const Type* elem, uint length) : TypeVect(VectorA, elem, length) {} + TypeVectA(BasicType elem_bt, uint length) : TypeVect(VectorA, elem_bt, length) {} }; class TypeVectS : public TypeVect { friend class TypeVect; - TypeVectS(const Type* elem, uint length) : TypeVect(VectorS, elem, length) {} + TypeVectS(BasicType elem_bt, uint length) : TypeVect(VectorS, elem_bt, length) {} }; class TypeVectD : public TypeVect { friend class TypeVect; - TypeVectD(const Type* elem, uint length) : TypeVect(VectorD, elem, length) {} + TypeVectD(BasicType elem_bt, uint length) : TypeVect(VectorD, elem_bt, length) {} }; class TypeVectX : public TypeVect { friend class TypeVect; - TypeVectX(const Type* elem, uint length) : TypeVect(VectorX, elem, length) {} + TypeVectX(BasicType elem_bt, uint length) : TypeVect(VectorX, elem_bt, length) {} }; class TypeVectY : public TypeVect { friend class TypeVect; - TypeVectY(const Type* elem, uint length) : TypeVect(VectorY, elem, length) {} + TypeVectY(BasicType elem_bt, uint length) : TypeVect(VectorY, elem_bt, length) {} }; class TypeVectZ : public TypeVect { friend class TypeVect; - TypeVectZ(const Type* elem, uint length) : TypeVect(VectorZ, elem, length) {} + TypeVectZ(BasicType elem_bt, uint length) : TypeVect(VectorZ, elem_bt, length) {} }; class TypeVectMask : public TypeVect { public: friend class TypeVect; - TypeVectMask(const Type* elem, uint length) : TypeVect(VectorMask, elem, length) {} - virtual bool eq(const Type *t) const; - virtual const Type *xdual() const; + TypeVectMask(BasicType elem_bt, uint length) : TypeVect(VectorMask, elem_bt, length) {} static const TypeVectMask* make(const BasicType elem_bt, uint length); - static const TypeVectMask* make(const Type* elem, uint length); }; // Set of implemented interfaces. Referenced from TypeOopPtr and TypeKlassPtr. diff --git a/src/hotspot/share/opto/vectorIntrinsics.cpp b/src/hotspot/share/opto/vectorIntrinsics.cpp index 8eb26c6c519f3..838f87eac011f 100644 --- a/src/hotspot/share/opto/vectorIntrinsics.cpp +++ b/src/hotspot/share/opto/vectorIntrinsics.cpp @@ -524,17 +524,16 @@ bool LibraryCallKit::inline_vector_nary_operation(int n) { Node* LibraryCallKit::partially_wrap_indexes(Node* index_vec, int num_elem, BasicType elem_bt) { assert(elem_bt == T_BYTE, "Shuffles use byte array based backing storage."); const TypeVect* vt = TypeVect::make(elem_bt, num_elem); - const Type* type_bt = Type::get_const_basic_type(elem_bt); Node* mod_mask = gvn().makecon(TypeInt::make(num_elem-1)); - Node* bcast_mod_mask = gvn().transform(VectorNode::scalar2vector(mod_mask, num_elem, type_bt)); + Node* bcast_mod_mask = gvn().transform(VectorNode::scalar2vector(mod_mask, num_elem, elem_bt)); BoolTest::mask pred = BoolTest::ugt; ConINode* pred_node = (ConINode*)gvn().makecon(TypeInt::make(pred)); Node* lane_cnt = gvn().makecon(TypeInt::make(num_elem)); - Node* bcast_lane_cnt = gvn().transform(VectorNode::scalar2vector(lane_cnt, num_elem, type_bt)); - const TypeVect* vmask_type = TypeVect::makemask(type_bt, num_elem); - Node* mask = gvn().transform(new VectorMaskCmpNode(pred, bcast_lane_cnt, index_vec, pred_node, vmask_type)); + Node* bcast_lane_cnt = gvn().transform(VectorNode::scalar2vector(lane_cnt, num_elem, elem_bt)); + const TypeVect* vmask_type = TypeVect::makemask(elem_bt, num_elem); + Node* mask = gvn().transform(new VectorMaskCmpNode(pred, bcast_lane_cnt, index_vec, pred_node, vmask_type)); // Make the indices greater than lane count as -ve values to match the java side implementation. index_vec = gvn().transform(VectorNode::make(Op_AndV, index_vec, bcast_mod_mask, vt)); @@ -600,8 +599,7 @@ bool LibraryCallKit::inline_vector_shuffle_iota() { return false; } - const Type * type_bt = Type::get_const_basic_type(elem_bt); - const TypeVect * vt = TypeVect::make(type_bt, num_elem); + const TypeVect* vt = TypeVect::make(elem_bt, num_elem); Node* res = gvn().transform(new VectorLoadConstNode(gvn().makecon(TypeInt::ZERO), vt)); @@ -609,7 +607,7 @@ bool LibraryCallKit::inline_vector_shuffle_iota() { Node* step = argument(5); if (step_multiply) { - Node* bcast_step = gvn().transform(VectorNode::scalar2vector(step, num_elem, type_bt)); + Node* bcast_step = gvn().transform(VectorNode::scalar2vector(step, num_elem, elem_bt)); res = gvn().transform(VectorNode::make(Op_MulVB, res, bcast_step, vt)); } else if (step_val->get_con() > 1) { Node* cnt = gvn().makecon(TypeInt::make(log2i_exact(step_val->get_con()))); @@ -618,12 +616,12 @@ bool LibraryCallKit::inline_vector_shuffle_iota() { } if (!start_val->is_con() || start_val->get_con() != 0) { - Node* bcast_start = gvn().transform(VectorNode::scalar2vector(start, num_elem, type_bt)); + Node* bcast_start = gvn().transform(VectorNode::scalar2vector(start, num_elem, elem_bt)); res = gvn().transform(VectorNode::make(Op_AddVB, res, bcast_start, vt)); } - Node * mod_val = gvn().makecon(TypeInt::make(num_elem-1)); - Node * bcast_mod = gvn().transform(VectorNode::scalar2vector(mod_val, num_elem, type_bt)); + Node* mod_val = gvn().makecon(TypeInt::make(num_elem-1)); + Node* bcast_mod = gvn().transform(VectorNode::scalar2vector(mod_val, num_elem, elem_bt)); if (do_wrap) { // Wrap the indices greater than lane count. @@ -802,9 +800,8 @@ bool LibraryCallKit::inline_vector_wrap_shuffle_indexes() { Node* shuffle_vec = unbox_vector(shuffle, shuffle_box_type, shuffle_bt, num_elem, true); const TypeVect* vt = TypeVect::make(shuffle_bt, num_elem); - const Type* shuffle_type_bt = Type::get_const_basic_type(shuffle_bt); - Node* mod_mask = gvn().makecon(TypeInt::make(num_elem-1)); - Node* bcast_mod_mask = gvn().transform(VectorNode::scalar2vector(mod_mask, num_elem, shuffle_type_bt)); + Node* mod_mask = gvn().makecon(TypeInt::make(num_elem - 1)); + Node* bcast_mod_mask = gvn().transform(VectorNode::scalar2vector(mod_mask, num_elem, shuffle_bt)); // Wrap the indices greater than lane count. Node* res = gvn().transform(VectorNode::make(Op_AndV, shuffle_vec, bcast_mod_mask, vt)); @@ -908,7 +905,7 @@ bool LibraryCallKit::inline_vector_frombits_coerced() { } default: fatal("%s", type2name(elem_bt)); } - broadcast = VectorNode::scalar2vector(elem, num_elem, Type::get_const_basic_type(elem_bt), is_mask); + broadcast = VectorNode::scalar2vector(elem, num_elem, elem_bt, is_mask); broadcast = gvn().transform(broadcast); } @@ -1352,7 +1349,7 @@ bool LibraryCallKit::inline_vector_mem_masked_operation(bool is_store) { } else { // Use the vector blend to implement the masked load vector. The biased elements are zeros. Node* zero = gvn().transform(gvn().zerocon(mem_elem_bt)); - zero = gvn().transform(VectorNode::scalar2vector(zero, mem_num_elem, Type::get_const_basic_type(mem_elem_bt))); + zero = gvn().transform(VectorNode::scalar2vector(zero, mem_num_elem, mem_elem_bt)); vload = gvn().transform(LoadVectorNode::make(0, control(), memory(addr), addr, addr_type, mem_num_elem, mem_elem_bt)); vload = gvn().transform(new VectorBlendNode(zero, vload, mask)); } @@ -1678,7 +1675,7 @@ bool LibraryCallKit::inline_vector_reduction() { assert(mask != nullptr || !is_masked_op, "Masked op needs the mask value never null"); if (mask != nullptr && !use_predicate) { - Node* reduce_identity = gvn().transform(VectorNode::scalar2vector(init, num_elem, Type::get_const_basic_type(elem_bt))); + Node* reduce_identity = gvn().transform(VectorNode::scalar2vector(init, num_elem, elem_bt)); value = gvn().transform(new VectorBlendNode(reduce_identity, value, mask)); } @@ -2059,7 +2056,7 @@ bool LibraryCallKit::inline_vector_rearrange() { const TypeVect* vt = v1->bottom_type()->is_vect(); rearrange = gvn().transform(rearrange); Node* zero = gvn().makecon(Type::get_zero_type(elem_bt)); - Node* zerovec = gvn().transform(VectorNode::scalar2vector(zero, num_elem, Type::get_const_basic_type(elem_bt))); + Node* zerovec = gvn().transform(VectorNode::scalar2vector(zero, num_elem, elem_bt)); rearrange = new VectorBlendNode(zerovec, rearrange, mask); } } @@ -2215,18 +2212,17 @@ bool LibraryCallKit::inline_vector_select_from() { } // cast index vector from elem_bt vector to byte vector - const Type * byte_bt = Type::get_const_basic_type(T_BYTE); - const TypeVect * byte_vt = TypeVect::make(byte_bt, num_elem); + const TypeVect* byte_vt = TypeVect::make(T_BYTE, num_elem); Node* byte_shuffle = gvn().transform(VectorCastNode::make(cast_vopc, v1, T_BYTE, num_elem)); // wrap the byte vector lanes to (num_elem - 1) to form the shuffle vector where num_elem is vector length // this is a simple AND operation as we come here only for power of two vector length Node* mod_val = gvn().makecon(TypeInt::make(num_elem-1)); - Node* bcast_mod = gvn().transform(VectorNode::scalar2vector(mod_val, num_elem, byte_bt)); + Node* bcast_mod = gvn().transform(VectorNode::scalar2vector(mod_val, num_elem, T_BYTE)); byte_shuffle = gvn().transform(VectorNode::make(Op_AndV, byte_shuffle, bcast_mod, byte_vt)); // load the shuffle to use in rearrange - const TypeVect * shuffle_vt = TypeVect::make(elem_bt, num_elem); + const TypeVect* shuffle_vt = TypeVect::make(elem_bt, num_elem); Node* load_shuffle = gvn().transform(new VectorLoadShuffleNode(byte_shuffle, shuffle_vt)); // and finally rearrange @@ -2243,7 +2239,7 @@ bool LibraryCallKit::inline_vector_select_from() { // create a zero vector with each lane element set as zero Node* zero = gvn().makecon(Type::get_zero_type(elem_bt)); - Node* zerovec = gvn().transform(VectorNode::scalar2vector(zero, num_elem, Type::get_const_basic_type(elem_bt))); + Node* zerovec = gvn().transform(VectorNode::scalar2vector(zero, num_elem, elem_bt)); // For each lane for which mask is set, blend in the rearranged lane into zero vector rearrange = new VectorBlendNode(zerovec, rearrange, mask); @@ -2391,9 +2387,8 @@ bool LibraryCallKit::inline_vector_broadcast_int() { } else { assert(is_rotate, "unexpected operation"); if (!is_const_rotate) { - const Type * type_bt = Type::get_const_basic_type(elem_bt); cnt = elem_bt == T_LONG ? gvn().transform(new ConvI2LNode(cnt)) : cnt; - opd2 = gvn().transform(VectorNode::scalar2vector(cnt, num_elem, type_bt)); + opd2 = gvn().transform(VectorNode::scalar2vector(cnt, num_elem, elem_bt)); } else { // Constant shift value. opd2 = cnt; @@ -3051,7 +3046,7 @@ bool LibraryCallKit::inline_index_vector() { } default: fatal("%s", type2name(elem_bt)); } - scale = gvn().transform(VectorNode::scalar2vector(scale, num_elem, Type::get_const_basic_type(elem_bt))); + scale = gvn().transform(VectorNode::scalar2vector(scale, num_elem, elem_bt)); index = gvn().transform(VectorNode::make(vmul_op, index, scale, vt)); } @@ -3164,7 +3159,7 @@ bool LibraryCallKit::inline_index_partially_in_upper_range() { } default: fatal("%s", type2name(elem_bt)); } - indexLimit = gvn().transform(VectorNode::scalar2vector(indexLimit, num_elem, Type::get_const_basic_type(elem_bt))); + indexLimit = gvn().transform(VectorNode::scalar2vector(indexLimit, num_elem, elem_bt)); // Load the "iota" vector. const TypeVect* vt = TypeVect::make(elem_bt, num_elem); diff --git a/src/hotspot/share/opto/vectornode.cpp b/src/hotspot/share/opto/vectornode.cpp index 72b49c043b6b6..094d4dca564a8 100644 --- a/src/hotspot/share/opto/vectornode.cpp +++ b/src/hotspot/share/opto/vectornode.cpp @@ -799,15 +799,13 @@ VectorNode* VectorNode::make(int opc, Node* n1, Node* n2, Node* n3, uint vlen, B } // Scalar promotion -VectorNode* VectorNode::scalar2vector(Node* s, uint vlen, const Type* opd_t, bool is_mask) { - BasicType bt = opd_t->array_element_basic_type(); +VectorNode* VectorNode::scalar2vector(Node* s, uint vlen, BasicType bt, bool is_mask) { if (is_mask && Matcher::match_rule_supported_vector(Op_MaskAll, vlen, bt)) { - const TypeVect* vt = TypeVect::make(opd_t, vlen, true); + const TypeVect* vt = TypeVect::make(bt, vlen, true); return new MaskAllNode(s, vt); } - const TypeVect* vt = opd_t->singleton() ? TypeVect::make(opd_t, vlen) - : TypeVect::make(bt, vlen); + const TypeVect* vt = TypeVect::make(bt, vlen); return new ReplicateNode(s, vt); } @@ -1626,8 +1624,6 @@ Node* VectorNode::degenerate_vector_rotate(Node* src, Node* cnt, bool is_rotate_ Node* const_one_node = nullptr; assert(cnt->bottom_type()->isa_vect(), "Unexpected shift"); - const Type* elem_ty = Type::get_const_basic_type(bt); - if (bt == T_LONG) { shift_mask_node = phase->longcon(shift_mask); const_one_node = phase->longcon(1L); @@ -1639,8 +1635,8 @@ Node* VectorNode::degenerate_vector_rotate(Node* src, Node* cnt, bool is_rotate_ subVopc = VectorNode::opcode(Op_SubI, bt); addVopc = VectorNode::opcode(Op_AddI, bt); } - Node* vector_mask = phase->transform(VectorNode::scalar2vector(shift_mask_node, vlen, elem_ty)); - Node* vector_one = phase->transform(VectorNode::scalar2vector(const_one_node, vlen, elem_ty)); + Node* vector_mask = phase->transform(VectorNode::scalar2vector(shift_mask_node, vlen, bt)); + Node* vector_one = phase->transform(VectorNode::scalar2vector(const_one_node, vlen, bt)); shiftRCnt = cnt; shiftRCnt = phase->transform(VectorNode::make(Op_AndV, shiftRCnt, vector_mask, vt)); @@ -1882,12 +1878,12 @@ Node* NegVNode::degenerate_integral_negate(PhaseGVN* phase, bool is_predicated) const_one = phase->intcon(1); add_opc = Op_AddI; } - const_minus_one = phase->transform(VectorNode::scalar2vector(const_minus_one, vlen, Type::get_const_basic_type(bt))); + const_minus_one = phase->transform(VectorNode::scalar2vector(const_minus_one, vlen, bt)); Node* xorv = VectorNode::make(Op_XorV, in(1), const_minus_one, vt); xorv->add_req(in(2)); xorv->add_flag(Node::Flag_is_predicated_vector); phase->transform(xorv); - const_one = phase->transform(VectorNode::scalar2vector(const_one, vlen, Type::get_const_basic_type(bt))); + const_one = phase->transform(VectorNode::scalar2vector(const_one, vlen, bt)); Node* addv = VectorNode::make(VectorNode::opcode(add_opc, bt), xorv, const_one, vt); addv->add_req(in(2)); addv->add_flag(Node::Flag_is_predicated_vector); @@ -1904,7 +1900,7 @@ Node* NegVNode::degenerate_integral_negate(PhaseGVN* phase, bool is_predicated) const_zero = phase->intcon(0); sub_opc = Op_SubI; } - const_zero = phase->transform(VectorNode::scalar2vector(const_zero, vlen, Type::get_const_basic_type(bt))); + const_zero = phase->transform(VectorNode::scalar2vector(const_zero, vlen, bt)); return VectorNode::make(VectorNode::opcode(sub_opc, bt), const_zero, in(1), vt); } @@ -2069,8 +2065,7 @@ Node* XorVNode::Ideal(PhaseGVN* phase, bool can_reshape) { if (!is_predicated_vector() && (in(1) == in(2))) { BasicType bt = vect_type()->element_basic_type(); Node* zero = phase->transform(phase->zerocon(bt)); - return VectorNode::scalar2vector(zero, length(), Type::get_const_basic_type(bt), - bottom_type()->isa_vectmask() != nullptr); + return VectorNode::scalar2vector(zero, length(), bt, bottom_type()->isa_vectmask() != nullptr); } return nullptr; } diff --git a/src/hotspot/share/opto/vectornode.hpp b/src/hotspot/share/opto/vectornode.hpp index 23ddebaf33889..d23e6b8c9268d 100644 --- a/src/hotspot/share/opto/vectornode.hpp +++ b/src/hotspot/share/opto/vectornode.hpp @@ -75,7 +75,7 @@ class VectorNode : public TypeNode { virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); - static VectorNode* scalar2vector(Node* s, uint vlen, const Type* opd_t, bool is_mask = false); + static VectorNode* scalar2vector(Node* s, uint vlen, BasicType bt, bool is_mask = false); static VectorNode* shift_count(int opc, Node* cnt, uint vlen, BasicType bt); static VectorNode* make(int opc, Node* n1, Node* n2, uint vlen, BasicType bt, bool is_var_shift = false); static VectorNode* make(int vopc, Node* n1, Node* n2, const TypeVect* vt, bool is_mask = false, bool is_var_shift = false); diff --git a/src/hotspot/share/opto/vtransform.cpp b/src/hotspot/share/opto/vtransform.cpp index e40157caa362b..7c7aca3b90e7c 100644 --- a/src/hotspot/share/opto/vtransform.cpp +++ b/src/hotspot/share/opto/vtransform.cpp @@ -422,8 +422,7 @@ void VTransformScalarNode::print_spec() const { } void VTransformReplicateNode::print_spec() const { - tty->print("vlen=%d element_type=", _vlen); - _element_type->dump(); + tty->print("vlen=%d element_type=%s", _vlen, type2name(_element_type)); } void VTransformShiftCountNode::print_spec() const { diff --git a/src/hotspot/share/opto/vtransform.hpp b/src/hotspot/share/opto/vtransform.hpp index 071674533a798..ee298e7fe723f 100644 --- a/src/hotspot/share/opto/vtransform.hpp +++ b/src/hotspot/share/opto/vtransform.hpp @@ -354,9 +354,9 @@ class VTransformInputScalarNode : public VTransformScalarNode { class VTransformReplicateNode : public VTransformNode { private: int _vlen; - const Type* _element_type; + BasicType _element_type; public: - VTransformReplicateNode(VTransform& vtransform, int vlen, const Type* element_type) : + VTransformReplicateNode(VTransform& vtransform, int vlen, BasicType element_type) : VTransformNode(vtransform, 2), _vlen(vlen), _element_type(element_type) {} virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, const GrowableArray& vnode_idx_to_transformed_node) const override; diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index a7c61f710505a..8c4b3c93343f6 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -119,13 +119,13 @@ public class IRNode { public static final String VECTOR_SIZE_32 = VECTOR_SIZE + "32"; public static final String VECTOR_SIZE_64 = VECTOR_SIZE + "64"; - private static final String TYPE_BYTE = "byte"; - private static final String TYPE_CHAR = "char"; - private static final String TYPE_SHORT = "short"; - private static final String TYPE_INT = "int"; - private static final String TYPE_LONG = "long"; - private static final String TYPE_FLOAT = "float"; - private static final String TYPE_DOUBLE = "double"; + private static final String TYPE_BYTE = "B"; + private static final String TYPE_CHAR = "C"; + private static final String TYPE_SHORT = "S"; + private static final String TYPE_INT = "I"; + private static final String TYPE_LONG = "J"; + private static final String TYPE_FLOAT = "F"; + private static final String TYPE_DOUBLE = "D"; /** * IR placeholder string to regex-for-compile-phase map. diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/checkattribute/parsing/RawIRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/checkattribute/parsing/RawIRNode.java index e7db6c4844ca2..bf3021a6868f1 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/checkattribute/parsing/RawIRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/checkattribute/parsing/RawIRNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ private String regexForVectorIRNode(String nodeRegex, VMInfo vmInfo, Comparison. } } String sizeRegex = IRNode.parseVectorNodeSize(size, type, vmInfo); - return nodeRegex.replaceAll(IRNode.IS_REPLACED, - "vector[A-Za-z]\\\\[" + sizeRegex + "\\\\]:\\\\{" + type + "\\\\}"); + return nodeRegex.replaceAll(IRNode.IS_REPLACED, "vector[A-Za-z]<" + type + "," + sizeRegex + ">"); } } From 1f6bd0c3e509029bbf524b0ba34ce44601ac0b6a Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Fri, 11 Oct 2024 20:03:14 +0000 Subject: [PATCH 035/118] 8341972: java/awt/dnd/DnDRemoveFocusOwnerCrashTest.java timed out after JDK-8341257 Reviewed-by: azvegint --- test/jdk/ProblemList.txt | 1 + .../awt/dnd/DnDRemoveFocusOwnerCrashTest.java | 49 +++++++++---------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index db0794f8f2dab..034830a2575a5 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -201,6 +201,7 @@ java/awt/event/KeyEvent/ExtendedKeyCode/ExtendedKeyCodeTest.java 8169476 windows java/awt/event/KeyEvent/KeyChar/KeyCharTest.java 8169474,8224055 macosx-all,windows-all java/awt/event/KeyEvent/KeyTyped/CtrlASCII.java 8298910 linux-all +java/awt/dnd/DnDRemoveFocusOwnerCrashTest.java 8242805 macosx-all java/awt/dnd/DnDCursorCrashTest.java 8242805 macosx-all java/awt/dnd/DnDClipboardDeadlockTest.java 8079553 linux-all java/awt/dnd/URIListToFileListBetweenJVMsTest/URIListToFileListBetweenJVMsTest.java 8194947 generic-all diff --git a/test/jdk/java/awt/dnd/DnDRemoveFocusOwnerCrashTest.java b/test/jdk/java/awt/dnd/DnDRemoveFocusOwnerCrashTest.java index 27cf54e184558..1fc7c2e82b89c 100644 --- a/test/jdk/java/awt/dnd/DnDRemoveFocusOwnerCrashTest.java +++ b/test/jdk/java/awt/dnd/DnDRemoveFocusOwnerCrashTest.java @@ -64,10 +64,13 @@ public class DnDRemoveFocusOwnerCrashTest { public static Frame frame; public static Robot robot; public static DragSourceButton dragSourceButton; + static volatile Point p; public static void main(String[] args) throws Exception { try { robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.delay(FRAME_ACTIVATION_TIMEOUT); EventQueue.invokeAndWait(() -> { frame = new Frame(); dragSourceButton = new DragSourceButton(); @@ -79,37 +82,33 @@ public static void main(String[] args) throws Exception { frame.add(dropTargetPanel); frame.pack(); frame.setVisible(true); + }); - try { - robot.delay(FRAME_ACTIVATION_TIMEOUT); - } catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException("The test failed."); - } + robot.waitForIdle(); + robot.delay(FRAME_ACTIVATION_TIMEOUT); - Point p = dragSourceButton.getLocationOnScreen(); + EventQueue.invokeAndWait(() -> { + p = dragSourceButton.getLocationOnScreen(); p.translate(10, 10); + }); - try { - Robot robot = new Robot(); - robot.mouseMove(p.x, p.y); - robot.keyPress(KeyEvent.VK_CONTROL); - robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); - for (int dy = 0; dy < 50; dy++) { - robot.mouseMove(p.x, p.y + dy); - robot.delay(10); - } - robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); - robot.keyRelease(KeyEvent.VK_CONTROL); - } catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException("The test failed."); + robot.delay(FRAME_ACTIVATION_TIMEOUT); + robot.mouseMove(p.x, p.y); + robot.delay(FRAME_ACTIVATION_TIMEOUT); + robot.keyPress(KeyEvent.VK_CONTROL); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + for (int dy = 0; dy < 50; dy++) { + robot.mouseMove(p.x, p.y + dy); + robot.delay(10); + } + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.keyRelease(KeyEvent.VK_CONTROL); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); } }); - } finally { - if (frame != null) { - EventQueue.invokeAndWait(() -> frame.dispose()); - } } } From 0a57fe1df6f3431cfb2d5d868597c61ef6af3806 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Fri, 11 Oct 2024 21:11:12 +0000 Subject: [PATCH 036/118] 8341178: TypeRawPtr::add_offset may be "miscompiled" due to UB Reviewed-by: dlong, kvn --- src/hotspot/share/opto/type.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index 828cea88d8339..70cd46c900dc2 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -3111,8 +3111,8 @@ const TypeRawPtr *TypeRawPtr::make( enum PTR ptr ) { return (TypeRawPtr*)(new TypeRawPtr(ptr,nullptr))->hashcons(); } -const TypeRawPtr *TypeRawPtr::make( address bits ) { - assert( bits, "Use TypePtr for null" ); +const TypeRawPtr *TypeRawPtr::make(address bits) { + assert(bits != nullptr, "Use TypePtr for null"); return (TypeRawPtr*)(new TypeRawPtr(Constant,bits))->hashcons(); } @@ -3201,15 +3201,21 @@ const TypePtr* TypeRawPtr::add_offset(intptr_t offset) const { case TypePtr::BotPTR: case TypePtr::NotNull: return this; - case TypePtr::Null: case TypePtr::Constant: { - address bits = _bits+offset; - if ( bits == 0 ) return TypePtr::NULL_PTR; - return make( bits ); + uintptr_t bits = (uintptr_t)_bits; + uintptr_t sum = bits + offset; + if (( offset < 0 ) + ? ( sum > bits ) // Underflow? + : ( sum < bits )) { // Overflow? + return BOTTOM; + } else if ( sum == 0 ) { + return TypePtr::NULL_PTR; + } else { + return make( (address)sum ); + } } default: ShouldNotReachHere(); } - return nullptr; // Lint noise } //------------------------------eq--------------------------------------------- From 3f53d571343792341481f4d15970cdc0bcd76a5e Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Fri, 11 Oct 2024 21:16:41 +0000 Subject: [PATCH 037/118] 8340327: A common framework to support public key algorithms with standard parameter sets Reviewed-by: ascarpino, mullan --- .../sun/security/pkcs/NamedPKCS8Key.java | 143 +++++++++ .../sun/security/provider/NamedKEM.java | 223 ++++++++++++++ .../security/provider/NamedKeyFactory.java | 288 ++++++++++++++++++ .../provider/NamedKeyPairGenerator.java | 177 +++++++++++ .../sun/security/provider/NamedSignature.java | 222 ++++++++++++++ .../classes/sun/security/util/KeyUtil.java | 8 +- .../sun/security/util/SignatureUtil.java | 21 +- .../sun/security/x509/NamedX509Key.java | 120 ++++++++ .../jdk/sun/security/provider/NamedEdDSA.java | 239 +++++++++++++++ .../provider/NamedKeyFactoryTest.java | 261 ++++++++++++++++ 10 files changed, 1693 insertions(+), 9 deletions(-) create mode 100644 src/java.base/share/classes/sun/security/pkcs/NamedPKCS8Key.java create mode 100644 src/java.base/share/classes/sun/security/provider/NamedKEM.java create mode 100644 src/java.base/share/classes/sun/security/provider/NamedKeyFactory.java create mode 100644 src/java.base/share/classes/sun/security/provider/NamedKeyPairGenerator.java create mode 100644 src/java.base/share/classes/sun/security/provider/NamedSignature.java create mode 100644 src/java.base/share/classes/sun/security/x509/NamedX509Key.java create mode 100644 test/jdk/sun/security/provider/NamedEdDSA.java create mode 100644 test/jdk/sun/security/provider/NamedKeyFactoryTest.java diff --git a/src/java.base/share/classes/sun/security/pkcs/NamedPKCS8Key.java b/src/java.base/share/classes/sun/security/pkcs/NamedPKCS8Key.java new file mode 100644 index 0000000000000..88a2909cfac1c --- /dev/null +++ b/src/java.base/share/classes/sun/security/pkcs/NamedPKCS8Key.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 sun.security.pkcs; + +import sun.security.util.DerInputStream; +import sun.security.util.DerValue; +import sun.security.x509.AlgorithmId; + +import javax.security.auth.DestroyFailedException; +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; +import java.io.Serial; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.ProviderException; +import java.security.spec.NamedParameterSpec; +import java.util.Arrays; + +/// Represents a private key from an algorithm family that is specialized +/// with a named parameter set. +/// +/// This key is generated by either a [sun.security.provider.NamedKeyPairGenerator] +/// or [sun.security.provider.NamedKeyFactory]. Its [#getAlgorithm] method +/// returns the algorithm family name, while its [#getParams()] method returns +/// the parameter set name as a [NamedParameterSpec] object. The algorithm +/// identifier in the PKCS #8 encoding of the key is always a single OID derived +/// from the parameter set name. +/// +/// @see sun.security.provider.NamedKeyPairGenerator +public final class NamedPKCS8Key extends PKCS8Key { + @Serial + private static final long serialVersionUID = 1L; + + private final String fname; + private final transient NamedParameterSpec paramSpec; + private final byte[] rawBytes; + + private transient boolean destroyed = false; + + /// Ctor from family name, parameter set name, raw key bytes. + /// Key bytes won't be cloned, caller must relinquish ownership + public NamedPKCS8Key(String fname, String pname, byte[] rawBytes) { + this.fname = fname; + this.paramSpec = new NamedParameterSpec(pname); + try { + this.algid = AlgorithmId.get(pname); + } catch (NoSuchAlgorithmException e) { + throw new ProviderException(e); + } + this.rawBytes = rawBytes; + + DerValue val = new DerValue(DerValue.tag_OctetString, rawBytes); + try { + this.key = val.toByteArray(); + } finally { + val.clear(); + } + } + + /// Ctor from family name, and PKCS #8 bytes + public NamedPKCS8Key(String fname, byte[] encoded) throws InvalidKeyException { + super(encoded); + this.fname = fname; + try { + paramSpec = new NamedParameterSpec(algid.getName()); + if (algid.getEncodedParams() != null) { + throw new InvalidKeyException("algorithm identifier has params"); + } + rawBytes = new DerInputStream(key).getOctetString(); + } catch (IOException e) { + throw new InvalidKeyException("Cannot parse input", e); + } + } + + @Override + public String toString() { + // Do not modify: this can be used by earlier JDKs that + // do not have the getParams() method + return paramSpec.getName() + " private key"; + } + + /// Returns the reference to the internal key. Caller must not modify + /// the content or keep a reference. + public byte[] getRawBytes() { + return rawBytes; + } + + @Override + public NamedParameterSpec getParams() { + return paramSpec; + } + + @Override + public String getAlgorithm() { + return fname; + } + + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + throw new InvalidObjectException( + "NamedPKCS8Key keys are not directly deserializable"); + } + + @Override + public void destroy() throws DestroyFailedException { + Arrays.fill(rawBytes, (byte)0); + Arrays.fill(key, (byte)0); + if (encodedKey != null) { + Arrays.fill(encodedKey, (byte)0); + } + destroyed = true; + } + + @Override + public boolean isDestroyed() { + return destroyed; + } +} diff --git a/src/java.base/share/classes/sun/security/provider/NamedKEM.java b/src/java.base/share/classes/sun/security/provider/NamedKEM.java new file mode 100644 index 0000000000000..2731b3460af3b --- /dev/null +++ b/src/java.base/share/classes/sun/security/provider/NamedKEM.java @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 sun.security.provider; + +import sun.security.pkcs.NamedPKCS8Key; +import sun.security.x509.NamedX509Key; + +import javax.crypto.DecapsulateException; +import javax.crypto.KEM; +import javax.crypto.KEMSpi; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.PrivateKey; +import java.security.ProviderException; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.NamedParameterSpec; +import java.util.Arrays; +import java.util.Objects; + +/// A base class for all `KEM` implementations that can be +/// configured with a named parameter set. See [NamedKeyPairGenerator] +/// for more details. +public abstract class NamedKEM implements KEMSpi { + + private final String fname; // family name + private final String[] pnames; // allowed parameter set name (at least one) + + /// Creates a new `NamedKEM` object. + /// + /// @param fname the family name + /// @param pnames the standard parameter set names, at least one is needed. + protected NamedKEM(String fname, String... pnames) { + if (fname == null) { + throw new AssertionError("fname cannot be null"); + } + if (pnames == null || pnames.length == 0) { + throw new AssertionError("pnames cannot be null or empty"); + } + this.fname = fname; + this.pnames = pnames; + } + + @Override + public EncapsulatorSpi engineNewEncapsulator(PublicKey publicKey, + AlgorithmParameterSpec spec, SecureRandom secureRandom) + throws InvalidAlgorithmParameterException, InvalidKeyException { + if (spec != null) { + throw new InvalidAlgorithmParameterException( + "The " + fname + " algorithm does not take any parameters"); + } + // translate also check the key + var nk = (NamedX509Key) new NamedKeyFactory(fname, pnames) + .engineTranslateKey(publicKey); + var pk = nk.getRawBytes(); + return getKeyConsumerImpl(this, nk.getParams(), pk, + implCheckPublicKey(nk.getParams().getName(), pk), secureRandom); + } + + @Override + public DecapsulatorSpi engineNewDecapsulator( + PrivateKey privateKey, AlgorithmParameterSpec spec) + throws InvalidAlgorithmParameterException, InvalidKeyException { + if (spec != null) { + throw new InvalidAlgorithmParameterException( + "The " + fname + " algorithm does not take any parameters"); + } + // translate also check the key + var nk = (NamedPKCS8Key) new NamedKeyFactory(fname, pnames) + .engineTranslateKey(privateKey); + var sk = nk.getRawBytes(); + return getKeyConsumerImpl(this, nk.getParams(), sk, + implCheckPrivateKey(nk.getParams().getName(), sk), null); + } + + // We don't have a flag on whether key is public key or private key. + // The correct method should always be called. + private record KeyConsumerImpl(NamedKEM kem, String name, int sslen, + int clen, byte[] key, Object k2, SecureRandom sr) + implements KEMSpi.EncapsulatorSpi, KEMSpi.DecapsulatorSpi { + @Override + public SecretKey engineDecapsulate(byte[] encapsulation, int from, int to, + String algorithm) throws DecapsulateException { + if (encapsulation.length != clen) { + throw new DecapsulateException("Invalid key encapsulation message length"); + } + var ss = kem.implDecapsulate(name, key, k2, encapsulation); + try { + return new SecretKeySpec(ss, + from, to - from, algorithm); + } finally { + Arrays.fill(ss, (byte)0); + } + } + + @Override + public KEM.Encapsulated engineEncapsulate(int from, int to, String algorithm) { + var enc = kem.implEncapsulate(name, key, k2, sr); + try { + return new KEM.Encapsulated( + new SecretKeySpec(enc[1], + from, to - from, algorithm), + enc[0], + null); + } finally { + Arrays.fill(enc[1], (byte)0); + } + } + + @Override + public int engineSecretSize() { + return sslen; + } + + @Override + public int engineEncapsulationSize() { + return clen; + } + } + + private static KeyConsumerImpl getKeyConsumerImpl(NamedKEM kem, + NamedParameterSpec nps, byte[] key, Object k2, SecureRandom sr) { + String name = nps.getName(); + return new KeyConsumerImpl(kem, name, kem.implSecretSize(name), kem.implEncapsulationSize(name), + key, k2, sr); + } + + /// User-defined encap function. + /// + /// @param name parameter name + /// @param pk public key in raw bytes + /// @param pk2 parsed public key, `null` if none. See [#implCheckPublicKey]. + /// @param sr SecureRandom object, `null` if not initialized + /// @return the key encapsulation message and the shared key (in this order) + /// @throws ProviderException if there is an internal error + protected abstract byte[][] implEncapsulate(String name, byte[] pk, Object pk2, SecureRandom sr); + + /// User-defined decap function. + /// + /// @param name parameter name + /// @param sk private key in raw bytes + /// @param sk2 parsed private key, `null` if none. See [#implCheckPrivateKey]. + /// @param encap the key encapsulation message + /// @return the shared key + /// @throws ProviderException if there is an internal error + /// @throws DecapsulateException if there is another error + protected abstract byte[] implDecapsulate(String name, byte[] sk, Object sk2, byte[] encap) + throws DecapsulateException; + + /// User-defined function returning shared secret key length. + /// + /// @param name parameter name + /// @return shared secret key length + /// @throws ProviderException if there is an internal error + protected abstract int implSecretSize(String name); + + /// User-defined function returning key encapsulation message length. + /// + /// @param name parameter name + /// @return key encapsulation message length + /// @throws ProviderException if there is an internal error + protected abstract int implEncapsulationSize(String name); + + /// User-defined function to validate a public key. + /// + /// This method will be called in `newEncapsulator`. This gives the provider a chance to + /// reject the key so an `InvalidKeyException` can be thrown earlier. + /// An implementation can optionally return a "parsed key" as an `Object` value. + /// This object will be passed into the [#implEncapsulate] method along with the raw key. + /// + /// The default implementation returns `null`. + /// + /// @param name parameter name + /// @param pk public key in raw bytes + /// @return a parsed key, `null` if none. + /// @throws InvalidKeyException if the key is invalid + protected Object implCheckPublicKey(String name, byte[] pk) throws InvalidKeyException { + return null; + } + + /// User-defined function to validate a private key. + /// + /// This method will be called in `newDecapsulator`. This gives the provider a chance to + /// reject the key so an `InvalidKeyException` can be thrown earlier. + /// An implementation can optionally return a "parsed key" as an `Object` value. + /// This object will be passed into the [#implDecapsulate] method along with the raw key. + /// + /// The default implementation returns `null`. + /// + /// @param name parameter name + /// @param sk private key in raw bytes + /// @return a parsed key, `null` if none. + /// @throws InvalidKeyException if the key is invalid + protected Object implCheckPrivateKey(String name, byte[] sk) throws InvalidKeyException { + return null; + } +} diff --git a/src/java.base/share/classes/sun/security/provider/NamedKeyFactory.java b/src/java.base/share/classes/sun/security/provider/NamedKeyFactory.java new file mode 100644 index 0000000000000..727358dd07491 --- /dev/null +++ b/src/java.base/share/classes/sun/security/provider/NamedKeyFactory.java @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 sun.security.provider; + +import sun.security.pkcs.NamedPKCS8Key; +import sun.security.util.RawKeySpec; +import sun.security.x509.NamedX509Key; + +import java.security.AsymmetricKey; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactorySpi; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.EncodedKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.NamedParameterSpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Arrays; +import java.util.Objects; + +/// A base class for all `KeyFactory` implementations that can be +/// configured with a named parameter set. See [NamedKeyPairGenerator] +/// for more details. +/// +/// This factory supports reading and writing to RAW formats: +/// +/// 1. It reads from a RAW key using `translateKey` if `key.getFormat` is "RAW". +/// 2. It writes to a RAW [EncodedKeySpec] if `getKeySpec(key, EncodedKeySpec.class)` +/// is called. The format of the output is "RAW" and the algorithm is +/// intentionally left unspecified. +/// 3. It reads from and writes to the internal type [RawKeySpec]. +/// +/// When reading from a RAW format, it needs enough info to derive the +/// parameter set name. +public class NamedKeyFactory extends KeyFactorySpi { + + private final String fname; // family name + private final String[] pnames; // allowed parameter set name (at least one) + + /// Creates a new `NamedKeyFactory` object. + /// + /// @param fname the family name + /// @param pnames the standard parameter set names, at least one is needed. + protected NamedKeyFactory(String fname, String... pnames) { + if (fname == null) { + throw new AssertionError("fname cannot be null"); + } + if (pnames == null || pnames.length == 0) { + throw new AssertionError("pnames cannot be null or empty"); + } + this.fname = fname; + this.pnames = pnames; + } + + private String checkName(String name) throws InvalidKeyException { + for (var pname : pnames) { + if (pname.equalsIgnoreCase(name)) { + // return the stored standard name + return pname; + } + } + throw new InvalidKeyException("Unsupported parameter set name: " + name); + } + + @Override + protected PublicKey engineGeneratePublic(KeySpec keySpec) + throws InvalidKeySpecException { + if (keySpec instanceof X509EncodedKeySpec xspec) { + try { + return fromX509(xspec.getEncoded()); + } catch (InvalidKeyException e) { + throw new InvalidKeySpecException(e); + } + } else if (keySpec instanceof RawKeySpec rks) { + if (pnames.length == 1) { + return new NamedX509Key(fname, pnames[0], rks.getKeyArr()); + } else { + throw new InvalidKeySpecException("Parameter set name unavailable"); + } + } else if (keySpec instanceof EncodedKeySpec espec + && espec.getFormat().equalsIgnoreCase("RAW")) { + if (pnames.length == 1) { + return new NamedX509Key(fname, pnames[0], espec.getEncoded()); + } else { + throw new InvalidKeySpecException("Parameter set name unavailable"); + } + } else { + throw new InvalidKeySpecException("Unsupported keyspec: " + keySpec); + } + } + + @Override + protected PrivateKey engineGeneratePrivate(KeySpec keySpec) + throws InvalidKeySpecException { + if (keySpec instanceof PKCS8EncodedKeySpec pspec) { + var bytes = pspec.getEncoded(); + try { + return fromPKCS8(bytes); + } catch (InvalidKeyException e) { + throw new InvalidKeySpecException(e); + } finally { + Arrays.fill(bytes, (byte) 0); + } + } else if (keySpec instanceof RawKeySpec rks) { + if (pnames.length == 1) { + var bytes = rks.getKeyArr(); + try { + return new NamedPKCS8Key(fname, pnames[0], bytes); + } finally { + Arrays.fill(bytes, (byte) 0); + } + } else { + throw new InvalidKeySpecException("Parameter set name unavailable"); + } + } else if (keySpec instanceof EncodedKeySpec espec + && espec.getFormat().equalsIgnoreCase("RAW")) { + if (pnames.length == 1) { + var bytes = espec.getEncoded(); + try { + return new NamedPKCS8Key(fname, pnames[0], bytes); + } finally { + Arrays.fill(bytes, (byte) 0); + } + } else { + throw new InvalidKeySpecException("Parameter set name unavailable"); + } + } else { + throw new InvalidKeySpecException("Unsupported keyspec: " + keySpec); + } + } + + private PrivateKey fromPKCS8(byte[] bytes) + throws InvalidKeyException, InvalidKeySpecException { + var k = new NamedPKCS8Key(fname, bytes); + checkName(k.getParams().getName()); + return k; + } + + private PublicKey fromX509(byte[] bytes) + throws InvalidKeyException, InvalidKeySpecException { + var k = new NamedX509Key(fname, bytes); + checkName(k.getParams().getName()); + return k; + } + + private static class RawEncodedKeySpec extends EncodedKeySpec { + public RawEncodedKeySpec(byte[] encodedKey) { + super(encodedKey); + } + + @Override + public String getFormat() { + return "RAW"; + } + } + + @Override + protected T engineGetKeySpec(Key key, Class keySpec) + throws InvalidKeySpecException { + try { + key = engineTranslateKey(key); + } catch (InvalidKeyException e) { + throw new InvalidKeySpecException(e); + } + // key is now either NamedPKCS8Key or NamedX509Key of permitted param set + if (key instanceof NamedPKCS8Key nk) { + byte[] bytes = null; + try { + if (keySpec == PKCS8EncodedKeySpec.class) { + return keySpec.cast( + new PKCS8EncodedKeySpec(bytes = key.getEncoded())); + } else if (keySpec == RawKeySpec.class) { + return keySpec.cast(new RawKeySpec(nk.getRawBytes())); + } else if (keySpec.isAssignableFrom(EncodedKeySpec.class)) { + return keySpec.cast( + new RawEncodedKeySpec(nk.getRawBytes())); + } else { + throw new InvalidKeySpecException("Unsupported type: " + keySpec); + } + } finally { + if (bytes != null) { + Arrays.fill(bytes, (byte)0); + } + } + } else if (key instanceof NamedX509Key nk) { + if (keySpec == X509EncodedKeySpec.class + && key.getFormat().equalsIgnoreCase("X.509")) { + return keySpec.cast(new X509EncodedKeySpec(key.getEncoded())); + } else if (keySpec == RawKeySpec.class) { + return keySpec.cast(new RawKeySpec(nk.getRawBytes())); + } else if (keySpec.isAssignableFrom(EncodedKeySpec.class)) { + return keySpec.cast(new RawEncodedKeySpec(nk.getRawBytes())); + } else { + throw new InvalidKeySpecException("Unsupported type: " + keySpec); + } + } + throw new AssertionError("No " + keySpec.getName() + " for " + key.getClass()); + } + + @Override + protected Key engineTranslateKey(Key key) throws InvalidKeyException { + if (key == null) { + throw new InvalidKeyException("Key must not be null"); + } + if (key instanceof NamedX509Key nk) { + checkName(nk.getParams().getName()); + return key; + } + if (key instanceof NamedPKCS8Key nk) { + checkName(nk.getParams().getName()); + return key; + } + var format = key.getFormat(); + if (format == null) { + throw new InvalidKeyException("Unextractable key"); + } else if (format.equalsIgnoreCase("RAW")) { + var kAlg = key.getAlgorithm(); + if (key instanceof AsymmetricKey pk) { + String name; + // Three cases that we can find the parameter set name from a RAW key: + // 1. getParams() returns one + // 2. getAlgorithm() returns param set name (some provider does this) + // 3. getAlgorithm() returns family name but this KF is for param set name + if (pk.getParams() instanceof NamedParameterSpec nps) { + name = checkName(nps.getName()); + } else { + if (kAlg.equalsIgnoreCase(fname)) { + if (pnames.length == 1) { + name = pnames[0]; + } else { + throw new InvalidKeyException("No parameter set info"); + } + } else { + name = checkName(kAlg); + } + } + return key instanceof PrivateKey + ? new NamedPKCS8Key(fname, name, key.getEncoded()) + : new NamedX509Key(fname, name, key.getEncoded()); + } else { + throw new InvalidKeyException("Unsupported key type: " + key.getClass()); + } + } else if (format.equalsIgnoreCase("PKCS#8") && key instanceof PrivateKey) { + var bytes = key.getEncoded(); + try { + return fromPKCS8(bytes); + } catch (InvalidKeySpecException e) { + throw new InvalidKeyException("Invalid PKCS#8 key", e); + } finally { + Arrays.fill(bytes, (byte) 0); + } + } else if (format.equalsIgnoreCase("X.509") && key instanceof PublicKey) { + try { + return fromX509(key.getEncoded()); + } catch (InvalidKeySpecException e) { + throw new InvalidKeyException("Invalid X.509 key", e); + } + } else { + throw new InvalidKeyException("Unsupported key format: " + key.getFormat()); + } + } +} diff --git a/src/java.base/share/classes/sun/security/provider/NamedKeyPairGenerator.java b/src/java.base/share/classes/sun/security/provider/NamedKeyPairGenerator.java new file mode 100644 index 0000000000000..5be2b2b2a08b0 --- /dev/null +++ b/src/java.base/share/classes/sun/security/provider/NamedKeyPairGenerator.java @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 sun.security.provider; + +import sun.security.pkcs.NamedPKCS8Key; +import sun.security.x509.NamedX509Key; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidParameterException; +import java.security.KeyPair; +import java.security.KeyPairGeneratorSpi; +import java.security.ProviderException; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.NamedParameterSpec; +import java.util.Objects; + +/// A base class for all `KeyPairGenerator` implementations that can be +/// configured with a named parameter set. +/// +/// Together with [NamedKeyFactory], [NamedKEM], and [NamedSignature], these +/// classes form a compact framework designed to support any public key +/// algorithm standardized with named parameter sets. In this scenario, +/// the algorithm name is the "family name" and each standardized parameter +/// set has a "parameter set name". Implementations of these classes are able +/// to instantiate a `KeyPairGenerator`, `KeyFactory`, or `KEM` or `Signature` +/// object using either the family name or a parameter set name. All keys used +/// in this context will be of the type [NamedPKCS8Key] or [NamedX509Key], +/// with `getAlgorithm` returning the family name, and `getParams` returning +/// the parameter set name as a [NamedParameterSpec] object. +/// +/// An implementation must include a zero-argument public constructor that +/// calls `super(fname, pnames)`, where `fname` is the family name of the +/// algorithm and `pnames` are its supported parameter set names. `pnames` +/// must contain at least one element. For an implementation of +/// `NamedKeyPairGenerator`, the first element becomes its default parameter +/// set, i.e. the parameter set to be used in key pair generation unless +/// [#initialize(AlgorithmParameterSpec, java.security.SecureRandom)] +/// is called on a different parameter set. +/// +/// An implementation must implement all abstract methods. For all these +/// methods, the implementation must relinquish any "ownership" of any input +/// and output array argument. Precisely, the implementation must not retain +/// any reference to a returning array so that it won't be able to modify its +/// content later. Similarly, the implementation must not modify any input +/// array argument and must not retain any reference to an input array argument +/// after the call. +/// +/// Also, an implementation must not keep any extra copy of a private key. +/// For key generation, the only copy is the one returned in the +/// [#implGenerateKeyPair] call. For all other methods, it must not make +/// a copy of the input private key. A `KEM` implementation also must not +/// keep a copy of the shared secret key, no matter if it's an encapsulator +/// or a decapsulator. Only the code that owns these sensitive data can +/// choose to perform cleanup when it determines they are no longer needed. +/// +/// The `NamedSignature` and `NamedKEM` classes provide `implCheckPublicKey` +/// and `implCheckPrivateKey` methods that allow an implementation to validate +/// a key before using it. An implementation may return a parsed key in +/// a local type, and this parsed key will be passed to an operational method +/// (For example, `implSign`) later. An implementation must not retain +/// a reference of the parsed key. +/// +/// When constructing a [NamedX509Key] or [NamedPKCS8Key] object from raw key +/// bytes, the key bytes are directly referenced within the object, so the +/// caller must not modify them afterward. Similarly, the key's `getRawBytes` +/// method returns direct references to the underlying raw key bytes, meaning +/// the caller must not alter the contents of the returned value. +/// +/// Together, these measures ensure the classes are as efficient as possible, +/// preventing unnecessary array cloning and potential data leaks. While these +/// classes should not be considered immutable, strictly adhering to the rules +/// above will ensure data integrity is maintained. +/// +/// Note: A limitation of `NamedKeyPairGenerator` and `NamedKeyFactory` is +/// that the keys generated by their implementations will always be of type +/// `NamedX509Key` or `NamedPKCS8Key`. Existing implementations of algorithms +/// like EdDSA and XDH have been generating keys implementing `EdECKey` or +/// `XECKey` interfaces, and they are not rewritten with this framework. +/// `NamedParameterSpec` fields not implemented with this framework include +/// Ed25519, Ed448, X25519, and X448. +public abstract class NamedKeyPairGenerator extends KeyPairGeneratorSpi { + + private final String fname; // family name + private final String[] pnames; // allowed parameter set name (at least one) + + protected String name; // init as + private SecureRandom secureRandom; + + /// Creates a new `NamedKeyPairGenerator` object. + /// + /// @param fname the family name + /// @param pnames supported parameter set names, at least one is needed. + /// If multiple, the first one becomes the default parameter set name. + protected NamedKeyPairGenerator(String fname, String... pnames) { + if (fname == null) { + throw new AssertionError("fname cannot be null"); + } + if (pnames == null || pnames.length == 0) { + throw new AssertionError("pnames cannot be null or empty"); + } + this.fname = fname; + this.pnames = pnames; + } + + private String checkName(String name) throws InvalidAlgorithmParameterException { + for (var pname : pnames) { + if (pname.equalsIgnoreCase(name)) { + // return the stored standard name + return pname; + } + } + throw new InvalidAlgorithmParameterException( + "Unsupported parameter set name: " + name); + } + + @Override + public void initialize(AlgorithmParameterSpec params, SecureRandom random) + throws InvalidAlgorithmParameterException { + if (params instanceof NamedParameterSpec spec) { + name = checkName(spec.getName()); + } else { + throw new InvalidAlgorithmParameterException( + "Unsupported AlgorithmParameterSpec: " + params); + } + this.secureRandom = random; + } + + @Override + public void initialize(int keysize, SecureRandom random) { + if (keysize != -1) { + // User can call initialize(-1, sr) to provide a SecureRandom + // without touching the parameter set currently used + throw new InvalidParameterException("keysize not supported"); + } + this.secureRandom = random; + } + + @Override + public KeyPair generateKeyPair() { + String pname = name != null ? name : pnames[0]; + var keys = implGenerateKeyPair(pname, secureRandom); + return new KeyPair(new NamedX509Key(fname, pname, keys[0]), + new NamedPKCS8Key(fname, pname, keys[1])); + } + + /// User-defined key pair generator. + /// + /// @param pname parameter set name + /// @param sr `SecureRandom` object, `null` if not initialized + /// @return public key and private key (in this order) in raw bytes + /// @throws ProviderException if there is an internal error + protected abstract byte[][] implGenerateKeyPair(String pname, SecureRandom sr); +} diff --git a/src/java.base/share/classes/sun/security/provider/NamedSignature.java b/src/java.base/share/classes/sun/security/provider/NamedSignature.java new file mode 100644 index 0000000000000..921a39cfc926d --- /dev/null +++ b/src/java.base/share/classes/sun/security/provider/NamedSignature.java @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 sun.security.provider; + +import sun.security.pkcs.NamedPKCS8Key; +import sun.security.x509.NamedX509Key; + +import java.io.ByteArrayOutputStream; +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.InvalidParameterException; +import java.security.PrivateKey; +import java.security.ProviderException; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.SignatureException; +import java.security.SignatureSpi; +import java.security.spec.AlgorithmParameterSpec; +import java.util.Objects; + +/// A base class for all `Signature` implementations that can be +/// configured with a named parameter set. See [NamedKeyPairGenerator] +/// for more details. +/// +/// This class does not work with preHash signatures. +public abstract class NamedSignature extends SignatureSpi { + + private final String fname; // family name + private final String[] pnames; // allowed parameter set name (at least one) + + private final ByteArrayOutputStream bout = new ByteArrayOutputStream(); + + // init with... + private String name; + private byte[] secKey; + private byte[] pubKey; + + private Object sk2; + private Object pk2; + + /// Creates a new `NamedSignature` object. + /// + /// @param fname the family name + /// @param pnames the standard parameter set names, at least one is needed. + protected NamedSignature(String fname, String... pnames) { + if (fname == null) { + throw new AssertionError("fname cannot be null"); + } + if (pnames == null || pnames.length == 0) { + throw new AssertionError("pnames cannot be null or empty"); + } + this.fname = fname; + this.pnames = pnames; + } + + @Override + protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { + // translate also check the key + var nk = (NamedX509Key) new NamedKeyFactory(fname, pnames) + .engineTranslateKey(publicKey); + name = nk.getParams().getName(); + pubKey = nk.getRawBytes(); + pk2 = implCheckPublicKey(name, pubKey); + secKey = null; + bout.reset(); + } + + @Override + protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException { + // translate also check the key + var nk = (NamedPKCS8Key) new NamedKeyFactory(fname, pnames) + .engineTranslateKey(privateKey); + name = nk.getParams().getName(); + secKey = nk.getRawBytes(); + sk2 = implCheckPrivateKey(name, secKey); + pubKey = null; + bout.reset(); + } + + @Override + protected void engineUpdate(byte b) throws SignatureException { + bout.write(b); + } + + @Override + protected void engineUpdate(byte[] b, int off, int len) throws SignatureException { + bout.write(b, off, len); + } + + @Override + protected byte[] engineSign() throws SignatureException { + if (secKey != null) { + var msg = bout.toByteArray(); + bout.reset(); + return implSign(name, secKey, sk2, msg, appRandom); + } else { + throw new SignatureException("No private key"); + } + } + + @Override + protected boolean engineVerify(byte[] sig) throws SignatureException { + if (pubKey != null) { + var msg = bout.toByteArray(); + bout.reset(); + return implVerify(name, pubKey, pk2, msg, sig); + } else { + throw new SignatureException("No public key"); + } + } + + @Override + @SuppressWarnings("deprecation") + protected void engineSetParameter(String param, Object value) + throws InvalidParameterException { + throw new InvalidParameterException("setParameter() not supported"); + } + + @Override + @SuppressWarnings("deprecation") + protected Object engineGetParameter(String param) throws InvalidParameterException { + throw new InvalidParameterException("getParameter() not supported"); + } + + @Override + protected void engineSetParameter(AlgorithmParameterSpec params) + throws InvalidAlgorithmParameterException { + if (params != null) { + throw new InvalidAlgorithmParameterException( + "The " + fname + " algorithm does not take any parameters"); + } + } + + @Override + protected AlgorithmParameters engineGetParameters() { + return null; + } + + /// User-defined sign function. + /// + /// @param name parameter name + /// @param sk private key in raw bytes + /// @param sk2 parsed private key, `null` if none. See [#implCheckPrivateKey]. + /// @param msg the message + /// @param sr SecureRandom object, `null` if not initialized + /// @return the signature + /// @throws ProviderException if there is an internal error + /// @throws SignatureException if there is another error + protected abstract byte[] implSign(String name, byte[] sk, Object sk2, + byte[] msg, SecureRandom sr) throws SignatureException; + + /// User-defined verify function. + /// + /// @param name parameter name + /// @param pk public key in raw bytes + /// @param pk2 parsed public key, `null` if none. See [#implCheckPublicKey]. + /// @param msg the message + /// @param sig the signature + /// @return true if verified + /// @throws ProviderException if there is an internal error + /// @throws SignatureException if there is another error + protected abstract boolean implVerify(String name, byte[] pk, Object pk2, + byte[] msg, byte[] sig) throws SignatureException; + + /// User-defined function to validate a public key. + /// + /// This method will be called in `initVerify`. This gives the provider a chance to + /// reject the key so an `InvalidKeyException` can be thrown earlier. + /// An implementation can optionally return a "parsed key" as an `Object` value. + /// This object will be passed into the [#implVerify] method along with the raw key. + /// + /// The default implementation returns `null`. + /// + /// @param name parameter name + /// @param pk public key in raw bytes + /// @return a parsed key, `null` if none. + /// @throws InvalidKeyException if the key is invalid + protected Object implCheckPublicKey(String name, byte[] pk) throws InvalidKeyException { + return null; + } + + /// User-defined function to validate a private key. + /// + /// This method will be called in `initSign`. This gives the provider a chance to + /// reject the key so an `InvalidKeyException` can be thrown earlier. + /// An implementation can optionally return a "parsed key" as an `Object` value. + /// This object will be passed into the [#implSign] method along with the raw key. + /// + /// The default implementation returns `null`. + /// + /// @param name parameter name + /// @param sk private key in raw bytes + /// @return a parsed key, `null` if none. + /// @throws InvalidKeyException if the key is invalid + protected Object implCheckPrivateKey(String name, byte[] sk) throws InvalidKeyException { + return null; + } +} 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 6884b9b201a39..d057bb689e99e 100644 --- a/src/java.base/share/classes/sun/security/util/KeyUtil.java +++ b/src/java.base/share/classes/sun/security/util/KeyUtil.java @@ -184,13 +184,13 @@ public static final int getKeySize(AlgorithmParameters parameters) { */ public static final String fullDisplayAlgName(Key key) { String result = key.getAlgorithm(); - if (key instanceof ECKey) { - ECParameterSpec paramSpec = ((ECKey) key).getParams(); + if (key instanceof AsymmetricKey ak) { + AlgorithmParameterSpec paramSpec = ak.getParams(); if (paramSpec instanceof NamedCurve nc) { result += " (" + nc.getNameAndAliases()[0] + ")"; + } else if (paramSpec instanceof NamedParameterSpec nps) { + result = nps.getName(); } - } else if (key instanceof EdECKey) { - result = ((EdECKey) key).getParams().getName(); } return result; } 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 155adc198d0e9..c1ffd248f2a60 100644 --- a/src/java.base/share/classes/sun/security/util/SignatureUtil.java +++ b/src/java.base/share/classes/sun/security/util/SignatureUtil.java @@ -33,6 +33,7 @@ import java.security.spec.*; import java.util.Locale; +import sun.security.pkcs.NamedPKCS8Key; import sun.security.rsa.RSAUtil; import jdk.internal.access.SharedSecrets; import sun.security.x509.AlgorithmId; @@ -274,7 +275,7 @@ public static String extractDigestAlgFromDwithE(String signatureAlgorithm) { return signatureAlgorithm.substring(0, with); } else { throw new IllegalArgumentException( - "Unknown algorithm: " + signatureAlgorithm); + "Cannot extract digest algorithm from " + signatureAlgorithm); } } @@ -390,8 +391,8 @@ private static Signature autoInitInternal(String alg, PrivateKey key, Signature public static AlgorithmId fromSignature(Signature sigEngine, PrivateKey key) throws SignatureException { try { - if (key instanceof EdECKey) { - return AlgorithmId.get(((EdECKey) key).getParams().getName()); + if (key.getParams() instanceof NamedParameterSpec nps) { + return AlgorithmId.get(nps.getName()); } AlgorithmParameters params = null; @@ -431,6 +432,14 @@ public static AlgorithmId fromSignature(Signature sigEngine, PrivateKey key) public static void checkKeyAndSigAlgMatch(PrivateKey key, String sAlg) { String kAlg = key.getAlgorithm().toUpperCase(Locale.ENGLISH); sAlg = checkName(sAlg); + if (key instanceof NamedPKCS8Key n8k) { + if (!sAlg.equalsIgnoreCase(n8k.getAlgorithm()) + && !sAlg.equalsIgnoreCase(n8k.getParams().getName())) { + throw new IllegalArgumentException( + "key algorithm not compatible with signature algorithm"); + } + return; + } switch (sAlg) { case "RSASSA-PSS" -> { if (!kAlg.equals("RSASSA-PSS") @@ -495,8 +504,10 @@ public static String getDefaultSigAlgForKey(PrivateKey k) { case "EDDSA" -> k instanceof EdECPrivateKey ? ((EdECPrivateKey) k).getParams().getName() : kAlg; - default -> kAlg; // All modern signature algorithms, - // RSASSA-PSS, ED25519, ED448, HSS/LMS, etc + default -> kAlg.contains("KEM") ? null : kAlg; + // All modern signature algorithms use the same name across + // key algorithms and signature algorithms, for example, + // RSASSA-PSS, ED25519, ED448, HSS/LMS, etc }; } diff --git a/src/java.base/share/classes/sun/security/x509/NamedX509Key.java b/src/java.base/share/classes/sun/security/x509/NamedX509Key.java new file mode 100644 index 0000000000000..dc36bd3b9b306 --- /dev/null +++ b/src/java.base/share/classes/sun/security/x509/NamedX509Key.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 sun.security.x509; + +import sun.security.util.BitArray; + +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; +import java.io.Serial; +import java.security.InvalidKeyException; +import java.security.KeyRep; +import java.security.NoSuchAlgorithmException; +import java.security.ProviderException; +import java.security.spec.NamedParameterSpec; + +/// Represents a public key from an algorithm family that is specialized +/// with a named parameter set. +/// +/// This key is generated by either a [sun.security.provider.NamedKeyPairGenerator] +/// or [sun.security.provider.NamedKeyFactory]. Its [#getAlgorithm] method +/// returns the algorithm family name, while its [#getParams()] method returns +/// the parameter set name as a [NamedParameterSpec] object. The algorithm +/// identifier in the X.509 encoding of the key is always a single OID derived +/// from the parameter set name. +/// +/// @see sun.security.provider.NamedKeyPairGenerator +public final class NamedX509Key extends X509Key { + @Serial + private static final long serialVersionUID = 1L; + + private final String fname; + private final transient NamedParameterSpec paramSpec; + private final byte[] rawBytes; + + /// Ctor from family name, parameter set name, raw key bytes. + /// Key bytes won't be cloned, caller must relinquish ownership + public NamedX509Key(String fname, String pname, byte[] rawBytes) { + this.fname = fname; + this.paramSpec = new NamedParameterSpec(pname); + try { + this.algid = AlgorithmId.get(pname); + } catch (NoSuchAlgorithmException e) { + throw new ProviderException(e); + } + this.rawBytes = rawBytes; + + setKey(new BitArray(rawBytes.length * 8, rawBytes)); + } + + /// Ctor from family name, and X.509 bytes + public NamedX509Key(String fname, byte[] encoded) throws InvalidKeyException { + this.fname = fname; + decode(encoded); + this.paramSpec = new NamedParameterSpec(algid.getName()); + if (algid.encodedParams != null) { + throw new InvalidKeyException("algorithm identifier has params"); + } + this.rawBytes = getKey().toByteArray(); + } + + @Override + public String toString() { + // Do not modify: this can be used by earlier JDKs that + // do not have the getParams() method + return paramSpec.getName() + " public key"; + } + + /// Returns the reference to the internal key. Caller must not modify + /// the content or keep a reference. + public byte[] getRawBytes() { + return rawBytes; + } + + @Override + public NamedParameterSpec getParams() { + return paramSpec; + } + + @Override + public String getAlgorithm() { + return fname; + } + + @java.io.Serial + private Object writeReplace() throws java.io.ObjectStreamException { + return new KeyRep(KeyRep.Type.PUBLIC, getAlgorithm(), getFormat(), + getEncoded()); + } + + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + throw new InvalidObjectException( + "NamedX509Key keys are not directly deserializable"); + } +} diff --git a/test/jdk/sun/security/provider/NamedEdDSA.java b/test/jdk/sun/security/provider/NamedEdDSA.java new file mode 100644 index 0000000000000..4d0e3e9228aac --- /dev/null +++ b/test/jdk/sun/security/provider/NamedEdDSA.java @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 8340327 + * @modules java.base/sun.security.ec.ed + * java.base/sun.security.ec.point + * java.base/sun.security.jca + * java.base/sun.security.provider + * @library /test/lib + */ + +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; +import sun.security.ec.ed.EdDSAOperations; +import sun.security.ec.ed.EdDSAParameters; +import sun.security.ec.point.AffinePoint; +import sun.security.jca.JCAUtil; +import sun.security.provider.NamedKeyFactory; +import sun.security.provider.NamedKeyPairGenerator; +import sun.security.provider.NamedSignature; + +import java.security.*; +import java.security.spec.EdDSAParameterSpec; +import java.security.spec.NamedParameterSpec; +import java.util.Arrays; +import java.util.List; + +public class NamedEdDSA { + + public static class ProviderImpl extends Provider { + public ProviderImpl() { + super("Named", "0", ""); + put("KeyPairGenerator.EdDSA", EdDSAKeyPairGenerator.class.getName()); + put("KeyPairGenerator.Ed25519", EdDSAKeyPairGenerator.Ed25519.class.getName()); + put("KeyPairGenerator.Ed448", EdDSAKeyPairGenerator.Ed448.class.getName()); + put("KeyFactory.EdDSA", EdDSAKeyFactory.class.getName()); + put("KeyFactory.Ed25519", EdDSAKeyFactory.Ed25519.class.getName()); + put("KeyFactory.Ed448", EdDSAKeyFactory.Ed448.class.getName()); + put("Signature.EdDSA", EdDSASignature.class.getName()); + put("Signature.Ed25519", EdDSASignature.Ed25519.class.getName()); + put("Signature.Ed448", EdDSASignature.Ed448.class.getName()); + } + } + + public static class EdDSASignature extends NamedSignature { + public EdDSASignature() { + super("EdDSA", "Ed25519", "Ed448"); + } + + protected EdDSASignature(String pname) { + super("EdDSA", pname); + } + + public static class Ed25519 extends EdDSASignature { + public Ed25519() { + super("Ed25519"); + } + } + + public static class Ed448 extends EdDSASignature { + public Ed448() { + super("Ed448"); + } + } + + @Override + public byte[] implSign(String name, byte[] sk, Object sk2, byte[] msg, SecureRandom sr) throws SignatureException { + return getOps(name).sign(plain, sk, msg); + } + + @Override + public boolean implVerify(String name, byte[] pk, Object pk2, byte[] msg, byte[] sig) throws SignatureException { + return getOps(name).verify(plain, (AffinePoint) pk2, pk, msg, sig); + } + + @Override + public Object implCheckPublicKey(String name, byte[] pk) throws InvalidKeyException { + return getOps(name).decodeAffinePoint(InvalidKeyException::new, pk); + } + } + + public static class EdDSAKeyFactory extends NamedKeyFactory { + public EdDSAKeyFactory() { + super("EdDSA", "Ed25519", "Ed448"); + } + + protected EdDSAKeyFactory(String pname) { + super("EdDSA", pname); + } + + public static class Ed25519 extends EdDSAKeyFactory { + public Ed25519() { + super("Ed25519"); + } + } + + public static class Ed448 extends EdDSAKeyFactory { + public Ed448() { + super("Ed448"); + } + } + } + + public static class EdDSAKeyPairGenerator extends NamedKeyPairGenerator { + public EdDSAKeyPairGenerator() { + super("EdDSA", "Ed25519", "Ed448"); + } + + protected EdDSAKeyPairGenerator(String pname) { + super("EdDSA", pname); + } + + public static class Ed25519 extends EdDSAKeyPairGenerator { + public Ed25519() { + super("Ed25519"); + } + } + + public static class Ed448 extends EdDSAKeyPairGenerator { + public Ed448() { + super("Ed448"); + } + } + + @Override + public byte[][] implGenerateKeyPair(String pname, SecureRandom sr) { + sr = sr == null ? JCAUtil.getDefSecureRandom() : sr; + var op = getOps(pname); + var sk = op.generatePrivate(sr); + var point = op.computePublic(sk); + byte[] encodedPoint = point.getY().toByteArray(); + reverse(encodedPoint); + // array may be too large or too small, depending on the value + encodedPoint = Arrays.copyOf(encodedPoint, op.getParameters().getKeyLength()); + // set the high-order bit of the encoded point + byte msb = (byte) (point.isXOdd() ? 0x80 : 0); + encodedPoint[encodedPoint.length - 1] |= msb; + return new byte[][] { encodedPoint, sk }; + } + + private static void swap(byte[] arr, int i, int j) { + byte tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; + } + + private static void reverse(byte [] arr) { + int i = 0; + int j = arr.length - 1; + + while (i < j) { + swap(arr, i, j); + i++; + j--; + } + } + } + + private static EdDSAOperations getOps(String pname) { + var op = switch (pname) { + case "Ed25519" -> e2; + case "Ed448" -> e4; + default -> throw new AssertionError("unknown pname " + pname); + }; + return op; + } + + static final EdDSAParameterSpec plain = new EdDSAParameterSpec(false); + static final EdDSAOperations e2, e4; + static { + try { + e2 = new EdDSAOperations(EdDSAParameters.getBySize(AssertionError::new, 255)); + e4 = new EdDSAOperations(EdDSAParameters.getBySize(AssertionError::new, 448)); + } catch (Exception e) { + throw new AssertionError(e); + } + } + + public static void main(String[] args) throws Exception { + var ps = List.of(new ProviderImpl(), Security.getProvider("SunEC")); + for (var p1 : ps) { + for (var p2 : ps) { + for (var p3 : ps) { + test(p1, p2, p3); + } + } + } + } + + static void test(Provider p1, Provider p2, Provider p3) throws Exception { + System.out.println(p1.getName() + " " + p2.getName() + " " + p3.getName()); + var g = KeyPairGenerator.getInstance("EdDSA", p1); + g.initialize(NamedParameterSpec.ED448); + var kp = g.generateKeyPair(); + var s1 = Signature.getInstance("EdDSA", p2); + var s2 = Signature.getInstance("EdDSA", p3); + var f1 = KeyFactory.getInstance("EdDSA", p2); + var f2 = KeyFactory.getInstance("EdDSA", p3); + var sk = (PrivateKey) f1.translateKey(kp.getPrivate()); + var pk = (PublicKey) f2.translateKey(kp.getPublic()); + // sign and verify twice to make sure the key is intact + s1.initSign(sk); + var sig1 = s1.sign(); + s1.initSign(sk); + var sig2 = s1.sign(); + // EdDSA signing is deterministic + Asserts.assertEqualsByteArray(sig1, sig2); + s2.initVerify(pk); + Asserts.assertTrue(s2.verify(sig1)); + s2.initVerify(pk); + Asserts.assertTrue(s2.verify(sig2)); + // No parameters defined + s1.setParameter(null); + Utils.runAndCheckException(() -> s1.setParameter(NamedParameterSpec.ED448), + InvalidAlgorithmParameterException.class); + } +} diff --git a/test/jdk/sun/security/provider/NamedKeyFactoryTest.java b/test/jdk/sun/security/provider/NamedKeyFactoryTest.java new file mode 100644 index 0000000000000..1ca179bc04690 --- /dev/null +++ b/test/jdk/sun/security/provider/NamedKeyFactoryTest.java @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 8340327 + * @modules java.base/sun.security.x509 + * java.base/sun.security.pkcs + * java.base/sun.security.provider + * java.base/sun.security.util + * @library /test/lib + */ +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; +import jdk.test.lib.security.SeededSecureRandom; +import sun.security.pkcs.NamedPKCS8Key; +import sun.security.provider.NamedKeyFactory; +import sun.security.provider.NamedKeyPairGenerator; +import sun.security.util.RawKeySpec; +import sun.security.x509.NamedX509Key; + +import java.security.*; +import java.security.spec.*; + +public class NamedKeyFactoryTest { + + private static final SeededSecureRandom RAND = SeededSecureRandom.one(); + + public static void main(String[] args) throws Exception { + Security.addProvider(new ProviderImpl()); + + var g = KeyPairGenerator.getInstance("sHA"); + var g2 = KeyPairGenerator.getInstance("ShA-256"); + var g5 = KeyPairGenerator.getInstance("SHa-512"); + var kf = KeyFactory.getInstance("ShA"); + var kf2 = KeyFactory.getInstance("Sha-256"); + var kf5 = KeyFactory.getInstance("Sha-512"); + + checkKeyPair(g.generateKeyPair(), "SHA", "SHA-256"); + checkKeyPair(g2.generateKeyPair(), "SHA", "SHA-256"); + checkKeyPair(g5.generateKeyPair(), "SHA", "SHA-512"); + + checkKeyPair(g.generateKeyPair(), "SHA", "SHA-256"); + checkKeyPair(g2.generateKeyPair(), "SHA", "SHA-256"); + checkKeyPair(g5.generateKeyPair(), "SHA", "SHA-512"); + + Utils.runAndCheckException(() -> g.initialize(NamedParameterSpec.ED448), + InvalidAlgorithmParameterException.class); // wrong pname + Utils.runAndCheckException(() -> g.initialize(new NamedParameterSpec("SHA-384")), + InvalidAlgorithmParameterException.class); // wrong pname + + Utils.runAndCheckException(() -> g5.initialize(new NamedParameterSpec("SHA-256")), + InvalidAlgorithmParameterException.class); // diff pname + g5.initialize(new NamedParameterSpec("SHA-512")); + + g.initialize(new NamedParameterSpec("sHA-512")); + checkKeyPair(g.generateKeyPair(), "SHA", "SHA-512"); + g.initialize(new NamedParameterSpec("ShA-256")); + checkKeyPair(g.generateKeyPair(), "SHA", "SHA-256"); + + var pk = new NamedX509Key("sHa", "ShA-256", RAND.nBytes(2)); + var sk = new NamedPKCS8Key("sHa", "SHa-256", RAND.nBytes(2)); + checkKey(pk, "sHa", "ShA-256"); + checkKey(sk, "sHa", "SHa-256"); + + Asserts.assertEquals("X.509", pk.getFormat()); + Asserts.assertEquals("PKCS#8", sk.getFormat()); + + var pkSpec = kf.getKeySpec(pk, X509EncodedKeySpec.class); + var skSpec = kf.getKeySpec(sk, PKCS8EncodedKeySpec.class); + + kf2.getKeySpec(pk, X509EncodedKeySpec.class); + kf2.getKeySpec(sk, PKCS8EncodedKeySpec.class); + Utils.runAndCheckException(() -> kf5.getKeySpec(pk, X509EncodedKeySpec.class), + InvalidKeySpecException.class); // wrong KF + Utils.runAndCheckException(() -> kf5.getKeySpec(sk, PKCS8EncodedKeySpec.class), + InvalidKeySpecException.class); + Utils.runAndCheckException(() -> kf.getKeySpec(pk, PKCS8EncodedKeySpec.class), + InvalidKeySpecException.class); // wrong KeySpec + Utils.runAndCheckException(() -> kf.getKeySpec(sk, X509EncodedKeySpec.class), + InvalidKeySpecException.class); + + checkKey(kf.generatePublic(pkSpec), "SHA", "SHA-256"); + Utils.runAndCheckException(() -> kf.generatePrivate(pkSpec), + InvalidKeySpecException.class); + + checkKey(kf.generatePrivate(skSpec), "SHA", "SHA-256"); + Utils.runAndCheckException(() -> kf.generatePublic(skSpec), + InvalidKeySpecException.class); + + checkKey(kf2.generatePrivate(skSpec), "SHA", "SHA-256"); + checkKey(kf2.generatePublic(pkSpec), "SHA", "SHA-256"); + + Utils.runAndCheckException(() -> kf5.generatePublic(pkSpec), + InvalidKeySpecException.class); // wrong KF + Utils.runAndCheckException(() -> kf5.generatePublic(skSpec), + InvalidKeySpecException.class); + + // The private RawKeySpec and unnamed RAW EncodedKeySpec + var prk = kf.getKeySpec(pk, RawKeySpec.class); + Asserts.assertEqualsByteArray(prk.getKeyArr(), pk.getRawBytes()); + var prk2 = kf.getKeySpec(pk, EncodedKeySpec.class); + Asserts.assertEquals("RAW", prk2.getFormat()); + Asserts.assertEqualsByteArray(prk.getKeyArr(), prk2.getEncoded()); + + Asserts.assertEqualsByteArray(kf2.generatePublic(prk).getEncoded(), pk.getEncoded()); + Utils.runAndCheckException(() -> kf.generatePublic(prk), InvalidKeySpecException.class); // no pname + Asserts.assertEqualsByteArray(kf2.generatePublic(prk2).getEncoded(), pk.getEncoded()); + Utils.runAndCheckException(() -> kf.generatePublic(prk2), InvalidKeySpecException.class); // no pname + + var srk = kf.getKeySpec(sk, RawKeySpec.class); + Asserts.assertEqualsByteArray(srk.getKeyArr(), sk.getRawBytes()); + var srk2 = kf.getKeySpec(sk, EncodedKeySpec.class); + Asserts.assertEquals("RAW", srk2.getFormat()); + Asserts.assertEqualsByteArray(srk2.getEncoded(), sk.getRawBytes()); + + Asserts.assertEqualsByteArray(kf2.generatePrivate(srk).getEncoded(), sk.getEncoded()); + Utils.runAndCheckException(() -> kf.generatePrivate(srk), InvalidKeySpecException.class); // no pname + Asserts.assertEqualsByteArray(kf2.generatePrivate(srk2).getEncoded(), sk.getEncoded()); + Utils.runAndCheckException(() -> kf.generatePrivate(srk2), InvalidKeySpecException.class); // no pname + + var pk1 = new PublicKey() { + public String getAlgorithm() { return "SHA"; } + public String getFormat() { return "RAW"; } + public byte[] getEncoded() { return RAND.nBytes(2); } + }; + var pk2 = new PublicKey() { + public String getAlgorithm() { return "sHA-256"; } + public String getFormat() { return "RAW"; } + public byte[] getEncoded() { return RAND.nBytes(2); } + }; + var pk3 = new PublicKey() { + public String getAlgorithm() { return "SHA"; } + public String getFormat() { return "RAW"; } + public byte[] getEncoded() { return RAND.nBytes(2); } + public AlgorithmParameterSpec getParams() { return new NamedParameterSpec("sHA-256"); } + }; + + checkKey(kf2.translateKey(pk1), "SHA", "SHA-256"); + checkKey(kf.translateKey(pk2), "SHA", "SHA-256"); + checkKey(kf.translateKey(pk3), "SHA", "SHA-256"); + + Utils.runAndCheckException(() -> kf.translateKey(pk1), InvalidKeyException.class); + Utils.runAndCheckException(() -> kf5.translateKey(pk2), InvalidKeyException.class); + Utils.runAndCheckException(() -> kf5.translateKey(pk3), InvalidKeyException.class); + + var sk1 = new PrivateKey() { + public String getAlgorithm() { return "SHA"; } + public String getFormat() { return "RAW"; } + public byte[] getEncoded() { return RAND.nBytes(2); } + }; + var sk2 = new PrivateKey() { + public String getAlgorithm() { return "sHA-256"; } + public String getFormat() { return "RAW"; } + public byte[] getEncoded() { return RAND.nBytes(2); } + }; + var sk3 = new PrivateKey() { + public String getAlgorithm() { return "SHA"; } + public String getFormat() { return "RAW"; } + public byte[] getEncoded() { return RAND.nBytes(2); } + public AlgorithmParameterSpec getParams() { return new NamedParameterSpec("sHA-256"); } + }; + + checkKey(kf2.translateKey(sk1), "SHA", "SHA-256"); + checkKey(kf.translateKey(sk2), "SHA", "SHA-256"); + checkKey(kf.translateKey(sk3), "SHA", "SHA-256"); + + Utils.runAndCheckException(() -> kf.translateKey(sk1), InvalidKeyException.class); + Utils.runAndCheckException(() -> kf5.translateKey(sk2), InvalidKeyException.class); + Utils.runAndCheckException(() -> kf5.translateKey(sk3), InvalidKeyException.class); + } + + static void checkKeyPair(KeyPair kp, String algName, String toString) { + checkKey(kp.getPrivate(), algName, toString); + checkKey(kp.getPublic(), algName, toString); + } + + static void checkKey(Key k, String algName, String pname) { + Asserts.assertEquals(algName, k.getAlgorithm()); + Asserts.assertTrue(k.toString().contains(pname)); + if (k instanceof AsymmetricKey ak && ak.getParams() instanceof NamedParameterSpec nps) { + Asserts.assertEquals(pname, nps.getName()); + } + } + + // Provider + + public static class ProviderImpl extends Provider { + public ProviderImpl() { + super("P", "1", "..."); + put("KeyFactory.SHA", KF.class.getName()); + put("KeyFactory.SHA-256", KF1.class.getName()); + put("KeyFactory.SHA-512", KF2.class.getName()); + put("KeyPairGenerator.SHA", KPG.class.getName()); + put("KeyPairGenerator.SHA-256", KPG1.class.getName()); + put("KeyPairGenerator.SHA-512", KPG2.class.getName()); + } + } + public static class KF extends NamedKeyFactory { + public KF() { + super("SHA", "SHA-256", "SHA-512"); + } + } + public static class KF1 extends NamedKeyFactory { + public KF1() { + super("SHA", "SHA-256"); + } + } + public static class KF2 extends NamedKeyFactory { + public KF2() { + super("SHA", "SHA-512"); + } + } + public static class KPG extends NamedKeyPairGenerator { + public KPG() { + super("SHA", "SHA-256", "SHA-512"); + } + + public KPG(String pname) { + super("SHA", pname); + } + + @Override + public byte[][] implGenerateKeyPair(String name, SecureRandom sr) { + var out = new byte[2][]; + out[0] = RAND.nBytes(name.endsWith("256") ? 2 : 4); + out[1] = RAND.nBytes(name.endsWith("256") ? 2 : 4); + return out; + } + } + public static class KPG1 extends KPG { + public KPG1() { + super("SHA-256"); + } + } + public static class KPG2 extends KPG { + public KPG2() { + super("SHA-512"); + } + } +} From c4965d9b135b58e0b3604bc1cc60978ad4c8c11b Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Fri, 11 Oct 2024 21:30:53 +0000 Subject: [PATCH 038/118] 8341794: Fix ExceptionOccurred in jdk.attach Reviewed-by: amenkov, cjplummer --- .../windows/native/libattach/VirtualMachineImpl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/jdk.attach/windows/native/libattach/VirtualMachineImpl.c b/src/jdk.attach/windows/native/libattach/VirtualMachineImpl.c index a8b17c22d83f2..74d0e7bf7d5fa 100644 --- a/src/jdk.attach/windows/native/libattach/VirtualMachineImpl.c +++ b/src/jdk.attach/windows/native/libattach/VirtualMachineImpl.c @@ -432,7 +432,7 @@ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_enqueue return; } } - if ((*env)->ExceptionOccurred(env)) return; + if ((*env)->ExceptionCheck(env)) return; } } for (i = argsLen; i < MAX_ARGS; i++) { @@ -463,7 +463,7 @@ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_enqueue stubLen = (DWORD)(*env)->GetArrayLength(env, stub); stubCode = (*env)->GetByteArrayElements(env, stub, &isCopy); - if ((*env)->ExceptionOccurred(env)) return; + if ((*env)->ExceptionCheck(env)) return; pCode = (PDWORD) VirtualAllocEx( hProcess, 0, stubLen, MEM_COMMIT, PAGE_EXECUTE_READWRITE ); if (pCode == NULL) { @@ -636,7 +636,7 @@ static jboolean jstring_to_cstring(JNIEnv* env, jstring jstr, char* cstr, size_t cstr[0] = '\0'; } else { str = JNU_GetStringPlatformChars(env, jstr, &isCopy); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { return result; } if (strlen(str) >= cstr_buf_size) { From 2db3397187563d1821d24578247f764c372fbb4b Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Fri, 11 Oct 2024 21:31:58 +0000 Subject: [PATCH 039/118] 8341797: Fix ExceptionOccurred in jdk.jdi Reviewed-by: amenkov, cjplummer --- .../native/libdt_shmem/SharedMemoryConnection.c | 12 ++++++------ .../share/native/libdt_shmem/SharedMemoryTransport.c | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/jdk.jdi/share/native/libdt_shmem/SharedMemoryConnection.c b/src/jdk.jdi/share/native/libdt_shmem/SharedMemoryConnection.c index af78969e316ac..b6d246d043363 100644 --- a/src/jdk.jdi/share/native/libdt_shmem/SharedMemoryConnection.c +++ b/src/jdk.jdi/share/native/libdt_shmem/SharedMemoryConnection.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -115,7 +115,7 @@ packetToByteArray(JNIEnv *env, jdwpPacket *str) /* total packet length is header + data */ array = (*env)->NewByteArray(env, total_length); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { return NULL; } @@ -144,7 +144,7 @@ packetToByteArray(JNIEnv *env, jdwpPacket *str) if (data_length > 0) { (*env)->SetByteArrayRegion(env, array, JDWP_HEADER_SIZE, data_length, str->type.cmd.data); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { return NULL; } } @@ -174,7 +174,7 @@ byteArrayToPacket(JNIEnv *env, jbyteArray b, jdwpPacket *str) * Get the packet header */ (*env)->GetByteArrayRegion(env, b, 0, sizeof(pktHeader), pktHeader); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { /* b shorter than sizeof(pktHeader) */ return; } @@ -221,7 +221,7 @@ byteArrayToPacket(JNIEnv *env, jbyteArray b, jdwpPacket *str) } (*env)->GetByteArrayRegion(env, b, sizeof(pktHeader), /*sizeof(CmdPacket)+4*/ data_length, data); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { free(data); return; } @@ -326,7 +326,7 @@ JNIEXPORT void JNICALL Java_com_sun_tools_jdi_SharedMemoryConnection_sendPacket0 jint rc; byteArrayToPacket(env, b, &packet); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { return; } diff --git a/src/jdk.jdi/share/native/libdt_shmem/SharedMemoryTransport.c b/src/jdk.jdi/share/native/libdt_shmem/SharedMemoryTransport.c index 7258503f7e173..867ed1d8567fa 100644 --- a/src/jdk.jdi/share/native/libdt_shmem/SharedMemoryTransport.c +++ b/src/jdk.jdi/share/native/libdt_shmem/SharedMemoryTransport.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * 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 @@ void throwException(JNIEnv *env, char *exceptionClassName, char *message) { jclass excClass = (*env)->FindClass(env, exceptionClassName); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { return; } (*env)->ThrowNew(env, excClass, message); @@ -109,7 +109,7 @@ JNIEXPORT jlong JNICALL Java_com_sun_tools_jdi_SharedMemoryTransportService_atta const char *addrChars; addrChars = (*env)->GetStringUTFChars(env, address, NULL); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { return CONNECTION_TO_ID(connection); } else if (addrChars == NULL) { throwException(env, "java/lang/InternalError", "GetStringUTFChars failed"); @@ -143,7 +143,7 @@ JNIEXPORT jstring JNICALL Java_com_sun_tools_jdi_SharedMemoryTransportService_na throwShmemException(env, "shmemBase_name failed", rc); } else { nameString = (*env)->NewStringUTF(env, namePtr); - if ((nameString == NULL) && !(*env)->ExceptionOccurred(env)) { + if ((nameString == NULL) && !(*env)->ExceptionCheck(env)) { throwException(env, "java/lang/InternalError", "Unable to create string"); } } @@ -190,7 +190,7 @@ JNIEXPORT jlong JNICALL Java_com_sun_tools_jdi_SharedMemoryTransportService_star if (address != NULL) { addrChars = (*env)->GetStringUTFChars(env, address, NULL); - if ((*env)->ExceptionOccurred(env)) { + if ((*env)->ExceptionCheck(env)) { return TRANSPORT_TO_ID(transport); } else if (addrChars == NULL) { throwException(env, "java/lang/InternalError", "GetStringUTFChars failed"); From 2e1c1936e183fe8329bb6247523bd73ad9b3ca88 Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Sat, 12 Oct 2024 02:45:50 +0000 Subject: [PATCH 040/118] 8342003: ProblemList sun/security/tools/keytool/GenKeyPairSigner.java Reviewed-by: jpai --- test/jdk/ProblemList.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 034830a2575a5..0aa27e4ac0ce6 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -644,6 +644,8 @@ sun/security/provider/PolicyParser/PrincipalExpansionError.java 8039280 generic- sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java 8316183 linux-ppc64le +sun/security/tools/keytool/GenKeyPairSigner.java 8342002 generic-all + ############################################################################ # jdk_sound From 41ee582df8c65f2f26b21e46784cf0bc4ece0585 Mon Sep 17 00:00:00 2001 From: Ramkumar Sunderbabu Date: Sat, 12 Oct 2024 03:25:42 +0000 Subject: [PATCH 041/118] 8341138: Rename jtreg property docker.support as container.support Reviewed-by: sgehwolf, mseledtsov --- test/hotspot/jtreg/TEST.ROOT | 2 +- .../containers/docker/DockerBasicTest.java | 4 ++-- .../jtreg/containers/docker/ShareTmpDir.java | 4 ++-- .../containers/docker/TestCPUAwareness.java | 4 ++-- .../jtreg/containers/docker/TestCPUSets.java | 4 ++-- .../containers/docker/TestContainerInfo.java | 2 +- .../jtreg/containers/docker/TestJFREvents.java | 2 +- .../docker/TestJFRNetworkEvents.java | 4 ++-- .../containers/docker/TestJFRWithJMX.java | 4 ++-- .../jtreg/containers/docker/TestJcmd.java | 4 ++-- .../containers/docker/TestJcmdWithSideCar.java | 4 ++-- .../containers/docker/TestLimitsUpdating.java | 3 ++- .../containers/docker/TestMemoryAwareness.java | 4 ++-- .../jtreg/containers/docker/TestMisc.java | 4 ++-- .../jtreg/containers/docker/TestPids.java | 2 +- test/jdk/TEST.ROOT | 2 +- .../platform/docker/TestDockerBasic.java | 3 ++- .../platform/docker/TestDockerCpuMetrics.java | 4 ++-- .../docker/TestDockerMemoryMetrics.java | 2 +- .../docker/TestGetFreeSwapSpaceSize.java | 3 ++- .../platform/docker/TestLimitsUpdating.java | 3 ++- .../platform/docker/TestPidsLimit.java | 4 ++-- .../platform/docker/TestSystemMetrics.java | 4 ++-- .../docker/TestUseContainerSupport.java | 3 ++- test/jtreg-ext/requires/VMProps.java | 18 +++++++++--------- test/lib/jdk/test/lib/Container.java | 5 +++-- 26 files changed, 54 insertions(+), 48 deletions(-) diff --git a/test/hotspot/jtreg/TEST.ROOT b/test/hotspot/jtreg/TEST.ROOT index 5ed0227068cf6..962fc36838c37 100644 --- a/test/hotspot/jtreg/TEST.ROOT +++ b/test/hotspot/jtreg/TEST.ROOT @@ -86,7 +86,7 @@ requires.properties= \ vm.compiler2.enabled \ vm.musl \ vm.flagless \ - docker.support \ + container.support \ systemd.support \ jdk.containerized diff --git a/test/hotspot/jtreg/containers/docker/DockerBasicTest.java b/test/hotspot/jtreg/containers/docker/DockerBasicTest.java index 357eb3db49727..9233b199532bf 100644 --- a/test/hotspot/jtreg/containers/docker/DockerBasicTest.java +++ b/test/hotspot/jtreg/containers/docker/DockerBasicTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * 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 * @summary Basic (sanity) test for JDK-under-test inside a docker image. - * @requires docker.support + * @requires container.support * @library /test/lib * @modules java.base/jdk.internal.misc * java.management diff --git a/test/hotspot/jtreg/containers/docker/ShareTmpDir.java b/test/hotspot/jtreg/containers/docker/ShareTmpDir.java index 08493a7539805..43cd6ec515208 100644 --- a/test/hotspot/jtreg/containers/docker/ShareTmpDir.java +++ b/test/hotspot/jtreg/containers/docker/ShareTmpDir.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @bug 8286030 * @key cgroups * @summary Test for hsperfdata file name conflict when two containers share the same /tmp directory - * @requires docker.support + * @requires container.support * @library /test/lib * @build WaitForFlagFile * @run driver ShareTmpDir diff --git a/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java b/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java index a41dc9c39392b..c51bfa1abbb18 100644 --- a/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java +++ b/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @test * @key cgroups * @summary Test JVM's CPU resource awareness when running inside docker container - * @requires docker.support + * @requires container.support * @library /test/lib * @modules java.base/jdk.internal.misc * java.base/jdk.internal.platform diff --git a/test/hotspot/jtreg/containers/docker/TestCPUSets.java b/test/hotspot/jtreg/containers/docker/TestCPUSets.java index de35388f5a843..aabe82e131fe9 100644 --- a/test/hotspot/jtreg/containers/docker/TestCPUSets.java +++ b/test/hotspot/jtreg/containers/docker/TestCPUSets.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @test * @key cgroups * @summary Test JVM's awareness of cpu sets (cpus and mems) - * @requires docker.support + * @requires container.support * @requires (os.arch != "s390x") * @library /test/lib * @modules java.base/jdk.internal.misc diff --git a/test/hotspot/jtreg/containers/docker/TestContainerInfo.java b/test/hotspot/jtreg/containers/docker/TestContainerInfo.java index 6bcb706fa7a6a..5db3c2af09850 100644 --- a/test/hotspot/jtreg/containers/docker/TestContainerInfo.java +++ b/test/hotspot/jtreg/containers/docker/TestContainerInfo.java @@ -27,7 +27,7 @@ * @test * @summary Test container info for cgroup v2 * @key cgroups - * @requires docker.support + * @requires container.support * @library /test/lib * @modules java.base/jdk.internal.misc * java.management diff --git a/test/hotspot/jtreg/containers/docker/TestJFREvents.java b/test/hotspot/jtreg/containers/docker/TestJFREvents.java index abc9de45db842..77c735cde00f1 100644 --- a/test/hotspot/jtreg/containers/docker/TestJFREvents.java +++ b/test/hotspot/jtreg/containers/docker/TestJFREvents.java @@ -29,7 +29,7 @@ * when run inside Docker container, such as available CPU and memory. * Also make sure that PIDs are based on value provided by container, * not by the host system. - * @requires (docker.support & os.maxMemory >= 2g) + * @requires (container.support & os.maxMemory >= 2g) * @modules java.base/jdk.internal.platform * @library /test/lib * @modules java.base/jdk.internal.misc diff --git a/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java b/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java index 54ffff4e60ef3..9f9497d9c635f 100644 --- a/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java +++ b/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @summary Test JFR network related events inside a container; make sure * the reported host ip and host name are correctly reported within * the container. - * @requires docker.support + * @requires container.support * @library /test/lib * @modules java.base/jdk.internal.misc * java.management diff --git a/test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java b/test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java index 61fad4f86be28..b751725428162 100644 --- a/test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java +++ b/test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * 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 * @summary Test JFR recording controlled via JMX across container boundary. - * @requires docker.support + * @requires container.support * @library /test/lib * @modules java.base/jdk.internal.misc * java.management diff --git a/test/hotspot/jtreg/containers/docker/TestJcmd.java b/test/hotspot/jtreg/containers/docker/TestJcmd.java index 60d4f4a9e5b46..ca8f1659fe9ef 100644 --- a/test/hotspot/jtreg/containers/docker/TestJcmd.java +++ b/test/hotspot/jtreg/containers/docker/TestJcmd.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @test * @summary Test JCMD across container boundary. The JCMD runs on a host system, * while sending commands to a JVM that runs inside a container. - * @requires docker.support + * @requires container.support * @requires vm.flagless * @modules java.base/jdk.internal.misc * java.management diff --git a/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java b/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java index 5dea864f42750..de27f4d24e207 100644 --- a/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java +++ b/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * 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 @@ * and other uses. In side car pattern the main application/service container * is paired with a sidecar container by sharing certain aspects of container * namespace such as PID namespace, specific sub-directories, IPC and more. - * @requires docker.support + * @requires container.support * @requires vm.flagless * @modules java.base/jdk.internal.misc * java.management diff --git a/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java b/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java index e15ab9b2b81fa..14227a7106804 100644 --- a/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java +++ b/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2023, Red Hat, Inc. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -28,7 +29,7 @@ * @bug 8308090 * @key cgroups * @summary Test container limits updating as they get updated at runtime without restart - * @requires docker.support + * @requires container.support * @library /test/lib * @build jdk.test.whitebox.WhiteBox LimitUpdateChecker * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar whitebox.jar jdk.test.whitebox.WhiteBox diff --git a/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java b/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java index 20354cf934d96..06a874e008ae5 100644 --- a/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java +++ b/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @bug 8146115 8292083 * @key cgroups * @summary Test JVM's memory resource awareness when running inside docker container - * @requires docker.support + * @requires container.support * @library /test/lib * @modules java.base/jdk.internal.misc * java.base/jdk.internal.platform diff --git a/test/hotspot/jtreg/containers/docker/TestMisc.java b/test/hotspot/jtreg/containers/docker/TestMisc.java index 5b7f96112b901..a811666999bdc 100644 --- a/test/hotspot/jtreg/containers/docker/TestMisc.java +++ b/test/hotspot/jtreg/containers/docker/TestMisc.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * 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 * @summary Test miscellanous functionality related to JVM running in docker container - * @requires docker.support + * @requires container.support * @library /test/lib * @modules java.base/jdk.internal.misc * java.management diff --git a/test/hotspot/jtreg/containers/docker/TestPids.java b/test/hotspot/jtreg/containers/docker/TestPids.java index 2b3b2594cfa93..9b65a1b1ee880 100644 --- a/test/hotspot/jtreg/containers/docker/TestPids.java +++ b/test/hotspot/jtreg/containers/docker/TestPids.java @@ -27,7 +27,7 @@ * @test * @key cgroups * @summary Test JVM's awareness of pids controller - * @requires docker.support + * @requires container.support * @library /test/lib * @modules java.base/jdk.internal.misc * java.management diff --git a/test/jdk/TEST.ROOT b/test/jdk/TEST.ROOT index 6198d33214293..c8db6b89a71c7 100644 --- a/test/jdk/TEST.ROOT +++ b/test/jdk/TEST.ROOT @@ -100,7 +100,7 @@ requires.properties= \ vm.jvmci.enabled \ vm.jvmti \ vm.cpu.features \ - docker.support \ + container.support \ systemd.support \ release.implementor \ jdk.containerized \ diff --git a/test/jdk/jdk/internal/platform/docker/TestDockerBasic.java b/test/jdk/jdk/internal/platform/docker/TestDockerBasic.java index 5518943a6e666..e236292de984a 100644 --- a/test/jdk/jdk/internal/platform/docker/TestDockerBasic.java +++ b/test/jdk/jdk/internal/platform/docker/TestDockerBasic.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2022, Red Hat, Inc. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * 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 +27,7 @@ * @bug 8293540 * @summary Verify that -XshowSettings:system works * @key cgroups - * @requires docker.support + * @requires container.support * @library /test/lib * @run main/timeout=360 TestDockerBasic */ diff --git a/test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java b/test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java index f08e80c76f422..4d452f20eefe1 100644 --- a/test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java +++ b/test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @test * @key cgroups * @summary Test JDK Metrics class when running inside docker container - * @requires docker.support + * @requires container.support * @library /test/lib * @modules java.base/jdk.internal.platform * @build MetricsCpuTester diff --git a/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java b/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java index 416e91bec5ca2..e8dc616b5e79a 100644 --- a/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java +++ b/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java @@ -32,7 +32,7 @@ * @test * @key cgroups * @summary Test JDK Metrics class when running inside docker container - * @requires docker.support + * @requires container.support * @library /test/lib * @modules java.base/jdk.internal.platform * @build MetricsMemoryTester diff --git a/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java b/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java index 92f3364da10b0..204d7a215d89f 100644 --- a/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java +++ b/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2020, 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * 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 +26,7 @@ * @test * @key cgroups * @bug 8242480 - * @requires docker.support + * @requires container.support * @library /test/lib * @build GetFreeSwapSpaceSize * @run driver TestGetFreeSwapSpaceSize diff --git a/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java b/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java index 22e03293c486e..1544088f68858 100644 --- a/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java +++ b/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2023, Red Hat, Inc. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -28,7 +29,7 @@ * @bug 8308090 * @key cgroups * @summary Test container limits updating as they get updated at runtime without restart - * @requires docker.support + * @requires container.support * @library /test/lib * @modules java.base/jdk.internal.platform * @build LimitUpdateChecker diff --git a/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java b/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java index 6c6ff76fa9998..9fedeb55234ca 100644 --- a/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java +++ b/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -27,7 +27,7 @@ * @key cgroups * @summary Test JDK Metrics class when running inside a docker container with limited pids * @bug 8266490 - * @requires docker.support + * @requires container.support * @library /test/lib * @build TestPidsLimit * @run driver TestPidsLimit diff --git a/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java b/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java index 854d24b2279f8..93efff64cc428 100644 --- a/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java +++ b/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * 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 * @key cgroups * @summary Test JDK Metrics class when running inside docker container - * @requires docker.support + * @requires container.support * @library /test/lib * @modules java.base/jdk.internal.platform * @run main TestSystemMetrics diff --git a/test/jdk/jdk/internal/platform/docker/TestUseContainerSupport.java b/test/jdk/jdk/internal/platform/docker/TestUseContainerSupport.java index 7a2f77b3ce41a..6a96514771ce4 100644 --- a/test/jdk/jdk/internal/platform/docker/TestUseContainerSupport.java +++ b/test/jdk/jdk/internal/platform/docker/TestUseContainerSupport.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, Red Hat, Inc. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * 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 +25,7 @@ /* * @test * @summary UseContainerSupport flag should reflect Metrics being available - * @requires docker.support + * @requires container.support * @library /test/lib * @modules java.base/jdk.internal.platform * @build CheckUseContainerSupport diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java index 0457fb7e3c528..465c641d44204 100644 --- a/test/jtreg-ext/requires/VMProps.java +++ b/test/jtreg-ext/requires/VMProps.java @@ -131,7 +131,7 @@ public Map call() { map.put("vm.libgraal.jit", this::isLibgraalJIT); map.put("vm.compiler1.enabled", this::isCompiler1Enabled); map.put("vm.compiler2.enabled", this::isCompiler2Enabled); - map.put("docker.support", this::dockerSupport); + map.put("container.support", this::containerSupport); map.put("systemd.support", this::systemdSupport); map.put("vm.musl", this::isMusl); map.put("release.implementor", this::implementor); @@ -585,16 +585,16 @@ protected String isCompiler2Enabled() { } /** - * A simple check for docker support + * A simple check for container support * - * @return true if docker is supported in a given environment + * @return true if container is supported in a given environment */ - protected String dockerSupport() { - log("Entering dockerSupport()"); + protected String containerSupport() { + log("Entering containerSupport()"); boolean isSupported = false; if (Platform.isLinux()) { - // currently docker testing is only supported for Linux, + // currently container testing is only supported for Linux, // on certain platforms String arch = System.getProperty("os.arch"); @@ -610,17 +610,17 @@ protected String dockerSupport() { } } - log("dockerSupport(): platform check: isSupported = " + isSupported); + log("containerSupport(): platform check: isSupported = " + isSupported); if (isSupported) { try { - isSupported = checkProgramSupport("checkDockerSupport()", Container.ENGINE_COMMAND); + isSupported = checkProgramSupport("checkContainerSupport()", Container.ENGINE_COMMAND); } catch (Exception e) { isSupported = false; } } - log("dockerSupport(): returning isSupported = " + isSupported); + log("containerSupport(): returning isSupported = " + isSupported); return "" + isSupported; } diff --git a/test/lib/jdk/test/lib/Container.java b/test/lib/jdk/test/lib/Container.java index e0ca4851e144b..83fd265980f26 100644 --- a/test/lib/jdk/test/lib/Container.java +++ b/test/lib/jdk/test/lib/Container.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2019, Red Hat Inc. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * 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 +24,9 @@ package jdk.test.lib; public class Container { - // Use this property to specify docker location on your system. + // Use this property to specify container runtime location (e.g. docker) on your system. // E.g.: "/usr/local/bin/docker". We define this constant here so - // that it can be used in VMProps as well which checks docker support + // that it can be used in VMProps as well which checks container support // via this command public static final String ENGINE_COMMAND = System.getProperty("jdk.test.container.command", "docker"); From 5c4f1ef746b0c373a131726d74d27f0e0cc6e40d Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Mon, 14 Oct 2024 04:45:12 +0000 Subject: [PATCH 042/118] 8226933: [TEST_BUG]GTK L&F: There is no swatches or RGB tab in JColorChooser Reviewed-by: aivanov, psadhukhan, tr --- .../swing/JColorChooser/Test4887836.java | 13 +++- .../plaf/basic/BasicSliderUI/bug4419255.java | 65 +++++++++++++++++++ 2 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 test/jdk/javax/swing/plaf/basic/BasicSliderUI/bug4419255.java diff --git a/test/jdk/javax/swing/JColorChooser/Test4887836.java b/test/jdk/javax/swing/JColorChooser/Test4887836.java index 4043dbdd88ae6..82a09c460853b 100644 --- a/test/jdk/javax/swing/JColorChooser/Test4887836.java +++ b/test/jdk/javax/swing/JColorChooser/Test4887836.java @@ -26,10 +26,12 @@ import javax.swing.JColorChooser; import javax.swing.UIManager; +import jtreg.SkippedException; + /* * @test * @bug 4887836 - * @library /java/awt/regtesthelpers + * @library /java/awt/regtesthelpers /test/lib * @build PassFailJFrame * @summary Checks for white area under the JColorChooser Swatch tab * @run main/manual Test4887836 @@ -38,6 +40,13 @@ public class Test4887836 { public static void main(String[] args) throws Exception { + + // ColorChooser UI design is different for GTK L&F. + // There is no Swatches tab available for GTK L&F, skip the testing. + if (UIManager.getLookAndFeel().getName().contains("GTK")) { + throw new SkippedException("Test not applicable for GTK L&F"); + } + String instructions = """ If you do not see white area under the \"Swatches\" tab, then test passed, otherwise it failed."""; @@ -45,9 +54,7 @@ public static void main(String[] args) throws Exception { PassFailJFrame.builder() .title("Test4759306") .instructions(instructions) - .rows(5) .columns(40) - .testTimeOut(10) .testUI(Test4887836::createColorChooser) .build() .awaitAndCheck(); diff --git a/test/jdk/javax/swing/plaf/basic/BasicSliderUI/bug4419255.java b/test/jdk/javax/swing/plaf/basic/BasicSliderUI/bug4419255.java new file mode 100644 index 0000000000000..eb23901f60d4b --- /dev/null +++ b/test/jdk/javax/swing/plaf/basic/BasicSliderUI/bug4419255.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * 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 javax.swing.JColorChooser; +import javax.swing.UIManager; + +import jtreg.SkippedException; + +/* + * @test + * @bug 4419255 + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame + * @summary Tests if Metal Slider's thumb isn't clipped + * @run main/manual bug4419255 + */ + +public class bug4419255 { + + public static void main(String[] args) throws Exception { + + // ColorChooser UI design is different for GTK L&F. + // There is no RGB tab available for GTK L&F, skip the testing. + if (UIManager.getLookAndFeel().getName().contains("GTK")) { + throw new SkippedException("Test not applicable for GTK L&F"); + } + String instructions = """ + Choose RGB tab. If sliders' thumbs are painted correctly + (top is not clipped, black line is visible), + then test passed. Otherwise it failed."""; + + PassFailJFrame.builder() + .title("bug4419255") + .instructions(instructions) + .columns(40) + .testUI(bug4419255::createColorChooser) + .build() + .awaitAndCheck(); + } + + private static JColorChooser createColorChooser() { + return new JColorChooser(Color.BLUE); + } +} From fe98f86b5792cbb17d47871452d27ab87d72b342 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Mon, 14 Oct 2024 04:45:24 +0000 Subject: [PATCH 043/118] 8226938: [TEST_BUG]GTK L&F: There is no Details button in FileChooser Dialog Reviewed-by: honkar, prr --- .../javax/swing/JFileChooser/bug4587721.java | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 test/jdk/javax/swing/JFileChooser/bug4587721.java diff --git a/test/jdk/javax/swing/JFileChooser/bug4587721.java b/test/jdk/javax/swing/JFileChooser/bug4587721.java new file mode 100644 index 0000000000000..408f4e47f49f7 --- /dev/null +++ b/test/jdk/javax/swing/JFileChooser/bug4587721.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * 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 4587721 + * @summary Tests if JFileChooser details view chops off text + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4587721 + */ + +import java.awt.Font; +import java.util.Enumeration; + +import javax.swing.JFileChooser; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.plaf.FontUIResource; +import javax.swing.plaf.metal.MetalLookAndFeel; + +public class bug4587721 { + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel(new MetalLookAndFeel()); + + String instructions = """ + Click on the Details button in JFileChooser Window. + If the filename text is chopped off by height, + then Press FAIL else Press PASS. + """; + + PassFailJFrame.builder() + .title("bug4587721") + .instructions(instructions) + .columns(40) + .testUI(bug4587721::createUI) + .build() + .awaitAndCheck(); + } + + public static JFileChooser createUI() { + setFonts(); + JFileChooser fc = new JFileChooser(); + return fc; + } + + public static void setFonts() { + UIDefaults defaults = UIManager.getDefaults(); + Enumeration keys = defaults.keys(); + while (keys.hasMoreElements()) { + Object key = keys.nextElement(); + if (defaults.get(key) instanceof Font) + UIManager.put(key, new FontUIResource(new Font("Courier", Font.BOLD, 30))); + } + } +} From 8d0975a27d826f7aa487a612131827586abaefd5 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Mon, 14 Oct 2024 05:26:48 +0000 Subject: [PATCH 044/118] 8336726: C2: assert(!do_asserts || projs->fallthrough_ioproj != nullptr) failed: must be found Reviewed-by: chagedorn, kvn, vlivanov --- src/hotspot/share/opto/callGenerator.cpp | 9 ++- src/hotspot/share/opto/graphKit.cpp | 4 +- src/hotspot/share/opto/graphKit.hpp | 2 +- ...tCallDevirtualizationWithInfiniteLoop.java | 76 +++++++++++++++++++ 4 files changed, 85 insertions(+), 6 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/TestCallDevirtualizationWithInfiniteLoop.java diff --git a/src/hotspot/share/opto/callGenerator.cpp b/src/hotspot/share/opto/callGenerator.cpp index afd9ca25a56fe..36fca9f61b691 100644 --- a/src/hotspot/share/opto/callGenerator.cpp +++ b/src/hotspot/share/opto/callGenerator.cpp @@ -623,7 +623,10 @@ void CallGenerator::do_late_inline_helper() { // check for unreachable loop CallProjections callprojs; - call->extract_projections(&callprojs, true); + // Similar to incremental inlining, don't assert that all call + // projections are still there for post-parse call devirtualization. + bool do_asserts = !is_mh_late_inline() && !is_virtual_late_inline(); + call->extract_projections(&callprojs, true, do_asserts); if ((callprojs.fallthrough_catchproj == call->in(0)) || (callprojs.catchall_catchproj == call->in(0)) || (callprojs.fallthrough_memproj == call->in(TypeFunc::Memory)) || @@ -647,7 +650,7 @@ void CallGenerator::do_late_inline_helper() { if (is_pure_call() && result_not_used) { GraphKit kit(call->jvms()); - kit.replace_call(call, C->top(), true); + kit.replace_call(call, C->top(), true, do_asserts); } else { // Make a clone of the JVMState that appropriate to use for driving a parse JVMState* old_jvms = call->jvms(); @@ -729,7 +732,7 @@ void CallGenerator::do_late_inline_helper() { } C->set_inlining_progress(true); C->set_do_cleanup(kit.stopped()); // path is dead; needs cleanup - kit.replace_call(call, result, true); + kit.replace_call(call, result, true, do_asserts); } } diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index 27120c5ea1e73..fe8ca76e318c1 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -1930,7 +1930,7 @@ static void add_mergemem_users_to_worklist(Unique_Node_List& wl, Node* mem) { } // Replace the call with the current state of the kit. -void GraphKit::replace_call(CallNode* call, Node* result, bool do_replaced_nodes) { +void GraphKit::replace_call(CallNode* call, Node* result, bool do_replaced_nodes, bool do_asserts) { JVMState* ejvms = nullptr; if (has_exceptions()) { ejvms = transfer_exceptions_into_jvms(); @@ -1944,7 +1944,7 @@ void GraphKit::replace_call(CallNode* call, Node* result, bool do_replaced_nodes // Find all the needed outputs of this call CallProjections callprojs; - call->extract_projections(&callprojs, true); + call->extract_projections(&callprojs, true, do_asserts); Unique_Node_List wl; Node* init_mem = call->in(TypeFunc::Memory); diff --git a/src/hotspot/share/opto/graphKit.hpp b/src/hotspot/share/opto/graphKit.hpp index 421ce933ed1f5..3333b7d1bd95f 100644 --- a/src/hotspot/share/opto/graphKit.hpp +++ b/src/hotspot/share/opto/graphKit.hpp @@ -731,7 +731,7 @@ class GraphKit : public Phase { // Replace the call with the current state of the kit. Requires // that the call was generated with separate io_projs so that // exceptional control flow can be handled properly. - void replace_call(CallNode* call, Node* result, bool do_replaced_nodes = false); + void replace_call(CallNode* call, Node* result, bool do_replaced_nodes = false, bool do_asserts = true); // helper functions for statistics void increment_counter(address counter_addr); // increment a debug counter diff --git a/test/hotspot/jtreg/compiler/c2/TestCallDevirtualizationWithInfiniteLoop.java b/test/hotspot/jtreg/compiler/c2/TestCallDevirtualizationWithInfiniteLoop.java new file mode 100644 index 0000000000000..1afbe8d94653e --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestCallDevirtualizationWithInfiniteLoop.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 8336726 + * @summary Test that post-parse call devirtualization works when call does not have an IO projection. + * @run main/othervm -XX:-TieredCompilation -Xcomp -XX:CompileCommand=compileonly,TestCallDevirtualizationWithInfiniteLoop::test + * TestCallDevirtualizationWithInfiniteLoop + */ + +public class TestCallDevirtualizationWithInfiniteLoop { + + static interface I { + public void method(); + } + + static final class A implements I { + @Override + public void method() { }; + } + + static final class B implements I { + @Override + public void method() { }; + } + + static final A a = new A(); + static final B b = new B(); + + public static void test(boolean flag) { + // Avoid executing endless loop + if (flag) { + return; + } + + // We only know after loop opts that the receiver type is B. + I recv = a; + for (int i = 0; i < 3; ++i) { + if (i > 1) { + recv = b; + } + } + // Post-parse call devirtualization will then convert below + // virtual call to a static call. + recv.method(); + + // Endless loop which does not use IO. As a result the IO + // projection of the call is removed unexpectedly. + while (true) { } + } + + public static void main(String[] args) { + test(true); + } +} From 037f11b864734734dd7fbce029b2e8b4bc17f3ab Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Mon, 14 Oct 2024 06:02:00 +0000 Subject: [PATCH 045/118] 8341708: Optimize safepoint poll encoding with smaller poll data offset Reviewed-by: kvn, qamai --- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 2 +- src/hotspot/share/runtime/javaThread.hpp | 20 +++++++++++++++---- src/hotspot/share/runtime/thread.hpp | 7 +++++++ .../compiler/c2/irTests/TestPadding.java | 2 +- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 5452cca96b8c0..05081197c4bd5 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -241,7 +241,6 @@ nonstatic_field(JavaThread, _jvmci_reserved_oop0, oop) \ nonstatic_field(JavaThread, _should_post_on_exceptions_flag, int) \ nonstatic_field(JavaThread, _jni_environment, JNIEnv) \ - nonstatic_field(JavaThread, _poll_data, SafepointMechanism::ThreadData) \ nonstatic_field(JavaThread, _stack_overflow_state._reserved_stack_activation, address) \ nonstatic_field(JavaThread, _held_monitor_count, intx) \ nonstatic_field(JavaThread, _lock_stack, LockStack) \ @@ -409,6 +408,7 @@ static_field(StubRoutines, _cont_thaw, address) \ static_field(StubRoutines, _lookup_secondary_supers_table_slow_path_stub, address) \ \ + nonstatic_field(Thread, _poll_data, SafepointMechanism::ThreadData) \ nonstatic_field(Thread, _tlab, ThreadLocalAllocBuffer) \ nonstatic_field(Thread, _allocated_bytes, jlong) \ JFR_ONLY(nonstatic_field(Thread, _jfr_thread_local, JfrThreadLocal)) \ diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp index 20bb08a4acbca..bda438612e349 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -238,8 +238,6 @@ class JavaThread: public Thread { // Safepoint support public: // Expose _thread_state for SafeFetchInt() volatile JavaThreadState _thread_state; - private: - SafepointMechanism::ThreadData _poll_data; ThreadSafepointState* _safepoint_state; // Holds information about a thread during a safepoint address _saved_exception_pc; // Saved pc of instruction where last implicit exception happened NOT_PRODUCT(bool _requires_cross_modify_fence;) // State used by VerifyCrossModifyFence @@ -598,6 +596,22 @@ class JavaThread: public Thread { SafepointMechanism::ThreadData* poll_data() { return &_poll_data; } + static ByteSize polling_word_offset() { + ByteSize offset = byte_offset_of(Thread, _poll_data) + + byte_offset_of(SafepointMechanism::ThreadData, _polling_word); + // At least on x86_64, safepoint polls encode the offset as disp8 imm. + assert(in_bytes(offset) < 128, "Offset >= 128"); + return offset; + } + + static ByteSize polling_page_offset() { + ByteSize offset = byte_offset_of(Thread, _poll_data) + + byte_offset_of(SafepointMechanism::ThreadData, _polling_page); + // At least on x86_64, safepoint polls encode the offset as disp8 imm. + assert(in_bytes(offset) < 128, "Offset >= 128"); + return offset; + } + void set_requires_cross_modify_fence(bool val) PRODUCT_RETURN NOT_PRODUCT({ _requires_cross_modify_fence = val; }) // Continuation support @@ -787,8 +801,6 @@ class JavaThread: public Thread { static ByteSize vm_result_offset() { return byte_offset_of(JavaThread, _vm_result); } static ByteSize vm_result_2_offset() { return byte_offset_of(JavaThread, _vm_result_2); } static ByteSize thread_state_offset() { return byte_offset_of(JavaThread, _thread_state); } - static ByteSize polling_word_offset() { return byte_offset_of(JavaThread, _poll_data) + byte_offset_of(SafepointMechanism::ThreadData, _polling_word);} - static ByteSize polling_page_offset() { return byte_offset_of(JavaThread, _poll_data) + byte_offset_of(SafepointMechanism::ThreadData, _polling_page);} static ByteSize saved_exception_pc_offset() { return byte_offset_of(JavaThread, _saved_exception_pc); } static ByteSize osthread_offset() { return byte_offset_of(JavaThread, _osthread); } #if INCLUDE_JVMCI diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index 45c39eae151d2..e2dfce7b2555b 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -33,6 +33,7 @@ #include "runtime/atomic.hpp" #include "runtime/globals.hpp" #include "runtime/os.hpp" +#include "runtime/safepointMechanism.hpp" #include "runtime/threadHeapSampler.hpp" #include "runtime/threadLocalStorage.hpp" #include "runtime/threadStatisticalInfo.hpp" @@ -109,6 +110,7 @@ class Thread: public ThreadShadow { friend class VMErrorCallbackMark; friend class VMStructs; friend class JVMCIVMStructs; + friend class JavaThread; private: #ifndef USE_LIBRARY_BASED_TLS_ONLY @@ -135,6 +137,11 @@ class Thread: public ThreadShadow { } private: + // Poll data is used in generated code for safepoint polls. + // It is important for performance to put this at lower offset + // in Thread. The accessors are in JavaThread. + SafepointMechanism::ThreadData _poll_data; + // Thread local data area available to the GC. The internal // structure and contents of this data area is GC-specific. // Only GC and GC barrier code should access this data area. diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestPadding.java b/test/hotspot/jtreg/compiler/c2/irTests/TestPadding.java index 25225e86b2846..17b2817a9a29d 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestPadding.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestPadding.java @@ -48,7 +48,7 @@ public static void test_runner() { } @Test - @IR(counts = { IRNode.NOP, "1" }) + @IR(counts = { IRNode.NOP, "<=1" }) static int test(int i) { TestPadding tp = tpf; if (tp.b1 > 42) { // Big 'cmpb' instruction at offset 0x30 From e3f650393744790e24820b2d6d99dd1da1a44de6 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Mon, 14 Oct 2024 07:55:38 +0000 Subject: [PATCH 046/118] 8341893: AArch64: Micro-optimize compressed ptr decoding Reviewed-by: aph, fyang --- src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 16473b09fff42..9835fb5aca159 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -5011,8 +5011,10 @@ void MacroAssembler::decode_heap_oop(Register d, Register s) { verify_heapbase("MacroAssembler::decode_heap_oop: heap base corrupted?"); #endif if (CompressedOops::base() == nullptr) { - if (CompressedOops::shift() != 0 || d != s) { + if (CompressedOops::shift() != 0) { lsl(d, s, CompressedOops::shift()); + } else if (d != s) { + mov(d, s); } } else { Label done; From dcac4b0a532f2ca6cb374da7ece331e8266ab351 Mon Sep 17 00:00:00 2001 From: Fei Gao Date: Mon, 14 Oct 2024 08:40:03 +0000 Subject: [PATCH 047/118] 8341471: Reversed field layout caused by unstable sorting Reviewed-by: jwaters, jsjolen --- .../share/classfile/fieldLayoutBuilder.hpp | 10 +-- .../runtime/FieldLayout/TestFieldLayout.java | 76 +++++++++++++++++++ 2 files changed, 79 insertions(+), 7 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/FieldLayout/TestFieldLayout.java diff --git a/src/hotspot/share/classfile/fieldLayoutBuilder.hpp b/src/hotspot/share/classfile/fieldLayoutBuilder.hpp index cda64788acffa..9b0d80b2a5583 100644 --- a/src/hotspot/share/classfile/fieldLayoutBuilder.hpp +++ b/src/hotspot/share/classfile/fieldLayoutBuilder.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -101,17 +101,13 @@ class LayoutRawBlock : public ResourceObj { // sort fields in decreasing order. // Note: with line types, the comparison should include alignment constraint if sizes are equals static int compare_size_inverted(LayoutRawBlock** x, LayoutRawBlock** y) { -#ifdef _WINDOWS - // qsort() on Windows reverse the order of fields with the same size - // the extension of the comparison function below preserves this order int diff = (*y)->size() - (*x)->size(); + // qsort() may reverse the order of fields with the same size. + // The extension is to ensure stable sort. if (diff == 0) { diff = (*x)->field_index() - (*y)->field_index(); } return diff; -#else - return (*y)->size() - (*x)->size(); -#endif // _WINDOWS } }; diff --git a/test/hotspot/jtreg/runtime/FieldLayout/TestFieldLayout.java b/test/hotspot/jtreg/runtime/FieldLayout/TestFieldLayout.java new file mode 100644 index 0000000000000..4066d6dd743d5 --- /dev/null +++ b/test/hotspot/jtreg/runtime/FieldLayout/TestFieldLayout.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2024, 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. + */ + +import java.lang.reflect.Field; +import jdk.internal.misc.Unsafe; + +/* + * @test + * @bug 8341471 + * @summary Reversed field layout caused by unstable sorting + * @modules java.base/jdk.internal.misc + * @run main/othervm TestFieldLayout + */ + +public class TestFieldLayout { + + private static final Unsafe U = Unsafe.getUnsafe(); + + public static void main(String[] args) throws Exception { + + boolean endResult = true; + long previous = 0; + + for (Field f : Test.class.getDeclaredFields()) { + long current = U.objectFieldOffset(f); + if (current < previous) { + System.out.printf("FAILED: field %s offset %d previous %d\n", + f.getName(), current, previous); + endResult = false; + } + previous = current; + } + + System.out.println(endResult ? "Test PASSES" : "Test FAILS"); + if (!endResult) { + throw new Error("Test failed"); + } + } + + public class Test { + char a000; + char a001; + char a002; + char a003; + char a004; + char a005; + char a006; + char a007; + char a008; + char a009; + char a00a; + char a00b; + } + +} + From b20c5c79def1ef2cc4b587b7688f8f1d4c81d699 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Mon, 14 Oct 2024 10:34:19 +0000 Subject: [PATCH 048/118] 8341967: Unify os::current_file_offset and os::seek_to_file_offset across posix platforms Reviewed-by: jsjolen, mdoerr --- src/hotspot/os/aix/os_aix.cpp | 10 ---------- src/hotspot/os/bsd/os_bsd.cpp | 10 ---------- src/hotspot/os/linux/os_linux.cpp | 10 ---------- src/hotspot/os/posix/os_posix.cpp | 10 ++++++++++ 4 files changed, 10 insertions(+), 30 deletions(-) diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index fd16a7984a6f3..63aa53f0a2350 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -2483,16 +2483,6 @@ int os::open(const char *path, int oflag, int mode) { return fd; } -// return current position of file pointer -jlong os::current_file_offset(int fd) { - return (jlong)::lseek(fd, (off_t)0, SEEK_CUR); -} - -// move file pointer to the specified offset -jlong os::seek_to_file_offset(int fd, jlong offset) { - return (jlong)::lseek(fd, (off_t)offset, SEEK_SET); -} - // current_thread_cpu_time(bool) and thread_cpu_time(Thread*, bool) // are used by JVM M&M and JVMTI to get user+sys or user CPU time // of a thread. diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 9ad7c35e6bdef..18818268c1f9a 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -2400,16 +2400,6 @@ int os::open(const char *path, int oflag, int mode) { return fd; } -// return current position of file pointer -jlong os::current_file_offset(int fd) { - return (jlong)::lseek(fd, (off_t)0, SEEK_CUR); -} - -// move file pointer to the specified offset -jlong os::seek_to_file_offset(int fd, jlong offset) { - return (jlong)::lseek(fd, (off_t)offset, SEEK_SET); -} - // current_thread_cpu_time(bool) and thread_cpu_time(Thread*, bool) // are used by JVM M&M and JVMTI to get user+sys or user CPU time // of a thread. diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index c9968fc9f3580..c80663fec3d3a 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -5053,16 +5053,6 @@ int os::open(const char *path, int oflag, int mode) { return fd; } -// return current position of file pointer -jlong os::current_file_offset(int fd) { - return (jlong)::lseek(fd, (off_t)0, SEEK_CUR); -} - -// move file pointer to the specified offset -jlong os::seek_to_file_offset(int fd, jlong offset) { - return (jlong)::lseek(fd, (off_t)offset, SEEK_SET); -} - static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time); static jlong fast_cpu_time(Thread *thread) { diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index 60efdeb2ef59a..cc29f209160ee 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -348,6 +348,16 @@ int os::create_file_for_heap(const char* dir) { return fd; } +// return current position of file pointer +jlong os::current_file_offset(int fd) { + return (jlong)::lseek(fd, (off_t)0, SEEK_CUR); +} + +// move file pointer to the specified offset +jlong os::seek_to_file_offset(int fd, jlong offset) { + return (jlong)::lseek(fd, (off_t)offset, SEEK_SET); +} + // Is a (classpath) directory empty? bool os::dir_is_empty(const char* path) { DIR *dir = nullptr; From 1581508988141bfb420d97759138203f30926b35 Mon Sep 17 00:00:00 2001 From: Afshin Zafari Date: Mon, 14 Oct 2024 10:51:37 +0000 Subject: [PATCH 049/118] 8335091: NMT: VMATree reserve_mapping and commit_mapping APIs need MEMFLAGS while un/-committing API has no MEMFLAGS arg Reviewed-by: jsjolen, gziemski --- src/hotspot/share/nmt/vmatree.cpp | 20 +++++++++++++++- src/hotspot/share/nmt/vmatree.hpp | 32 ++++++++++++++++--------- test/hotspot/gtest/nmt/test_vmatree.cpp | 18 +++++++++++++- 3 files changed, 57 insertions(+), 13 deletions(-) diff --git a/src/hotspot/share/nmt/vmatree.cpp b/src/hotspot/share/nmt/vmatree.cpp index 3795376d4768d..65a5bdb94aef0 100644 --- a/src/hotspot/share/nmt/vmatree.cpp +++ b/src/hotspot/share/nmt/vmatree.cpp @@ -24,6 +24,7 @@ */ #include "precompiled.hpp" +#include "logging/log.hpp" #include "nmt/vmatree.hpp" #include "utilities/growableArray.hpp" @@ -34,7 +35,9 @@ const char* VMATree::statetype_strings[3] = { }; VMATree::SummaryDiff VMATree::register_mapping(position A, position B, StateType state, - const RegionData& metadata) { + const RegionData& metadata, bool use_tag_inplace) { + assert(!use_tag_inplace || metadata.mem_tag == mtNone, + "If using use_tag_inplace, then the supplied tag should be mtNone, was instead: %s", NMTUtil::tag_to_name(metadata.mem_tag)); if (A == B) { // A 0-sized mapping isn't worth recording. return SummaryDiff(); @@ -55,6 +58,10 @@ VMATree::SummaryDiff VMATree::register_mapping(position A, position B, StateType AddressState LEQ_A; TreapNode* leqA_n = _tree.closest_leq(A); if (leqA_n == nullptr) { + assert(!use_tag_inplace, "Cannot use the tag inplace if no pre-existing tag exists. From: " PTR_FORMAT " To: " PTR_FORMAT, A, B); + if (use_tag_inplace) { + log_debug(nmt)("Cannot use the tag inplace if no pre-existing tag exists. From: " PTR_FORMAT " To: " PTR_FORMAT, A, B); + } // No match. We add the A node directly, unless it would have no effect. if (!stA.is_noop()) { _tree.upsert(A, stA); @@ -62,6 +69,17 @@ VMATree::SummaryDiff VMATree::register_mapping(position A, position B, StateType } else { LEQ_A_found = true; LEQ_A = AddressState{leqA_n->key(), leqA_n->val()}; + StateType leqA_state = leqA_n->val().out.type(); + StateType new_state = stA.out.type(); + // If we specify use_tag_inplace then the new region takes over the current tag instead of the tag in metadata. + // This is important because the VirtualMemoryTracker API doesn't require supplying the tag for some operations. + if (use_tag_inplace) { + assert(leqA_n->val().out.type() != StateType::Released, "Should not use inplace the tag of a released region"); + MemTag tag = leqA_n->val().out.mem_tag(); + stA.out.set_tag(tag); + stB.in.set_tag(tag); + } + // Unless we know better, let B's outgoing state be the outgoing state of the node at or preceding A. // Consider the case where the found node is the start of a region enclosing [A,B) stB.out = leqA_n->val().out; diff --git a/src/hotspot/share/nmt/vmatree.hpp b/src/hotspot/share/nmt/vmatree.hpp index 55399e51b9d22..cfb3c8ab5246d 100644 --- a/src/hotspot/share/nmt/vmatree.hpp +++ b/src/hotspot/share/nmt/vmatree.hpp @@ -66,7 +66,7 @@ class VMATree { return statetype_strings[static_cast(type)]; } - // Each point has some stack and a flag associated with it. + // Each point has some stack and a tag associated with it. struct RegionData { const NativeCallStackStorage::StackIndex stack_idx; const MemTag mem_tag; @@ -88,30 +88,34 @@ class VMATree { struct IntervalState { private: // Store the type and mem_tag as two bytes - uint8_t type_flag[2]; + uint8_t type_tag[2]; NativeCallStackStorage::StackIndex sidx; public: - IntervalState() : type_flag{0,0}, sidx() {} + IntervalState() : type_tag{0,0}, sidx() {} IntervalState(const StateType type, const RegionData data) { assert(!(type == StateType::Released) || data.mem_tag == mtNone, "Released type must have memory tag mtNone"); - type_flag[0] = static_cast(type); - type_flag[1] = static_cast(data.mem_tag); + type_tag[0] = static_cast(type); + type_tag[1] = static_cast(data.mem_tag); sidx = data.stack_idx; } StateType type() const { - return static_cast(type_flag[0]); + return static_cast(type_tag[0]); } MemTag mem_tag() const { - return static_cast(type_flag[1]); + return static_cast(type_tag[1]); } RegionData regiondata() const { return RegionData{sidx, mem_tag()}; } + void set_tag(MemTag tag) { + type_tag[1] = static_cast(tag); + } + NativeCallStackStorage::StackIndex stack() const { return sidx; } @@ -167,14 +171,20 @@ class VMATree { } }; - SummaryDiff register_mapping(position A, position B, StateType state, const RegionData& metadata); + private: + SummaryDiff register_mapping(position A, position B, StateType state, const RegionData& metadata, bool use_tag_inplace = false); + public: SummaryDiff reserve_mapping(position from, position sz, const RegionData& metadata) { - return register_mapping(from, from + sz, StateType::Reserved, metadata); + return register_mapping(from, from + sz, StateType::Reserved, metadata, false); + } + + SummaryDiff commit_mapping(position from, position sz, const RegionData& metadata, bool use_tag_inplace = false) { + return register_mapping(from, from + sz, StateType::Committed, metadata, use_tag_inplace); } - SummaryDiff commit_mapping(position from, position sz, const RegionData& metadata) { - return register_mapping(from, from + sz, StateType::Committed, metadata); + SummaryDiff uncommit_mapping(position from, position sz, const RegionData& metadata) { + return register_mapping(from, from + sz, StateType::Reserved, metadata, true); } SummaryDiff release_mapping(position from, position sz) { diff --git a/test/hotspot/gtest/nmt/test_vmatree.cpp b/test/hotspot/gtest/nmt/test_vmatree.cpp index 08b4340ae4fb7..7a5a98b786305 100644 --- a/test/hotspot/gtest/nmt/test_vmatree.cpp +++ b/test/hotspot/gtest/nmt/test_vmatree.cpp @@ -171,7 +171,6 @@ class NMTVMATreeTest : public testing::Test { }; - TEST_VM_F(NMTVMATreeTest, OverlappingReservationsResultInTwoNodes) { VMATree::RegionData rd{si[0], mtTest}; Tree tree; @@ -181,6 +180,23 @@ TEST_VM_F(NMTVMATreeTest, OverlappingReservationsResultInTwoNodes) { EXPECT_EQ(2, count_nodes(tree)); } +TEST_VM_F(NMTVMATreeTest, UseFlagInplace) { + Tree tree; + VMATree::RegionData rd1(si[0], mtTest); + VMATree::RegionData rd2(si[1], mtNone); + tree.reserve_mapping(0, 100, rd1); + tree.commit_mapping(20, 50, rd2, true); + tree.uncommit_mapping(30, 10, rd2); + tree.visit_in_order([&](Node* node) { + if (node->key() != 100) { + EXPECT_EQ(mtTest, node->val().out.mem_tag()) << "failed at: " << node->key(); + if (node->key() != 20 && node->key() != 40) { + EXPECT_EQ(VMATree::StateType::Reserved, node->val().out.type()); + } + } + }); +} + // Low-level tests inspecting the state of the tree. TEST_VM_F(NMTVMATreeTest, LowLevel) { adjacent_2_nodes(VMATree::empty_regiondata); From ba3774dc5d27e762dfd61f8acf842ae11dec0cb7 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Mon, 14 Oct 2024 12:29:06 +0000 Subject: [PATCH 050/118] 8341637: java/net/Socket/UdpSocket.java fails with "java.net.BindException: Address already in use" (macos-aarch64) Reviewed-by: jpai --- test/jdk/java/net/Socket/UdpSocket.java | 27 ++++++++++++++++--------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/test/jdk/java/net/Socket/UdpSocket.java b/test/jdk/java/net/Socket/UdpSocket.java index a15f9255b450a..5d13c1f916a60 100644 --- a/test/jdk/java/net/Socket/UdpSocket.java +++ b/test/jdk/java/net/Socket/UdpSocket.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ @Test public class UdpSocket { + private static final int MAX_RETRIES = 3; + /** * Test using the Socket API to send/receive datagrams */ @@ -133,16 +135,21 @@ public void testMaxSockets() throws Exception { } - private Socket newUdpSocket() throws IOException { - Socket s = null; - - try { - s = new Socket(InetAddress.getLoopbackAddress(), 8000, false); - } catch (BindException unexpected) { - System.out.println("BindException caught retry Socket creation"); - s = new Socket(InetAddress.getLoopbackAddress(), 8000, false); + private Socket newUdpSocket() throws IOException, InterruptedException { + BindException unexpected = null; + for (int i=0; i < MAX_RETRIES; i++) { + try { + return new Socket(InetAddress.getLoopbackAddress(), 8000, false); + } catch (BindException be) { + unexpected = be; + if (i != MAX_RETRIES - 1) { + System.out.printf("BindException caught: retry Socket creation [%s/%s]%n", + i + 1, MAX_RETRIES); + Thread.sleep(10 + 10 * i); + } + } } - return s; + throw unexpected; } private void closeAll(Deque sockets) throws IOException { From f56a154132f7e66b1b65adfa2aa937119999b14a Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Mon, 14 Oct 2024 12:32:55 +0000 Subject: [PATCH 051/118] 8341881: [REDO] java/nio/file/attribute/BasicFileAttributeView/CreationTime.java#tmp fails on alinux3 Reviewed-by: liach, sgehwolf, ihse, bpb --- make/test/JtregNativeJdk.gmk | 2 + .../BasicFileAttributeView/CreationTime.java | 38 +++--- .../CreationTimeHelper.java | 61 +++++++++ .../libCreationTimeHelper.c | 122 ++++++++++++++++++ 4 files changed, 205 insertions(+), 18 deletions(-) create mode 100644 test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTimeHelper.java create mode 100644 test/jdk/java/nio/file/attribute/BasicFileAttributeView/libCreationTimeHelper.c diff --git a/make/test/JtregNativeJdk.gmk b/make/test/JtregNativeJdk.gmk index d9f1e334a5cf8..90055cb5c0114 100644 --- a/make/test/JtregNativeJdk.gmk +++ b/make/test/JtregNativeJdk.gmk @@ -115,6 +115,8 @@ ifeq ($(call isTargetOs, linux), true) # stripping during the test libraries' build. BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libFib := -g BUILD_JDK_JTREG_LIBRARIES_STRIP_SYMBOLS_libFib := false + # nio tests' libCreationTimeHelper native needs -ldl linker flag + BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libCreationTimeHelper := -ldl endif ifeq ($(ASAN_ENABLED), true) diff --git a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java index ad85da7ae63b1..65e801b0a9f35 100644 --- a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java +++ b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024 Alibaba Group Holding 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 @@ -25,18 +26,18 @@ * @bug 8011536 8151430 8316304 8334339 * @summary Basic test for creationTime attribute on platforms/file systems * that support it, tests using /tmp directory. - * @library ../.. /test/lib - * @build jdk.test.lib.Platform - * @run main CreationTime + * @library ../.. /test/lib /java/foreign + * @build jdk.test.lib.Platform NativeTestHelper + * @run main/othervm/native --enable-native-access=ALL-UNNAMED CreationTime */ /* @test id=cwd * @summary Basic test for creationTime attribute on platforms/file systems * that support it, tests using the test scratch directory, the test * scratch directory maybe at diff disk partition to /tmp on linux. - * @library ../.. /test/lib - * @build jdk.test.lib.Platform - * @run main CreationTime . + * @library ../.. /test/lib /java/foreign + * @build jdk.test.lib.Platform NativeTestHelper + * @run main/othervm/native --enable-native-access=ALL-UNNAMED CreationTime . */ import java.lang.foreign.Linker; @@ -51,8 +52,6 @@ public class CreationTime { - private static final java.io.PrintStream err = System.err; - /** * Reads the creationTime attribute */ @@ -78,14 +77,9 @@ static void test(Path top) throws IOException { FileTime creationTime = creationTime(file); Instant now = Instant.now(); if (Math.abs(creationTime.toMillis()-now.toEpochMilli()) > 10000L) { - System.out.println("creationTime.toMillis() == " + creationTime.toMillis()); - // If the file system doesn't support birth time, then skip this test - if (creationTime.toMillis() == 0) { - throw new SkippedException("birth time not support for: " + file); - } else { - err.println("File creation time reported as: " + creationTime); - throw new RuntimeException("Expected to be close to: " + now); - } + System.err.println("creationTime.toMillis() == " + creationTime.toMillis()); + System.err.println("File creation time reported as: " + creationTime); + throw new RuntimeException("Expected to be close to: " + now); } /** @@ -107,7 +101,12 @@ static void test(Path top) throws IOException { } } else if (Platform.isLinux()) { // Creation time read depends on statx system call support - supportsCreationTimeRead = Linker.nativeLinker().defaultLookup().find("statx").isPresent(); + try { + supportsCreationTimeRead = CreationTimeHelper. + linuxIsCreationTimeSupported(file.toAbsolutePath().toString()); + } catch (Throwable e) { + supportsCreationTimeRead = false; + } // Creation time updates are not supported on Linux supportsCreationTimeWrite = false; } @@ -122,8 +121,11 @@ static void test(Path top) throws IOException { Instant plusHour = Instant.now().plusSeconds(60L * 60L); Files.setLastModifiedTime(file, FileTime.from(plusHour)); FileTime current = creationTime(file); - if (!current.equals(creationTime)) + if (!current.equals(creationTime)) { + System.err.println("current = " + current); + System.err.println("creationTime = " + creationTime); throw new RuntimeException("Creation time should not have changed"); + } } /** diff --git a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTimeHelper.java b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTimeHelper.java new file mode 100644 index 0000000000000..592aeba322dd0 --- /dev/null +++ b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTimeHelper.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024 Alibaba Group Holding 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. + */ + +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; + +public class CreationTimeHelper extends NativeTestHelper { + + static { + System.loadLibrary("CreationTimeHelper"); + } + + final static Linker abi = Linker.nativeLinker(); + static final SymbolLookup lookup = SymbolLookup.loaderLookup(); + final static MethodHandle methodHandle = abi. + downcallHandle(lookup.findOrThrow("linuxIsCreationTimeSupported"), + FunctionDescriptor.of(C_BOOL, C_POINTER)); + + // Helper so as to determine birth time support or not on Linux. + // Support is determined in a two-step process: + // 1. Determine if `statx` system call is available. If available proceed, + // otherwise return false. + // 2. Perform an actual `statx` call on the given file and check for birth + // time support in the mask returned from the call. This is needed, + // since some file systems, like nfs/tmpfs etc., don't support birth + // time even though the `statx` system call is available. + static boolean linuxIsCreationTimeSupported(String file) throws Throwable { + if (!abi.defaultLookup().find("statx").isPresent()) { + return false; + } + try (var arena = Arena.ofConfined()) { + MemorySegment s = arena.allocateFrom(file); + return (boolean)methodHandle.invokeExact(s); + } + } +} diff --git a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/libCreationTimeHelper.c b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/libCreationTimeHelper.c new file mode 100644 index 0000000000000..fb518b3b701eb --- /dev/null +++ b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/libCreationTimeHelper.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2024 Alibaba Group Holding 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. + */ +#include "export.h" +#include +#if defined(__linux__) +#include +#include +#include +#include +#include +#ifndef STATX_BASIC_STATS +#define STATX_BASIC_STATS 0x000007ffU +#endif +#ifndef STATX_BTIME +#define STATX_BTIME 0x00000800U +#endif +#ifndef RTLD_DEFAULT +#define RTLD_DEFAULT RTLD_LOCAL +#endif +#ifndef AT_SYMLINK_NOFOLLOW +#define AT_SYMLINK_NOFOLLOW 0x100 +#endif +#ifndef AT_FDCWD +#define AT_FDCWD -100 +#endif + +/* + * Timestamp structure for the timestamps in struct statx. + */ +struct my_statx_timestamp { + __int64_t tv_sec; + __uint32_t tv_nsec; + __int32_t __reserved; +}; + +/* + * struct statx used by statx system call on >= glibc 2.28 + * systems + */ +struct my_statx +{ + __uint32_t stx_mask; + __uint32_t stx_blksize; + __uint64_t stx_attributes; + __uint32_t stx_nlink; + __uint32_t stx_uid; + __uint32_t stx_gid; + __uint16_t stx_mode; + __uint16_t __statx_pad1[1]; + __uint64_t stx_ino; + __uint64_t stx_size; + __uint64_t stx_blocks; + __uint64_t stx_attributes_mask; + struct my_statx_timestamp stx_atime; + struct my_statx_timestamp stx_btime; + struct my_statx_timestamp stx_ctime; + struct my_statx_timestamp stx_mtime; + __uint32_t stx_rdev_major; + __uint32_t stx_rdev_minor; + __uint32_t stx_dev_major; + __uint32_t stx_dev_minor; + __uint64_t __statx_pad2[14]; +}; + +typedef int statx_func(int dirfd, const char *restrict pathname, int flags, + unsigned int mask, struct my_statx *restrict statxbuf); + +static statx_func* my_statx_func = NULL; +#endif //#defined(__linux__) + +// static boolean linuxIsCreationTimeSupported(char* file) +EXPORT bool linuxIsCreationTimeSupported(char* file) { +#if defined(__linux__) + struct my_statx stx = {0}; + int ret, atflag = AT_SYMLINK_NOFOLLOW; + unsigned int mask = STATX_BASIC_STATS | STATX_BTIME; + + my_statx_func = (statx_func*) dlsym(RTLD_DEFAULT, "statx"); + if (my_statx_func == NULL) { + return false; + } + + if (file == NULL) { + printf("input file error!\n"); + return false; + } + + ret = my_statx_func(AT_FDCWD, file, atflag, mask, &stx); + if (ret != 0) { + return false; + } + // On some systems where statx is available but birth time might still not + // be supported as it's file system specific. The only reliable way to + // check for supported or not is looking at the filled in STATX_BTIME bit + // in the returned statx buffer mask. + if ((stx.stx_mask & STATX_BTIME) != 0) + return true; + return false; +#else + return false; +#endif +} From 9e262df813874043f72b60695a88c28fc7d5cccb Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Mon, 14 Oct 2024 16:00:04 +0000 Subject: [PATCH 052/118] 8342002: sun/security/tools/keytool/GenKeyPairSigner.java failed due to missing certificate output Reviewed-by: mullan --- test/jdk/ProblemList.txt | 2 -- .../security/tools/keytool/GenKeyPairSigner.java | 14 +++++++------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 0aa27e4ac0ce6..034830a2575a5 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -644,8 +644,6 @@ sun/security/provider/PolicyParser/PrincipalExpansionError.java 8039280 generic- sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java 8316183 linux-ppc64le -sun/security/tools/keytool/GenKeyPairSigner.java 8342002 generic-all - ############################################################################ # jdk_sound diff --git a/test/jdk/sun/security/tools/keytool/GenKeyPairSigner.java b/test/jdk/sun/security/tools/keytool/GenKeyPairSigner.java index 52ca1ead82c5a..84cfcd7cb17de 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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -84,7 +84,7 @@ static void testSignerPKCS12() throws Exception { System.out.println("Generating an XDH cert with -signer option"); SecurityTools.keytool("-keystore ks -storepass changeit " + "-genkeypair -keyalg XDH -alias e1 -dname CN=E1 -signer ca") - .shouldContain("Generating 255 bit XDH key pair and a certificate (Ed25519) issued by with a validity of 90 days") + .shouldContain("Generating 255 bit X25519 key pair and a certificate (Ed25519) issued by with a validity of 90 days") .shouldContain("for: CN=E1") .shouldHaveExitValue(0); @@ -118,7 +118,7 @@ static void testSignerPKCS12() throws Exception { .shouldContain("Alias name: e1") .shouldContain("Certificate chain length: 2") .shouldContain("Signature algorithm name: Ed25519") - .shouldContain("Subject Public Key Algorithm: 255-bit XDH key") + .shouldContain("Subject Public Key Algorithm: 255-bit X25519 key") .shouldHaveExitValue(0); // check to make sure that cert's AKID is created from the SKID of the signing cert @@ -150,7 +150,7 @@ static void testSignerPKCS12() throws Exception { System.out.println("Generating an X448 cert with -signer option"); SecurityTools.keytool("-keystore ks -storepass changeit " + "-genkeypair -keyalg X448 -alias e2 -dname CN=E2 -sigalg SHA384withRSA -signer ca2") - .shouldContain("Generating 448 bit XDH key pair and a certificate (SHA384withRSA) issued by with a validity of 90 days") + .shouldContain("Generating 448 bit X448 key pair and a certificate (SHA384withRSA) issued by with a validity of 90 days") .shouldContain("for: CN=E2") .shouldHaveExitValue(0); @@ -177,7 +177,7 @@ static void testSignerPKCS12() throws Exception { "-list -v") .shouldContain("Alias name: e2") .shouldContain("Signature algorithm name: SHA384withRSA") - .shouldContain("Subject Public Key Algorithm: 448-bit XDH key") + .shouldContain("Subject Public Key Algorithm: 448-bit X448 key") .shouldHaveExitValue(0); kt("-genkeypair -keyalg DSA -alias ca3 -dname CN=CA3 -ext bc:c ", @@ -249,7 +249,7 @@ static void testSignerJKS() throws Exception { SecurityTools.keytool("-keystore ksjks -storepass changeit -storetype jks " + "-genkeypair -keyalg XDH -alias e1 -dname CN=E1 " + "-keypass e1keypass -signer ca1 -signerkeypass ca1keypass") - .shouldContain("Generating 255 bit XDH key pair and a certificate (SHA256withDSA) issued by with a validity of 90 days") + .shouldContain("Generating 255 bit X25519 key pair and a certificate (SHA256withDSA) issued by with a validity of 90 days") .shouldContain("for: CN=E1") .shouldContain("The generated certificate #2 of 3 uses a 1024-bit DSA key which is considered a security risk") .shouldContain("The generated certificate #3 of 3 uses a 1024-bit RSA key which is considered a security risk") @@ -285,7 +285,7 @@ static void testSignerJKS() throws Exception { .shouldContain("Alias name: e1") .shouldContain("Certificate chain length: 3") .shouldContain("Signature algorithm name: SHA256withDSA") - .shouldContain("Subject Public Key Algorithm: 255-bit XDH key") + .shouldContain("Subject Public Key Algorithm: 255-bit X25519 key") .shouldHaveExitValue(0); } From a8a8b2deba854ac105ed760c09e65701c4d0f6fc Mon Sep 17 00:00:00 2001 From: Igor Veresov Date: Mon, 14 Oct 2024 16:44:53 +0000 Subject: [PATCH 053/118] 8341831: PhaseCFG::insert_anti_dependences asserts with "no loads" Reviewed-by: dlong, kvn --- src/hotspot/share/opto/gcm.cpp | 12 +++++++++++- test/hotspot/jtreg/ProblemList.txt | 2 -- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/opto/gcm.cpp b/src/hotspot/share/opto/gcm.cpp index dd51bb4709452..c46d69058e99d 100644 --- a/src/hotspot/share/opto/gcm.cpp +++ b/src/hotspot/share/opto/gcm.cpp @@ -763,7 +763,17 @@ Block* PhaseCFG::insert_anti_dependences(Block* LCA, Node* load, bool verify) { worklist_def_use_mem_states.pop(); uint op = use_mem_state->Opcode(); - assert(!use_mem_state->needs_anti_dependence_check(), "no loads"); + +#ifdef ASSERT + // CacheWB nodes are peculiar in a sense that they both are anti-dependent and produce memory. + // Allow them to be treated as a store. + bool is_cache_wb = false; + if (use_mem_state->is_Mach()) { + int ideal_op = use_mem_state->as_Mach()->ideal_Opcode(); + is_cache_wb = (ideal_op == Op_CacheWB); + } + assert(!use_mem_state->needs_anti_dependence_check() || is_cache_wb, "no loads"); +#endif // MergeMems do not directly have anti-deps. // Treat them as internal nodes in a forward tree of memory states, diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index e85b742a53b8b..3ff450dc3ad92 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -43,8 +43,6 @@ # :hotspot_compiler -applications/ctw/modules/java_base_2.java 8341831 linux-x64 - compiler/ciReplay/TestSAServer.java 8029528 generic-all compiler/compilercontrol/jcmd/ClearDirectivesFileStackTest.java 8225370 generic-all From 60713463c7014e4e15da73023e82ef58d7134b48 Mon Sep 17 00:00:00 2001 From: Alisen Chung Date: Mon, 14 Oct 2024 16:45:59 +0000 Subject: [PATCH 054/118] 8339879: Open some dialog awt tests Reviewed-by: honkar, prr --- test/jdk/java/awt/Dialog/DefaultIconTest.java | 71 ++++ .../awt/Dialog/DialogInitialResizability.java | 96 ++++++ .../jdk/java/awt/Dialog/NestedDialogTest.java | 312 ++++++++++++++++++ .../ShownModalDialogSerializationTest.java | 92 ++++++ 4 files changed, 571 insertions(+) create mode 100644 test/jdk/java/awt/Dialog/DefaultIconTest.java create mode 100644 test/jdk/java/awt/Dialog/DialogInitialResizability.java create mode 100644 test/jdk/java/awt/Dialog/NestedDialogTest.java create mode 100644 test/jdk/java/awt/Dialog/ShownModalDialogSerializationTest.java diff --git a/test/jdk/java/awt/Dialog/DefaultIconTest.java b/test/jdk/java/awt/Dialog/DefaultIconTest.java new file mode 100644 index 0000000000000..8d2ec8c406f0a --- /dev/null +++ b/test/jdk/java/awt/Dialog/DefaultIconTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * 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.Dialog; +import java.awt.Frame; + +/* + * @test + * @bug 4964237 + * @requires (os.family == "windows") + * @summary Win: Changing theme changes java dialogs title icon + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DefaultIconTest + */ + +public class DefaultIconTest { + static String instructions = """ + This test shows frame and two dialogs + Change windows theme. Resizable dialog should retain default icon + Non-resizable dialog should retain no icon + Press PASS if icons look correct, FAIL otherwise + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("ShownModalDialogSerializationTest Instructions") + .instructions(instructions) + .testTimeOut(5) + .rows(10) + .columns(35) + .testUI(DefaultIconTest::createGUIs) + .build() + .awaitAndCheck(); + } + + public static Frame createGUIs() { + Frame f = new Frame("DefaultIconTest"); + f.setSize(200, 100); + Dialog d1 = new Dialog(f, "Resizable Dialog, should show default icon"); + d1.setSize(200, 100); + d1.setVisible(true); + d1.setLocation(0, 150); + Dialog d2 = new Dialog(f, "Non-resizable dialog, should have no icon"); + d2.setSize(200, 100); + d2.setVisible(true); + d2.setResizable(false); + d2.setLocation(0, 300); + return f; + } +} diff --git a/test/jdk/java/awt/Dialog/DialogInitialResizability.java b/test/jdk/java/awt/Dialog/DialogInitialResizability.java new file mode 100644 index 0000000000000..7ecde39c4add1 --- /dev/null +++ b/test/jdk/java/awt/Dialog/DialogInitialResizability.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * 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.Dialog; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; + +/* + * @test + * @bug 4912551 + * @summary Checks that with resizable set to false before show() + * dialog can not be resized. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DialogInitialResizability + */ + +public class DialogInitialResizability { + static String instructions = """ + When this test is run a dialog will display (setResizable Test). + This dialog should not be resizable. + + Additionally ensure that there are NO componentResized events in the log section. + If the above conditions are true, then Press PASS else FAIL. + """; + + private static final Dimension INITIAL_SIZE = new Dimension(400, 150); + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("DialogInitialResizability") + .instructions(instructions) + .testTimeOut(5) + .rows((int) instructions.lines().count() + 2) + .columns(40) + .testUI(DialogInitialResizability::createGUI) + .logArea() + .build() + .awaitAndCheck(); + } + + public static MyDialog createGUI() { + Frame f = new Frame("invisible dialog owner"); + + MyDialog ld = new MyDialog(f); + ld.setBounds(100, 100, INITIAL_SIZE.width, INITIAL_SIZE.height); + ld.setResizable(false); + + PassFailJFrame.log("Dialog isResizable is set to: " + ld.isResizable()); + PassFailJFrame.log("Dialog Initial Size " + ld.getSize()); + return ld; + } + + private static class MyDialog extends Dialog implements ComponentListener { + public MyDialog(Frame f) { + super(f, "setResizable test", false); + this.addComponentListener(this); + } + + public void componentResized(ComponentEvent e) { + if (!e.getComponent().getSize().equals(INITIAL_SIZE)) { + PassFailJFrame.log("Component Resized. Test Failed!!"); + } + } + + public void componentMoved(ComponentEvent e) { + } + + public void componentShown(ComponentEvent e) { + } + + public void componentHidden(ComponentEvent e) { + } + } +} diff --git a/test/jdk/java/awt/Dialog/NestedDialogTest.java b/test/jdk/java/awt/Dialog/NestedDialogTest.java new file mode 100644 index 0000000000000..28fb1bc919e6a --- /dev/null +++ b/test/jdk/java/awt/Dialog/NestedDialogTest.java @@ -0,0 +1,312 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * 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.Button; +import java.awt.Choice; +import java.awt.Dialog; +import java.awt.FileDialog; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.List; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.Vector; +import java.util.Enumeration; + +/* + * @test + * @bug 4110094 4178930 4178390 + * @summary Test: Rewrite of Win modal dialogs + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual NestedDialogTest + */ + +public class NestedDialogTest { + private static Vector windows = new Vector(); + static String instructions = """ + To solve various race conditions, windows modal dialogs were rewritten. This + test exercises various modal dialog boundary conditions and checks that + previous fixes to modality are incorporated in the rewrite. + + Check the following: + - No IllegalMonitorStateException is thrown when a dialog closes + + - Open multiple nested dialogs and verify that all other windows + are disabled when modal dialog is active. + + - Check that the proper window is activated when a modal dialog closes. + + - Close nested dialogs out of order (e.g. close dialog1 before dialog2) + and verify that this works and no deadlock occurs. + + - Check that all other windows are disabled when a FileDialog is open. + + - Check that the proper window is activated when a FileDialog closes. + + - Verify that the active window nevers switches to another application + when closing dialogs, even temporarily. + + - Check that choosing Hide always sucessfully hides a dialog. You should + try this multiple times to catch any race conditions. + + - Check that the scrollbar on the Choice component in the dialog works, as opposed + to just using drag-scrolling or the cursor keys + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("NestedDialogTest") + .instructions(instructions) + .testTimeOut(5) + .rows((int) instructions.lines().count() + 2) + .columns(35) + .testUI(NestedDialogTest::createGUI) + .build() + .awaitAndCheck(); + } + + public static Frame createGUI() { + Frame frame1 = new NestedDialogTestFrame("frame0"); + Frame frame2 = new NestedDialogTestFrame("frame1"); + frame2.setLocation(100, 100); + return frame1; + } + + public static void addWindow(Window window) { + // System.out.println("Pushing window " + window); + windows.removeElement(window); + windows.addElement(window); + } + + public static void removeWindow(Window window) { + // System.out.println("Popping window " + window); + windows.removeElement(window); + } + + public static Window getWindow(int index) { + return (Window) windows.elementAt(index); + } + + public static Enumeration enumWindows() { + return windows.elements(); + } + + public static int getWindowIndex(Window win) { + return windows.indexOf(win); + } +} + +class NestedDialogTestFrame extends Frame { + NestedDialogTestFrame(String name) { + super(name); + setSize(200, 200); + show(); + + setLayout(new FlowLayout()); + Button btnDlg = new Button("Dialog..."); + add(btnDlg); + Button btnFileDlg = new Button("FileDialog..."); + add(btnFileDlg); + + addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent ev) { + System.exit(0); + } + }); + + btnDlg.addActionListener( + new ActionListener() { + public void actionPerformed(ActionEvent e) { + Dialog d1 = new SimpleDialog(NestedDialogTestFrame.this, null, true); + System.out.println("Returned from showing dialog: " + d1); + } + } + ); + + btnFileDlg.addActionListener( + new ActionListener() { + public void actionPerformed(ActionEvent e) { + FileDialog dlg = new FileDialog(NestedDialogTestFrame.this); + dlg.show(); + } + } + ); + + validate(); + } + + public void show() { + if (!isVisible()) { + NestedDialogTest.addWindow(this); + } + super.show(); + } + + public void dispose() { + NestedDialogTest.removeWindow(this); + super.dispose(); + } +} + +class SimpleDialog extends Dialog { + Button btnNested; + Button btnFileDlg; + Button btnShow; + Button btnHide; + Button btnDispose; + Button btnExit; + List listWins; + Dialog dlgPrev; + + public SimpleDialog(Frame frame, Dialog prev, boolean isModal) { + super(frame, "", isModal); + + dlgPrev = prev; + + addWindowListener(new WindowAdapter() { + public void windowActivated(WindowEvent ev) { + populateListWin(); + } + }); + + setTitle(getName()); + + Panel panelNorth = new Panel(); + panelNorth.setLayout(new GridLayout(1, 1)); + listWins = new List(); + panelNorth.add(listWins); + + Panel panelSouth = new Panel(); + panelSouth.setLayout(new FlowLayout()); + btnNested = new Button("Dialog..."); + panelSouth.add(btnNested); + btnFileDlg = new Button("FileDialog..."); + panelSouth.add(btnFileDlg); + btnShow = new Button("Show"); + panelSouth.add(btnShow); + btnHide = new Button("Hide"); + panelSouth.add(btnHide); + btnDispose = new Button("Dispose"); + panelSouth.add(btnDispose); + + Choice cbox = new Choice(); + cbox.add("Test1"); + cbox.add("Test2"); + cbox.add("Test3"); + cbox.add("Test4"); + cbox.add("Test5"); + cbox.add("Test6"); + cbox.add("Test7"); + cbox.add("Test8"); + cbox.add("Test9"); + cbox.add("Test10"); + cbox.add("Test11"); + panelSouth.add(cbox); + + validate(); + + add("Center", panelNorth); + add("South", panelSouth); + + btnNested.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + Dialog dlg = new SimpleDialog((Frame) getParent(), SimpleDialog.this, true); + System.out.println("Returned from showing dialog: " + dlg); + } + }); + + btnFileDlg.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + FileDialog dlg = new FileDialog((Frame) getParent()); + dlg.show(); + } + }); + + btnHide.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + Window wnd = getSelectedWindow(); + System.out.println(wnd); + wnd.hide(); + } + }); + + btnShow.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + getSelectedWindow().show(); + } + }); + + btnDispose.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + getSelectedWindow().dispose(); + populateListWin(); + } + }); + + pack(); + setSize(getSize().width, getSize().height * 2); + if (dlgPrev != null) { + Point pt = dlgPrev.getLocation(); + setLocation(pt.x + 30, pt.y + 50); + } + show(); + } + + private Window getSelectedWindow() { + Window window; + int index = listWins.getSelectedIndex(); + + window = NestedDialogTest.getWindow(index); + return window; + } + + private void populateListWin() { + Enumeration enumWindows = NestedDialogTest.enumWindows(); + + listWins.removeAll(); + while (enumWindows.hasMoreElements()) { + Window win = (Window) enumWindows.nextElement(); + listWins.add(win.getName()); + } + listWins.select(NestedDialogTest.getWindowIndex(this)); + } + + public void show() { + if (!isVisible()) { + NestedDialogTest.addWindow(this); + } + super.show(); + } + + public void dispose() { + NestedDialogTest.removeWindow(this); + super.dispose(); + } +} diff --git a/test/jdk/java/awt/Dialog/ShownModalDialogSerializationTest.java b/test/jdk/java/awt/Dialog/ShownModalDialogSerializationTest.java new file mode 100644 index 0000000000000..b57dd2cf8f238 --- /dev/null +++ b/test/jdk/java/awt/Dialog/ShownModalDialogSerializationTest.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * 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.Dialog; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Label; + +import java.awt.TextArea; +import java.io.File; +import java.io.FileOutputStream; +import java.io.ObjectOutputStream; + +/* + * @test + * @bug 4739757 + * @summary REGRESSION: Modal Dialog is not serializable after showing + * @key headful + * @run main ShownModalDialogSerializationTest + */ + +public class ShownModalDialogSerializationTest { + static volatile Frame frame; + static volatile Frame outputFrame; + static volatile Dialog dialog; + + public static void main(String[] args) throws Exception { + + EventQueue.invokeLater(ShownModalDialogSerializationTest::createTestUI); + + while (dialog == null || !dialog.isShowing()) { + Thread.sleep(500); + } + File file = new File("dialog.ser"); + FileOutputStream fos = new FileOutputStream(file); + ObjectOutputStream oos = new ObjectOutputStream(fos); + oos.writeObject(dialog); + oos.flush(); + file.delete(); + + EventQueue.invokeAndWait(ShownModalDialogSerializationTest::deleteTestUI); + } + + static void deleteTestUI() { + if (dialog != null) { + dialog.setVisible(false); + dialog.dispose(); + } + if (frame != null) { + frame.setVisible(false); + frame.dispose(); + } + if (outputFrame != null) { + outputFrame.setVisible(false); + outputFrame.dispose(); + } + } + + private static void createTestUI() { + outputFrame = new Frame("ShownModalDialogSerializationTest"); + TextArea output = new TextArea(40, 50); + outputFrame.add(output); + + frame = new Frame("invisible dialog owner"); + dialog = new Dialog(frame, "Dialog for Close", true); + dialog.add(new Label("Close This Dialog")); + outputFrame.setSize(200, 200); + outputFrame.setVisible(true); + dialog.pack(); + dialog.setVisible(true); + } +} From a2c775222e17a3ba2e388c9a0eb9ffd33efad219 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Mon, 14 Oct 2024 17:21:10 +0000 Subject: [PATCH 055/118] 8317356: Fix missing null checks in the ClassFile API Co-authored-by: Nizar Benalla Reviewed-by: asotona --- .../java/lang/classfile/AnnotationValue.java | 17 ++- .../lang/classfile/AttributedElement.java | 4 + .../classfile/ClassHierarchyResolver.java | 10 +- .../java/lang/classfile/ClassTransform.java | 14 ++- .../java/lang/classfile/CodeTransform.java | 7 +- .../java/lang/classfile/FieldTransform.java | 8 +- .../java/lang/classfile/MethodTransform.java | 9 +- .../classfile/components/ClassRemapper.java | 7 +- .../classfile/components/CodeRelabeler.java | 5 +- .../instruction/DiscontinuedInstruction.java | 2 +- .../java/lang/invoke/MethodHandleProxies.java | 4 +- .../classfile/impl/AbstractInstruction.java | 31 ++--- .../classfile/impl/AbstractPoolEntry.java | 4 +- .../impl/AbstractPseudoInstruction.java | 25 ++-- .../classfile/impl/AnnotationImpl.java | 8 ++ .../classfile/impl/BlockCodeBuilderImpl.java | 4 +- .../classfile/impl/BufferedCodeBuilder.java | 4 +- .../classfile/impl/BufferedFieldBuilder.java | 8 +- .../classfile/impl/BufferedMethodBuilder.java | 8 +- .../classfile/impl/BytecodeHelpers.java | 5 +- .../classfile/impl/ChainedClassBuilder.java | 4 +- .../classfile/impl/ChainedCodeBuilder.java | 6 +- .../classfile/impl/ChainedFieldBuilder.java | 4 +- .../classfile/impl/ChainedMethodBuilder.java | 4 +- .../classfile/impl/ClassFileImpl.java | 4 +- .../classfile/impl/ClassHierarchyImpl.java | 4 +- .../classfile/impl/ClassPrinterImpl.java | 2 + .../classfile/impl/DirectClassBuilder.java | 8 +- .../classfile/impl/DirectCodeBuilder.java | 3 +- .../classfile/impl/DirectFieldBuilder.java | 8 +- .../classfile/impl/DirectMethodBuilder.java | 8 +- .../classfile/impl/SplitConstantPool.java | 2 + .../classfile/impl/StackMapDecoder.java | 8 ++ .../classfile/impl/TargetInfoImpl.java | 4 +- .../classfile/impl/TemporaryConstantPool.java | 2 + .../classfile/impl/UnboundAttribute.java | 110 ++++++++++++------ 36 files changed, 249 insertions(+), 116 deletions(-) diff --git a/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java b/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java index 50bfa0b7aa6fb..fe768e93b1308 100644 --- a/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java +++ b/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java @@ -42,6 +42,8 @@ import jdk.internal.classfile.impl.Util; import jdk.internal.javac.PreviewFeature; +import static java.util.Objects.requireNonNull; + /** * Models an {@code element_value} structure, or a value of an element-value * pair of an annotation, as defined in JVMS {@jvms 4.7.16.1}. @@ -488,6 +490,8 @@ default ClassDesc classSymbol() { */ static OfEnum ofEnum(Utf8Entry className, Utf8Entry constantName) { + requireNonNull(className); + requireNonNull(constantName); return new AnnotationImpl.OfEnumImpl(className, constantName); } @@ -506,6 +510,7 @@ static OfEnum ofEnum(ClassDesc className, String constantName) { * @param className the descriptor string of the class */ static OfClass ofClass(Utf8Entry className) { + requireNonNull(className); return new AnnotationImpl.OfClassImpl(className); } @@ -522,6 +527,7 @@ static OfClass ofClass(ClassDesc className) { * @param value the string */ static OfString ofString(Utf8Entry value) { + requireNonNull(value); return new AnnotationImpl.OfStringImpl(value); } @@ -538,6 +544,7 @@ static OfString ofString(String value) { * @param value the double value */ static OfDouble ofDouble(DoubleEntry value) { + requireNonNull(value); return new AnnotationImpl.OfDoubleImpl(value); } @@ -554,6 +561,7 @@ static OfDouble ofDouble(double value) { * @param value the float value */ static OfFloat ofFloat(FloatEntry value) { + requireNonNull(value); return new AnnotationImpl.OfFloatImpl(value); } @@ -570,6 +578,7 @@ static OfFloat ofFloat(float value) { * @param value the long value */ static OfLong ofLong(LongEntry value) { + requireNonNull(value); return new AnnotationImpl.OfLongImpl(value); } @@ -586,6 +595,7 @@ static OfLong ofLong(long value) { * @param value the int value */ static OfInt ofInt(IntegerEntry value) { + requireNonNull(value); return new AnnotationImpl.OfIntImpl(value); } @@ -602,6 +612,7 @@ static OfInt ofInt(int value) { * @param value the short value */ static OfShort ofShort(IntegerEntry value) { + requireNonNull(value); return new AnnotationImpl.OfShortImpl(value); } @@ -618,6 +629,7 @@ static OfShort ofShort(short value) { * @param value the char value */ static OfChar ofChar(IntegerEntry value) { + requireNonNull(value); return new AnnotationImpl.OfCharImpl(value); } @@ -634,6 +646,7 @@ static OfChar ofChar(char value) { * @param value the byte value */ static OfByte ofByte(IntegerEntry value) { + requireNonNull(value); return new AnnotationImpl.OfByteImpl(value); } @@ -650,6 +663,7 @@ static OfByte ofByte(byte value) { * @param value the boolean value */ static OfBoolean ofBoolean(IntegerEntry value) { + requireNonNull(value); return new AnnotationImpl.OfBooleanImpl(value); } @@ -667,6 +681,7 @@ static OfBoolean ofBoolean(boolean value) { * @param value the annotation */ static OfAnnotation ofAnnotation(Annotation value) { + requireNonNull(value); return new AnnotationImpl.OfAnnotationImpl(value); } @@ -784,6 +799,6 @@ static AnnotationValue of(Object value) { } else if (value instanceof Enum e) { return ofEnum(ClassDesc.ofDescriptor(e.getDeclaringClass().descriptorString()), e.name()); } - throw new IllegalArgumentException("Illegal annotation constant value type " + (value == null ? null : value.getClass())); + throw new IllegalArgumentException("Illegal annotation constant value type " + requireNonNull(value).getClass()); } } diff --git a/src/java.base/share/classes/java/lang/classfile/AttributedElement.java b/src/java.base/share/classes/java/lang/classfile/AttributedElement.java index d66806ca93b43..0caf231ec2a10 100644 --- a/src/java.base/share/classes/java/lang/classfile/AttributedElement.java +++ b/src/java.base/share/classes/java/lang/classfile/AttributedElement.java @@ -33,6 +33,8 @@ import jdk.internal.classfile.impl.AbstractUnboundModel; import jdk.internal.javac.PreviewFeature; +import static java.util.Objects.requireNonNull; + /** * A {@link ClassFileElement} describing an entity that has attributes, such * as a class, field, method, code attribute, or record component. @@ -58,6 +60,7 @@ public sealed interface AttributedElement extends ClassFileElement * is not present */ default > Optional findAttribute(AttributeMapper attr) { + requireNonNull(attr); for (Attribute la : attributes()) { if (la.attributeMapper() == attr) { @SuppressWarnings("unchecked") @@ -76,6 +79,7 @@ default > Optional findAttribute(AttributeMapper at * is not present */ default > List findAttributes(AttributeMapper attr) { + requireNonNull(attr); var list = new ArrayList(); for (var a : attributes()) { if (a.attributeMapper() == attr) { diff --git a/src/java.base/share/classes/java/lang/classfile/ClassHierarchyResolver.java b/src/java.base/share/classes/java/lang/classfile/ClassHierarchyResolver.java index 589713c8e95c8..3f16ce8402492 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassHierarchyResolver.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassHierarchyResolver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ import jdk.internal.classfile.impl.Util; import static java.lang.constant.ConstantDescs.CD_Object; +import static java.util.Objects.requireNonNull; + import jdk.internal.javac.PreviewFeature; /** @@ -106,6 +108,7 @@ static ClassHierarchyInfo ofInterface() { * other resolver in cases where this resolver returns {@code null}. */ default ClassHierarchyResolver orElse(ClassHierarchyResolver other) { + requireNonNull(other); return new ClassHierarchyResolver() { @Override public ClassHierarchyInfo getClassInfo(ClassDesc classDesc) { @@ -170,7 +173,7 @@ public Map get() { * @return the {@linkplain ClassHierarchyResolver} */ static ClassHierarchyResolver ofResourceParsing(Function classStreamResolver) { - return new ClassHierarchyImpl.ResourceParsingClassHierarchyResolver(classStreamResolver); + return new ClassHierarchyImpl.ResourceParsingClassHierarchyResolver(requireNonNull(classStreamResolver)); } /** @@ -181,6 +184,7 @@ static ClassHierarchyResolver ofResourceParsing(Function * @return the {@linkplain ClassHierarchyResolver} */ static ClassHierarchyResolver ofResourceParsing(ClassLoader loader) { + requireNonNull(loader); return ofResourceParsing(new Function<>() { @Override public InputStream apply(ClassDesc classDesc) { @@ -210,6 +214,7 @@ static ClassHierarchyResolver of(Collection interfaces, * @return the class hierarchy resolver */ static ClassHierarchyResolver ofClassLoading(ClassLoader loader) { + requireNonNull(loader); return new ClassLoadingClassHierarchyResolver(new Function<>() { @Override public Class apply(ClassDesc cd) { @@ -232,6 +237,7 @@ public Class apply(ClassDesc cd) { * @return the class hierarchy resolver */ static ClassHierarchyResolver ofClassLoading(MethodHandles.Lookup lookup) { + requireNonNull(lookup); return new ClassLoadingClassHierarchyResolver(new Function<>() { @Override public Class apply(ClassDesc cd) { diff --git a/src/java.base/share/classes/java/lang/classfile/ClassTransform.java b/src/java.base/share/classes/java/lang/classfile/ClassTransform.java index 743a39851148a..230b436b138ad 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassTransform.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassTransform.java @@ -32,6 +32,8 @@ import jdk.internal.classfile.impl.TransformImpl; import jdk.internal.javac.PreviewFeature; +import static java.util.Objects.requireNonNull; + /** * A transformation on streams of {@link ClassElement}. * @@ -63,7 +65,7 @@ public void accept(ClassBuilder builder, ClassElement element) { * @return the stateful class transform */ static ClassTransform ofStateful(Supplier supplier) { - return new TransformImpl.SupplierClassTransform(supplier); + return new TransformImpl.SupplierClassTransform(requireNonNull(supplier)); } /** @@ -74,6 +76,7 @@ static ClassTransform ofStateful(Supplier supplier) { * @return the class transform */ static ClassTransform endHandler(Consumer finisher) { + requireNonNull(finisher); return new ClassTransform() { @Override public void accept(ClassBuilder builder, ClassElement element) { @@ -95,6 +98,7 @@ public void atEnd(ClassBuilder builder) { * @return the class transform */ static ClassTransform dropping(Predicate filter) { + requireNonNull(filter); return (b, e) -> { if (!filter.test(e)) b.with(e); @@ -111,7 +115,7 @@ static ClassTransform dropping(Predicate filter) { */ static ClassTransform transformingMethods(Predicate filter, MethodTransform xform) { - return new TransformImpl.ClassMethodTransform(xform, filter); + return new TransformImpl.ClassMethodTransform(requireNonNull(xform), requireNonNull(filter)); } /** @@ -122,7 +126,7 @@ static ClassTransform transformingMethods(Predicate filter, * @return the class transform */ static ClassTransform transformingMethods(MethodTransform xform) { - return transformingMethods(mm -> true, xform); + return transformingMethods(_ -> true, xform); } /** @@ -157,7 +161,7 @@ static ClassTransform transformingMethodBodies(CodeTransform xform) { * @return the class transform */ static ClassTransform transformingFields(FieldTransform xform) { - return new TransformImpl.ClassFieldTransform(xform, f -> true); + return new TransformImpl.ClassFieldTransform(requireNonNull(xform), _ -> true); } /** @@ -169,6 +173,6 @@ static ClassTransform transformingFields(FieldTransform xform) { */ @Override default ClassTransform andThen(ClassTransform t) { - return new TransformImpl.ChainedClassTransform(this, t); + return new TransformImpl.ChainedClassTransform(this, requireNonNull(t)); } } diff --git a/src/java.base/share/classes/java/lang/classfile/CodeTransform.java b/src/java.base/share/classes/java/lang/classfile/CodeTransform.java index cdc7a3b1434d7..0474e0c9c67f7 100644 --- a/src/java.base/share/classes/java/lang/classfile/CodeTransform.java +++ b/src/java.base/share/classes/java/lang/classfile/CodeTransform.java @@ -30,6 +30,8 @@ import jdk.internal.classfile.impl.TransformImpl; import jdk.internal.javac.PreviewFeature; +import static java.util.Objects.requireNonNull; + /** * A transformation on streams of {@link CodeElement}. * @@ -61,7 +63,7 @@ public void accept(CodeBuilder builder, CodeElement element) { * @return the stateful code transform */ static CodeTransform ofStateful(Supplier supplier) { - return new TransformImpl.SupplierCodeTransform(supplier); + return new TransformImpl.SupplierCodeTransform(requireNonNull(supplier)); } /** @@ -72,6 +74,7 @@ static CodeTransform ofStateful(Supplier supplier) { * @return the code transform */ static CodeTransform endHandler(Consumer finisher) { + requireNonNull(finisher); return new CodeTransform() { @Override public void accept(CodeBuilder builder, CodeElement element) { @@ -94,6 +97,6 @@ public void atEnd(CodeBuilder builder) { */ @Override default CodeTransform andThen(CodeTransform t) { - return new TransformImpl.ChainedCodeTransform(this, t); + return new TransformImpl.ChainedCodeTransform(this, requireNonNull(t)); } } diff --git a/src/java.base/share/classes/java/lang/classfile/FieldTransform.java b/src/java.base/share/classes/java/lang/classfile/FieldTransform.java index 4e39f1e9c7fec..78a6f5ead2f79 100644 --- a/src/java.base/share/classes/java/lang/classfile/FieldTransform.java +++ b/src/java.base/share/classes/java/lang/classfile/FieldTransform.java @@ -31,6 +31,8 @@ import jdk.internal.classfile.impl.TransformImpl; import jdk.internal.javac.PreviewFeature; +import static java.util.Objects.requireNonNull; + /** * A transformation on streams of {@link FieldElement}. * @@ -62,7 +64,7 @@ public void accept(FieldBuilder builder, FieldElement element) { * @return the stateful field transform */ static FieldTransform ofStateful(Supplier supplier) { - return new TransformImpl.SupplierFieldTransform(supplier); + return new TransformImpl.SupplierFieldTransform(requireNonNull(supplier)); } /** @@ -73,6 +75,7 @@ static FieldTransform ofStateful(Supplier supplier) { * @return the field transform */ static FieldTransform endHandler(Consumer finisher) { + requireNonNull(finisher); return new FieldTransform() { @Override public void accept(FieldBuilder builder, FieldElement element) { @@ -94,6 +97,7 @@ public void atEnd(FieldBuilder builder) { * @return the field transform */ static FieldTransform dropping(Predicate filter) { + requireNonNull(filter); return (b, e) -> { if (!filter.test(e)) b.with(e); @@ -109,6 +113,6 @@ static FieldTransform dropping(Predicate filter) { */ @Override default FieldTransform andThen(FieldTransform t) { - return new TransformImpl.ChainedFieldTransform(this, t); + return new TransformImpl.ChainedFieldTransform(this, requireNonNull(t)); } } diff --git a/src/java.base/share/classes/java/lang/classfile/MethodTransform.java b/src/java.base/share/classes/java/lang/classfile/MethodTransform.java index e7e024ebc3467..bf5786f3dc74b 100644 --- a/src/java.base/share/classes/java/lang/classfile/MethodTransform.java +++ b/src/java.base/share/classes/java/lang/classfile/MethodTransform.java @@ -31,6 +31,8 @@ import jdk.internal.classfile.impl.TransformImpl; import jdk.internal.javac.PreviewFeature; +import static java.util.Objects.requireNonNull; + /** * A transformation on streams of {@link MethodElement}. * @@ -62,6 +64,7 @@ public void accept(MethodBuilder builder, MethodElement element) { * @return the stateful method transform */ static MethodTransform ofStateful(Supplier supplier) { + requireNonNull(supplier); return new TransformImpl.SupplierMethodTransform(supplier); } @@ -73,6 +76,7 @@ static MethodTransform ofStateful(Supplier supplier) { * @return the method transform */ static MethodTransform endHandler(Consumer finisher) { + requireNonNull(finisher); return new MethodTransform() { @Override public void accept(MethodBuilder builder, MethodElement element) { @@ -94,6 +98,7 @@ public void atEnd(MethodBuilder builder) { * @return the method transform */ static MethodTransform dropping(Predicate filter) { + requireNonNull(filter); return (b, e) -> { if (!filter.test(e)) b.with(e); @@ -108,7 +113,7 @@ static MethodTransform dropping(Predicate filter) { * @return the class transform */ static MethodTransform transformingCode(CodeTransform xform) { - return new TransformImpl.MethodCodeTransform(xform); + return new TransformImpl.MethodCodeTransform(requireNonNull(xform)); } /** @@ -120,6 +125,6 @@ static MethodTransform transformingCode(CodeTransform xform) { */ @Override default MethodTransform andThen(MethodTransform t) { - return new TransformImpl.ChainedMethodTransform(this, t); + return new TransformImpl.ChainedMethodTransform(this, requireNonNull(t)); } } diff --git a/src/java.base/share/classes/java/lang/classfile/components/ClassRemapper.java b/src/java.base/share/classes/java/lang/classfile/components/ClassRemapper.java index d3ae180dde573..bcda36355870a 100644 --- a/src/java.base/share/classes/java/lang/classfile/components/ClassRemapper.java +++ b/src/java.base/share/classes/java/lang/classfile/components/ClassRemapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * 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,6 +36,8 @@ import jdk.internal.classfile.impl.ClassRemapperImpl; import jdk.internal.javac.PreviewFeature; +import static java.util.Objects.requireNonNull; + /** * {@code ClassRemapper} is a {@link ClassTransform}, {@link FieldTransform}, * {@link MethodTransform} and {@link CodeTransform} @@ -64,6 +66,7 @@ public sealed interface ClassRemapper extends ClassTransform permits ClassRemapp * @return new instance of {@code ClassRemapper} */ static ClassRemapper of(Map classMap) { + requireNonNull(classMap); return of(desc -> classMap.getOrDefault(desc, desc)); } @@ -75,7 +78,7 @@ static ClassRemapper of(Map classMap) { * @return new instance of {@code ClassRemapper} */ static ClassRemapper of(Function mapFunction) { - return new ClassRemapperImpl(mapFunction); + return new ClassRemapperImpl(requireNonNull(mapFunction)); } /** diff --git a/src/java.base/share/classes/java/lang/classfile/components/CodeRelabeler.java b/src/java.base/share/classes/java/lang/classfile/components/CodeRelabeler.java index ca5ad90389c5c..6ec3f9f792b72 100644 --- a/src/java.base/share/classes/java/lang/classfile/components/CodeRelabeler.java +++ b/src/java.base/share/classes/java/lang/classfile/components/CodeRelabeler.java @@ -33,6 +33,8 @@ import jdk.internal.classfile.impl.CodeRelabelerImpl; import jdk.internal.javac.PreviewFeature; +import static java.util.Objects.requireNonNull; + /** * A code relabeler is a {@link CodeTransform} replacing all occurrences * of {@link java.lang.classfile.Label} in the transformed code with new instances. @@ -62,6 +64,7 @@ static CodeRelabeler of() { * @return a new instance of CodeRelabeler */ static CodeRelabeler of(Map map) { + requireNonNull(map); return of((l, cob) -> map.computeIfAbsent(l, ll -> cob.newLabel())); } @@ -72,6 +75,6 @@ static CodeRelabeler of(Map map) { * @return a new instance of CodeRelabeler */ static CodeRelabeler of(BiFunction mapFunction) { - return new CodeRelabelerImpl(mapFunction); + return new CodeRelabelerImpl(requireNonNull(mapFunction)); } } diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/DiscontinuedInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/DiscontinuedInstruction.java index 84bead6d8ccb4..fc87dd274d36e 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/DiscontinuedInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/DiscontinuedInstruction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java b/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java index dc4133ae244db..9709c881863ef 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java @@ -54,6 +54,7 @@ import java.lang.classfile.TypeKind; import jdk.internal.constant.ConstantUtils; +import jdk.internal.loader.ClassLoaders; import jdk.internal.module.Modules; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; @@ -371,7 +372,8 @@ private static Class getProxyClass(Class intfc) { */ private static byte[] createTemplate(ClassLoader loader, ClassDesc proxyDesc, ClassDesc ifaceDesc, String methodName, List methods) { - return ClassFile.of(ClassHierarchyResolverOption.of(ClassHierarchyResolver.ofClassLoading(loader))) + return ClassFile.of(ClassHierarchyResolverOption.of(ClassHierarchyResolver.ofClassLoading(loader == null ? + ClassLoaders.platformClassLoader() : loader))) .build(proxyDesc, clb -> { clb.withSuperclass(CD_Object) .withFlags(ACC_FINAL | ACC_SYNTHETIC) diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java index 6b77f6ff1ade9..23dad36b1b163 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java @@ -66,6 +66,8 @@ import java.lang.classfile.Opcode; import java.lang.classfile.TypeKind; +import static java.util.Objects.requireNonNull; + public abstract sealed class AbstractInstruction extends AbstractElement implements Instruction { @@ -247,6 +249,9 @@ public String toString() { public record SwitchCaseImpl(int caseValue, Label target) implements SwitchCase { + public SwitchCaseImpl { + requireNonNull(target); + } } public static final class BoundLookupSwitchInstruction @@ -892,7 +897,7 @@ public static final class UnboundBranchInstruction public UnboundBranchInstruction(Opcode op, Label target) { super(op); - this.target = target; + this.target = requireNonNull(target); } @Override @@ -919,7 +924,7 @@ public static final class UnboundLookupSwitchInstruction public UnboundLookupSwitchInstruction(Label defaultTarget, List cases) { super(Opcode.LOOKUPSWITCH); - this.defaultTarget = defaultTarget; + this.defaultTarget = requireNonNull(defaultTarget); this.cases = List.copyOf(cases); } @@ -955,7 +960,7 @@ public UnboundTableSwitchInstruction(int lowValue, int highValue, Label defaultT super(Opcode.TABLESWITCH); this.lowValue = lowValue; this.highValue = highValue; - this.defaultTarget = defaultTarget; + this.defaultTarget = requireNonNull(defaultTarget); this.cases = List.copyOf(cases); } @@ -1030,7 +1035,7 @@ public static final class UnboundFieldInstruction public UnboundFieldInstruction(Opcode op, FieldRefEntry fieldEntry) { super(op); - this.fieldEntry = fieldEntry; + this.fieldEntry = requireNonNull(fieldEntry); } @Override @@ -1055,7 +1060,7 @@ public static final class UnboundInvokeInstruction public UnboundInvokeInstruction(Opcode op, MemberRefEntry methodEntry) { super(op); - this.methodEntry = methodEntry; + this.methodEntry = requireNonNull(methodEntry); } @Override @@ -1095,7 +1100,7 @@ public static final class UnboundInvokeDynamicInstruction public UnboundInvokeDynamicInstruction(InvokeDynamicEntry indyEntry) { super(Opcode.INVOKEDYNAMIC); - this.indyEntry = indyEntry; + this.indyEntry = requireNonNull(indyEntry); } @Override @@ -1120,7 +1125,7 @@ public static final class UnboundNewObjectInstruction public UnboundNewObjectInstruction(ClassEntry classEntry) { super(Opcode.NEW); - this.classEntry = classEntry; + this.classEntry = requireNonNull(classEntry); } @Override @@ -1145,7 +1150,7 @@ public static final class UnboundNewPrimitiveArrayInstruction public UnboundNewPrimitiveArrayInstruction(TypeKind typeKind) { super(Opcode.NEWARRAY); - this.typeKind = typeKind; + this.typeKind = requireNonNull(typeKind); } @Override @@ -1170,7 +1175,7 @@ public static final class UnboundNewReferenceArrayInstruction public UnboundNewReferenceArrayInstruction(ClassEntry componentTypeEntry) { super(Opcode.ANEWARRAY); - this.componentTypeEntry = componentTypeEntry; + this.componentTypeEntry = requireNonNull(componentTypeEntry); } @Override @@ -1197,7 +1202,7 @@ public static final class UnboundNewMultidimensionalArrayInstruction public UnboundNewMultidimensionalArrayInstruction(ClassEntry arrayTypeEntry, int dimensions) { super(Opcode.MULTIANEWARRAY); - this.arrayTypeEntry = arrayTypeEntry; + this.arrayTypeEntry = requireNonNull(arrayTypeEntry); this.dimensions = dimensions; } @@ -1255,7 +1260,7 @@ public static final class UnboundTypeCheckInstruction public UnboundTypeCheckInstruction(Opcode op, ClassEntry typeEntry) { super(op); - this.typeEntry = typeEntry; + this.typeEntry = requireNonNull(typeEntry); } @Override @@ -1357,7 +1362,7 @@ public static final class UnboundLoadConstantInstruction public UnboundLoadConstantInstruction(Opcode op, LoadableConstantEntry constant) { super(op); - this.constant = constant; + this.constant = requireNonNull(constant); } @Override @@ -1405,7 +1410,7 @@ public static final class UnboundJsrInstruction public UnboundJsrInstruction(Opcode op, Label target) { super(op); - this.target = target; + this.target = requireNonNull(target); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java index 447e7e25c45f1..15b5262176441 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java @@ -56,6 +56,8 @@ import jdk.internal.util.ArraysSupport; import jdk.internal.vm.annotation.Stable; +import static java.util.Objects.requireNonNull; + public abstract sealed class AbstractPoolEntry { /* Invariant: a {CP,BSM} entry for pool P refer only to {CP,BSM} entries @@ -439,7 +441,7 @@ public boolean equalsString(String s) { inflate(); switch (state) { case STRING: - return stringValue.equals(s); + return stringValue.equals(requireNonNull(s)); case CHAR: if (charLen != s.length() || contentHash != s.hashCode()) return false; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java index ffba8ec7a5d27..596379305a9fe 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java @@ -36,6 +36,8 @@ import java.lang.classfile.Label; import java.lang.classfile.PseudoInstruction; +import static java.util.Objects.requireNonNull; + public abstract sealed class AbstractPseudoInstruction extends AbstractElement implements PseudoInstruction { @@ -55,17 +57,14 @@ public static final class ExceptionCatchImpl public ExceptionCatchImpl(Label handler, Label tryStart, Label tryEnd, ClassEntry catchTypeEntry) { this.catchTypeEntry = catchTypeEntry; - this.handler = handler; - this.tryStart = tryStart; - this.tryEnd = tryEnd; + this.handler = requireNonNull(handler); + this.tryStart = requireNonNull(tryStart); + this.tryEnd = requireNonNull(tryEnd); } public ExceptionCatchImpl(Label handler, Label tryStart, Label tryEnd, Optional catchTypeEntry) { - this.catchTypeEntry = catchTypeEntry.orElse(null); - this.handler = handler; - this.tryStart = tryStart; - this.tryEnd = tryEnd; + this(handler, tryStart, tryEnd, catchTypeEntry.orElse(null)); } @Override @@ -115,8 +114,8 @@ public static final class UnboundCharacterRange public UnboundCharacterRange(Label startScope, Label endScope, int characterRangeStart, int characterRangeEnd, int flags) { - this.startScope = startScope; - this.endScope = endScope; + this.startScope = requireNonNull(startScope); + this.endScope = requireNonNull(endScope); this.characterRangeStart = characterRangeStart; this.characterRangeEnd = characterRangeEnd; this.flags = flags; @@ -165,10 +164,10 @@ private abstract static sealed class AbstractLocalPseudo extends AbstractPseudoI public AbstractLocalPseudo(int slot, Utf8Entry name, Utf8Entry descriptor, Label startScope, Label endScope) { BytecodeHelpers.validateSlot(slot); this.slot = slot; - this.name = name; - this.descriptor = descriptor; - this.startScope = startScope; - this.endScope = endScope; + this.name = requireNonNull(name); + this.descriptor = requireNonNull(descriptor); + this.startScope = requireNonNull(startScope); + this.endScope = requireNonNull(endScope); } public int slot() { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java index 6aeda552b4787..f1c7e6aaf658b 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java @@ -29,9 +29,12 @@ import java.util.List; +import static java.util.Objects.requireNonNull; + public record AnnotationImpl(Utf8Entry className, List elements) implements Annotation { public AnnotationImpl { + requireNonNull(className); elements = List.copyOf(elements); } @@ -50,6 +53,11 @@ public String toString() { public record AnnotationElementImpl(Utf8Entry name, AnnotationValue value) implements AnnotationElement { + public AnnotationElementImpl { + requireNonNull(name); + requireNonNull(value); + } + @Override public String toString() { return name + "=" + value; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java index b28bcc0b4b56f..2fdc9f3642624 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java @@ -33,6 +33,8 @@ import java.util.Objects; import java.lang.classfile.Instruction; +import static java.util.Objects.requireNonNull; + public final class BlockCodeBuilderImpl extends NonterminalCodeBuilder implements CodeBuilder.BlockCodeBuilder { @@ -80,7 +82,7 @@ private int topLocal(CodeBuilder parent) { @Override public CodeBuilder with(CodeElement element) { - parent.with(element); + parent.with(requireNonNull(element)); hasInstructions |= element instanceof Instruction; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java index c506d265f6895..4ed458c398309 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java @@ -38,6 +38,8 @@ import java.util.Optional; import java.util.function.Consumer; +import static java.util.Objects.requireNonNull; + public final class BufferedCodeBuilder implements TerminalCodeBuilder { private final SplitConstantPool constantPool; @@ -121,7 +123,7 @@ public ConstantPoolBuilder constantPool() { public CodeBuilder with(CodeElement element) { if (finished) throw new IllegalStateException("Can't add elements after traversal"); - elements.add(element); + elements.add(requireNonNull(element)); return this; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java index 8cf274d746c1c..0578cf85c4cc6 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java @@ -34,6 +34,8 @@ import java.lang.classfile.constantpool.ConstantPoolBuilder; import java.lang.classfile.constantpool.Utf8Entry; +import static java.util.Objects.requireNonNull; + public final class BufferedFieldBuilder implements TerminalFieldBuilder { private final SplitConstantPool constantPool; @@ -49,8 +51,8 @@ public BufferedFieldBuilder(SplitConstantPool constantPool, Utf8Entry type) { this.constantPool = constantPool; this.context = context; - this.name = name; - this.desc = type; + this.name = requireNonNull(name); + this.desc = requireNonNull(type); this.flags = new AccessFlagsImpl(AccessFlag.Location.FIELD); } @@ -61,7 +63,7 @@ public ConstantPoolBuilder constantPool() { @Override public FieldBuilder with(FieldElement element) { - elements.add(element); + elements.add(requireNonNull(element)); if (element instanceof AccessFlags f) this.flags = f; return this; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java index bc6ab555ae597..8f511218d1e30 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java @@ -43,6 +43,8 @@ import java.lang.classfile.MethodModel; import java.lang.classfile.constantpool.Utf8Entry; +import static java.util.Objects.requireNonNull; + public final class BufferedMethodBuilder implements TerminalMethodBuilder { private final List elements; @@ -63,15 +65,15 @@ public BufferedMethodBuilder(SplitConstantPool constantPool, this.elements = new ArrayList<>(); this.constantPool = constantPool; this.context = context; - this.name = nameInfo; - this.desc = typeInfo; + this.name = requireNonNull(nameInfo); + this.desc = requireNonNull(typeInfo); this.flags = new AccessFlagsImpl(AccessFlag.Location.METHOD, flags); this.original = original; } @Override public MethodBuilder with(MethodElement element) { - elements.add(element); + elements.add(requireNonNull(element)); if (element instanceof AccessFlags f) this.flags = checkFlags(f); return this; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java index bca80c1ed4b1f..fde8905abc183 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java @@ -47,6 +47,7 @@ import java.lang.classfile.constantpool.NameAndTypeEntry; import java.util.Objects; +import static java.util.Objects.requireNonNull; import static jdk.internal.classfile.impl.RawBytecodeHelper.*; /** @@ -463,7 +464,7 @@ public static void validateRet(Opcode opcode, int slot) { if (opcode == Opcode.RET && (slot & ~0xFF) == 0 || opcode == Opcode.RET_W && (slot & ~0xFFFF) == 0) return; - Objects.requireNonNull(opcode); + requireNonNull(opcode); throw slotOutOfBounds(opcode, slot); } @@ -551,7 +552,7 @@ public static LoadableConstantEntry constantEntry(ConstantPoolBuilder constantPo } if (constantValue instanceof DynamicConstantDesc value) { return handleConstantDescToHandleInfo(constantPool, value); } - throw new UnsupportedOperationException("not yet: " + constantValue); + throw new UnsupportedOperationException("not yet: " + requireNonNull(constantValue)); } public static ConstantDesc intrinsicConstantValue(Opcode opcode) { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java index 8f05f20d739be..ebf803f5f2725 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java @@ -31,6 +31,8 @@ import java.lang.classfile.constantpool.ConstantPoolBuilder; import java.lang.classfile.constantpool.Utf8Entry; +import static java.util.Objects.requireNonNull; + public final class ChainedClassBuilder implements ClassBuilder, Consumer { private final DirectClassBuilder terminal; @@ -47,7 +49,7 @@ public ChainedClassBuilder(ClassBuilder downstream, @Override public ClassBuilder with(ClassElement element) { - consumer.accept(element); + consumer.accept(requireNonNull(element)); return this; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedCodeBuilder.java index 8c6c80b3013f3..fa02a346fabd8 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedCodeBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * 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,6 +31,8 @@ import java.util.function.Consumer; +import static java.util.Objects.requireNonNull; + public final class ChainedCodeBuilder extends NonterminalCodeBuilder implements CodeBuilder { @@ -59,7 +61,7 @@ public int allocateLocal(TypeKind typeKind) { @Override public CodeBuilder with(CodeElement element) { - consumer.accept(element); + consumer.accept(requireNonNull(element)); return this; } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedFieldBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedFieldBuilder.java index b3a30b5351ba7..f9c2b50f414ac 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedFieldBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedFieldBuilder.java @@ -30,6 +30,8 @@ import java.lang.classfile.FieldElement; import java.lang.classfile.constantpool.ConstantPoolBuilder; +import static java.util.Objects.requireNonNull; + public final class ChainedFieldBuilder implements FieldBuilder { private final TerminalFieldBuilder terminal; private final Consumer consumer; @@ -50,7 +52,7 @@ public ConstantPoolBuilder constantPool() { @Override public FieldBuilder with(FieldElement element) { - consumer.accept(element); + consumer.accept(requireNonNull(element)); return this; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedMethodBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedMethodBuilder.java index a7084116b9bd3..5bab6806b71b4 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedMethodBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedMethodBuilder.java @@ -33,6 +33,8 @@ import java.lang.classfile.MethodElement; import java.lang.classfile.constantpool.ConstantPoolBuilder; +import static java.util.Objects.requireNonNull; + public final class ChainedMethodBuilder implements MethodBuilder { final TerminalMethodBuilder terminal; final Consumer consumer; @@ -48,7 +50,7 @@ public ChainedMethodBuilder(MethodBuilder downstream, @Override public MethodBuilder with(MethodElement element) { - consumer.accept(element); + consumer.accept(requireNonNull(element)); return this; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java index c6d9e55d8dbcc..ed81bcea009b8 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java @@ -40,6 +40,8 @@ import java.lang.classfile.constantpool.Utf8Entry; import jdk.internal.classfile.impl.verifier.VerifierImpl; +import static java.util.Objects.requireNonNull; + public final class ClassFileImpl implements ClassFile { private Option stackMapsOption; @@ -123,7 +125,7 @@ public ClassFileImpl withOptions(Option... options) { } else if (o instanceof AttributeMapperOption oo) { amo = oo; } else { // null or unknown Option type - throw new IllegalArgumentException("Invalid option: " + o); + throw new IllegalArgumentException("Invalid option: " + requireNonNull(o)); } } return new ClassFileImpl(smo, deo, lno, apo, cpso, sjo, dco, dlo, chro, amo); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java index 34e6f5f7c1aa7..9c2dd89553865 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java @@ -205,9 +205,9 @@ public StaticClassHierarchyResolver(Collection interfaceNames, Map convertVTIs(CodeAttribute lr, List model, Verbosity verbosity) { + requireNonNull(verbosity); // we are using == checks in implementations return switch(model) { case ClassModel cm -> classToTree(cm, verbosity); case FieldModel fm -> fieldToTree(fm, verbosity); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java index afa7ebac8ba6c..d1131d94db769 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java @@ -26,11 +26,7 @@ package jdk.internal.classfile.impl; -import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDescs; -import java.lang.constant.MethodTypeDesc; -import java.lang.reflect.AccessFlag; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -50,6 +46,8 @@ import java.lang.classfile.MethodTransform; import java.lang.classfile.constantpool.Utf8Entry; +import static java.util.Objects.requireNonNull; + public final class DirectClassBuilder extends AbstractDirectBuilder implements ClassBuilder { @@ -87,7 +85,7 @@ public ClassBuilder with(ClassElement element) { if (element instanceof AbstractElement ae) { ae.writeTo(this); } else { - writeAttribute((CustomAttribute) element); + writeAttribute((CustomAttribute) requireNonNull(element)); } return this; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java index b3c106c461d03..c00025e2a7e1e 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java @@ -64,6 +64,7 @@ import java.util.function.Consumer; import java.util.function.Function; +import static java.util.Objects.requireNonNull; import static jdk.internal.classfile.impl.BytecodeHelpers.*; import static jdk.internal.classfile.impl.RawBytecodeHelper.*; @@ -147,7 +148,7 @@ public CodeBuilder with(CodeElement element) { if (element instanceof AbstractElement ae) { ae.writeTo(this); } else { - writeAttribute((CustomAttribute) element); + writeAttribute((CustomAttribute) requireNonNull(element)); } return this; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectFieldBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectFieldBuilder.java index d1fafc626f926..222ed6b9792d2 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectFieldBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectFieldBuilder.java @@ -33,6 +33,8 @@ import java.lang.classfile.FieldModel; import java.lang.classfile.constantpool.Utf8Entry; +import static java.util.Objects.requireNonNull; + public final class DirectFieldBuilder extends AbstractDirectBuilder implements TerminalFieldBuilder, Util.Writable { @@ -48,8 +50,8 @@ public DirectFieldBuilder(SplitConstantPool constantPool, FieldModel original) { super(constantPool, context); setOriginal(original); - this.name = name; - this.desc = type; + this.name = requireNonNull(name); + this.desc = requireNonNull(type); this.flags = flags; } @@ -58,7 +60,7 @@ public FieldBuilder with(FieldElement element) { if (element instanceof AbstractElement ae) { ae.writeTo(this); } else { - writeAttribute((CustomAttribute) element); + writeAttribute((CustomAttribute) requireNonNull(element)); } return this; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java index a841cbf47f473..cdd5f8155e1c7 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java @@ -38,6 +38,8 @@ import java.lang.classfile.MethodModel; import java.lang.classfile.constantpool.Utf8Entry; +import static java.util.Objects.requireNonNull; + public final class DirectMethodBuilder extends AbstractDirectBuilder implements TerminalMethodBuilder, Util.Writable { @@ -55,8 +57,8 @@ public DirectMethodBuilder(SplitConstantPool constantPool, MethodModel original) { super(constantPool, context); setOriginal(original); - this.name = nameInfo; - this.desc = typeInfo; + this.name = requireNonNull(nameInfo); + this.desc = requireNonNull(typeInfo); this.flags = flags; } @@ -114,7 +116,7 @@ public MethodBuilder with(MethodElement element) { if (element instanceof AbstractElement ae) { ae.writeTo(this); } else { - writeAttribute((CustomAttribute) element); + writeAttribute((CustomAttribute) requireNonNull(element)); } return this; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java index 0b99766b385c4..4c76033885735 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java @@ -38,6 +38,7 @@ import jdk.internal.constant.ConstantUtils; import static java.lang.classfile.constantpool.PoolEntry.*; +import static java.util.Objects.requireNonNull; public final class SplitConstantPool implements ConstantPoolBuilder { @@ -122,6 +123,7 @@ public BootstrapMethodEntryImpl bootstrapMethodEntry(int index) { @Override public boolean canWriteDirect(ConstantPool other) { + requireNonNull(other); return this == other || parent == other; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java index 2cad163b17720..28b877cd83c70 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java @@ -42,6 +42,7 @@ import static java.lang.classfile.ClassFile.*; import static java.lang.classfile.attribute.StackMapFrameInfo.VerificationTypeInfo.*; +import static java.util.Objects.requireNonNull; public class StackMapDecoder { @@ -245,6 +246,9 @@ private VerificationTypeInfo readVerificationTypeInfo() { public static record ObjectVerificationTypeInfoImpl( ClassEntry className) implements ObjectVerificationTypeInfo { + public ObjectVerificationTypeInfoImpl { + requireNonNull(className); + } @Override public int tag() { return ITEM_OBJECT; } @@ -270,6 +274,9 @@ public String toString() { } public static record UninitializedVerificationTypeInfoImpl(Label newTarget) implements UninitializedVerificationTypeInfo { + public UninitializedVerificationTypeInfoImpl { + requireNonNull(newTarget); + } @Override public int tag() { return ITEM_UNINITIALIZED; } @@ -292,6 +299,7 @@ public static record StackMapFrameImpl(int frameType, List stack) implements StackMapFrameInfo { public StackMapFrameImpl { + requireNonNull(target); locals = List.copyOf(locals); stack = List.copyOf(stack); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java index b2d5cd9f62c84..f30597cb3c493 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ package jdk.internal.classfile.impl; import java.util.List; -import java.util.Objects; import java.lang.classfile.Label; import java.lang.classfile.TypeAnnotation.*; @@ -37,7 +36,6 @@ private TargetInfoImpl() { } private static TargetType checkValid(TargetType targetType, int rangeFrom, int rangeTo) { - Objects.requireNonNull(targetType); if (targetType.targetTypeValue() < rangeFrom || targetType.targetTypeValue() > rangeTo) throw new IllegalArgumentException("Wrong target type specified " + targetType); return targetType; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/TemporaryConstantPool.java b/src/java.base/share/classes/jdk/internal/classfile/impl/TemporaryConstantPool.java index 784e844b712f2..4fee9ba3d9510 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/TemporaryConstantPool.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/TemporaryConstantPool.java @@ -50,6 +50,7 @@ import java.lang.constant.MethodTypeDesc; import java.util.List; +import java.util.Objects; public final class TemporaryConstantPool implements ConstantPoolBuilder { @@ -187,6 +188,7 @@ public int bootstrapMethodCount() { @Override public boolean canWriteDirect(ConstantPool constantPool) { + Objects.requireNonNull(constantPool); return false; } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java index 3119cfa0f4953..a979a31c593c0 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java @@ -92,6 +92,8 @@ import jdk.internal.access.SharedSecrets; +import static java.util.Objects.requireNonNull; + public abstract sealed class UnboundAttribute> extends AbstractElement implements Attribute, Util.Writable { @@ -149,7 +151,7 @@ public static final class UnboundConstantValueAttribute public UnboundConstantValueAttribute(ConstantValueEntry entry) { super(Attributes.constantValue()); - this.entry = entry; + this.entry = requireNonNull(entry); } @Override @@ -182,7 +184,7 @@ public static final class UnboundSignatureAttribute public UnboundSignatureAttribute(Utf8Entry signature) { super(Attributes.signature()); - this.signature = signature; + this.signature = requireNonNull(signature); } @Override @@ -214,7 +216,7 @@ public static final class UnboundAnnotationDefaultAttribute public UnboundAnnotationDefaultAttribute(AnnotationValue annotationDefault) { super(Attributes.annotationDefault()); - this.annotationDefault = annotationDefault; + this.annotationDefault = requireNonNull(annotationDefault); } @Override @@ -229,7 +231,7 @@ public static final class UnboundSourceFileAttribute extends UnboundAttribute hashes) { super(Attributes.moduleHashes()); - this.algorithm = algorithm; + this.algorithm = requireNonNull(algorithm); this.hashes = List.copyOf(hashes); } @@ -451,7 +453,7 @@ public static final class UnboundNestHostAttribute public UnboundNestHostAttribute(ClassEntry hostEntry) { super(Attributes.nestHost()); - this.hostEntry = hostEntry; + this.hostEntry = requireNonNull(hostEntry); } @Override @@ -467,7 +469,7 @@ public static final class UnboundCompilationIDAttribute public UnboundCompilationIDAttribute(Utf8Entry idEntry) { super(Attributes.compilationId()); - this.idEntry = idEntry; + this.idEntry = requireNonNull(idEntry); } @Override @@ -483,7 +485,7 @@ public static final class UnboundSourceIDAttribute public UnboundSourceIDAttribute(Utf8Entry idEntry) { super(Attributes.sourceId()); - this.idEntry = idEntry; + this.idEntry = requireNonNull(idEntry); } @Override @@ -499,7 +501,7 @@ public static final class UnboundSourceDebugExtensionAttribute public UnboundSourceDebugExtensionAttribute(byte[] contents) { super(Attributes.sourceDebugExtension()); - this.contents = contents; + this.contents = requireNonNull(contents); } @Override @@ -611,7 +613,13 @@ public static final class UnboundRuntimeVisibleParameterAnnotationsAttribute public UnboundRuntimeVisibleParameterAnnotationsAttribute(List> elements) { super(Attributes.runtimeVisibleParameterAnnotations()); - this.elements = List.copyOf(elements); + // deep copy + var array = elements.toArray().clone(); + for (int i = 0; i < array.length; i++) { + array[i] = List.copyOf((List) array[i]); + } + + this.elements = SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(array); } @Override @@ -684,7 +692,13 @@ public record UnboundInnerClassInfo(ClassEntry innerClass, Optional outerClass, Optional innerName, int flagsMask) - implements InnerClassInfo {} + implements InnerClassInfo { + public UnboundInnerClassInfo { + requireNonNull(innerClass); + requireNonNull(outerClass); + requireNonNull(innerName); + } + } public record UnboundLineNumberInfo(int startPc, int lineNumber) implements LineNumberInfo { } @@ -693,64 +707,84 @@ public record UnboundLocalVariableInfo(int startPc, int length, Utf8Entry name, Utf8Entry type, int slot) - implements LocalVariableInfo { } + implements LocalVariableInfo { + public UnboundLocalVariableInfo { + requireNonNull(name); + requireNonNull(type); + } + } public record UnboundLocalVariableTypeInfo(int startPc, int length, Utf8Entry name, Utf8Entry signature, int slot) - implements LocalVariableTypeInfo { } + implements LocalVariableTypeInfo { + public UnboundLocalVariableTypeInfo { + requireNonNull(name); + requireNonNull(signature); + } + } public record UnboundMethodParameterInfo(Optional name, int flagsMask) - implements MethodParameterInfo {} + implements MethodParameterInfo { + public UnboundMethodParameterInfo { + requireNonNull(name); + } + } public record UnboundModuleExportInfo(PackageEntry exportedPackage, int exportsFlagsMask, List exportsTo) implements ModuleExportInfo { - public UnboundModuleExportInfo(PackageEntry exportedPackage, int exportsFlagsMask, - List exportsTo) { - this.exportedPackage = exportedPackage; - this.exportsFlagsMask = exportsFlagsMask; - this.exportsTo = List.copyOf(exportsTo); + public UnboundModuleExportInfo { + requireNonNull(exportedPackage); + exportsTo = List.copyOf(exportsTo); } } public record UnboundModuleHashInfo(ModuleEntry moduleName, - byte[] hash) implements ModuleHashInfo { } + byte[] hash) implements ModuleHashInfo { + public UnboundModuleHashInfo { + requireNonNull(moduleName); + requireNonNull(hash); + } + } public record UnboundModuleOpenInfo(PackageEntry openedPackage, int opensFlagsMask, List opensTo) implements ModuleOpenInfo { - public UnboundModuleOpenInfo(PackageEntry openedPackage, int opensFlagsMask, - List opensTo) { - this.openedPackage = openedPackage; - this.opensFlagsMask = opensFlagsMask; - this.opensTo = List.copyOf(opensTo); + public UnboundModuleOpenInfo { + requireNonNull(openedPackage); + opensTo = List.copyOf(opensTo); } } public record UnboundModuleProvideInfo(ClassEntry provides, List providesWith) implements ModuleProvideInfo { - public UnboundModuleProvideInfo(ClassEntry provides, List providesWith) { - this.provides = provides; - this.providesWith = List.copyOf(providesWith); + public UnboundModuleProvideInfo { + requireNonNull(provides); + providesWith = List.copyOf(providesWith); } } public record UnboundModuleRequiresInfo(ModuleEntry requires, int requiresFlagsMask, Optional requiresVersion) - implements ModuleRequireInfo {} + implements ModuleRequireInfo { + public UnboundModuleRequiresInfo { + requireNonNull(requires); + requireNonNull(requiresVersion); + } + } public record UnboundRecordComponentInfo(Utf8Entry name, Utf8Entry descriptor, List> attributes) implements RecordComponentInfo { - public UnboundRecordComponentInfo(Utf8Entry name, Utf8Entry descriptor, List> attributes) { - this.name = name; - this.descriptor = descriptor; - this.attributes = List.copyOf(attributes); + public UnboundRecordComponentInfo { + requireNonNull(name); + requireNonNull(descriptor); + attributes = List.copyOf(attributes); } } @@ -759,7 +793,9 @@ public record UnboundTypeAnnotation(TargetInfo targetInfo, Annotation annotation) implements TypeAnnotation { public UnboundTypeAnnotation { + requireNonNull(targetInfo); targetPath = List.copyOf(targetPath); + requireNonNull(annotation); } } @@ -786,7 +822,7 @@ public UnboundModuleAttribute(ModuleEntry moduleName, Collection provides) { super(Attributes.module()); - this.moduleName = moduleName; + this.moduleName = requireNonNull(moduleName); this.moduleFlags = moduleFlags; this.moduleVersion = moduleVersion; this.requires = List.copyOf(requires); From bd6264420b9f248999dd8387c25c549b08bd193a Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Mon, 14 Oct 2024 17:22:11 +0000 Subject: [PATCH 056/118] 8341924: Improve error message with structurally malformed Code array Reviewed-by: asotona --- .../classes/com/sun/tools/javap/CodeWriter.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/CodeWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/CodeWriter.java index 519a5adcf6278..8f6b9b1d2ed03 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/CodeWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/CodeWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -92,20 +92,22 @@ public void writeVerboseHeader(CodeAttribute attr) { public void writeInstrs(CodeAttribute attr) { List detailWriters = getDetailWriters(attr); - int pc = 0; + int[] pcState = {0}; try { - for (var coe: attr) { + attr.forEach(coe -> { if (coe instanceof Instruction instr) { - for (InstructionDetailWriter w: detailWriters) + int pc = pcState[0]; + for (InstructionDetailWriter w : detailWriters) w.writeDetails(pc, instr); writeInstr(pc, instr, attr); - pc += instr.sizeInBytes(); + pcState[0] = pc + instr.sizeInBytes(); } - } + }); } catch (IllegalArgumentException e) { - report("error at or after byte " + pc); + report("error at or after address " + pcState[0] + ": " + e.getMessage()); } + int pc = pcState[0]; for (InstructionDetailWriter w: detailWriters) w.flush(pc); } From a601cd2e100958e3f37ae65e32e4b3cac246c079 Mon Sep 17 00:00:00 2001 From: Fei Yang Date: Tue, 15 Oct 2024 02:53:44 +0000 Subject: [PATCH 057/118] 8342014: RISC-V: ZStoreBarrierStubC2 clobbers rflags Reviewed-by: rehn, aboldtch, mli --- src/hotspot/cpu/riscv/gc/g1/g1_riscv.ad | 68 ++++++++++++------------- src/hotspot/cpu/riscv/gc/x/x_riscv.ad | 28 +++++----- src/hotspot/cpu/riscv/gc/z/z_riscv.ad | 32 ++++++------ 3 files changed, 64 insertions(+), 64 deletions(-) diff --git a/src/hotspot/cpu/riscv/gc/g1/g1_riscv.ad b/src/hotspot/cpu/riscv/gc/g1/g1_riscv.ad index 1dc5834dbdc89..7a525323021dd 100644 --- a/src/hotspot/cpu/riscv/gc/g1/g1_riscv.ad +++ b/src/hotspot/cpu/riscv/gc/g1/g1_riscv.ad @@ -74,11 +74,11 @@ static void write_barrier_post(MacroAssembler* masm, %} -instruct g1StoreP(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3) +instruct g1StoreP(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) %{ predicate(UseG1GC && n->as_Store()->barrier_data() != 0); match(Set mem (StoreP mem src)); - effect(TEMP tmp1, TEMP tmp2, TEMP tmp3); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); ins_cost(STORE_COST); format %{ "sd $src, $mem\t# ptr" %} ins_encode %{ @@ -99,11 +99,11 @@ instruct g1StoreP(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegP ins_pipe(istore_reg_mem); %} -instruct g1StoreN(indirect mem, iRegN src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3) +instruct g1StoreN(indirect mem, iRegN src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) %{ predicate(UseG1GC && n->as_Store()->barrier_data() != 0); match(Set mem (StoreN mem src)); - effect(TEMP tmp1, TEMP tmp2, TEMP tmp3); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); ins_cost(STORE_COST); format %{ "sw $src, $mem\t# compressed ptr" %} ins_encode %{ @@ -131,11 +131,11 @@ instruct g1StoreN(indirect mem, iRegN src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegP ins_pipe(istore_reg_mem); %} -instruct g1EncodePAndStoreN(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3) +instruct g1EncodePAndStoreN(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) %{ predicate(UseG1GC && n->as_Store()->barrier_data() != 0); match(Set mem (StoreN mem (EncodeP src))); - effect(TEMP tmp1, TEMP tmp2, TEMP tmp3); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); ins_cost(STORE_COST); format %{ "encode_heap_oop $tmp1, $src\n\t" "sw $tmp1, $mem\t# compressed ptr" %} @@ -162,11 +162,11 @@ instruct g1EncodePAndStoreN(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp t ins_pipe(istore_reg_mem); %} -instruct g1CompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2) +instruct g1CompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, rFlagsReg cr) %{ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); match(Set res (CompareAndExchangeP mem (Binary oldval newval))); - effect(TEMP res, TEMP tmp1, TEMP tmp2); + effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr); ins_cost(2 * VOLATILE_REF_COST); format %{ "cmpxchg $res = $mem, $oldval, $newval\t# ptr" %} ins_encode %{ @@ -194,11 +194,11 @@ instruct g1CompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP ins_pipe(pipe_slow); %} -instruct g1CompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2) +instruct g1CompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, rFlagsReg cr) %{ predicate(UseG1GC && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); match(Set res (CompareAndExchangeP mem (Binary oldval newval))); - effect(TEMP res, TEMP tmp1, TEMP tmp2); + effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr); ins_cost(VOLATILE_REF_COST); format %{ "cmpxchg_acq $res = $mem, $oldval, $newval\t# ptr" %} ins_encode %{ @@ -226,11 +226,11 @@ instruct g1CompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRe ins_pipe(pipe_slow); %} -instruct g1CompareAndExchangeN(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3) +instruct g1CompareAndExchangeN(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) %{ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); match(Set res (CompareAndExchangeN mem (Binary oldval newval))); - effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3); + effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); ins_cost(2 * VOLATILE_REF_COST); format %{ "cmpxchg $res = $mem, $oldval, $newval\t# narrow oop" %} ins_encode %{ @@ -256,11 +256,11 @@ instruct g1CompareAndExchangeN(iRegNNoSp res, indirect mem, iRegN oldval, iRegN ins_pipe(pipe_slow); %} -instruct g1CompareAndExchangeNAcq(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3) +instruct g1CompareAndExchangeNAcq(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) %{ predicate(UseG1GC && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); match(Set res (CompareAndExchangeN mem (Binary oldval newval))); - effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3); + effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); ins_cost(VOLATILE_REF_COST); format %{ "cmpxchg_acq $res = $mem, $oldval, $newval\t# narrow oop" %} ins_encode %{ @@ -286,12 +286,12 @@ instruct g1CompareAndExchangeNAcq(iRegNNoSp res, indirect mem, iRegN oldval, iRe ins_pipe(pipe_slow); %} -instruct g1CompareAndSwapP(iRegINoSp res, indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegP oldval) +instruct g1CompareAndSwapP(iRegINoSp res, indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegP oldval, rFlagsReg cr) %{ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); match(Set res (CompareAndSwapP mem (Binary oldval newval))); match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); - effect(TEMP res, TEMP tmp1, TEMP tmp2); + effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr); ins_cost(2 * VOLATILE_REF_COST); format %{ "cmpxchg $mem, $oldval, $newval\t# (ptr)\n\t" "mv $res, $res == $oldval" %} @@ -318,12 +318,12 @@ instruct g1CompareAndSwapP(iRegINoSp res, indirect mem, iRegP newval, iRegPNoSp ins_pipe(pipe_slow); %} -instruct g1CompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegP oldval) +instruct g1CompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegP oldval, rFlagsReg cr) %{ predicate(UseG1GC && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); match(Set res (CompareAndSwapP mem (Binary oldval newval))); match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); - effect(TEMP res, TEMP tmp1, TEMP tmp2); + effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr); ins_cost(VOLATILE_REF_COST); format %{ "cmpxchg_acq $mem, $oldval, $newval\t# (ptr)\n\t" "mv $res, $res == $oldval" %} @@ -350,12 +350,12 @@ instruct g1CompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP newval, iRegPNo ins_pipe(pipe_slow); %} -instruct g1CompareAndSwapN(iRegINoSp res, indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegN oldval) +instruct g1CompareAndSwapN(iRegINoSp res, indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegN oldval, rFlagsReg cr) %{ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); match(Set res (CompareAndSwapN mem (Binary oldval newval))); match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); - effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3); + effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); ins_cost(2 * VOLATILE_REF_COST); format %{ "cmpxchg $mem, $oldval, $newval\t# (narrow oop)\n\t" "mv $res, $res == $oldval" %} @@ -383,12 +383,12 @@ instruct g1CompareAndSwapN(iRegINoSp res, indirect mem, iRegN newval, iRegPNoSp ins_pipe(pipe_slow); %} -instruct g1CompareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegN oldval) +instruct g1CompareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegN oldval, rFlagsReg cr) %{ predicate(UseG1GC && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); match(Set res (CompareAndSwapN mem (Binary oldval newval))); match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); - effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3); + effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); ins_cost(VOLATILE_REF_COST); format %{ "cmpxchg_acq $mem, $oldval, $newval\t# (narrow oop)\n\t" "mv $res, $res == $oldval" %} @@ -416,11 +416,11 @@ instruct g1CompareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN newval, iRegPNo ins_pipe(pipe_slow); %} -instruct g1GetAndSetP(indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp preval) +instruct g1GetAndSetP(indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp preval, rFlagsReg cr) %{ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); match(Set preval (GetAndSetP mem newval)); - effect(TEMP preval, TEMP tmp1, TEMP tmp2); + effect(TEMP preval, TEMP tmp1, TEMP tmp2, KILL cr); ins_cost(2 * VOLATILE_REF_COST); format %{ "atomic_xchg $preval, $newval, [$mem]" %} ins_encode %{ @@ -442,11 +442,11 @@ instruct g1GetAndSetP(indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2 ins_pipe(pipe_serial); %} -instruct g1GetAndSetPAcq(indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp preval) +instruct g1GetAndSetPAcq(indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp preval, rFlagsReg cr) %{ predicate(UseG1GC && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); match(Set preval (GetAndSetP mem newval)); - effect(TEMP preval, TEMP tmp1, TEMP tmp2); + effect(TEMP preval, TEMP tmp1, TEMP tmp2, KILL cr); ins_cost(VOLATILE_REF_COST); format %{ "atomic_xchg_acq $preval, $newval, [$mem]" %} ins_encode %{ @@ -468,11 +468,11 @@ instruct g1GetAndSetPAcq(indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp t ins_pipe(pipe_serial); %} -instruct g1GetAndSetN(indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegNNoSp preval) +instruct g1GetAndSetN(indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegNNoSp preval, rFlagsReg cr) %{ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); match(Set preval (GetAndSetN mem newval)); - effect(TEMP preval, TEMP tmp1, TEMP tmp2, TEMP tmp3); + effect(TEMP preval, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); ins_cost(2 * VOLATILE_REF_COST); format %{ "atomic_xchgwu $preval, $newval, [$mem]" %} ins_encode %{ @@ -495,11 +495,11 @@ instruct g1GetAndSetN(indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2 ins_pipe(pipe_serial); %} -instruct g1GetAndSetNAcq(indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegNNoSp preval) +instruct g1GetAndSetNAcq(indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegNNoSp preval, rFlagsReg cr) %{ predicate(UseG1GC && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); match(Set preval (GetAndSetN mem newval)); - effect(TEMP preval, TEMP tmp1, TEMP tmp2, TEMP tmp3); + effect(TEMP preval, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); ins_cost(VOLATILE_REF_COST); format %{ "atomic_xchgwu_acq $preval, $newval, [$mem]" %} ins_encode %{ @@ -522,11 +522,11 @@ instruct g1GetAndSetNAcq(indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp t ins_pipe(pipe_serial); %} -instruct g1LoadP(iRegPNoSp dst, indirect mem, iRegPNoSp tmp1, iRegPNoSp tmp2) +instruct g1LoadP(iRegPNoSp dst, indirect mem, iRegPNoSp tmp1, iRegPNoSp tmp2, rFlagsReg cr) %{ predicate(UseG1GC && n->as_Load()->barrier_data() != 0); match(Set dst (LoadP mem)); - effect(TEMP dst, TEMP tmp1, TEMP tmp2); + effect(TEMP dst, TEMP tmp1, TEMP tmp2, KILL cr); ins_cost(LOAD_COST + BRANCH_COST); format %{ "ld $dst, $mem\t# ptr" %} ins_encode %{ @@ -541,11 +541,11 @@ instruct g1LoadP(iRegPNoSp dst, indirect mem, iRegPNoSp tmp1, iRegPNoSp tmp2) ins_pipe(iload_reg_mem); %} -instruct g1LoadN(iRegNNoSp dst, indirect mem, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3) +instruct g1LoadN(iRegNNoSp dst, indirect mem, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) %{ predicate(UseG1GC && n->as_Load()->barrier_data() != 0); match(Set dst (LoadN mem)); - effect(TEMP dst, TEMP tmp1, TEMP tmp2, TEMP tmp3); + effect(TEMP dst, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); ins_cost(LOAD_COST + BRANCH_COST); format %{ "lwu $dst, $mem\t# compressed ptr" %} ins_encode %{ diff --git a/src/hotspot/cpu/riscv/gc/x/x_riscv.ad b/src/hotspot/cpu/riscv/gc/x/x_riscv.ad index ef02f301c6aeb..b93b7066425b9 100644 --- a/src/hotspot/cpu/riscv/gc/x/x_riscv.ad +++ b/src/hotspot/cpu/riscv/gc/x/x_riscv.ad @@ -52,11 +52,11 @@ static void x_load_barrier_slow_path(MacroAssembler* masm, const MachNode* node, %} // Load Pointer -instruct xLoadP(iRegPNoSp dst, memory mem, iRegPNoSp tmp) +instruct xLoadP(iRegPNoSp dst, memory mem, iRegPNoSp tmp, rFlagsReg cr) %{ match(Set dst (LoadP mem)); predicate(UseZGC && !ZGenerational && (n->as_Load()->barrier_data() != 0)); - effect(TEMP dst, TEMP tmp); + effect(TEMP dst, TEMP tmp, KILL cr); ins_cost(4 * DEFAULT_COST); @@ -71,11 +71,11 @@ instruct xLoadP(iRegPNoSp dst, memory mem, iRegPNoSp tmp) ins_pipe(iload_reg_mem); %} -instruct xCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp) %{ +instruct xCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp, rFlagsReg cr) %{ match(Set res (CompareAndSwapP mem (Binary oldval newval))); match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); predicate(UseZGC && !ZGenerational && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() == XLoadBarrierStrong); - effect(TEMP_DEF res, TEMP tmp); + effect(TEMP_DEF res, TEMP tmp, KILL cr); ins_cost(2 * VOLATILE_REF_COST); @@ -105,11 +105,11 @@ instruct xCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newva ins_pipe(pipe_slow); %} -instruct xCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp) %{ +instruct xCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp, rFlagsReg cr) %{ match(Set res (CompareAndSwapP mem (Binary oldval newval))); match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); predicate(UseZGC && !ZGenerational && needs_acquiring_load_reserved(n) && (n->as_LoadStore()->barrier_data() == XLoadBarrierStrong)); - effect(TEMP_DEF res, TEMP tmp); + effect(TEMP_DEF res, TEMP tmp, KILL cr); ins_cost(2 * VOLATILE_REF_COST); @@ -139,10 +139,10 @@ instruct xCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP ne ins_pipe(pipe_slow); %} -instruct xCompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp) %{ +instruct xCompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp, rFlagsReg cr) %{ match(Set res (CompareAndExchangeP mem (Binary oldval newval))); predicate(UseZGC && !ZGenerational && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() == XLoadBarrierStrong); - effect(TEMP_DEF res, TEMP tmp); + effect(TEMP_DEF res, TEMP tmp, KILL cr); ins_cost(2 * VOLATILE_REF_COST); @@ -167,10 +167,10 @@ instruct xCompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP n ins_pipe(pipe_slow); %} -instruct xCompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp) %{ +instruct xCompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp, rFlagsReg cr) %{ match(Set res (CompareAndExchangeP mem (Binary oldval newval))); predicate(UseZGC && !ZGenerational && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() == XLoadBarrierStrong); - effect(TEMP_DEF res, TEMP tmp); + effect(TEMP_DEF res, TEMP tmp, KILL cr); ins_cost(2 * VOLATILE_REF_COST); @@ -195,10 +195,10 @@ instruct xCompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iReg ins_pipe(pipe_slow); %} -instruct xGetAndSetP(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp) %{ +instruct xGetAndSetP(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp, rFlagsReg cr) %{ match(Set prev (GetAndSetP mem newv)); predicate(UseZGC && !ZGenerational && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); - effect(TEMP_DEF prev, TEMP tmp); + effect(TEMP_DEF prev, TEMP tmp, KILL cr); ins_cost(2 * VOLATILE_REF_COST); @@ -212,10 +212,10 @@ instruct xGetAndSetP(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp) %{ ins_pipe(pipe_serial); %} -instruct xGetAndSetPAcq(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp) %{ +instruct xGetAndSetPAcq(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp, rFlagsReg cr) %{ match(Set prev (GetAndSetP mem newv)); predicate(UseZGC && !ZGenerational && needs_acquiring_load_reserved(n) && (n->as_LoadStore()->barrier_data() != 0)); - effect(TEMP_DEF prev, TEMP tmp); + effect(TEMP_DEF prev, TEMP tmp, KILL cr); ins_cost(VOLATILE_REF_COST); diff --git a/src/hotspot/cpu/riscv/gc/z/z_riscv.ad b/src/hotspot/cpu/riscv/gc/z/z_riscv.ad index 4c94e504475ee..5b545fe801203 100644 --- a/src/hotspot/cpu/riscv/gc/z/z_riscv.ad +++ b/src/hotspot/cpu/riscv/gc/z/z_riscv.ad @@ -90,11 +90,11 @@ static void z_store_barrier(MacroAssembler* masm, const MachNode* node, Address %} // Load Pointer -instruct zLoadP(iRegPNoSp dst, memory mem, iRegPNoSp tmp) +instruct zLoadP(iRegPNoSp dst, memory mem, iRegPNoSp tmp, rFlagsReg cr) %{ match(Set dst (LoadP mem)); predicate(UseZGC && ZGenerational && n->as_Load()->barrier_data() != 0); - effect(TEMP dst, TEMP tmp); + effect(TEMP dst, TEMP tmp, KILL cr); ins_cost(4 * DEFAULT_COST); @@ -110,11 +110,11 @@ instruct zLoadP(iRegPNoSp dst, memory mem, iRegPNoSp tmp) %} // Store Pointer -instruct zStoreP(memory mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2) +instruct zStoreP(memory mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, rFlagsReg cr) %{ predicate(UseZGC && ZGenerational && n->as_Store()->barrier_data() != 0); match(Set mem (StoreP mem src)); - effect(TEMP tmp1, TEMP tmp2); + effect(TEMP tmp1, TEMP tmp2, KILL cr); ins_cost(125); // XXX format %{ "sd $mem, $src\t# ptr" %} @@ -127,11 +127,11 @@ instruct zStoreP(memory mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2) %} instruct zCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, - iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, iRegPNoSp tmp1) %{ + iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, iRegPNoSp tmp1, rFlagsReg cr) %{ match(Set res (CompareAndSwapP mem (Binary oldval newval))); match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); predicate(UseZGC && ZGenerational && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); - effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP tmp1, TEMP_DEF res); + effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP tmp1, TEMP_DEF res, KILL cr); ins_cost(2 * VOLATILE_REF_COST); @@ -150,11 +150,11 @@ instruct zCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newva %} instruct zCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, - iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, iRegPNoSp tmp1) %{ + iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, iRegPNoSp tmp1, rFlagsReg cr) %{ match(Set res (CompareAndSwapP mem (Binary oldval newval))); match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); predicate(UseZGC && ZGenerational && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); - effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP tmp1, TEMP_DEF res); + effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP tmp1, TEMP_DEF res, KILL cr); ins_cost(2 * VOLATILE_REF_COST); @@ -173,10 +173,10 @@ instruct zCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP ne %} instruct zCompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, - iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, iRegPNoSp tmp1) %{ + iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, iRegPNoSp tmp1, rFlagsReg cr) %{ match(Set res (CompareAndExchangeP mem (Binary oldval newval))); predicate(UseZGC && ZGenerational && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); - effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP tmp1, TEMP_DEF res); + effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP tmp1, TEMP_DEF res, KILL cr); ins_cost(2 * VOLATILE_REF_COST); @@ -195,10 +195,10 @@ instruct zCompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP n %} instruct zCompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, - iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, iRegPNoSp tmp1) %{ + iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, iRegPNoSp tmp1, rFlagsReg cr) %{ match(Set res (CompareAndExchangeP mem (Binary oldval newval))); predicate(UseZGC && ZGenerational && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); - effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP tmp1, TEMP_DEF res); + effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP tmp1, TEMP_DEF res, KILL cr); ins_cost(2 * VOLATILE_REF_COST); @@ -216,10 +216,10 @@ instruct zCompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iReg ins_pipe(pipe_slow); %} -instruct zGetAndSetP(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp) %{ +instruct zGetAndSetP(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp, rFlagsReg cr) %{ match(Set prev (GetAndSetP mem newv)); predicate(UseZGC && ZGenerational && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); - effect(TEMP_DEF prev, TEMP tmp); + effect(TEMP_DEF prev, TEMP tmp, KILL cr); ins_cost(2 * VOLATILE_REF_COST); @@ -234,10 +234,10 @@ instruct zGetAndSetP(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp) %{ ins_pipe(pipe_serial); %} -instruct zGetAndSetPAcq(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp) %{ +instruct zGetAndSetPAcq(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp, rFlagsReg cr) %{ match(Set prev (GetAndSetP mem newv)); predicate(UseZGC && ZGenerational && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); - effect(TEMP_DEF prev, TEMP tmp); + effect(TEMP_DEF prev, TEMP tmp, KILL cr); ins_cost(2 * VOLATILE_REF_COST); From e6698f51a1977d553ce4e1dd14b43b0d325224fa Mon Sep 17 00:00:00 2001 From: "t.ogata" Date: Tue, 15 Oct 2024 07:47:42 +0000 Subject: [PATCH 058/118] 8337851: Some tests have name which confuse jtreg Reviewed-by: aivanov, prr, cstein --- test/jdk/java/awt/dnd/{ => URLDragTest}/URLDragTest.java | 0 .../generics/{ => parametricException}/ParametricException.java | 0 test/langtools/tools/javac/warnings/{ => Serial}/Serial.java | 0 test/langtools/tools/javac/warnings/{ => Serial}/Serial.out | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename test/jdk/java/awt/dnd/{ => URLDragTest}/URLDragTest.java (100%) rename test/langtools/tools/javac/generics/{ => parametricException}/ParametricException.java (100%) rename test/langtools/tools/javac/warnings/{ => Serial}/Serial.java (100%) rename test/langtools/tools/javac/warnings/{ => Serial}/Serial.out (100%) diff --git a/test/jdk/java/awt/dnd/URLDragTest.java b/test/jdk/java/awt/dnd/URLDragTest/URLDragTest.java similarity index 100% rename from test/jdk/java/awt/dnd/URLDragTest.java rename to test/jdk/java/awt/dnd/URLDragTest/URLDragTest.java diff --git a/test/langtools/tools/javac/generics/ParametricException.java b/test/langtools/tools/javac/generics/parametricException/ParametricException.java similarity index 100% rename from test/langtools/tools/javac/generics/ParametricException.java rename to test/langtools/tools/javac/generics/parametricException/ParametricException.java diff --git a/test/langtools/tools/javac/warnings/Serial.java b/test/langtools/tools/javac/warnings/Serial/Serial.java similarity index 100% rename from test/langtools/tools/javac/warnings/Serial.java rename to test/langtools/tools/javac/warnings/Serial/Serial.java diff --git a/test/langtools/tools/javac/warnings/Serial.out b/test/langtools/tools/javac/warnings/Serial/Serial.out similarity index 100% rename from test/langtools/tools/javac/warnings/Serial.out rename to test/langtools/tools/javac/warnings/Serial/Serial.out From 521effe017b9b6322036f1851220056a637d6b1c Mon Sep 17 00:00:00 2001 From: Per Minborg Date: Tue, 15 Oct 2024 07:59:33 +0000 Subject: [PATCH 059/118] 8340189: 8339531 incorrect for Big Endian platforms Reviewed-by: mdoerr, amitkumar --- .../foreign/SegmentBulkOperations.java | 26 +++++++------------ 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java b/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java index 30e146a82f49b..d5a5954fa0e0b 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java +++ b/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java @@ -200,8 +200,8 @@ private static long mismatch(AbstractMemorySegmentImpl src, long srcFromOffset, int offset = 0; final int limit = length & (NATIVE_THRESHOLD_MISMATCH - 8); for (; offset < limit; offset += 8) { - final long s = SCOPED_MEMORY_ACCESS.getLongUnaligned(src.sessionImpl(), src.unsafeGetBase(), src.unsafeGetOffset() + srcFromOffset + offset, !Architecture.isLittleEndian()); - final long d = SCOPED_MEMORY_ACCESS.getLongUnaligned(dst.sessionImpl(), dst.unsafeGetBase(), dst.unsafeGetOffset() + dstFromOffset + offset, !Architecture.isLittleEndian()); + final long s = SCOPED_MEMORY_ACCESS.getLongUnaligned(src.sessionImpl(), src.unsafeGetBase(), src.unsafeGetOffset() + srcFromOffset + offset, false); + final long d = SCOPED_MEMORY_ACCESS.getLongUnaligned(dst.sessionImpl(), dst.unsafeGetBase(), dst.unsafeGetOffset() + dstFromOffset + offset, false); if (s != d) { return start + offset + mismatch(s, d); } @@ -210,8 +210,8 @@ private static long mismatch(AbstractMemorySegmentImpl src, long srcFromOffset, // 0...0X00 if (remaining >= 4) { - final int s = SCOPED_MEMORY_ACCESS.getIntUnaligned(src.sessionImpl(), src.unsafeGetBase(), src.unsafeGetOffset() + srcFromOffset + offset, !Architecture.isLittleEndian()); - final int d = SCOPED_MEMORY_ACCESS.getIntUnaligned(dst.sessionImpl(), dst.unsafeGetBase(), dst.unsafeGetOffset() + dstFromOffset + offset, !Architecture.isLittleEndian()); + final int s = SCOPED_MEMORY_ACCESS.getIntUnaligned(src.sessionImpl(), src.unsafeGetBase(), src.unsafeGetOffset() + srcFromOffset + offset, false); + final int d = SCOPED_MEMORY_ACCESS.getIntUnaligned(dst.sessionImpl(), dst.unsafeGetBase(), dst.unsafeGetOffset() + dstFromOffset + offset, false); if (s != d) { return start + offset + mismatch(s, d); } @@ -220,8 +220,8 @@ private static long mismatch(AbstractMemorySegmentImpl src, long srcFromOffset, } // 0...00X0 if (remaining >= 2) { - final short s = SCOPED_MEMORY_ACCESS.getShortUnaligned(src.sessionImpl(), src.unsafeGetBase(), src.unsafeGetOffset() + srcFromOffset + offset, !Architecture.isLittleEndian()); - final short d = SCOPED_MEMORY_ACCESS.getShortUnaligned(dst.sessionImpl(), dst.unsafeGetBase(), dst.unsafeGetOffset() + dstFromOffset + offset, !Architecture.isLittleEndian()); + final short s = SCOPED_MEMORY_ACCESS.getShortUnaligned(src.sessionImpl(), src.unsafeGetBase(), src.unsafeGetOffset() + srcFromOffset + offset, false); + final short d = SCOPED_MEMORY_ACCESS.getShortUnaligned(dst.sessionImpl(), dst.unsafeGetBase(), dst.unsafeGetOffset() + dstFromOffset + offset, false); if (s != d) { return start + offset + mismatch(s, d); } @@ -243,26 +243,18 @@ private static long mismatch(AbstractMemorySegmentImpl src, long srcFromOffset, @ForceInline private static int mismatch(long first, long second) { final long x = first ^ second; - return (Architecture.isLittleEndian() - ? Long.numberOfTrailingZeros(x) - : Long.numberOfLeadingZeros(x)) / 8; + return Long.numberOfTrailingZeros(x) / 8; } @ForceInline private static int mismatch(int first, int second) { final int x = first ^ second; - return (Architecture.isLittleEndian() - ? Integer.numberOfTrailingZeros(x) - : Integer.numberOfLeadingZeros(x)) / 8; + return Integer.numberOfTrailingZeros(x) / 8; } @ForceInline private static int mismatch(short first, short second) { - if (Architecture.isLittleEndian()) { - return ((0xff & first) == (0xff & second)) ? 1 : 0; - } else { - return ((0xff & first) == (0xff & second)) ? 0 : 1; - } + return ((0xff & first) == (0xff & second)) ? 1 : 0; } /** From 3b8a2f8c45ffd0bdb48db805cf70b4652525d891 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Tue, 15 Oct 2024 08:46:23 +0000 Subject: [PATCH 060/118] 8337269: G1ConfidencePercent interpreted inconsistently Reviewed-by: kbarrett, iwalulya --- src/hotspot/share/gc/g1/g1Policy.cpp | 2 +- src/hotspot/share/gc/g1/g1Predictions.hpp | 17 ++++++++--------- src/hotspot/share/gc/g1/g1_globals.hpp | 3 ++- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index 6d0864f032c86..1b71901f0fe05 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -53,7 +53,7 @@ #include "gc/shared/gcTraceTime.inline.hpp" G1Policy::G1Policy(STWGCTimer* gc_timer) : - _predictor(G1ConfidencePercent / 100.0), + _predictor((100 - G1ConfidencePercent) / 100.0), _analytics(new G1Analytics(&_predictor)), _remset_tracker(), _mmu_tracker(new G1MMUTracker(GCPauseIntervalMillis / 1000.0, MaxGCPauseMillis / 1000.0)), diff --git a/src/hotspot/share/gc/g1/g1Predictions.hpp b/src/hotspot/share/gc/g1/g1Predictions.hpp index 510f296a9f3ac..ae2a8f418802a 100644 --- a/src/hotspot/share/gc/g1/g1Predictions.hpp +++ b/src/hotspot/share/gc/g1/g1Predictions.hpp @@ -29,8 +29,9 @@ // Utility class containing various helper methods for prediction. class G1Predictions { - private: - double _sigma; +private: + // Scale factor indicating to which degree stddev should be taking into account in predictions. + double _stddev_scale; // This function is used to estimate the stddev of sample sets. There is some // special consideration of small sample sets: the actual stddev for them is @@ -46,16 +47,14 @@ class G1Predictions { } return estimate; } - public: - G1Predictions(double sigma) : _sigma(sigma) { - assert(sigma >= 0.0, "Confidence must be larger than or equal to zero"); - } - // Confidence factor. - double sigma() const { return _sigma; } +public: + G1Predictions(double stddev_scale) : _stddev_scale(stddev_scale) { + assert(stddev_scale >= 0.0, "must be"); + } double predict(TruncatedSeq const* seq) const { - return seq->davg() + _sigma * stddev_estimate(seq); + return seq->davg() + _stddev_scale * stddev_estimate(seq); } double predict_in_unit_interval(TruncatedSeq const* seq) const { diff --git a/src/hotspot/share/gc/g1/g1_globals.hpp b/src/hotspot/share/gc/g1/g1_globals.hpp index c8016ddc0ddf5..ed02ba2dc5cad 100644 --- a/src/hotspot/share/gc/g1/g1_globals.hpp +++ b/src/hotspot/share/gc/g1/g1_globals.hpp @@ -111,7 +111,8 @@ range(1, max_intx) \ \ product(uint, G1ConfidencePercent, 50, \ - "Confidence level for MMU/pause predictions") \ + "Confidence level for MMU/pause predictions. A higher value " \ + "means that G1 will use less safety margin for its predictions.") \ range(1, 100) \ \ product(uintx, G1SummarizeRSetStatsPeriod, 0, DIAGNOSTIC, \ From f4dccfd4cf354f360b823c8cce15bb54ef90e9ca Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Tue, 15 Oct 2024 09:10:13 +0000 Subject: [PATCH 061/118] 8338596: Clarify handling of restricted and caller-sensitive methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Hannes Wallnöfer Reviewed-by: alanb, jvernee --- .../lang/doc-files/RestrictedMethods.html | 53 +++++++++++++++++++ .../java/lang/foreign/package-info.java | 40 -------------- .../formats/html/HtmlDocletWriter.java | 28 +++++++--- .../html/resources/standard.properties | 3 +- .../doclets/toolkit/util/DocPaths.java | 3 ++ 5 files changed, 78 insertions(+), 49 deletions(-) create mode 100644 src/java.base/share/classes/java/lang/doc-files/RestrictedMethods.html diff --git a/src/java.base/share/classes/java/lang/doc-files/RestrictedMethods.html b/src/java.base/share/classes/java/lang/doc-files/RestrictedMethods.html new file mode 100644 index 0000000000000..413adf8e0630d --- /dev/null +++ b/src/java.base/share/classes/java/lang/doc-files/RestrictedMethods.html @@ -0,0 +1,53 @@ + + + + + Restricted methods + + +

Restricted methods

+

Various methods in the Java SE API allow Java code to interoperate with resources outside the Java runtime + in such a way that the runtime cannot prove correct or safe use of the resources. These methods can, + when used incorrectly, violate the integrity of the Java Virtual Machine, but are conditionally made available + to users, as they provide essential functionality. They are known as restricted methods.

+

Given the potential danger of restricted methods, the Java runtime issues a warning on + the standard error stream every time a restricted method is invoked. Such warnings can + be disabled by granting access to restricted methods to selected modules. This can be + done either via implementation-specific command line options or programmatically, e.g. + by calling ModuleLayer.Controller.enableNativeAccess(java.lang.Module).

+

When a restricted method is invoked by JNI code, + or from an upcall stub + and there is no caller class on the stack, it is as if the restricted method call occurred in an unnamed module.

+

In the reference implementation, access to restricted methods can be granted to + specific modules using the command line option --enable-native-access=M1,M2, ... Mn, + where M1, M2, ... Mn are module names (for the unnamed module, + the special value ALL-UNNAMED can be used). Access to restricted methods + from modules not listed by that option is deemed illegal. Clients can + control how access to restricted methods is handled, using the command line + option --illegal-native-access. If this option is not specified, + illegal access to restricted methods will result in runtime warnings.

+ + diff --git a/src/java.base/share/classes/java/lang/foreign/package-info.java b/src/java.base/share/classes/java/lang/foreign/package-info.java index 1f31301638e05..18419ba1877d8 100644 --- a/src/java.base/share/classes/java/lang/foreign/package-info.java +++ b/src/java.base/share/classes/java/lang/foreign/package-info.java @@ -128,49 +128,9 @@ * {@linkplain java.lang.foreign.SegmentAllocator#allocateFrom(java.lang.String) converting} * Java strings into zero-terminated, UTF-8 strings, as demonstrated in the above example. * - *

Restricted methods

- * - * Some methods in this package are considered restricted. Restricted methods - * are typically used to bind native foreign data and/or functions to first-class - * Java API elements which can then be used directly by clients. For instance the - * restricted method {@link java.lang.foreign.MemorySegment#reinterpret(long)} can be - * used to create a fresh segment with the same address and temporal bounds, but with - * the provided size. This can be useful to resize memory segments obtained when - * interacting with native functions. - *

- * Binding foreign data and/or functions is generally unsafe and, if done incorrectly, - * can result in VM crashes, or memory corruption when the bound Java API element - * is accessed. For instance, incorrectly resizing a native memory segment using - * {@link java.lang.foreign.MemorySegment#reinterpret(long)} can lead to a JVM crash, or, - * worse, lead to silent memory corruption when attempting to access the resized segment. - * For these reasons, it is crucial for code that calls a restricted method to never pass - * arguments that might cause incorrect binding of foreign data and/or functions to - * a Java API. - *

- * Given the potential danger of restricted methods, the Java runtime issues a warning on - * the standard error stream every time a restricted method is invoked. Such warnings can - * be disabled by granting access to restricted methods to selected modules. This can be - * done either via implementation-specific command line options or programmatically, e.g. - * by calling {@link java.lang.ModuleLayer.Controller#enableNativeAccess(java.lang.Module)}. - *

- * For every class in this package, unless specified otherwise, any method arguments of - * reference type must not be {@code null}, and any null argument will elicit a - * {@code NullPointerException}. This fact is not individually documented for methods of - * this API. - * * @apiNote Usual memory model guarantees (see {@jls 17.4}) do not apply when accessing * native memory segments as these segments are backed by off-heap regions of memory. * - * @implNote - * In the reference implementation, access to restricted methods can be granted to - * specific modules using the command line option {@code --enable-native-access=M1,M2, ... Mn}, - * where {@code M1}, {@code M2}, {@code ... Mn} are module names (for the unnamed module, - * the special value {@code ALL-UNNAMED} can be used). Access to restricted methods - * from modules not listed by that option is deemed illegal. Clients can - * control how access to restricted methods is handled, using the command line - * option {@code --illegal-native-access}. If this option is not specified, - * illegal access to restricted methods will result in runtime warnings. - * * @spec jni/index.html Java Native Interface Specification * * @since 22 diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java index fdf05489168f7..9bb1ebaaf620b 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java @@ -2642,19 +2642,31 @@ public void addRestrictedInfo(ExecutableElement forWhat, Content target) { //in Java platform: var restrictedDiv = HtmlTree.DIV(HtmlStyles.restrictedBlock); restrictedDiv.setId(htmlIds.forRestrictedSection(forWhat)); - String name = forWhat.getSimpleName().toString(); + var name = forWhat.getSimpleName().toString(); var nameCode = HtmlTree.CODE(Text.of(name)); - String leadingNoteKey = "doclet.RestrictedLeadingNote"; - Content leadingNote = - contents.getContent(leadingNoteKey, nameCode); - restrictedDiv.add(HtmlTree.SPAN(HtmlStyles.restrictedLabel, - leadingNote)); - Content note1 = contents.getContent("doclet.RestrictedTrailingNote1", nameCode); + var restrictedMethodLink = getRestrictedMethodDocLink(); + var leadingNoteKey = "doclet.RestrictedLeadingNote"; + var leadingNote = contents.getContent(leadingNoteKey, nameCode, restrictedMethodLink); + restrictedDiv.add(HtmlTree.SPAN(HtmlStyles.restrictedLabel, leadingNote)); + var note1 = contents.getContent("doclet.RestrictedTrailingNote1", nameCode); restrictedDiv.add(HtmlTree.DIV(HtmlStyles.restrictedComment, note1)); - Content note2 = contents.getContent("doclet.RestrictedTrailingNote2", nameCode); + var note2 = contents.getContent("doclet.RestrictedTrailingNote2", nameCode); restrictedDiv.add(HtmlTree.DIV(HtmlStyles.restrictedComment, note2)); target.add(restrictedDiv); } } + private Content getRestrictedMethodDocLink() { + var restrictedMethodLabel = contents.getContent("doclet.RestrictedMethod"); + var javaLang = utils.elementUtils.getPackageElement("java.lang"); + if (utils.isIncluded(javaLang)) { + var restrictedDocPath = pathToRoot + .resolve(docPaths.forPackage(javaLang)) + .resolve(DocPaths.DOC_FILES) + .resolve(DocPaths.RESTRICTED_DOC); + return links.createLink(restrictedDocPath, restrictedMethodLabel); + } + return restrictedMethodLabel; + } + } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties index 6141ce46fe8fc..bb001912229c2 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties @@ -424,7 +424,8 @@ doclet.ReflectivePreviewAPI={0} refers to one or more reflective preview APIs: doclet.UsesDeclaredUsingPreview={0} refers to one or more types which are declared using a preview feature of the Java language: {1}. doclet.PreviewTrailingNote1=Programs can only use {0} when preview features are enabled. doclet.PreviewTrailingNote2=Preview features may be removed in a future release, or upgraded to permanent features of the Java platform. -doclet.RestrictedLeadingNote={0} is a restricted method of the Java platform. +doclet.RestrictedMethod=restricted method +doclet.RestrictedLeadingNote={0} is a {1} of the Java platform. doclet.RestrictedTrailingNote1=Programs can only use {0} when access to restricted methods is enabled. doclet.RestrictedTrailingNote2=Restricted methods are unsafe, and, if used incorrectly, might crash \ the JVM or result in memory corruption. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocPaths.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocPaths.java index 5ae2d1590721c..47cf3e81ebed5 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocPaths.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocPaths.java @@ -163,6 +163,9 @@ public static DocPath indexN(int n) { /** The name of the file for restricted methods. */ public static final DocPath RESTRICTED_LIST = DocPath.create("restricted-list.html"); + /** The name of the doc-file for restricted methods. */ + public static final DocPath RESTRICTED_DOC = DocPath.create("RestrictedMethods.html"); + /** The name of the directory for the resource files. */ public static final DocPath RESOURCE_FILES = DocPath.create("resource-files"); From c9a536c330d37632139a1d71b0c054352eae5aa0 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Tue, 15 Oct 2024 09:15:40 +0000 Subject: [PATCH 062/118] 8337339: gc/arguments/Test*SizeFlags.java timing out with Xcomp Reviewed-by: shade, iwalulya --- test/hotspot/jtreg/gc/arguments/TestG1HeapSizeFlags.java | 1 + test/hotspot/jtreg/gc/arguments/TestParallelHeapSizeFlags.java | 1 + test/hotspot/jtreg/gc/arguments/TestSerialHeapSizeFlags.java | 1 + 3 files changed, 3 insertions(+) diff --git a/test/hotspot/jtreg/gc/arguments/TestG1HeapSizeFlags.java b/test/hotspot/jtreg/gc/arguments/TestG1HeapSizeFlags.java index 24e542881c0c3..4b69421e6e336 100644 --- a/test/hotspot/jtreg/gc/arguments/TestG1HeapSizeFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestG1HeapSizeFlags.java @@ -29,6 +29,7 @@ * @summary Tests argument processing for initial and maximum heap size for the G1 collector * @key flag-sensitive * @requires vm.gc.G1 & vm.opt.MinHeapSize == null & vm.opt.MaxHeapSize == null & vm.opt.InitialHeapSize == null + * @requires vm.compMode != "Xcomp" * @library /test/lib * @library / * @modules java.base/jdk.internal.misc diff --git a/test/hotspot/jtreg/gc/arguments/TestParallelHeapSizeFlags.java b/test/hotspot/jtreg/gc/arguments/TestParallelHeapSizeFlags.java index 544064953dfb2..ca8d1e74895b3 100644 --- a/test/hotspot/jtreg/gc/arguments/TestParallelHeapSizeFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestParallelHeapSizeFlags.java @@ -30,6 +30,7 @@ * parallel collectors. * @key flag-sensitive * @requires vm.gc.Parallel & vm.opt.MinHeapSize == null & vm.opt.MaxHeapSize == null & vm.opt.InitialHeapSize == null + * @requires vm.compMode != "Xcomp" * @library /test/lib * @library / * @modules java.base/jdk.internal.misc diff --git a/test/hotspot/jtreg/gc/arguments/TestSerialHeapSizeFlags.java b/test/hotspot/jtreg/gc/arguments/TestSerialHeapSizeFlags.java index c580245a2a39e..b9cc0f231f2e6 100644 --- a/test/hotspot/jtreg/gc/arguments/TestSerialHeapSizeFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestSerialHeapSizeFlags.java @@ -29,6 +29,7 @@ * @summary Tests argument processing for initial and maximum heap size for the Serial collector * @key flag-sensitive * @requires vm.gc.Serial & vm.opt.MinHeapSize == null & vm.opt.MaxHeapSize == null & vm.opt.InitialHeapSize == null + * @requires vm.compMode != "Xcomp" * @library /test/lib * @library / * @modules java.base/jdk.internal.misc From df7d6e081ff9513fbd6cff5d033a307e6798418b Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Tue, 15 Oct 2024 10:50:45 +0000 Subject: [PATCH 063/118] 8338603: DiagnosticCommandMBean operations should standardize types for parameters Reviewed-by: cjplummer, egahlin --- .../internal/DiagnosticCommandImpl.java | 20 +++++++- .../DiagnosticCommandMBean/DcmdMBeanTest.java | 46 ++++++++++++++++--- 2 files changed, 58 insertions(+), 8 deletions(-) diff --git a/src/jdk.management/share/classes/com/sun/management/internal/DiagnosticCommandImpl.java b/src/jdk.management/share/classes/com/sun/management/internal/DiagnosticCommandImpl.java index be84beb03bb46..eee0ea051d4fe 100644 --- a/src/jdk.management/share/classes/com/sun/management/internal/DiagnosticCommandImpl.java +++ b/src/jdk.management/share/classes/com/sun/management/internal/DiagnosticCommandImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -317,7 +317,7 @@ private Descriptor commandDescriptor(Wrapper w) throws IllegalArgumentException for (DiagnosticCommandArgumentInfo arginfo : w.info.getArgumentsInfo()) { HashMap argmap = new HashMap<>(); argmap.put("dcmd.arg.name", arginfo.getName()); - argmap.put("dcmd.arg.type", arginfo.getType()); + argmap.put("dcmd.arg.type", sanitiseType(arginfo.getType())); argmap.put("dcmd.arg.description", arginfo.getDescription()); argmap.put("dcmd.arg.isMandatory", arginfo.isMandatory()); argmap.put("dcmd.arg.isMultiple", arginfo.isMultiple()); @@ -335,6 +335,22 @@ private Descriptor commandDescriptor(Wrapper w) throws IllegalArgumentException return new ImmutableDescriptor(map); } + // Type names that will be published in dcmd.arg.type: + private static final String [] publicTypes = new String [] { "INT", "STRING", "BOOLEAN", "STRING SET", "MEMORY SIZE", "NANOTIME" }; + + private static final String sanitiseType(String typeName) { + // For any typeName not in the set to be made public, return "STRING". + if (typeName == null) { + return null; + } + for (String t : publicTypes) { + if (typeName.equals(t)) { + return t; + } + } + return "STRING"; + } + private static final String notifName = "javax.management.Notification"; diff --git a/test/jdk/com/sun/management/DiagnosticCommandMBean/DcmdMBeanTest.java b/test/jdk/com/sun/management/DiagnosticCommandMBean/DcmdMBeanTest.java index 3cc9f40b8957c..ba6fffd067025 100644 --- a/test/jdk/com/sun/management/DiagnosticCommandMBean/DcmdMBeanTest.java +++ b/test/jdk/com/sun/management/DiagnosticCommandMBean/DcmdMBeanTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * 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 7150256 + * @bug 7150256 8338603 * @summary Basic Test for the DiagnosticCommandMBean * @author Frederic Parain, Shanliang JIANG * @@ -68,10 +68,14 @@ public static void main(String[] args) throws Exception { System.out.println("Description:" + info.getDescription()); MBeanOperationInfo[] opInfo = info.getOperations(); System.out.println("Operations:"); + int operationFailures = 0; for (int i = 0; i < opInfo.length; i++) { - printOperation(opInfo[i]); + operationFailures += printOperation(opInfo[i]); System.out.println("\n@@@@@@\n"); } + if (operationFailures > 0) { + throw new RuntimeException("FAILED. " + operationFailures + " operations found with non-standard parameter types."); + } } finally { try { cc.close(); @@ -83,7 +87,12 @@ public static void main(String[] args) throws Exception { System.out.println("Test passed"); } - static void printOperation(MBeanOperationInfo info) { + /** + * Print an Operation, and check for any non-standard parameter types. + * Return the number of failed parameters, so the caller can signal to fail the test. + */ + static int printOperation(MBeanOperationInfo info) { + int failures = 0; System.out.println("Name: "+info.getName()); System.out.println("Description: "+info.getDescription()); System.out.println("Return Type: "+info.getReturnType()); @@ -100,8 +109,16 @@ static void printOperation(MBeanOperationInfo info) { Descriptor desc3 = (Descriptor)desc2.getFieldValue(desc2.getFieldNames()[j]); for(int k=0; k Date: Mon, 5 Feb 2024 22:53:51 +0000 Subject: [PATCH 064/118] 8302111: Serialization considerations Reviewed-by: skoivu, rhalade, weijun, wetmore --- .../com/sun/crypto/provider/DHPrivateKey.java | 291 ++++++++++-------- .../com/sun/crypto/provider/DHPublicKey.java | 243 +++++++++------ .../provider/TlsMasterSecretGenerator.java | 38 +-- .../classes/java/security/Permissions.java | 7 +- .../classes/java/security/SignedObject.java | 54 ++-- .../classes/java/security/Timestamp.java | 14 +- .../UnresolvedPermissionCollection.java | 38 ++- .../cert/CertificateRevokedException.java | 23 +- .../javax/crypto/spec/SecretKeySpec.java | 30 +- .../auth/callback/ChoiceCallback.java | 59 ++-- .../auth/callback/ConfirmationCallback.java | 139 +++++---- .../auth/callback/PasswordCallback.java | 6 +- .../classes/sun/security/provider/DRBG.java | 12 +- .../sun/security/util/ObjectIdentifier.java | 18 +- .../classes/sun/security/x509/AlgIdDSA.java | 123 ++++---- .../sun/security/jgss/krb5/Krb5Context.java | 19 +- .../jgss/krb5/Krb5InitCredential.java | 17 +- .../sun/security/krb5/internal/KRBError.java | 44 +-- .../classes/sun/security/pkcs11/P11Key.java | 13 + .../sun/security/pkcs11/P11SecureRandom.java | 16 +- .../sun/security/pkcs11/SunPKCS11.java | 13 + 21 files changed, 748 insertions(+), 469 deletions(-) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DHPrivateKey.java b/src/java.base/share/classes/com/sun/crypto/provider/DHPrivateKey.java index 0d5363e866a95..fcdc3fbea49e6 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DHPrivateKey.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DHPrivateKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ final class DHPrivateKey implements PrivateKey, private final BigInteger x; // the key bytes, without the algorithm information + // cannot be final as it's re-assigned for deserialization private byte[] key; // the encoded key @@ -70,115 +71,85 @@ final class DHPrivateKey implements PrivateKey, // the private-value length (optional) private final int l; - /** - * Make a DH private key out of a private value x, a prime - * modulus p, and a base generator g. - * - * @param x the private value - * @param p the prime modulus - * @param g the base generator - */ - DHPrivateKey(BigInteger x, BigInteger p, BigInteger g) - throws InvalidKeyException { - this(x, p, g, 0); - } - - /** - * Make a DH private key out of a private value x, a prime - * modulus p, a base generator g, and a - * private-value length l. - * - * @param x the private value - * @param p the prime modulus - * @param g the base generator - * @param l the private-value length - */ - DHPrivateKey(BigInteger x, BigInteger p, BigInteger g, int l) { - this.x = x; - this.p = p; - this.g = g; - this.l = l; - byte[] xbytes = x.toByteArray(); - DerValue val = new DerValue(DerValue.tag_Integer, xbytes); - this.key = val.toByteArray(); - val.clear(); - Arrays.fill(xbytes, (byte) 0); - encode(); + private static class DHComponents { + final BigInteger x; + final BigInteger p; + final BigInteger g; + final int l; + final byte[] key; + + DHComponents(BigInteger x, BigInteger p, BigInteger g, int l, + byte[] key) { + this.x = x; + this.p = p; + this.g = g; + this.l = l; + this.key = key; + } } - /** - * Make a DH private key from its DER encoding (PKCS #8). - * - * @param encodedKey the encoded key - * - * @throws InvalidKeyException if the encoded key does not represent - * a Diffie-Hellman private key - */ - DHPrivateKey(byte[] encodedKey) throws InvalidKeyException { + // parses the specified encoding into a DHComponents object + private static DHComponents decode(byte[] encodedKey) + throws IOException { DerValue val = null; + try { val = new DerValue(encodedKey); if (val.tag != DerValue.tag_Sequence) { - throw new InvalidKeyException ("Key not a SEQUENCE"); + throw new IOException("Key not a SEQUENCE"); } - // // version - // BigInteger parsedVersion = val.data.getBigInteger(); if (!parsedVersion.equals(PKCS8_VERSION)) { throw new IOException("version mismatch: (supported: " + - PKCS8_VERSION + ", parsed: " + - parsedVersion); + PKCS8_VERSION + ", parsed: " + parsedVersion); } - // // privateKeyAlgorithm - // DerValue algid = val.data.getDerValue(); if (algid.tag != DerValue.tag_Sequence) { - throw new InvalidKeyException("AlgId is not a SEQUENCE"); + throw new IOException("AlgId is not a SEQUENCE"); } DerInputStream derInStream = algid.toDerInputStream(); ObjectIdentifier oid = derInStream.getOID(); if (oid == null) { - throw new InvalidKeyException("Null OID"); + throw new IOException("Null OID"); } if (derInStream.available() == 0) { - throw new InvalidKeyException("Parameters missing"); + throw new IOException("Parameters missing"); } // parse the parameters DerValue params = derInStream.getDerValue(); if (params.tag == DerValue.tag_Null) { - throw new InvalidKeyException("Null parameters"); + throw new IOException("Null parameters"); } if (params.tag != DerValue.tag_Sequence) { - throw new InvalidKeyException("Parameters not a SEQUENCE"); + throw new IOException("Parameters not a SEQUENCE"); } params.data.reset(); - this.p = params.data.getBigInteger(); - this.g = params.data.getBigInteger(); + BigInteger p = params.data.getBigInteger(); + BigInteger g = params.data.getBigInteger(); // Private-value length is OPTIONAL + int l = (params.data.available() != 0 ? + params.data.getInteger() : 0); + // should have no trailing data if (params.data.available() != 0) { - this.l = params.data.getInteger(); - } else { - this.l = 0; - } - if (params.data.available() != 0) { - throw new InvalidKeyException("Extra parameter data"); + throw new IOException("Extra parameter data"); } - // // privateKey - // - this.key = val.data.getOctetString(); - - DerInputStream in = new DerInputStream(this.key); - this.x = in.getBigInteger(); + byte[] key = val.data.getOctetString(); + DerInputStream in = new DerInputStream(key); + BigInteger x = in.getBigInteger(); - this.encodedKey = encodedKey.clone(); - } catch (IOException | NumberFormatException e) { - throw new InvalidKeyException("Error parsing key encoding", e); + // should have no trailing data + if (val.data.available() != 0) { + throw new IOException("Excess trailing data"); + } + return new DHComponents(x, p, g, l, key); + } catch (NumberFormatException e) { + throw new IOException("Error parsing key encoding", e); } finally { if (val != null) { val.clear(); @@ -186,6 +157,108 @@ final class DHPrivateKey implements PrivateKey, } } + // Generates the ASN.1 encoding + private static byte[] encode(BigInteger p, BigInteger g, int l, + byte[] key) { + DerOutputStream tmp = new DerOutputStream(); + + // version + tmp.putInteger(PKCS8_VERSION); + + // privateKeyAlgorithm + DerOutputStream algid = new DerOutputStream(); + + // store OID + algid.putOID(DHPublicKey.DH_OID); + // encode parameters + DerOutputStream params = new DerOutputStream(); + params.putInteger(p); + params.putInteger(g); + if (l != 0) { + params.putInteger(l); + } + // wrap parameters into SEQUENCE + DerValue paramSequence = new DerValue(DerValue.tag_Sequence, + params.toByteArray()); + // store parameter SEQUENCE in algid + algid.putDerValue(paramSequence); + // wrap algid into SEQUENCE + tmp.write(DerValue.tag_Sequence, algid); + + // privateKey + tmp.putOctetString(key); + + // make it a SEQUENCE + DerValue val = DerValue.wrap(DerValue.tag_Sequence, tmp); + byte[] encoded = val.toByteArray(); + val.clear(); + + return encoded; + } + + /** + * Make a DH private key out of a private value x, a prime + * modulus p, and a base generator g. + * + * @param x the private value + * @param p the prime modulus + * @param g the base generator + */ + DHPrivateKey(BigInteger x, BigInteger p, BigInteger g) + throws InvalidKeyException { + this(x, p, g, 0); + } + + /** + * Make a DH private key out of a private value x, a prime + * modulus p, a base generator g, and a + * private-value length l. + * + * @param x the private value + * @param p the prime modulus + * @param g the base generator + * @param l the private-value length + */ + DHPrivateKey(BigInteger x, BigInteger p, BigInteger g, int l) { + this.x = x; + this.p = p; + this.g = g; + this.l = l; + + byte[] xbytes = x.toByteArray(); + DerValue val = new DerValue(DerValue.tag_Integer, xbytes); + try { + this.key = val.toByteArray(); + } finally { + val.clear(); + Arrays.fill(xbytes, (byte) 0); + } + this.encodedKey = encode(p, g, l, key); + } + + /** + * Make a DH private key from its DER encoding (PKCS #8). + * + * @param encodedKey the encoded key + * + * @throws InvalidKeyException if the encoded key does not represent + * a Diffie-Hellman private key + */ + DHPrivateKey(byte[] encodedKey) throws InvalidKeyException { + this.encodedKey = encodedKey.clone(); + DHComponents dc; + try { + dc = decode(this.encodedKey); + } catch (IOException e) { + throw new InvalidKeyException("Invalid encoding", e); + } + this.x = dc.x; + this.p = dc.p; + this.g = dc.g; + this.l = dc.l; + this.key = dc.key; + } + /** * Returns the encoding format of this key: "PKCS#8" */ @@ -204,55 +277,9 @@ public String getAlgorithm() { * Get the encoding of the key. */ public synchronized byte[] getEncoded() { - encode(); return encodedKey.clone(); } - /** - * Generate the encodedKey field if it has not been calculated. - * Could generate null. - */ - private void encode() { - if (this.encodedKey == null) { - DerOutputStream tmp = new DerOutputStream(); - - // - // version - // - tmp.putInteger(PKCS8_VERSION); - - // - // privateKeyAlgorithm - // - DerOutputStream algid = new DerOutputStream(); - - // store OID - algid.putOID(DHPublicKey.DH_OID); - // encode parameters - DerOutputStream params = new DerOutputStream(); - params.putInteger(this.p); - params.putInteger(this.g); - if (this.l != 0) { - params.putInteger(this.l); - } - // wrap parameters into SEQUENCE - DerValue paramSequence = new DerValue(DerValue.tag_Sequence, - params.toByteArray()); - // store parameter SEQUENCE in algid - algid.putDerValue(paramSequence); - // wrap algid into SEQUENCE - tmp.write(DerValue.tag_Sequence, algid); - - // privateKey - tmp.putOctetString(this.key); - - // make it a SEQUENCE - DerValue val = DerValue.wrap(DerValue.tag_Sequence, tmp); - this.encodedKey = val.toByteArray(); - val.clear(); - } - } - /** * Returns the private value, x. * @@ -307,10 +334,7 @@ public boolean equals(Object obj) { */ @java.io.Serial private Object writeReplace() throws java.io.ObjectStreamException { - encode(); - return new KeyRep(KeyRep.Type.PRIVATE, - getAlgorithm(), - getFormat(), + return new KeyRep(KeyRep.Type.PRIVATE, getAlgorithm(), getFormat(), encodedKey); } @@ -330,11 +354,28 @@ private void readObject(ObjectInputStream stream) if ((key == null) || (key.length == 0)) { throw new InvalidObjectException("key not deserializable"); } - this.key = key.clone(); if ((encodedKey == null) || (encodedKey.length == 0)) { throw new InvalidObjectException( "encoded key not deserializable"); } - this.encodedKey = encodedKey.clone(); + // check if the "encodedKey" value matches the deserialized fields + DHComponents c; + byte[] encodedKeyIntern = encodedKey.clone(); + try { + c = decode(encodedKeyIntern); + } catch (IOException e) { + throw new InvalidObjectException("Invalid encoding", e); + } + if (!Arrays.equals(c.key, key) || !c.x.equals(x) || !c.p.equals(p) + || !c.g.equals(g) || c.l != l) { + throw new InvalidObjectException( + "encoded key not matching internal fields"); + } + // zero out external arrays + Arrays.fill(key, (byte)0x00); + Arrays.fill(encodedKey, (byte)0x00); + // use self-created internal copies + this.key = c.key; + this.encodedKey = encodedKeyIntern; } } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DHPublicKey.java b/src/java.base/share/classes/com/sun/crypto/provider/DHPublicKey.java index 47727c432a672..c95b40482d5bd 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DHPublicKey.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DHPublicKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * 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 @@ package com.sun.crypto.provider; import java.io.*; +import java.util.Arrays; import java.util.Objects; import java.math.BigInteger; import java.security.KeyRep; @@ -70,6 +71,116 @@ final class DHPublicKey implements PublicKey, static final ObjectIdentifier DH_OID = ObjectIdentifier.of(KnownOIDs.DiffieHellman); + private static class DHComponents { + final BigInteger y; + final BigInteger p; + final BigInteger g; + final int l; + final byte[] key; + + DHComponents(BigInteger y, BigInteger p, BigInteger g, int l, + byte[] key) { + this.y = y; + this.p = p; + this.g = g; + this.l = l; + this.key = key; + } + } + + // parses the specified encoding into a DHComponents object + private static DHComponents decode(byte[] encodedKey) + throws IOException { + DerValue val = null; + + try { + val = new DerValue(encodedKey); + if (val.tag != DerValue.tag_Sequence) { + throw new IOException("Invalid key format"); + } + + // algorithm identifier + DerValue algid = val.data.getDerValue(); + if (algid.tag != DerValue.tag_Sequence) { + throw new IOException("AlgId is not a SEQUENCE"); + } + DerInputStream derInStream = algid.toDerInputStream(); + ObjectIdentifier oid = derInStream.getOID(); + if (oid == null) { + throw new IOException("Null OID"); + } + if (derInStream.available() == 0) { + throw new IOException("Parameters missing"); + } + + // parse the parameters + DerValue params = derInStream.getDerValue(); + if (params.tag == DerValue.tag_Null) { + throw new IOException("Null parameters"); + } + if (params.tag != DerValue.tag_Sequence) { + throw new IOException("Parameters not a SEQUENCE"); + } + params.data.reset(); + + BigInteger p = params.data.getBigInteger(); + BigInteger g = params.data.getBigInteger(); + // Private-value length is OPTIONAL + int l = (params.data.available() != 0 ? params.data.getInteger() : + 0); + if (params.data.available() != 0) { + throw new IOException("Extra parameter data"); + } + + // publickey + byte[] key = val.data.getBitString(); + DerInputStream in = new DerInputStream(key); + BigInteger y = in.getBigInteger(); + + if (val.data.available() != 0) { + throw new IOException("Excess key data"); + } + return new DHComponents(y, p, g, l, key); + } catch (NumberFormatException e) { + throw new IOException("Error parsing key encoding", e); + } + } + + // generates the ASN.1 encoding + private static byte[] encode(BigInteger p, BigInteger g, int l, + byte[] key) { + DerOutputStream algid = new DerOutputStream(); + + // store oid in algid + algid.putOID(DH_OID); + + // encode parameters + DerOutputStream params = new DerOutputStream(); + params.putInteger(p); + params.putInteger(g); + if (l != 0) { + params.putInteger(l); + } + + // wrap parameters into SEQUENCE + DerValue paramSequence = new DerValue(DerValue.tag_Sequence, + params.toByteArray()); + // store parameter SEQUENCE in algid + algid.putDerValue(paramSequence); + + // wrap algid into SEQUENCE, and store it in key encoding + DerOutputStream tmpDerKey = new DerOutputStream(); + tmpDerKey.write(DerValue.tag_Sequence, algid); + + // store key data + tmpDerKey.putBitString(key); + + // wrap algid and key into SEQUENCE + DerOutputStream derKey = new DerOutputStream(); + derKey.write(DerValue.tag_Sequence, tmpDerKey); + return derKey.toByteArray(); + } + /** * Make a DH public key out of a public value y, a prime * modulus p, and a base generator g. @@ -102,7 +213,7 @@ final class DHPublicKey implements PublicKey, this.l = l; this.key = new DerValue(DerValue.tag_Integer, this.y.toByteArray()).toByteArray(); - this.encodedKey = getEncoded(); + this.encodedKey = encode(p, g, l, key); } /** @@ -114,68 +225,19 @@ final class DHPublicKey implements PublicKey, * a Diffie-Hellman public key */ DHPublicKey(byte[] encodedKey) throws InvalidKeyException { - InputStream inStream = new ByteArrayInputStream(encodedKey); - try { - DerValue derKeyVal = new DerValue(inStream); - if (derKeyVal.tag != DerValue.tag_Sequence) { - throw new InvalidKeyException ("Invalid key format"); - } - - /* - * Parse the algorithm identifier - */ - DerValue algid = derKeyVal.data.getDerValue(); - if (algid.tag != DerValue.tag_Sequence) { - throw new InvalidKeyException("AlgId is not a SEQUENCE"); - } - DerInputStream derInStream = algid.toDerInputStream(); - ObjectIdentifier oid = derInStream.getOID(); - if (oid == null) { - throw new InvalidKeyException("Null OID"); - } - if (derInStream.available() == 0) { - throw new InvalidKeyException("Parameters missing"); - } - - /* - * Parse the parameters - */ - DerValue params = derInStream.getDerValue(); - if (params.tag == DerValue.tag_Null) { - throw new InvalidKeyException("Null parameters"); - } - if (params.tag != DerValue.tag_Sequence) { - throw new InvalidKeyException("Parameters not a SEQUENCE"); - } - params.data.reset(); - this.p = params.data.getBigInteger(); - this.g = params.data.getBigInteger(); - // Private-value length is OPTIONAL - if (params.data.available() != 0) { - this.l = params.data.getInteger(); - } else { - this.l = 0; - } - if (params.data.available() != 0) { - throw new InvalidKeyException("Extra parameter data"); - } - - /* - * Parse the key - */ - this.key = derKeyVal.data.getBitString(); - - DerInputStream in = new DerInputStream(this.key); - this.y = in.getBigInteger(); - - if (derKeyVal.data.available() != 0) { - throw new InvalidKeyException("Excess key data"); - } + this.encodedKey = encodedKey.clone(); - this.encodedKey = encodedKey.clone(); - } catch (IOException | NumberFormatException e) { - throw new InvalidKeyException("Error parsing key encoding", e); + DHComponents dc; + try { + dc = decode(this.encodedKey); + } catch (IOException e) { + throw new InvalidKeyException("Invalid encoding", e); } + this.y = dc.y; + this.p = dc.p; + this.g = dc.g; + this.l = dc.l; + this.key = dc.key; } /** @@ -196,37 +258,6 @@ public String getAlgorithm() { * Get the encoding of the key. */ public synchronized byte[] getEncoded() { - if (this.encodedKey == null) { - DerOutputStream algid = new DerOutputStream(); - - // store oid in algid - algid.putOID(DH_OID); - - // encode parameters - DerOutputStream params = new DerOutputStream(); - params.putInteger(this.p); - params.putInteger(this.g); - if (this.l != 0) { - params.putInteger(this.l); - } - // wrap parameters into SEQUENCE - DerValue paramSequence = new DerValue(DerValue.tag_Sequence, - params.toByteArray()); - // store parameter SEQUENCE in algid - algid.putDerValue(paramSequence); - - // wrap algid into SEQUENCE, and store it in key encoding - DerOutputStream tmpDerKey = new DerOutputStream(); - tmpDerKey.write(DerValue.tag_Sequence, algid); - - // store key data - tmpDerKey.putBitString(this.key); - - // wrap algid and key into SEQUENCE - DerOutputStream derKey = new DerOutputStream(); - derKey.write(DerValue.tag_Sequence, tmpDerKey); - this.encodedKey = derKey.toByteArray(); - } return this.encodedKey.clone(); } @@ -263,8 +294,9 @@ public String toString() { + Debug.toHexString(this.p) + LINE_SEP + "g:" + LINE_SEP + Debug.toHexString(this.g)); - if (this.l != 0) + if (this.l != 0) { sb.append(LINE_SEP + "l:" + LINE_SEP + " " + this.l); + } return sb.toString(); } @@ -304,7 +336,7 @@ private Object writeReplace() throws java.io.ObjectStreamException { return new KeyRep(KeyRep.Type.PUBLIC, getAlgorithm(), getFormat(), - getEncoded()); + encodedKey); } /** @@ -323,11 +355,28 @@ private void readObject(ObjectInputStream stream) if ((key == null) || (key.length == 0)) { throw new InvalidObjectException("key not deserializable"); } - this.key = key.clone(); if ((encodedKey == null) || (encodedKey.length == 0)) { throw new InvalidObjectException( "encoded key not deserializable"); } - this.encodedKey = encodedKey.clone(); + // check if the "encodedKey" value matches the deserialized fields + DHComponents c; + byte[] encodedKeyIntern = encodedKey.clone(); + try { + c = decode(encodedKeyIntern); + } catch (IOException e) { + throw new InvalidObjectException("Invalid encoding", e); + } + if (!Arrays.equals(c.key, key) || !c.y.equals(y) || !c.p.equals(p) + || !c.g.equals(g) || c.l != l) { + throw new InvalidObjectException( + "encoded key not matching internal fields"); + } + // zero out external arrays + Arrays.fill(key, (byte)0x00); + Arrays.fill(encodedKey, (byte)0x00); + // use self-created internal copies + this.key = c.key; + this.encodedKey = encodedKeyIntern; } } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java b/src/java.base/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java index 14ada1699c18c..2762fb3751c1b 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * 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,22 +194,24 @@ public byte[] getEncoded() { return key.clone(); } - /** - * Restores the state of this object from the stream. - * - * @param stream the {@code ObjectInputStream} from which data is read - * @throws IOException if an I/O error occurs - * @throws ClassNotFoundException if a serialized class cannot be loaded - */ - @java.io.Serial - private void readObject(ObjectInputStream stream) - throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - if ((key == null) || (key.length == 0)) { - throw new InvalidObjectException("TlsMasterSecretKey is null"); - } - key = key.clone(); - } - } + /** + * Restores the state of this object from the stream. + * + * @param stream the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + stream.defaultReadObject(); + if (key == null || key.length == 0) { + throw new InvalidObjectException("TlsMasterSecretKey is null"); + } + byte[] temp = key; + this.key = temp.clone(); + Arrays.fill(temp, (byte)0); + } + } } diff --git a/src/java.base/share/classes/java/security/Permissions.java b/src/java.base/share/classes/java/security/Permissions.java index 42c1adc90021c..3bdeac6f92945 100644 --- a/src/java.base/share/classes/java/security/Permissions.java +++ b/src/java.base/share/classes/java/security/Permissions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -407,6 +407,11 @@ private void readObject(ObjectInputStream in) throws IOException, @SuppressWarnings("unchecked") Hashtable, PermissionCollection> perms = (Hashtable, PermissionCollection>)gfields.get("perms", null); + + if (perms == null) { + throw new InvalidObjectException("perms can't be null"); + } + permsMap = new ConcurrentHashMap<>(perms.size()*2); permsMap.putAll(perms); diff --git a/src/java.base/share/classes/java/security/SignedObject.java b/src/java.base/share/classes/java/security/SignedObject.java index e2f9c764ec2da..f65300fc80814 100644 --- a/src/java.base/share/classes/java/security/SignedObject.java +++ b/src/java.base/share/classes/java/security/SignedObject.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -152,20 +152,20 @@ public final class SignedObject implements Serializable { */ public SignedObject(Serializable object, PrivateKey signingKey, Signature signingEngine) - throws IOException, InvalidKeyException, SignatureException { - // creating a stream pipe-line, from a to b - ByteArrayOutputStream b = new ByteArrayOutputStream(); - ObjectOutput a = new ObjectOutputStream(b); + throws IOException, InvalidKeyException, SignatureException { + // creating a stream pipe-line, from a to b + ByteArrayOutputStream b = new ByteArrayOutputStream(); + ObjectOutput a = new ObjectOutputStream(b); - // write and flush the object content to byte array - a.writeObject(object); - a.flush(); - a.close(); - this.content = b.toByteArray(); - b.close(); + // write and flush the object content to byte array + a.writeObject(object); + a.flush(); + a.close(); + this.content = b.toByteArray(); + b.close(); - // now sign the encapsulated object - this.sign(signingKey, signingEngine); + // now sign the encapsulated object + this.sign(signingKey, signingEngine); } /** @@ -245,12 +245,12 @@ public boolean verify(PublicKey verificationKey, * @throws SignatureException if signing fails. */ private void sign(PrivateKey signingKey, Signature signingEngine) - throws InvalidKeyException, SignatureException { - // initialize the signing engine - signingEngine.initSign(signingKey); - signingEngine.update(this.content.clone()); - this.signature = signingEngine.sign().clone(); - this.thealgorithm = signingEngine.getAlgorithm(); + throws InvalidKeyException, SignatureException { + // initialize the signing engine + signingEngine.initSign(signingKey); + signingEngine.update(this.content.clone()); + this.signature = signingEngine.sign(); + this.thealgorithm = signingEngine.getAlgorithm(); } /** @@ -263,10 +263,16 @@ private void sign(PrivateKey signingKey, Signature signingEngine) */ @Serial private void readObject(ObjectInputStream s) - throws IOException, ClassNotFoundException { - ObjectInputStream.GetField fields = s.readFields(); - content = ((byte[])fields.get("content", null)).clone(); - signature = ((byte[])fields.get("signature", null)).clone(); - thealgorithm = (String)fields.get("thealgorithm", null); + throws IOException, ClassNotFoundException { + ObjectInputStream.GetField fields = s.readFields(); + byte[] c = (byte[]) fields.get("content", null); + byte[] sig = (byte[]) fields.get("signature", null); + String a = (String) fields.get("thealgorithm", null); + if (c == null || sig == null || a == null) { + throw new InvalidObjectException("One or more null fields"); + } + content = c.clone(); + signature = sig.clone(); + thealgorithm = a; } } diff --git a/src/java.base/share/classes/java/security/Timestamp.java b/src/java.base/share/classes/java/security/Timestamp.java index 10a93a9b180f7..96df37a8c1f2d 100644 --- a/src/java.base/share/classes/java/security/Timestamp.java +++ b/src/java.base/share/classes/java/security/Timestamp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * 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 +27,7 @@ import java.io.IOException; import java.io.ObjectInputStream; +import java.io.InvalidObjectException; import java.io.Serializable; import java.security.cert.CertPath; import java.security.cert.Certificate; @@ -78,7 +79,7 @@ public final class Timestamp implements Serializable { * {@code null}. */ public Timestamp(Date timestamp, CertPath signerCertPath) { - if (timestamp == null || signerCertPath == null) { + if (isNull(timestamp, signerCertPath)) { throw new NullPointerException(); } this.timestamp = new Date(timestamp.getTime()); // clone @@ -166,9 +167,16 @@ public String toString() { */ @java.io.Serial private void readObject(ObjectInputStream ois) - throws IOException, ClassNotFoundException { + throws IOException, ClassNotFoundException { ois.defaultReadObject(); + if (isNull(timestamp, signerCertPath)) { + throw new InvalidObjectException("Invalid null field(s)"); + } myhash = -1; timestamp = new Date(timestamp.getTime()); } + + private static boolean isNull(Date d, CertPath c) { + return (d == null || c == null); + } } diff --git a/src/java.base/share/classes/java/security/UnresolvedPermissionCollection.java b/src/java.base/share/classes/java/security/UnresolvedPermissionCollection.java index a5f4de22d89bc..c0bdf5fc2a1f8 100644 --- a/src/java.base/share/classes/java/security/UnresolvedPermissionCollection.java +++ b/src/java.base/share/classes/java/security/UnresolvedPermissionCollection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * 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,6 +29,7 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamField; +import java.io.InvalidObjectException; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; @@ -196,23 +197,32 @@ private void readObject(ObjectInputStream in) throws IOException, ObjectInputStream.GetField gfields = in.readFields(); // Get permissions - @SuppressWarnings("unchecked") // writeObject writes a Hashtable> // for the permissions key, so this cast is safe, unless the data is corrupt. - Hashtable> permissions = - (Hashtable>) - gfields.get("permissions", null); - perms = new ConcurrentHashMap<>(permissions.size()*2); + try { + @SuppressWarnings("unchecked") + Hashtable> permissions = + (Hashtable>) + gfields.get("permissions", null); + + if (permissions == null) { + throw new InvalidObjectException("Invalid null permissions"); + } - // Convert each entry (Vector) into a List - Set>> set = permissions.entrySet(); - for (Map.Entry> e : set) { - // Convert Vector into ArrayList - Vector vec = e.getValue(); - List list = new CopyOnWriteArrayList<>(vec); + perms = new ConcurrentHashMap<>(permissions.size()*2); - // Add to Hashtable being serialized - perms.put(e.getKey(), list); + // Convert each entry (Vector) into a List + Set>> set = permissions.entrySet(); + for (Map.Entry> e : set) { + // Convert Vector into ArrayList + Vector vec = e.getValue(); + List list = new CopyOnWriteArrayList<>(vec); + + // Add to Hashtable being serialized + perms.put(e.getKey(), list); + } + } catch (ClassCastException cce) { + throw new InvalidObjectException("Invalid type for permissions"); } } } diff --git a/src/java.base/share/classes/java/security/cert/CertificateRevokedException.java b/src/java.base/share/classes/java/security/cert/CertificateRevokedException.java index 70083033fc6e6..6649dcda6ccb2 100644 --- a/src/java.base/share/classes/java/security/cert/CertificateRevokedException.java +++ b/src/java.base/share/classes/java/security/cert/CertificateRevokedException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * 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,6 +28,7 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.IOException; +import java.io.InvalidObjectException; import java.util.Collections; import java.util.Date; import java.util.HashMap; @@ -70,6 +71,13 @@ public class CertificateRevokedException extends CertificateException { private transient Map extensions; + private static boolean isNull(Date revocationDate, + CRLReason reason, X500Principal authority, + Map extensions) { + return (revocationDate == null || reason == null || authority == null + || extensions == null); + } + /** * Constructs a {@code CertificateRevokedException} with * the specified revocation date, reason code, authority name, and map @@ -92,8 +100,7 @@ public class CertificateRevokedException extends CertificateException { */ public CertificateRevokedException(Date revocationDate, CRLReason reason, X500Principal authority, Map extensions) { - if (revocationDate == null || reason == null || authority == null || - extensions == null) { + if (isNull(revocationDate, reason, authority, extensions)) { throw new NullPointerException(); } this.revocationDate = new Date(revocationDate.getTime()); @@ -234,9 +241,6 @@ private void readObject(ObjectInputStream ois) // (revocationDate, reason, authority) ois.defaultReadObject(); - // Defensively copy the revocation date - revocationDate = new Date(revocationDate.getTime()); - // Read in the size (number of mappings) of the extensions map // and create the extensions map int size = ois.readInt(); @@ -247,6 +251,13 @@ private void readObject(ObjectInputStream ois) } else { extensions = HashMap.newHashMap(Math.min(size, 20)); } + // make sure all fields are set before checking + if (isNull(revocationDate, reason, authority, extensions)) { + throw new InvalidObjectException("Invalid null field(s)"); + } + + // Defensively copy the revocation date + revocationDate = new Date(revocationDate.getTime()); // Read in the extensions and put the mappings in the extensions map for (int i = 0; i < size; i++) { diff --git a/src/java.base/share/classes/javax/crypto/spec/SecretKeySpec.java b/src/java.base/share/classes/javax/crypto/spec/SecretKeySpec.java index e76a51e5d68c7..2ad9a7748f2e6 100644 --- a/src/java.base/share/classes/javax/crypto/spec/SecretKeySpec.java +++ b/src/java.base/share/classes/javax/crypto/spec/SecretKeySpec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * 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,11 +100,9 @@ public class SecretKeySpec implements KeySpec, SecretKey { * is null or key is null or empty. */ public SecretKeySpec(byte[] key, String algorithm) { - if (key == null || algorithm == null) { - throw new IllegalArgumentException("Missing argument"); - } - if (key.length == 0) { - throw new IllegalArgumentException("Empty key"); + String errMsg = doSanityCheck(key, algorithm); + if (errMsg != null) { + throw new IllegalArgumentException(errMsg); } this.key = key.clone(); this.algorithm = algorithm; @@ -266,14 +264,22 @@ void clear() { private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { stream.defaultReadObject(); - - if (key == null || algorithm == null) { - throw new InvalidObjectException("Missing argument"); + String errMsg = doSanityCheck(key, algorithm); + if (errMsg != null) { + throw new InvalidObjectException(errMsg); } + byte[] temp = key; + this.key = temp.clone(); + Arrays.fill(temp, (byte) 0); + } - this.key = key.clone(); - if (key.length == 0) { - throw new InvalidObjectException("Invalid key length"); + private static String doSanityCheck(byte[] key, String algorithm) { + String errMsg = null; + if (key == null || algorithm == null) { + errMsg = "Missing argument"; + } else if (key.length == 0) { + errMsg = "Empty key"; } + return errMsg; } } diff --git a/src/java.base/share/classes/javax/security/auth/callback/ChoiceCallback.java b/src/java.base/share/classes/javax/security/auth/callback/ChoiceCallback.java index c005b4ea02b0b..1c35491e4e21f 100644 --- a/src/java.base/share/classes/javax/security/auth/callback/ChoiceCallback.java +++ b/src/java.base/share/classes/javax/security/auth/callback/ChoiceCallback.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -102,20 +102,18 @@ public class ChoiceCallback implements Callback, java.io.Serializable { public ChoiceCallback(String prompt, String[] choices, int defaultChoice, boolean multipleSelectionsAllowed) { - if (prompt == null || prompt.isEmpty() || - choices == null || choices.length == 0 || - defaultChoice < 0 || defaultChoice >= choices.length) - throw new IllegalArgumentException(); - + choices = (choices == null || choices.length == 0 ? choices : + choices.clone()); + String errMsg = doSanityCheck(prompt, choices, defaultChoice, + multipleSelectionsAllowed); + if (errMsg != null) { + throw new IllegalArgumentException(errMsg); + } this.prompt = prompt; this.defaultChoice = defaultChoice; this.multipleSelectionsAllowed = multipleSelectionsAllowed; - this.choices = choices.clone(); - for (int i = 0; i < choices.length; i++) { - if (choices[i] == null || choices[i].isEmpty()) - throw new IllegalArgumentException(); - } + this.choices = choices; } /** @@ -183,9 +181,11 @@ public void setSelectedIndex(int selection) { * @see #getSelectedIndexes */ public void setSelectedIndexes(int[] selections) { - if (!multipleSelectionsAllowed) + if (!multipleSelectionsAllowed) { throw new UnsupportedOperationException(); - this.selections = selections == null ? null : selections.clone(); + } + this.selections = ((selections == null || selections.length == 0) ? + selections : selections.clone()); } /** @@ -211,26 +211,35 @@ public int[] getSelectedIndexes() { private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { stream.defaultReadObject(); + choices = (choices == null || choices.length == 0 ? + choices : choices.clone()); + String errMsg = doSanityCheck(prompt, choices, defaultChoice, + multipleSelectionsAllowed); + if (errMsg != null) { + throw new InvalidObjectException(errMsg); + } + selections = (selections == null || selections.length == 0 ? + selections : selections.clone()); + if (selections != null && selections.length > 1 && + !multipleSelectionsAllowed) { + throw new InvalidObjectException("Multiple selections not allowed"); + } + } + + private static String doSanityCheck(String prompt, String[] choices, + int defaultChoice, boolean allowMultiple) { if ((prompt == null) || prompt.isEmpty() || (choices == null) || (choices.length == 0) || (defaultChoice < 0) || (defaultChoice >= choices.length)) { - throw new InvalidObjectException( - "Missing/invalid prompt/choices"); + return "Missing/invalid prompt/choices"; } - choices = choices.clone(); for (int i = 0; i < choices.length; i++) { - if ((choices[i] == null) || choices[i].isEmpty()) - throw new InvalidObjectException("Null/empty choices"); - } - - if (selections != null) { - selections = selections.clone(); - if (!multipleSelectionsAllowed && (selections.length != 1)) { - throw new InvalidObjectException( - "Multiple selections not allowed"); + if ((choices[i] == null) || choices[i].isEmpty()) { + return "Null/empty choices value"; } } + return null; } } diff --git a/src/java.base/share/classes/javax/security/auth/callback/ConfirmationCallback.java b/src/java.base/share/classes/javax/security/auth/callback/ConfirmationCallback.java index 437ce7041a7d7..a00fc7013ecc1 100644 --- a/src/java.base/share/classes/javax/security/auth/callback/ConfirmationCallback.java +++ b/src/java.base/share/classes/javax/security/auth/callback/ConfirmationCallback.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * 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 @@ package javax.security.auth.callback; import java.io.IOException; +import java.io.InvalidObjectException; import java.io.ObjectInputStream; /** @@ -189,25 +190,10 @@ public class ConfirmationCallback implements Callback, java.io.Serializable { */ public ConfirmationCallback(int messageType, int optionType, int defaultOption) { - - if (messageType < INFORMATION || messageType > ERROR || - optionType < YES_NO_OPTION || optionType > OK_CANCEL_OPTION) - throw new IllegalArgumentException(); - - switch (optionType) { - case YES_NO_OPTION: - if (defaultOption != YES && defaultOption != NO) - throw new IllegalArgumentException(); - break; - case YES_NO_CANCEL_OPTION: - if (defaultOption != YES && defaultOption != NO && - defaultOption != CANCEL) - throw new IllegalArgumentException(); - break; - case OK_CANCEL_OPTION: - if (defaultOption != OK && defaultOption != CANCEL) - throw new IllegalArgumentException(); - break; + String errMsg = doSanityCheck(messageType, optionType, false, null, + defaultOption, null, false); + if (errMsg != null) { + throw new IllegalArgumentException(errMsg); } this.prompt = null; @@ -250,21 +236,20 @@ public ConfirmationCallback(int messageType, public ConfirmationCallback(int messageType, String[] options, int defaultOption) { - if (messageType < INFORMATION || messageType > ERROR || - options == null || options.length == 0 || - defaultOption < 0 || defaultOption >= options.length) - throw new IllegalArgumentException(); + if (options != null) { + options = options.clone(); + } + String errMsg = doSanityCheck(messageType, UNSPECIFIED_OPTION, true, + options, defaultOption, null, false); + if (errMsg != null) { + throw new IllegalArgumentException(errMsg); + } this.prompt = null; this.messageType = messageType; this.optionType = UNSPECIFIED_OPTION; this.defaultOption = defaultOption; - - this.options = options.clone(); - for (int i = 0; i < options.length; i++) { - if (options[i] == null || options[i].isEmpty()) - throw new IllegalArgumentException(); - } + this.options = options; } /** @@ -304,27 +289,11 @@ public ConfirmationCallback(int messageType, public ConfirmationCallback(String prompt, int messageType, int optionType, int defaultOption) { - if (prompt == null || prompt.isEmpty() || - messageType < INFORMATION || messageType > ERROR || - optionType < YES_NO_OPTION || optionType > OK_CANCEL_OPTION) - throw new IllegalArgumentException(); - - switch (optionType) { - case YES_NO_OPTION: - if (defaultOption != YES && defaultOption != NO) - throw new IllegalArgumentException(); - break; - case YES_NO_CANCEL_OPTION: - if (defaultOption != YES && defaultOption != NO && - defaultOption != CANCEL) - throw new IllegalArgumentException(); - break; - case OK_CANCEL_OPTION: - if (defaultOption != OK && defaultOption != CANCEL) - throw new IllegalArgumentException(); - break; + String errMsg = doSanityCheck(messageType, optionType, false, null, + defaultOption, prompt, true); + if (errMsg != null) { + throw new IllegalArgumentException(errMsg); } - this.prompt = prompt; this.messageType = messageType; this.optionType = optionType; @@ -369,22 +338,20 @@ public ConfirmationCallback(String prompt, int messageType, public ConfirmationCallback(String prompt, int messageType, String[] options, int defaultOption) { - if (prompt == null || prompt.isEmpty() || - messageType < INFORMATION || messageType > ERROR || - options == null || options.length == 0 || - defaultOption < 0 || defaultOption >= options.length) - throw new IllegalArgumentException(); + if (options != null) { + options = options.clone(); + } + String errMsg = doSanityCheck(messageType, UNSPECIFIED_OPTION, true, + options, defaultOption, prompt, true); + if (errMsg != null) { + throw new IllegalArgumentException(errMsg); + } this.prompt = prompt; this.messageType = messageType; this.optionType = UNSPECIFIED_OPTION; this.defaultOption = defaultOption; - - this.options = options.clone(); - for (int i = 0; i < options.length; i++) { - if (options[i] == null || options[i].isEmpty()) - throw new IllegalArgumentException(); - } + this.options = options; } /** @@ -491,6 +458,49 @@ public int getSelectedIndex() { return selection; } + private static String doSanityCheck(int msgType, int optionType, + boolean isUnspecifiedOption, String[] options, int defOption, + String prompt, boolean checkPrompt) { + // validate msgType + if (msgType < INFORMATION || msgType > ERROR) { + return "Invalid msgType"; + } + // validate prompt if checkPrompt == true + if (checkPrompt && (prompt == null || prompt.isEmpty())) { + return "Invalid prompt"; + } + // validate optionType + if (isUnspecifiedOption) { + if (optionType != UNSPECIFIED_OPTION) { + return "Invalid optionType"; + } + // check options + if (options == null || options.length == 0 || + defOption < 0 || defOption >= options.length) { + return "Invalid options and/or default option"; + } + for (String ov : options) { + if (ov == null || ov.isEmpty()) { + return "Invalid option value"; + } + } + } else { + if (optionType < YES_NO_OPTION || optionType > OK_CANCEL_OPTION) { + return "Invalid optionType"; + } + // validate defOption based on optionType + if ((optionType == YES_NO_OPTION && (defOption != YES && + defOption != NO)) || + (optionType == YES_NO_CANCEL_OPTION && (defOption != YES && + defOption != NO && defOption != CANCEL)) || + (optionType == OK_CANCEL_OPTION && (defOption != OK && + defOption != CANCEL))) { + return "Invalid default option"; + } + } + return null; + } + /** * Restores the state of this object from the stream. * @@ -502,8 +512,15 @@ public int getSelectedIndex() { private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { stream.defaultReadObject(); + if (options != null) { options = options.clone(); } + String errMsg = doSanityCheck(messageType, optionType, + (optionType == UNSPECIFIED_OPTION), options, defaultOption, + prompt, false); + if (errMsg != null) { + throw new InvalidObjectException(errMsg); + } } } diff --git a/src/java.base/share/classes/javax/security/auth/callback/PasswordCallback.java b/src/java.base/share/classes/javax/security/auth/callback/PasswordCallback.java index bbe7ab882a6a1..2bee38ceaaaf0 100644 --- a/src/java.base/share/classes/javax/security/auth/callback/PasswordCallback.java +++ b/src/java.base/share/classes/javax/security/auth/callback/PasswordCallback.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -178,7 +178,9 @@ private void readObject(ObjectInputStream stream) } if (inputPassword != null) { - inputPassword = inputPassword.clone(); + char[] temp = inputPassword; + inputPassword = temp.clone(); + Arrays.fill(temp, '0'); cleanable = CleanerFactory.cleaner().register( this, cleanerFor(inputPassword)); } diff --git a/src/java.base/share/classes/sun/security/provider/DRBG.java b/src/java.base/share/classes/sun/security/provider/DRBG.java index 923c8c3aa544a..01958285e430a 100644 --- a/src/java.base/share/classes/sun/security/provider/DRBG.java +++ b/src/java.base/share/classes/sun/security/provider/DRBG.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * 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 @@ package sun.security.provider; import java.io.IOException; +import java.io.InvalidObjectException; import java.security.AccessController; import java.security.DrbgParameters; import java.security.PrivilegedAction; @@ -272,11 +273,18 @@ private static void checkTwice(boolean flag, String name) { } } + /** + * Restores the state of this object from the stream. + * + * @param s the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ @java.io.Serial private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); - if (mdp.mech == null) { + if (mdp == null || mdp.mech == null) { throw new IllegalArgumentException("Input data is corrupted"); } createImpl(); diff --git a/src/java.base/share/classes/sun/security/util/ObjectIdentifier.java b/src/java.base/share/classes/sun/security/util/ObjectIdentifier.java index 6181bf223e9ae..306d34d7149f4 100644 --- a/src/java.base/share/classes/sun/security/util/ObjectIdentifier.java +++ b/src/java.base/share/classes/sun/security/util/ObjectIdentifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -127,13 +127,24 @@ public final class ObjectIdentifier implements Serializable { // Is the component's field calculated? private transient boolean componentsCalculated = false; + /** + * Restores the state of this object from the stream. + * + * @param is the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ @java.io.Serial private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException { is.defaultReadObject(); if (encoding == null) { // from an old version - int[] comp = (int[])components; + if (components == null) { + throw new InvalidObjectException("OID components is null"); + } + + int[] comp = ((int[]) components).clone(); if (componentLen > comp.length) { componentLen = comp.length; } @@ -142,7 +153,9 @@ private void readObject(ObjectInputStream is) // will be performed again in init(). checkOidSize(componentLen); init(comp, componentLen); + components = comp; } else { + encoding = encoding.clone(); // defensive copying checkOidSize(encoding.length); check(encoding); } @@ -261,6 +274,7 @@ public ObjectIdentifier(DerInputStream in) throws IOException { encoding = in.getDerValue().getOID().encoding; } + // set 'encoding' field based on the specified 'components' and 'length' private void init(int[] components, int length) throws IOException { int pos = 0; byte[] tmp = new byte[length * 5 + 1]; // +1 for empty input diff --git a/src/java.base/share/classes/sun/security/x509/AlgIdDSA.java b/src/java.base/share/classes/sun/security/x509/AlgIdDSA.java index 3a3d384a0e861..764d77e6da87f 100644 --- a/src/java.base/share/classes/sun/security/x509/AlgIdDSA.java +++ b/src/java.base/share/classes/sun/security/x509/AlgIdDSA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * 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,11 +25,13 @@ package sun.security.x509; +import java.io.ObjectInputStream; import java.io.IOException; +import java.io.InvalidObjectException; import java.math.BigInteger; import java.security.*; import java.security.interfaces.DSAParams; - +import java.util.Arrays; import sun.security.util.*; @@ -72,33 +74,42 @@ * * @author David Brownell */ -public final -class AlgIdDSA extends AlgorithmId implements DSAParams -{ +public final class AlgIdDSA extends AlgorithmId implements DSAParams { @java.io.Serial private static final long serialVersionUID = 3437177836797504046L; + private static class DSAComponents { + private final BigInteger p; + private final BigInteger q; + private final BigInteger g; + DSAComponents(BigInteger p, BigInteger q, BigInteger g) { + this.p = p; + this.q = q; + this.g = g; + } + } + /* * The three unsigned integer parameters. */ - private BigInteger p , q, g; + private BigInteger p, q, g; /** Returns the DSS/DSA parameter "P" */ - public BigInteger getP () { return p; } + public BigInteger getP() { return p; } /** Returns the DSS/DSA parameter "Q" */ - public BigInteger getQ () { return q; } + public BigInteger getQ() { return q; } /** Returns the DSS/DSA parameter "G" */ - public BigInteger getG () { return g; } + public BigInteger getG() { return g; } /** * Default constructor. The OID and parameters must be * deserialized before this algorithm ID is used. */ @Deprecated - public AlgIdDSA () {} + public AlgIdDSA() {} /** * Constructs a DSS/DSA Algorithm ID from numeric parameters. @@ -109,7 +120,7 @@ public AlgIdDSA () {} * @param q the DSS/DSA parameter "Q" * @param g the DSS/DSA parameter "G" */ - public AlgIdDSA (BigInteger p, BigInteger q, BigInteger g) { + public AlgIdDSA(BigInteger p, BigInteger q, BigInteger g) { super (DSA_oid); if (p != null || q != null || g != null) { @@ -120,8 +131,10 @@ public AlgIdDSA (BigInteger p, BigInteger q, BigInteger g) { this.p = p; this.q = q; this.g = g; - initializeParams (); - + // For algorithm IDs which haven't been created from a DER + // encoded value, need to create DER encoding and store it + // into "encodedParams" + encodedParams = encode(p, q, g); } catch (IOException e) { /* this should not happen */ throw new ProviderException ("Construct DSS/DSA Algorithm ID"); @@ -133,50 +146,10 @@ public AlgIdDSA (BigInteger p, BigInteger q, BigInteger g) { * Returns "DSA", indicating the Digital Signature Algorithm (DSA) as * defined by the Digital Signature Standard (DSS), FIPS 186. */ - public String getName () - { return "DSA"; } - - - /* - * For algorithm IDs which haven't been created from a DER encoded - * value, "params" must be created. - */ - private void initializeParams () throws IOException { - DerOutputStream out = new DerOutputStream(); - out.putInteger(p); - out.putInteger(q); - out.putInteger(g); - DerOutputStream result = new DerOutputStream(); - result.write(DerValue.tag_Sequence, out); - encodedParams = result.toByteArray(); - } - - /** - * Parses algorithm parameters P, Q, and G. They're found - * in the "params" member, which never needs to be changed. - */ - protected void decodeParams () throws IOException { - if (encodedParams == null) { - throw new IOException("DSA alg params are null"); - } - - DerValue params = new DerValue(encodedParams); - if (params.tag != DerValue.tag_Sequence) { - throw new IOException("DSA alg parsing error"); - } - - params.data.reset (); - - this.p = params.data.getBigInteger(); - this.q = params.data.getBigInteger(); - this.g = params.data.getBigInteger(); - - if (params.data.available () != 0) - throw new IOException ("AlgIdDSA params, extra="+ - params.data.available ()); + public String getName() { + return "DSA"; } - /* * Returns a formatted string describing the parameters. */ @@ -197,4 +170,44 @@ protected String paramsToString () { "\n"; } } + + /** + * Restores the state of this object from the stream. Override to check + * on the 'p', 'q', 'g', and 'encodedParams'. + * + * @param stream the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial + private void readObject(ObjectInputStream stream) throws IOException { + try { + stream.defaultReadObject(); + // if any of the 'p', 'q', 'g', 'encodedParams' is non-null, + // then they must be all non-null w/ matching encoding + if ((p != null || q != null || g != null || encodedParams != null) + && !Arrays.equals(encodedParams, encode(p, q, g))) { + throw new InvalidObjectException("Invalid DSA alg params"); + } + } catch (ClassNotFoundException e) { + throw new IOException(e); + } + } + + /* + * Create the DER encoding w/ the specified 'p', 'q', 'g' + */ + private static byte[] encode(BigInteger p, BigInteger q, + BigInteger g) throws IOException { + if (p == null || q == null || g == null) { + throw new InvalidObjectException("invalid null value"); + } + DerOutputStream out = new DerOutputStream(); + out.putInteger(p); + out.putInteger(q); + out.putInteger(g); + DerOutputStream result = new DerOutputStream(); + result.write(DerValue.tag_Sequence, out); + return result.toByteArray(); + } } diff --git a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java index fa596fc6a1e5c..cb9b8746994a6 100644 --- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java +++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java @@ -33,8 +33,10 @@ import sun.security.jgss.TokenTracker; import sun.security.krb5.*; import java.io.InputStream; -import java.io.OutputStream; +import java.io.InvalidObjectException; import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.OutputStream; import java.security.*; import javax.security.auth.Subject; import javax.security.auth.kerberos.ServicePermission; @@ -1408,6 +1410,20 @@ public String toString() { return "Kerberos session key: etype: " + key.getEType() + "\n" + new HexDumpEncoder().encodeBuffer(key.getBytes()); } + + /** + * Restores the state of this object from the stream. + * + * @param stream the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + throw new InvalidObjectException + ("KerberosSessionKey not directly deserializable"); + } } /** @@ -1477,5 +1493,4 @@ public void setAuthTime(String authTime) { public void setAuthzData(AuthorizationData authzData) { this.authzData = authzData; } - } diff --git a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java index 1b109cc881f15..4cc306282e687 100644 --- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java +++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * 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,9 @@ import javax.security.auth.kerberos.KerberosPrincipal; import java.io.Serial; import java.net.InetAddress; +import java.io.InvalidObjectException; import java.io.IOException; +import java.io.ObjectInputStream; import java.util.Date; import java.security.AccessController; import java.security.PrivilegedExceptionAction; @@ -400,4 +402,17 @@ public GSSCredentialSpi impersonate(GSSNameSpi name) throws GSSException { throw ge; } } + + /** + * Restores the state of this object from the stream. + * + * @param stream the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + throw new InvalidObjectException("Krb5InitCredential not deserializable"); + } } diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBError.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBError.java index b93ced00c65c1..db6192ce9ee2c 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBError.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBError.java @@ -83,28 +83,36 @@ * * http://www.ietf.org/rfc/rfc4120.txt. */ -// The instance fields not statically typed as Serializable are ASN.1 -// encoded and written by the writeObject method. -@SuppressWarnings("serial") + public class KRBError implements java.io.Serializable { static final long serialVersionUID = 3643809337475284503L; - private int pvno; - private int msgType; - private KerberosTime cTime; //optional - private Integer cuSec; //optional - private KerberosTime sTime; - private Integer suSec; - private int errorCode; - private Realm crealm; //optional - private PrincipalName cname; //optional - private PrincipalName sname; - private String eText; //optional - private byte[] eData; //optional - private Checksum eCksum; //optional - - private PAData[] pa; // PA-DATA in eData + private transient int pvno; + private transient int msgType; + private transient KerberosTime cTime; //optional + private transient Integer cuSec; //optional + private transient KerberosTime sTime; + private transient Integer suSec; + private transient int errorCode; + private transient Realm crealm; //optional + private transient PrincipalName cname; //optional + private transient PrincipalName sname; + private transient String eText; //optional + private transient byte[] eData; //optional + private transient Checksum eCksum; //optional + + private transient PAData[] pa; // PA-DATA in eData + + + /** + * Restores the state of this object from the stream. + * + * @param is the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException { try { diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java index d528f1b848584..49718e254b3e1 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java @@ -240,6 +240,19 @@ protected Object writeReplace() throws ObjectStreamException { return new KeyRep(type, getAlgorithm(), format, getEncodedInternal()); } + /** + * Restores the state of this object from the stream. + * + * @param stream the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + throw new InvalidObjectException("P11Key not directly deserializable"); + } + public String toString() { token.ensureValid(); String s1 = token.provider.getName() + " " + algorithm + " " + type diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecureRandom.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecureRandom.java index 70effc141bc11..7ef8510ddee48 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecureRandom.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecureRandom.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -187,9 +187,23 @@ private void implNextBytes(byte[] bytes) { } } + /** + * Restores the state of this object from the stream. + * + * @param in the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); + if (token == null) { + throw new InvalidObjectException("token is null"); + } + if (mixBuffer != null) { + mixBuffer = mixBuffer.clone(); + } // assign default values to non-null transient fields iBuffer = new byte[IBUFFER_SIZE]; ibuffered = 0; diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java index 44a2c4efb0694..e77edc98399eb 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java @@ -1947,6 +1947,19 @@ private Object writeReplace() throws ObjectStreamException { return new SunPKCS11Rep(this); } + /** + * Restores the state of this object from the stream. + * + * @param stream the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + throw new InvalidObjectException("SunPKCS11 not directly deserializable"); + } + /** * Serialized representation of the SunPKCS11 provider. */ From 893e7bc894e2828f8d02db06302485d02f2cfa5a Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Wed, 17 Apr 2024 22:38:46 +0000 Subject: [PATCH 065/118] 8328726: Better Kerberos support Reviewed-by: ahgross, rhalade, valeriep, coffeys --- .../security/auth/kerberos/EncryptionKey.java | 4 ++-- .../auth/kerberos/KerberosCredMessage.java | 6 ++--- .../security/auth/kerberos/KerberosKey.java | 8 +++---- .../javax/security/auth/kerberos/KeyImpl.java | 16 +++++--------- .../sun/security/jgss/krb5/Krb5Context.java | 22 +++++-------------- .../sun/security/jgss/krb5/Krb5Util.java | 15 +++++++++++++ .../sun/security/krb5/EncryptionKey.java | 8 ++----- .../sun/security/krb5/internal/Krb5.java | 3 --- .../security/krb5/internal/tools/Kinit.java | 4 ---- .../pkcs11/wrapper/CK_PBE_PARAMS.java | 5 ----- .../security/auth/module/Krb5LoginModule.java | 10 +++------ 11 files changed, 39 insertions(+), 62 deletions(-) diff --git a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/EncryptionKey.java b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/EncryptionKey.java index 5a6f74e130ca0..6140168ebbb9e 100644 --- a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/EncryptionKey.java +++ b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/EncryptionKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -170,7 +170,7 @@ public String toString() { if (destroyed) { return "Destroyed EncryptionKey"; } - return "key " + key.toString(); + return "EncryptionKey: " + key.toString(); } /** diff --git a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosCredMessage.java b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosCredMessage.java index c6f3f083a6630..c331833e9f05b 100644 --- a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosCredMessage.java +++ b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosCredMessage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ import javax.security.auth.Destroyable; import java.util.Arrays; -import java.util.Base64; import java.util.Objects; /** @@ -140,8 +139,7 @@ public String toString() { if (destroyed) { return "Destroyed KerberosCredMessage"; } else { - return "KRB_CRED from " + sender + " to " + recipient + ":\n" - + Base64.getUrlEncoder().encodeToString(message); + return "KRB_CRED from " + sender + " to " + recipient; } } diff --git a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosKey.java b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosKey.java index 55c1be3c0d819..71aaddda9deff 100644 --- a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosKey.java +++ b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -273,9 +273,9 @@ public String toString() { if (destroyed) { return "Destroyed KerberosKey"; } - return "Kerberos Principal " + principal + - "Key Version " + versionNum + - "key " + key.toString(); + return "KerberosKey: principal " + principal + + ", version " + versionNum + + ", key " + key.toString(); } /** diff --git a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KeyImpl.java b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KeyImpl.java index 46168cf83775c..b18f7d8eae1f1 100644 --- a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KeyImpl.java +++ b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KeyImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * 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,7 +30,8 @@ import javax.crypto.SecretKey; import javax.security.auth.Destroyable; import javax.security.auth.DestroyFailedException; -import sun.security.util.HexDumpEncoder; + +import sun.security.jgss.krb5.Krb5Util; import sun.security.krb5.Asn1Exception; import sun.security.krb5.PrincipalName; import sun.security.krb5.EncryptionKey; @@ -225,15 +226,8 @@ private void readObject(ObjectInputStream ois) } public String toString() { - HexDumpEncoder hd = new HexDumpEncoder(); - return "EncryptionKey: keyType=" + keyType - + " keyBytes (hex dump)=" - + (keyBytes == null || keyBytes.length == 0 ? - " Empty Key" : - '\n' + hd.encodeBuffer(keyBytes) - + '\n'); - - + return "keyType=" + keyType + + ", " + Krb5Util.keyInfo(keyBytes); } public int hashCode() { diff --git a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java index cb9b8746994a6..92b694efb86ca 100644 --- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java +++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java @@ -901,15 +901,11 @@ public final int getWrapSizeLimit(int qop, boolean confReq, public final byte[] wrap(byte[] inBuf, int offset, int len, MessageProp msgProp) throws GSSException { - if (DEBUG != null) { - DEBUG.println("Krb5Context.wrap: data=[" - + getHexBytes(inBuf, offset, len) - + "]"); - } - if (state != STATE_DONE) - throw new GSSException(GSSException.NO_CONTEXT, -1, - "Wrap called in invalid state!"); + if (state != STATE_DONE) { + throw new GSSException(GSSException.NO_CONTEXT, -1, + "Wrap called in invalid state!"); + } byte[] encToken = null; try { @@ -1052,12 +1048,6 @@ public final byte[] unwrap(byte[] inBuf, int offset, int len, setSequencingAndReplayProps(token, msgProp); } - if (DEBUG != null) { - DEBUG.println("Krb5Context.unwrap: data=[" - + getHexBytes(data, 0, data.length) - + "]"); - } - return data; } @@ -1407,8 +1397,8 @@ public byte[] getEncoded() { @Override public String toString() { - return "Kerberos session key: etype: " + key.getEType() + "\n" + - new HexDumpEncoder().encodeBuffer(key.getBytes()); + return "Kerberos session key: etype=" + key.getEType() + + ", " + Krb5Util.keyInfo(key.getBytes()); } /** diff --git a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Util.java b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Util.java index 10dea6749e59e..e784b7b33cad6 100644 --- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Util.java +++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Util.java @@ -187,4 +187,19 @@ public static EncryptionKey[] keysFromJavaxKeyTab( KeyTab ktab, PrincipalName cname) { return snapshotFromJavaxKeyTab(ktab).readServiceKeys(cname); } + + public static String keyInfo(byte[] data) { + if (data == null) { + return "null key"; + } else if (data.length == 0) { + return "empty key"; + } else { + for (byte b : data) { + if (b != 0) { + return data.length + "-byte key"; + } + } + return data.length + "-byte zero key"; + } + } } diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/EncryptionKey.java b/src/java.security.jgss/share/classes/sun/security/krb5/EncryptionKey.java index f975ba15a673e..b5453fae916a0 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/EncryptionKey.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/EncryptionKey.java @@ -31,6 +31,7 @@ package sun.security.krb5; +import sun.security.jgss.krb5.Krb5Util; import sun.security.util.*; import sun.security.krb5.internal.*; import sun.security.krb5.internal.crypto.*; @@ -498,12 +499,7 @@ public synchronized void writeKey(CCacheOutputStream cos) public String toString() { return "EncryptionKey: keyType=" + keyType - + " kvno=" + kvno - + " keyValue (hex dump)=" - + (keyValue == null || keyValue.length == 0 ? - " Empty Key" : '\n' - + Krb5.hexDumper.encodeBuffer(keyValue) - + '\n'); + + ", kvno=" + kvno + ", " + Krb5Util.keyInfo(keyValue); } /** diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/Krb5.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/Krb5.java index c3cac113c4029..0850abb53c83a 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/Krb5.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/Krb5.java @@ -320,9 +320,6 @@ public static String getErrorMessage(int i) { public static final Debug DEBUG = Debug.of("krb5", GetPropertyAction .privilegedGetProperty("sun.security.krb5.debug")); - public static final sun.security.util.HexDumpEncoder hexDumper = - new sun.security.util.HexDumpEncoder(); - static { errMsgList = new Hashtable (); errMsgList.put(KDC_ERR_NONE, "No error"); diff --git a/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Kinit.java b/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Kinit.java index 9d24de5c2e61c..6b9f5de0c3d8e 100644 --- a/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Kinit.java +++ b/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Kinit.java @@ -195,10 +195,6 @@ private void acquire() System.out.print("Password for " + princName + ":"); System.out.flush(); psswd = Password.readPassword(System.in); - if (DEBUG != null) { - DEBUG.println(">>> Kinit console input " + - new String(psswd)); - } } builder = new KrbAsReqBuilder(principal, psswd); } else { diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_PBE_PARAMS.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_PBE_PARAMS.java index a25fa1c39e5b7..d6c291ebc570c 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_PBE_PARAMS.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_PBE_PARAMS.java @@ -127,11 +127,6 @@ public String toString() { sb.append(pPassword.length); sb.append(Constants.NEWLINE); - sb.append(Constants.INDENT); - sb.append("pPassword: "); - sb.append(pPassword); - sb.append(Constants.NEWLINE); - sb.append(Constants.INDENT); sb.append("ulSaltLen: "); sb.append(pSalt.length); diff --git a/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java b/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java index 24f26d4364b94..18016a07260fb 100644 --- a/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java +++ b/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java @@ -43,7 +43,7 @@ import sun.security.jgss.krb5.Krb5Util; import sun.security.krb5.Credentials; import sun.security.util.Debug; -import sun.security.util.HexDumpEncoder; + import static sun.security.util.ResourcesMgr.getAuthResourceString; /** @@ -769,15 +769,11 @@ private void attemptAuthentication(boolean getPasswdFromSharedState) if (debug != null) { debug.println("principal is " + principal); - HexDumpEncoder hd = new HexDumpEncoder(); if (ktab != null) { debug.println("Will use keytab"); } else if (storeKey) { for (int i = 0; i < encKeys.length; i++) { - debug.println("EncryptionKey: keyType=" + - encKeys[i].getEType() + - " keyBytes (hex dump)=" + - hd.encodeBuffer(encKeys[i].getBytes())); + debug.println(encKeys[i].toString()); } } } @@ -868,7 +864,7 @@ private void promptForPass(boolean getPasswdFromSharedState) } if (debug != null) { debug.println - ("password is " + new String(password)); + ("Get password from shared state"); } return; } From 03bc6b359fc5ff4fa2b569723903cdf1c9c5775b Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Tue, 7 May 2024 19:29:49 +0000 Subject: [PATCH 066/118] 8328286: Enhance HTTP client Reviewed-by: aefimov, michaelm --- .../java/net/doc-files/net-properties.html | 9 + .../classes/sun/net/www/MessageHeader.java | 55 ++++ .../www/protocol/http/HttpURLConnection.java | 23 +- src/java.base/share/conf/net.properties | 17 + .../jdk/internal/net/http/Exchange.java | 45 ++- .../internal/net/http/Http1HeaderParser.java | 49 ++- .../internal/net/http/Http2ClientImpl.java | 78 +++-- .../internal/net/http/Http2Connection.java | 292 ++++++++++++++---- .../jdk/internal/net/http/HttpClientImpl.java | 4 +- .../internal/net/http/HttpRequestImpl.java | 4 +- .../net/http/ResponseBodyHandlers.java | 12 +- .../classes/jdk/internal/net/http/Stream.java | 118 +++++-- .../net/http/common/HeaderDecoder.java | 6 +- .../jdk/internal/net/http/common/Utils.java | 13 + .../jdk/internal/net/http/hpack/Decoder.java | 80 ++++- .../net/http/hpack/DecodingCallback.java | 14 + .../jdk/internal/net/http/hpack/Encoder.java | 14 +- .../share/classes/module-info.java | 30 +- .../share/classes/module-info.java | 12 +- .../classes/sun/net/httpserver/Request.java | 35 ++- .../sun/net/httpserver/ServerConfig.java | 18 +- .../net/httpclient/ExpectContinueTest.java | 3 +- test/jdk/java/net/httpclient/ShutdownNow.java | 1 + .../http2/PushPromiseContinuation.java | 9 +- .../test/lib/common/HttpServerAdapters.java | 12 +- .../test/lib/http2/HpackTestEncoder.java | 174 +++++++++++ .../test/lib/http2/Http2TestExchange.java | 13 + .../test/lib/http2/Http2TestExchangeImpl.java | 16 +- .../lib/http2/Http2TestServerConnection.java | 153 +++++++-- 29 files changed, 1125 insertions(+), 184 deletions(-) create mode 100644 test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/HpackTestEncoder.java diff --git a/src/java.base/share/classes/java/net/doc-files/net-properties.html b/src/java.base/share/classes/java/net/doc-files/net-properties.html index a61844cca6e09..a67df0c0d0092 100644 --- a/src/java.base/share/classes/java/net/doc-files/net-properties.html +++ b/src/java.base/share/classes/java/net/doc-files/net-properties.html @@ -253,6 +253,15 @@

Misc HTTP URL stream protocol handler properties

The channel binding tokens generated are of the type "tls-server-end-point" as defined in RFC 5929.

+ +
  • {@systemProperty jdk.http.maxHeaderSize} (default: 393216 or 384kB)
    + This is the maximum header field section size that a client is prepared to accept. + This is computed as the sum of the size of the uncompressed header name, plus + the size of the uncompressed header value, plus an overhead of 32 bytes for + each field section line. If a peer sends a field section that exceeds this + size a {@link java.net.ProtocolException ProtocolException} will be raised. + This applies to all versions of the HTTP protocol. A value of zero or a negative + value means no limit. If left unspecified, the default value is 393216 bytes.

    All these properties are checked only once at startup.

    diff --git a/src/java.base/share/classes/sun/net/www/MessageHeader.java b/src/java.base/share/classes/sun/net/www/MessageHeader.java index 6af23e43ad25d..5095507d9684e 100644 --- a/src/java.base/share/classes/sun/net/www/MessageHeader.java +++ b/src/java.base/share/classes/sun/net/www/MessageHeader.java @@ -30,6 +30,8 @@ package sun.net.www; import java.io.*; +import java.lang.reflect.Array; +import java.net.ProtocolException; import java.util.Collections; import java.util.*; @@ -45,11 +47,32 @@ public final class MessageHeader { private String[] values; private int nkeys; + // max number of bytes for headers, <=0 means unlimited; + // this corresponds to the length of the names, plus the length + // of the values, plus an overhead of 32 bytes per name: value + // pair. + // Note: we use the same definition as HTTP/2 SETTINGS_MAX_HEADER_LIST_SIZE + // see RFC 9113, section 6.5.2. + // https://www.rfc-editor.org/rfc/rfc9113.html#SETTINGS_MAX_HEADER_LIST_SIZE + private final int maxHeaderSize; + + // Aggregate size of the field lines (name + value + 32) x N + // that have been parsed and accepted so far. + // This is defined as a long to force promotion to long + // and avoid overflows; see checkNewSize; + private long size; + public MessageHeader () { + this(0); + } + + public MessageHeader (int maxHeaderSize) { + this.maxHeaderSize = maxHeaderSize; grow(); } public MessageHeader (InputStream is) throws java.io.IOException { + maxHeaderSize = 0; parseHeader(is); } @@ -476,10 +499,28 @@ public static String canonicalID(String id) { public void parseHeader(InputStream is) throws java.io.IOException { synchronized (this) { nkeys = 0; + size = 0; } mergeHeader(is); } + private void checkMaxHeaderSize(int sz) throws ProtocolException { + if (maxHeaderSize > 0) checkNewSize(size, sz, 0); + } + + private long checkNewSize(long size, int name, int value) throws ProtocolException { + // See SETTINGS_MAX_HEADER_LIST_SIZE, RFC 9113, section 6.5.2. + long newSize = size + name + value + 32; + if (maxHeaderSize > 0 && newSize > maxHeaderSize) { + Arrays.fill(keys, 0, nkeys, null); + Arrays.fill(values,0, nkeys, null); + nkeys = 0; + throw new ProtocolException(String.format("Header size too big: %s > %s", + newSize, maxHeaderSize)); + } + return newSize; + } + /** Parse and merge a MIME header from an input stream. */ @SuppressWarnings("fallthrough") public void mergeHeader(InputStream is) throws java.io.IOException { @@ -493,7 +534,15 @@ public void mergeHeader(InputStream is) throws java.io.IOException { int c; boolean inKey = firstc > ' '; s[len++] = (char) firstc; + checkMaxHeaderSize(len); parseloop:{ + // We start parsing for a new name value pair here. + // The max header size includes an overhead of 32 bytes per + // name value pair. + // See SETTINGS_MAX_HEADER_LIST_SIZE, RFC 9113, section 6.5.2. + long maxRemaining = maxHeaderSize > 0 + ? maxHeaderSize - size - 32 + : Long.MAX_VALUE; while ((c = is.read()) >= 0) { switch (c) { case ':': @@ -527,6 +576,9 @@ public void mergeHeader(InputStream is) throws java.io.IOException { s = ns; } s[len++] = (char) c; + if (maxHeaderSize > 0 && len > maxRemaining) { + checkMaxHeaderSize(len); + } } firstc = -1; } @@ -548,6 +600,9 @@ public void mergeHeader(InputStream is) throws java.io.IOException { v = new String(); else v = String.copyValueOf(s, keyend, len - keyend); + int klen = k == null ? 0 : k.length(); + + size = checkNewSize(size, klen, v.length()); add(k, v); } } diff --git a/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java b/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java index f47261f4491d0..8351185350269 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java +++ b/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java @@ -172,6 +172,8 @@ public class HttpURLConnection extends java.net.HttpURLConnection { */ private static final int bufSize4ES; + private static final int maxHeaderSize; + /* * Restrict setting of request headers through the public api * consistent with JavaScript XMLHttpRequest2 with a few @@ -288,6 +290,19 @@ private static Set schemesListToSet(String list) { } else { restrictedHeaderSet = null; } + + int defMaxHeaderSize = 384 * 1024; + String maxHeaderSizeStr = getNetProperty("jdk.http.maxHeaderSize"); + int maxHeaderSizeVal = defMaxHeaderSize; + if (maxHeaderSizeStr != null) { + try { + maxHeaderSizeVal = Integer.parseInt(maxHeaderSizeStr); + } catch (NumberFormatException n) { + maxHeaderSizeVal = defMaxHeaderSize; + } + } + if (maxHeaderSizeVal < 0) maxHeaderSizeVal = 0; + maxHeaderSize = maxHeaderSizeVal; } static final String httpVersion = "HTTP/1.1"; @@ -754,7 +769,7 @@ private void writeRequests() throws IOException { } ps = (PrintStream) http.getOutputStream(); connected=true; - responses = new MessageHeader(); + responses = new MessageHeader(maxHeaderSize); setRequests=false; writeRequests(); } @@ -912,7 +927,7 @@ protected HttpURLConnection(URL u, Proxy p, Handler handler) throws IOException { super(checkURL(u)); requests = new MessageHeader(); - responses = new MessageHeader(); + responses = new MessageHeader(maxHeaderSize); userHeaders = new MessageHeader(); this.handler = handler; instProxy = p; @@ -2810,7 +2825,7 @@ private boolean followRedirect0(String loc, int stat, URL locUrl) } // clear out old response headers!!!! - responses = new MessageHeader(); + responses = new MessageHeader(maxHeaderSize); if (stat == HTTP_USE_PROXY) { /* This means we must re-request the resource through the * proxy denoted in the "Location:" field of the response. @@ -3000,7 +3015,7 @@ private void reset() throws IOException { } catch (IOException e) { } } responseCode = -1; - responses = new MessageHeader(); + responses = new MessageHeader(maxHeaderSize); connected = false; } diff --git a/src/java.base/share/conf/net.properties b/src/java.base/share/conf/net.properties index 67f294355a10e..2aa9a9630bed2 100644 --- a/src/java.base/share/conf/net.properties +++ b/src/java.base/share/conf/net.properties @@ -130,3 +130,20 @@ jdk.http.auth.tunneling.disabledSchemes=Basic #jdk.http.ntlm.transparentAuth=trustedHosts # jdk.http.ntlm.transparentAuth=disabled + +# +# Maximum HTTP field section size that a client is prepared to accept +# +# jdk.http.maxHeaderSize=393216 +# +# This is the maximum header field section size that a client is prepared to accept. +# This is computed as the sum of the size of the uncompressed header name, plus +# the size of the uncompressed header value, plus an overhead of 32 bytes for +# each field section line. If a peer sends a field section that exceeds this +# size a {@link java.net.ProtocolException ProtocolException} will be raised. +# This applies to all versions of the HTTP protocol. A value of zero or a negative +# value means no limit. If left unspecified, the default value is 393216 bytes +# or 384kB. +# +# Note: This property is currently used by the JDK Reference implementation. It +# is not guaranteed to be examined and used by other implementations. 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 eb30dc85e9c8e..1ff1e5f47330f 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 @@ -41,6 +41,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import java.net.http.HttpClient; import java.net.http.HttpHeaders; @@ -69,6 +70,8 @@ */ final class Exchange { + static final int MAX_NON_FINAL_RESPONSES = + Utils.getIntegerNetProperty("jdk.httpclient.maxNonFinalResponses", 8); final Logger debug = Utils.getDebugLogger(this::dbgString, Utils.DEBUG); final HttpRequestImpl request; @@ -93,6 +96,8 @@ final class Exchange { // exchange so that it can be aborted/timed out mid setup. final ConnectionAborter connectionAborter = new ConnectionAborter(); + final AtomicInteger nonFinalResponses = new AtomicInteger(); + Exchange(HttpRequestImpl request, MultiExchange multi) { this.request = request; this.upgrading = false; @@ -359,7 +364,7 @@ CompletableFuture checkCancelled(CompletableFuture cf, HttpConnection public void h2Upgrade() { upgrading = true; - request.setH2Upgrade(client.client2()); + request.setH2Upgrade(this); } synchronized IOException getCancelCause() { @@ -482,9 +487,9 @@ private CompletableFuture expectContinue(ExchangeImpl ex) { Log.logResponse(r1::toString); int rcode = r1.statusCode(); if (rcode == 100) { + nonFinalResponses.incrementAndGet(); Log.logTrace("Received 100-Continue: sending body"); - if (debug.on()) - debug.log("Received 100-Continue for %s", r1); + if (debug.on()) debug.log("Received 100-Continue for %s", r1); CompletableFuture cf = exchImpl.sendBodyAsync() .thenCompose(exIm -> exIm.getResponseAsync(parentExecutor)); @@ -492,9 +497,9 @@ private CompletableFuture expectContinue(ExchangeImpl ex) { cf = wrapForLog(cf); return cf; } else { - Log.logTrace("Expectation failed: Received {0}", rcode); - if (debug.on()) - debug.log("Expect-Continue failed (%d) for: %s", rcode, r1); + Log.logTrace("Expectation failed: Received {0}", + rcode); + if (debug.on()) debug.log("Expect-Continue failed (%d) for: %s", rcode, r1); if (upgrading && rcode == 101) { IOException failed = new IOException( "Unable to handle 101 while waiting for 100"); @@ -559,12 +564,20 @@ private CompletableFuture ignore1xxResponse(final Response rsp) { + rsp.statusCode()); } assert exchImpl != null : "Illegal state - current exchange isn't set"; - // ignore this Response and wait again for the subsequent response headers - final CompletableFuture cf = exchImpl.getResponseAsync(parentExecutor); - // we recompose the CF again into the ignore1xxResponse check/function because - // the 1xx response is allowed to be sent multiple times for a request, before - // a final response arrives - return cf.thenCompose(this::ignore1xxResponse); + int count = nonFinalResponses.incrementAndGet(); + if (MAX_NON_FINAL_RESPONSES > 0 && (count < 0 || count > MAX_NON_FINAL_RESPONSES)) { + return MinimalFuture.failedFuture( + new ProtocolException(String.format( + "Too many interim responses received: %s > %s", + count, MAX_NON_FINAL_RESPONSES))); + } else { + // ignore this Response and wait again for the subsequent response headers + final CompletableFuture cf = exchImpl.getResponseAsync(parentExecutor); + // we recompose the CF again into the ignore1xxResponse check/function because + // the 1xx response is allowed to be sent multiple times for a request, before + // a final response arrives + return cf.thenCompose(this::ignore1xxResponse); + } } else { // return the already completed future return MinimalFuture.completedFuture(rsp); @@ -829,6 +842,14 @@ HttpClient.Version version() { return multi.version(); } + boolean pushEnabled() { + return pushGroup != null; + } + + String h2cSettingsStrings() { + return client.client2().getSettingsString(pushEnabled()); + } + String dbgString() { return dbgTag; } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http1HeaderParser.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http1HeaderParser.java index 669c173e3f825..8c796193015d3 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http1HeaderParser.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http1HeaderParser.java @@ -25,6 +25,7 @@ package jdk.internal.net.http; +import java.io.IOException; import java.net.ProtocolException; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; @@ -53,6 +54,12 @@ class Http1HeaderParser { private int responseCode; private HttpHeaders headers; private Map> privateMap = new HashMap<>(); + private long size; + + private static final int K = 1024; + private static final int MAX_HTTP_HEADER_SIZE = Utils.getIntegerNetProperty( + "jdk.http.maxHeaderSize", + Integer.MIN_VALUE, Integer.MAX_VALUE, 384 * K, true); enum State { INITIAL, STATUS_LINE, @@ -164,11 +171,16 @@ private char get(ByteBuffer input) { return (char)(input.get() & 0xFF); } - private void readResumeStatusLine(ByteBuffer input) { + private void readResumeStatusLine(ByteBuffer input) throws ProtocolException { + final long max = MAX_HTTP_HEADER_SIZE - size - 32 - sb.length(); + int count = 0; char c = 0; while (input.hasRemaining() && (c = get(input)) != CR) { if (c == LF) break; sb.append(c); + if (++count > max) { + checkMaxHeaderSize(sb.length()); + } } if (c == CR) { state = State.STATUS_LINE_FOUND_CR; @@ -185,6 +197,7 @@ private void readStatusLineFeed(ByteBuffer input) throws ProtocolException { } statusLine = sb.toString(); + size = size + 32 + statusLine.length(); sb = new StringBuilder(); if (!statusLine.startsWith("HTTP/1.")) { throw protocolException("Invalid status line: \"%s\"", statusLine); @@ -205,7 +218,23 @@ private void readStatusLineFeed(ByteBuffer input) throws ProtocolException { state = State.STATUS_LINE_END; } - private void maybeStartHeaders(ByteBuffer input) { + private void checkMaxHeaderSize(int sz) throws ProtocolException { + long s = size + sz + 32; + if (MAX_HTTP_HEADER_SIZE > 0 && s > MAX_HTTP_HEADER_SIZE) { + throw new ProtocolException(String.format("Header size too big: %s > %s", + s, MAX_HTTP_HEADER_SIZE)); + } + } + static private long newSize(long size, int name, int value) throws ProtocolException { + long newSize = size + name + value + 32; + if (MAX_HTTP_HEADER_SIZE > 0 && newSize > MAX_HTTP_HEADER_SIZE) { + throw new ProtocolException(String.format("Header size too big: %s > %s", + newSize, MAX_HTTP_HEADER_SIZE)); + } + return newSize; + } + + private void maybeStartHeaders(ByteBuffer input) throws ProtocolException { assert state == State.STATUS_LINE_END; assert sb.length() == 0; char c = get(input); @@ -215,6 +244,7 @@ private void maybeStartHeaders(ByteBuffer input) { state = State.STATUS_LINE_END_LF; } else { sb.append(c); + checkMaxHeaderSize(sb.length()); state = State.HEADER; } } @@ -232,9 +262,11 @@ private void maybeEndHeaders(ByteBuffer input) throws ProtocolException { } } - private void readResumeHeader(ByteBuffer input) { + private void readResumeHeader(ByteBuffer input) throws ProtocolException { assert state == State.HEADER; assert input.hasRemaining(); + final long max = MAX_HTTP_HEADER_SIZE - size - 32 - sb.length(); + int count = 0; while (input.hasRemaining()) { char c = get(input); if (c == CR) { @@ -248,6 +280,9 @@ private void readResumeHeader(ByteBuffer input) { if (c == HT) c = SP; sb.append(c); + if (++count > max) { + checkMaxHeaderSize(sb.length()); + } } } @@ -268,12 +303,12 @@ private void addHeaderFromString(String headerString) throws ProtocolException { if (!Utils.isValidValue(value)) { throw protocolException("Invalid header value \"%s: %s\"", name, value); } - + size = newSize(size, name.length(), value.length()); privateMap.computeIfAbsent(name.toLowerCase(Locale.US), k -> new ArrayList<>()).add(value); } - private void resumeOrLF(ByteBuffer input) { + private void resumeOrLF(ByteBuffer input) throws ProtocolException { assert state == State.HEADER_FOUND_CR || state == State.HEADER_FOUND_LF; char c = state == State.HEADER_FOUND_LF ? LF : get(input); if (c == LF) { @@ -283,10 +318,12 @@ private void resumeOrLF(ByteBuffer input) { state = State.HEADER_FOUND_CR_LF; } else if (c == SP || c == HT) { sb.append(SP); // parity with MessageHeaders + checkMaxHeaderSize(sb.length()); state = State.HEADER; } else { sb = new StringBuilder(); sb.append(c); + checkMaxHeaderSize(1); state = State.HEADER; } } @@ -312,6 +349,7 @@ private void resumeOrSecondCR(ByteBuffer input) throws ProtocolException { } else if (c == SP || c == HT) { assert sb.length() != 0; sb.append(SP); // continuation line + checkMaxHeaderSize(sb.length()); state = State.HEADER; } else { if (sb.length() > 0) { @@ -322,6 +360,7 @@ private void resumeOrSecondCR(ByteBuffer input) throws ProtocolException { addHeaderFromString(headerString); } sb.append(c); + checkMaxHeaderSize(sb.length()); state = State.HEADER; } } 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 50338f94c1de5..022442b5371b5 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, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * 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 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.locks.ReentrantLock; -import jdk.internal.net.http.common.Log; import jdk.internal.net.http.common.Logger; import jdk.internal.net.http.common.MinimalFuture; import jdk.internal.net.http.common.Utils; @@ -46,6 +45,7 @@ import static jdk.internal.net.http.frame.SettingsFrame.HEADER_TABLE_SIZE; import static jdk.internal.net.http.frame.SettingsFrame.MAX_CONCURRENT_STREAMS; import static jdk.internal.net.http.frame.SettingsFrame.MAX_FRAME_SIZE; +import static jdk.internal.net.http.frame.SettingsFrame.MAX_HEADER_LIST_SIZE; /** * Http2 specific aspects of HttpClientImpl @@ -98,16 +98,20 @@ class Http2ClientImpl { CompletableFuture getConnectionFor(HttpRequestImpl req, Exchange exchange) { String key = Http2Connection.keyFor(req); + boolean pushEnabled = exchange.pushEnabled(); connectionPoolLock.lock(); try { Http2Connection connection = connections.get(key); if (connection != null) { try { - if (!connection.tryReserveForPoolCheckout() || !connection.reserveStream(true)) { + if (!connection.tryReserveForPoolCheckout() + || !connection.reserveStream(true, pushEnabled)) { if (debug.on()) debug.log("removing connection from pool since it couldn't be" + - " reserved for use: %s", connection); + " reserved for use%s: %s", + pushEnabled ? " with server push enabled" : "", + connection); removeFromPool(connection); } else { // fast path if connection already exists @@ -137,7 +141,7 @@ CompletableFuture getConnectionFor(HttpRequestImpl req, try { if (conn != null) { try { - conn.reserveStream(true); + conn.reserveStream(true, exchange.pushEnabled()); } catch (IOException e) { throw new UncheckedIOException(e); // shouldn't happen } @@ -183,10 +187,21 @@ boolean offerConnection(Http2Connection c) { } Http2Connection c1 = connections.putIfAbsent(key, c); if (c1 != null) { - c.setFinalStream(); - if (debug.on()) - debug.log("existing entry in connection pool for %s", key); - return false; + if (c.serverPushEnabled() && !c1.serverPushEnabled()) { + c1.setFinalStream(); + connections.remove(key, c1); + connections.put(key, c); + if (debug.on()) { + debug.log("Replacing %s with %s in connection pool", c1, c); + } + if (c1.shouldClose()) c1.close(); + return true; + } else { + c.setFinalStream(); + if (debug.on()) + debug.log("existing entry in connection pool for %s", key); + return false; + } } if (debug.on()) debug.log("put in the connection pool: %s", c); @@ -250,8 +265,8 @@ HttpClientImpl client() { } /** Returns the client settings as a base64 (url) encoded string */ - String getSettingsString() { - SettingsFrame sf = getClientSettings(); + String getSettingsString(boolean defaultServerPush) { + SettingsFrame sf = getClientSettings(defaultServerPush); byte[] settings = sf.toByteArray(); // without the header Base64.Encoder encoder = Base64.getUrlEncoder() .withoutPadding(); @@ -261,14 +276,7 @@ String getSettingsString() { private static final int K = 1024; private static int getParameter(String property, int min, int max, int defaultValue) { - int value = Utils.getIntegerNetProperty(property, defaultValue); - // use default value if misconfigured - if (value < min || value > max) { - Log.logError("Property value for {0}={1} not in [{2}..{3}]: " + - "using default={4}", property, value, min, max, defaultValue); - value = defaultValue; - } - return value; + return Utils.getIntegerNetProperty(property, min, max, defaultValue, true); } // used for the connection window, to have a connection window size @@ -288,7 +296,18 @@ int getConnectionWindowSize(SettingsFrame clientSettings) { streamWindow, Integer.MAX_VALUE, defaultValue); } - SettingsFrame getClientSettings() { + /** + * This method is used to test whether pushes are globally + * disabled on all connections. + * @return true if pushes are globally disabled on all connections + */ + boolean serverPushDisabled() { + return getParameter( + "jdk.httpclient.enablepush", + 0, 1, 1) == 0; + } + + SettingsFrame getClientSettings(boolean defaultServerPush) { SettingsFrame frame = new SettingsFrame(); // default defined for HTTP/2 is 4 K, we use 16 K. frame.setParameter(HEADER_TABLE_SIZE, getParameter( @@ -297,14 +316,15 @@ SettingsFrame getClientSettings() { // O: does not accept push streams. 1: accepts push streams. frame.setParameter(ENABLE_PUSH, getParameter( "jdk.httpclient.enablepush", - 0, 1, 1)); + 0, 1, defaultServerPush ? 1 : 0)); // HTTP/2 recommends to set the number of concurrent streams - // no lower than 100. We use 100. 0 means no stream would be - // accepted. That would render the client to be non functional, - // so we won't let 0 be configured for our Http2ClientImpl. + // no lower than 100. We use 100, unless push promises are + // disabled. + int initialServerStreams = frame.getParameter(ENABLE_PUSH) == 0 + ? 0 : 100; frame.setParameter(MAX_CONCURRENT_STREAMS, getParameter( "jdk.httpclient.maxstreams", - 1, Integer.MAX_VALUE, 100)); + 0, Integer.MAX_VALUE, initialServerStreams)); // Maximum size is 2^31-1. Don't allow window size to be less // than the minimum frame size as this is likely to be a // configuration error. HTTP/2 specify a default of 64 * K -1, @@ -317,6 +337,14 @@ SettingsFrame getClientSettings() { frame.setParameter(MAX_FRAME_SIZE, getParameter( "jdk.httpclient.maxframesize", 16 * K, 16 * K * K -1, 16 * K)); + // Maximum field section size we're prepared to accept + // This is the uncompressed name + value size + 32 per field line + int maxHeaderSize = getParameter( + "jdk.http.maxHeaderSize", + Integer.MIN_VALUE, Integer.MAX_VALUE, 384 * K); + // If the property is <= 0 the value is unlimited + if (maxHeaderSize <= 0) maxHeaderSize = -1; + frame.setParameter(MAX_HEADER_LIST_SIZE, maxHeaderSize); return frame; } 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 9457ff6998832..080905222c34d 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 @@ -31,6 +31,7 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.net.InetSocketAddress; +import java.net.ProtocolException; import java.net.http.HttpClient; import java.net.http.HttpHeaders; import java.nio.ByteBuffer; @@ -49,6 +50,7 @@ import java.util.concurrent.Flow; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.function.Function; @@ -88,10 +90,12 @@ import jdk.internal.net.http.hpack.Encoder; import static java.nio.charset.StandardCharsets.UTF_8; import static jdk.internal.net.http.frame.SettingsFrame.DEFAULT_INITIAL_WINDOW_SIZE; +import static jdk.internal.net.http.frame.SettingsFrame.ENABLE_PUSH; import static jdk.internal.net.http.frame.SettingsFrame.HEADER_TABLE_SIZE; import static jdk.internal.net.http.frame.SettingsFrame.INITIAL_WINDOW_SIZE; import static jdk.internal.net.http.frame.SettingsFrame.MAX_CONCURRENT_STREAMS; import static jdk.internal.net.http.frame.SettingsFrame.MAX_FRAME_SIZE; +import static jdk.internal.net.http.frame.SettingsFrame.MAX_HEADER_LIST_SIZE; /** * An Http2Connection. Encapsulates the socket(channel) and any SSLEngine used @@ -327,6 +331,45 @@ void markPrefaceSent() { } } + private final class PushPromiseDecoder extends HeaderDecoder implements DecodingCallback { + + final int parentStreamId; + final int pushPromiseStreamId; + final Stream parent; + final AtomicReference errorRef = new AtomicReference<>(); + + PushPromiseDecoder(int parentStreamId, int pushPromiseStreamId, Stream parent) { + this.parentStreamId = parentStreamId; + this.pushPromiseStreamId = pushPromiseStreamId; + this.parent = parent; + } + + @Override + protected void addHeader(String name, String value) { + if (errorRef.get() == null) { + super.addHeader(name, value); + } + } + + @Override + public void onMaxHeaderListSizeReached(long size, int maxHeaderListSize) throws ProtocolException { + try { + DecodingCallback.super.onMaxHeaderListSizeReached(size, maxHeaderListSize); + } catch (ProtocolException pe) { + if (parent != null) { + if (errorRef.compareAndSet(null, pe)) { + // cancel the parent stream + resetStream(pushPromiseStreamId, ResetFrame.REFUSED_STREAM); + parent.onProtocolError(pe); + } + } else { + // interrupt decoding and closes the connection + throw pe; + } + } + } + } + private static final int HALF_CLOSED_LOCAL = 1; private static final int HALF_CLOSED_REMOTE = 2; @@ -355,7 +398,7 @@ void markPrefaceSent() { private final Decoder hpackIn; final SettingsFrame clientSettings; private volatile SettingsFrame serverSettings; - private record PushContinuationState(HeaderDecoder pushContDecoder, PushPromiseFrame pushContFrame) {} + private record PushContinuationState(PushPromiseDecoder pushContDecoder, PushPromiseFrame pushContFrame) {} private volatile PushContinuationState pushContinuationState; private final String key; // for HttpClientImpl.connections map private final FramesDecoder framesDecoder; @@ -370,12 +413,24 @@ private record PushContinuationState(HeaderDecoder pushContDecoder, PushPromiseF private final FramesController framesController = new FramesController(); private final Http2TubeSubscriber subscriber; final ConnectionWindowUpdateSender windowUpdater; - private volatile Throwable cause; + private final AtomicReference cause = new AtomicReference<>(); private volatile Supplier initial; private volatile Stream initialStream; + private ValidatingHeadersConsumer orphanedConsumer; + private final AtomicInteger orphanedHeaders = new AtomicInteger(); + static final int DEFAULT_FRAME_SIZE = 16 * 1024; + static final int MAX_LITERAL_WITH_INDEXING = + Utils.getIntegerNetProperty("jdk.httpclient.maxLiteralWithIndexing",512); + // The maximum number of HEADER frames, CONTINUATION frames, or PUSH_PROMISE frames + // referring to an already closed or non-existent stream that a client will accept to + // process. Receiving frames referring to non-existent or closed streams doesn't necessarily + // constitute an HTTP/2 protocol error, but receiving too many may indicate a problem + // with the connection. If this limit is reached, a {@link java.net.ProtocolException + // ProtocolException} will be raised and the connection will be closed. + static final int MAX_ORPHANED_HEADERS = 1024; // TODO: need list of control frames from other threads // that need to be sent @@ -383,19 +438,21 @@ private record PushContinuationState(HeaderDecoder pushContDecoder, PushPromiseF private Http2Connection(HttpConnection connection, Http2ClientImpl client2, int nextstreamid, - String key) { + String key, + boolean defaultServerPush) { this.connection = connection; this.client2 = client2; this.subscriber = new Http2TubeSubscriber(client2.client()); this.nextstreamid = nextstreamid; this.key = key; - this.clientSettings = this.client2.getClientSettings(); + this.clientSettings = this.client2.getClientSettings(defaultServerPush); this.framesDecoder = new FramesDecoder(this::processFrame, clientSettings.getParameter(SettingsFrame.MAX_FRAME_SIZE)); // serverSettings will be updated by server this.serverSettings = SettingsFrame.defaultRFCSettings(); this.hpackOut = new Encoder(serverSettings.getParameter(HEADER_TABLE_SIZE)); - this.hpackIn = new Decoder(clientSettings.getParameter(HEADER_TABLE_SIZE)); + this.hpackIn = new Decoder(clientSettings.getParameter(HEADER_TABLE_SIZE), + clientSettings.getParameter(MAX_HEADER_LIST_SIZE), MAX_LITERAL_WITH_INDEXING); if (debugHpack.on()) { debugHpack.log("For the record:" + super.toString()); debugHpack.log("Decoder created: %s", hpackIn); @@ -414,14 +471,16 @@ private Http2Connection(HttpConnection connection, private Http2Connection(HttpConnection connection, Http2ClientImpl client2, Exchange exchange, - Supplier initial) + Supplier initial, + boolean defaultServerPush) throws IOException, InterruptedException { this(connection, client2, 3, // stream 1 is registered during the upgrade - keyFor(connection)); - reserveStream(true); + keyFor(connection), + defaultServerPush); + reserveStream(true, clientSettings.getFlag(ENABLE_PUSH)); Log.logTrace("Connection send window size {0} ", windowController.connectionWindowSize()); Stream initialStream = createStream(exchange); @@ -454,7 +513,8 @@ static CompletableFuture createAsync(HttpConnection connection, Exchange exchange, Supplier initial) { - return MinimalFuture.supply(() -> new Http2Connection(connection, client2, exchange, initial)); + return MinimalFuture.supply(() -> new Http2Connection(connection, client2, exchange, initial, + exchange.pushEnabled())); } // Requires TLS handshake. So, is really async @@ -478,7 +538,8 @@ static CompletableFuture createAsync(HttpRequestImpl request, .thenCompose(notused-> { CompletableFuture cf = new MinimalFuture<>(); try { - Http2Connection hc = new Http2Connection(request, h2client, connection); + Http2Connection hc = new Http2Connection(request, h2client, + connection, exchange.pushEnabled()); cf.complete(hc); } catch (IOException e) { cf.completeExceptionally(e); @@ -493,13 +554,15 @@ static CompletableFuture createAsync(HttpRequestImpl request, */ private Http2Connection(HttpRequestImpl request, Http2ClientImpl h2client, - HttpConnection connection) + HttpConnection connection, + boolean defaultServerPush) throws IOException { this(connection, h2client, 1, - keyFor(request)); + keyFor(request), + defaultServerPush); Log.logTrace("Connection send window size {0} ", windowController.connectionWindowSize()); @@ -522,24 +585,30 @@ final HttpClientImpl client() { // if false returned then a new Http2Connection is required // if true, the stream may be assigned to this connection // for server push, if false returned, then the stream should be cancelled - boolean reserveStream(boolean clientInitiated) throws IOException { + boolean reserveStream(boolean clientInitiated, boolean pushEnabled) throws IOException { stateLock.lock(); try { - return reserveStream0(clientInitiated); + return reserveStream0(clientInitiated, pushEnabled); } finally { stateLock.unlock(); } } - private boolean reserveStream0(boolean clientInitiated) throws IOException { + private boolean reserveStream0(boolean clientInitiated, boolean pushEnabled) throws IOException { if (finalStream()) { return false; } - if (clientInitiated && (lastReservedClientStreamid + 2) >= MAX_CLIENT_STREAM_ID) { + // If requesting to reserve a stream for an exchange for which push is enabled, + // we will reserve the stream in this connection only if this connection is also + // push enabled, unless pushes are globally disabled. + boolean pushCompatible = !clientInitiated || !pushEnabled + || this.serverPushEnabled() + || client2.serverPushDisabled(); + if (clientInitiated && (lastReservedClientStreamid >= MAX_CLIENT_STREAM_ID -2 || !pushCompatible)) { setFinalStream(); client2.removeFromPool(this); return false; - } else if (!clientInitiated && (lastReservedServerStreamid + 2) >= MAX_SERVER_STREAM_ID) { + } else if (!clientInitiated && (lastReservedServerStreamid >= MAX_SERVER_STREAM_ID - 2)) { setFinalStream(); client2.removeFromPool(this); return false; @@ -564,6 +633,15 @@ private boolean reserveStream0(boolean clientInitiated) throws IOException { return true; } + boolean shouldClose() { + stateLock.lock(); + try { + return finalStream() && streams.isEmpty(); + } finally { + stateLock.unlock(); + } + } + /** * Throws an IOException if h2 was not negotiated */ @@ -691,6 +769,10 @@ String key() { return this.key; } + public boolean serverPushEnabled() { + return clientSettings.getParameter(SettingsFrame.ENABLE_PUSH) == 1; + } + boolean offerConnection() { return client2.offerConnection(this); } @@ -795,7 +877,7 @@ final void asyncReceive(ByteBuffer buffer) { } Throwable getRecordedCause() { - return cause; + return cause.get(); } void shutdown(Throwable t) { @@ -804,11 +886,11 @@ void shutdown(Throwable t) { stateLock.lock(); try { if (!markShutdownRequested()) return; - Throwable initialCause = this.cause; - if (initialCause == null && t != null) this.cause = t; + cause.compareAndSet(null, t); } finally { stateLock.unlock(); } + if (Log.errors()) { if (t!= null && (!(t instanceof EOFException) || isActive())) { Log.logError(t); @@ -819,6 +901,7 @@ void shutdown(Throwable t) { } } client2.removeFromPool(this); + subscriber.stop(cause.get()); for (Stream s : streams.values()) { try { s.connectionClosing(t); @@ -872,17 +955,39 @@ void processFrame(Http2Frame frame) throws IOException { return; } + if (frame instanceof PushPromiseFrame && !serverPushEnabled()) { + String protocolError = "received a PUSH_PROMISE when SETTINGS_ENABLE_PUSH is 0"; + protocolError(ResetFrame.PROTOCOL_ERROR, protocolError); + return; + } + Stream stream = getStream(streamid); + var nextstreamid = this.nextstreamid; + if (stream == null && (streamid & 0x01) == 0x01 && streamid >= nextstreamid) { + String protocolError = String.format( + "received a frame for a non existing streamid(%s) >= nextstreamid(%s)", + streamid, nextstreamid); + protocolError(ResetFrame.PROTOCOL_ERROR, protocolError); + return; + } if (stream == null && pushContinuationState == null) { // Should never receive a frame with unknown stream id - if (frame instanceof HeaderFrame) { + if (frame instanceof HeaderFrame hf) { + String protocolError = checkMaxOrphanedHeadersExceeded(hf); + if (protocolError != null) { + protocolError(ResetFrame.PROTOCOL_ERROR, protocolError); + return; + } // always decode the headers as they may affect // connection-level HPACK decoding state - DecodingCallback decoder = new ValidatingHeadersConsumer()::onDecoded; + if (orphanedConsumer == null || frame.getClass() != ContinuationFrame.class) { + orphanedConsumer = new ValidatingHeadersConsumer(); + } + DecodingCallback decoder = orphanedConsumer::onDecoded; try { - decodeHeaders((HeaderFrame) frame, decoder); - } catch (UncheckedIOException e) { + decodeHeaders(hf, decoder); + } catch (IOException | UncheckedIOException e) { protocolError(ResetFrame.PROTOCOL_ERROR, e.getMessage()); return; } @@ -910,29 +1015,41 @@ void processFrame(Http2Frame frame) throws IOException { // While push frame is not null, the only acceptable frame on this // stream is a Continuation frame - if (pushContinuationState != null) { + PushContinuationState pcs = pushContinuationState; + if (pcs != null) { if (frame instanceof ContinuationFrame cf) { + if (stream == null) { + String protocolError = checkMaxOrphanedHeadersExceeded(cf); + if (protocolError != null) { + protocolError(ResetFrame.PROTOCOL_ERROR, protocolError); + return; + } + } try { - if (streamid == pushContinuationState.pushContFrame.streamid()) - handlePushContinuation(stream, cf); - else - protocolError(ErrorFrame.PROTOCOL_ERROR, "Received a Continuation Frame with an " + - "unexpected stream id"); - } catch (UncheckedIOException e) { + if (streamid == pcs.pushContFrame.streamid()) + handlePushContinuation(pcs, stream, cf); + else { + String protocolError = "Received a CONTINUATION with " + + "unexpected stream id: " + streamid + " != " + + pcs.pushContFrame.streamid(); + protocolError(ErrorFrame.PROTOCOL_ERROR, protocolError); + } + } catch (IOException | UncheckedIOException e) { debug.log("Error handling Push Promise with Continuation: " + e.getMessage(), e); protocolError(ErrorFrame.PROTOCOL_ERROR, e.getMessage()); return; } } else { pushContinuationState = null; - protocolError(ErrorFrame.PROTOCOL_ERROR, "Expected a Continuation frame but received " + frame); + String protocolError = "Expected a CONTINUATION frame but received " + frame; + protocolError(ErrorFrame.PROTOCOL_ERROR, protocolError); return; } } else { if (frame instanceof PushPromiseFrame pp) { try { handlePushPromise(stream, pp); - } catch (UncheckedIOException e) { + } catch (IOException | UncheckedIOException e) { protocolError(ErrorFrame.PROTOCOL_ERROR, e.getMessage()); return; } @@ -940,7 +1057,7 @@ void processFrame(Http2Frame frame) throws IOException { // decode headers try { decodeHeaders(hf, stream.rspHeadersConsumer()); - } catch (UncheckedIOException e) { + } catch (IOException | UncheckedIOException e) { debug.log("Error decoding headers: " + e.getMessage(), e); protocolError(ErrorFrame.PROTOCOL_ERROR, e.getMessage()); return; @@ -953,6 +1070,16 @@ void processFrame(Http2Frame frame) throws IOException { } } + private String checkMaxOrphanedHeadersExceeded(HeaderFrame hf) { + if (MAX_ORPHANED_HEADERS > 0 ) { + int orphaned = orphanedHeaders.incrementAndGet(); + if (orphaned < 0 || orphaned > MAX_ORPHANED_HEADERS) { + return "Too many orphaned header frames received on connection"; + } + } + return null; + } + final void dropDataFrame(DataFrame df) { if (isMarked(closedState, SHUTDOWN_REQUESTED)) return; if (debug.on()) { @@ -977,38 +1104,65 @@ final void ensureWindowUpdated(DataFrame df) { private void handlePushPromise(Stream parent, PushPromiseFrame pp) throws IOException { + int promisedStreamid = pp.getPromisedStream(); + if ((promisedStreamid & 0x01) != 0x00) { + throw new ProtocolException("Received PUSH_PROMISE for stream " + promisedStreamid); + } + int streamId = pp.streamid(); + if ((streamId & 0x01) != 0x01) { + throw new ProtocolException("Received PUSH_PROMISE on stream " + streamId); + } // always decode the headers as they may affect connection-level HPACK // decoding state assert pushContinuationState == null; - HeaderDecoder decoder = new HeaderDecoder(); - decodeHeaders(pp, decoder::onDecoded); - int promisedStreamid = pp.getPromisedStream(); + PushPromiseDecoder decoder = new PushPromiseDecoder(streamId, promisedStreamid, parent); + decodeHeaders(pp, decoder); if (pp.endHeaders()) { - completePushPromise(promisedStreamid, parent, decoder.headers()); + if (decoder.errorRef.get() == null) { + completePushPromise(promisedStreamid, parent, decoder.headers()); + } } else { pushContinuationState = new PushContinuationState(decoder, pp); } } - private void handlePushContinuation(Stream parent, ContinuationFrame cf) + private void handlePushContinuation(PushContinuationState pcs, Stream parent, ContinuationFrame cf) throws IOException { - var pcs = pushContinuationState; - decodeHeaders(cf, pcs.pushContDecoder::onDecoded); + assert pcs.pushContFrame.streamid() == cf.streamid() : String.format( + "Received CONTINUATION on a different stream %s != %s", + cf.streamid(), pcs.pushContFrame.streamid()); + decodeHeaders(cf, pcs.pushContDecoder); // if all continuations are sent, set pushWithContinuation to null if (cf.endHeaders()) { - completePushPromise(pcs.pushContFrame.getPromisedStream(), parent, - pcs.pushContDecoder.headers()); + if (pcs.pushContDecoder.errorRef.get() == null) { + completePushPromise(pcs.pushContFrame.getPromisedStream(), parent, + pcs.pushContDecoder.headers()); + } pushContinuationState = null; } } private void completePushPromise(int promisedStreamid, Stream parent, HttpHeaders headers) throws IOException { + if (parent == null) { + resetStream(promisedStreamid, ResetFrame.REFUSED_STREAM); + return; + } HttpRequestImpl parentReq = parent.request; + if (promisedStreamid < nextPushStream) { + // From RFC 9113 section 5.1.1: + // The identifier of a newly established stream MUST be numerically + // greater than all streams that the initiating endpoint has + // opened or reserved. + protocolError(ResetFrame.PROTOCOL_ERROR, String.format( + "Unexpected stream identifier: %s < %s", promisedStreamid, nextPushStream)); + return; + } if (promisedStreamid != nextPushStream) { + // we don't support skipping stream ids; resetStream(promisedStreamid, ResetFrame.PROTOCOL_ERROR); return; - } else if (!reserveStream(false)) { + } else if (!reserveStream(false, true)) { resetStream(promisedStreamid, ResetFrame.REFUSED_STREAM); return; } else { @@ -1177,11 +1331,17 @@ private void protocolError(int errorCode) private void protocolError(int errorCode, String msg) throws IOException { + String protocolError = "protocol error" + (msg == null?"":(": " + msg)); + ProtocolException protocolException = + new ProtocolException(protocolError); if (markHalfClosedLocal()) { + framesDecoder.close(protocolError); + subscriber.stop(protocolException); + if (debug.on()) debug.log("Sending GOAWAY due to " + protocolException); GoAwayFrame frame = new GoAwayFrame(0, errorCode); sendFrame(frame); } - shutdown(new IOException("protocol error" + (msg == null?"":(": " + msg)))); + shutdown(protocolException); } private void handleSettings(SettingsFrame frame) @@ -1356,7 +1516,7 @@ final Stream createStream(Exchange exchange) { Stream.PushedStream createPushStream(Stream parent, Exchange pushEx) { PushGroup pg = parent.exchange.getPushGroup(); - return new Stream.PushedStream<>(pg, this, pushEx); + return new Stream.PushedStream<>(parent, pg, this, pushEx); } /** @@ -1466,16 +1626,18 @@ private ByteBuffer getHeaderBuffer(int size) { private List encodeHeadersImpl(int bufferSize, HttpHeaders... headers) { ByteBuffer buffer = getHeaderBuffer(bufferSize); List buffers = new ArrayList<>(); - for(HttpHeaders header : headers) { + for (HttpHeaders header : headers) { for (Map.Entry> e : header.map().entrySet()) { String lKey = e.getKey().toLowerCase(Locale.US); List values = e.getValue(); for (String value : values) { hpackOut.header(lKey, value); while (!hpackOut.encode(buffer)) { - buffer.flip(); - buffers.add(buffer); - buffer = getHeaderBuffer(bufferSize); + if (!buffer.hasRemaining()) { + buffer.flip(); + buffers.add(buffer); + buffer = getHeaderBuffer(bufferSize); + } } } } @@ -1514,7 +1676,7 @@ private Stream registerNewStream(OutgoingHeaders> oh) { Throwable cause = null; synchronized (this) { if (isMarked(closedState, SHUTDOWN_REQUESTED)) { - cause = this.cause; + cause = this.cause.get(); if (cause == null) { cause = new IOException("Connection closed"); } @@ -1553,6 +1715,8 @@ void sendFrame(Http2Frame frame) { Stream stream = registerNewStream(oh); // provide protection from inserting unordered frames between Headers and Continuation if (stream != null) { + // we are creating a new stream: reset orphaned header count + orphanedHeaders.set(0); publisher.enqueue(encodeHeaders(oh, stream)); } } else { @@ -1621,7 +1785,7 @@ final class Http2TubeSubscriber implements TubeSubscriber { private volatile Flow.Subscription subscription; private volatile boolean completed; private volatile boolean dropped; - private volatile Throwable error; + private final AtomicReference errorRef = new AtomicReference<>(); private final ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue<>(); private final SequentialScheduler scheduler = @@ -1642,10 +1806,9 @@ final void processQueue() { asyncReceive(buffer); } } catch (Throwable t) { - Throwable x = error; - if (x == null) error = t; + errorRef.compareAndSet(null, t); } finally { - Throwable x = error; + Throwable x = errorRef.get(); if (x != null) { if (debug.on()) debug.log("Stopping scheduler", x); scheduler.stop(); @@ -1680,6 +1843,7 @@ public void onSubscribe(Flow.Subscription subscription) { @Override public void onNext(List item) { + if (completed) return; if (debug.on()) debug.log(() -> "onNext: got " + Utils.remaining(item) + " bytes in " + item.size() + " buffers"); queue.addAll(item); @@ -1688,19 +1852,21 @@ public void onNext(List item) { @Override public void onError(Throwable throwable) { + if (completed) return; if (debug.on()) debug.log(() -> "onError: " + throwable); - error = throwable; + errorRef.compareAndSet(null, throwable); completed = true; runOrSchedule(); } @Override public void onComplete() { + if (completed) return; String msg = isActive() ? "EOF reached while reading" : "Idle connection closed by HTTP/2 peer"; if (debug.on()) debug.log(msg); - error = new EOFException(msg); + errorRef.compareAndSet(null, new EOFException(msg)); completed = true; runOrSchedule(); } @@ -1712,6 +1878,18 @@ public void dropSubscription() { // then we might not need the 'dropped' boolean? dropped = true; } + + void stop(Throwable error) { + if (errorRef.compareAndSet(null, error)) { + completed = true; + scheduler.stop(); + queue.clear(); + if (subscription != null) { + subscription.cancel(); + } + queue.clear(); + } + } } boolean isActive() { 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 3fe8efdd7af43..e1f4ec16dcd46 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 @@ -964,7 +964,9 @@ private void debugCompleted(String tag, long startNanos, HttpRequest req) { // SSLException throw new SSLException(msg, throwable); } else if (throwable instanceof ProtocolException) { - throw new ProtocolException(msg); + ProtocolException pe = new ProtocolException(msg); + pe.initCause(throwable); + throw pe; } else if (throwable instanceof IOException) { throw new IOException(msg, throwable); } else { diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestImpl.java index 68a27041d6b25..f5b5ed54bf354 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestImpl.java @@ -287,10 +287,10 @@ public HttpHeaders headers() { InetSocketAddress authority() { return authority; } - void setH2Upgrade(Http2ClientImpl h2client) { + void setH2Upgrade(Exchange exchange) { systemHeadersBuilder.setHeader("Connection", "Upgrade, HTTP2-Settings"); systemHeadersBuilder.setHeader("Upgrade", Alpns.H2C); - systemHeadersBuilder.setHeader("HTTP2-Settings", h2client.getSettingsString()); + systemHeadersBuilder.setHeader("HTTP2-Settings", exchange.h2cSettingsStrings()); } @Override diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/ResponseBodyHandlers.java b/src/java.net.http/share/classes/jdk/internal/net/http/ResponseBodyHandlers.java index 66d89ae1fc5f9..22e03238d2140 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/ResponseBodyHandlers.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/ResponseBodyHandlers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ import java.security.AccessControlContext; import java.security.AccessController; import java.util.List; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentMap; import java.util.function.Function; @@ -137,16 +138,21 @@ public void applyPushPromise( if (!initiatingURI.getHost().equalsIgnoreCase(pushRequestURI.getHost())) return; + String initiatingScheme = initiatingURI.getScheme(); + String pushRequestScheme = pushRequestURI.getScheme(); + + if (!initiatingScheme.equalsIgnoreCase(pushRequestScheme)) return; + int initiatingPort = initiatingURI.getPort(); if (initiatingPort == -1 ) { - if ("https".equalsIgnoreCase(initiatingURI.getScheme())) + if ("https".equalsIgnoreCase(initiatingScheme)) initiatingPort = 443; else initiatingPort = 80; } int pushPort = pushRequestURI.getPort(); if (pushPort == -1 ) { - if ("https".equalsIgnoreCase(pushRequestURI.getScheme())) + if ("https".equalsIgnoreCase(pushRequestScheme)) pushPort = 443; else pushPort = 80; diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java index 4563362292329..84187678f94b5 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java @@ -30,6 +30,7 @@ import java.io.UncheckedIOException; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; +import java.net.ProtocolException; import java.net.URI; import java.net.http.HttpResponse.BodyHandler; import java.net.http.HttpResponse.ResponseInfo; @@ -43,6 +44,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.Flow; import java.util.concurrent.Flow.Subscription; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -52,10 +54,13 @@ import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.http.HttpResponse.BodySubscriber; + import jdk.internal.net.http.common.*; import jdk.internal.net.http.frame.*; import jdk.internal.net.http.hpack.DecodingCallback; +import static jdk.internal.net.http.Exchange.MAX_NON_FINAL_RESPONSES; + /** * Http/2 Stream handling. * @@ -140,6 +145,9 @@ class Stream extends ExchangeImpl { private volatile boolean closed; private volatile boolean endStreamSent; private volatile boolean finalResponseCodeReceived; + private volatile boolean trailerReceived; + private AtomicInteger nonFinalResponseCount = new AtomicInteger(); + // Indicates the first reason that was invoked when sending a ResetFrame // to the server. A streamState of 0 indicates that no reset was sent. // (see markStream(int code) @@ -520,16 +528,38 @@ void otherFrame(Http2Frame frame) throws IOException { // The Hpack decoder decodes into one of these consumers of name,value pairs DecodingCallback rspHeadersConsumer() { - return rspHeadersConsumer::onDecoded; + return rspHeadersConsumer; + } + + String checkInterimResponseCountExceeded() { + // this is also checked by Exchange - but tracking it here too provides + // a more informative message. + int count = nonFinalResponseCount.incrementAndGet(); + if (MAX_NON_FINAL_RESPONSES > 0 && (count < 0 || count > MAX_NON_FINAL_RESPONSES)) { + return String.format( + "Stream %s PROTOCOL_ERROR: too many interim responses received: %s > %s", + streamid, count, MAX_NON_FINAL_RESPONSES); + } + return null; } protected void handleResponse(HeaderFrame hf) throws IOException { HttpHeaders responseHeaders = responseHeadersBuilder.build(); if (!finalResponseCodeReceived) { - responseCode = (int) responseHeaders - .firstValueAsLong(":status") - .orElseThrow(() -> new IOException("no statuscode in response")); + try { + responseCode = (int) responseHeaders + .firstValueAsLong(":status") + .orElseThrow(() -> new ProtocolException(String.format( + "Stream %s PROTOCOL_ERROR: no status code in response", + streamid))); + } catch (ProtocolException cause) { + cancelImpl(cause, ResetFrame.PROTOCOL_ERROR); + rspHeadersConsumer.reset(); + return; + } + + String protocolErrorMsg = null; // If informational code, response is partially complete if (responseCode < 100 || responseCode > 199) { this.finalResponseCodeReceived = true; @@ -537,23 +567,31 @@ protected void handleResponse(HeaderFrame hf) throws IOException { // see RFC 9113 section 8.1: // A HEADERS frame with the END_STREAM flag set that carries an // informational status code is malformed - String msg = ("Stream %s PROTOCOL_ERROR: " + - "HEADERS frame with status %s has END_STREAM flag set") - .formatted(streamid, responseCode); + protocolErrorMsg = String.format( + "Stream %s PROTOCOL_ERROR: " + + "HEADERS frame with status %s has END_STREAM flag set", + streamid, responseCode); + } else { + protocolErrorMsg = checkInterimResponseCountExceeded(); + } + + if (protocolErrorMsg != null) { if (debug.on()) { - debug.log(msg); + debug.log(protocolErrorMsg); } - cancelImpl(new IOException(msg), ResetFrame.PROTOCOL_ERROR); + cancelImpl(new ProtocolException(protocolErrorMsg), ResetFrame.PROTOCOL_ERROR); + rspHeadersConsumer.reset(); + return; } response = new Response( request, exchange, responseHeaders, connection(), responseCode, HttpClient.Version.HTTP_2); - /* TODO: review if needs to be removed - the value is not used, but in case `content-length` doesn't parse as - long, there will be NumberFormatException. If left as is, make sure - code up the stack handles NFE correctly. */ + /* TODO: review if needs to be removed + the value is not used, but in case `content-length` doesn't parse as + long, there will be NumberFormatException. If left as is, make sure + code up the stack handles NFE correctly. */ responseHeaders.firstValueAsLong("content-length"); if (Log.headers()) { @@ -572,6 +610,15 @@ request, exchange, responseHeaders, connection(), Log.dumpHeaders(sb, " ", responseHeaders); Log.logHeaders(sb.toString()); } + if (trailerReceived) { + String protocolErrorMsg = String.format( + "Stream %s PROTOCOL_ERROR: trailers already received", streamid); + if (debug.on()) { + debug.log(protocolErrorMsg); + } + cancelImpl(new ProtocolException(protocolErrorMsg), ResetFrame.PROTOCOL_ERROR); + } + trailerReceived = true; rspHeadersConsumer.reset(); } @@ -1182,7 +1229,7 @@ private DataFrame getEmptyEndStreamDataFrame() { /** * A List of responses relating to this stream. Normally there is only - * one response, but intermediate responses like 100 are allowed + * one response, but interim responses like 100 are allowed * and must be passed up to higher level before continuing. Deals with races * such as if responses are returned before the CFs get created by * getResponseAsync() @@ -1401,7 +1448,7 @@ void cancelImpl(Throwable e) { cancelImpl(e, ResetFrame.CANCEL); } - private void cancelImpl(final Throwable e, final int resetFrameErrCode) { + void cancelImpl(final Throwable e, final int resetFrameErrCode) { errorRef.compareAndSet(null, e); if (debug.on()) { if (streamid == 0) debug.log("cancelling stream: %s", (Object)e); @@ -1511,6 +1558,7 @@ void close() { } static class PushedStream extends Stream { + final Stream parent; final PushGroup pushGroup; // push streams need the response CF allocated up front as it is // given directly to user via the multi handler callback function. @@ -1520,16 +1568,17 @@ static class PushedStream extends Stream { volatile HttpResponse.BodyHandler pushHandler; private volatile boolean finalPushResponseCodeReceived; - PushedStream(PushGroup pushGroup, + PushedStream(Stream parent, + PushGroup pushGroup, Http2Connection connection, Exchange pushReq) { // ## no request body possible, null window controller super(connection, pushReq, null); + this.parent = parent; this.pushGroup = pushGroup; this.pushReq = pushReq.request(); this.pushCF = new MinimalFuture<>(); this.responseCF = new MinimalFuture<>(); - } CompletableFuture> responseCF() { @@ -1617,7 +1666,16 @@ protected void handleResponse(HeaderFrame hf) { .orElse(-1); if (responseCode == -1) { - completeResponseExceptionally(new IOException("No status code")); + cancelImpl(new ProtocolException("No status code"), ResetFrame.PROTOCOL_ERROR); + rspHeadersConsumer.reset(); + return; + } else if (responseCode >= 100 && responseCode < 200) { + String protocolErrorMsg = checkInterimResponseCountExceeded(); + if (protocolErrorMsg != null) { + cancelImpl(new ProtocolException(protocolErrorMsg), ResetFrame.PROTOCOL_ERROR); + rspHeadersConsumer.reset(); + return; + } } this.finalPushResponseCodeReceived = true; @@ -1727,7 +1785,9 @@ void closeAsUnprocessed() { } } - private class HeadersConsumer extends ValidatingHeadersConsumer { + private class HeadersConsumer extends ValidatingHeadersConsumer implements DecodingCallback { + + boolean maxHeaderListSizeReached; @Override public void reset() { @@ -1740,6 +1800,9 @@ public void reset() { public void onDecoded(CharSequence name, CharSequence value) throws UncheckedIOException { + if (maxHeaderListSizeReached) { + return; + } try { String n = name.toString(); String v = value.toString(); @@ -1762,6 +1825,23 @@ public void onDecoded(CharSequence name, CharSequence value) protected String formatMessage(String message, String header) { return "malformed response: " + super.formatMessage(message, header); } + + @Override + public void onMaxHeaderListSizeReached(long size, int maxHeaderListSize) throws ProtocolException { + if (maxHeaderListSizeReached) return; + try { + DecodingCallback.super.onMaxHeaderListSizeReached(size, maxHeaderListSize); + } catch (ProtocolException cause) { + maxHeaderListSizeReached = true; + // If this is a push stream: cancel the parent. + if (Stream.this instanceof Stream.PushedStream ps) { + ps.parent.onProtocolError(cause); + } + // cancel the stream, continue processing + onProtocolError(cause); + reset(); + } + } } final class Http2StreamResponseSubscriber extends HttpBodySubscriberWrapper { diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/HeaderDecoder.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/HeaderDecoder.java index 62d03844d2e82..d81f52e6630ef 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/HeaderDecoder.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/HeaderDecoder.java @@ -39,7 +39,11 @@ public void onDecoded(CharSequence name, CharSequence value) { String n = name.toString(); String v = value.toString(); super.onDecoded(n, v); - headersBuilder.addHeader(n, v); + addHeader(n, v); + } + + protected void addHeader(String name, String value) { + headersBuilder.addHeader(name, value); } public HttpHeaders headers() { diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java index b2eb570db0c1e..49e669e5addcb 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java @@ -616,6 +616,19 @@ public static int getIntegerProperty(String name, int defaultValue) { Integer.parseInt(System.getProperty(name, String.valueOf(defaultValue)))); } + public static int getIntegerNetProperty(String property, int min, int max, int defaultValue, boolean log) { + int value = Utils.getIntegerNetProperty(property, defaultValue); + // use default value if misconfigured + if (value < min || value > max) { + if (log && Log.errors()) { + Log.logError("Property value for {0}={1} not in [{2}..{3}]: " + + "using default={4}", property, value, min, max, defaultValue); + } + value = defaultValue; + } + return value; + } + public static SSLParameters copySSLParameters(SSLParameters p) { SSLParameters p1 = new SSLParameters(); p1.setAlgorithmConstraints(p.getAlgorithmConstraints()); diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/hpack/Decoder.java b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/Decoder.java index 9d57a734ac304..881be12c67cee 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/hpack/Decoder.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/Decoder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * 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 +27,7 @@ import jdk.internal.net.http.hpack.HPACK.Logger; import java.io.IOException; +import java.net.ProtocolException; import java.nio.ByteBuffer; import java.util.List; import java.util.concurrent.atomic.AtomicLong; @@ -107,12 +108,16 @@ public final class Decoder { private final StringReader stringReader; private final StringBuilder name; private final StringBuilder value; + private final int maxHeaderListSize; + private final int maxIndexed; private int intValue; private boolean firstValueRead; private boolean firstValueIndex; private boolean nameHuffmanEncoded; private boolean valueHuffmanEncoded; private int capacity; + private long size; + private int indexed; /** * Constructs a {@code Decoder} with the specified initial capacity of the @@ -129,6 +134,31 @@ public final class Decoder { * if capacity is negative */ public Decoder(int capacity) { + this(capacity, 0, 0); + } + + /** + * Constructs a {@code Decoder} with the specified initial capacity of the + * header table, a max header list size, and a maximum number of literals + * with indexing per header section. + * + *

    The value of the capacity has to be agreed between decoder and encoder out-of-band, + * e.g. by a protocol that uses HPACK + * (see 4.2. Maximum Table Size). + * + * @param capacity + * a non-negative integer + * @param maxHeaderListSize + * a maximum value for the header list size. This is the uncompressed + * names size + uncompressed values size + 32 bytes per field line + * @param maxIndexed + * the maximum number of literal with indexing we're prepared to handle + * for a header field section + * + * @throws IllegalArgumentException + * if capacity is negative + */ + public Decoder(int capacity, int maxHeaderListSize, int maxIndexed) { id = DECODERS_IDS.incrementAndGet(); logger = HPACK.getLogger().subLogger("Decoder#" + id); if (logger.isLoggable(NORMAL)) { @@ -145,6 +175,8 @@ public Decoder(int capacity) { toString(), hashCode); }); } + this.maxHeaderListSize = maxHeaderListSize; + this.maxIndexed = maxIndexed; setMaxCapacity0(capacity); table = new SimpleHeaderTable(capacity, logger.subLogger("HeaderTable")); integerReader = new IntegerReader(); @@ -242,22 +274,25 @@ public void decode(ByteBuffer headerBlock, requireNonNull(consumer, "consumer"); if (logger.isLoggable(NORMAL)) { logger.log(NORMAL, () -> format("reading %s, end of header block? %s", - headerBlock, endOfHeaderBlock)); + headerBlock, endOfHeaderBlock)); } while (headerBlock.hasRemaining()) { proceed(headerBlock, consumer); } if (endOfHeaderBlock && state != State.READY) { logger.log(NORMAL, () -> format("unexpected end of %s representation", - state)); + state)); throw new IOException("Unexpected end of header block"); } + if (endOfHeaderBlock) { + size = indexed = 0; + } } private void proceed(ByteBuffer input, DecodingCallback action) throws IOException { switch (state) { - case READY -> resumeReady(input); + case READY -> resumeReady(input, action); case INDEXED -> resumeIndexed(input, action); case LITERAL -> resumeLiteral(input, action); case LITERAL_WITH_INDEXING -> resumeLiteralWithIndexing(input, action); @@ -268,7 +303,7 @@ private void proceed(ByteBuffer input, DecodingCallback action) } } - private void resumeReady(ByteBuffer input) { + private void resumeReady(ByteBuffer input, DecodingCallback action) throws IOException { int b = input.get(input.position()) & 0xff; // absolute read State s = states.get(b); if (logger.isLoggable(EXTRA)) { @@ -289,6 +324,9 @@ private void resumeReady(ByteBuffer input) { } break; case LITERAL_WITH_INDEXING: + if (maxIndexed > 0 && ++indexed > maxIndexed) { + action.onMaxLiteralWithIndexingReached(indexed, maxIndexed); + } state = State.LITERAL_WITH_INDEXING; firstValueIndex = (b & 0b0011_1111) != 0; if (firstValueIndex) { @@ -315,6 +353,12 @@ private void resumeReady(ByteBuffer input) { } } + private void checkMaxHeaderListSize(long sz, DecodingCallback consumer) throws ProtocolException { + if (maxHeaderListSize > 0 && sz > maxHeaderListSize) { + consumer.onMaxHeaderListSizeReached(sz, maxHeaderListSize); + } + } + // 0 1 2 3 4 5 6 7 // +---+---+---+---+---+---+---+---+ // | 1 | Index (7+) | @@ -332,6 +376,8 @@ private void resumeIndexed(ByteBuffer input, DecodingCallback action) } try { SimpleHeaderTable.HeaderField f = getHeaderFieldAt(intValue); + size = size + 32 + f.name.length() + f.value.length(); + checkMaxHeaderListSize(size, action); action.onIndexed(intValue, f.name, f.value); } finally { state = State.READY; @@ -374,7 +420,7 @@ private SimpleHeaderTable.HeaderField getHeaderFieldAt(int index) // private void resumeLiteral(ByteBuffer input, DecodingCallback action) throws IOException { - if (!completeReading(input)) { + if (!completeReading(input, action)) { return; } try { @@ -385,6 +431,8 @@ private void resumeLiteral(ByteBuffer input, DecodingCallback action) intValue, value, valueHuffmanEncoded)); } SimpleHeaderTable.HeaderField f = getHeaderFieldAt(intValue); + size = size + 32 + f.name.length() + value.length(); + checkMaxHeaderListSize(size, action); action.onLiteral(intValue, f.name, value, valueHuffmanEncoded); } else { if (logger.isLoggable(NORMAL)) { @@ -392,6 +440,8 @@ private void resumeLiteral(ByteBuffer input, DecodingCallback action) "literal without indexing ('%s', huffman=%b, '%s', huffman=%b)", name, nameHuffmanEncoded, value, valueHuffmanEncoded)); } + size = size + 32 + name.length() + value.length(); + checkMaxHeaderListSize(size, action); action.onLiteral(name, nameHuffmanEncoded, value, valueHuffmanEncoded); } } finally { @@ -425,7 +475,7 @@ private void resumeLiteral(ByteBuffer input, DecodingCallback action) private void resumeLiteralWithIndexing(ByteBuffer input, DecodingCallback action) throws IOException { - if (!completeReading(input)) { + if (!completeReading(input, action)) { return; } try { @@ -445,6 +495,8 @@ private void resumeLiteralWithIndexing(ByteBuffer input, } SimpleHeaderTable.HeaderField f = getHeaderFieldAt(intValue); n = f.name; + size = size + 32 + n.length() + v.length(); + checkMaxHeaderListSize(size, action); action.onLiteralWithIndexing(intValue, n, v, valueHuffmanEncoded); } else { n = name.toString(); @@ -453,6 +505,8 @@ private void resumeLiteralWithIndexing(ByteBuffer input, "literal with incremental indexing ('%s', huffman=%b, '%s', huffman=%b)", n, nameHuffmanEncoded, value, valueHuffmanEncoded)); } + size = size + 32 + n.length() + v.length(); + checkMaxHeaderListSize(size, action); action.onLiteralWithIndexing(n, nameHuffmanEncoded, v, valueHuffmanEncoded); } table.put(n, v); @@ -486,7 +540,7 @@ private void resumeLiteralWithIndexing(ByteBuffer input, private void resumeLiteralNeverIndexed(ByteBuffer input, DecodingCallback action) throws IOException { - if (!completeReading(input)) { + if (!completeReading(input, action)) { return; } try { @@ -497,6 +551,8 @@ private void resumeLiteralNeverIndexed(ByteBuffer input, intValue, value, valueHuffmanEncoded)); } SimpleHeaderTable.HeaderField f = getHeaderFieldAt(intValue); + size = size + 32 + f.name.length() + value.length(); + checkMaxHeaderListSize(size, action); action.onLiteralNeverIndexed(intValue, f.name, value, valueHuffmanEncoded); } else { if (logger.isLoggable(NORMAL)) { @@ -504,6 +560,8 @@ private void resumeLiteralNeverIndexed(ByteBuffer input, "literal never indexed ('%s', huffman=%b, '%s', huffman=%b)", name, nameHuffmanEncoded, value, valueHuffmanEncoded)); } + size = size + 32 + name.length() + value.length(); + checkMaxHeaderListSize(size, action); action.onLiteralNeverIndexed(name, nameHuffmanEncoded, value, valueHuffmanEncoded); } } finally { @@ -541,7 +599,7 @@ private void resumeSizeUpdate(ByteBuffer input, } } - private boolean completeReading(ByteBuffer input) throws IOException { + private boolean completeReading(ByteBuffer input, DecodingCallback action) throws IOException { if (!firstValueRead) { if (firstValueIndex) { if (!integerReader.read(input)) { @@ -551,6 +609,8 @@ private boolean completeReading(ByteBuffer input) throws IOException { integerReader.reset(); } else { if (!stringReader.read(input, name)) { + long sz = size + 32 + name.length(); + checkMaxHeaderListSize(sz, action); return false; } nameHuffmanEncoded = stringReader.isHuffmanEncoded(); @@ -560,6 +620,8 @@ private boolean completeReading(ByteBuffer input) throws IOException { return false; } else { if (!stringReader.read(input, value)) { + long sz = size + 32 + name.length() + value.length(); + checkMaxHeaderListSize(sz, action); return false; } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/hpack/DecodingCallback.java b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/DecodingCallback.java index 5e9df860febeb..228f9bf02061e 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/hpack/DecodingCallback.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/DecodingCallback.java @@ -24,6 +24,7 @@ */ package jdk.internal.net.http.hpack; +import java.net.ProtocolException; import java.nio.ByteBuffer; /** @@ -292,4 +293,17 @@ default void onLiteralWithIndexing(CharSequence name, * new capacity of the header table */ default void onSizeUpdate(int capacity) { } + + default void onMaxHeaderListSizeReached(long size, int maxHeaderListSize) + throws ProtocolException { + throw new ProtocolException(String + .format("Size exceeds MAX_HEADERS_LIST_SIZE: %s > %s", + size, maxHeaderListSize)); + } + + default void onMaxLiteralWithIndexingReached(long indexed, int maxIndexed) + throws ProtocolException { + throw new ProtocolException(String.format("Too many literal with indexing: %s > %s", + indexed, maxIndexed)); + } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/hpack/Encoder.java b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/Encoder.java index 4188937b1ad93..c603e917ca437 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/hpack/Encoder.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/Encoder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -258,9 +258,10 @@ public void header(CharSequence name, } } } + assert encoding : "encoding is false"; } - private boolean isHuffmanBetterFor(CharSequence value) { + protected final boolean isHuffmanBetterFor(CharSequence value) { // prefer Huffman encoding only if it is strictly smaller than Latin-1 return huffmanWriter.lengthOf(value) < value.length(); } @@ -340,6 +341,10 @@ protected int calculateCapacity(int maxCapacity) { return 0; } + protected final int tableIndexOf(CharSequence name, CharSequence value) { + return getHeaderTable().indexOf(name, value); + } + /** * Encodes the {@linkplain #header(CharSequence, CharSequence) set up} * header into the given buffer. @@ -380,6 +385,7 @@ public final boolean encode(ByteBuffer headerBlock) { writer.reset(); // FIXME: WHY? encoding = false; } + assert done || encoding : "done: " + done + ", encoding: " + encoding; return done; } @@ -542,4 +548,8 @@ protected final void checkEncoding() { // TODO: better name e.g. checkIfEncoding "Previous encoding operation hasn't finished yet"); } } + + protected final Logger logger() { + return logger; + } } diff --git a/src/java.net.http/share/classes/module-info.java b/src/java.net.http/share/classes/module-info.java index cf9d07bdf328f..5303e818866be 100644 --- a/src/java.net.http/share/classes/module-info.java +++ b/src/java.net.http/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -115,6 +115,25 @@ * The HTTP/2 client maximum frame size in bytes. The server is not permitted to send a frame * larger than this. *

  • + *
  • {@systemProperty jdk.httpclient.maxLiteralWithIndexing} (default: 512)
    + * The maximum number of header field lines (header name and value pairs) that a + * client is willing to add to the HPack Decoder dynamic table during the decoding + * of an entire header field section. + * This is purely an implementation limit. + * If a peer sends a field section with encoding that + * exceeds this limit a {@link java.net.ProtocolException ProtocolException} will be raised. + * A value of zero or a negative value means no limit. + *

  • + *
  • {@systemProperty jdk.httpclient.maxNonFinalResponses} (default: 8)
    + * The maximum number of interim (non-final) responses that a client is prepared + * to accept on a request-response stream before the final response is received. + * Interim responses are responses with a status in the range [100, 199] inclusive. + * This is purely an implementation limit. + * If a peer sends a number of interim response that exceeds this limit before + * sending the final response, a {@link java.net.ProtocolException ProtocolException} + * will be raised. + * A value of zero or a negative value means no limit. + *

  • *
  • {@systemProperty jdk.httpclient.maxstreams} (default: 100)
    * The maximum number of HTTP/2 push streams that the client will permit servers to open * simultaneously. @@ -155,6 +174,15 @@ * conf/net.properties)
    A comma separated list of HTTP authentication scheme names, that * are disallowed for use by the HTTP client implementation, for HTTP CONNECT tunneling. *

  • + *
  • {@systemProperty jdk.http.maxHeaderSize} (default: 393216 or 384kB) + *
    The maximum header field section size that the client is prepared to accept. + * This is computed as the sum of the size of the uncompressed header name, plus + * the size of the uncompressed header value, plus an overhead of 32 bytes for + * each field section line. If a peer sends a field section that exceeds this + * size a {@link java.net.ProtocolException ProtocolException} will be raised. + * This applies to all versions of the protocol. A value of zero or a negative + * value means no limit. + *

  • * * @moduleGraph * @since 11 diff --git a/src/jdk.httpserver/share/classes/module-info.java b/src/jdk.httpserver/share/classes/module-info.java index 46dbb6ea64f68..23e04405ee863 100644 --- a/src/jdk.httpserver/share/classes/module-info.java +++ b/src/jdk.httpserver/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * 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,6 +70,16 @@ * while the headers are being read, then the connection is terminated and the request ignored. * If the value is less than or equal to zero, then the default value is used. * + *
  • {@systemProperty sun.net.httpserver.maxReqHeaderSize} (default: 393216 or 384kB)
    + * The maximum header field section size that the server is prepared to accept. + * This is computed as the sum of the size of the header name, plus + * the size of the header value, plus an overhead of 32 bytes for + * each field section line. The request line counts as a first field section line, + * where the name is empty and the value is the whole line. + * If this limit is exceeded while the headers are being read, then the connection + * is terminated and the request ignored. + * If the value is less than or equal to zero, there is no limit. + *

  • *
  • {@systemProperty sun.net.httpserver.maxReqTime} (default: -1)
    * The maximum time in milliseconds allowed to receive a request headers and body. * In practice, the actual time is a function of request size, network speed, and handler diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/Request.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/Request.java index 99dac0547cead..6c0c2c271ed4a 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/Request.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/Request.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * 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,8 +44,10 @@ class Request { private SocketChannel chan; private InputStream is; private OutputStream os; + private final int maxReqHeaderSize; Request (InputStream rawInputStream, OutputStream rawout) throws IOException { + this.maxReqHeaderSize = ServerConfig.getMaxReqHeaderSize(); is = rawInputStream; os = rawout; do { @@ -75,6 +77,7 @@ public OutputStream outputStream () { public String readLine () throws IOException { boolean gotCR = false, gotLF = false; pos = 0; lineBuf = new StringBuffer(); + long lsize = 32; while (!gotLF) { int c = is.read(); if (c == -1) { @@ -87,20 +90,27 @@ public String readLine () throws IOException { gotCR = false; consume (CR); consume (c); + lsize = lsize + 2; } } else { if (c == CR) { gotCR = true; } else { consume (c); + lsize = lsize + 1; } } + if (maxReqHeaderSize > 0 && lsize > maxReqHeaderSize) { + throw new IOException("Maximum header (" + + "sun.net.httpserver.maxReqHeaderSize) exceeded, " + + ServerConfig.getMaxReqHeaderSize() + "."); + } } lineBuf.append (buf, 0, pos); return new String (lineBuf); } - private void consume (int c) { + private void consume (int c) throws IOException { if (pos == BUF_LEN) { lineBuf.append (buf); pos = 0; @@ -138,13 +148,22 @@ Headers headers () throws IOException { len = 1; firstc = c; } + long hsize = startLine.length() + 32L; while (firstc != LF && firstc != CR && firstc >= 0) { int keyend = -1; int c; boolean inKey = firstc > ' '; s[len++] = (char) firstc; + hsize = hsize + 1; parseloop:{ + // We start parsing for a new name value pair here. + // The max header size includes an overhead of 32 bytes per + // name value pair. + // See SETTINGS_MAX_HEADER_LIST_SIZE, RFC 9113, section 6.5.2. + long maxRemaining = maxReqHeaderSize > 0 + ? maxReqHeaderSize - hsize - 32 + : Long.MAX_VALUE; while ((c = is.read()) >= 0) { switch (c) { /*fallthrough*/ @@ -178,6 +197,11 @@ Headers headers () throws IOException { s = ns; } s[len++] = (char) c; + if (maxReqHeaderSize > 0 && len > maxRemaining) { + throw new IOException("Maximum header (" + + "sun.net.httpserver.maxReqHeaderSize) exceeded, " + + ServerConfig.getMaxReqHeaderSize() + "."); + } } firstc = -1; } @@ -205,6 +229,13 @@ Headers headers () throws IOException { "sun.net.httpserver.maxReqHeaders) exceeded, " + ServerConfig.getMaxReqHeaders() + "."); } + hsize = hsize + len + 32; + if (maxReqHeaderSize > 0 && hsize > maxReqHeaderSize) { + throw new IOException("Maximum header (" + + "sun.net.httpserver.maxReqHeaderSize) exceeded, " + + ServerConfig.getMaxReqHeaderSize() + "."); + } + if (k == null) { // Headers disallows null keys, use empty string k = ""; // instead to represent invalid key } diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerConfig.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerConfig.java index 21f6165b05eae..9186dd4c168c1 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerConfig.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * 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,6 +49,7 @@ class ServerConfig { // timing out request/response if max request/response time is configured private static final long DEFAULT_REQ_RSP_TIMER_TASK_SCHEDULE_MILLIS = 1000; private static final int DEFAULT_MAX_REQ_HEADERS = 200; + private static final int DEFAULT_MAX_REQ_HEADER_SIZE = 380 * 1024; private static final long DEFAULT_DRAIN_AMOUNT = 64 * 1024; private static long idleTimerScheduleMillis; @@ -62,6 +63,9 @@ class ServerConfig { private static int maxIdleConnections; // The maximum number of request headers allowable private static int maxReqHeaders; + // a maximum value for the header list size. This is the + // names size + values size + 32 bytes per field line + private static int maxReqHeadersSize; // max time a request or response is allowed to take private static long maxReqTime; private static long maxRspTime; @@ -107,6 +111,14 @@ public Void run () { maxReqHeaders = DEFAULT_MAX_REQ_HEADERS; } + // a value <= 0 means unlimited + maxReqHeadersSize = Integer.getInteger( + "sun.net.httpserver.maxReqHeaderSize", + DEFAULT_MAX_REQ_HEADER_SIZE); + if (maxReqHeadersSize <= 0) { + maxReqHeadersSize = 0; + } + maxReqTime = Long.getLong("sun.net.httpserver.maxReqTime", DEFAULT_MAX_REQ_TIME); @@ -215,6 +227,10 @@ static int getMaxReqHeaders() { return maxReqHeaders; } + static int getMaxReqHeaderSize() { + return maxReqHeadersSize; + } + /** * @return Returns the maximum amount of time the server will wait for the request to be read * completely. This method can return a value of 0 or negative to imply no maximum limit has diff --git a/test/jdk/java/net/httpclient/ExpectContinueTest.java b/test/jdk/java/net/httpclient/ExpectContinueTest.java index 3d28ae8c8b49c..50e43099255ac 100644 --- a/test/jdk/java/net/httpclient/ExpectContinueTest.java +++ b/test/jdk/java/net/httpclient/ExpectContinueTest.java @@ -59,6 +59,7 @@ import java.io.Writer; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.ProtocolException; import java.net.ServerSocket; import java.net.Socket; import java.net.URI; @@ -361,7 +362,7 @@ private void verifyRequest(String path, int expectedStatusCode, HttpResponse cf.join()); - assertEquals(t.getCause().getClass(), IOException.class, "Expected an IOException but got " + t.getCause()); + assertEquals(t.getCause().getClass(), ProtocolException.class, + "Expected a ProtocolException but got " + t.getCause()); System.err.println("Client received the following expected exception: " + t.getCause()); faultyServer.stop(); } @@ -222,7 +224,10 @@ private void verify(HttpResponse resp) { static class Http2PushPromiseHeadersExchangeImpl extends Http2TestExchangeImpl { - Http2PushPromiseHeadersExchangeImpl(int streamid, String method, HttpHeaders reqheaders, HttpHeadersBuilder rspheadersBuilder, URI uri, InputStream is, SSLSession sslSession, BodyOutputStream os, Http2TestServerConnection conn, boolean pushAllowed) { + Http2PushPromiseHeadersExchangeImpl(int streamid, String method, HttpHeaders reqheaders, + HttpHeadersBuilder rspheadersBuilder, URI uri, InputStream is, + SSLSession sslSession, BodyOutputStream os, + Http2TestServerConnection conn, boolean pushAllowed) { super(streamid, method, reqheaders, rspheadersBuilder, uri, is, sslSession, os, conn, pushAllowed); } diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/HttpServerAdapters.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/HttpServerAdapters.java index 36498684a9a95..27dbe637b94ef 100644 --- a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/HttpServerAdapters.java +++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/HttpServerAdapters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ public static abstract class HttpTestExchange implements AutoCloseable { public abstract void close(); public abstract InetSocketAddress getRemoteAddress(); public abstract String getConnectionKey(); + public abstract InetSocketAddress getLocalAddress(); public void serverPush(URI uri, HttpHeaders headers, byte[] body) { ByteArrayInputStream bais = new ByteArrayInputStream(body); serverPush(uri, headers, bais); @@ -303,7 +304,10 @@ void doFilter(Filter.Chain chain) throws IOException { public InetSocketAddress getRemoteAddress() { return exchange.getRemoteAddress(); } - + @Override + public InetSocketAddress getLocalAddress() { + return exchange.getLocalAddress(); + } @Override public URI getRequestURI() { return exchange.getRequestURI(); } @Override @@ -370,6 +374,10 @@ void doFilter(Filter.Chain filter) throws IOException { public InetSocketAddress getRemoteAddress() { return exchange.getRemoteAddress(); } + @Override + public InetSocketAddress getLocalAddress() { + return exchange.getLocalAddress(); + } @Override public String getConnectionKey() { diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/HpackTestEncoder.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/HpackTestEncoder.java new file mode 100644 index 0000000000000..f54a4a766b86e --- /dev/null +++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/HpackTestEncoder.java @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.httpclient.test.lib.http2; + +import java.util.function.*; + +import jdk.internal.net.http.hpack.Encoder; + +import static java.lang.String.format; +import static java.util.Objects.requireNonNull; +import static jdk.internal.net.http.hpack.HPACK.Logger.Level.EXTRA; +import static jdk.internal.net.http.hpack.HPACK.Logger.Level.NORMAL; + +public class HpackTestEncoder extends Encoder { + + public HpackTestEncoder(int maxCapacity) { + super(maxCapacity); + } + + /** + * Sets up the given header {@code (name, value)} with possibly sensitive + * value. + * + *

    If the {@code value} is sensitive (think security, secrecy, etc.) + * this encoder will compress it using a special representation + * (see 6.2.3. Literal Header Field Never Indexed). + * + *

    Fixates {@code name} and {@code value} for the duration of encoding. + * + * @param name + * the name + * @param value + * the value + * @param sensitive + * whether or not the value is sensitive + * + * @throws NullPointerException + * if any of the arguments are {@code null} + * @throws IllegalStateException + * if the encoder hasn't fully encoded the previous header, or + * hasn't yet started to encode it + * @see #header(CharSequence, CharSequence) + * @see DecodingCallback#onDecoded(CharSequence, CharSequence, boolean) + */ + public void header(CharSequence name, + CharSequence value, + boolean sensitive) throws IllegalStateException { + if (sensitive || getMaxCapacity() == 0) { + super.header(name, value, true); + } else { + header(name, value, false, (n,v) -> false); + } + } + /** + * Sets up the given header {@code (name, value)} with possibly sensitive + * value. + * + *

    If the {@code value} is sensitive (think security, secrecy, etc.) + * this encoder will compress it using a special representation + * (see 6.2.3. Literal Header Field Never Indexed). + * + *

    Fixates {@code name} and {@code value} for the duration of encoding. + * + * @param name + * the name + * @param value + * the value + * @param insertionPolicy + * a bipredicate to indicate whether a name value pair + * should be added to the dynamic table + * + * @throws NullPointerException + * if any of the arguments are {@code null} + * @throws IllegalStateException + * if the encoder hasn't fully encoded the previous header, or + * hasn't yet started to encode it + * @see #header(CharSequence, CharSequence) + * @see DecodingCallback#onDecoded(CharSequence, CharSequence, boolean) + */ + public void header(CharSequence name, + CharSequence value, + BiPredicate insertionPolicy) + throws IllegalStateException { + header(name, value, false, insertionPolicy); + } + + /** + * Sets up the given header {@code (name, value)} with possibly sensitive + * value. + * + *

    If the {@code value} is sensitive (think security, secrecy, etc.) + * this encoder will compress it using a special representation + * (see + * 6.2.3. Literal Header Field Never Indexed). + * + *

    Fixates {@code name} and {@code value} for the duration of encoding. + * + * @param name + * the name + * @param value + * the value + * @param sensitive + * whether or not the value is sensitive + * @param insertionPolicy + * a bipredicate to indicate whether a name value pair + * should be added to the dynamic table + * + * @throws NullPointerException + * if any of the arguments are {@code null} + * @throws IllegalStateException + * if the encoder hasn't fully encoded the previous header, or + * hasn't yet started to encode it + * @see #header(CharSequence, CharSequence) + * @see DecodingCallback#onDecoded(CharSequence, CharSequence, boolean) + */ + public void header(CharSequence name, + CharSequence value, + boolean sensitive, + BiPredicate insertionPolicy) + throws IllegalStateException { + if (sensitive == true || getMaxCapacity() == 0 || !insertionPolicy.test(name, value)) { + super.header(name, value, sensitive); + return; + } + var logger = logger(); + // Arguably a good balance between complexity of implementation and + // efficiency of encoding + requireNonNull(name, "name"); + requireNonNull(value, "value"); + var t = getHeaderTable(); + int index = tableIndexOf(name, value); + if (logger.isLoggable(NORMAL)) { + logger.log(NORMAL, () -> format("encoding with indexing ('%s', '%s'): index:%s", + name, value, index)); + } + if (index > 0) { + indexed(index); + } else { + boolean huffmanValue = isHuffmanBetterFor(value); + if (index < 0) { + literalWithIndexing(-index, value, huffmanValue); + } else { + boolean huffmanName = isHuffmanBetterFor(name); + literalWithIndexing(name, huffmanName, value, huffmanValue); + } + } + } + + protected int calculateCapacity(int maxCapacity) { + return maxCapacity; + } + +} diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchange.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchange.java index d982349dac500..828c939f53f20 100644 --- a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchange.java +++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchange.java @@ -29,9 +29,12 @@ import java.net.URI; import java.net.InetSocketAddress; import java.net.http.HttpHeaders; +import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.function.BiPredicate; import javax.net.ssl.SSLSession; import jdk.internal.net.http.common.HttpHeadersBuilder; +import jdk.internal.net.http.frame.Http2Frame; public interface Http2TestExchange { @@ -53,6 +56,12 @@ public interface Http2TestExchange { void sendResponseHeaders(int rCode, long responseLength) throws IOException; + default void sendResponseHeaders(int rCode, long responseLength, + BiPredicate insertionPolicy) + throws IOException { + sendResponseHeaders(rCode, responseLength); + } + InetSocketAddress getRemoteAddress(); int getResponseCode(); @@ -65,6 +74,10 @@ public interface Http2TestExchange { void serverPush(URI uri, HttpHeaders headers, InputStream content); + default void sendFrames(List frames) throws IOException { + throw new UnsupportedOperationException("not implemented"); + } + /** * Send a PING on this exchanges connection, and completes the returned CF * with the number of milliseconds it took to get a valid response. diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchangeImpl.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchangeImpl.java index d25019f9094c0..fa7589c023249 100644 --- a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchangeImpl.java +++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchangeImpl.java @@ -27,6 +27,7 @@ import jdk.internal.net.http.common.HttpHeadersBuilder; import jdk.internal.net.http.frame.HeaderFrame; import jdk.internal.net.http.frame.HeadersFrame; +import jdk.internal.net.http.frame.Http2Frame; import jdk.internal.net.http.frame.ResetFrame; import javax.net.ssl.SSLSession; @@ -39,6 +40,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.function.BiPredicate; public class Http2TestExchangeImpl implements Http2TestExchange { @@ -132,8 +134,13 @@ public OutputStream getResponseBody() { return os; } - @Override public void sendResponseHeaders(int rCode, long responseLength) throws IOException { + sendResponseHeaders(rCode, responseLength, (n,v) -> false); + } + @Override + public void sendResponseHeaders(int rCode, long responseLength, + BiPredicate insertionPolicy) + throws IOException { // Do not set Content-Length for 100, and do not set END_STREAM if (rCode == 100) responseLength = 0; @@ -147,7 +154,7 @@ public void sendResponseHeaders(int rCode, long responseLength) throws IOExcepti HttpHeaders headers = rspheadersBuilder.build(); ResponseHeaders response - = new ResponseHeaders(headers); + = new ResponseHeaders(headers, insertionPolicy); response.streamid(streamid); response.setFlag(HeaderFrame.END_HEADERS); @@ -172,6 +179,11 @@ public void sendResponseHeaders(ResponseHeaders response) throws IOException { conn.outputQ.put(response); } + @Override + public void sendFrames(List frames) throws IOException { + conn.sendFrames(frames); + } + @Override public InetSocketAddress getRemoteAddress() { return (InetSocketAddress) conn.socket.getRemoteSocketAddress(); diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestServerConnection.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestServerConnection.java index 1aeeee60b197e..c98e986ca85ab 100644 --- a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestServerConnection.java +++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestServerConnection.java @@ -24,6 +24,8 @@ package jdk.httpclient.test.lib.http2; import jdk.internal.net.http.common.HttpHeadersBuilder; +import jdk.internal.net.http.common.Log; +import jdk.internal.net.http.frame.ContinuationFrame; import jdk.internal.net.http.frame.DataFrame; import jdk.internal.net.http.frame.ErrorFrame; import jdk.internal.net.http.frame.FramesDecoder; @@ -80,6 +82,7 @@ import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.ReentrantLock; import java.util.function.BiPredicate; import java.util.function.Consumer; import java.util.function.Predicate; @@ -87,6 +90,7 @@ import static java.nio.charset.StandardCharsets.ISO_8859_1; import static java.nio.charset.StandardCharsets.UTF_8; import static jdk.internal.net.http.frame.ErrorFrame.REFUSED_STREAM; +import static jdk.internal.net.http.frame.SettingsFrame.DEFAULT_MAX_FRAME_SIZE; import static jdk.internal.net.http.frame.SettingsFrame.HEADER_TABLE_SIZE; /** @@ -105,7 +109,7 @@ public class Http2TestServerConnection { final Http2TestExchangeSupplier exchangeSupplier; final InputStream is; final OutputStream os; - volatile Encoder hpackOut; + volatile HpackTestEncoder hpackOut; volatile Decoder hpackIn; volatile SettingsFrame clientSettings; final SettingsFrame serverSettings; @@ -421,7 +425,9 @@ private SettingsFrame getSettingsFromString(String s) throws IOException { } public int getMaxFrameSize() { - return clientSettings.getParameter(SettingsFrame.MAX_FRAME_SIZE); + var max = clientSettings.getParameter(SettingsFrame.MAX_FRAME_SIZE); + if (max <= 0) max = DEFAULT_MAX_FRAME_SIZE; + return max; } /** Sends a pre-canned HTTP/1.1 response. */ @@ -482,7 +488,7 @@ void run() throws Exception { //System.out.println("ServerSettings: " + serverSettings); //System.out.println("ClientSettings: " + clientSettings); - hpackOut = new Encoder(serverSettings.getParameter(HEADER_TABLE_SIZE)); + hpackOut = new HpackTestEncoder(serverSettings.getParameter(HEADER_TABLE_SIZE)); hpackIn = new Decoder(clientSettings.getParameter(HEADER_TABLE_SIZE)); if (!secure) { @@ -812,6 +818,14 @@ headers, rspheadersBuilder, uri, bis, getSSLSession(), } } + public void sendFrames(List frames) throws IOException { + synchronized (outputQ) { + for (var frame : frames) { + outputQ.put(frame); + } + } + } + protected HttpHeadersBuilder createNewHeadersBuilder() { return new HttpHeadersBuilder(); } @@ -938,26 +952,38 @@ static boolean isServerStreamId(int streamid) { return (streamid & 0x01) == 0x00; } + final ReentrantLock headersLock = new ReentrantLock(); + /** Encodes an group of headers, without any ordering guarantees. */ public List encodeHeaders(HttpHeaders headers) { + return encodeHeaders(headers, (n,v) -> false); + } + + public List encodeHeaders(HttpHeaders headers, + BiPredicate insertionPolicy) { List buffers = new LinkedList<>(); ByteBuffer buf = getBuffer(); boolean encoded; - for (Map.Entry> entry : headers.map().entrySet()) { - List values = entry.getValue(); - String key = entry.getKey().toLowerCase(); - for (String value : values) { - do { - hpackOut.header(key, value); - encoded = hpackOut.encode(buf); - if (!encoded) { - buf.flip(); - buffers.add(buf); - buf = getBuffer(); - } - } while (!encoded); + headersLock.lock(); + try { + for (Map.Entry> entry : headers.map().entrySet()) { + List values = entry.getValue(); + String key = entry.getKey().toLowerCase(); + for (String value : values) { + hpackOut.header(key, value, insertionPolicy); + do { + encoded = hpackOut.encode(buf); + if (!encoded && !buf.hasRemaining()) { + buf.flip(); + buffers.add(buf); + buf = getBuffer(); + } + } while (!encoded); + } } + } finally { + headersLock.unlock(); } buf.flip(); buffers.add(buf); @@ -970,18 +996,23 @@ public List encodeHeadersOrdered(List> head ByteBuffer buf = getBuffer(); boolean encoded; - for (Map.Entry entry : headers) { - String value = entry.getValue(); - String key = entry.getKey().toLowerCase(); - do { + headersLock.lock(); + try { + for (Map.Entry entry : headers) { + String value = entry.getValue(); + String key = entry.getKey().toLowerCase(); hpackOut.header(key, value); - encoded = hpackOut.encode(buf); - if (!encoded) { - buf.flip(); - buffers.add(buf); - buf = getBuffer(); - } - } while (!encoded); + do { + encoded = hpackOut.encode(buf); + if (!encoded && !buf.hasRemaining()) { + buf.flip(); + buffers.add(buf); + buf = getBuffer(); + } + } while (!encoded); + } + } finally { + headersLock.unlock(); } buf.flip(); buffers.add(buf); @@ -1008,10 +1039,50 @@ void writeLoop() { break; } else throw x; } - if (frame instanceof ResponseHeaders) { - ResponseHeaders rh = (ResponseHeaders)frame; - HeadersFrame hf = new HeadersFrame(rh.streamid(), rh.getFlags(), encodeHeaders(rh.headers)); - writeFrame(hf); + if (frame instanceof ResponseHeaders rh) { + var buffers = encodeHeaders(rh.headers, rh.insertionPolicy); + int maxFrameSize = Math.min(rh.getMaxFrameSize(), getMaxFrameSize() - 64); + int next = 0; + int cont = 0; + do { + // If the total size of headers exceeds the max frame + // size we need to split the headers into one + // HeadersFrame + N x ContinuationFrames + int remaining = maxFrameSize; + var list = new ArrayList(buffers.size()); + for (; next < buffers.size(); next++) { + var b = buffers.get(next); + var len = b.remaining(); + if (!b.hasRemaining()) continue; + if (len <= remaining) { + remaining -= len; + list.add(b); + } else { + if (next == 0) { + list.add(b.slice(b.position(), remaining)); + b.position(b.position() + remaining); + remaining = 0; + } + break; + } + } + int flags = rh.getFlags(); + if (next != buffers.size()) { + flags = flags & ~HeadersFrame.END_HEADERS; + } + if (cont > 0) { + flags = flags & ~HeadersFrame.END_STREAM; + } + HeaderFrame hf = cont == 0 + ? new HeadersFrame(rh.streamid(), flags, list) + : new ContinuationFrame(rh.streamid(), flags, list); + if (Log.headers()) { + // avoid too much chatter: log only if Log.headers() is enabled + System.err.println("TestServer writing " + hf); + } + writeFrame(hf); + cont++; + } while (next < buffers.size()); } else if (frame instanceof OutgoingPushPromise) { handlePush((OutgoingPushPromise)frame); } else @@ -1322,11 +1393,29 @@ synchronized void updateConnectionWindow(int amount) { // for the hashmap. public static class ResponseHeaders extends Http2Frame { - HttpHeaders headers; + final HttpHeaders headers; + final BiPredicate insertionPolicy; + + final int maxFrameSize; public ResponseHeaders(HttpHeaders headers) { + this(headers, (n,v) -> false); + } + public ResponseHeaders(HttpHeaders headers, BiPredicate insertionPolicy) { + this(headers, insertionPolicy, Integer.MAX_VALUE); + } + + public ResponseHeaders(HttpHeaders headers, + BiPredicate insertionPolicy, + int maxFrameSize) { super(0, 0); this.headers = headers; + this.insertionPolicy = insertionPolicy; + this.maxFrameSize = maxFrameSize; + } + + public int getMaxFrameSize() { + return maxFrameSize; } } From cfa25b71a65bfff1b31efe0d37ded37c50a98247 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Tue, 21 May 2024 10:31:14 +0000 Subject: [PATCH 067/118] 8328544: Improve handling of vectorization Co-authored-by: Christian Hagedorn Reviewed-by: mschoene, kvn, chagedorn, rhalade --- src/hotspot/share/opto/vectorization.cpp | 472 +++++++++++++++++- src/hotspot/share/opto/vectorization.hpp | 89 +++- .../TestVectorizationMismatchedAccess.java | 335 +++++++++++-- .../loopopts/superword/TestAlignVector.java | 8 +- .../superword/TestAlignVectorFuzzer.java | 20 +- ...tIndependentPacksWithCyclicDependency.java | 140 +++--- ...IndependentPacksWithCyclicDependency2.java | 28 +- .../TestScheduleReordersScalarMemops.java | 8 +- 8 files changed, 935 insertions(+), 165 deletions(-) diff --git a/src/hotspot/share/opto/vectorization.cpp b/src/hotspot/share/opto/vectorization.cpp index 8d2d3868fe635..f013abb38fb4a 100644 --- a/src/hotspot/share/opto/vectorization.cpp +++ b/src/hotspot/share/opto/vectorization.cpp @@ -416,6 +416,10 @@ VPointer::VPointer(MemNode* const mem, const VLoop& vloop, #ifdef ASSERT _debug_invar(nullptr), _debug_negate_invar(false), _debug_invar_scale(nullptr), #endif + _has_int_index_after_convI2L(false), + _int_index_after_convI2L_offset(0), + _int_index_after_convI2L_invar(nullptr), + _int_index_after_convI2L_scale(0), _nstack(nstack), _analyze_only(analyze_only), _stack_idx(0) #ifndef PRODUCT , _tracer(vloop.is_trace_pointer_analysis()) @@ -495,6 +499,11 @@ VPointer::VPointer(MemNode* const mem, const VLoop& vloop, return; } + if (!is_safe_to_use_as_simple_form(base, adr)) { + assert(!valid(), "does not have simple form"); + return; + } + _base = base; _adr = adr; assert(valid(), "Usable"); @@ -508,6 +517,10 @@ VPointer::VPointer(VPointer* p) : #ifdef ASSERT _debug_invar(nullptr), _debug_negate_invar(false), _debug_invar_scale(nullptr), #endif + _has_int_index_after_convI2L(false), + _int_index_after_convI2L_offset(0), + _int_index_after_convI2L_invar(nullptr), + _int_index_after_convI2L_scale(0), _nstack(p->_nstack), _analyze_only(p->_analyze_only), _stack_idx(p->_stack_idx) #ifndef PRODUCT , _tracer(p->_tracer._is_trace_alignment) @@ -530,6 +543,354 @@ int VPointer::invar_factor() const { return 1; } +// We would like to make decisions about aliasing (i.e. removing memory edges) and adjacency +// (i.e. which loads/stores can be packed) based on the simple form: +// +// s_pointer = adr + offset + invar + scale * ConvI2L(iv) +// +// However, we parse the compound-long-int form: +// +// c_pointer = adr + long_offset + long_invar + long_scale * ConvI2L(int_index) +// int_index = int_offset + int_invar + int_scale * iv +// +// In general, the simple and the compound-long-int form do not always compute the same pointer +// at runtime. For example, the simple form would give a different result due to an overflow +// in the int_index. +// +// Example: +// For both forms, we have: +// iv = 0 +// scale = 1 +// +// We now account the offset and invar once to the long part and once to the int part: +// Pointer 1 (long offset and long invar): +// long_offset = min_int +// long_invar = min_int +// int_offset = 0 +// int_invar = 0 +// +// Pointer 2 (int offset and int invar): +// long_offset = 0 +// long_invar = 0 +// int_offset = min_int +// int_invar = min_int +// +// This gives us the following pointers: +// Compound-long-int form pointers: +// Form: +// c_pointer = adr + long_offset + long_invar + long_scale * ConvI2L(int_offset + int_invar + int_scale * iv) +// +// Pointers: +// c_pointer1 = adr + min_int + min_int + 1 * ConvI2L(0 + 0 + 1 * 0) +// = adr + min_int + min_int +// = adr - 2^32 +// +// c_pointer2 = adr + 0 + 0 + 1 * ConvI2L(min_int + min_int + 1 * 0) +// = adr + ConvI2L(min_int + min_int) +// = adr + 0 +// = adr +// +// Simple form pointers: +// Form: +// s_pointer = adr + offset + invar + scale * ConvI2L(iv) +// s_pointer = adr + (long_offset + int_offset) + (long_invar + int_invar) + (long_scale * int_scale) * ConvI2L(iv) +// +// Pointers: +// s_pointer1 = adr + (min_int + 0 ) + (min_int + 0 ) + 1 * 0 +// = adr + min_int + min_int +// = adr - 2^32 +// s_pointer2 = adr + (0 + min_int ) + (0 + min_int ) + 1 * 0 +// = adr + min_int + min_int +// = adr - 2^32 +// +// We see that the two addresses are actually 2^32 bytes apart (derived from the c_pointers), but their simple form look identical. +// +// Hence, we need to determine in which cases it is safe to make decisions based on the simple +// form, rather than the compound-long-int form. If we cannot prove that using the simple form +// is safe (i.e. equivalent to the compound-long-int form), then we do not get a valid VPointer, +// and the associated memop cannot be vectorized. +bool VPointer::is_safe_to_use_as_simple_form(Node* base, Node* adr) const { +#ifndef _LP64 + // On 32-bit platforms, there is never an explicit int_index with ConvI2L for the iv. Thus, the + // parsed pointer form is always the simple form, with int operations: + // + // pointer = adr + offset + invar + scale * iv + // + assert(!_has_int_index_after_convI2L, "32-bit never has an int_index with ConvI2L for the iv"); + return true; +#else + + // Array accesses that are not Unsafe always have a RangeCheck which ensures that there is no + // int_index overflow. This implies that the conversion to long can be done separately: + // + // ConvI2L(int_index) = ConvI2L(int_offset) + ConvI2L(int_invar) + ConvI2L(scale) * ConvI2L(iv) + // + // And hence, the simple form is guaranteed to be identical to the compound-long-int form at + // runtime and the VPointer is safe/valid to be used. + const TypeAryPtr* ary_ptr_t = _mem->adr_type()->isa_aryptr(); + if (ary_ptr_t != nullptr) { + if (!_mem->is_unsafe_access()) { + return true; + } + } + + // We did not find the int_index. Just to be safe, reject this VPointer. + if (!_has_int_index_after_convI2L) { + return false; + } + + int int_offset = _int_index_after_convI2L_offset; + Node* int_invar = _int_index_after_convI2L_invar; + int int_scale = _int_index_after_convI2L_scale; + int long_scale = _scale / int_scale; + + // If "int_index = iv", then the simple form is identical to the compound-long-int form. + // + // int_index = int_offset + int_invar + int_scale * iv + // = 0 0 1 * iv + // = iv + if (int_offset == 0 && int_invar == nullptr && int_scale == 1) { + return true; + } + + // Intuition: What happens if the int_index overflows? Let us look at two pointers on the "overflow edge": + // + // pointer1 = adr + ConvI2L(int_index1) + // pointer2 = adr + ConvI2L(int_index2) + // + // int_index1 = max_int + 0 = max_int -> very close to but before the overflow + // int_index2 = max_int + 1 = min_int -> just enough to get the overflow + // + // When looking at the difference of pointer1 and pointer2, we notice that it is very large + // (almost 2^32). Since arrays have at most 2^31 elements, chances are high that pointer2 is + // an actual out-of-bounds access at runtime. These would normally be prevented by range checks + // at runtime. However, if the access was done by using Unsafe, where range checks are omitted, + // then an out-of-bounds access constitutes undefined behavior. This means that we are allowed to + // do anything, including changing the behavior. + // + // If we can set the right conditions, we have a guarantee that an overflow is either impossible + // (no overflow or range checks preventing that) or undefined behavior. In both cases, we are + // safe to do a vectorization. + // + // Approach: We want to prove a lower bound for the distance between these two pointers, and an + // upper bound for the size of a memory object. We can derive such an upper bound for + // arrays. We know they have at most 2^31 elements. If we know the size of the elements + // in bytes, we have: + // + // array_element_size_in_bytes * 2^31 >= max_possible_array_size_in_bytes + // >= array_size_in_bytes (ARR) + // + // If some small difference "delta" leads to an int_index overflow, we know that the + // int_index1 before overflow must have been close to max_int, and the int_index2 after + // the overflow must be close to min_int: + // + // pointer1 = adr + long_offset + long_invar + long_scale * ConvI2L(int_index1) + // =approx adr + long_offset + long_invar + long_scale * max_int + // + // pointer2 = adr + long_offset + long_invar + long_scale * ConvI2L(int_index2) + // =approx adr + long_offset + long_invar + long_scale * min_int + // + // We realize that the pointer difference is very large: + // + // difference =approx long_scale * 2^32 + // + // Hence, if we set the right condition for long_scale and array_element_size_in_bytes, + // we can prove that an overflow is impossible (or would imply undefined behaviour). + // + // We must now take this intuition, and develop a rigorous proof. We start by stating the problem + // more precisely, with the help of some definitions and the Statement we are going to prove. + // + // Definition: + // Two VPointers are "comparable" (i.e. VPointer::comparable is true, set with VPointer::cmp()), + // iff all of these conditions apply for the simple form: + // 1) Both VPointers are valid. + // 2) The adr are identical, or both are array bases of different arrays. + // 3) They have identical scale. + // 4) They have identical invar. + // 5) The difference in offsets is limited: abs(offset1 - offset2) < 2^31. (DIFF) + // + // For the Vectorization Optimization, we pair-wise compare VPointers and determine if they are: + // 1) "not comparable": + // We do not optimize them (assume they alias, not assume adjacency). + // + // Whenever we chose this option based on the simple form, it is also correct based on the + // compound-long-int form, since we make no optimizations based on it. + // + // 2) "comparable" with different array bases at runtime: + // We assume they do not alias (remove memory edges), but not assume adjacency. + // + // Whenever we have two different array bases for the simple form, we also have different + // array bases for the compound-long-form. Since VPointers provably point to different + // memory objects, they can never alias. + // + // 3) "comparable" with the same base address: + // We compute the relative pointer difference, and based on the load/store size we can + // compute aliasing and adjacency. + // + // We must find a condition under which the pointer difference of the simple form is + // identical to the pointer difference of the compound-long-form. We do this with the + // Statement below, which we then proceed to prove. + // + // Statement: + // If two VPointers satisfy these 3 conditions: + // 1) They are "comparable". + // 2) They have the same base address. + // 3) Their long_scale is a multiple of the array element size in bytes: + // + // abs(long_scale) % array_element_size_in_bytes = 0 (A) + // + // Then their pointer difference of the simple form is identical to the pointer difference + // of the compound-long-int form. + // + // More precisely: + // Such two VPointers by definition have identical adr, invar, and scale. + // Their simple form is: + // + // s_pointer1 = adr + offset1 + invar + scale * ConvI2L(iv) (B1) + // s_pointer2 = adr + offset2 + invar + scale * ConvI2L(iv) (B2) + // + // Thus, the pointer difference of the simple forms collapses to the difference in offsets: + // + // s_difference = s_pointer1 - s_pointer2 = offset1 - offset2 (C) + // + // Their compound-long-int form for these VPointer is: + // + // c_pointer1 = adr + long_offset1 + long_invar1 + long_scale1 * ConvI2L(int_index1) (D1) + // int_index1 = int_offset1 + int_invar1 + int_scale1 * iv (D2) + // + // c_pointer2 = adr + long_offset2 + long_invar2 + long_scale2 * ConvI2L(int_index2) (D3) + // int_index2 = int_offset2 + int_invar2 + int_scale2 * iv (D4) + // + // And these are the offset1, offset2, invar and scale from the simple form (B1) and (B2): + // + // offset1 = long_offset1 + long_scale1 * ConvI2L(int_offset1) (D5) + // offset2 = long_offset2 + long_scale2 * ConvI2L(int_offset2) (D6) + // + // invar = long_invar1 + long_scale1 * ConvI2L(int_invar1) + // = long_invar2 + long_scale2 * ConvI2L(int_invar2) (D7) + // + // scale = long_scale1 * ConvI2L(int_scale1) + // = long_scale2 * ConvI2L(int_scale2) (D8) + // + // The pointer difference of the compound-long-int form is defined as: + // + // c_difference = c_pointer1 - c_pointer2 + // + // Thus, the statement claims that for the two VPointer we have: + // + // s_difference = c_difference (Statement) + // + // We prove the Statement with the help of a Lemma: + // + // Lemma: + // There is some integer x, such that: + // + // c_difference = s_difference + array_element_size_in_bytes * x * 2^32 (Lemma) + // + // From condition (DIFF), we can derive: + // + // abs(s_difference) < 2^31 (E) + // + // Assuming the Lemma, we prove the Statement: + // If "x = 0" (intuitively: the int_index does not overflow), then: + // c_difference = s_difference + // and hence the simple form computes the same pointer difference as the compound-long-int form. + // If "x != 0" (intuitively: the int_index overflows), then: + // abs(c_difference) >= abs(s_difference + array_element_size_in_bytes * x * 2^32) + // >= array_element_size_in_bytes * 2^32 - abs(s_difference) + // -- apply (E) -- + // > array_element_size_in_bytes * 2^32 - 2^31 + // >= array_element_size_in_bytes * 2^31 + // -- apply (ARR) -- + // >= max_possible_array_size_in_bytes + // >= array_size_in_bytes + // + // This shows that c_pointer1 and c_pointer2 have a distance that exceeds the maximum array size. + // Thus, at least one of the two pointers must be outside of the array bounds. But we can assume + // that out-of-bounds accesses do not happen. If they still do, it is undefined behavior. Hence, + // we are allowed to do anything. We can also "safely" use the simple form in this case even though + // it might not match the compound-long-int form at runtime. + // QED Statement. + // + // We must now prove the Lemma. + // + // ConvI2L always truncates by some power of 2^32, i.e. there is some integer y such that: + // + // ConvI2L(y1 + y2) = ConvI2L(y1) + ConvI2L(y2) + 2^32 * y (F) + // + // It follows, that there is an integer y1 such that: + // + // ConvI2L(int_index1) = ConvI2L(int_offset1 + int_invar1 + int_scale1 * iv) + // -- apply (F) -- + // = ConvI2L(int_offset1) + // + ConvI2L(int_invar1) + // + ConvI2L(int_scale1) * ConvI2L(iv) + // + y1 * 2^32 (G) + // + // Thus, we can write the compound-long-int form (D1) as: + // + // c_pointer1 = adr + long_offset1 + long_invar1 + long_scale1 * ConvI2L(int_index1) + // -- apply (G) -- + // = adr + // + long_offset1 + // + long_invar1 + // + long_scale1 * ConvI2L(int_offset1) + // + long_scale1 * ConvI2L(int_invar1) + // + long_scale1 * ConvI2L(int_scale1) * ConvI2L(iv) + // + long_scale1 * y1 * 2^32 (H) + // + // And we can write the simple form as: + // + // s_pointer1 = adr + offset1 + invar + scale * ConvI2L(iv) + // -- apply (D5, D7, D8) -- + // = adr + // + long_offset1 + // + long_scale1 * ConvI2L(int_offset1) + // + long_invar1 + // + long_scale1 * ConvI2L(int_invar1) + // + long_scale1 * ConvI2L(int_scale1) * ConvI2L(iv) (K) + // + // We now compute the pointer difference between the simple (K) and compound-long-int form (H). + // Most terms cancel out immediately: + // + // sc_difference1 = c_pointer1 - s_pointer1 = long_scale1 * y1 * 2^32 (L) + // + // Rearranging the equation (L), we get: + // + // c_pointer1 = s_pointer1 + long_scale1 * y1 * 2^32 (M) + // + // And since long_scale1 is a multiple of array_element_size_in_bytes, there is some integer + // x1, such that (M) implies: + // + // c_pointer1 = s_pointer1 + array_element_size_in_bytes * x1 * 2^32 (N) + // + // With an analogue equation for c_pointer2, we can now compute the pointer difference for + // the compound-long-int form: + // + // c_difference = c_pointer1 - c_pointer2 + // -- apply (N) -- + // = s_pointer1 + array_element_size_in_bytes * x1 * 2^32 + // -(s_pointer2 + array_element_size_in_bytes * x2 * 2^32) + // -- where "x = x1 - x2" -- + // = s_pointer1 - s_pointer2 + array_element_size_in_bytes * x * 2^32 + // -- apply (C) -- + // = s_difference + array_element_size_in_bytes * x * 2^32 + // QED Lemma. + if (ary_ptr_t != nullptr) { + BasicType array_element_bt = ary_ptr_t->elem()->array_element_basic_type(); + if (is_java_primitive(array_element_bt)) { + int array_element_size_in_bytes = type2aelembytes(array_element_bt); + if (abs(long_scale) % array_element_size_in_bytes == 0) { + return true; + } + } + } + + // General case: we do not know if it is safe to use the simple form. + return false; +#endif +} + bool VPointer::is_loop_member(Node* n) const { Node* n_c = phase()->get_ctrl(n); return lpt()->is_member(phase()->get_loop(n_c)); @@ -632,6 +993,37 @@ bool VPointer::scaled_iv(Node* n) { NOT_PRODUCT(_tracer.scaled_iv_6(n, _scale);) return true; } + } else if (opc == Op_ConvI2L && !has_iv()) { + // So far we have not found the iv yet, and are about to enter a ConvI2L subgraph, + // which may be the int index (that might overflow) for the memory access, of the form: + // + // int_index = int_offset + int_invar + int_scale * iv + // + // If we simply continue parsing with the current VPointer, then the int_offset and + // int_invar simply get added to the long offset and invar. But for the checks in + // VPointer::is_safe_to_use_as_simple_form() we need to have explicit access to the + // int_index. Thus, we must parse it explicitly here. For this, we use a temporary + // VPointer, to pattern match the int_index sub-expression of the address. + + NOT_PRODUCT(Tracer::Depth dddd;) + VPointer tmp(this); + NOT_PRODUCT(_tracer.scaled_iv_8(n, &tmp);) + + if (tmp.scaled_iv_plus_offset(n->in(1)) && tmp.has_iv()) { + // We successfully matched an integer index, of the form: + // int_index = int_offset + int_invar + int_scale * iv + _has_int_index_after_convI2L = true; + _int_index_after_convI2L_offset = tmp._offset; + _int_index_after_convI2L_invar = tmp._invar; + _int_index_after_convI2L_scale = tmp._scale; + } + + // Now parse it again for the real VPointer. This makes sure that the int_offset, int_invar, + // and int_scale are properly added to the final VPointer's offset, invar, and scale. + if (scaled_iv_plus_offset(n->in(1))) { + NOT_PRODUCT(_tracer.scaled_iv_7(n);) + return true; + } } else if (opc == Op_ConvI2L || opc == Op_CastII) { if (scaled_iv_plus_offset(n->in(1))) { NOT_PRODUCT(_tracer.scaled_iv_7(n);) @@ -648,8 +1040,17 @@ bool VPointer::scaled_iv(Node* n) { if (tmp.scaled_iv_plus_offset(n->in(1))) { int scale = n->in(2)->get_int(); + // Accumulate scale. _scale = tmp._scale << scale; - _offset += tmp._offset << scale; + // Accumulate offset. + int shifted_offset = 0; + if (!try_LShiftI_no_overflow(tmp._offset, scale, shifted_offset)) { + return false; // shift overflow. + } + if (!try_AddI_no_overflow(_offset, shifted_offset, _offset)) { + return false; // add overflow. + } + // Accumulate invar. if (tmp._invar != nullptr) { BasicType bt = tmp._invar->bottom_type()->basic_type(); assert(bt == T_INT || bt == T_LONG, ""); @@ -658,6 +1059,13 @@ bool VPointer::scaled_iv(Node* n) { _debug_invar_scale = n->in(2); #endif } + + // Forward info about the int_index: + _has_int_index_after_convI2L = tmp._has_int_index_after_convI2L; + _int_index_after_convI2L_offset = tmp._int_index_after_convI2L_offset; + _int_index_after_convI2L_invar = tmp._int_index_after_convI2L_invar; + _int_index_after_convI2L_scale = tmp._int_index_after_convI2L_scale; + NOT_PRODUCT(_tracer.scaled_iv_9(n, _scale, _offset, _invar);) return true; } @@ -675,7 +1083,9 @@ bool VPointer::offset_plus_k(Node* n, bool negate) { int opc = n->Opcode(); if (opc == Op_ConI) { - _offset += negate ? -(n->get_int()) : n->get_int(); + if (!try_AddSubI_no_overflow(_offset, n->get_int(), negate, _offset)) { + return false; // add/sub overflow. + } NOT_PRODUCT(_tracer.offset_plus_k_2(n, _offset);) return true; } else if (opc == Op_ConL) { @@ -684,7 +1094,9 @@ bool VPointer::offset_plus_k(Node* n, bool negate) { if (t->higher_equal(TypeLong::INT)) { jlong loff = n->get_long(); jint off = (jint)loff; - _offset += negate ? -off : loff; + if (!try_AddSubI_no_overflow(_offset, off, negate, _offset)) { + return false; // add/sub overflow. + } NOT_PRODUCT(_tracer.offset_plus_k_3(n, _offset);) return true; } @@ -699,11 +1111,15 @@ bool VPointer::offset_plus_k(Node* n, bool negate) { if (opc == Op_AddI) { if (n->in(2)->is_Con() && invariant(n->in(1))) { maybe_add_to_invar(n->in(1), negate); - _offset += negate ? -(n->in(2)->get_int()) : n->in(2)->get_int(); + if (!try_AddSubI_no_overflow(_offset, n->in(2)->get_int(), negate, _offset)) { + return false; // add/sub overflow. + } NOT_PRODUCT(_tracer.offset_plus_k_6(n, _invar, negate, _offset);) return true; } else if (n->in(1)->is_Con() && invariant(n->in(2))) { - _offset += negate ? -(n->in(1)->get_int()) : n->in(1)->get_int(); + if (!try_AddSubI_no_overflow(_offset, n->in(1)->get_int(), negate, _offset)) { + return false; // add/sub overflow. + } maybe_add_to_invar(n->in(2), negate); NOT_PRODUCT(_tracer.offset_plus_k_7(n, _invar, negate, _offset);) return true; @@ -712,11 +1128,15 @@ bool VPointer::offset_plus_k(Node* n, bool negate) { if (opc == Op_SubI) { if (n->in(2)->is_Con() && invariant(n->in(1))) { maybe_add_to_invar(n->in(1), negate); - _offset += !negate ? -(n->in(2)->get_int()) : n->in(2)->get_int(); + if (!try_AddSubI_no_overflow(_offset, n->in(2)->get_int(), !negate, _offset)) { + return false; // add/sub overflow. + } NOT_PRODUCT(_tracer.offset_plus_k_8(n, _invar, negate, _offset);) return true; } else if (n->in(1)->is_Con() && invariant(n->in(2))) { - _offset += negate ? -(n->in(1)->get_int()) : n->in(1)->get_int(); + if (!try_AddSubI_no_overflow(_offset, n->in(1)->get_int(), negate, _offset)) { + return false; // add/sub overflow. + } maybe_add_to_invar(n->in(2), !negate); NOT_PRODUCT(_tracer.offset_plus_k_9(n, _invar, !negate, _offset);) return true; @@ -806,6 +1226,44 @@ void VPointer::maybe_add_to_invar(Node* new_invar, bool negate) { _invar = register_if_new(add); } +bool VPointer::try_AddI_no_overflow(int offset1, int offset2, int& result) { + jlong long_offset = java_add((jlong)(offset1), (jlong)(offset2)); + jint int_offset = java_add( offset1, offset2); + if (long_offset != int_offset) { + return false; + } + result = int_offset; + return true; +} + +bool VPointer::try_SubI_no_overflow(int offset1, int offset2, int& result) { + jlong long_offset = java_subtract((jlong)(offset1), (jlong)(offset2)); + jint int_offset = java_subtract( offset1, offset2); + if (long_offset != int_offset) { + return false; + } + result = int_offset; + return true; +} + +bool VPointer::try_AddSubI_no_overflow(int offset1, int offset2, bool is_sub, int& result) { + if (is_sub) { + return try_SubI_no_overflow(offset1, offset2, result); + } else { + return try_AddI_no_overflow(offset1, offset2, result); + } +} + +bool VPointer::try_LShiftI_no_overflow(int offset, int shift, int& result) { + jlong long_offset = java_shift_left((jlong)(offset), shift); + jint int_offset = java_shift_left( offset, shift); + if (long_offset != int_offset) { + return false; + } + result = int_offset; + return true; +} + // We use two comparisons, because a subtraction could underflow. #define RETURN_CMP_VALUE_IF_NOT_EQUAL(a, b) \ if (a < b) { return -1; } \ diff --git a/src/hotspot/share/opto/vectorization.hpp b/src/hotspot/share/opto/vectorization.hpp index 3984407c5654b..7de29444e5f8f 100644 --- a/src/hotspot/share/opto/vectorization.hpp +++ b/src/hotspot/share/opto/vectorization.hpp @@ -670,13 +670,51 @@ class VLoopAnalyzer : StackObj { // A vectorization pointer (VPointer) has information about an address for // dependence checking and vector alignment. It's usually bound to a memory // operation in a counted loop for vectorizable analysis. +// +// We parse and represent pointers of the simple form: +// +// pointer = adr + offset + invar + scale * ConvI2L(iv) +// +// Where: +// +// adr: the base address of an array (base = adr) +// OR +// some address to off-heap memory (base = TOP) +// +// offset: a constant offset +// invar: a runtime variable, which is invariant during the loop +// scale: scaling factor +// iv: loop induction variable +// +// But more precisely, we parse the composite-long-int form: +// +// pointer = adr + long_offset + long_invar + long_scale * ConvI2L(int_offset + inv_invar + int_scale * iv) +// +// pointer = adr + long_offset + long_invar + long_scale * ConvI2L(int_index) +// int_index = int_offset + int_invar + int_scale * iv +// +// However, for aliasing and adjacency checks (e.g. VPointer::cmp()) we always use the simple form to make +// decisions. Hence, we must make sure to only create a "valid" VPointer if the optimisations based on the +// simple form produce the same result as the compound-long-int form would. Intuitively, this depends on +// if the int_index overflows, but the precise conditions are given in VPointer::is_safe_to_use_as_simple_form(). +// +// ConvI2L(int_index) = ConvI2L(int_offset + int_invar + int_scale * iv) +// = Convi2L(int_offset) + ConvI2L(int_invar) + ConvI2L(int_scale) * ConvI2L(iv) +// +// scale = long_scale * ConvI2L(int_scale) +// offset = long_offset + long_scale * ConvI2L(int_offset) +// invar = long_invar + long_scale * ConvI2L(int_invar) +// +// pointer = adr + offset + invar + scale * ConvI2L(iv) +// class VPointer : public ArenaObj { protected: MemNode* const _mem; // My memory reference node const VLoop& _vloop; - Node* _base; // null if unsafe nonheap reference - Node* _adr; // address pointer + // Components of the simple form: + Node* _base; // Base address of an array OR null if some off-heap memory. + Node* _adr; // Same as _base if an array pointer OR some off-heap memory pointer. int _scale; // multiplier for iv (in bytes), 0 if no loop iv int _offset; // constant offset (in bytes) @@ -687,6 +725,13 @@ class VPointer : public ArenaObj { Node* _debug_invar_scale; // multiplier for invariant #endif + // The int_index components of the compound-long-int form. Used to decide if it is safe to use the + // simple form rather than the compound-long-int form that was parsed. + bool _has_int_index_after_convI2L; + int _int_index_after_convI2L_offset; + Node* _int_index_after_convI2L_invar; + int _int_index_after_convI2L_scale; + Node_Stack* _nstack; // stack used to record a vpointer trace of variants bool _analyze_only; // Used in loop unrolling only for vpointer trace uint _stack_idx; // Used in loop unrolling only for vpointer trace @@ -726,6 +771,8 @@ class VPointer : public ArenaObj { VPointer(VPointer* p); NONCOPYABLE(VPointer); + bool is_safe_to_use_as_simple_form(Node* base, Node* adr) const; + public: bool valid() const { return _adr != nullptr; } bool has_iv() const { return _scale != 0; } @@ -751,10 +798,43 @@ class VPointer : public ArenaObj { return _invar == q._invar; } + // We compute if and how two VPointers can alias at runtime, i.e. if the two addressed regions of memory can + // ever overlap. There are essentially 3 relevant return states: + // - NotComparable: Synonymous to "unknown aliasing". + // We have no information about how the two VPointers can alias. They could overlap, refer + // to another location in the same memory object, or point to a completely different object. + // -> Memory edge required. Aliasing unlikely but possible. + // + // - Less / Greater: Synonymous to "never aliasing". + // The two VPointers may point into the same memory object, but be non-aliasing (i.e. we + // know both address regions inside the same memory object, but these regions are non- + // overlapping), or the VPointers point to entirely different objects. + // -> No memory edge required. Aliasing impossible. + // + // - Equal: Synonymous to "overlap, or point to different memory objects". + // The two VPointers either overlap on the same memory object, or point to two different + // memory objects. + // -> Memory edge required. Aliasing likely. + // + // In a future refactoring, we can simplify to two states: + // - NeverAlias: instead of Less / Greater + // - MayAlias: instead of Equal / NotComparable + // + // Two VPointer are "comparable" (Less / Greater / Equal), iff all of these conditions apply: + // 1) Both are valid, i.e. expressible in the compound-long-int or simple form. + // 2) The adr are identical, or both are array bases of different arrays. + // 3) They have identical scale. + // 4) They have identical invar. + // 5) The difference in offsets is limited: abs(offset0 - offset1) < 2^31. int cmp(const VPointer& q) const { if (valid() && q.valid() && (_adr == q._adr || (_base == _adr && q._base == q._adr)) && _scale == q._scale && invar_equals(q)) { + jlong difference = abs(java_subtract((jlong)_offset, (jlong)q._offset)); + jlong max_diff = (jlong)1 << 31; + if (difference >= max_diff) { + return NotComparable; + } bool overlap = q._offset < _offset + memory_size() && _offset < q._offset + q.memory_size(); return overlap ? Equal : (_offset < q._offset ? Less : Greater); @@ -859,6 +939,11 @@ class VPointer : public ArenaObj { void maybe_add_to_invar(Node* new_invar, bool negate); + static bool try_AddI_no_overflow(int offset1, int offset2, int& result); + static bool try_SubI_no_overflow(int offset1, int offset2, int& result); + static bool try_AddSubI_no_overflow(int offset1, int offset2, bool is_sub, int& result); + static bool try_LShiftI_no_overflow(int offset1, int offset2, int& result); + Node* register_if_new(Node* n) const; }; diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMismatchedAccess.java b/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMismatchedAccess.java index b68ddfe2799ce..2fdbb0816ade8 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMismatchedAccess.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMismatchedAccess.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2023, Red Hat, Inc. All rights reserved. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * 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 +36,6 @@ * @test * @bug 8300258 * @key randomness - * @requires (os.simpleArch == "x64") | (os.simpleArch == "aarch64") * @summary C2: vectorization fails on simple ByteBuffer loop * @modules java.base/jdk.internal.misc * @library /test/lib / @@ -147,193 +147,420 @@ static private void runAndVerify3(Runnable test, int offset) { } @Test - @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) - public static void testByteLong1(byte[] dest, long[] src) { + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}) + // 32-bit: offsets are badly aligned (UNSAFE.ARRAY_BYTE_BASE_OFFSET is 4 byte aligned, but not 8 byte aligned). + // might get fixed with JDK-8325155. + public static void testByteLong1a(byte[] dest, long[] src) { for (int i = 0; i < src.length; i++) { UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * i, src[i]); } } - @Run(test = "testByteLong1") + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}) + // 32-bit: address has ConvL2I for cast of long to address, not supported. + public static void testByteLong1b(byte[] dest, long[] src) { + for (int i = 0; i < src.length; i++) { + UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * i, src[i]); + } + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + public static void testByteLong1c(byte[] dest, long[] src) { + long base = 64; // make sure it is big enough and 8 byte aligned (required for 32-bit) + for (int i = 0; i < src.length - 8; i++) { + UNSAFE.putLongUnaligned(dest, base + 8 * i, src[i]); + } + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}) + // 32-bit: address has ConvL2I for cast of long to address, not supported. + public static void testByteLong1d(byte[] dest, long[] src) { + long base = 64; // make sure it is big enough and 8 byte aligned (required for 32-bit) + for (int i = 0; i < src.length - 8; i++) { + UNSAFE.putLongUnaligned(dest, base + 8L * i, src[i]); + } + } + + @Run(test = {"testByteLong1a", "testByteLong1b", "testByteLong1c", "testByteLong1d"}) public static void testByteLong1_runner() { - runAndVerify(() -> testByteLong1(byteArray, longArray), 0); + runAndVerify(() -> testByteLong1a(byteArray, longArray), 0); + runAndVerify(() -> testByteLong1b(byteArray, longArray), 0); + testByteLong1c(byteArray, longArray); + testByteLong1d(byteArray, longArray); } @Test - @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) - public static void testByteLong2(byte[] dest, long[] src) { + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}) + // 32-bit: offsets are badly aligned (UNSAFE.ARRAY_BYTE_BASE_OFFSET is 4 byte aligned, but not 8 byte aligned). + // might get fixed with JDK-8325155. + public static void testByteLong2a(byte[] dest, long[] src) { for (int i = 1; i < src.length; i++) { UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * (i - 1), src[i]); } } - @Run(test = "testByteLong2") + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}) + // 32-bit: address has ConvL2I for cast of long to address, not supported. + public static void testByteLong2b(byte[] dest, long[] src) { + for (int i = 1; i < src.length; i++) { + UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * (i - 1), src[i]); + } + } + + @Run(test = {"testByteLong2a", "testByteLong2b"}) public static void testByteLong2_runner() { - runAndVerify(() -> testByteLong2(byteArray, longArray), -8); + runAndVerify(() -> testByteLong2a(byteArray, longArray), -8); + runAndVerify(() -> testByteLong2b(byteArray, longArray), -8); } @Test - @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) - public static void testByteLong3(byte[] dest, long[] src) { + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}) + // 32-bit: offsets are badly aligned (UNSAFE.ARRAY_BYTE_BASE_OFFSET is 4 byte aligned, but not 8 byte aligned). + // might get fixed with JDK-8325155. + public static void testByteLong3a(byte[] dest, long[] src) { for (int i = 0; i < src.length - 1; i++) { UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * (i + 1), src[i]); } } - @Run(test = "testByteLong3") + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}) + // 32-bit: address has ConvL2I for cast of long to address, not supported. + public static void testByteLong3b(byte[] dest, long[] src) { + for (int i = 0; i < src.length - 1; i++) { + UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * (i + 1), src[i]); + } + } + + @Run(test = {"testByteLong3a", "testByteLong3b"}) public static void testByteLong3_runner() { - runAndVerify(() -> testByteLong3(byteArray, longArray), 8); + runAndVerify(() -> testByteLong3a(byteArray, longArray), 8); + runAndVerify(() -> testByteLong3b(byteArray, longArray), 8); } @Test @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, applyIf = {"AlignVector", "false"}) + // 32-bit: offsets are badly aligned (UNSAFE.ARRAY_BYTE_BASE_OFFSET is 4 byte aligned, but not 8 byte aligned). + // might get fixed with JDK-8325155. // AlignVector cannot guarantee that invar is aligned. - public static void testByteLong4(byte[] dest, long[] src, int start, int stop) { + public static void testByteLong4a(byte[] dest, long[] src, int start, int stop) { for (int i = start; i < stop; i++) { UNSAFE.putLongUnaligned(dest, 8 * i + baseOffset, src[i]); } } - @Run(test = "testByteLong4") + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "false"}) + // 32-bit: address has ConvL2I for cast of long to address, not supported. + // AlignVector cannot guarantee that invar is aligned. + public static void testByteLong4b(byte[] dest, long[] src, int start, int stop) { + for (int i = start; i < stop; i++) { + UNSAFE.putLongUnaligned(dest, 8L * i + baseOffset, src[i]); + } + } + + @Run(test = {"testByteLong4a", "testByteLong4b"}) public static void testByteLong4_runner() { baseOffset = UNSAFE.ARRAY_BYTE_BASE_OFFSET; - runAndVerify(() -> testByteLong4(byteArray, longArray, 0, size), 0); + runAndVerify(() -> testByteLong4a(byteArray, longArray, 0, size), 0); + runAndVerify(() -> testByteLong4b(byteArray, longArray, 0, size), 0); } @Test - @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) - public static void testByteLong5(byte[] dest, long[] src, int start, int stop) { + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}) + // 32-bit: offsets are badly aligned (UNSAFE.ARRAY_BYTE_BASE_OFFSET is 4 byte aligned, but not 8 byte aligned). + // might get fixed with JDK-8325155. + public static void testByteLong5a(byte[] dest, long[] src, int start, int stop) { for (int i = start; i < stop; i++) { UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * (i + baseOffset), src[i]); } } - @Run(test = "testByteLong5") + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}) + // 32-bit: address has ConvL2I for cast of long to address, not supported. + public static void testByteLong5b(byte[] dest, long[] src, int start, int stop) { + for (int i = start; i < stop; i++) { + UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * (i + baseOffset), src[i]); + } + } + + @Run(test = {"testByteLong5a", "testByteLong5b"}) public static void testByteLong5_runner() { baseOffset = 1; - runAndVerify(() -> testByteLong5(byteArray, longArray, 0, size-1), 8); + runAndVerify(() -> testByteLong5a(byteArray, longArray, 0, size-1), 8); + runAndVerify(() -> testByteLong5b(byteArray, longArray, 0, size-1), 8); } @Test - @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) - public static void testByteByte1(byte[] dest, byte[] src) { + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}) + // 32-bit: offsets are badly aligned (UNSAFE.ARRAY_BYTE_BASE_OFFSET is 4 byte aligned, but not 8 byte aligned). + // might get fixed with JDK-8325155. + public static void testByteByte1a(byte[] dest, byte[] src) { for (int i = 0; i < src.length / 8; i++) { UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * i, UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * i)); } } - @Run(test = "testByteByte1") + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}) + // 32-bit: address has ConvL2I for cast of long to address, not supported. + public static void testByteByte1b(byte[] dest, byte[] src) { + for (int i = 0; i < src.length / 8; i++) { + UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * i, UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * i)); + } + } + + @Run(test = {"testByteByte1a", "testByteByte1b"}) public static void testByteByte1_runner() { - runAndVerify2(() -> testByteByte1(byteArray, byteArray), 0); + runAndVerify2(() -> testByteByte1a(byteArray, byteArray), 0); + runAndVerify2(() -> testByteByte1b(byteArray, byteArray), 0); } @Test - @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) - public static void testByteByte2(byte[] dest, byte[] src) { + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}) + // 32-bit: offsets are badly aligned (UNSAFE.ARRAY_BYTE_BASE_OFFSET is 4 byte aligned, but not 8 byte aligned). + // might get fixed with JDK-8325155. + public static void testByteByte2a(byte[] dest, byte[] src) { for (int i = 1; i < src.length / 8; i++) { UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * (i - 1), UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * i)); } } - @Run(test = "testByteByte2") + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}) + // 32-bit: address has ConvL2I for cast of long to address, not supported. + public static void testByteByte2b(byte[] dest, byte[] src) { + for (int i = 1; i < src.length / 8; i++) { + UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * (i - 1), UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * i)); + } + } + + @Run(test = {"testByteByte2a", "testByteByte2b"}) public static void testByteByte2_runner() { - runAndVerify2(() -> testByteByte2(byteArray, byteArray), -8); + runAndVerify2(() -> testByteByte2a(byteArray, byteArray), -8); + runAndVerify2(() -> testByteByte2b(byteArray, byteArray), -8); } @Test @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }) - public static void testByteByte3(byte[] dest, byte[] src) { + public static void testByteByte3a(byte[] dest, byte[] src) { for (int i = 0; i < src.length / 8 - 1; i++) { UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * (i + 1), UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * i)); } } - @Run(test = "testByteByte3") + @Test + @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }) + public static void testByteByte3b(byte[] dest, byte[] src) { + for (int i = 0; i < src.length / 8 - 1; i++) { + UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * (i + 1), UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * i)); + } + } + + @Run(test = {"testByteByte3a", "testByteByte3b"}) public static void testByteByte3_runner() { - runAndVerify2(() -> testByteByte3(byteArray, byteArray), 8); + runAndVerify2(() -> testByteByte3a(byteArray, byteArray), 8); + runAndVerify2(() -> testByteByte3b(byteArray, byteArray), 8); } @Test @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }) - public static void testByteByte4(byte[] dest, byte[] src, int start, int stop) { + public static void testByteByte4a(byte[] dest, byte[] src, int start, int stop) { for (int i = start; i < stop; i++) { UNSAFE.putLongUnaligned(dest, 8 * i + baseOffset, UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * i)); } } - @Run(test = "testByteByte4") + @Test + @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }) + public static void testByteByte4b(byte[] dest, byte[] src, int start, int stop) { + for (int i = start; i < stop; i++) { + UNSAFE.putLongUnaligned(dest, 8L * i + baseOffset, UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * i)); + } + } + + @Run(test = {"testByteByte4a", "testByteByte4b"}) public static void testByteByte4_runner() { baseOffset = UNSAFE.ARRAY_BYTE_BASE_OFFSET; - runAndVerify2(() -> testByteByte4(byteArray, byteArray, 0, size), 0); + runAndVerify2(() -> testByteByte4a(byteArray, byteArray, 0, size), 0); + runAndVerify2(() -> testByteByte4b(byteArray, byteArray, 0, size), 0); } @Test @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }) - public static void testByteByte5(byte[] dest, byte[] src, int start, int stop) { + public static void testByteByte5a(byte[] dest, byte[] src, int start, int stop) { for (int i = start; i < stop; i++) { UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * (i + baseOffset), UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * i)); } } - @Run(test = "testByteByte5") + @Test + @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }) + public static void testByteByte5b(byte[] dest, byte[] src, int start, int stop) { + for (int i = start; i < stop; i++) { + UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * (i + baseOffset), UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * i)); + } + } + + @Run(test = {"testByteByte5a", "testByteByte5b"}) public static void testByteByte5_runner() { baseOffset = 1; - runAndVerify2(() -> testByteByte5(byteArray, byteArray, 0, size-1), 8); + runAndVerify2(() -> testByteByte5a(byteArray, byteArray, 0, size-1), 8); + runAndVerify2(() -> testByteByte5b(byteArray, byteArray, 0, size-1), 8); } @Test - @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) - public static void testOffHeapLong1(long dest, long[] src) { + @IR(counts = { IRNode.LOAD_VECTOR_L, "=0", IRNode.STORE_VECTOR, "=0" }) // temporary + // @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) + // FAILS: adr is CastX2P(dest + 8 * (i + int_con)) + // See: JDK-8331576 + public static void testOffHeapLong1a(long dest, long[] src) { for (int i = 0; i < src.length; i++) { UNSAFE.putLongUnaligned(null, dest + 8 * i, src[i]); } } - @Run(test = "testOffHeapLong1") + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, "=0", IRNode.STORE_VECTOR, "=0" }) // temporary + // @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) + // FAILS: adr is CastX2P(dest + 8L * (i + int_con)) + // See: JDK-8331576 + public static void testOffHeapLong1b(long dest, long[] src) { + for (int i = 0; i < src.length; i++) { + UNSAFE.putLongUnaligned(null, dest + 8L * i, src[i]); + } + } + + @Run(test = {"testOffHeapLong1a", "testOffHeapLong1b"}) public static void testOffHeapLong1_runner() { - runAndVerify3(() -> testOffHeapLong1(baseOffHeap, longArray), 0); + runAndVerify3(() -> testOffHeapLong1a(baseOffHeap, longArray), 0); + runAndVerify3(() -> testOffHeapLong1b(baseOffHeap, longArray), 0); } @Test - @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) - public static void testOffHeapLong2(long dest, long[] src) { + @IR(counts = { IRNode.LOAD_VECTOR_L, "=0", IRNode.STORE_VECTOR, "=0" }) // temporary + // @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) + // FAILS: adr is CastX2P + // See: JDK-8331576 + public static void testOffHeapLong2a(long dest, long[] src) { for (int i = 1; i < src.length; i++) { UNSAFE.putLongUnaligned(null, dest + 8 * (i - 1), src[i]); } } - @Run(test = "testOffHeapLong2") + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, "=0", IRNode.STORE_VECTOR, "=0" }) // temporary + // @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) + // FAILS: adr is CastX2P + // See: JDK-8331576 + public static void testOffHeapLong2b(long dest, long[] src) { + for (int i = 1; i < src.length; i++) { + UNSAFE.putLongUnaligned(null, dest + 8L * (i - 1), src[i]); + } + } + + @Run(test = {"testOffHeapLong2a", "testOffHeapLong2b"}) public static void testOffHeapLong2_runner() { - runAndVerify3(() -> testOffHeapLong2(baseOffHeap, longArray), -8); + runAndVerify3(() -> testOffHeapLong2a(baseOffHeap, longArray), -8); + runAndVerify3(() -> testOffHeapLong2b(baseOffHeap, longArray), -8); } @Test - @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) - public static void testOffHeapLong3(long dest, long[] src) { + @IR(counts = { IRNode.LOAD_VECTOR_L, "=0", IRNode.STORE_VECTOR, "=0" }) // temporary + // @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) + // FAILS: adr is CastX2P + // See: JDK-8331576 + public static void testOffHeapLong3a(long dest, long[] src) { for (int i = 0; i < src.length - 1; i++) { UNSAFE.putLongUnaligned(null, dest + 8 * (i + 1), src[i]); } } - @Run(test = "testOffHeapLong3") + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, "=0", IRNode.STORE_VECTOR, "=0" }) // temporary + // @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) + // FAILS: adr is CastX2P + // See: JDK-8331576 + public static void testOffHeapLong3b(long dest, long[] src) { + for (int i = 0; i < src.length - 1; i++) { + UNSAFE.putLongUnaligned(null, dest + 8L * (i + 1), src[i]); + } + } + + @Run(test = {"testOffHeapLong3a", "testOffHeapLong3b"}) public static void testOffHeapLong3_runner() { - runAndVerify3(() -> testOffHeapLong3(baseOffHeap, longArray), 8); + runAndVerify3(() -> testOffHeapLong3a(baseOffHeap, longArray), 8); + runAndVerify3(() -> testOffHeapLong3b(baseOffHeap, longArray), 8); } @Test - @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, - applyIf = {"AlignVector", "false"}) + @IR(counts = { IRNode.LOAD_VECTOR_L, "=0", IRNode.STORE_VECTOR, "=0" }) // temporary + // @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + // applyIf = {"AlignVector", "false"}) + // FAILS: adr is CastX2P + // See: JDK-8331576 // AlignVector cannot guarantee that invar is aligned. - public static void testOffHeapLong4(long dest, long[] src, int start, int stop) { + public static void testOffHeapLong4a(long dest, long[] src, int start, int stop) { for (int i = start; i < stop; i++) { UNSAFE.putLongUnaligned(null, dest + 8 * i + baseOffset, src[i]); } } - @Run(test = "testOffHeapLong4") + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, "=0", IRNode.STORE_VECTOR, "=0" }) // temporary + // @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + // applyIf = {"AlignVector", "false"}) + // FAILS: adr is CastX2P + // See: JDK-8331576 + // AlignVector cannot guarantee that invar is aligned. + public static void testOffHeapLong4b(long dest, long[] src, int start, int stop) { + for (int i = start; i < stop; i++) { + UNSAFE.putLongUnaligned(null, dest + 8L * i + baseOffset, src[i]); + } + } + + @Run(test = {"testOffHeapLong4a", "testOffHeapLong4b"}) public static void testOffHeapLong4_runner() { baseOffset = 8; - runAndVerify3(() -> testOffHeapLong4(baseOffHeap, longArray, 0, size-1), 8); + runAndVerify3(() -> testOffHeapLong4a(baseOffHeap, longArray, 0, size-1), 8); + runAndVerify3(() -> testOffHeapLong4b(baseOffHeap, longArray, 0, size-1), 8); } } diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVector.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVector.java index fd5c2969074f9..c77f4f6fa2e25 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVector.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVector.java @@ -1363,7 +1363,7 @@ static Object[] test16b(byte[] a) { static Object[] test17a(long[] a) { // Unsafe: vectorizes with profiling (not xcomp) for (int i = 0; i < RANGE; i++) { - int adr = UNSAFE.ARRAY_LONG_BASE_OFFSET + 8 * i; + long adr = UNSAFE.ARRAY_LONG_BASE_OFFSET + 8L * i; long v = UNSAFE.getLongUnaligned(a, adr); UNSAFE.putLongUnaligned(a, adr, v + 1); } @@ -1375,7 +1375,7 @@ static Object[] test17a(long[] a) { static Object[] test17b(long[] a) { // Not alignable for (int i = 0; i < RANGE-1; i++) { - int adr = UNSAFE.ARRAY_LONG_BASE_OFFSET + 8 * i + 1; + long adr = UNSAFE.ARRAY_LONG_BASE_OFFSET + 8L * i + 1; long v = UNSAFE.getLongUnaligned(a, adr); UNSAFE.putLongUnaligned(a, adr, v + 1); } @@ -1392,7 +1392,7 @@ static Object[] test17b(long[] a) { static Object[] test17c(long[] a) { // Unsafe: aligned vectorizes for (int i = 0; i < RANGE-1; i+=4) { - int adr = UNSAFE.ARRAY_LONG_BASE_OFFSET + 8 * i; + long adr = UNSAFE.ARRAY_LONG_BASE_OFFSET + 8L * i; long v0 = UNSAFE.getLongUnaligned(a, adr + 0); long v1 = UNSAFE.getLongUnaligned(a, adr + 8); UNSAFE.putLongUnaligned(a, adr + 0, v0 + 1); @@ -1422,7 +1422,7 @@ static Object[] test17c(long[] a) { static Object[] test17d(long[] a) { // Not alignable for (int i = 0; i < RANGE-1; i+=4) { - int adr = UNSAFE.ARRAY_LONG_BASE_OFFSET + 8 * i + 1; + long adr = UNSAFE.ARRAY_LONG_BASE_OFFSET + 8L * i + 1; long v0 = UNSAFE.getLongUnaligned(a, adr + 0); long v1 = UNSAFE.getLongUnaligned(a, adr + 8); UNSAFE.putLongUnaligned(a, adr + 0, v0 + 1); diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVectorFuzzer.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVectorFuzzer.java index 7b95781905ead..d75db965ea3c1 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVectorFuzzer.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVectorFuzzer.java @@ -1090,11 +1090,11 @@ static Object[] testUU_unsafe_BasI(byte[] a) { int init = init_con_or_var(); int limit = limit_con_or_var(); int stride = stride_con(); - int scale = scale_con(); - int offset = offset1_con_or_var(); + long scale = scale_con(); + long offset = offset1_con_or_var(); for (int i = init; i < limit; i += stride) { - int adr = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset + i * scale; + long adr = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset + i * scale; int v = UNSAFE.getIntUnaligned(a, adr); UNSAFE.putIntUnaligned(a, adr, v + 1); } @@ -1105,19 +1105,19 @@ static Object[] testUU_unsafe_BasIH(byte[] a, byte[] b, byte[] c) { int init = init_con_or_var(); int limit = limit_con_or_var(); int stride = stride_con(); - int scale = scale_con(); - int offset1 = offset1_con_or_var(); - int offset2 = offset2_con_or_var(); - int offset3 = offset3_con_or_var(); + long scale = scale_con(); + long offset1 = offset1_con_or_var(); + long offset2 = offset2_con_or_var(); + long offset3 = offset3_con_or_var(); int h1 = hand_unrolling1_con(); int h2 = hand_unrolling2_con(); int h3 = hand_unrolling3_con(); for (int i = init; i < limit; i += stride) { - int adr1 = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset1 + i * scale; - int adr2 = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset2 + i * scale; - int adr3 = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset3 + i * scale; + long adr1 = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset1 + i * scale; + long adr2 = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset2 + i * scale; + long adr3 = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset3 + i * scale; if (h1 >= 1) { UNSAFE.putIntUnaligned(a, adr1 + 0*4, UNSAFE.getIntUnaligned(a, adr1 + 0*4) + 1); } if (h1 >= 2) { UNSAFE.putIntUnaligned(a, adr1 + 1*4, UNSAFE.getIntUnaligned(a, adr1 + 1*4) + 1); } diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestIndependentPacksWithCyclicDependency.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestIndependentPacksWithCyclicDependency.java index 65398e8adfd39..197ae08b6d882 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestIndependentPacksWithCyclicDependency.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestIndependentPacksWithCyclicDependency.java @@ -172,10 +172,10 @@ public void runTest2() { static void test2(int[] dataIa, int[] dataIb, float[] dataFa, float[] dataFb) { for (int i = 0; i < RANGE; i+=2) { // int and float arrays are two slices. But we pretend both are of type int. - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, dataIa[i+0] + 1); - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, dataIa[i+1] + 1); - dataIb[i+0] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0); - dataIb[i+1] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4); + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0, dataIa[i+0] + 1); + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4, dataIa[i+1] + 1); + dataIb[i+0] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0); + dataIb[i+1] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4); } } @@ -248,10 +248,10 @@ static void test5(int[] dataIa, int[] dataIb, float[] dataFa, float[] dataFb) { for (int i = 0; i < RANGE; i+=2) { // same as test2, except that reordering leads to different semantics // explanation analogue to test4 - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, dataIa[i+0] + 1); // A - dataIb[i+0] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0); // X - dataIb[i+1] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4); // Y - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, dataIa[i+1] + 1); // B + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0, dataIa[i+0] + 1); // A + dataIb[i+0] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0); // X + dataIb[i+1] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4); // Y + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4, dataIa[i+1] + 1); // B } } @@ -275,18 +275,18 @@ static void test6(int[] dataIa, int[] dataIb, float[] dataFa, float[] dataFb, long[] dataLa, long[] dataLb) { for (int i = 0; i < RANGE; i+=2) { // Chain of parallelizable op and conversion - int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0) + 3; - int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4) + 3; - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, v00); - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, v01); - int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0) * 45; - int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4) * 45; - unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0, v10); - unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4, v11); - float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0) + 0.55f; - float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4) + 0.55f; - unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0, v20); - unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4, v21); + int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0) + 3; + int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4) + 3; + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0, v00); + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4, v01); + int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0) * 45; + int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4) * 45; + unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0, v10); + unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4, v11); + float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0) + 0.55f; + float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4) + 0.55f; + unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0, v20); + unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4, v21); } } @@ -307,18 +307,18 @@ static void test7(int[] dataIa, int[] dataIb, float[] dataFa, float[] dataFb, long[] dataLa, long[] dataLb) { for (int i = 0; i < RANGE; i+=2) { // Cycle involving 3 memory slices - int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0) + 3; - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, v00); - int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0) * 45; - int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4) * 45; - unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0, v10); - unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4, v11); - float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0) + 0.55f; - float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4) + 0.55f; - unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0, v20); - unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4, v21); - int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4) + 3; // moved down - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, v01); + int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0) + 3; + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0, v00); + int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0) * 45; + int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4) * 45; + unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0, v10); + unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4, v11); + float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0) + 0.55f; + float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4) + 0.55f; + unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0, v20); + unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4, v21); + int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4) + 3; // moved down + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4, v01); } } @@ -340,19 +340,19 @@ static void test8(int[] dataIa, int[] dataIb, float[] dataFa, float[] dataFb, long[] dataLa, long[] dataLb) { for (int i = 0; i < RANGE; i+=2) { // 2-cycle, with more ops after - int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0) + 3; - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, v00); - int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0) * 45; - int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4) * 45; - unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0, v10); - unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4, v11); - int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4) + 3; - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, v01); + int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0) + 3; + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0, v00); + int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0) * 45; + int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4) * 45; + unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0, v10); + unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4, v11); + int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4) + 3; + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4, v01); // more stuff after - float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0) + 0.55f; - float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4) + 0.55f; - unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0, v20); - unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4, v21); + float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0) + 0.55f; + float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4) + 0.55f; + unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0, v20); + unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4, v21); } } @@ -373,19 +373,19 @@ static void test9(int[] dataIa, int[] dataIb, float[] dataFa, float[] dataFb, long[] dataLa, long[] dataLb) { for (int i = 0; i < RANGE; i+=2) { // 2-cycle, with more stuff before - float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0) + 0.55f; - float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4) + 0.55f; - unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0, v20); - unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4, v21); + float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0) + 0.55f; + float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4) + 0.55f; + unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0, v20); + unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4, v21); // 2-cycle - int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0) + 3; - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, v00); - int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0) * 45; - int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4) * 45; - unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0, v10); - unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4, v11); - int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4) + 3; - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, v01); + int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0) + 3; + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0, v00); + int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0) * 45; + int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4) * 45; + unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0, v10); + unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4, v11); + int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4) + 3; + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4, v01); } } @@ -423,18 +423,18 @@ static void test10(int[] dataIa, int[] dataIb, float[] dataFa, float[] dataFb, // // The cycle thus does not only go via packs, but also scalar ops. // - int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0) + 3; // A - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, v00); - int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0) * 45; // R: constant mismatch - int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4) + 43; // S - unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0, v10); - unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4, v11); - float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0) + 0.55f; // U - float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4) + 0.55f; // V - unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0, v20); - unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4, v21); - int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4) + 3; // B: moved down - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, v01); + int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0) + 3; // A + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0, v00); + int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0) * 45; // R: constant mismatch + int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4) + 43; // S + unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0, v10); + unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4, v11); + float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0) + 0.55f; // U + float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4) + 0.55f; // V + unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0, v20); + unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4, v21); + int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4) + 3; // B: moved down + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4, v01); } } @@ -463,8 +463,8 @@ static void verify(String name, int[] data, int[] gold) { static void verify(String name, float[] data, float[] gold) { for (int i = 0; i < RANGE; i++) { - int datav = unsafe.getInt(data, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i); - int goldv = unsafe.getInt(gold, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i); + int datav = unsafe.getInt(data, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i); + int goldv = unsafe.getInt(gold, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i); if (datav != goldv) { throw new RuntimeException(" Invalid " + name + " result: dataF[" + i + "]: " + datav + " != " + goldv); } diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestIndependentPacksWithCyclicDependency2.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestIndependentPacksWithCyclicDependency2.java index 32d69689a4269..2be7d52c78087 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestIndependentPacksWithCyclicDependency2.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestIndependentPacksWithCyclicDependency2.java @@ -58,18 +58,18 @@ static void test(int[] dataIa, int[] dataIb, float[] dataFa, float[] dataFb, long[] dataLa, long[] dataLb) { for (int i = 0; i < RANGE; i+=2) { // For explanation, see test 10 in TestIndependentPacksWithCyclicDependency.java - int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0) + 3; - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, v00); - int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0) * 45; - int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4) + 43; - unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0, v10); - unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4, v11); - float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0) + 0.55f; - float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4) + 0.55f; - unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0, v20); - unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4, v21); - int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4) + 3; // moved down - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, v01); + int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0) + 3; + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0, v00); + int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0) * 45; + int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4) + 43; + unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0, v10); + unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4, v11); + float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0) + 0.55f; + float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4) + 0.55f; + unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0, v20); + unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4, v21); + int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4) + 3; // moved down + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4, v01); } } @@ -83,8 +83,8 @@ static void verify(String name, int[] data, int[] gold) { static void verify(String name, float[] data, float[] gold) { for (int i = 0; i < RANGE; i++) { - int datav = unsafe.getInt(data, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i); - int goldv = unsafe.getInt(gold, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i); + int datav = unsafe.getInt(data, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i); + int goldv = unsafe.getInt(gold, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i); if (datav != goldv) { throw new RuntimeException(" Invalid " + name + " result: dataF[" + i + "]: " + datav + " != " + goldv); } diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestScheduleReordersScalarMemops.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestScheduleReordersScalarMemops.java index f2ed8b6aec2b3..c54a684c6911d 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestScheduleReordersScalarMemops.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestScheduleReordersScalarMemops.java @@ -124,10 +124,10 @@ static void test1(int[] dataIa, int[] dataIb, float[] dataFa, float[] dataFb) { for (int i = 0; i < RANGE; i+=2) { // Do the same as test0, but without int-float conversion. // This should reproduce on machines where conversion is not implemented. - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, dataIa[i+0] + 1); // A +1 - dataIb[i+0] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0); // X - dataIb[i+1] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4); // Y - unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, dataIa[i+1] * 11); // B *11 + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0, dataIa[i+0] + 1); // A +1 + dataIb[i+0] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0); // X + dataIb[i+1] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4); // Y + unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4, dataIa[i+1] * 11); // B *11 } } From 498a58244d79b6aaffd17300844f9908991d463c Mon Sep 17 00:00:00 2001 From: Matias Saavedra Silva Date: Fri, 21 Jun 2024 16:48:04 +0000 Subject: [PATCH 068/118] 8311208: Improve CDS Support Reviewed-by: rhalade, mschoene, ccheung, iklam --- src/hotspot/share/classfile/verifier.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/hotspot/share/classfile/verifier.cpp b/src/hotspot/share/classfile/verifier.cpp index a66fbf645f55f..375570cf19691 100644 --- a/src/hotspot/share/classfile/verifier.cpp +++ b/src/hotspot/share/classfile/verifier.cpp @@ -32,6 +32,7 @@ #include "classfile/stackMapTableFormat.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" +#include "classfile/systemDictionaryShared.hpp" #include "classfile/verifier.hpp" #include "classfile/vmClasses.hpp" #include "classfile/vmSymbols.hpp" @@ -212,6 +213,11 @@ bool Verifier::verify(InstanceKlass* klass, bool should_verify_class, TRAPS) { exception_name == vmSymbols::java_lang_ClassFormatError())) { log_info(verification)("Fail over class verification to old verifier for: %s", klass->external_name()); log_info(class, init)("Fail over class verification to old verifier for: %s", klass->external_name()); + // Exclude any classes that fail over during dynamic dumping + if (CDSConfig::is_dumping_dynamic_archive()) { + SystemDictionaryShared::warn_excluded(klass, "Failed over class verification while dynamic dumping"); + SystemDictionaryShared::set_excluded(klass); + } message_buffer = NEW_RESOURCE_ARRAY(char, message_buffer_len); exception_message = message_buffer; exception_name = inference_verify( From dadcee1b89515a651d0532d9803c22dfeeb64f9e Mon Sep 17 00:00:00 2001 From: Hai-May Chao Date: Mon, 1 Jul 2024 19:43:34 +0000 Subject: [PATCH 069/118] 8307383: Enhance DTLS connections Co-authored-by: Jamil Nimeh Reviewed-by: rhalade, mschoene, ascarpino --- .../classes/sun/security/ssl/ClientHello.java | 5 +- .../sun/security/ssl/DTLSInputRecord.java | 137 +++++++++++++++++- .../security/ssl/ServerHandshakeContext.java | 3 +- .../sun/security/ssl/TransportContext.java | 7 +- .../javax/net/ssl/DTLS/InvalidRecords.java | 32 +++- .../jdk/javax/net/ssl/TLSCommon/MFLNTest.java | 12 +- 6 files changed, 184 insertions(+), 12 deletions(-) diff --git a/src/java.base/share/classes/sun/security/ssl/ClientHello.java b/src/java.base/share/classes/sun/security/ssl/ClientHello.java index babf2bb452da4..e75076b11d64f 100644 --- a/src/java.base/share/classes/sun/security/ssl/ClientHello.java +++ b/src/java.base/share/classes/sun/security/ssl/ClientHello.java @@ -213,8 +213,6 @@ byte[] getHelloCookieBytes() { // ignore cookie hos.putBytes16(getEncodedCipherSuites()); hos.putBytes8(compressionMethod); - extensions.send(hos); // In TLS 1.3, use of certain - // extensions is mandatory. } catch (IOException ioe) { // unlikely } @@ -1426,6 +1424,9 @@ public void consume(ConnectionContext context, shc.handshakeProducers.put(SSLHandshake.SERVER_HELLO.id, SSLHandshake.SERVER_HELLO); + // Reset the ClientHello non-zero offset fragment allowance + shc.acceptCliHelloFragments = false; + // // produce // diff --git a/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java b/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java index 337cf76f2c241..e0196f3009cb8 100644 --- a/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java +++ b/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * 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,12 +40,23 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { private DTLSReassembler reassembler = null; private int readEpoch; + private SSLContextImpl sslContext; DTLSInputRecord(HandshakeHash handshakeHash) { super(handshakeHash, SSLReadCipher.nullDTlsReadCipher()); this.readEpoch = 0; } + // Method to set TransportContext + public void setTransportContext(TransportContext tc) { + this.tc = tc; + } + + // Method to set SSLContext + public void setSSLContext(SSLContextImpl sslContext) { + this.sslContext = sslContext; + } + @Override void changeReadCiphers(SSLReadCipher readCipher) { this.readCipher = readCipher; @@ -537,6 +548,27 @@ public int compareTo(RecordFragment o) { } } + /** + * Turn a sufficiently-large initial ClientHello fragment into one that + * stops immediately after the compression methods. This is only used + * for the initial CH message fragment at offset 0. + * + * @param srcFrag the fragment actually received by the DTLSReassembler + * @param limit the size of the new, cloned/truncated handshake fragment + * + * @return a truncated handshake fragment that is sized to look like a + * complete message, but actually contains only up to the compression + * methods (no extensions) + */ + private static HandshakeFragment truncateChFragment(HandshakeFragment srcFrag, + int limit) { + return new HandshakeFragment(Arrays.copyOf(srcFrag.fragment, limit), + srcFrag.contentType, srcFrag.majorVersion, + srcFrag.minorVersion, srcFrag.recordEnS, srcFrag.recordEpoch, + srcFrag.recordSeq, srcFrag.handshakeType, limit, + srcFrag.messageSeq, srcFrag.fragmentOffset, limit); + } + private static final class HoleDescriptor { int offset; // fragment_offset int limit; // fragment_offset + fragment_length @@ -640,10 +672,17 @@ void expectingFinishFlight() { // Queue up a handshake message. void queueUpHandshake(HandshakeFragment hsf) throws SSLProtocolException { if (!isDesirable(hsf)) { - // Not a dedired record, discard it. + // Not a desired record, discard it. return; } + if (hsf.handshakeType == SSLHandshake.CLIENT_HELLO.id) { + // validate the first or subsequent ClientHello message + if ((hsf = valHello(hsf, hsf.messageSeq == 0)) == null) { + return; + } + } + // Clean up the retransmission messages if necessary. cleanUpRetransmit(hsf); @@ -769,6 +808,100 @@ void queueUpHandshake(HandshakeFragment hsf) throws SSLProtocolException { } } + private HandshakeFragment valHello(HandshakeFragment hsf, + boolean firstHello) { + ServerHandshakeContext shc = + (ServerHandshakeContext) tc.handshakeContext; + // Drop any fragment that is not a zero offset until we've received + // a second (or possibly later) CH message that passes the cookie + // check. + if (shc == null || !shc.acceptCliHelloFragments) { + if (hsf.fragmentOffset != 0) { + return null; + } + } else { + // Let this fragment through to the DTLSReassembler as-is + return hsf; + } + + try { + ByteBuffer fragmentData = ByteBuffer.wrap(hsf.fragment); + + ProtocolVersion pv = ProtocolVersion.valueOf( + Record.getInt16(fragmentData)); + if (!pv.isDTLS) { + return null; + } + // Read the random (32 bytes) + if (fragmentData.remaining() < 32) { + if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + SSLLogger.fine("Rejected client hello fragment (bad random len) " + + "fo=" + hsf.fragmentOffset + " fl=" + hsf.fragmentLength); + } + return null; + } + fragmentData.position(fragmentData.position() + 32); + + // SessionID + byte[] sessId = Record.getBytes8(fragmentData); + if (sessId.length > 0 && + !SSLConfiguration.enableDtlsResumeCookie) { + // If we are in a resumption it is possible that the cookie + // exchange will be skipped. This is a server-side setting + // and it is NOT the default. If enableDtlsResumeCookie is + // false though, then we will buffer fragments since there + // is no cookie exchange to execute prior to performing + // reassembly. + return hsf; + } + + // Cookie + byte[] cookie = Record.getBytes8(fragmentData); + if (firstHello && cookie.length != 0) { + if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + SSLLogger.fine("Rejected initial client hello fragment (bad cookie len) " + + "fo=" + hsf.fragmentOffset + " fl=" + hsf.fragmentLength); + } + return null; + } + // CipherSuites + Record.getBytes16(fragmentData); + // Compression methods + Record.getBytes8(fragmentData); + + // If it's the first fragment, we'll truncate it and push it + // through the reassembler. + if (firstHello) { + return truncateChFragment(hsf, fragmentData.position()); + } else { + HelloCookieManager hcMgr = sslContext. + getHelloCookieManager(ProtocolVersion.DTLS10); + ByteBuffer msgFragBuf = ByteBuffer.wrap(hsf.fragment, 0, + fragmentData.position()); + ClientHello.ClientHelloMessage chMsg = + new ClientHello.ClientHelloMessage(shc, msgFragBuf, null); + if (!hcMgr.isCookieValid(shc, chMsg, cookie)) { + // Bad cookie check, truncate it and let the ClientHello + // consumer recheck, fail and take the appropriate action. + return truncateChFragment(hsf, fragmentData.position()); + } else { + // It's a good cookie, return the original handshake + // fragment and let it go into the DTLSReassembler like + // any other fragment so we can wait for the rest of + // the CH message. + shc.acceptCliHelloFragments = true; + return hsf; + } + } + } catch (IOException ioe) { + if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + SSLLogger.fine("Rejected client hello fragment " + + "fo=" + hsf.fragmentOffset + " fl=" + hsf.fragmentLength); + } + return null; + } + } + // Queue up a ChangeCipherSpec message void queueUpChangeCipherSpec(RecordFragment rf) throws SSLProtocolException { diff --git a/src/java.base/share/classes/sun/security/ssl/ServerHandshakeContext.java b/src/java.base/share/classes/sun/security/ssl/ServerHandshakeContext.java index 829fa2af96c7c..11b625e57911c 100644 --- a/src/java.base/share/classes/sun/security/ssl/ServerHandshakeContext.java +++ b/src/java.base/share/classes/sun/security/ssl/ServerHandshakeContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * 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,6 +55,7 @@ class ServerHandshakeContext extends HandshakeContext { CertificateMessage.CertificateEntry currentCertEntry; private static final long DEFAULT_STATUS_RESP_DELAY = 5000L; final long statusRespTimeout; + boolean acceptCliHelloFragments = false; ServerHandshakeContext(SSLContextImpl sslContext, diff --git a/src/java.base/share/classes/sun/security/ssl/TransportContext.java b/src/java.base/share/classes/sun/security/ssl/TransportContext.java index c235da3068cba..f65a08dfcfed8 100644 --- a/src/java.base/share/classes/sun/security/ssl/TransportContext.java +++ b/src/java.base/share/classes/sun/security/ssl/TransportContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * 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,6 +156,11 @@ private TransportContext(SSLContextImpl sslContext, SSLTransport transport, this.acc = AccessController.getContext(); this.consumers = new HashMap<>(); + + if (inputRecord instanceof DTLSInputRecord dtlsInputRecord) { + dtlsInputRecord.setTransportContext(this); + dtlsInputRecord.setSSLContext(this.sslContext); + } } // Dispatch plaintext to a specific consumer. diff --git a/test/jdk/javax/net/ssl/DTLS/InvalidRecords.java b/test/jdk/javax/net/ssl/DTLS/InvalidRecords.java index 304cb0695d618..120e6b258e630 100644 --- a/test/jdk/javax/net/ssl/DTLS/InvalidRecords.java +++ b/test/jdk/javax/net/ssl/DTLS/InvalidRecords.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * 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 @@ /* * @test - * @bug 8043758 + * @bug 8043758 8307383 * @summary Datagram Transport Layer Security (DTLS) * @modules java.base/sun.security.util * @library /test/lib @@ -36,6 +36,7 @@ import java.net.DatagramPacket; import java.net.SocketAddress; +import java.nio.ByteBuffer; import java.util.concurrent.atomic.AtomicBoolean; /** @@ -73,11 +74,34 @@ DatagramPacket createHandshakePacket(byte[] ba, SocketAddress socketAddr) { // ClientHello with cookie needInvalidRecords.set(false); System.out.println("invalidate ClientHello message"); - if (ba[ba.length - 1] == (byte)0xFF) { - ba[ba.length - 1] = (byte)0xFE; + // We will alter the compression method field in order to make the cookie + // check fail. + ByteBuffer chRec = ByteBuffer.wrap(ba); + // Skip 59 bytes past the record header (13), the handshake header (12), + // the protocol version (2), and client random (32) + chRec.position(59); + // Jump past the session ID + int len = Byte.toUnsignedInt(chRec.get()); + chRec.position(chRec.position() + len); + // Skip the cookie + len = Byte.toUnsignedInt(chRec.get()); + chRec.position(chRec.position() + len); + // Skip past cipher suites + len = Short.toUnsignedInt(chRec.getShort()); + chRec.position(chRec.position() + len); + // Read the data on the compression methods, should be at least 1 + len = Byte.toUnsignedInt(chRec.get()); + if (len >= 1) { + System.out.println("Detected compression methods (count = " + len + ")"); } else { ba[ba.length - 1] = (byte)0xFF; + throw new RuntimeException("Got zero length comp methods"); } + // alter the first comp method. + int compMethodVal = Byte.toUnsignedInt(chRec.get(chRec.position())); + System.out.println("Changing value at position " + chRec.position() + + " from " + compMethodVal + " to " + ++compMethodVal); + chRec.put(chRec.position(), (byte)compMethodVal); } return super.createHandshakePacket(ba, socketAddr); diff --git a/test/jdk/javax/net/ssl/TLSCommon/MFLNTest.java b/test/jdk/javax/net/ssl/TLSCommon/MFLNTest.java index ee50f21ae27d1..0867925f1359e 100644 --- a/test/jdk/javax/net/ssl/TLSCommon/MFLNTest.java +++ b/test/jdk/javax/net/ssl/TLSCommon/MFLNTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * 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,15 @@ public class MFLNTest extends SSLEngineTestCase { public static void main(String[] args) { setUpAndStartKDCIfNeeded(); System.setProperty("jsse.enableMFLNExtension", "true"); - for (int mfl = 4096; mfl >= 256; mfl /= 2) { + String testMode = System.getProperty("test.mode", "norm"); + int mflLen; + if (testMode.equals("norm_sni")) { + mflLen = 512; + } else { + mflLen = 256; + } + + for (int mfl = 4096; mfl >= mflLen; mfl /= 2) { System.out.println("==============================================" + "=============="); System.out.printf("Testsing DTLS handshake with MFL = %d%n", mfl); From d9f638303737c4e5174e5cf21ad2f634cc0b1494 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Thu, 4 Jul 2024 23:09:40 +0000 Subject: [PATCH 070/118] 8331446: Improve deserialization support Reviewed-by: rhalade, skoivu, rriggs, naoto --- .../classes/java/text/MessageFormat.java | 60 ++++++++++-- .../MessageFormat/MaxArgumentIndexTest.java | 97 +++++++++++++++++++ .../MessageFormat/SerializationTest.java | 96 ++++++++++++++++++ 3 files changed, 243 insertions(+), 10 deletions(-) create mode 100644 test/jdk/java/text/Format/MessageFormat/MaxArgumentIndexTest.java create mode 100644 test/jdk/java/text/Format/MessageFormat/SerializationTest.java diff --git a/src/java.base/share/classes/java/text/MessageFormat.java b/src/java.base/share/classes/java/text/MessageFormat.java index 58872834567d5..83cc3ec4647f4 100644 --- a/src/java.base/share/classes/java/text/MessageFormat.java +++ b/src/java.base/share/classes/java/text/MessageFormat.java @@ -41,6 +41,7 @@ import java.io.IOException; import java.io.InvalidObjectException; import java.io.ObjectInputStream; +import java.io.ObjectStreamException; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Arrays; @@ -1181,6 +1182,8 @@ public Object[] parse(String source, ParsePosition pos) { maximumArgumentNumber = argumentNumbers[i]; } } + + // Constructors/applyPattern ensure that resultArray.length < MAX_ARGUMENT_INDEX Object[] resultArray = new Object[maximumArgumentNumber + 1]; int patternOffset = 0; @@ -1459,6 +1462,9 @@ protected Object readResolve() throws InvalidObjectException { * @serial */ private int[] argumentNumbers = new int[INITIAL_FORMATS]; + // Implementation limit for ArgumentIndex pattern element. Valid indices must + // be less than this value + private static final int MAX_ARGUMENT_INDEX = 10000; /** * One less than the number of entries in {@code offsets}. Can also be thought of @@ -1639,6 +1645,11 @@ private void setFormatFromPattern(int position, int offsetNumber, + argumentNumber); } + if (argumentNumber >= MAX_ARGUMENT_INDEX) { + throw new IllegalArgumentException( + argumentNumber + " exceeds the ArgumentIndex implementation limit"); + } + // resize format information arrays if necessary if (offsetNumber >= formats.length) { int newLength = formats.length * 2; @@ -2006,24 +2017,53 @@ private static FormatStyle fromString(String text) { */ @java.io.Serial private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - in.defaultReadObject(); - boolean isValid = maxOffset >= -1 - && formats.length > maxOffset - && offsets.length > maxOffset - && argumentNumbers.length > maxOffset; + ObjectInputStream.GetField fields = in.readFields(); + if (fields.defaulted("argumentNumbers") || fields.defaulted("offsets") + || fields.defaulted("formats") || fields.defaulted("locale") + || fields.defaulted("pattern") || fields.defaulted("maxOffset")){ + throw new InvalidObjectException("Stream has missing data"); + } + + locale = (Locale) fields.get("locale", null); + String patt = (String) fields.get("pattern", null); + int maxOff = fields.get("maxOffset", -2); + int[] argNums = ((int[]) fields.get("argumentNumbers", null)).clone(); + int[] offs = ((int[]) fields.get("offsets", null)).clone(); + Format[] fmts = ((Format[]) fields.get("formats", null)).clone(); + + // Check arrays/maxOffset have correct value/length + boolean isValid = maxOff >= -1 && argNums.length > maxOff + && offs.length > maxOff && fmts.length > maxOff; + + // Check the correctness of arguments and offsets if (isValid) { - int lastOffset = pattern.length() + 1; - for (int i = maxOffset; i >= 0; --i) { - if ((offsets[i] < 0) || (offsets[i] > lastOffset)) { + int lastOffset = patt.length() + 1; + for (int i = maxOff; i >= 0; --i) { + if (argNums[i] < 0 || argNums[i] >= MAX_ARGUMENT_INDEX + || offs[i] < 0 || offs[i] > lastOffset) { isValid = false; break; } else { - lastOffset = offsets[i]; + lastOffset = offs[i]; } } } + if (!isValid) { - throw new InvalidObjectException("Could not reconstruct MessageFormat from corrupt stream."); + throw new InvalidObjectException("Stream has invalid data"); } + maxOffset = maxOff; + pattern = patt; + offsets = offs; + formats = fmts; + argumentNumbers = argNums; + } + + /** + * Serialization without data not supported for this class. + */ + @java.io.Serial + private void readObjectNoData() throws ObjectStreamException { + throw new InvalidObjectException("Deserialized MessageFormat objects need data"); } } diff --git a/test/jdk/java/text/Format/MessageFormat/MaxArgumentIndexTest.java b/test/jdk/java/text/Format/MessageFormat/MaxArgumentIndexTest.java new file mode 100644 index 0000000000000..e12dabb638388 --- /dev/null +++ b/test/jdk/java/text/Format/MessageFormat/MaxArgumentIndexTest.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 8331446 + * @summary Enforce the MAX_ARGUMENT_INDEX(10,000) implementation limit for the + * ArgumentIndex element in the MessageFormat pattern syntax. This + * should be checked during construction/applyPattern/readObject and should effectively + * prevent parse/format from being invoked with values over the limit. + * @run junit MaxArgumentIndexTest + */ + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.text.MessageFormat; +import java.util.Locale; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class MaxArgumentIndexTest { + + // A MessageFormat pattern that contains an ArgumentIndex value + // which violates this implementation's limit: MAX_ARGUMENT_INDEX(10,000) + // As this check is exclusive, 10,000 will violate the limit + private static final String VIOLATES_MAX_ARGUMENT_INDEX = "{10000}"; + + // Check String constructor enforces the limit + @Test + public void constructorTest() { + assertThrows(IllegalArgumentException.class, + () -> new MessageFormat(VIOLATES_MAX_ARGUMENT_INDEX)); + } + + // Check String, Locale constructor enforces the limit + @ParameterizedTest + @MethodSource + public void constructorWithLocaleTest(Locale locale) { + assertThrows(IllegalArgumentException.class, + () -> new MessageFormat(VIOLATES_MAX_ARGUMENT_INDEX, locale)); + } + + // Provide some basic common locale values + private static Stream constructorWithLocaleTest() { + return Stream.of(null, Locale.US, Locale.ROOT); + } + + // Edge case: Test a locale dependent subformat (with null locale) with a + // violating ArgumentIndex. In this instance, the violating ArgumentIndex + // will be caught and IAE thrown instead of the NPE + @Test + public void localeDependentSubFormatTest() { + assertThrows(IllegalArgumentException.class, + () -> new MessageFormat("{10000,number,short}", null)); + // For reference + assertThrows(NullPointerException.class, + () -> new MessageFormat("{999,number,short}", null)); + } + + // Check that the static format method enforces the limit + @Test + public void staticFormatTest() { + assertThrows(IllegalArgumentException.class, + () -> MessageFormat.format(VIOLATES_MAX_ARGUMENT_INDEX, new Object[]{1})); + } + + // Check that applyPattern(String) enforces the limit + @Test + public void applyPatternTest() { + MessageFormat mf = new MessageFormat(""); + assertThrows(IllegalArgumentException.class, + () -> mf.applyPattern(VIOLATES_MAX_ARGUMENT_INDEX)); + } +} diff --git a/test/jdk/java/text/Format/MessageFormat/SerializationTest.java b/test/jdk/java/text/Format/MessageFormat/SerializationTest.java new file mode 100644 index 0000000000000..9191c5caef35f --- /dev/null +++ b/test/jdk/java/text/Format/MessageFormat/SerializationTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 8331446 + * @summary Check correctness of deserialization + * @run junit SerializationTest + */ + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.text.MessageFormat; +import java.util.Locale; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class SerializationTest { + + // Ensure basic correctness of serialization round trip + @ParameterizedTest + @MethodSource + public void serializationRoundTrip(MessageFormat expectedMf) + throws IOException, ClassNotFoundException { + byte[] bytes = ser(expectedMf); + MessageFormat actualMf = (MessageFormat) deSer(bytes); + assertEquals(expectedMf, actualMf); + } + + // Various valid MessageFormats + private static Stream serializationRoundTrip() { + return Stream.of( + // basic pattern + new MessageFormat("{0} foo"), + // Multiple arguments + new MessageFormat("{0} {1} foo"), + // duplicate arguments + new MessageFormat("{0} {0} {1} foo"), + // Non-ascending arguments + new MessageFormat("{1} {0} foo"), + // With locale + new MessageFormat("{1} {0} foo", Locale.UK), + // With null locale. (NPE not thrown, if no format defined) + new MessageFormat("{1} {0} foo", null), + // With formats + new MessageFormat("{0,number,short} {0} {1,date,long} foo") + ); + } + + // Utility method to serialize + private static byte[] ser(Object obj) throws IOException { + ByteArrayOutputStream byteArrayOutputStream = new + ByteArrayOutputStream(); + ObjectOutputStream oos = new + ObjectOutputStream(byteArrayOutputStream); + oos.writeObject(obj); + return byteArrayOutputStream.toByteArray(); + } + + // Utility method to deserialize + private static Object deSer(byte[] bytes) throws + IOException, ClassNotFoundException { + ByteArrayInputStream byteArrayInputStream = new + ByteArrayInputStream(bytes); + ObjectInputStream ois = new + ObjectInputStream(byteArrayInputStream); + return ois.readObject(); + } +} From c89f76c0b9ca085192775af9bd9368562b582dd6 Mon Sep 17 00:00:00 2001 From: Dean Long Date: Thu, 11 Jul 2024 22:32:41 +0000 Subject: [PATCH 071/118] 8332644: Improve graph optimizations Co-authored-by: Martin Balao Co-authored-by: Francisco Ferrari Bihurriet Reviewed-by: epeter, ahgross, thartmann, rhalade, dlong, roland --- src/hotspot/share/opto/loopnode.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index 6cb50b3dee2b5..c0e929ca1f4f4 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -2601,7 +2601,7 @@ Node *LoopLimitNode::Ideal(PhaseGVN *phase, bool can_reshape) { const TypeInt* init_t = phase->type(in(Init) )->is_int(); const TypeInt* limit_t = phase->type(in(Limit))->is_int(); - int stride_p; + jlong stride_p; jlong lim, ini; julong max; if (stride_con > 0) { @@ -2610,10 +2610,10 @@ Node *LoopLimitNode::Ideal(PhaseGVN *phase, bool can_reshape) { ini = init_t->_lo; max = (julong)max_jint; } else { - stride_p = -stride_con; + stride_p = -(jlong)stride_con; lim = init_t->_hi; ini = limit_t->_lo; - max = (julong)min_jint; + max = (julong)(juint)min_jint; // double cast to get 0x0000000080000000, not 0xffffffff80000000 } julong range = lim - ini + stride_p; if (range <= max) { From 490d099e234f27adef7d691d3c5a08ebdb550c5d Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Tue, 23 Jul 2024 09:28:58 +0000 Subject: [PATCH 072/118] 8335713: Enhance vectorization analysis Co-authored-by: Roland Westrelin Reviewed-by: rhalade, ahgross, thartmann, kvn --- src/hotspot/share/opto/vectorization.cpp | 76 ++++++++++++++++++++---- src/hotspot/share/opto/vectorization.hpp | 1 + 2 files changed, 67 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/opto/vectorization.cpp b/src/hotspot/share/opto/vectorization.cpp index f013abb38fb4a..fc4eaccff5ce5 100644 --- a/src/hotspot/share/opto/vectorization.cpp +++ b/src/hotspot/share/opto/vectorization.cpp @@ -943,11 +943,40 @@ bool VPointer::scaled_iv_plus_offset(Node* n) { } } else if (opc == Op_SubI || opc == Op_SubL) { if (offset_plus_k(n->in(2), true) && scaled_iv_plus_offset(n->in(1))) { + // (offset1 + invar1 + scale * iv) - (offset2 + invar2) + // Subtraction handled via "negate" flag of "offset_plus_k". NOT_PRODUCT(_tracer.scaled_iv_plus_offset_6(n);) return true; } - if (offset_plus_k(n->in(1)) && scaled_iv_plus_offset(n->in(2))) { - _scale *= -1; + VPointer tmp(this); + if (offset_plus_k(n->in(1)) && tmp.scaled_iv_plus_offset(n->in(2))) { + // (offset1 + invar1) - (offset2 + invar2 + scale * iv) + // Subtraction handled explicitly below. + assert(_scale == 0, "shouldn't be set yet"); + // _scale = -tmp._scale + if (!try_MulI_no_overflow(-1, tmp._scale, _scale)) { + return false; // mul overflow. + } + // _offset -= tmp._offset + if (!try_SubI_no_overflow(_offset, tmp._offset, _offset)) { + return false; // sub overflow. + } + // _invar -= tmp._invar + if (tmp._invar != nullptr) { + maybe_add_to_invar(tmp._invar, true); +#ifdef ASSERT + _debug_invar_scale = tmp._debug_invar_scale; + _debug_negate_invar = !tmp._debug_negate_invar; +#endif + } + + // Forward info about the int_index: + assert(!_has_int_index_after_convI2L, "no previous int_index discovered"); + _has_int_index_after_convI2L = tmp._has_int_index_after_convI2L; + _int_index_after_convI2L_offset = tmp._int_index_after_convI2L_offset; + _int_index_after_convI2L_invar = tmp._int_index_after_convI2L_invar; + _int_index_after_convI2L_scale = tmp._int_index_after_convI2L_scale; + NOT_PRODUCT(_tracer.scaled_iv_plus_offset_7(n);) return true; } @@ -989,7 +1018,9 @@ bool VPointer::scaled_iv(Node* n) { } } else if (opc == Op_LShiftI) { if (n->in(1) == iv() && n->in(2)->is_Con()) { - _scale = 1 << n->in(2)->get_int(); + if (!try_LShiftI_no_overflow(1, n->in(2)->get_int(), _scale)) { + return false; // shift overflow. + } NOT_PRODUCT(_tracer.scaled_iv_6(n, _scale);) return true; } @@ -1012,15 +1043,24 @@ bool VPointer::scaled_iv(Node* n) { if (tmp.scaled_iv_plus_offset(n->in(1)) && tmp.has_iv()) { // We successfully matched an integer index, of the form: // int_index = int_offset + int_invar + int_scale * iv + // Forward scale. + assert(_scale == 0 && tmp._scale != 0, "iv only found just now"); + _scale = tmp._scale; + // Accumulate offset. + if (!try_AddI_no_overflow(_offset, tmp._offset, _offset)) { + return false; // add overflow. + } + // Accumulate invar. + if (tmp._invar != nullptr) { + maybe_add_to_invar(tmp._invar, false); + } + // Set info about the int_index: + assert(!_has_int_index_after_convI2L, "no previous int_index discovered"); _has_int_index_after_convI2L = true; _int_index_after_convI2L_offset = tmp._offset; _int_index_after_convI2L_invar = tmp._invar; _int_index_after_convI2L_scale = tmp._scale; - } - // Now parse it again for the real VPointer. This makes sure that the int_offset, int_invar, - // and int_scale are properly added to the final VPointer's offset, invar, and scale. - if (scaled_iv_plus_offset(n->in(1))) { NOT_PRODUCT(_tracer.scaled_iv_7(n);) return true; } @@ -1039,12 +1079,14 @@ bool VPointer::scaled_iv(Node* n) { NOT_PRODUCT(_tracer.scaled_iv_8(n, &tmp);) if (tmp.scaled_iv_plus_offset(n->in(1))) { - int scale = n->in(2)->get_int(); + int shift = n->in(2)->get_int(); // Accumulate scale. - _scale = tmp._scale << scale; + if (!try_LShiftI_no_overflow(tmp._scale, shift, _scale)) { + return false; // shift overflow. + } // Accumulate offset. int shifted_offset = 0; - if (!try_LShiftI_no_overflow(tmp._offset, scale, shifted_offset)) { + if (!try_LShiftI_no_overflow(tmp._offset, shift, shifted_offset)) { return false; // shift overflow. } if (!try_AddI_no_overflow(_offset, shifted_offset, _offset)) { @@ -1061,6 +1103,7 @@ bool VPointer::scaled_iv(Node* n) { } // Forward info about the int_index: + assert(!_has_int_index_after_convI2L, "no previous int_index discovered"); _has_int_index_after_convI2L = tmp._has_int_index_after_convI2L; _int_index_after_convI2L_offset = tmp._int_index_after_convI2L_offset; _int_index_after_convI2L_invar = tmp._int_index_after_convI2L_invar; @@ -1255,6 +1298,9 @@ bool VPointer::try_AddSubI_no_overflow(int offset1, int offset2, bool is_sub, in } bool VPointer::try_LShiftI_no_overflow(int offset, int shift, int& result) { + if (shift < 0 || shift > 31) { + return false; + } jlong long_offset = java_shift_left((jlong)(offset), shift); jint int_offset = java_shift_left( offset, shift); if (long_offset != int_offset) { @@ -1264,6 +1310,16 @@ bool VPointer::try_LShiftI_no_overflow(int offset, int shift, int& result) { return true; } +bool VPointer::try_MulI_no_overflow(int offset1, int offset2, int& result) { + jlong long_offset = java_multiply((jlong)(offset1), (jlong)(offset2)); + jint int_offset = java_multiply( offset1, offset2); + if (long_offset != int_offset) { + return false; + } + result = int_offset; + return true; +} + // We use two comparisons, because a subtraction could underflow. #define RETURN_CMP_VALUE_IF_NOT_EQUAL(a, b) \ if (a < b) { return -1; } \ diff --git a/src/hotspot/share/opto/vectorization.hpp b/src/hotspot/share/opto/vectorization.hpp index 7de29444e5f8f..b084edd44b339 100644 --- a/src/hotspot/share/opto/vectorization.hpp +++ b/src/hotspot/share/opto/vectorization.hpp @@ -943,6 +943,7 @@ class VPointer : public ArenaObj { static bool try_SubI_no_overflow(int offset1, int offset2, int& result); static bool try_AddSubI_no_overflow(int offset1, int offset2, bool is_sub, int& result); static bool try_LShiftI_no_overflow(int offset1, int offset2, int& result); + static bool try_MulI_no_overflow(int offset1, int offset2, int& result); Node* register_if_new(Node* n) const; }; From 2c0c65353b2f67bdcd954b4d2c2ae3e9b24d1c22 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 15 Oct 2024 11:52:34 +0000 Subject: [PATCH 073/118] 8342044: Increase timeout of gc/shenandoah/oom/TestClassLoaderLeak.java Reviewed-by: shade --- test/hotspot/jtreg/gc/shenandoah/oom/TestClassLoaderLeak.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/gc/shenandoah/oom/TestClassLoaderLeak.java b/test/hotspot/jtreg/gc/shenandoah/oom/TestClassLoaderLeak.java index 1a3d07bf80d06..00e32a4136e68 100644 --- a/test/hotspot/jtreg/gc/shenandoah/oom/TestClassLoaderLeak.java +++ b/test/hotspot/jtreg/gc/shenandoah/oom/TestClassLoaderLeak.java @@ -27,7 +27,7 @@ * @summary Test OOME in due to classloader leak * @requires vm.gc.Shenandoah * @library /test/lib - * @run driver TestClassLoaderLeak + * @run driver/timeout=600 TestClassLoaderLeak */ import java.util.*; From 54c9348c8c0f5b363d1ef31166179fe9ac61ab9c Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 15 Oct 2024 12:16:15 +0000 Subject: [PATCH 074/118] 8336103: Clean up confusing Method::is_initializer Reviewed-by: dholmes, coleenp --- src/hotspot/share/ci/ciMethod.cpp | 1 - src/hotspot/share/ci/ciMethod.hpp | 1 - src/hotspot/share/jvmci/jvmciCompiler.cpp | 2 +- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 13 ++++++------- src/hotspot/share/oops/klassVtable.cpp | 7 ++++--- src/hotspot/share/oops/method.cpp | 4 ---- src/hotspot/share/oops/method.hpp | 3 --- 7 files changed, 11 insertions(+), 20 deletions(-) diff --git a/src/hotspot/share/ci/ciMethod.cpp b/src/hotspot/share/ci/ciMethod.cpp index 94b405cdbfacd..a74a812c6a23b 100644 --- a/src/hotspot/share/ci/ciMethod.cpp +++ b/src/hotspot/share/ci/ciMethod.cpp @@ -1249,7 +1249,6 @@ bool ciMethod::has_jsrs () const { FETCH_FLAG_FROM_VM(has_jsrs); bool ciMethod::is_getter () const { FETCH_FLAG_FROM_VM(is_getter); } bool ciMethod::is_setter () const { FETCH_FLAG_FROM_VM(is_setter); } bool ciMethod::is_accessor () const { FETCH_FLAG_FROM_VM(is_accessor); } -bool ciMethod::is_initializer () const { FETCH_FLAG_FROM_VM(is_initializer); } bool ciMethod::is_empty () const { FETCH_FLAG_FROM_VM(is_empty_method); } bool ciMethod::is_boxing_method() const { diff --git a/src/hotspot/share/ci/ciMethod.hpp b/src/hotspot/share/ci/ciMethod.hpp index 5cb63204d0b72..cc524930192cd 100644 --- a/src/hotspot/share/ci/ciMethod.hpp +++ b/src/hotspot/share/ci/ciMethod.hpp @@ -352,7 +352,6 @@ class ciMethod : public ciMetadata { bool is_getter () const; bool is_setter () const; bool is_accessor () const; - bool is_initializer () const; bool is_empty () const; bool can_be_statically_bound() const { return _can_be_statically_bound; } bool has_reserved_stack_access() const { return _has_reserved_stack_access; } diff --git a/src/hotspot/share/jvmci/jvmciCompiler.cpp b/src/hotspot/share/jvmci/jvmciCompiler.cpp index 2b8684f7ab85b..04cdb4b4b4fda 100644 --- a/src/hotspot/share/jvmci/jvmciCompiler.cpp +++ b/src/hotspot/share/jvmci/jvmciCompiler.cpp @@ -87,7 +87,7 @@ void JVMCICompiler::bootstrap(TRAPS) { int len = objectMethods->length(); for (int i = 0; i < len; i++) { methodHandle mh(THREAD, objectMethods->at(i)); - if (!mh->is_native() && !mh->is_static() && !mh->is_initializer()) { + if (!mh->is_native() && !mh->is_static() && !mh->is_object_initializer() && !mh->is_static_initializer()) { ResourceMark rm; int hot_count = 10; // TODO: what's the appropriate value? CompileBroker::compile_method(mh, InvocationEntryBci, CompLevel_full_optimization, mh, hot_count, CompileTask::Reason_Bootstrap, CHECK); diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index d231fbe8a6a0e..ba1155e66946b 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -2178,7 +2178,7 @@ C2V_VMENTRY_NULL(jobjectArray, getDeclaredConstructors, (JNIEnv* env, jobject, A GrowableArray constructors_array; for (int i = 0; i < iklass->methods()->length(); i++) { Method* m = iklass->methods()->at(i); - if (m->is_initializer() && !m->is_static()) { + if (m->is_object_initializer()) { constructors_array.append(m); } } @@ -2205,7 +2205,7 @@ C2V_VMENTRY_NULL(jobjectArray, getDeclaredMethods, (JNIEnv* env, jobject, ARGUME GrowableArray methods_array; for (int i = 0; i < iklass->methods()->length(); i++) { Method* m = iklass->methods()->at(i); - if (!m->is_initializer() && !m->is_overpass()) { + if (!m->is_object_initializer() && !m->is_static_initializer() && !m->is_overpass()) { methods_array.append(m); } } @@ -2921,12 +2921,11 @@ C2V_VMENTRY_NULL(jobject, asReflectionExecutable, (JNIEnv* env, jobject, ARGUMEN requireInHotSpot("asReflectionExecutable", JVMCI_CHECK_NULL); methodHandle m(THREAD, UNPACK_PAIR(Method, method)); oop executable; - if (m->is_initializer()) { - if (m->is_static_initializer()) { - JVMCI_THROW_MSG_NULL(IllegalArgumentException, - "Cannot create java.lang.reflect.Method for class initializer"); - } + if (m->is_object_initializer()) { executable = Reflection::new_constructor(m, CHECK_NULL); + } else if (m->is_static_initializer()) { + JVMCI_THROW_MSG_NULL(IllegalArgumentException, + "Cannot create java.lang.reflect.Method for class initializer"); } else { executable = Reflection::new_method(m, false, CHECK_NULL); } diff --git a/src/hotspot/share/oops/klassVtable.cpp b/src/hotspot/share/oops/klassVtable.cpp index cbc379709f1f4..e1bffc90d5129 100644 --- a/src/hotspot/share/oops/klassVtable.cpp +++ b/src/hotspot/share/oops/klassVtable.cpp @@ -1230,9 +1230,10 @@ void klassItable::initialize_itable_and_check_constraints(TRAPS) { } inline bool interface_method_needs_itable_index(Method* m) { - if (m->is_static()) return false; // e.g., Stream.empty - if (m->is_initializer()) return false; // or - if (m->is_private()) return false; // uses direct call + if (m->is_static()) return false; // e.g., Stream.empty + if (m->is_object_initializer()) return false; // + if (m->is_static_initializer()) return false; // + if (m->is_private()) return false; // uses direct call // If an interface redeclares a method from java.lang.Object, // it should already have a vtable index, don't touch it. // e.g., CharSequence.toString (from initialize_vtable) diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index f4dcd4f149302..a1b380d364655 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -846,10 +846,6 @@ bool Method::is_constant_getter() const { Bytecodes::is_return(java_code_at(last_index))); } -bool Method::is_initializer() const { - return is_object_initializer() || is_static_initializer(); -} - bool Method::has_valid_initializer_flags() const { return (is_static() || method_holder()->major_version() < 51); diff --git a/src/hotspot/share/oops/method.hpp b/src/hotspot/share/oops/method.hpp index 905c53a4ea38b..6ffaebcdfdab2 100644 --- a/src/hotspot/share/oops/method.hpp +++ b/src/hotspot/share/oops/method.hpp @@ -576,9 +576,6 @@ class Method : public Metadata { // returns true if the method does nothing but return a constant of primitive type bool is_constant_getter() const; - // returns true if the method is an initializer ( or ). - bool is_initializer() const; - // returns true if the method is static OR if the classfile version < 51 bool has_valid_initializer_flags() const; From 6ed6dff22208e7e6c24c98d3a9ff895a6c6c0ae0 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 15 Oct 2024 12:55:49 +0000 Subject: [PATCH 075/118] 8341871: Disable G1 for unsupported platforms after JDK-8334060 Reviewed-by: mdoerr, erikj --- make/autoconf/jvm-features.m4 | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/make/autoconf/jvm-features.m4 b/make/autoconf/jvm-features.m4 index bd33315090fce..9695644bafe63 100644 --- a/make/autoconf/jvm-features.m4 +++ b/make/autoconf/jvm-features.m4 @@ -479,6 +479,22 @@ AC_DEFUN([JVM_FEATURES_CALCULATE_ACTIVE], $JVM_FEATURES_ENABLED, $JVM_FEATURES_DISABLED) ]) +################################################################################ +# Filter the unsupported feature combinations. +# This is called after JVM_FEATURES_ACTIVE are fully populated. +# +AC_DEFUN([JVM_FEATURES_FILTER_UNSUPPORTED], +[ + # G1 late barrier expansion in C2 is not implemented for some platforms. + # Choose not to support G1 in this configuration. + if JVM_FEATURES_IS_ACTIVE(compiler2); then + if test "x$OPENJDK_TARGET_CPU" = "xx86"; then + AC_MSG_NOTICE([G1 cannot be used with C2 on this platform, disabling G1]) + UTIL_GET_NON_MATCHING_VALUES(JVM_FEATURES_ACTIVE, $JVM_FEATURES_ACTIVE, "g1gc") + fi + fi +]) + ################################################################################ # Helper function for JVM_FEATURES_VERIFY. Check if the specified JVM # feature is active. To be used in shell if constructs, like this: @@ -554,6 +570,9 @@ AC_DEFUN_ONCE([JVM_FEATURES_SETUP], # The result is stored in JVM_FEATURES_ACTIVE. JVM_FEATURES_CALCULATE_ACTIVE($variant) + # Filter unsupported feature combinations from JVM_FEATURES_ACTIVE. + JVM_FEATURES_FILTER_UNSUPPORTED + # Verify consistency for JVM_FEATURES_ACTIVE. JVM_FEATURES_VERIFY($variant) From 5eae20f73b9e8578d58c7e49d2da79cf1b0b229c Mon Sep 17 00:00:00 2001 From: Julian Waters Date: Tue, 15 Oct 2024 14:10:53 +0000 Subject: [PATCH 076/118] 8323672: Suppress unwanted autoconf added flags in CC and CXX Reviewed-by: ihse --- make/autoconf/toolchain.m4 | 6 +--- make/autoconf/util.m4 | 64 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4 index 5b3ef98c7364b..d84ae447e541a 100644 --- a/make/autoconf/toolchain.m4 +++ b/make/autoconf/toolchain.m4 @@ -307,7 +307,7 @@ AC_DEFUN_ONCE([TOOLCHAIN_POST_DETECTION], [ # Restore old path, except for the microsoft toolchain, which requires the # toolchain path to remain in place. Otherwise the compiler will not work in - # some siutations in later configure checks. + # some situations in later configure checks. if test "x$TOOLCHAIN_TYPE" != "xmicrosoft"; then PATH="$OLD_PATH" fi @@ -316,10 +316,6 @@ AC_DEFUN_ONCE([TOOLCHAIN_POST_DETECTION], # This is necessary since AC_PROG_CC defaults CFLAGS to "-g -O2" CFLAGS="$ORG_CFLAGS" CXXFLAGS="$ORG_CXXFLAGS" - - # filter out some unwanted additions autoconf may add to CXX; we saw this on macOS with autoconf 2.72 - UTIL_GET_NON_MATCHING_VALUES(cxx_filtered, $CXX, -std=c++11 -std=gnu++11) - CXX="$cxx_filtered" ]) # Check if a compiler is of the toolchain type we expect, and save the version diff --git a/make/autoconf/util.m4 b/make/autoconf/util.m4 index 6beadb4c942c7..5a6142d509202 100644 --- a/make/autoconf/util.m4 +++ b/make/autoconf/util.m4 @@ -25,6 +25,70 @@ m4_include([util_paths.m4]) +############################################################################### +# Overwrite the existing version of AC_PROG_CC with our own custom variant. +# Unlike the regular AC_PROG_CC, the compiler list must always be passed. +AC_DEFUN([AC_PROG_CC], +[ + AC_LANG_PUSH(C) + AC_ARG_VAR([CC], [C compiler command]) + AC_ARG_VAR([CFLAGS], [C compiler flags]) + + _AC_ARG_VAR_LDFLAGS() + _AC_ARG_VAR_LIBS() + _AC_ARG_VAR_CPPFLAGS() + + AC_CHECK_TOOLS(CC, [$1]) + + test -z "$CC" && AC_MSG_FAILURE([no acceptable C compiler found in \$PATH]) + + # Provide some information about the compiler. + _AS_ECHO_LOG([checking for _AC_LANG compiler version]) + set X $ac_compile + ac_compiler=$[2] + for ac_option in --version -v -V -qversion -version; do + _AC_DO_LIMIT([$ac_compiler $ac_option >&AS_MESSAGE_LOG_FD]) + done + + m4_expand_once([_AC_COMPILER_EXEEXT]) + m4_expand_once([_AC_COMPILER_OBJEXT]) + + _AC_PROG_CC_G + + AC_LANG_POP(C) +]) + +############################################################################### +# Overwrite the existing version of AC_PROG_CXX with our own custom variant. +# Unlike the regular AC_PROG_CXX, the compiler list must always be passed. +AC_DEFUN([AC_PROG_CXX], +[ + AC_LANG_PUSH(C++) + AC_ARG_VAR([CXX], [C++ compiler command]) + AC_ARG_VAR([CXXFLAGS], [C++ compiler flags]) + + _AC_ARG_VAR_LDFLAGS() + _AC_ARG_VAR_LIBS() + _AC_ARG_VAR_CPPFLAGS() + + AC_CHECK_TOOLS(CXX, [$1]) + + # Provide some information about the compiler. + _AS_ECHO_LOG([checking for _AC_LANG compiler version]) + set X $ac_compile + ac_compiler=$[2] + for ac_option in --version -v -V -qversion; do + _AC_DO_LIMIT([$ac_compiler $ac_option >&AS_MESSAGE_LOG_FD]) + done + + m4_expand_once([_AC_COMPILER_EXEEXT]) + m4_expand_once([_AC_COMPILER_OBJEXT]) + + _AC_PROG_CXX_G + + AC_LANG_POP(C++) +]) + ################################################################################ # Create a function/macro that takes a series of named arguments. The call is # similar to AC_DEFUN, but the setup of the function looks like this: From b9cabbecdac27ae8b93df88660a4a0f3f60e6828 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Tue, 15 Oct 2024 17:44:49 +0000 Subject: [PATCH 077/118] 8341997: Tests create files in src tree instead of scratch dir Reviewed-by: erikj, jpai --- test/jdk/java/io/FileInputStream/ReadXBytes.java | 4 ++-- test/jdk/java/nio/MappedByteBuffer/ForceException.java | 4 ++-- test/jdk/java/nio/MappedByteBuffer/ForceViews.java | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/jdk/java/io/FileInputStream/ReadXBytes.java b/test/jdk/java/io/FileInputStream/ReadXBytes.java index 3b0fe7d0590de..9a38205cb13e1 100644 --- a/test/jdk/java/io/FileInputStream/ReadXBytes.java +++ b/test/jdk/java/io/FileInputStream/ReadXBytes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * 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 @@ public class ReadXBytes { private static final Random RND = RandomFactory.getRandom(); public static void main(String args[]) throws IOException { - File dir = new File(System.getProperty("test.src", ".")); + File dir = new File("."); dir.deleteOnExit(); File empty = File.createTempFile("foo", "bar", dir); diff --git a/test/jdk/java/nio/MappedByteBuffer/ForceException.java b/test/jdk/java/nio/MappedByteBuffer/ForceException.java index dea63db42bf9c..c8bd06967d027 100644 --- a/test/jdk/java/nio/MappedByteBuffer/ForceException.java +++ b/test/jdk/java/nio/MappedByteBuffer/ForceException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * 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 @@ public static void main(String[] args) throws IOException { int numberOfBlocks = 200; int fileLength = numberOfBlocks * blockSize; - File file = new File(System.getProperty("test.src", "."), "test.dat"); + File file = new File(".", "test.dat"); file.deleteOnExit(); try (RandomAccessFile raf = new RandomAccessFile(file, "rw")) { raf.setLength(fileLength); diff --git a/test/jdk/java/nio/MappedByteBuffer/ForceViews.java b/test/jdk/java/nio/MappedByteBuffer/ForceViews.java index 83727f8096859..57ddac28cdfa0 100644 --- a/test/jdk/java/nio/MappedByteBuffer/ForceViews.java +++ b/test/jdk/java/nio/MappedByteBuffer/ForceViews.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * 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 @@ static record Segment(int position, int length) {} @BeforeTest(alwaysRun=true) public void openChannel() throws IOException { - Path file = Path.of(System.getProperty("test.src", "."), "junk"); + Path file = Path.of(".", "junk"); fc = FileChannel.open(file, CREATE_NEW, READ, WRITE, DELETE_ON_CLOSE); ByteBuffer buf = ByteBuffer.wrap(new byte[1024]); fc.write(buf); From 86ce19e8db6950fc529b8c510137e91e97cae0c4 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Wed, 16 Oct 2024 01:51:09 +0000 Subject: [PATCH 078/118] 8341142: Maintain a single source file for sun.net.www.protocol.jar.JarFileFactory Reviewed-by: dfuchs --- .../net/www/protocol/jar/JarFileFactory.java | 9 +- .../net/www/protocol/jar/JarFileFactory.java | 239 ------------------ 2 files changed, 8 insertions(+), 240 deletions(-) rename src/java.base/{windows => share}/classes/sun/net/www/protocol/jar/JarFileFactory.java (97%) delete mode 100644 src/java.base/unix/classes/sun/net/www/protocol/jar/JarFileFactory.java diff --git a/src/java.base/windows/classes/sun/net/www/protocol/jar/JarFileFactory.java b/src/java.base/share/classes/sun/net/www/protocol/jar/JarFileFactory.java similarity index 97% rename from src/java.base/windows/classes/sun/net/www/protocol/jar/JarFileFactory.java rename to src/java.base/share/classes/sun/net/www/protocol/jar/JarFileFactory.java index 178ffe84a0643..17ca43d4ace9f 100644 --- a/src/java.base/windows/classes/sun/net/www/protocol/jar/JarFileFactory.java +++ b/src/java.base/share/classes/sun/net/www/protocol/jar/JarFileFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ import java.util.HashMap; import java.util.jar.JarFile; import java.security.Permission; + +import jdk.internal.util.OperatingSystem; import sun.net.util.URLUtil; /* A factory for cached JAR file. This class is used to both retrieve @@ -148,6 +150,11 @@ boolean cacheIfAbsent(URL url, JarFile jarFile) { } private URL urlFor(URL url) throws IOException { + // for systems other than Windows we don't + // do any special conversion + if (!OperatingSystem.isWindows()) { + return url; + } if (url.getProtocol().equalsIgnoreCase("file")) { // Deal with UNC pathnames specially. See 4180841 diff --git a/src/java.base/unix/classes/sun/net/www/protocol/jar/JarFileFactory.java b/src/java.base/unix/classes/sun/net/www/protocol/jar/JarFileFactory.java deleted file mode 100644 index 291b6d06d8e3f..0000000000000 --- a/src/java.base/unix/classes/sun/net/www/protocol/jar/JarFileFactory.java +++ /dev/null @@ -1,239 +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. 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 sun.net.www.protocol.jar; - -import java.io.IOException; -import java.io.FileNotFoundException; -import java.net.URL; -import java.net.URLConnection; -import java.util.HashMap; -import java.util.jar.JarFile; -import java.security.Permission; -import sun.net.util.URLUtil; - -/* A factory for cached JAR file. This class is used to both retrieve - * and cache Jar files. - * - * @author Benjamin Renaud - * @since 1.2 - */ -class JarFileFactory implements URLJarFile.URLJarFileCloseController { - - /* the url to file cache */ - private static final HashMap fileCache = new HashMap<>(); - - /* the file to url cache */ - private static final HashMap urlCache = new HashMap<>(); - - private static final JarFileFactory instance = new JarFileFactory(); - - private JarFileFactory() { } - - public static JarFileFactory getInstance() { - return instance; - } - - URLConnection getConnection(JarFile jarFile) throws IOException { - URL u; - synchronized (instance) { - u = urlCache.get(jarFile); - } - if (u != null) - return u.openConnection(); - - return null; - } - - public JarFile get(URL url) throws IOException { - return get(url, true); - } - - /** - * Get or create a {@code JarFile} for the given {@code url}. - * If {@code useCaches} is true, this method attempts to find - * a jar file in the cache, and if so, returns it. - * If no jar file is found in the cache, or {@code useCaches} - * is false, the method creates a new jar file. - * If the URL points to a local file, the returned jar file - * will not be put in the cache yet. - * The caller should then call {@link #cacheIfAbsent(URL, JarFile)} - * with the returned jar file, if updating the cache is desired. - * @param url the jar file url - * @param useCaches whether the cache should be used - * @return a new or cached jar file. - * @throws IOException if the jar file couldn't be created - */ - JarFile getOrCreate(URL url, boolean useCaches) throws IOException { - if (useCaches == false) { - return get(url, false); - } - - if (!URLJarFile.isFileURL(url)) { - // A temporary file will be created, we can prepopulate - // the cache in this case. - return get(url, useCaches); - } - - // We have a local file. Do not prepopulate the cache. - JarFile result; - synchronized (instance) { - result = getCachedJarFile(url); - } - if (result == null) { - result = URLJarFile.getJarFile(url, this); - } - if (result == null) - throw new FileNotFoundException(url.toString()); - return result; - } - - /** - * Close the given jar file if it isn't present in the cache. - * Otherwise, does nothing. - * @param url the jar file URL - * @param jarFile the jar file to close - * @return true if the jar file has been closed, false otherwise. - * @throws IOException if an error occurs while closing the jar file. - */ - boolean closeIfNotCached(URL url, JarFile jarFile) throws IOException { - JarFile result; - synchronized (instance) { - result = getCachedJarFile(url); - } - if (result != jarFile) jarFile.close(); - return result != jarFile; - } - - boolean cacheIfAbsent(URL url, JarFile jarFile) { - JarFile cached; - synchronized (instance) { - String key = urlKey(url); - cached = fileCache.get(key); - if (cached == null) { - fileCache.put(key, jarFile); - urlCache.put(jarFile, url); - } - } - return cached == null || cached == jarFile; - } - - JarFile get(URL url, boolean useCaches) throws IOException { - - JarFile result; - JarFile local_result; - - if (useCaches) { - synchronized (instance) { - result = getCachedJarFile(url); - } - if (result == null) { - local_result = URLJarFile.getJarFile(url, this); - synchronized (instance) { - result = getCachedJarFile(url); - if (result == null) { - fileCache.put(urlKey(url), local_result); - urlCache.put(local_result, url); - result = local_result; - } else { - if (local_result != null) { - local_result.close(); - } - } - } - } - } else { - result = URLJarFile.getJarFile(url, this); - } - if (result == null) - throw new FileNotFoundException(url.toString()); - - return result; - } - - /** - * Callback method of the URLJarFileCloseController to - * indicate that the JarFile is closed. This way we can - * remove the JarFile from the cache - */ - public void close(JarFile jarFile) { - synchronized (instance) { - URL urlRemoved = urlCache.remove(jarFile); - if (urlRemoved != null) - fileCache.remove(urlKey(urlRemoved)); - } - } - - private JarFile getCachedJarFile(URL url) { - assert Thread.holdsLock(instance); - JarFile result = fileCache.get(urlKey(url)); - - /* if the JAR file is cached, the permission will always be there */ - if (result != null) { - @SuppressWarnings("removal") - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - Permission perm = getPermission(result); - if (perm != null) { - try { - sm.checkPermission(perm); - } catch (SecurityException se) { - // fallback to checkRead/checkConnect for pre 1.2 - // security managers - if ((perm instanceof java.io.FilePermission) && - perm.getActions().contains("read")) { - sm.checkRead(perm.getName()); - } else if ((perm instanceof - java.net.SocketPermission) && - perm.getActions().contains("connect")) { - sm.checkConnect(url.getHost(), url.getPort()); - } else { - throw se; - } - } - } - } - } - return result; - } - - private String urlKey(URL url) { - String urlstr = URLUtil.urlNoFragString(url); - if ("runtime".equals(url.getRef())) urlstr += "#runtime"; - return urlstr; - } - - private Permission getPermission(JarFile jarFile) { - try { - URLConnection uc = getConnection(jarFile); - if (uc != null) - return uc.getPermission(); - } catch (IOException ioe) { - // gulp - } - - return null; - } -} From 6d7e67956b1722b4e3d33253d68c095058f39f02 Mon Sep 17 00:00:00 2001 From: Tejesh R Date: Wed, 16 Oct 2024 05:14:59 +0000 Subject: [PATCH 079/118] 8340790: Open source several AWT Dialog tests - Batch 4 Reviewed-by: honkar, prr --- test/jdk/ProblemList.txt | 1 + .../awt/Dialog/ChoiceModalDialogTest.java | 140 ++++++++++++++++ .../java/awt/Dialog/DialogBackgroundTest.java | 153 ++++++++++++++++++ .../jdk/java/awt/Dialog/EnabledResetTest.java | 145 +++++++++++++++++ .../awt/Dialog/FileDialogGetFileTest.java | 78 +++++++++ 5 files changed, 517 insertions(+) create mode 100644 test/jdk/java/awt/Dialog/ChoiceModalDialogTest.java create mode 100644 test/jdk/java/awt/Dialog/DialogBackgroundTest.java create mode 100644 test/jdk/java/awt/Dialog/EnabledResetTest.java create mode 100644 test/jdk/java/awt/Dialog/FileDialogGetFileTest.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 034830a2575a5..942e15002bdcb 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -478,6 +478,7 @@ java/awt/KeyboardFocusmanager/ConsumeNextMnemonicKeyTypedTest/ConsumeNextMnemoni java/awt/Window/GetScreenLocation/GetScreenLocationTest.java 8225787 linux-x64 java/awt/Dialog/MakeWindowAlwaysOnTop/MakeWindowAlwaysOnTop.java 8266243 macosx-aarch64 +java/awt/Dialog/ChoiceModalDialogTest.java 8161475 macosx-all java/awt/Dialog/FileDialogUserFilterTest.java 8001142 generic-all java/awt/dnd/BadSerializationTest/BadSerializationTest.java 8277817 linux-x64,windows-x64 diff --git a/test/jdk/java/awt/Dialog/ChoiceModalDialogTest.java b/test/jdk/java/awt/Dialog/ChoiceModalDialogTest.java new file mode 100644 index 0000000000000..97ce5a83a96b7 --- /dev/null +++ b/test/jdk/java/awt/Dialog/ChoiceModalDialogTest.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * 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 6213128 + * @key headful + * @summary Tests that choice is releasing input capture when a modal + * dialog is shown + * @run main ChoiceModalDialogTest + */ + +import java.awt.Choice; +import java.awt.Dialog; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Robot; +import java.awt.TextField; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.InputEvent; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +public class ChoiceModalDialogTest { + static Frame f; + static Dialog d; + static volatile boolean keyOK; + static volatile boolean mouseOK; + static TextField tf; + static Choice c; + + public static void main(String[] args) throws Exception { + Robot r; + try { + r = new Robot(); + r.setAutoDelay(100); + EventQueue.invokeAndWait(() -> { + f = new Frame("Frame"); + c = new Choice(); + f.setBounds(100, 300, 300, 200); + f.setLayout(new FlowLayout()); + tf = new TextField(3); + f.add(tf); + + c.add("1"); + c.add("2"); + c.add("3"); + c.add("4"); + f.add(c); + + tf.addFocusListener(new FocusAdapter() { + public void focusLost(FocusEvent ev) { + d = new Dialog(f, "Dialog", true); + d.setBounds(300, 300, 200, 150); + d.addKeyListener(new KeyAdapter() { + public void keyPressed(KeyEvent ev) { + keyOK = true; + } + }); + d.addMouseListener(new MouseAdapter() { + public void mousePressed(MouseEvent ev) { + mouseOK = true; + } + }); + d.setVisible(true); + } + }); + + f.setVisible(true); + f.toFront(); + }); + r.waitForIdle(); + r.delay(1000); + EventQueue.invokeAndWait(() -> { + r.mouseMove(tf.getLocationOnScreen().x + tf.getSize().width / 2, + tf.getLocationOnScreen().y + tf.getSize().height / 2); + }); + r.waitForIdle(); + r.delay(500); + EventQueue.invokeAndWait(() -> { + r.mouseMove(c.getLocationOnScreen().x + c.getSize().width - 4, + c.getLocationOnScreen().y + c.getSize().height / 2); + r.mousePress(InputEvent.BUTTON1_DOWN_MASK); + r.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + }); + r.waitForIdle(); + r.delay(500); + EventQueue.invokeAndWait(() -> { + r.mouseMove(d.getLocationOnScreen().x + d.getSize().width / 2, + d.getLocationOnScreen().y + d.getSize().height / 2); + r.mousePress(InputEvent.BUTTON1_DOWN_MASK); + r.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + r.keyPress(KeyEvent.VK_A); + r.keyRelease(KeyEvent.VK_A); + }); + r.waitForIdle(); + r.delay(500); + if (!mouseOK) { + throw new RuntimeException("Test Failed due to Mouse release failure!"); + } + if (!keyOK) { + throw new RuntimeException("Test Failed due to Key release failure!"); + } + System.out.println("Test Passed!"); + } finally { + EventQueue.invokeAndWait(() -> { + if (d != null) { + d.dispose(); + } + if (f != null) { + f.dispose(); + } + }); + } + } +} diff --git a/test/jdk/java/awt/Dialog/DialogBackgroundTest.java b/test/jdk/java/awt/Dialog/DialogBackgroundTest.java new file mode 100644 index 0000000000000..793782fc43be8 --- /dev/null +++ b/test/jdk/java/awt/Dialog/DialogBackgroundTest.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * 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 4255230 4191946 + * @summary Tests to verify Dialog inherits background from its owner + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DialogBackgroundTest + */ + +import java.awt.Button; +import java.awt.Color; +import java.awt.Dialog; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.TextField; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +public class DialogBackgroundTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Perform the following steps: + 1) Select "New Frame" from the "File" menu of the + "TreeCopy Frame #1" frame. + 2) Select "Configure" from the "File" menu in the + *new* frame. + If label text "This is a label:" in the appeared + "Configuration Dialog" dialog has a grey background + test PASSES, otherwise it FAILS + """; + TreeCopy treeCopy = new TreeCopy(++TreeCopy.windowCount, null); + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(treeCopy) + .logArea(8) + .build() + .awaitAndCheck(); + } +} + +class TreeCopy extends Frame implements ActionListener { + TextField tfRoot; + ConfigDialog configDlg; + MenuItem miConfigure = new MenuItem("Configure..."); + MenuItem miNewWindow = new MenuItem("New Frame"); + static int windowCount = 0; + Window parent; + + public TreeCopy(int windowNum, Window myParent) { + super(); + setTitle("TreeCopy Frame #" + windowNum); + MenuBar mb = new MenuBar(); + Menu m = new Menu("File"); + configDlg = new ConfigDialog(this); + parent = myParent; + + m.add(miConfigure); + m.add(miNewWindow); + miConfigure.addActionListener(this); + miNewWindow.addActionListener(this); + mb.add(m); + setMenuBar(mb); + m.addActionListener(this); + + tfRoot = new TextField(); + tfRoot.setEditable(false); + add(tfRoot); + + addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent we) { + dispose(); + } + }); + + setSize(200, 100); + setLocationRelativeTo(parent); + } + + public void actionPerformed(ActionEvent ae) { + Object source = ae.getSource(); + + if (source == miConfigure) { + configDlg.setVisible(true); + if (configDlg.getBackground() != configDlg.labelColor) + PassFailJFrame.log("FAIL: Test failed!!!"); + } else if (source == miNewWindow) { + new TreeCopy(++windowCount, this).setVisible(true); + } + } +} + +class ConfigDialog extends Dialog implements ActionListener { + public Button okButton; + public Button cancelButton; + public Label l2; + public Color labelColor; + + public ConfigDialog(Frame parent) { + super(parent, "Configuration Dialog"); + okButton = new Button("OK"); + cancelButton = new Button("Cancel"); + l2 = new Label("This is a label:"); + + setLayout(new FlowLayout()); + add(l2); + add(okButton); + add(cancelButton); + + okButton.addActionListener(this); + cancelButton.addActionListener(this); + + pack(); + labelColor = l2.getBackground(); + } + + public void actionPerformed(ActionEvent ae) { + dispose(); + } +} diff --git a/test/jdk/java/awt/Dialog/EnabledResetTest.java b/test/jdk/java/awt/Dialog/EnabledResetTest.java new file mode 100644 index 0000000000000..d71c9b1801b22 --- /dev/null +++ b/test/jdk/java/awt/Dialog/EnabledResetTest.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * 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 4232374 + * @summary Tests that dismissing a modal dialog does not enable + * disabled components + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual EnabledResetTest + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Dialog; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class EnabledResetTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Press "Create Child" twice to create three windows + Verify that the parent windows are disabled + 2. Press "Create Modal Dialog" + Verify that the parent windows are disabled + 3. Press "enable" + Verify that no windows accept mouse events + 4. Press "ok" + Verify that the first window is still disabled + If all the verifications are done, then test is + PASSED, else test fails. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(new ChildDialog(1, null)) + .build() + .awaitAndCheck(); + } +} + +class ChildDialog extends Frame implements ActionListener { + Window parent; + int id; + Button b, c, d; + + public ChildDialog(int frameNumber, Window myParent) { + super(); + id = frameNumber; + parent = myParent; + + setTitle("Frame Number " + id); + + b = new Button("Dismiss me"); + c = new Button("Create Child"); + d = new Button("Create Modal Dialog"); + + setLayout(new BorderLayout()); + add("North", c); + add("Center", d); + add("South", b); + pack(); + + b.addActionListener(this); + c.addActionListener(this); + d.addActionListener(this); + } + + public void setVisible(boolean b) { + if (parent != null) { + if (b) { + parent.setEnabled(false); + } else { + parent.setEnabled(true); + parent.requestFocus(); + } + } + + super.setVisible(b); + } + + public void dispose() { + if (parent != null) { + parent.setEnabled(true); + parent.requestFocus(); + } + super.dispose(); + } + + + public void actionPerformed(ActionEvent evt) { + if (evt.getSource() == c) { + (new ChildDialog(id + 1, this)).setVisible(true); + } else if (evt.getSource() == d) { + Dialog D = new Dialog(this, "Modal Dialog "); + D.setLayout(new FlowLayout()); + Button b = new Button("ok"); + Button e = new Button("enable"); + D.add(b); + D.add(e); + D.setModal(true); + D.pack(); + b.addActionListener(this); + e.addActionListener(this); + D.setVisible(true); + } else if (evt.getSource() == b) { + dispose(); + } else if (evt.getSource() instanceof Button) { + if ("ok".equals(evt.getActionCommand())) { + Button target = (Button) evt.getSource(); + Window w = (Window) target.getParent(); + w.dispose(); + } + if ("enable".equals(evt.getActionCommand())) { + parent.setEnabled(true); + } + } + } +} diff --git a/test/jdk/java/awt/Dialog/FileDialogGetFileTest.java b/test/jdk/java/awt/Dialog/FileDialogGetFileTest.java new file mode 100644 index 0000000000000..d4670cceb601e --- /dev/null +++ b/test/jdk/java/awt/Dialog/FileDialogGetFileTest.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * 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 4414105 + * @summary Tests that FileDialog returns null when cancelled + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FileDialogGetFileTest + */ + +import java.awt.Button; +import java.awt.FileDialog; +import java.awt.Frame; + +public class FileDialogGetFileTest { + static FileDialog fd; + static Frame frame; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Open FileDialog from "Show File Dialog" button. + 2. Click cancel button without selecting any file/folder. + 3. If FileDialog.getFile return null then test PASSES, + else test FAILS automatically. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .logArea(4) + .build() + .awaitAndCheck(); + } + + public static Frame initialize() { + frame = new Frame("FileDialog GetFile test"); + fd = new FileDialog(frame); + fd.setFile("FileDialogGetFileTest.html"); + fd.setBounds(100, 100, 400, 400); + Button showBtn = new Button("Show File Dialog"); + frame.add(showBtn); + frame.pack(); + showBtn.addActionListener(e -> { + fd.setVisible(true); + if (fd.getFile() != null) { + PassFailJFrame.forceFail("Test failed: FileDialog returned non-null value"); + } else { + PassFailJFrame.log("Test Passed!"); + } + }); + return frame; + } +} From e94e3bba3932f3d92c0a135d333d1ccd6e72b964 Mon Sep 17 00:00:00 2001 From: Ramkumar Sunderbabu Date: Wed, 16 Oct 2024 06:52:42 +0000 Subject: [PATCH 080/118] 8324672: Update jdk/java/time/tck/java/time/TCKInstant.java now() to be more robust Reviewed-by: rriggs, dfuchs --- .../java/time/tck/java/time/TCKInstant.java | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/test/jdk/java/time/tck/java/time/TCKInstant.java b/test/jdk/java/time/tck/java/time/TCKInstant.java index d7a6341527962..c666a1340d388 100644 --- a/test/jdk/java/time/tck/java/time/TCKInstant.java +++ b/test/jdk/java/time/tck/java/time/TCKInstant.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -187,10 +187,21 @@ public void constant_MAX() { //----------------------------------------------------------------------- @Test public void now() { - Instant expected = Instant.now(Clock.systemUTC()); - Instant test = Instant.now(); - long diff = Math.abs(test.toEpochMilli() - expected.toEpochMilli()); - assertTrue(diff < 100); // less than 0.1 secs + long beforeMillis, instantMillis, afterMillis, diff; + int retryRemaining = 5; // MAX_RETRY_COUNT + do { + beforeMillis = Instant.now(Clock.systemUTC()).toEpochMilli(); + instantMillis = Instant.now().toEpochMilli(); + afterMillis = Instant.now(Clock.systemUTC()).toEpochMilli(); + diff = instantMillis - beforeMillis; + if (instantMillis < beforeMillis || instantMillis > afterMillis) { + throw new RuntimeException(": Invalid instant: (~" + instantMillis + "ms)" + + " when systemUTC in millis is in [" + + beforeMillis + ", " + + afterMillis + "]"); + } + } while (diff > 100 && --retryRemaining > 0); // retry if diff more than 0.1 sec + assertTrue(retryRemaining > 0); } //----------------------------------------------------------------------- From e4ff553c121e29c497336fdde705e70d0abdc826 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 16 Oct 2024 07:05:17 +0000 Subject: [PATCH 081/118] 8341931: os_linux gtest uses lambdas with explicit capture lists Reviewed-by: jwaters, jsjolen --- test/hotspot/gtest/runtime/test_os_linux.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/hotspot/gtest/runtime/test_os_linux.cpp b/test/hotspot/gtest/runtime/test_os_linux.cpp index 387940afdf296..77b83ac1bd74d 100644 --- a/test/hotspot/gtest/runtime/test_os_linux.cpp +++ b/test/hotspot/gtest/runtime/test_os_linux.cpp @@ -360,10 +360,10 @@ TEST_VM(os_linux, pretouch_thp_and_use_concurrent) { EXPECT_TRUE(os::commit_memory(heap, size, false)); { - auto pretouch = [heap](Thread*, int) { + auto pretouch = [&](Thread*, int) { os::pretouch_memory(heap, heap + size, os::vm_page_size()); }; - auto useMemory = [heap](Thread*, int) { + auto useMemory = [&](Thread*, int) { int* iptr = reinterpret_cast(heap); for (int i = 0; i < 1000; i++) *iptr++ = i; }; From 724de682091623cd9877ee4e5f13123ef1d92ddf Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 16 Oct 2024 07:13:59 +0000 Subject: [PATCH 082/118] 8342081: Shenandoah: Remove extra ShenandoahMarkUpdateRefsSuperClosure Reviewed-by: ysr --- .../gc/shenandoah/shenandoahOopClosures.hpp | 26 ++++++------------- .../shenandoahOopClosures.inline.hpp | 5 ++-- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.hpp b/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.hpp index e433c2910c8d8..e6baa4096f0a1 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.hpp @@ -61,33 +61,23 @@ class ShenandoahMarkRefsSuperClosure : public MetadataVisitingOopIterateClosure } }; -class ShenandoahMarkUpdateRefsSuperClosure : public ShenandoahMarkRefsSuperClosure { -protected: +template +class ShenandoahMarkUpdateRefsClosure : public ShenandoahMarkRefsSuperClosure { +private: ShenandoahHeap* const _heap; - template + template inline void work(T* p); public: - ShenandoahMarkUpdateRefsSuperClosure(ShenandoahObjToScanQueue* q, ShenandoahReferenceProcessor* rp) : + ShenandoahMarkUpdateRefsClosure(ShenandoahObjToScanQueue* q, ShenandoahReferenceProcessor* rp) : ShenandoahMarkRefsSuperClosure(q, rp), _heap(ShenandoahHeap::heap()) { assert(_heap->is_stw_gc_in_progress(), "Can only be used for STW GC"); - }; -}; - -template -class ShenandoahMarkUpdateRefsClosure : public ShenandoahMarkUpdateRefsSuperClosure { -private: - template - inline void do_oop_work(T* p) { work(p); } - -public: - ShenandoahMarkUpdateRefsClosure(ShenandoahObjToScanQueue* q, ShenandoahReferenceProcessor* rp) : - ShenandoahMarkUpdateRefsSuperClosure(q, rp) {} + } - virtual void do_oop(narrowOop* p) { do_oop_work(p); } - virtual void do_oop(oop* p) { do_oop_work(p); } + virtual void do_oop(narrowOop* p) { work(p); } + virtual void do_oop(oop* p) { work(p); } }; template diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.inline.hpp index 70d7e94fb503f..e0662c24462f8 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.inline.hpp @@ -35,8 +35,9 @@ inline void ShenandoahMarkRefsSuperClosure::work(T* p) { ShenandoahMark::mark_through_ref(p, _queue, _mark_context, _weak); } -template -inline void ShenandoahMarkUpdateRefsSuperClosure::work(T* p) { +template +template +inline void ShenandoahMarkUpdateRefsClosure::work(T* p) { // Update the location _heap->update_with_forwarded(p); From b9b0bd0871886eb65f87864f262424b119f2c748 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Wed, 16 Oct 2024 07:23:12 +0000 Subject: [PATCH 083/118] 8337221: CompileFramework: test library to conveniently compile java and jasm sources for fuzzing Reviewed-by: chagedorn, tholenstein --- .../compile_framework/ClassLoaderBuilder.java | 64 ++++++ .../lib/compile_framework/Compile.java | 202 ++++++++++++++++++ .../compile_framework/CompileFramework.java | 169 +++++++++++++++ .../CompileFrameworkException.java | 37 ++++ .../InternalCompileFrameworkException.java | 37 ++++ .../compiler/lib/compile_framework/README.md | 57 +++++ .../lib/compile_framework/SourceCode.java | 35 +++ .../compiler/lib/compile_framework/Utils.java | 81 +++++++ .../examples/CombinedJavaJasmExample.java | 114 ++++++++++ .../examples/IRFrameworkJavaExample.java | 156 ++++++++++++++ .../examples/MultiFileJasmExample.java | 88 ++++++++ .../examples/MultiFileJavaExample.java | 81 +++++++ .../examples/RunWithFlagsExample.java | 99 +++++++++ .../examples/SimpleJasmExample.java | 79 +++++++ .../examples/SimpleJavaExample.java | 73 +++++++ .../tests/TestBadJasmCompilation.java | 62 ++++++ .../tests/TestBadJavaCompilation.java | 62 ++++++ .../tests/TestConcurrentCompilation.java | 108 ++++++++++ 18 files changed, 1604 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/lib/compile_framework/ClassLoaderBuilder.java create mode 100644 test/hotspot/jtreg/compiler/lib/compile_framework/Compile.java create mode 100644 test/hotspot/jtreg/compiler/lib/compile_framework/CompileFramework.java create mode 100644 test/hotspot/jtreg/compiler/lib/compile_framework/CompileFrameworkException.java create mode 100644 test/hotspot/jtreg/compiler/lib/compile_framework/InternalCompileFrameworkException.java create mode 100644 test/hotspot/jtreg/compiler/lib/compile_framework/README.md create mode 100644 test/hotspot/jtreg/compiler/lib/compile_framework/SourceCode.java create mode 100644 test/hotspot/jtreg/compiler/lib/compile_framework/Utils.java create mode 100644 test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/CombinedJavaJasmExample.java create mode 100644 test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/IRFrameworkJavaExample.java create mode 100644 test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/MultiFileJasmExample.java create mode 100644 test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/MultiFileJavaExample.java create mode 100644 test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/RunWithFlagsExample.java create mode 100644 test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/SimpleJasmExample.java create mode 100644 test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/SimpleJavaExample.java create mode 100644 test/hotspot/jtreg/testlibrary_tests/compile_framework/tests/TestBadJasmCompilation.java create mode 100644 test/hotspot/jtreg/testlibrary_tests/compile_framework/tests/TestBadJavaCompilation.java create mode 100644 test/hotspot/jtreg/testlibrary_tests/compile_framework/tests/TestConcurrentCompilation.java diff --git a/test/hotspot/jtreg/compiler/lib/compile_framework/ClassLoaderBuilder.java b/test/hotspot/jtreg/compiler/lib/compile_framework/ClassLoaderBuilder.java new file mode 100644 index 0000000000000..2f14cfb0f0489 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/compile_framework/ClassLoaderBuilder.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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.lib.compile_framework; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +/** + * Build a ClassLoader that loads from classpath and {@code classesDir}. + * Helper class that generates a ClassLoader which allows loading classes + * from the classpath (see {@link Utils#getClassPaths()}) and {@code classesDir}. + *

    + * The CompileFramework compiles all its classes to a specific {@code classesDir}, + * and this generated ClassLoader thus can be used to load those classes. + */ +class ClassLoaderBuilder { + + /** + * Build a ClassLoader that loads from classpath and {@code classesDir}. + */ + public static ClassLoader build(Path classesDir) { + ClassLoader sysLoader = ClassLoader.getSystemClassLoader(); + + try { + // Classpath for all included classes (e.g. IR Framework). + // Get all class paths, convert to URLs. + List urls = new ArrayList<>(); + for (String path : Utils.getClassPaths()) { + urls.add(new File(path).toURI().toURL()); + } + // And add in the compiled classes from this instance of CompileFramework. + urls.add(new File(classesDir.toString()).toURI().toURL()); + return URLClassLoader.newInstance(urls.toArray(URL[]::new), sysLoader); + } catch (IOException e) { + throw new CompileFrameworkException("IOException while creating ClassLoader", e); + } + } +} diff --git a/test/hotspot/jtreg/compiler/lib/compile_framework/Compile.java b/test/hotspot/jtreg/compiler/lib/compile_framework/Compile.java new file mode 100644 index 0000000000000..0f45d982af6d6 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/compile_framework/Compile.java @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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.lib.compile_framework; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.concurrent.TimeUnit; +import java.util.List; +import jdk.test.lib.JDKToolFinder; + +/** + * Helper class for compilation of Java and Jasm {@link SourceCode}. + */ +class Compile { + private static final int COMPILE_TIMEOUT = 60; + + private static final String JAVA_PATH = JDKToolFinder.getJDKTool("java"); + private static final String JAVAC_PATH = JDKToolFinder.getJDKTool("javac"); + + /** + * Compile all sources in {@code javaSources}. First write them to the {@code sourceDir}, + * then compile them to class-files which are stored in {@code classesDir}. + */ + public static void compileJavaSources(List javaSources, Path sourceDir, Path classesDir) { + if (javaSources.isEmpty()) { + Utils.printlnVerbose("No java sources to compile."); + return; + } + Utils.printlnVerbose("Compiling Java sources: " + javaSources.size()); + + List javaFilePaths = writeSourcesToFiles(javaSources, sourceDir); + compileJavaFiles(javaFilePaths, classesDir); + Utils.printlnVerbose("Java sources compiled."); + } + + /** + * Compile a list of files (i.e. {@code paths}) using javac and store + * them in {@code classesDir}. + */ + private static void compileJavaFiles(List paths, Path classesDir) { + List command = new ArrayList<>(); + + command.add(JAVAC_PATH); + command.add("-classpath"); + // Note: the backslashes from windows paths must be escaped! + command.add(Utils.getEscapedClassPathAndClassesDir(classesDir)); + command.add("-d"); + command.add(classesDir.toString()); + for (Path path : paths) { + command.add(path.toAbsolutePath().toString()); + } + + executeCompileCommand(command); + } + + /** + * Compile all sources in {@code jasmSources}. First write them to the {@code sourceDir}, + * then compile them to class-files which are stored in {@code classesDir}. + */ + public static void compileJasmSources(List jasmSources, Path sourceDir, Path classesDir) { + if (jasmSources.isEmpty()) { + Utils.printlnVerbose("No jasm sources to compile."); + return; + } + Utils.printlnVerbose("Compiling jasm sources: " + jasmSources.size()); + + List jasmFilePaths = writeSourcesToFiles(jasmSources, sourceDir); + compileJasmFiles(jasmFilePaths, classesDir); + Utils.printlnVerbose("Jasm sources compiled."); + } + + /** + * Compile a list of files (i.e. {@code paths}) using asmtools jasm and store + * them in {@code classesDir}. + */ + private static void compileJasmFiles(List paths, Path classesDir) { + List command = new ArrayList<>(); + + command.add(JAVA_PATH); + command.add("-classpath"); + command.add(getAsmToolsPath()); + command.add("org.openjdk.asmtools.jasm.Main"); + command.add("-d"); + command.add(classesDir.toString()); + for (Path path : paths) { + command.add(path.toAbsolutePath().toString()); + } + + executeCompileCommand(command); + } + + /** + * Get the path of asmtools, which is shipped with JTREG. + */ + private static String getAsmToolsPath() { + for (String path : Utils.getClassPaths()) { + if (path.endsWith("jtreg.jar")) { + File jtreg = new File(path); + File dir = jtreg.getAbsoluteFile().getParentFile(); + File asmtools = new File(dir, "asmtools.jar"); + if (!asmtools.exists()) { + throw new InternalCompileFrameworkException("Found jtreg.jar in classpath, but could not find asmtools.jar"); + } + return asmtools.getAbsolutePath(); + } + } + throw new InternalCompileFrameworkException("Could not find asmtools because could not find jtreg.jar in classpath"); + } + + private static void writeCodeToFile(String code, Path path) { + Utils.printlnVerbose("File: " + path); + + // Ensure directory of the file exists. + Path dir = path.getParent(); + try { + Files.createDirectories(dir); + } catch (Exception e) { + throw new CompileFrameworkException("Could not create directory: " + dir, e); + } + + // Write to file. + try (BufferedWriter writer = Files.newBufferedWriter(path)) { + writer.write(code); + } catch (Exception e) { + throw new CompileFrameworkException("Could not write file: " + path, e); + } + } + + /** + * Write each source in {@code sources} to a file inside {@code sourceDir}. + */ + private static List writeSourcesToFiles(List sources, Path sourceDir) { + List storedFiles = new ArrayList<>(); + for (SourceCode sourceCode : sources) { + Path path = sourceDir.resolve(sourceCode.filePathName()); + writeCodeToFile(sourceCode.code(), path); + storedFiles.add(path); + } + return storedFiles; + } + + /** + * Execute a given compilation, given as a {@code command}. + */ + private static void executeCompileCommand(List command) { + Utils.printlnVerbose("Compile command: " + String.join(" ", command)); + + ProcessBuilder builder = new ProcessBuilder(command); + builder.redirectErrorStream(true); + + String output; + int exitCode; + try { + Process process = builder.start(); + boolean exited = process.waitFor(COMPILE_TIMEOUT, TimeUnit.SECONDS); + if (!exited) { + process.destroyForcibly(); + System.out.println("Timeout: compile command: " + String.join(" ", command)); + throw new InternalCompileFrameworkException("Process timeout: compilation took too long."); + } + output = new String(process.getInputStream().readAllBytes(), StandardCharsets.UTF_8); + exitCode = process.exitValue(); + } catch (IOException e) { + throw new InternalCompileFrameworkException("IOException during compilation", e); + } catch (InterruptedException e) { + throw new CompileFrameworkException("InterruptedException during compilation", e); + } + + if (exitCode != 0 || !output.isEmpty()) { + System.err.println("Compilation failed."); + System.err.println("Exit code: " + exitCode); + System.err.println("Output: '" + output + "'"); + throw new CompileFrameworkException("Compilation failed."); + } + } +} diff --git a/test/hotspot/jtreg/compiler/lib/compile_framework/CompileFramework.java b/test/hotspot/jtreg/compiler/lib/compile_framework/CompileFramework.java new file mode 100644 index 0000000000000..fe23d596f3c64 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/compile_framework/CompileFramework.java @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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.lib.compile_framework; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +/** + * This is the entry-point for the Compile Framework. Its purpose it to allow + * compilation and execution of Java and Jasm sources generated at runtime. + * + *

    Please reference the README.md for more details and examples. + */ +public class CompileFramework { + private final List javaSources = new ArrayList<>(); + private final List jasmSources = new ArrayList<>(); + private final Path sourceDir = Utils.makeUniqueDir("compile-framework-sources-"); + private final Path classesDir = Utils.makeUniqueDir("compile-framework-classes-"); + private ClassLoader classLoader; + + /** + * Set up a new Compile Framework instance, for a new compilation unit. + */ + public CompileFramework() {} + + /** + * Add a Java source to the compilation. + * + * @param className Class name of the class (e.g. "{@code p.xyz.YXZ}"). + * @param code Java code for the class, in the form of a {@link String}. + */ + public void addJavaSourceCode(String className, String code) { + javaSources.add(new SourceCode(className, "java", code)); + } + + /** + * Add a Jasm source to the compilation. + * + * @param className Class name of the class (e.g. "{@code p.xyz.YXZ}"). + * @param code Jasm code for the class, in the form of a {@link String}. + */ + public void addJasmSourceCode(String className, String code) { + jasmSources.add(new SourceCode(className, "jasm", code)); + } + + /** + * Compile all sources: store the sources to the {@link sourceDir} directory, compile + * Java and Jasm sources and store the generated class-files in the {@link classesDir} + * directory. + */ + public void compile() { + if (classLoader != null) { + throw new CompileFrameworkException("Cannot compile twice!"); + } + + Utils.printlnVerbose("------------------ CompileFramework: SourceCode -------------------"); + Utils.printlnVerbose(sourceCodesAsString(jasmSources)); + Utils.printlnVerbose(sourceCodesAsString(javaSources)); + + System.out.println("------------------ CompileFramework: Compilation ------------------"); + System.out.println("Source directory: " + sourceDir); + System.out.println("Classes directory: " + classesDir); + + Compile.compileJasmSources(jasmSources, sourceDir, classesDir); + Compile.compileJavaSources(javaSources, sourceDir, classesDir); + classLoader = ClassLoaderBuilder.build(classesDir); + } + + private static String sourceCodesAsString(List sourceCodes) { + StringBuilder builder = new StringBuilder(); + for (SourceCode sourceCode : sourceCodes) { + builder.append("SourceCode: ").append(sourceCode.filePathName()).append(System.lineSeparator()); + builder.append(sourceCode.code()).append(System.lineSeparator()); + } + return builder.toString(); + } + + /** + * Access a class from the compiled code. + * + * @param name Name of the class to be retrieved. + * @return The class corresponding to the {@code name}. + */ + public Class getClass(String name) { + try { + return Class.forName(name, true, classLoader); + } catch (ClassNotFoundException e) { + throw new CompileFrameworkException("Class not found:", e); + } + } + + /** + * Invoke a static method from the compiled code. + * + * @param className Class name of a compiled class. + * @param methodName Method name of the class. + * @param args List of arguments for the method invocation. + * @return Return value from the invocation. + */ + public Object invoke(String className, String methodName, Object[] args) { + Method method = findMethod(className, methodName); + + try { + return method.invoke(null, args); + } catch (IllegalAccessException e) { + throw new CompileFrameworkException("Illegal access:", e); + } catch (InvocationTargetException e) { + throw new CompileFrameworkException("Invocation target:", e); + } + } + + private Method findMethod(String className, String methodName) { + Class c = getClass(className); + Method[] methods = c.getDeclaredMethods(); + Method method = null; + + for (Method m : methods) { + if (m.getName().equals(methodName)) { + if (method != null) { + throw new CompileFrameworkException("Method name \"" + methodName + "\" not unique in class \n" + className + "\"."); + } + method = m; + } + } + + if (method == null) { + throw new CompileFrameworkException("Method \"" + methodName + "\" not found in class \n" + className + "\"."); + } + + return method; + } + + /** + * Returns the classpath appended with the {@link classesDir}, where + * the compiled classes are stored. This enables another VM to load + * the compiled classes. Note, the string is already backslash escaped, + * so that Windows paths which use backslashes can be used directly + * as strings. + * + * @return Classpath appended with the path to the compiled classes. + */ + public String getEscapedClassPathOfCompiledClasses() { + return Utils.getEscapedClassPathAndClassesDir(classesDir); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/compile_framework/CompileFrameworkException.java b/test/hotspot/jtreg/compiler/lib/compile_framework/CompileFrameworkException.java new file mode 100644 index 0000000000000..5c71a33a533fd --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/compile_framework/CompileFrameworkException.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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.lib.compile_framework; + +/** + * Exception thrown in the Compilation Framework. Most likely, the user is responsible for the failure. + */ +public class CompileFrameworkException extends RuntimeException { + public CompileFrameworkException(String message) { + super("Exception in Compile Framework:" + System.lineSeparator() + message); + } + + public CompileFrameworkException(String message, Throwable e) { + super("Exception in Compile Framework:" + System.lineSeparator() + message, e); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/compile_framework/InternalCompileFrameworkException.java b/test/hotspot/jtreg/compiler/lib/compile_framework/InternalCompileFrameworkException.java new file mode 100644 index 0000000000000..0cfed80ce1cd6 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/compile_framework/InternalCompileFrameworkException.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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.lib.compile_framework; + +/** + * Internal exception thrown in Compilation Framework. Most likely, this is due to a bug in the CompileFramework. + */ +public class InternalCompileFrameworkException extends RuntimeException { + public InternalCompileFrameworkException(String message) { + super("Internal exception in Compile Framework, please file a bug:" + System.lineSeparator() + message); + } + + public InternalCompileFrameworkException(String message, Throwable e) { + super("Internal exception in Compile Framework, please file a bug:" + System.lineSeparator() + message, e); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/compile_framework/README.md b/test/hotspot/jtreg/compiler/lib/compile_framework/README.md new file mode 100644 index 0000000000000..76ddf677811c7 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/compile_framework/README.md @@ -0,0 +1,57 @@ +# Compile Framework +The Compile Framework allows the compilation and execution of Java and Jasm sources, which are generated at runtime. + +## Motivation +We want to be able to generate Java and Jasm source code in the form of Strings at runtime, then compile them, load the classes and invoke some methods. This allows us to write more elaborate tests. For example small dedicated fuzzers that are targetted at some specific compiler optimization. + +This is more powerful than hand-written tests, as we can generalize tests and cover more examples. It can also be better than a script-generated test: those are static and often the script is not integrated with the generated test. Another limitation of a generator script is that it is only run once, creating fixed static tests. Compilation at runtime allows us to randomly generate tests each time. + +Of course we could compile at runtime without this framework, but it abstracts away the complexity of compilation, and allows the test-writer to focus on the generation of the source code. + +## How to Use the Compile Framework + +Please reference the examples found in [examples](../../../testlibrary_tests/compile_framework/examples/). Some basic tests can be found in [tests](../../../testlibrary_tests/compile_framework/tests/). + +Here a very simple example: + + // Create a new CompileFramework instance. + CompileFramework compileFramework = new CompileFramework(); + + // Add a java source file. + compileFramework.addJavaSourceCode("XYZ", ""); + + // Compile the source file. + compileFramework.compile(); + + // Object returnValue = XYZ.test(5); + Object returnValue = compileFramework.invoke("XYZ", "test", new Object[] {5}); + +### Creating a new Compile Framework Instance + +First, one must create a `new CompileFramework()`, which creates two directories: a sources and a classes directory (see `sourcesDir` and `classesDir` in [CompileFramework](./CompileFramework.java)). The sources directory is where all the sources are placed by the Compile Framework, and the classes directory is where all the compiled classes are placed by the Compile Framework. + +The Compile Framework prints the names of the directories, they are subdirectories of the JTREG scratch directory `JTWork/scratch`. + +### Adding Sources to the Compilation + +Java and Jasm sources can be added to the compilation using `compileFramework.addJavaSourceCode()` and `compileFramework.addJasmSourceCode()`. The source classes can depend on each other, and they can also use the IR Framework ([IRFrameworkJavaExample](../../../testlibrary_tests/compile_framework/examples/IRFrameworkJavaExample.java)). + +When using the IR Framework, or any other library that needs to be compiled, it can be necessary to explicitly let JTREG compile that library. For example with `@compile ../../../compiler/lib/ir_framework/TestFramework.java`. Otherwise, the corresponding class files may not be available, and a corresponding failure will be encounter at class loading. + +### Compiling + +All sources are compiled with `compileFramework.compile()`. First, the sources are stored to the sources directory, then compiled, and then the class-files stored in the classes directory. The respective directory names are printed, so that the user can easily access the generated files for debugging. + +### Interacting with the Compiled Code + +The compiled code is then loaded with a `ClassLoader`. The classes can be accessed directly with `compileFramework.getClass(name)`. Specific methods can also directly be invoked with `compileFramework.invoke()`. + +Should one require the modified classpath that includes the compiled classes, this is available with `compileFramework.getEscapedClassPathOfCompiledClasses()`. This can be necessary if the test launches any other VMs that also access the compiled classes. This is for example necessary when using the IR Framework. + +### Running the Compiled Code in a New VM + +One can also run the compiled code in a new VM. For this, one has to set the classpath with `compileFramework.getEscapedClassPathOfCompiledClasses()` ([RunWithFlagsExample](../../../testlibrary_tests/compile_framework/examples/RunWithFlagsExample.java)) + +### Verbose Printing + +For debugging purposes, one can enable verbose printing, with `-DCompileFrameworkVerbose=true`. diff --git a/test/hotspot/jtreg/compiler/lib/compile_framework/SourceCode.java b/test/hotspot/jtreg/compiler/lib/compile_framework/SourceCode.java new file mode 100644 index 0000000000000..df38e420758e6 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/compile_framework/SourceCode.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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.lib.compile_framework; + +/** + * This class represents the source code of a specific class. + */ +record SourceCode(String className, String extension, String code) { + public String filePathName() { + StringBuilder builder = new StringBuilder(); + builder.append(className.replace('.','/')).append(".").append(extension); + return builder.toString(); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/compile_framework/Utils.java b/test/hotspot/jtreg/compiler/lib/compile_framework/Utils.java new file mode 100644 index 0000000000000..0ac2720f33b19 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/compile_framework/Utils.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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.lib.compile_framework; + +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.Path; +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +/** + * Utility class, with many helper methods for the Compile Framework. + */ +class Utils { + private static final boolean VERBOSE = Boolean.getBoolean("CompileFrameworkVerbose"); + + /** + * Verbose printing, enabled with {@code -DCompileFrameworkVerbose=true}. + */ + public static void printlnVerbose(String s) { + if (VERBOSE) { + System.out.println(s); + } + } + + /** + * Create a temporary directory with a unique name to avoid collisions + * with multi-threading. Used to create the sources and classes directories. Since they + * are unique even across threads, the Compile Framework is multi-threading safe, i.e. + * it does not have collisions if two instances generate classes with the same name. + */ + public static Path makeUniqueDir(String prefix) { + try { + return Files.createTempDirectory(Paths.get("."), prefix); + } catch (Exception e) { + throw new InternalCompileFrameworkException("Could not set up temporary directory", e); + } + } + + /** + * Get all paths in the classpath. + */ + public static String[] getClassPaths() { + String separator = File.pathSeparator; + return System.getProperty("java.class.path").split(separator); + } + + /** + * Return the classpath, appended with the {@code classesDir}. + */ + public static String getEscapedClassPathAndClassesDir(Path classesDir) { + String cp = System.getProperty("java.class.path") + + File.pathSeparator + + classesDir.toAbsolutePath(); + // Escape the backslash for Windows paths. We are using the path in the + // command-line and Java code, so we always want it to be escaped. + return cp.replace("\\", "\\\\"); + } +} diff --git a/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/CombinedJavaJasmExample.java b/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/CombinedJavaJasmExample.java new file mode 100644 index 0000000000000..565c92c1b7068 --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/CombinedJavaJasmExample.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 + * @summary Example test to use the Compile Framework. + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @run driver compile_framework.examples.CombinedJavaJasmExample + */ + +package compile_framework.examples; + +import compiler.lib.compile_framework.*; + +/** + * This test shows a compilation of multiple Java and Jasm source code files. + * In this example, the classes even reference each other. + */ +public class CombinedJavaJasmExample { + + // Generate a source jasm file as String + public static String generateJasm() { + return """ + package p/xyz; + + super public class XYZJasm { + public static Method test:"(I)I" + stack 20 locals 20 + { + iload_0; + iconst_2; + imul; + invokestatic Method p/xyz/XYZJava."mul3":"(I)I"; + ireturn; + } + + public static Method mul5:"(I)I" + stack 20 locals 20 + { + iload_0; + ldc 5; + imul; + ireturn; + } + } + """; + } + + // Generate a source java file as String + public static String generateJava() { + return """ + package p.xyz; + + public class XYZJava { + public static int test(int i) { + return p.xyz.XYZJasm.mul5(i * 7); + } + + public static int mul3(int i) { + return i * 3; + } + } + """; + } + + public static void main(String[] args) { + // Create a new CompileFramework instance. + CompileFramework comp = new CompileFramework(); + + // Generate files. + comp.addJasmSourceCode("p.xyz.XYZJasm", generateJasm()); + comp.addJavaSourceCode("p.xyz.XYZJava", generateJava()); + + // Compile the source files. + comp.compile(); + + test(comp, "p.xyz.XYZJasm", "test", 11, 11 * 2 * 3); + test(comp, "p.xyz.XYZJava", "test", 13, 13 * 7 * 5); + + System.out.println("Success."); + } + + public static void test(CompileFramework comp, String className, String methodName, int input, int expected) { + Object ret = comp.invoke(className, methodName, new Object[] {input}); + + // Extract return value of invocation, verify its value. + int i = (int)ret; + System.out.println("Result of call: " + i + " vs expected: " + expected); + if (i != expected) { + throw new RuntimeException("wrong value: " + i); + } + } +} diff --git a/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/IRFrameworkJavaExample.java b/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/IRFrameworkJavaExample.java new file mode 100644 index 0000000000000..11b8828d7530d --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/IRFrameworkJavaExample.java @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 + * @summary Example test to use the Compile Framework together with the IR Framework (i.e. TestFramework). + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @compile ../../../compiler/lib/ir_framework/TestFramework.java + * @run driver compile_framework.examples.IRFrameworkJavaExample + */ + +package compile_framework.examples; + +import compiler.lib.compile_framework.*; +import jdk.test.lib.Utils; +import jdk.test.lib.Platform; +import java.lang.reflect.InvocationTargetException; + +/** + * This test shows that the IR verification can be done on code compiled by the Compile Framework. + * The "@compile" command for JTREG is required so that the IRFramework is compiled, other javac + * might not compile it because it is not present in the class, only in the dynamically compiled + * code. + *

    + * Additionally, we must set the classpath for the Test-VM, so that it has access to all compiled + * classes (see {@link CompileFramework#getEscapedClassPathOfCompiledClasses}). + */ +public class IRFrameworkJavaExample { + + public static void main(String[] args) { + testX1(); + testX2(); + } + + // Generate a source java file as String + public static String generateX1(CompileFramework comp) { + return String.format(""" + import compiler.lib.ir_framework.*; + + public class X1 { + public static void main(String args[]) { + TestFramework framework = new TestFramework(X1.class); + framework.addFlags("-classpath", "%s"); + framework.start(); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0"}, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + static float[] test() { + float[] a = new float[1024*8]; + for (int i = 0; i < a.length; i++) { + a[i]++; + } + return a; + } + } + """, comp.getEscapedClassPathOfCompiledClasses()); + } + + static void testX1() { + // Create a new CompileFramework instance. + CompileFramework comp = new CompileFramework(); + + // Add a java source file. + comp.addJavaSourceCode("X1", generateX1(comp)); + + // Compile the source file. + comp.compile(); + + // X1.main(); + comp.invoke("X1", "main", new Object[] {null}); + } + + // Generate a source java file as String + public static String generateX2(CompileFramework comp) { + // Example with conflicting "@IR" rules -> expect a IRViolationException. + return String.format(""" + import compiler.lib.ir_framework.*; + + public class X2 { + public static void main(String args[]) { + TestFramework framework = new TestFramework(X2.class); + framework.addFlags("-classpath", "%s"); + framework.start(); + } + + @Test + @IR(counts = {IRNode.LOAD, "> 0"}) + @IR(failOn = IRNode.LOAD) + static void test() { + } + } + """, comp.getEscapedClassPathOfCompiledClasses()); + } + + static void testX2() { + // Create a new CompileFramework instance. + CompileFramework comp = new CompileFramework(); + + // Add a java source file. + comp.addJavaSourceCode("X2", generateX2(comp)); + + // Compile the source file. + comp.compile(); + + // Load the compiled class. + Class c = comp.getClass("X2"); + + // Invoke the "X2.main" method from the compiled and loaded class. + try { + c.getDeclaredMethod("main", new Class[] { String[].class }).invoke(null, new Object[] { null }); + + // Check if IR framework is expected to execute the IR rules. + if (Utils.getTestJavaOpts().length == 0 && Platform.isDebugBuild() && !Platform.isInt() && !Platform.isComp()) { + throw new RuntimeException("IRViolationException expected."); + } else { + System.out.println("Got no IRViolationException, but was also not expected."); + } + } catch (NoSuchMethodException e) { + throw new RuntimeException("No such method:", e); + } catch (IllegalAccessException e) { + throw new RuntimeException("Illegal access:", e); + } catch (InvocationTargetException e) { + Throwable t = e.getCause(); + if (t == null) { + throw new RuntimeException("IRViolationException expected:", e); + } + if (!t.getClass().getSimpleName().equals("IRViolationException")) { + throw new RuntimeException("IRViolationException expected:", e); + } + System.out.println("Success, we got a IRViolationException."); + } + } +} diff --git a/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/MultiFileJasmExample.java b/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/MultiFileJasmExample.java new file mode 100644 index 0000000000000..33fe07a53970b --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/MultiFileJasmExample.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 + * @summary Example test to use the Compile Framework. + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @run driver comile_framework.examples.MultiFileJasmExample + */ + +package comile_framework.examples; + +import compiler.lib.compile_framework.*; +import java.io.StringWriter; +import java.io.PrintWriter; + +/** + * This test shows a compilation of multiple jasm source code files. + */ +public class MultiFileJasmExample { + + // Generate a source jasm file as String + public static String generate(int i) { + StringWriter writer = new StringWriter(); + PrintWriter out = new PrintWriter(writer); + out.println("package p/xyz;"); + out.println(""); + out.println("super public class XYZ" + i + " {"); + out.println(" public static Method test:\"(I)I\""); + out.println(" stack 20 locals 20"); + out.println(" {"); + out.println(" iload_0;"); + out.println(" iconst_2;"); // every call multiplies by 2, in total 2^10 = 1024 + out.println(" imul;"); + if (i != 0) { + out.println(" invokestatic Method p/xyz/XYZ" + (i-1) + ".\"test\":\"(I)I\";"); + } + out.println(" ireturn;"); + out.println(" }"); + out.println("}"); + return writer.toString(); + } + + public static void main(String[] args) { + // Create a new CompileFramework instance. + CompileFramework comp = new CompileFramework(); + + // Generate 10 files. + for (int i = 0; i < 10; i++) { + comp.addJasmSourceCode("p.xyz.XYZ" + i, generate(i)); + } + + // Compile the source files. + comp.compile(); + + // Object ret = XYZ9.test(5); + Object ret = comp.invoke("p.xyz.XYZ9", "test", new Object[] { 5 }); + + // Extract return value of invocation, verify its value. + int i = (int)ret; + System.out.println("Result of call: " + i); + if (i != 5 * 1024) { + throw new RuntimeException("wrong value: " + i); + } + System.out.println("Success."); + } +} diff --git a/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/MultiFileJavaExample.java b/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/MultiFileJavaExample.java new file mode 100644 index 0000000000000..e493ebab4e8c8 --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/MultiFileJavaExample.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 + * @summary Example test to use the Compile Framework. + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @run driver compile_framework.examples.MultiFileJavaExample + */ + +package compile_framework.examples; + +import compiler.lib.compile_framework.*; +import java.io.StringWriter; +import java.io.PrintWriter; + +/** + * This test shows a compilation of multiple java source code files. + */ +public class MultiFileJavaExample { + + // Generate a source java file as String + public static String generate(int i) { + StringWriter writer = new StringWriter(); + PrintWriter out = new PrintWriter(writer); + out.println("package p.xyz;"); + out.println(""); + out.println("public class XYZ" + i + " {"); + if (i > 0) { + out.println(" public XYZ" + (i - 1) + " xyz = new XYZ" + (i - 1) + "();"); + } + out.println(""); + out.println(" public static Object test() {"); + out.println(" return new XYZ" + i + "();"); + out.println(" }"); + out.println("}"); + return writer.toString(); + } + + public static void main(String[] args) { + // Create a new CompileFramework instance. + CompileFramework comp = new CompileFramework(); + + // Generate 10 files. + for (int i = 0; i < 10; i++) { + comp.addJavaSourceCode("p.xyz.XYZ" + i, generate(i)); + } + + // Compile the source files. + comp.compile(); + + // Object ret = XYZ9.test(); + Object ret = comp.invoke("p.xyz.XYZ9", "test", new Object[] {}); + + if (!ret.getClass().getSimpleName().equals("XYZ9")) { + throw new RuntimeException("wrong result:" + ret); + } + System.out.println("Success."); + } +} diff --git a/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/RunWithFlagsExample.java b/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/RunWithFlagsExample.java new file mode 100644 index 0000000000000..a67e6e0eb4937 --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/RunWithFlagsExample.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 + * @summary Example test to use the Compile Framework and run the compiled code with additional flags + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @run driver compile_framework.examples.RunWithFlagsExample + */ + +package compile_framework.examples; + +import compiler.lib.compile_framework.*; + +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +/** + * This test shows how the generated code can be compiled and invoked in a new VM. This allows + * the execution of the code with additional VM flags and options. + *

    + * The new VM must be able to locate the class files of the newly compiled code. For this we + * set the class path using {@link CompileFramework#getEscapedClassPathOfCompiledClasses}. + */ +public class RunWithFlagsExample { + + private static String generate() { + return """ + package p.xyz; + + public class X { + public static void main(String args[]) { + System.out.println("Hello world!"); + System.out.println(System.getProperty("MyMessage", "fail")); + System.err.println(args[0]); + } + } + """; + } + + public static void main(String[] args) throws Exception { + // Create a new CompileFramework instance. + CompileFramework comp = new CompileFramework(); + + // Add a Java source file. + comp.addJavaSourceCode("p.xyz.X", generate()); + + // Compile the source file. + comp.compile(); + + // Build command line. + String[] command = { + // Set the classpath to include our newly compiled class. + "-classpath", + comp.getEscapedClassPathOfCompiledClasses(), + // Pass additional flags here. + // "-Xbatch" is a harmless VM flag, so this example runs everywhere without issues. + "-Xbatch", + // We can also pass properties like "MyMessage". + "-DMyMessage=hello_world", + "p.xyz.X", + "hello_arg" + }; + + // Execute the command, and capture the output. + // The JTREG Java and VM options are automatically passed to the test VM. + OutputAnalyzer analyzer = ProcessTools.executeTestJava(command); + + // Verify output. + analyzer.shouldHaveExitValue(0); + analyzer.stdoutContains("Hello world!"); + analyzer.stdoutContains("hello_world"); + analyzer.stdoutContains("hello_arg"); + + // Print output to stderr. + analyzer.reportDiagnosticSummary(); + } +} diff --git a/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/SimpleJasmExample.java b/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/SimpleJasmExample.java new file mode 100644 index 0000000000000..e01b45e744175 --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/SimpleJasmExample.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 + * @summary Example test to use the Compile Framework. + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @run driver compile_framework.examples.SimpleJasmExample + */ + +package compile_framework.examples; + +import compiler.lib.compile_framework.*; + +/** + * This test shows a simple compilation of java source code, and its invocation. + */ +public class SimpleJasmExample { + + // Generate a source jasm file as String + public static String generate() { + return """ + super public class XYZ { + public static Method test:"(I)I" + stack 20 locals 20 + { + iload_0; + iconst_2; + imul; + ireturn; + } + } + """; + } + + public static void main(String[] args) { + // Create a new CompileFramework instance. + CompileFramework comp = new CompileFramework(); + + // Add a java source file. + String src = generate(); + comp.addJasmSourceCode("XYZ", src); + + // Compile the source file. + comp.compile(); + + // Object ret = XYZ.test(5); + Object ret = comp.invoke("XYZ", "test", new Object[] {5}); + + // Extract return value of invocation, verify its value. + int i = (int)ret; + System.out.println("Result of call: " + i); + if (i != 10) { + throw new RuntimeException("wrong value: " + i); + } + System.out.println("Success."); + } +} diff --git a/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/SimpleJavaExample.java b/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/SimpleJavaExample.java new file mode 100644 index 0000000000000..5e54a6e8a08a6 --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/compile_framework/examples/SimpleJavaExample.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 + * @summary Example test to use the Compile Framework. + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @run driver compile_framework.examples.SimpleJavaExample + */ + +package compile_framework.examples; + +import compiler.lib.compile_framework.*; + +/** + * This test shows a simple compilation of java source code, and its invocation. + */ +public class SimpleJavaExample { + + // Generate a source java file as String + public static String generate() { + return """ + public class XYZ { + public static int test(int i) { + System.out.println("Hello from XYZ.test: " + i); + return i * 2; + } + } + """; + } + + public static void main(String[] args) { + // Create a new CompileFramework instance. + CompileFramework comp = new CompileFramework(); + + // Add a java source file. + comp.addJavaSourceCode("XYZ", generate()); + + // Compile the source file. + comp.compile(); + + // Object ret = XYZ.test(5); + Object ret = comp.invoke("XYZ", "test", new Object[] {5}); + + // Extract return value of invocation, verify its value. + int i = (int)ret; + System.out.println("Result of call: " + i); + if (i != 10) { + throw new RuntimeException("wrong value: " + i); + } + } +} diff --git a/test/hotspot/jtreg/testlibrary_tests/compile_framework/tests/TestBadJasmCompilation.java b/test/hotspot/jtreg/testlibrary_tests/compile_framework/tests/TestBadJasmCompilation.java new file mode 100644 index 0000000000000..b5b6f3e104095 --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/compile_framework/tests/TestBadJasmCompilation.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 + * @summary Example test with failing jasm compilation. + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @run driver compile_framework.tests.TestBadJasmCompilation + */ + +package compile_framework.tests; + +import compiler.lib.compile_framework.*; + +public class TestBadJasmCompilation { + + // Generate a source jasm file as String + public static String generate() { + return """ + super public class XYZ { + some bad code + } + """; + } + + public static void main(String[] args) { + // Create a new CompileFramework instance. + CompileFramework comp = new CompileFramework(); + + // Add a java source file. + comp.addJasmSourceCode("XYZ", generate()); + + try { + // Compile the source file. + comp.compile(); + throw new RuntimeException("Expected compilation to fail."); + } catch (CompileFrameworkException e) { + System.out.println("Success, expected compilation to fail."); + } + } +} diff --git a/test/hotspot/jtreg/testlibrary_tests/compile_framework/tests/TestBadJavaCompilation.java b/test/hotspot/jtreg/testlibrary_tests/compile_framework/tests/TestBadJavaCompilation.java new file mode 100644 index 0000000000000..1cb1d79afbcca --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/compile_framework/tests/TestBadJavaCompilation.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 + * @summary Example test with failing java compilation. + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @run driver compile_framework.tests.TestBadJavaCompilation + */ + +package compile_framework.tests; + +import compiler.lib.compile_framework.*; + +public class TestBadJavaCompilation { + + // Generate a source java file as String + public static String generate() { + return """ + public class XYZ { + some bad code + } + """; + } + + public static void main(String[] args) { + // Create a new CompileFramework instance. + CompileFramework comp = new CompileFramework(); + + // Add a java source file. + comp.addJavaSourceCode("XYZ", generate()); + + try { + // Compile the source file. + comp.compile(); + throw new RuntimeException("Expected compilation to fail."); + } catch (CompileFrameworkException e) { + System.out.println("Success, expected compilation to fail."); + } + } +} diff --git a/test/hotspot/jtreg/testlibrary_tests/compile_framework/tests/TestConcurrentCompilation.java b/test/hotspot/jtreg/testlibrary_tests/compile_framework/tests/TestConcurrentCompilation.java new file mode 100644 index 0000000000000..1cb902d34e4aa --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/compile_framework/tests/TestConcurrentCompilation.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 + * @summary Example test with multi-threaded use of the CompileFramework. + * Tests that the source and class directories are set up correctly. + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @run driver compile_framework.tests.TestConcurrentCompilation + */ + +package compile_framework.tests; + +import compiler.lib.compile_framework.*; + +import java.util.ArrayList; +import java.util.List; + +public class TestConcurrentCompilation { + + // Generate a source java file as String + public static String generate(int i) { + return String.format(""" + public class XYZ { + public static int test() { + return %d; + } + } + """, i); + } + + public static void test(int i) { + System.out.println("Generate and compile XYZ for " + i); + CompileFramework comp = new CompileFramework(); + comp.addJavaSourceCode("XYZ", generate(i)); + comp.compile(); + + // Now, sleep to give the other threads time to compile and store their class-files. + System.out.println("Sleep for " + i); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + System.out.println("Sleep interrupted for " + i); + } + + // Now, hopefully all threads have compiled and stored their class-files. + // We can check if we get the expected result, i.e. the class-file from the current thread. + System.out.println("Run XYZ.test for " + i); + int j = (int)comp.invoke("XYZ", "test", new Object[] {}); + if (i != j) { + System.out.println("Wrong value: " + i + " vs " + j); + throw new RuntimeException("Wrong value: " + i + " vs " + j); + } + System.out.println("Success for " + i); + } + + public static class MyRunnable implements Runnable { + private int i; + + public MyRunnable(int i) { + this.i = i; + } + + public void run() { + TestConcurrentCompilation.test(i); + } + } + + public static void main(String[] args) { + System.out.println("Generating threads:"); + List threads = new ArrayList(); + for (int i = 0; i < 3; i++) { + Thread thread = new Thread(new MyRunnable(i)); + thread.start(); + threads.add(thread); + } + System.out.println("Waiting to join threads:"); + try { + for (Thread thread : threads) { + thread.join(); + } + } catch (InterruptedException e) { + throw new RuntimeException("interrupted", e); + } + System.out.println("Success."); + } +} From 577babf1968700e4b648305cd5a5c2ddf712e2dc Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 16 Oct 2024 07:27:28 +0000 Subject: [PATCH 084/118] 8334010: VM crashes with ObjectAlignmentInBytes > GCCardSizeInBytes Reviewed-by: shade, iwalulya --- src/hotspot/share/gc/shared/gcArguments.cpp | 8 +++ .../jtreg/gc/TestObjectAlignmentCardSize.java | 63 +++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 test/hotspot/jtreg/gc/TestObjectAlignmentCardSize.java diff --git a/src/hotspot/share/gc/shared/gcArguments.cpp b/src/hotspot/share/gc/shared/gcArguments.cpp index 9736c0f7fdcab..2522925746be1 100644 --- a/src/hotspot/share/gc/shared/gcArguments.cpp +++ b/src/hotspot/share/gc/shared/gcArguments.cpp @@ -30,6 +30,7 @@ #include "runtime/arguments.hpp" #include "runtime/globals.hpp" #include "runtime/globals_extension.hpp" +#include "utilities/formatBuffer.hpp" #include "utilities/macros.hpp" size_t HeapAlignment = 0; @@ -166,6 +167,13 @@ void GCArguments::initialize_heap_flags_and_sizes() { FLAG_SET_ERGO(MinHeapDeltaBytes, align_up(MinHeapDeltaBytes, SpaceAlignment)); + if (checked_cast(ObjectAlignmentInBytes) > GCCardSizeInBytes) { + err_msg message("ObjectAlignmentInBytes %u is larger than GCCardSizeInBytes %u", + ObjectAlignmentInBytes, GCCardSizeInBytes); + vm_exit_during_initialization("Invalid combination of GCCardSizeInBytes and ObjectAlignmentInBytes", + message); + } + DEBUG_ONLY(assert_flags();) } diff --git a/test/hotspot/jtreg/gc/TestObjectAlignmentCardSize.java b/test/hotspot/jtreg/gc/TestObjectAlignmentCardSize.java new file mode 100644 index 0000000000000..5fb46a87b5104 --- /dev/null +++ b/test/hotspot/jtreg/gc/TestObjectAlignmentCardSize.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 gc; + +/* @test TestObjectAlignmentCardSize.java + * @summary Test to check correct handling of ObjectAlignmentInBytes and GCCardSizeInBytes combinations + * @requires vm.gc != "Z" + * @library /test/lib + * @modules java.base/jdk.internal.misc + * @run driver gc.TestObjectAlignmentCardSize + */ + +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +public class TestObjectAlignmentCardSize { + private static void runTest(int objectAlignment, int cardSize, boolean shouldSucceed) throws Exception { + OutputAnalyzer output = ProcessTools.executeTestJava( + "-XX:ObjectAlignmentInBytes=" + objectAlignment, + "-XX:GCCardSizeInBytes=" + cardSize, + "-Xmx32m", + "-Xms32m", + "-version"); + + System.out.println("Output:\n" + output.getOutput()); + + if (shouldSucceed) { + output.shouldHaveExitValue(0); + } else { + output.shouldContain("Invalid combination of GCCardSizeInBytes and ObjectAlignmentInBytes"); + output.shouldNotHaveExitValue(0); + } + } + + public static void main(String[] args) throws Exception { + runTest(8, 512, true); + runTest(128, 128, true); + runTest(256, 128, false); + runTest(256, 256, true); + runTest(256, 512, true); + } +} From e7cf25ce0efdf568fc8eaff249d49e46d5a6eda1 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 16 Oct 2024 07:28:36 +0000 Subject: [PATCH 085/118] 8340801: Disable ubsan checks in some awt/2d coding Reviewed-by: ihse, lucy, goetz, jwaters --- src/java.base/share/native/libjava/ub.h | 42 +++++++++++++++++++ .../share/native/libawt/java2d/loops/IntRgb.c | 3 ++ 2 files changed, 45 insertions(+) create mode 100644 src/java.base/share/native/libjava/ub.h diff --git a/src/java.base/share/native/libjava/ub.h b/src/java.base/share/native/libjava/ub.h new file mode 100644 index 0000000000000..cf7f491ca453e --- /dev/null +++ b/src/java.base/share/native/libjava/ub.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024 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 + * 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 _UB_H_ +#define _UB_H_ + +/* ATTRIBUTE_NO_UBSAN - Function attribute which informs the compiler to disable UBSan checks in the + * following function or method. + */ +#ifdef UNDEFINED_BEHAVIOR_SANITIZER +#if defined(__clang__) || defined(__GNUC__) +#define ATTRIBUTE_NO_UBSAN __attribute__((no_sanitize("undefined"))) +#endif +#endif + +#ifndef ATTRIBUTE_NO_UBSAN +#define ATTRIBUTE_NO_UBSAN +#endif + +#endif diff --git a/src/java.desktop/share/native/libawt/java2d/loops/IntRgb.c b/src/java.desktop/share/native/libawt/java2d/loops/IntRgb.c index 7155f70b472d3..aec11d17c890b 100644 --- a/src/java.desktop/share/native/libawt/java2d/loops/IntRgb.c +++ b/src/java.desktop/share/native/libawt/java2d/loops/IntRgb.c @@ -34,6 +34,8 @@ #include "ByteGray.h" #include "Index12Gray.h" +#include "ub.h" + /* * This file declares, registers, and defines the various graphics * primitive loops to manipulate surfaces of type "IntRgb". @@ -166,6 +168,7 @@ DEFINE_ALPHA_MASKBLIT(IntArgbPre, IntRgb, 4ByteArgb) DEFINE_ALPHA_MASKBLIT(IntRgb, IntRgb, 4ByteArgb) +ATTRIBUTE_NO_UBSAN DEFINE_SOLID_DRAWGLYPHLISTAA(IntRgb, 3ByteRgb) DEFINE_SOLID_DRAWGLYPHLISTLCD(IntRgb, 3ByteRgb) From ebc17c7c8d6febd5a887309d1b7a466bcd2cc0a9 Mon Sep 17 00:00:00 2001 From: Johny Jose Date: Wed, 16 Oct 2024 07:36:07 +0000 Subject: [PATCH 086/118] 8339637: (tz) Update Timezone Data to 2024b Reviewed-by: naoto, coffeys, jlu --- .../share/classes/java/time/ZoneId.java | 18 +- .../sun/util/calendar/ZoneInfoFile.java | 7 +- src/java.base/share/data/tzdata/VERSION | 2 +- src/java.base/share/data/tzdata/africa | 73 +- src/java.base/share/data/tzdata/antarctica | 58 +- src/java.base/share/data/tzdata/asia | 442 ++++++----- src/java.base/share/data/tzdata/australasia | 130 ++-- src/java.base/share/data/tzdata/backward | 15 +- src/java.base/share/data/tzdata/etcetera | 54 +- src/java.base/share/data/tzdata/europe | 713 +++++++++++------- src/java.base/share/data/tzdata/leapseconds | 8 +- src/java.base/share/data/tzdata/northamerica | 145 +++- src/java.base/share/data/tzdata/southamerica | 486 ++++++------ src/java.base/share/data/tzdata/zone.tab | 3 +- .../Format/DateFormat/TimeZoneNameTest.java | 2 +- .../java/time/tck/java/time/TCKZoneId.java | 12 +- .../java/util/TimeZone/OldIDMappingTest.java | 3 +- .../java/util/TimeZone/TimeZoneData/VERSION | 2 +- .../util/TimeZone/TimeZoneData/aliases.txt | 12 + .../TimeZone/TimeZoneData/displaynames.txt | 11 - .../sun/util/calendar/zi/TestZoneInfo310.java | 1 - .../jdk/sun/util/calendar/zi/ZoneInfoOld.java | 12 +- .../util/resources/TimeZone/Bug4848242.java | 12 +- 23 files changed, 1258 insertions(+), 963 deletions(-) diff --git a/src/java.base/share/classes/java/time/ZoneId.java b/src/java.base/share/classes/java/time/ZoneId.java index 21c9054761c21..47758b64e54ae 100644 --- a/src/java.base/share/classes/java/time/ZoneId.java +++ b/src/java.base/share/classes/java/time/ZoneId.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * 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,15 +186,12 @@ public abstract sealed class ZoneId implements Serializable permits ZoneOffset, * This map allows the IDs to continue to be used via the * {@link #of(String, Map)} factory method. *

    - * This map contains a mapping of the IDs that is in line with TZDB 2005r and + * This map contains a mapping of the IDs that is in line with TZDB 2024b and * later, where 'EST', 'MST' and 'HST' map to IDs which do not include daylight - * savings. + * savings since 1970. This mapping may change in update releases in support of new versions of TZDB. *

    * This maps as follows: *

      - *
    • EST - -05:00
    • - *
    • HST - -10:00
    • - *
    • MST - -07:00
    • *
    • ACT - Australia/Darwin
    • *
    • AET - Australia/Sydney
    • *
    • AGT - America/Argentina/Buenos_Aires
    • @@ -208,10 +205,13 @@ public abstract sealed class ZoneId implements Serializable permits ZoneOffset, *
    • CTT - Asia/Shanghai
    • *
    • EAT - Africa/Addis_Ababa
    • *
    • ECT - Europe/Paris
    • + *
    • EST - America/Panama
    • + *
    • HST - Pacific/Honolulu
    • *
    • IET - America/Indiana/Indianapolis
    • *
    • IST - Asia/Kolkata
    • *
    • JST - Asia/Tokyo
    • *
    • MIT - Pacific/Apia
    • + *
    • MST - America/Phoenix
    • *
    • NET - Asia/Yerevan
    • *
    • NST - Pacific/Auckland
    • *
    • PLT - Asia/Karachi
    • @@ -249,9 +249,9 @@ public abstract sealed class ZoneId implements Serializable permits ZoneOffset, entry("PST", "America/Los_Angeles"), entry("SST", "Pacific/Guadalcanal"), entry("VST", "Asia/Ho_Chi_Minh"), - entry("EST", "-05:00"), - entry("MST", "-07:00"), - entry("HST", "-10:00") + entry("EST", "America/Panama"), + entry("MST", "America/Phoenix"), + entry("HST", "Pacific/Honolulu") ); /** * Serialization version. diff --git a/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java b/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java index 4e30e403bb2f5..1550f7da3de22 100644 --- a/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java +++ b/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java @@ -281,12 +281,11 @@ private static void addOldMapping() { if (USE_OLDMAPPING) { aliases.put("EST", "America/New_York"); aliases.put("MST", "America/Denver"); - aliases.put("HST", "Pacific/Honolulu"); } else { - zones.put("EST", new ZoneInfo("EST", -18000000)); - zones.put("MST", new ZoneInfo("MST", -25200000)); - zones.put("HST", new ZoneInfo("HST", -36000000)); + aliases.put("EST", "America/Panama"); + aliases.put("MST", "America/Phoenix"); } + aliases.put("HST", "Pacific/Honolulu"); } public static boolean useOldMapping() { diff --git a/src/java.base/share/data/tzdata/VERSION b/src/java.base/share/data/tzdata/VERSION index b138ed7fa78f5..740427424a600 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. # -tzdata2024a +tzdata2024b diff --git a/src/java.base/share/data/tzdata/africa b/src/java.base/share/data/tzdata/africa index 72b188f074deb..8098f4bea9d30 100644 --- a/src/java.base/share/data/tzdata/africa +++ b/src/java.base/share/data/tzdata/africa @@ -126,17 +126,16 @@ Zone Africa/Algiers 0:12:12 - LMT 1891 Mar 16 # Cape Verde / Cabo Verde # -# From Paul Eggert (2018-02-16): -# Shanks gives 1907 for the transition to +02. -# For now, ignore that and follow the 1911-05-26 Portuguese decree -# (see Europe/Lisbon). +# From Tim Parenti (2024-07-01), per Paul Eggert (2018-02-16): +# For timestamps before independence, see commentary for Europe/Lisbon. +# Shanks gives 1907 instead for the transition to -02. # # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Atlantic/Cape_Verde -1:34:04 - LMT 1912 Jan 01 2:00u # Praia - -2:00 - -02 1942 Sep - -2:00 1:00 -01 1945 Oct 15 - -2:00 - -02 1975 Nov 25 2:00 - -1:00 - -01 + -2:00 - %z 1942 Sep + -2:00 1:00 %z 1945 Oct 15 + -2:00 - %z 1975 Nov 25 2:00 + -1:00 - %z # Chad # Zone NAME STDOFF RULES FORMAT [UNTIL] @@ -368,14 +367,12 @@ Zone Africa/Cairo 2:05:09 - LMT 1900 Oct # Guinea-Bissau # -# From Paul Eggert (2018-02-16): -# Shanks gives 1911-05-26 for the transition to WAT, -# evidently confusing the date of the Portuguese decree -# (see Europe/Lisbon) with the date that it took effect. +# From Tim Parenti (2024-07-01), per Paul Eggert (2018-02-16): +# For timestamps before independence, see commentary for Europe/Lisbon. # # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Africa/Bissau -1:02:20 - LMT 1912 Jan 1 1:00u - -1:00 - -01 1975 + -1:00 - %z 1975 0:00 - GMT # Comoros @@ -440,10 +437,10 @@ Zone Africa/Bissau -1:02:20 - LMT 1912 Jan 1 1:00u # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Africa/Nairobi 2:27:16 - LMT 1908 May - 2:30 - +0230 1928 Jun 30 24:00 + 2:30 - %z 1928 Jun 30 24:00 3:00 - EAT 1930 Jan 4 24:00 - 2:30 - +0230 1936 Dec 31 24:00 - 2:45 - +0245 1942 Jul 31 24:00 + 2:30 - %z 1936 Dec 31 24:00 + 2:45 - %z 1942 Jul 31 24:00 3:00 - EAT # Liberia @@ -614,7 +611,7 @@ Rule Mauritius 2008 only - Oct lastSun 2:00 1:00 - Rule Mauritius 2009 only - Mar lastSun 2:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Indian/Mauritius 3:50:00 - LMT 1907 # Port Louis - 4:00 Mauritius +04/+05 + 4:00 Mauritius %z # Agalega Is, Rodriguez # no information; probably like Indian/Mauritius @@ -1094,10 +1091,10 @@ Rule Morocco 2087 only - May 11 2:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Africa/Casablanca -0:30:20 - LMT 1913 Oct 26 - 0:00 Morocco +00/+01 1984 Mar 16 - 1:00 - +01 1986 - 0:00 Morocco +00/+01 2018 Oct 28 3:00 - 1:00 Morocco +01/+00 + 0:00 Morocco %z 1984 Mar 16 + 1:00 - %z 1986 + 0:00 Morocco %z 2018 Oct 28 3:00 + 1:00 Morocco %z # Western Sahara # @@ -1111,9 +1108,9 @@ Zone Africa/Casablanca -0:30:20 - LMT 1913 Oct 26 # since most of it was then controlled by Morocco. Zone Africa/El_Aaiun -0:52:48 - LMT 1934 Jan # El Aaiún - -1:00 - -01 1976 Apr 14 - 0:00 Morocco +00/+01 2018 Oct 28 3:00 - 1:00 Morocco +01/+00 + -1:00 - %z 1976 Apr 14 + 0:00 Morocco %z 2018 Oct 28 3:00 + 1:00 Morocco %z # Botswana # Burundi @@ -1124,13 +1121,27 @@ Zone Africa/El_Aaiun -0:52:48 - LMT 1934 Jan # El Aaiún # Zambia # Zimbabwe # -# Shanks gives 1903-03-01 for the transition to CAT. -# Perhaps the 1911-05-26 Portuguese decree -# https://dre.pt/pdf1sdip/1911/05/12500/23132313.pdf -# merely made it official? +# From Tim Parenti (2024-07-01): +# For timestamps before Mozambique's independence, see commentary for +# Europe/Lisbon. +# +# From Paul Eggert (2024-05-24): +# The London Gazette, 1903-04-03, page 2245, says that +# as of 1903-03-03 a time ball at the port of Lourenço Marques +# (as Maputo was then called) was dropped daily at 13:00:00 LMT, +# corresponding to 22:49:41.7 GMT, so local time was +02:10:18.3. +# Conversely, the newspaper South Africa, 1909-02-09, page 321, +# says the port had just installed an apparatus that communicated +# "from the controlling clock in the new Observatory at Reuben Point ... +# exact mean South African time, i.e., 30 deg., or 2 hours East of Greenwich". +# Although Shanks gives 1903-03-01 for the transition to CAT, +# evidently the port transitioned to CAT after 1903-03-03 but before +# the Portuguese legal transition of 1912-01-01 (see Europe/Lisbon commentary). +# For lack of better info, list 1909 as the transition date. # # Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone Africa/Maputo 2:10:20 - LMT 1903 Mar + #STDOFF 2:10:18.3 +Zone Africa/Maputo 2:10:18 - LMT 1909 2:00 - CAT # Namibia @@ -1195,7 +1206,7 @@ Rule Namibia 1995 2017 - Apr Sun>=1 2:00 -1:00 WAT # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Africa/Windhoek 1:08:24 - LMT 1892 Feb 8 - 1:30 - +0130 1903 Mar + 1:30 - %z 1903 Mar 2:00 - SAST 1942 Sep 20 2:00 2:00 1:00 SAST 1943 Mar 21 2:00 2:00 - SAST 1990 Mar 21 # independence @@ -1283,7 +1294,7 @@ Zone Africa/Windhoek 1:08:24 - LMT 1892 Feb 8 Zone Africa/Lagos 0:13:35 - LMT 1905 Jul 1 0:00 - GMT 1908 Jul 1 0:13:35 - LMT 1914 Jan 1 - 0:30 - +0030 1919 Sep 1 + 0:30 - %z 1919 Sep 1 1:00 - WAT # São Tomé and Príncipe diff --git a/src/java.base/share/data/tzdata/antarctica b/src/java.base/share/data/tzdata/antarctica index fc7176cd0d57a..058d8d6a7a28b 100644 --- a/src/java.base/share/data/tzdata/antarctica +++ b/src/java.base/share/data/tzdata/antarctica @@ -110,34 +110,34 @@ # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Antarctica/Casey 0 - -00 1969 - 8:00 - +08 2009 Oct 18 2:00 - 11:00 - +11 2010 Mar 5 2:00 - 8:00 - +08 2011 Oct 28 2:00 - 11:00 - +11 2012 Feb 21 17:00u - 8:00 - +08 2016 Oct 22 - 11:00 - +11 2018 Mar 11 4:00 - 8:00 - +08 2018 Oct 7 4:00 - 11:00 - +11 2019 Mar 17 3:00 - 8:00 - +08 2019 Oct 4 3:00 - 11:00 - +11 2020 Mar 8 3:00 - 8:00 - +08 2020 Oct 4 0:01 - 11:00 - +11 2021 Mar 14 0:00 - 8:00 - +08 2021 Oct 3 0:01 - 11:00 - +11 2022 Mar 13 0:00 - 8:00 - +08 2022 Oct 2 0:01 - 11:00 - +11 2023 Mar 9 3:00 - 8:00 - +08 + 8:00 - %z 2009 Oct 18 2:00 + 11:00 - %z 2010 Mar 5 2:00 + 8:00 - %z 2011 Oct 28 2:00 + 11:00 - %z 2012 Feb 21 17:00u + 8:00 - %z 2016 Oct 22 + 11:00 - %z 2018 Mar 11 4:00 + 8:00 - %z 2018 Oct 7 4:00 + 11:00 - %z 2019 Mar 17 3:00 + 8:00 - %z 2019 Oct 4 3:00 + 11:00 - %z 2020 Mar 8 3:00 + 8:00 - %z 2020 Oct 4 0:01 + 11:00 - %z 2021 Mar 14 0:00 + 8:00 - %z 2021 Oct 3 0:01 + 11:00 - %z 2022 Mar 13 0:00 + 8:00 - %z 2022 Oct 2 0:01 + 11:00 - %z 2023 Mar 9 3:00 + 8:00 - %z Zone Antarctica/Davis 0 - -00 1957 Jan 13 - 7:00 - +07 1964 Nov + 7:00 - %z 1964 Nov 0 - -00 1969 Feb - 7:00 - +07 2009 Oct 18 2:00 - 5:00 - +05 2010 Mar 10 20:00u - 7:00 - +07 2011 Oct 28 2:00 - 5:00 - +05 2012 Feb 21 20:00u - 7:00 - +07 + 7:00 - %z 2009 Oct 18 2:00 + 5:00 - %z 2010 Mar 10 20:00u + 7:00 - %z 2011 Oct 28 2:00 + 5:00 - %z 2012 Feb 21 20:00u + 7:00 - %z Zone Antarctica/Mawson 0 - -00 1954 Feb 13 - 6:00 - +06 2009 Oct 18 2:00 - 5:00 - +05 + 6:00 - %z 2009 Oct 18 2:00 + 5:00 - %z # References: # Casey Weather (1998-02-26) # http://www.antdiv.gov.au/aad/exop/sfo/casey/casey_aws.html @@ -313,10 +313,10 @@ Zone Antarctica/Troll 0 - -00 2005 Feb 12 # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Antarctica/Vostok 0 - -00 1957 Dec 16 - 7:00 - +07 1994 Feb + 7:00 - %z 1994 Feb 0 - -00 1994 Nov - 7:00 - +07 2023 Dec 18 2:00 - 5:00 - +05 + 7:00 - %z 2023 Dec 18 2:00 + 5:00 - %z # S Africa - year-round bases # Marion Island, -4653+03752 @@ -349,7 +349,7 @@ Zone Antarctica/Vostok 0 - -00 1957 Dec 16 # # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Antarctica/Rothera 0 - -00 1976 Dec 1 - -3:00 - -03 + -3:00 - %z # Uruguay - year round base # Artigas, King George Island, -621104-0585107 diff --git a/src/java.base/share/data/tzdata/asia b/src/java.base/share/data/tzdata/asia index 3a54291919d60..5c8568f334aee 100644 --- a/src/java.base/share/data/tzdata/asia +++ b/src/java.base/share/data/tzdata/asia @@ -106,8 +106,8 @@ Rule RussiaAsia 1996 2010 - Oct lastSun 2:00s 0 - # Afghanistan # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Kabul 4:36:48 - LMT 1890 - 4:00 - +04 1945 - 4:30 - +0430 + 4:00 - %z 1945 + 4:30 - %z # Armenia # From Paul Eggert (2006-03-22): @@ -139,12 +139,12 @@ Rule Armenia 2011 only - Mar lastSun 2:00s 1:00 - Rule Armenia 2011 only - Oct lastSun 2:00s 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Yerevan 2:58:00 - LMT 1924 May 2 - 3:00 - +03 1957 Mar - 4:00 RussiaAsia +04/+05 1991 Mar 31 2:00s - 3:00 RussiaAsia +03/+04 1995 Sep 24 2:00s - 4:00 - +04 1997 - 4:00 RussiaAsia +04/+05 2011 - 4:00 Armenia +04/+05 + 3:00 - %z 1957 Mar + 4:00 RussiaAsia %z 1991 Mar 31 2:00s + 3:00 RussiaAsia %z 1995 Sep 24 2:00s + 4:00 - %z 1997 + 4:00 RussiaAsia %z 2011 + 4:00 Armenia %z # Azerbaijan @@ -165,12 +165,12 @@ Rule Azer 1997 2015 - Mar lastSun 4:00 1:00 - Rule Azer 1997 2015 - Oct lastSun 5:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Baku 3:19:24 - LMT 1924 May 2 - 3:00 - +03 1957 Mar - 4:00 RussiaAsia +04/+05 1991 Mar 31 2:00s - 3:00 RussiaAsia +03/+04 1992 Sep lastSun 2:00s - 4:00 - +04 1996 - 4:00 EUAsia +04/+05 1997 - 4:00 Azer +04/+05 + 3:00 - %z 1957 Mar + 4:00 RussiaAsia %z 1991 Mar 31 2:00s + 3:00 RussiaAsia %z 1992 Sep lastSun 2:00s + 4:00 - %z 1996 + 4:00 EUAsia %z 1997 + 4:00 Azer %z # Bangladesh # From Alexander Krivenyshev (2009-05-13): @@ -251,17 +251,17 @@ Rule Dhaka 2009 only - Dec 31 24:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Dhaka 6:01:40 - LMT 1890 5:53:20 - HMT 1941 Oct # Howrah Mean Time? - 6:30 - +0630 1942 May 15 - 5:30 - +0530 1942 Sep - 6:30 - +0630 1951 Sep 30 - 6:00 - +06 2009 - 6:00 Dhaka +06/+07 + 6:30 - %z 1942 May 15 + 5:30 - %z 1942 Sep + 6:30 - %z 1951 Sep 30 + 6:00 - %z 2009 + 6:00 Dhaka %z # Bhutan # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Thimphu 5:58:36 - LMT 1947 Aug 15 # or Thimbu - 5:30 - +0530 1987 Oct - 6:00 - +06 + 5:30 - %z 1987 Oct + 6:00 - %z # British Indian Ocean Territory # Whitman and the 1995 CIA time zone map say 5:00, but the @@ -271,8 +271,8 @@ Zone Asia/Thimphu 5:58:36 - LMT 1947 Aug 15 # or Thimbu # then contained the Chagos Archipelago). # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Indian/Chagos 4:49:40 - LMT 1907 - 5:00 - +05 1996 - 6:00 - +06 + 5:00 - %z 1996 + 6:00 - %z # Cocos (Keeling) Islands # Myanmar (Burma) @@ -288,9 +288,9 @@ Zone Indian/Chagos 4:49:40 - LMT 1907 # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Yangon 6:24:47 - LMT 1880 # or Rangoon 6:24:47 - RMT 1920 # Rangoon local time - 6:30 - +0630 1942 May - 9:00 - +09 1945 May 3 - 6:30 - +0630 + 6:30 - %z 1942 May + 9:00 - %z 1945 May 3 + 6:30 - %z # China @@ -679,7 +679,7 @@ Zone Asia/Shanghai 8:05:43 - LMT 1901 # Xinjiang time, used by many in western China; represented by Ürümqi / Ürümchi # / Wulumuqi. (Please use Asia/Shanghai if you prefer Beijing time.) Zone Asia/Urumqi 5:50:20 - LMT 1928 - 6:00 - +06 + 6:00 - %z # Hong Kong @@ -1137,7 +1137,7 @@ Rule Macau 1979 only - Oct Sun>=16 03:30 0 S # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Macau 7:34:10 - LMT 1904 Oct 30 8:00 - CST 1941 Dec 21 23:00 - 9:00 Macau +09/+10 1945 Sep 30 24:00 + 9:00 Macau %z 1945 Sep 30 24:00 8:00 Macau C%sT @@ -1180,7 +1180,7 @@ Zone Asia/Nicosia 2:13:28 - LMT 1921 Nov 14 Zone Asia/Famagusta 2:15:48 - LMT 1921 Nov 14 2:00 Cyprus EE%sT 1998 Sep 2:00 EUAsia EE%sT 2016 Sep 8 - 3:00 - +03 2017 Oct 29 1:00u + 3:00 - %z 2017 Oct 29 1:00u 2:00 EUAsia EE%sT # Georgia @@ -1221,18 +1221,25 @@ Zone Asia/Famagusta 2:15:48 - LMT 1921 Nov 14 # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Tbilisi 2:59:11 - LMT 1880 2:59:11 - TBMT 1924 May 2 # Tbilisi Mean Time - 3:00 - +03 1957 Mar - 4:00 RussiaAsia +04/+05 1991 Mar 31 2:00s - 3:00 RussiaAsia +03/+04 1992 - 3:00 E-EurAsia +03/+04 1994 Sep lastSun - 4:00 E-EurAsia +04/+05 1996 Oct lastSun - 4:00 1:00 +05 1997 Mar lastSun - 4:00 E-EurAsia +04/+05 2004 Jun 27 - 3:00 RussiaAsia +03/+04 2005 Mar lastSun 2:00 - 4:00 - +04 + 3:00 - %z 1957 Mar + 4:00 RussiaAsia %z 1991 Mar 31 2:00s + 3:00 RussiaAsia %z 1992 + 3:00 E-EurAsia %z 1994 Sep lastSun + 4:00 E-EurAsia %z 1996 Oct lastSun + 4:00 1:00 %z 1997 Mar lastSun + 4:00 E-EurAsia %z 2004 Jun 27 + 3:00 RussiaAsia %z 2005 Mar lastSun 2:00 + 4:00 - %z # East Timor +# From Tim Parenti (2024-07-01): +# The 1912-01-01 transition occurred at 00:00 new time, per the 1911-05-24 +# Portuguese decree (see Europe/Lisbon). A provision in article 5(c) of the +# decree prescribed that Timor "will keep counting time in harmony with +# neighboring foreign colonies, [for] as long as they do not adopt the time +# that belongs to them in [the Washington Convention] system." + # See Indonesia for the 1945 transition. # From João Carrascalão, brother of the former governor of East Timor, in @@ -1256,11 +1263,11 @@ Zone Asia/Tbilisi 2:59:11 - LMT 1880 # midnight on Saturday, September 16. # Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone Asia/Dili 8:22:20 - LMT 1912 Jan 1 - 8:00 - +08 1942 Feb 21 23:00 - 9:00 - +09 1976 May 3 - 8:00 - +08 2000 Sep 17 0:00 - 9:00 - +09 +Zone Asia/Dili 8:22:20 - LMT 1911 Dec 31 16:00u + 8:00 - %z 1942 Feb 21 23:00 + 9:00 - %z 1976 May 3 + 8:00 - %z 2000 Sep 17 0:00 + 9:00 - %z # India @@ -1326,9 +1333,9 @@ Zone Asia/Kolkata 5:53:28 - LMT 1854 Jun 28 # Kolkata 5:53:20 - HMT 1870 # Howrah Mean Time? 5:21:10 - MMT 1906 Jan 1 # Madras local time 5:30 - IST 1941 Oct - 5:30 1:00 +0630 1942 May 15 + 5:30 1:00 %z 1942 May 15 5:30 - IST 1942 Sep - 5:30 1:00 +0630 1945 Oct 15 + 5:30 1:00 %z 1945 Oct 15 5:30 - IST # Since 1970 the following are like Asia/Kolkata: # Andaman Is @@ -1380,33 +1387,33 @@ Zone Asia/Jakarta 7:07:12 - LMT 1867 Aug 10 # Shanks & Pottenger say the next transition was at 1924 Jan 1 0:13, # but this must be a typo. 7:07:12 - BMT 1923 Dec 31 16:40u # Batavia - 7:20 - +0720 1932 Nov - 7:30 - +0730 1942 Mar 23 - 9:00 - +09 1945 Sep 23 - 7:30 - +0730 1948 May - 8:00 - +08 1950 May - 7:30 - +0730 1964 + 7:20 - %z 1932 Nov + 7:30 - %z 1942 Mar 23 + 9:00 - %z 1945 Sep 23 + 7:30 - %z 1948 May + 8:00 - %z 1950 May + 7:30 - %z 1964 7:00 - WIB # west and central Borneo Zone Asia/Pontianak 7:17:20 - LMT 1908 May 7:17:20 - PMT 1932 Nov # Pontianak MT - 7:30 - +0730 1942 Jan 29 - 9:00 - +09 1945 Sep 23 - 7:30 - +0730 1948 May - 8:00 - +08 1950 May - 7:30 - +0730 1964 + 7:30 - %z 1942 Jan 29 + 9:00 - %z 1945 Sep 23 + 7:30 - %z 1948 May + 8:00 - %z 1950 May + 7:30 - %z 1964 8:00 - WITA 1988 Jan 1 7:00 - WIB # Sulawesi, Lesser Sundas, east and south Borneo Zone Asia/Makassar 7:57:36 - LMT 1920 7:57:36 - MMT 1932 Nov # Macassar MT - 8:00 - +08 1942 Feb 9 - 9:00 - +09 1945 Sep 23 + 8:00 - %z 1942 Feb 9 + 9:00 - %z 1945 Sep 23 8:00 - WITA # Maluku Islands, West Papua, Papua Zone Asia/Jayapura 9:22:48 - LMT 1932 Nov - 9:00 - +09 1944 Sep 1 - 9:30 - +0930 1964 + 9:00 - %z 1944 Sep 1 + 9:30 - %z 1964 9:00 - WIT # Iran @@ -1642,9 +1649,9 @@ Rule Iran 2021 2022 - Sep 21 24:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Tehran 3:25:44 - LMT 1916 3:25:44 - TMT 1935 Jun 13 # Tehran Mean Time - 3:30 Iran +0330/+0430 1977 Oct 20 24:00 - 4:00 Iran +04/+05 1979 - 3:30 Iran +0330/+0430 + 3:30 Iran %z 1977 Oct 20 24:00 + 4:00 Iran %z 1979 + 3:30 Iran %z # Iraq @@ -1687,8 +1694,8 @@ Rule Iraq 1991 2007 - Oct 1 3:00s 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Baghdad 2:57:40 - LMT 1890 2:57:36 - BMT 1918 # Baghdad Mean Time? - 3:00 - +03 1982 May - 3:00 Iraq +03/+04 + 3:00 - %z 1982 May + 3:00 Iraq %z ############################################################################### @@ -2285,7 +2292,7 @@ Rule Jordan 2022 only - Feb lastThu 24:00 1:00 S # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Amman 2:23:44 - LMT 1931 2:00 Jordan EE%sT 2022 Oct 28 0:00s - 3:00 - +03 + 3:00 - %z # Kazakhstan @@ -2496,88 +2503,88 @@ Zone Asia/Amman 2:23:44 - LMT 1931 # Almaty (formerly Alma-Ata), representing most locations in Kazakhstan # This includes Abai/Abay (ISO 3166-2 code KZ-10), Aqmola/Akmola (KZ-11), # Almaty (KZ-19), Almaty city (KZ-75), Astana city (KZ-71), -# East Kazkhstan (KZ-63), Jambyl/Zhambyl (KZ-31), Jetisu/Zhetysu (KZ-33), +# East Kazakhstan (KZ-63), Jambyl/Zhambyl (KZ-31), Jetisu/Zhetysu (KZ-33), # Karaganda (KZ-35), North Kazakhstan (KZ-59), Pavlodar (KZ-55), -# Shyumkent city (KZ-79), Turkistan (KZ-61), and Ulytau (KZ-62). +# Shymkent city (KZ-79), Turkistan (KZ-61), and Ulytau (KZ-62). Zone Asia/Almaty 5:07:48 - LMT 1924 May 2 # or Alma-Ata - 5:00 - +05 1930 Jun 21 - 6:00 RussiaAsia +06/+07 1991 Mar 31 2:00s - 5:00 RussiaAsia +05/+06 1992 Jan 19 2:00s - 6:00 RussiaAsia +06/+07 2004 Oct 31 2:00s - 6:00 - +06 2024 Mar 1 0:00 - 5:00 - +05 + 5:00 - %z 1930 Jun 21 + 6:00 RussiaAsia %z 1991 Mar 31 2:00s + 5:00 RussiaAsia %z 1992 Jan 19 2:00s + 6:00 RussiaAsia %z 2004 Oct 31 2:00s + 6:00 - %z 2024 Mar 1 0:00 + 5:00 - %z # Qyzylorda (aka Kyzylorda, Kizilorda, Kzyl-Orda, etc.) (KZ-43) Zone Asia/Qyzylorda 4:21:52 - LMT 1924 May 2 - 4:00 - +04 1930 Jun 21 - 5:00 - +05 1981 Apr 1 - 5:00 1:00 +06 1981 Oct 1 - 6:00 - +06 1982 Apr 1 - 5:00 RussiaAsia +05/+06 1991 Mar 31 2:00s - 4:00 RussiaAsia +04/+05 1991 Sep 29 2:00s - 5:00 RussiaAsia +05/+06 1992 Jan 19 2:00s - 6:00 RussiaAsia +06/+07 1992 Mar 29 2:00s - 5:00 RussiaAsia +05/+06 2004 Oct 31 2:00s - 6:00 - +06 2018 Dec 21 0:00 - 5:00 - +05 + 4:00 - %z 1930 Jun 21 + 5:00 - %z 1981 Apr 1 + 5:00 1:00 %z 1981 Oct 1 + 6:00 - %z 1982 Apr 1 + 5:00 RussiaAsia %z 1991 Mar 31 2:00s + 4:00 RussiaAsia %z 1991 Sep 29 2:00s + 5:00 RussiaAsia %z 1992 Jan 19 2:00s + 6:00 RussiaAsia %z 1992 Mar 29 2:00s + 5:00 RussiaAsia %z 2004 Oct 31 2:00s + 6:00 - %z 2018 Dec 21 0:00 + 5:00 - %z # Qostanay (aka Kostanay, Kustanay) (KZ-39) # The 1991/2 rules are unclear partly because of the 1997 Turgai # reorganization. Zone Asia/Qostanay 4:14:28 - LMT 1924 May 2 - 4:00 - +04 1930 Jun 21 - 5:00 - +05 1981 Apr 1 - 5:00 1:00 +06 1981 Oct 1 - 6:00 - +06 1982 Apr 1 - 5:00 RussiaAsia +05/+06 1991 Mar 31 2:00s - 4:00 RussiaAsia +04/+05 1992 Jan 19 2:00s - 5:00 RussiaAsia +05/+06 2004 Oct 31 2:00s - 6:00 - +06 2024 Mar 1 0:00 - 5:00 - +05 + 4:00 - %z 1930 Jun 21 + 5:00 - %z 1981 Apr 1 + 5:00 1:00 %z 1981 Oct 1 + 6:00 - %z 1982 Apr 1 + 5:00 RussiaAsia %z 1991 Mar 31 2:00s + 4:00 RussiaAsia %z 1992 Jan 19 2:00s + 5:00 RussiaAsia %z 2004 Oct 31 2:00s + 6:00 - %z 2024 Mar 1 0:00 + 5:00 - %z # Aqtöbe (aka Aktobe, formerly Aktyubinsk) (KZ-15) Zone Asia/Aqtobe 3:48:40 - LMT 1924 May 2 - 4:00 - +04 1930 Jun 21 - 5:00 - +05 1981 Apr 1 - 5:00 1:00 +06 1981 Oct 1 - 6:00 - +06 1982 Apr 1 - 5:00 RussiaAsia +05/+06 1991 Mar 31 2:00s - 4:00 RussiaAsia +04/+05 1992 Jan 19 2:00s - 5:00 RussiaAsia +05/+06 2004 Oct 31 2:00s - 5:00 - +05 + 4:00 - %z 1930 Jun 21 + 5:00 - %z 1981 Apr 1 + 5:00 1:00 %z 1981 Oct 1 + 6:00 - %z 1982 Apr 1 + 5:00 RussiaAsia %z 1991 Mar 31 2:00s + 4:00 RussiaAsia %z 1992 Jan 19 2:00s + 5:00 RussiaAsia %z 2004 Oct 31 2:00s + 5:00 - %z # Mangghystaū (KZ-47) # Aqtau was not founded until 1963, but it represents an inhabited region, # so include timestamps before 1963. Zone Asia/Aqtau 3:21:04 - LMT 1924 May 2 - 4:00 - +04 1930 Jun 21 - 5:00 - +05 1981 Oct 1 - 6:00 - +06 1982 Apr 1 - 5:00 RussiaAsia +05/+06 1991 Mar 31 2:00s - 4:00 RussiaAsia +04/+05 1992 Jan 19 2:00s - 5:00 RussiaAsia +05/+06 1994 Sep 25 2:00s - 4:00 RussiaAsia +04/+05 2004 Oct 31 2:00s - 5:00 - +05 + 4:00 - %z 1930 Jun 21 + 5:00 - %z 1981 Oct 1 + 6:00 - %z 1982 Apr 1 + 5:00 RussiaAsia %z 1991 Mar 31 2:00s + 4:00 RussiaAsia %z 1992 Jan 19 2:00s + 5:00 RussiaAsia %z 1994 Sep 25 2:00s + 4:00 RussiaAsia %z 2004 Oct 31 2:00s + 5:00 - %z # Atyraū (KZ-23) is like Mangghystaū except it switched from # +04/+05 to +05/+06 in spring 1999, not fall 1994. Zone Asia/Atyrau 3:27:44 - LMT 1924 May 2 - 3:00 - +03 1930 Jun 21 - 5:00 - +05 1981 Oct 1 - 6:00 - +06 1982 Apr 1 - 5:00 RussiaAsia +05/+06 1991 Mar 31 2:00s - 4:00 RussiaAsia +04/+05 1992 Jan 19 2:00s - 5:00 RussiaAsia +05/+06 1999 Mar 28 2:00s - 4:00 RussiaAsia +04/+05 2004 Oct 31 2:00s - 5:00 - +05 + 3:00 - %z 1930 Jun 21 + 5:00 - %z 1981 Oct 1 + 6:00 - %z 1982 Apr 1 + 5:00 RussiaAsia %z 1991 Mar 31 2:00s + 4:00 RussiaAsia %z 1992 Jan 19 2:00s + 5:00 RussiaAsia %z 1999 Mar 28 2:00s + 4:00 RussiaAsia %z 2004 Oct 31 2:00s + 5:00 - %z # West Kazakhstan (KZ-27) # From Paul Eggert (2016-03-18): # The 1989 transition is from USSR act No. 227 (1989-03-14). Zone Asia/Oral 3:25:24 - LMT 1924 May 2 # or Ural'sk - 3:00 - +03 1930 Jun 21 - 5:00 - +05 1981 Apr 1 - 5:00 1:00 +06 1981 Oct 1 - 6:00 - +06 1982 Apr 1 - 5:00 RussiaAsia +05/+06 1989 Mar 26 2:00s - 4:00 RussiaAsia +04/+05 1992 Jan 19 2:00s - 5:00 RussiaAsia +05/+06 1992 Mar 29 2:00s - 4:00 RussiaAsia +04/+05 2004 Oct 31 2:00s - 5:00 - +05 + 3:00 - %z 1930 Jun 21 + 5:00 - %z 1981 Apr 1 + 5:00 1:00 %z 1981 Oct 1 + 6:00 - %z 1982 Apr 1 + 5:00 RussiaAsia %z 1989 Mar 26 2:00s + 4:00 RussiaAsia %z 1992 Jan 19 2:00s + 5:00 RussiaAsia %z 1992 Mar 29 2:00s + 4:00 RussiaAsia %z 2004 Oct 31 2:00s + 5:00 - %z # Kyrgyzstan (Kirgizstan) # Transitions through 1991 are from Shanks & Pottenger. @@ -2598,11 +2605,11 @@ Rule Kyrgyz 1997 2005 - Mar lastSun 2:30 1:00 - Rule Kyrgyz 1997 2004 - Oct lastSun 2:30 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Bishkek 4:58:24 - LMT 1924 May 2 - 5:00 - +05 1930 Jun 21 - 6:00 RussiaAsia +06/+07 1991 Mar 31 2:00s - 5:00 RussiaAsia +05/+06 1991 Aug 31 2:00 - 5:00 Kyrgyz +05/+06 2005 Aug 12 - 6:00 - +06 + 5:00 - %z 1930 Jun 21 + 6:00 RussiaAsia %z 1991 Mar 31 2:00s + 5:00 RussiaAsia %z 1991 Aug 31 2:00 + 5:00 Kyrgyz %z 2005 Aug 12 + 6:00 - %z ############################################################################### @@ -2809,16 +2816,16 @@ Rule NBorneo 1935 1941 - Dec 14 0:00 0 - # and 1982 transition dates are from Mok Ly Yng. # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Kuching 7:21:20 - LMT 1926 Mar - 7:30 - +0730 1933 - 8:00 NBorneo +08/+0820 1942 Feb 16 - 9:00 - +09 1945 Sep 12 - 8:00 - +08 + 7:30 - %z 1933 + 8:00 NBorneo %z 1942 Feb 16 + 9:00 - %z 1945 Sep 12 + 8:00 - %z # Maldives # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Indian/Maldives 4:54:00 - LMT 1880 # Malé 4:54:00 - MMT 1960 # Malé Mean Time - 5:00 - +05 + 5:00 - %z # Mongolia @@ -2920,9 +2927,37 @@ Zone Indian/Maldives 4:54:00 - LMT 1880 # Malé # From Arthur David Olson (2008-05-19): # Assume that Choibalsan is indeed offset by 8:00. -# XXX--in the absence of better information, assume that transition -# was at the start of 2008-03-31 (the day of Steffen Thorsen's report); -# this is almost surely wrong. + +# From Heitor David Pinto (2024-06-23): +# Sources about time zones in Mongolia seem to list one of two conflicting +# configurations. The first configuration, mentioned in a comment to the TZ +# database in 1999, citing a Mongolian government website, lists the provinces +# of Bayan-Ölgii, Khovd and Uvs in UTC+7, and the rest of the country in +# UTC+8. The second configuration, mentioned in a comment to the database in +# 2001, lists Bayan-Ölgii, Khovd, Uvs, Govi-Altai and Zavkhan in UTC+7, Dornod +# and Sükhbaatar in UTC+9, and the rest of the country in UTC+8. +# +# The first configuration is still mentioned by several Mongolian travel +# agencies: +# https://www.adventurerider.mn/en/page/about_mongolia +# http://www.naturetours.mn/nt/mongolia.php +# https://www.newjuulchin.mn/web/content/7506?unique=fa24a0f6e96e022a3578ee5195ac879638c734ce +# +# It also matches these flight schedules in 2013: +# http://web.archive.org/web/20130722023600/https://www.hunnuair.com/en/timetabled +# The flight times imply that the airports of Uliastai (Zavkhan), Choibalsan +# (Dornod) and Altai (Govi-Altai) are in the same time zone as Ulaanbaatar, +# and Khovd is one hour behind.... +# +# The second configuration was mentioned by an official of the Mongolian +# standards agency in an interview in 2014: https://ikon.mn/n/9v6 +# And it's still listed by the Mongolian aviation agency: +# https://ais.mn/files/aip/eAIP/2023-12-25/html/eSUP/ZM-eSUP-23-04-en-MN.html +# +# ... I believe that the first configuration is what is actually observed in +# Mongolia and has been so all along, at least since 1999. The second +# configuration closely matches the ideal time zone boundaries at 97.5° E and +# 112.5° E but it doesn't seem to be used in practice. # From Ganbold Tsagaankhuu (2015-03-10): # It seems like yesterday Mongolian Government meeting has concluded to use @@ -2961,25 +2996,18 @@ Rule Mongol 2015 2016 - Sep lastSat 0:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] # Hovd, a.k.a. Chovd, Dund-Us, Dzhargalant, Khovd, Jirgalanta Zone Asia/Hovd 6:06:36 - LMT 1905 Aug - 6:00 - +06 1978 - 7:00 Mongol +07/+08 + 6:00 - %z 1978 + 7:00 Mongol %z # Ulaanbaatar, a.k.a. Ulan Bataar, Ulan Bator, Urga Zone Asia/Ulaanbaatar 7:07:32 - LMT 1905 Aug - 7:00 - +07 1978 - 8:00 Mongol +08/+09 -# Choibalsan, a.k.a. Bajan Tümen, Bajan Tumen, Chojbalsan, -# Choybalsan, Sanbejse, Tchoibalsan -Zone Asia/Choibalsan 7:38:00 - LMT 1905 Aug - 7:00 - +07 1978 - 8:00 - +08 1983 Apr - 9:00 Mongol +09/+10 2008 Mar 31 - 8:00 Mongol +08/+09 + 7:00 - %z 1978 + 8:00 Mongol %z # Nepal # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Kathmandu 5:41:16 - LMT 1920 - 5:30 - +0530 1986 - 5:45 - +0545 + 5:30 - %z 1986 + 5:45 - %z # Pakistan @@ -3125,10 +3153,10 @@ Rule Pakistan 2009 only - Apr 15 0:00 1:00 S # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Karachi 4:28:12 - LMT 1907 - 5:30 - +0530 1942 Sep - 5:30 1:00 +0630 1945 Oct 15 - 5:30 - +0530 1951 Sep 30 - 5:00 - +05 1971 Mar 26 + 5:30 - %z 1942 Sep + 5:30 1:00 %z 1945 Oct 15 + 5:30 - %z 1951 Sep 30 + 5:00 - %z 1971 Mar 26 5:00 Pakistan PK%sT # Pakistan Time # Palestine @@ -3676,14 +3704,14 @@ Zone Asia/Hebron 2:20:23 - LMT 1900 Oct # Philippine Star 2014-08-05 # http://www.philstar.com/headlines/2014/08/05/1354152/pnoy-urged-declare-use-daylight-saving-time -# From Paul Goyette (2018-06-15): +# From Paul Goyette (2018-06-15) with URLs updated by Guy Harris (2024-02-15): # In the Philippines, there is a national law, Republic Act No. 10535 # which declares the official time here as "Philippine Standard Time". # The act [1] even specifies use of PST as the abbreviation, although # the FAQ provided by PAGASA [2] uses the "acronym PhST to distinguish # it from the Pacific Standard Time (PST)." -# [1] http://www.officialgazette.gov.ph/2013/05/15/republic-act-no-10535/ -# [2] https://www1.pagasa.dost.gov.ph/index.php/astronomy/philippine-standard-time#republic-act-10535 +# [1] https://www.officialgazette.gov.ph/2013/05/15/republic-act-no-10535/ +# [2] https://prsd.pagasa.dost.gov.ph/index.php/28-astronomy/302-philippine-standard-time # # From Paul Eggert (2018-06-19): # I surveyed recent news reports, and my impression is that "PST" is @@ -3716,8 +3744,8 @@ Zone Asia/Manila -15:56:00 - LMT 1844 Dec 31 # Qatar # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Qatar 3:26:08 - LMT 1920 # Al Dawhah / Doha - 4:00 - +04 1972 Jun - 3:00 - +03 + 4:00 - %z 1972 Jun + 3:00 - %z # Kuwait # Saudi Arabia @@ -3767,7 +3795,7 @@ Zone Asia/Qatar 3:26:08 - LMT 1920 # Al Dawhah / Doha # # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Riyadh 3:06:52 - LMT 1947 Mar 14 - 3:00 - +03 + 3:00 - %z # Singapore # taken from Mok Ly Yng (2003-10-30) @@ -3775,13 +3803,13 @@ Zone Asia/Riyadh 3:06:52 - LMT 1947 Mar 14 # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Singapore 6:55:25 - LMT 1901 Jan 1 6:55:25 - SMT 1905 Jun 1 # Singapore M.T. - 7:00 - +07 1933 Jan 1 - 7:00 0:20 +0720 1936 Jan 1 - 7:20 - +0720 1941 Sep 1 - 7:30 - +0730 1942 Feb 16 - 9:00 - +09 1945 Sep 12 - 7:30 - +0730 1981 Dec 31 16:00u - 8:00 - +08 + 7:00 - %z 1933 Jan 1 + 7:00 0:20 %z 1936 Jan 1 + 7:20 - %z 1941 Sep 1 + 7:30 - %z 1942 Feb 16 + 9:00 - %z 1945 Sep 12 + 7:30 - %z 1981 Dec 31 16:00u + 8:00 - %z # Spratly Is # no information @@ -3839,13 +3867,13 @@ Zone Asia/Singapore 6:55:25 - LMT 1901 Jan 1 # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Colombo 5:19:24 - LMT 1880 5:19:32 - MMT 1906 # Moratuwa Mean Time - 5:30 - +0530 1942 Jan 5 - 5:30 0:30 +06 1942 Sep - 5:30 1:00 +0630 1945 Oct 16 2:00 - 5:30 - +0530 1996 May 25 0:00 - 6:30 - +0630 1996 Oct 26 0:30 - 6:00 - +06 2006 Apr 15 0:30 - 5:30 - +0530 + 5:30 - %z 1942 Jan 5 + 5:30 0:30 %z 1942 Sep + 5:30 1:00 %z 1945 Oct 16 2:00 + 5:30 - %z 1996 May 25 0:00 + 6:30 - %z 1996 Oct 26 0:30 + 6:00 - %z 2006 Apr 15 0:30 + 5:30 - %z # Syria # Rule NAME FROM TO - IN ON AT SAVE LETTER/S @@ -4016,16 +4044,16 @@ Rule Syria 2009 2022 - Oct lastFri 0:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Damascus 2:25:12 - LMT 1920 # Dimashq 2:00 Syria EE%sT 2022 Oct 28 0:00 - 3:00 - +03 + 3:00 - %z # Tajikistan # From Shanks & Pottenger. # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Dushanbe 4:35:12 - LMT 1924 May 2 - 5:00 - +05 1930 Jun 21 - 6:00 RussiaAsia +06/+07 1991 Mar 31 2:00s - 5:00 1:00 +06 1991 Sep 9 2:00s - 5:00 - +05 + 5:00 - %z 1930 Jun 21 + 6:00 RussiaAsia %z 1991 Mar 31 2:00s + 5:00 1:00 %z 1991 Sep 9 2:00s + 5:00 - %z # Cambodia # Christmas I @@ -4035,16 +4063,16 @@ Zone Asia/Dushanbe 4:35:12 - LMT 1924 May 2 # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Bangkok 6:42:04 - LMT 1880 6:42:04 - BMT 1920 Apr # Bangkok Mean Time - 7:00 - +07 + 7:00 - %z # Turkmenistan # From Shanks & Pottenger. # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Ashgabat 3:53:32 - LMT 1924 May 2 # or Ashkhabad - 4:00 - +04 1930 Jun 21 - 5:00 RussiaAsia +05/+06 1991 Mar 31 2:00 - 4:00 RussiaAsia +04/+05 1992 Jan 19 2:00 - 5:00 - +05 + 4:00 - %z 1930 Jun 21 + 5:00 RussiaAsia %z 1991 Mar 31 2:00 + 4:00 RussiaAsia %z 1992 Jan 19 2:00 + 5:00 - %z # Oman # Réunion @@ -4054,25 +4082,25 @@ Zone Asia/Ashgabat 3:53:32 - LMT 1924 May 2 # or Ashkhabad # The Crozet Is also observe Réunion time; see the 'antarctica' file. # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Dubai 3:41:12 - LMT 1920 - 4:00 - +04 + 4:00 - %z # Uzbekistan # Byalokoz 1919 says Uzbekistan was 4:27:53. # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Samarkand 4:27:53 - LMT 1924 May 2 - 4:00 - +04 1930 Jun 21 - 5:00 - +05 1981 Apr 1 - 5:00 1:00 +06 1981 Oct 1 - 6:00 - +06 1982 Apr 1 - 5:00 RussiaAsia +05/+06 1992 - 5:00 - +05 + 4:00 - %z 1930 Jun 21 + 5:00 - %z 1981 Apr 1 + 5:00 1:00 %z 1981 Oct 1 + 6:00 - %z 1982 Apr 1 + 5:00 RussiaAsia %z 1992 + 5:00 - %z # Milne says Tashkent was 4:37:10.8. #STDOFF 4:37:10.8 Zone Asia/Tashkent 4:37:11 - LMT 1924 May 2 - 5:00 - +05 1930 Jun 21 - 6:00 RussiaAsia +06/+07 1991 Mar 31 2:00 - 5:00 RussiaAsia +05/+06 1992 - 5:00 - +05 + 5:00 - %z 1930 Jun 21 + 6:00 RussiaAsia %z 1991 Mar 31 2:00 + 5:00 RussiaAsia %z 1992 + 5:00 - %z # Vietnam (southern) @@ -4130,7 +4158,7 @@ Zone Asia/Tashkent 4:37:11 - LMT 1924 May 2 # Võ Nguyên Giáp, Việt Nam Dân Quốc Công Báo, No. 1 (1945-09-29), page 13 # http://baochi.nlv.gov.vn/baochi/cgi-bin/baochi?a=d&d=JwvzO19450929.2.5&dliv=none # It says that on 1945-09-01 at 24:00, Vietnam moved back two hours, to +07. -# It also mentions a 1945-03-29 decree (by a Japanese Goveror-General) +# It also mentions a 1945-03-29 decree (by a Japanese Governor-General) # to set the time zone to +09, but does not say whether that decree # merely legalized an earlier change to +09. # @@ -4151,14 +4179,14 @@ Zone Asia/Tashkent 4:37:11 - LMT 1924 May 2 #STDOFF 7:06:30.13 Zone Asia/Ho_Chi_Minh 7:06:30 - LMT 1906 Jul 1 7:06:30 - PLMT 1911 May 1 # Phù Liễn MT - 7:00 - +07 1942 Dec 31 23:00 - 8:00 - +08 1945 Mar 14 23:00 - 9:00 - +09 1945 Sep 1 24:00 - 7:00 - +07 1947 Apr 1 - 8:00 - +08 1955 Jul 1 01:00 - 7:00 - +07 1959 Dec 31 23:00 - 8:00 - +08 1975 Jun 13 - 7:00 - +07 + 7:00 - %z 1942 Dec 31 23:00 + 8:00 - %z 1945 Mar 14 23:00 + 9:00 - %z 1945 Sep 1 24:00 + 7:00 - %z 1947 Apr 1 + 8:00 - %z 1955 Jul 1 01:00 + 7:00 - %z 1959 Dec 31 23:00 + 8:00 - %z 1975 Jun 13 + 7:00 - %z # From Paul Eggert (2019-02-19): # diff --git a/src/java.base/share/data/tzdata/australasia b/src/java.base/share/data/tzdata/australasia index 624735be652d2..09698826a4969 100644 --- a/src/java.base/share/data/tzdata/australasia +++ b/src/java.base/share/data/tzdata/australasia @@ -66,8 +66,8 @@ Zone Australia/Perth 7:43:24 - LMT 1895 Dec 8:00 Aus AW%sT 1943 Jul 8:00 AW AW%sT Zone Australia/Eucla 8:35:28 - LMT 1895 Dec - 8:45 Aus +0845/+0945 1943 Jul - 8:45 AW +0845/+0945 + 8:45 Aus %z 1943 Jul + 8:45 AW %z # Queensland # @@ -232,8 +232,8 @@ Rule LH 2008 max - Apr Sun>=1 2:00 0 - Rule LH 2008 max - Oct Sun>=1 2:00 0:30 - Zone Australia/Lord_Howe 10:36:20 - LMT 1895 Feb 10:00 - AEST 1981 Mar - 10:30 LH +1030/+1130 1985 Jul - 10:30 LH +1030/+11 + 10:30 LH %z 1985 Jul + 10:30 LH %z # Australian miscellany # @@ -439,16 +439,16 @@ Rule Fiji 2019 only - Nov Sun>=8 2:00 1:00 - Rule Fiji 2020 only - Dec 20 2:00 1:00 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Fiji 11:55:44 - LMT 1915 Oct 26 # Suva - 12:00 Fiji +12/+13 + 12:00 Fiji %z # French Polynesia # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Gambier -8:59:48 - LMT 1912 Oct 1 # Rikitea - -9:00 - -09 + -9:00 - %z Zone Pacific/Marquesas -9:18:00 - LMT 1912 Oct 1 - -9:30 - -0930 + -9:30 - %z Zone Pacific/Tahiti -9:58:16 - LMT 1912 Oct 1 # Papeete - -10:00 - -10 + -10:00 - %z # Clipperton (near North America) is administered from French Polynesia; # it is uninhabited. @@ -491,7 +491,7 @@ Rule Guam 1977 only - Aug 28 2:00 0 S Zone Pacific/Guam -14:21:00 - LMT 1844 Dec 31 9:39:00 - LMT 1901 # Agana 10:00 - GST 1941 Dec 10 # Guam - 9:00 - +09 1944 Jul 31 + 9:00 - %z 1944 Jul 31 10:00 Guam G%sT 2000 Dec 23 10:00 - ChST # Chamorro Standard Time @@ -503,30 +503,30 @@ Zone Pacific/Guam -14:21:00 - LMT 1844 Dec 31 # Wallis & Futuna # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Tarawa 11:32:04 - LMT 1901 # Bairiki - 12:00 - +12 + 12:00 - %z # Kiribati (except Gilbert Is) # See Pacific/Tarawa for the Gilbert Is. # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Kanton 0 - -00 1937 Aug 31 - -12:00 - -12 1979 Oct - -11:00 - -11 1994 Dec 31 - 13:00 - +13 + -12:00 - %z 1979 Oct + -11:00 - %z 1994 Dec 31 + 13:00 - %z Zone Pacific/Kiritimati -10:29:20 - LMT 1901 - -10:40 - -1040 1979 Oct - -10:00 - -10 1994 Dec 31 - 14:00 - +14 + -10:40 - %z 1979 Oct + -10:00 - %z 1994 Dec 31 + 14:00 - %z # Marshall Is # See Pacific/Tarawa for most locations. # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Kwajalein 11:09:20 - LMT 1901 - 11:00 - +11 1937 - 10:00 - +10 1941 Apr 1 - 9:00 - +09 1944 Feb 6 - 11:00 - +11 1969 Oct - -12:00 - -12 1993 Aug 20 24:00 - 12:00 - +12 + 11:00 - %z 1937 + 10:00 - %z 1941 Apr 1 + 9:00 - %z 1944 Feb 6 + 11:00 - %z 1969 Oct + -12:00 - %z 1993 Aug 20 24:00 + 12:00 - %z # Micronesia # For Chuuk and Yap see Pacific/Port_Moresby. @@ -534,22 +534,22 @@ Zone Pacific/Kwajalein 11:09:20 - LMT 1901 # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Kosrae -13:08:04 - LMT 1844 Dec 31 10:51:56 - LMT 1901 - 11:00 - +11 1914 Oct - 9:00 - +09 1919 Feb 1 - 11:00 - +11 1937 - 10:00 - +10 1941 Apr 1 - 9:00 - +09 1945 Aug - 11:00 - +11 1969 Oct - 12:00 - +12 1999 - 11:00 - +11 + 11:00 - %z 1914 Oct + 9:00 - %z 1919 Feb 1 + 11:00 - %z 1937 + 10:00 - %z 1941 Apr 1 + 9:00 - %z 1945 Aug + 11:00 - %z 1969 Oct + 12:00 - %z 1999 + 11:00 - %z # Nauru # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Nauru 11:07:40 - LMT 1921 Jan 15 # Uaobe - 11:30 - +1130 1942 Aug 29 - 9:00 - +09 1945 Sep 8 - 11:30 - +1130 1979 Feb 10 2:00 - 12:00 - +12 + 11:30 - %z 1942 Aug 29 + 9:00 - %z 1945 Sep 8 + 11:30 - %z 1979 Feb 10 2:00 + 12:00 - %z # New Caledonia # Rule NAME FROM TO - IN ON AT SAVE LETTER/S @@ -560,7 +560,7 @@ Rule NC 1996 only - Dec 1 2:00s 1:00 - Rule NC 1997 only - Mar 2 2:00s 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Noumea 11:05:48 - LMT 1912 Jan 13 # Nouméa - 11:00 NC +11/+12 + 11:00 NC %z ############################################################################### @@ -604,8 +604,8 @@ Zone Pacific/Auckland 11:39:04 - LMT 1868 Nov 2 12:00 NZ NZ%sT Zone Pacific/Chatham 12:13:48 - LMT 1868 Nov 2 - 12:15 - +1215 1946 Jan 1 - 12:45 Chatham +1245/+1345 + 12:15 - %z 1946 Jan 1 + 12:45 Chatham %z # Auckland Is # uninhabited; Māori and Moriori, colonial settlers, pastoralists, sealers, @@ -658,8 +658,8 @@ Rule Cook 1979 1990 - Oct lastSun 0:00 0:30 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Rarotonga 13:20:56 - LMT 1899 Dec 26 # Avarua -10:39:04 - LMT 1952 Oct 16 - -10:30 - -1030 1978 Nov 12 - -10:00 Cook -10/-0930 + -10:30 - %z 1978 Nov 12 + -10:00 Cook %z ############################################################################### @@ -676,30 +676,30 @@ Zone Pacific/Rarotonga 13:20:56 - LMT 1899 Dec 26 # Avarua # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Niue -11:19:40 - LMT 1952 Oct 16 # Alofi - -11:20 - -1120 1964 Jul - -11:00 - -11 + -11:20 - %z 1964 Jul + -11:00 - %z # Norfolk # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Norfolk 11:11:52 - LMT 1901 # Kingston - 11:12 - +1112 1951 - 11:30 - +1130 1974 Oct 27 02:00s - 11:30 1:00 +1230 1975 Mar 2 02:00s - 11:30 - +1130 2015 Oct 4 02:00s - 11:00 - +11 2019 Jul - 11:00 AN +11/+12 + 11:12 - %z 1951 + 11:30 - %z 1974 Oct 27 02:00s + 11:30 1:00 %z 1975 Mar 2 02:00s + 11:30 - %z 2015 Oct 4 02:00s + 11:00 - %z 2019 Jul + 11:00 AN %z # Palau (Belau) # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Palau -15:02:04 - LMT 1844 Dec 31 # Koror 8:57:56 - LMT 1901 - 9:00 - +09 + 9:00 - %z # Papua New Guinea # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Port_Moresby 9:48:40 - LMT 1880 9:48:32 - PMMT 1895 # Port Moresby Mean Time - 10:00 - +10 + 10:00 - %z # # From Paul Eggert (2014-10-13): # Base the Bougainville entry on the Arawa-Kieta region, which appears to have @@ -720,16 +720,16 @@ Zone Pacific/Port_Moresby 9:48:40 - LMT 1880 # Zone Pacific/Bougainville 10:22:16 - LMT 1880 9:48:32 - PMMT 1895 - 10:00 - +10 1942 Jul - 9:00 - +09 1945 Aug 21 - 10:00 - +10 2014 Dec 28 2:00 - 11:00 - +11 + 10:00 - %z 1942 Jul + 9:00 - %z 1945 Aug 21 + 10:00 - %z 2014 Dec 28 2:00 + 11:00 - %z # Pitcairn # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Pitcairn -8:40:20 - LMT 1901 # Adamstown - -8:30 - -0830 1998 Apr 27 0:00 - -8:00 - -08 + -8:30 - %z 1998 Apr 27 0:00 + -8:00 - %z # American Samoa # Midway @@ -818,15 +818,15 @@ Rule WS 2012 2020 - Sep lastSun 3:00 1 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Apia 12:33:04 - LMT 1892 Jul 5 -11:26:56 - LMT 1911 - -11:30 - -1130 1950 - -11:00 WS -11/-10 2011 Dec 29 24:00 - 13:00 WS +13/+14 + -11:30 - %z 1950 + -11:00 WS %z 2011 Dec 29 24:00 + 13:00 WS %z # Solomon Is # excludes Bougainville, for which see Papua New Guinea # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Guadalcanal 10:39:48 - LMT 1912 Oct 1 # Honiara - 11:00 - +11 + 11:00 - %z # Tokelau # @@ -849,8 +849,8 @@ Zone Pacific/Guadalcanal 10:39:48 - LMT 1912 Oct 1 # Honiara # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Fakaofo -11:24:56 - LMT 1901 - -11:00 - -11 2011 Dec 30 - 13:00 - +13 + -11:00 - %z 2011 Dec 30 + 13:00 - %z # Tonga # Rule NAME FROM TO - IN ON AT SAVE LETTER/S @@ -862,9 +862,9 @@ Rule Tonga 2016 only - Nov Sun>=1 2:00 1:00 - Rule Tonga 2017 only - Jan Sun>=15 3:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Tongatapu 12:19:12 - LMT 1945 Sep 10 - 12:20 - +1220 1961 - 13:00 - +13 1999 - 13:00 Tonga +13/+14 + 12:20 - %z 1961 + 13:00 - %z 1999 + 13:00 Tonga %z # US minor outlying islands @@ -953,7 +953,7 @@ Rule Vanuatu 1992 1993 - Jan Sat>=22 24:00 0 - Rule Vanuatu 1992 only - Oct Sat>=22 24:00 1:00 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Efate 11:13:16 - LMT 1912 Jan 13 # Vila - 11:00 Vanuatu +11/+12 + 11:00 Vanuatu %z ############################################################################### diff --git a/src/java.base/share/data/tzdata/backward b/src/java.base/share/data/tzdata/backward index 7ddc6cc3d93b0..cda2ccc0c66ec 100644 --- a/src/java.base/share/data/tzdata/backward +++ b/src/java.base/share/data/tzdata/backward @@ -21,12 +21,13 @@ # or visit www.oracle.com if you need additional information or have any # questions. # -# tzdb links for backward compatibility +# Links and zones for backward compatibility # This file is in the public domain, so clarified as of # 2009-05-17 by Arthur David Olson. # This file provides links from old or merged timezone names to current ones. +# It also provides a few zone entries for old naming conventions. # Many names changed in 1993 and in 1995, and many merged names moved here # in the period from 2013 through 2022. Several of these names are # also present in the file 'backzone', which has data important only @@ -67,6 +68,8 @@ Link America/Rio_Branco Brazil/Acre #= America/Porto_Acre Link America/Noronha Brazil/DeNoronha Link America/Sao_Paulo Brazil/East Link America/Manaus Brazil/West +Link Europe/Brussels CET +Link America/Chicago CST6CDT Link America/Halifax Canada/Atlantic Link America/Winnipeg Canada/Central # This line is commented out, as the name exceeded the 14-character limit @@ -81,6 +84,9 @@ Link America/Whitehorse Canada/Yukon Link America/Santiago Chile/Continental Link Pacific/Easter Chile/EasterIsland Link America/Havana Cuba +Link Europe/Athens EET +Link America/Panama EST +Link America/New_York EST5EDT Link Africa/Cairo Egypt Link Europe/Dublin Eire # Vanguard section, for most .zi parsers. @@ -119,6 +125,9 @@ Link America/Jamaica Jamaica Link Asia/Tokyo Japan Link Pacific/Kwajalein Kwajalein Link Africa/Tripoli Libya +Link Europe/Brussels MET +Link America/Phoenix MST +Link America/Denver MST7MDT Link America/Tijuana Mexico/BajaNorte Link America/Mazatlan Mexico/BajaSur Link America/Mexico_City Mexico/General @@ -298,6 +307,7 @@ Link America/Denver America/Shiprock Link America/Toronto America/Thunder_Bay Link America/Edmonton America/Yellowknife Link Pacific/Auckland Antarctica/South_Pole +Link Asia/Ulaanbaatar Asia/Choibalsan Link Asia/Shanghai Asia/Chongqing Link Asia/Shanghai Asia/Harbin Link Asia/Urumqi Asia/Kashgar @@ -312,6 +322,7 @@ Link Europe/Kyiv Europe/Zaporozhye Link Pacific/Kanton Pacific/Enderbury Link Pacific/Honolulu Pacific/Johnston Link Pacific/Port_Moresby Pacific/Yap +Link Europe/Lisbon WET # Alternate names for the same location @@ -337,5 +348,7 @@ Link Europe/Kyiv Europe/Kiev # Classically, Cyprus is in Asia; e.g. see Herodotus, Histories, I.72. # However, for various reasons many users expect to find it under Europe. Link Asia/Nicosia Europe/Nicosia +Link Pacific/Honolulu HST +Link America/Los_Angeles PST8PDT Link Pacific/Guadalcanal Pacific/Ponape #= Pacific/Pohnpei Link Pacific/Port_Moresby Pacific/Truk #= Pacific/Chuuk diff --git a/src/java.base/share/data/tzdata/etcetera b/src/java.base/share/data/tzdata/etcetera index 27147715ef6a5..780c835819def 100644 --- a/src/java.base/share/data/tzdata/etcetera +++ b/src/java.base/share/data/tzdata/etcetera @@ -28,7 +28,7 @@ # These entries are for uses not otherwise covered by the tz database. # Their main practical use is for platforms like Android that lack -# support for POSIX.1-2017-style TZ strings. On such platforms these entries +# support for POSIX proleptic TZ strings. On such platforms these entries # can be useful if the timezone database is wrong or if a ship or # aircraft at sea is not in a timezone. @@ -74,29 +74,29 @@ Link Etc/GMT GMT # so we moved the names into the Etc subdirectory. # Also, the time zone abbreviations are now compatible with %z. -Zone Etc/GMT-14 14 - +14 -Zone Etc/GMT-13 13 - +13 -Zone Etc/GMT-12 12 - +12 -Zone Etc/GMT-11 11 - +11 -Zone Etc/GMT-10 10 - +10 -Zone Etc/GMT-9 9 - +09 -Zone Etc/GMT-8 8 - +08 -Zone Etc/GMT-7 7 - +07 -Zone Etc/GMT-6 6 - +06 -Zone Etc/GMT-5 5 - +05 -Zone Etc/GMT-4 4 - +04 -Zone Etc/GMT-3 3 - +03 -Zone Etc/GMT-2 2 - +02 -Zone Etc/GMT-1 1 - +01 -Zone Etc/GMT+1 -1 - -01 -Zone Etc/GMT+2 -2 - -02 -Zone Etc/GMT+3 -3 - -03 -Zone Etc/GMT+4 -4 - -04 -Zone Etc/GMT+5 -5 - -05 -Zone Etc/GMT+6 -6 - -06 -Zone Etc/GMT+7 -7 - -07 -Zone Etc/GMT+8 -8 - -08 -Zone Etc/GMT+9 -9 - -09 -Zone Etc/GMT+10 -10 - -10 -Zone Etc/GMT+11 -11 - -11 -Zone Etc/GMT+12 -12 - -12 +Zone Etc/GMT-14 14 - %z +Zone Etc/GMT-13 13 - %z +Zone Etc/GMT-12 12 - %z +Zone Etc/GMT-11 11 - %z +Zone Etc/GMT-10 10 - %z +Zone Etc/GMT-9 9 - %z +Zone Etc/GMT-8 8 - %z +Zone Etc/GMT-7 7 - %z +Zone Etc/GMT-6 6 - %z +Zone Etc/GMT-5 5 - %z +Zone Etc/GMT-4 4 - %z +Zone Etc/GMT-3 3 - %z +Zone Etc/GMT-2 2 - %z +Zone Etc/GMT-1 1 - %z +Zone Etc/GMT+1 -1 - %z +Zone Etc/GMT+2 -2 - %z +Zone Etc/GMT+3 -3 - %z +Zone Etc/GMT+4 -4 - %z +Zone Etc/GMT+5 -5 - %z +Zone Etc/GMT+6 -6 - %z +Zone Etc/GMT+7 -7 - %z +Zone Etc/GMT+8 -8 - %z +Zone Etc/GMT+9 -9 - %z +Zone Etc/GMT+10 -10 - %z +Zone Etc/GMT+11 -11 - %z +Zone Etc/GMT+12 -12 - %z diff --git a/src/java.base/share/data/tzdata/europe b/src/java.base/share/data/tzdata/europe index 18865f33b6c59..df203f218d118 100644 --- a/src/java.base/share/data/tzdata/europe +++ b/src/java.base/share/data/tzdata/europe @@ -753,14 +753,6 @@ Rule Russia 1996 2010 - Oct lastSun 2:00s 0 - # Take "abolishing daylight saving time" to mean that time is now considered # to be standard. -# These are for backward compatibility with older versions. - -# Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone WET 0:00 EU WE%sT -Zone CET 1:00 C-Eur CE%sT -Zone MET 1:00 C-Eur ME%sT -Zone EET 2:00 EU EE%sT - # Previous editions of this database used abbreviations like MET DST # for Central European Summer Time, but this didn't agree with common usage. @@ -894,7 +886,7 @@ Zone Europe/Minsk 1:50:16 - LMT 1880 3:00 Russia MSK/MSD 1990 3:00 - MSK 1991 Mar 31 2:00s 2:00 Russia EE%sT 2011 Mar 27 2:00s - 3:00 - +03 + 3:00 - %z # Belgium # Luxembourg @@ -1199,22 +1191,22 @@ Rule Thule 2007 max - Nov Sun>=1 2:00 0 S # # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/Danmarkshavn -1:14:40 - LMT 1916 Jul 28 - -3:00 - -03 1980 Apr 6 2:00 - -3:00 EU -03/-02 1996 + -3:00 - %z 1980 Apr 6 2:00 + -3:00 EU %z 1996 0:00 - GMT # # Use the old name Scoresbysund, as the current name Ittoqqortoormiit # exceeds tzdb's 14-letter limit and has no common English abbreviation. Zone America/Scoresbysund -1:27:52 - LMT 1916 Jul 28 # Ittoqqortoormiit - -2:00 - -02 1980 Apr 6 2:00 - -2:00 C-Eur -02/-01 1981 Mar 29 - -1:00 EU -01/+00 2024 Mar 31 - -2:00 EU -02/-01 + -2:00 - %z 1980 Apr 6 2:00 + -2:00 C-Eur %z 1981 Mar 29 + -1:00 EU %z 2024 Mar 31 + -2:00 EU %z Zone America/Nuuk -3:26:56 - LMT 1916 Jul 28 # Godthåb - -3:00 - -03 1980 Apr 6 2:00 - -3:00 EU -03/-02 2023 Mar 26 1:00u - -2:00 - -02 2023 Oct 29 1:00u - -2:00 EU -02/-01 + -3:00 - %z 1980 Apr 6 2:00 + -3:00 EU %z 2023 Mar 26 1:00u + -2:00 - %z 2023 Oct 29 1:00u + -2:00 EU %z Zone America/Thule -4:35:08 - LMT 1916 Jul 28 # Pituffik -4:00 Thule A%sT @@ -2086,10 +2078,39 @@ Zone Europe/Warsaw 1:24:00 - LMT 1880 # Portugal -# From Paul Eggert (2014-08-11), after a heads-up from Stephen Colebourne: -# According to a Portuguese decree (1911-05-26) -# https://dre.pt/application/dir/pdf1sdip/1911/05/12500/23132313.pdf -# Lisbon was at -0:36:44.68, but switched to GMT on 1912-01-01 at 00:00. +# From Tim Parenti (2024-07-01), per Alois Treindl (2021-02-07) and Michael +# Deckers (2021-02-10): +# http://oal.ul.pt/documentos/2018/01/hl1911a2018.pdf/ +# The Astronomical Observatory of Lisbon has published a list detailing the +# historical transitions in legal time within continental Portugal. It +# directly references many decrees and ordinances which are, in turn, +# referenced below. They can be viewed in the public archives of the Diário da +# República (until 1976-04-09 known as the Diário do Govêrno) at +# https://dre.pt/ (in Portuguese). +# +# Most of the Rules below have been updated simply to match the Observatory's +# listing for continental (mainland) Portugal. Although there are over 50 +# referenced decrees and ordinances, only the handful with comments below have +# been verified against the text, typically to provide additional confidence +# wherever dates provided by Whitman and Shanks & Pottenger had disagreed. +# See further below for the Azores and Madeira. + +# From Tim Parenti (2024-07-01), per Paul Eggert (2014-08-11), after a +# heads-up from Stephen Colebourne: +# According to a 1911-05-24 Portuguese decree, Lisbon was at -0:36:44.68, but +# switched to GMT on 1912-01-01 at 00:00. +# https://dre.pt/dr/detalhe/decreto/593090 +# https://dre.pt/application/conteudo/593090 +# The decree made legal time throughout Portugal and her possessions +# "subordinate to the Greenwich meridian, according to the principle adopted at +# the Washington Convention in 1884" and eliminated the "difference of five +# minutes between the internal and external clocks of railway stations". +# +# The decree was gazetted in the 1911-05-30 issue of Diário do Govêrno, and is +# considered to be dated 1911-05-24 by that issue's summary; however, the text +# of the decree itself is dated 1911-05-26. The Diário da República website +# notes the discrepancy, but later laws and the Observatory all seem to refer +# to this decree by the 1911-05-24 date. # # From Michael Deckers (2018-02-15): # article 5 [of the 1911 decree; Deckers's translation] ...: @@ -2097,37 +2118,62 @@ Zone Europe/Warsaw 1:24:00 - LMT 1880 # according to the 2nd article, the civil day January 1, 1912 begins, # all clocks therefore having to be advanced or set back correspondingly ... -# From Rui Pedro Salgueiro (1992-11-12): -# Portugal has recently (September, 27) changed timezone -# (from WET to MET or CET) to harmonize with EEC. -# -# Martin Bruckmann (1996-02-29) reports via Peter Ilieve -# that Portugal is reverting to 0:00 by not moving its clocks this spring. -# The new Prime Minister was fed up with getting up in the dark in the winter. -# -# From Paul Eggert (1996-11-12): -# IATA SSIM (1991-09) reports several 1991-09 and 1992-09 transitions -# at 02:00u, not 01:00u. Assume that these are typos. -# IATA SSIM (1991/1992) reports that the Azores were at -1:00. -# IATA SSIM (1993-02) says +0:00; later issues (through 1996-09) say -1:00. -# Guess that the Azores changed to EU rules in 1992 (since that's when Portugal -# harmonized with EU rules), and that they stayed +0:00 that winter. -# # Rule NAME FROM TO - IN ON AT SAVE LETTER/S -# DSH writes that despite Decree 1,469 (1915), the change to the clocks was not -# done every year, depending on what Spain did, because of railroad schedules. -# Go with Shanks & Pottenger. +# From Tim Parenti (2024-07-01), per Paul Eggert (1999-01-30): +# DSH writes in their history that Decreto 1469 of 1915-03-30 established +# summer time and that, "despite" this, the change to the clocks was not done +# every year, depending on what Spain did, because of railroad schedules. +# In fact, that decree had nothing to do with DST; rather, it regulated the +# sending of time signals. But we do see linkage to Spain in the 1920s below. +# https://dre.pt/dr/detalhe/decreto/1469-1915-285721 +# https://dre.pt/application/conteudo/285721 +# +# According to the Observatory, standard time was first advanced by Decreto +# 2433 of 1916-06-09 and restored by Decreto 2712 of 1916-10-28. While Whitman +# gives 1916-10-31 for the latter transition, Shanks & Pottenger agrees more +# closely with the decree, which stated that its provision "will start sixty +# minutes after the end of 31 October, according to the current time," i.e., +# 01:00 on 1 November. +# https://dre.pt/dr/detalhe/decreto/2433-1916-267192 +# https://dre.pt/application/conteudo/267192 +# https://dre.pt/dr/detalhe/decreto/2712-1916-590937 +# https://dre.pt/application/conteudo/590937 Rule Port 1916 only - Jun 17 23:00 1:00 S -# Whitman gives 1916 Oct 31; go with Shanks & Pottenger. Rule Port 1916 only - Nov 1 1:00 0 - -Rule Port 1917 only - Feb 28 23:00s 1:00 S -Rule Port 1917 1921 - Oct 14 23:00s 0 - -Rule Port 1918 only - Mar 1 23:00s 1:00 S -Rule Port 1919 only - Feb 28 23:00s 1:00 S -Rule Port 1920 only - Feb 29 23:00s 1:00 S -Rule Port 1921 only - Feb 28 23:00s 1:00 S +# From Tim Parenti (2024-07-01): +# Article 7 of Decreto 2922 of 1916-12-30 stated that "the legal time will be +# advanced by sixty minutes from 1 March to 31 October." Per Article 15, this +# came into force from 1917-01-01. Just before the first fall back, Decreto +# 3446 of 1917-10-11 changed the annual end date to 14 October. +# https://dre.pt/dr/detalhe/decreto/2922-1916-261894 +# https://dre.pt/application/conteudo/261894 +# https://dre.pt/dr/detalhe/decreto/3446-1917-495161 +# https://dre.pt/application/conteudo/495161 +# This annual change was revoked by Decreto 8038 of 1922-02-18. +# https://dre.pt/dr/detalhe/decreto/8038-1922-569751 +# https://dre.pt/application/conteudo/569751 +Rule Port 1917 1921 - Mar 1 0:00 1:00 S +Rule Port 1917 1921 - Oct 14 24:00 0 - +# From Tim Parenti (2024-07-01): +# Decreto 9592 of 1924-04-14 noted that "France maintains the advance of legal +# time in the summer and Spain has now adopted it for the first time" and +# considered "that the absence of similar measures would cause serious +# difficulties for international rail connections with consequent repercussions +# on domestic service hours..." along with "inconvenient analogues...for postal +# and telegraph services." Summer time would be in effect from 17 April to 4 +# October, with the spring change explicitly specified by bringing clocks +# forward from 16 April 23:00. +# https://dre.pt/dr/detalhe/decreto/9592-1924-652133 +# https://dre.pt/application/conteudo/652133 +# +# Decreto 10700, issued 1925-04-16, noted that Spain had not continued summer +# time, declared that "the current legal hour prior to 17 April remains +# unchanged from that day forward", and revoked legislation to the contrary, +# just a day before summer time would have otherwise resumed. +# https://dre.pt/dr/detalhe/decreto/10700-1925-437826 +# https://dre.pt/application/conteudo/437826 Rule Port 1924 only - Apr 16 23:00s 1:00 S -Rule Port 1924 only - Oct 14 23:00s 0 - +Rule Port 1924 only - Oct 4 23:00s 0 - Rule Port 1926 only - Apr 17 23:00s 1:00 S Rule Port 1926 1929 - Oct Sat>=1 23:00s 0 - Rule Port 1927 only - Apr 9 23:00s 1:00 S @@ -2139,6 +2185,8 @@ Rule Port 1931 1932 - Oct Sat>=1 23:00s 0 - Rule Port 1932 only - Apr 2 23:00s 1:00 S Rule Port 1934 only - Apr 7 23:00s 1:00 S # Whitman gives 1934 Oct 5; go with Shanks & Pottenger. +# Note: The 1935 law specified 10-06 00:00, not 10-05 24:00, but the following +# is equivalent and more succinct. Rule Port 1934 1938 - Oct Sat>=1 23:00s 0 - # Shanks & Pottenger give 1935 Apr 30; go with Whitman. Rule Port 1935 only - Mar 30 23:00s 1:00 S @@ -2149,10 +2197,19 @@ Rule Port 1938 only - Mar 26 23:00s 1:00 S Rule Port 1939 only - Apr 15 23:00s 1:00 S # Whitman gives 1939 Oct 7; go with Shanks & Pottenger. Rule Port 1939 only - Nov 18 23:00s 0 - +# From Tim Parenti (2024-07-01): +# Portaria 9465 of 1940-02-17 advanced clocks from Saturday 1940-02-24 23:00. +# The clocks were restored by Portaria 9658, issued Monday 1940-10-07, +# effective from 24:00 that very night, which agrees with Shanks & Pottenger; +# Whitman gives Saturday 1940-10-05 instead. +# https://dre.pt/dr/detalhe/portaria/9465-1940-189096 +# https://dre.pt/application/conteudo/189096 +# https://dre.pt/dr/detalhe/portaria/9658-1940-196729 +# https://dre.pt/application/conteudo/196729 Rule Port 1940 only - Feb 24 23:00s 1:00 S -# Shanks & Pottenger give 1940 Oct 7; go with Whitman. -Rule Port 1940 1941 - Oct 5 23:00s 0 - +Rule Port 1940 only - Oct 7 23:00s 0 - Rule Port 1941 only - Apr 5 23:00s 1:00 S +Rule Port 1941 only - Oct 5 23:00s 0 - Rule Port 1942 1945 - Mar Sat>=8 23:00s 1:00 S Rule Port 1942 only - Apr 25 22:00s 2:00 M # Midsummer Rule Port 1942 only - Aug 15 22:00s 1:00 S @@ -2162,66 +2219,195 @@ Rule Port 1943 1945 - Aug Sat>=25 22:00s 1:00 S Rule Port 1944 1945 - Apr Sat>=21 22:00s 2:00 M Rule Port 1946 only - Apr Sat>=1 23:00s 1:00 S Rule Port 1946 only - Oct Sat>=1 23:00s 0 - -# Whitman says DST was not observed in 1950; go with Shanks & Pottenger. -# Whitman gives Oct lastSun for 1952 on; go with Shanks & Pottenger. -Rule Port 1947 1965 - Apr Sun>=1 2:00s 1:00 S +# From Tim Parenti (2024-07-01), per Alois Treindl (2021-02-07): +# The Astronomical Observatory of Lisbon cites Portaria 11767 of 1947-03-28 for +# 1947 and Portaria 12286 of 1948-02-19 for 1948. +# https://dre.pt/dr/detalhe/portaria/11767-1947-414787 +# https://dre.pt/application/conteudo/414787 +# https://dre.pt/dr/detalhe/portaria/12286-1948-152953 +# https://dre.pt/application/conteudo/152953 +# +# Although the latter ordinance explicitly had the 1948-10-03 transition +# scheduled for 02:00 rather than 03:00 as had been used in 1947, Decreto-Lei +# 37048 of 1948-09-07 recognized "that it is advisable to definitely set...the +# 'summer time' regime", and fixed the fall transition at 03:00 moving forward. +# https://dre.pt/dr/detalhe/decreto-lei/37048-1948-373810 +# https://dre.pt/application/conteudo/373810 +# While the Observatory only cites this act for 1949-1965 and not for 1948, it +# does not appear to have had any provision delaying its effect, so assume that +# it overrode the prior ordinance for 1948-10-03. +# +# Whitman says DST was not observed in 1950 and gives Oct lastSun for 1952 on. +# The Observatory, however, agrees with Shanks & Pottenger that 1950 was not an +# exception and that Oct Sun>=1 was maintained through 1965. +Rule Port 1947 1966 - Apr Sun>=1 2:00s 1:00 S Rule Port 1947 1965 - Oct Sun>=1 2:00s 0 - -Rule Port 1977 only - Mar 27 0:00s 1:00 S -Rule Port 1977 only - Sep 25 0:00s 0 - -Rule Port 1978 1979 - Apr Sun>=1 0:00s 1:00 S -Rule Port 1978 only - Oct 1 0:00s 0 - -Rule Port 1979 1982 - Sep lastSun 1:00s 0 - -Rule Port 1980 only - Mar lastSun 0:00s 1:00 S -Rule Port 1981 1982 - Mar lastSun 1:00s 1:00 S -Rule Port 1983 only - Mar lastSun 2:00s 1:00 S +# From Tim Parenti (2024-07-01): +# Decreto-Lei 47233 of 1966-10-01 considered that the "duality" in time was +# "the cause of serious disturbances" and noted that "the countries with which +# we have the most frequent contacts...have already adopted" a solution +# coinciding with the extant "summer time". It established that the former +# "summer time" would apply year-round on the mainland and adjacent islands +# with immediate effect, as the fall back would have otherwise occurred later +# that evening. +# https://dre.pt/dr/detalhe/decreto-lei/47233-1966-293729 +# Model this by changing zones without changing clocks at the +# previously-appointed fall back time. +# +# Decreto-Lei 309/76 of 1976-04-27 acknowledged that those international +# contacts had returned to adopting seasonal times, and considered that the +# year-round advancement "entails considerable sacrifices for the vast majority +# of the working population during the winter months", including morning +# visibility concerns for schoolchildren. It specified, beginning 1976-09-26 +# 01:00, an annual return to UT+00 on the mainland from 00:00 UT on Sep lastSun +# to 00:00 UT on Mar lastSun (unless the latter date fell on Easter, in which +# case it was to be brought forward to the preceding Sunday). It also assigned +# the Permanent Time Commission to study and propose revisions for the Azores +# and Madeira, neither of which resumed DST until 1982 (as described further +# below). +# https://dre.pt/dr/detalhe/decreto-lei/309-1976-502063 +Rule Port 1976 only - Sep lastSun 1:00 0 - +Rule Port 1977 only - Mar lastSun 0:00s 1:00 S +Rule Port 1977 only - Sep lastSun 0:00s 0 - +# From Tim Parenti (2024-07-01): +# Beginning in 1978, rather than triggering the Easter rule of the 1976 decree +# (Easter fell on 1978-03-26), Article 5 was used instead, which allowed DST +# dates to be changed by order of the Minister of Education and Scientific +# Research, upon consultation with the Permanent Time Commission, "whenever +# considered convenient." As such, a series of one-off ordinances were +# promulgated for the mainland in 1978 through 1980, after which the 1976 +# decree naturally came back into force from 1981. +Rule Port 1978 1980 - Apr Sun>=1 1:00s 1:00 S +Rule Port 1978 only - Oct 1 1:00s 0 - +Rule Port 1979 1980 - Sep lastSun 1:00s 0 - +Rule Port 1981 1986 - Mar lastSun 0:00s 1:00 S +Rule Port 1981 1985 - Sep lastSun 0:00s 0 - +# From Tim Parenti (2024-07-01): +# Decreto-Lei 44-B/86 of 1986-03-07 switched mainland Portugal's transition +# times from 0:00s to 1:00u to harmonize with the EEC from 1986-03-30. +# https://dre.pt/dr/detalhe/decreto-lei/44-b-1986-628280 +# (Transitions of 1:00s as previously reported and used by the W-Eur rules, +# though equivalent, appear to have been fiction here.) Madeira continued to +# use 0:00s for spring 1986 before joining with the mainland using 1:00u in the +# fall; meanwhile, in the Azores the two were equivalent, so the law specifying +# 0:00s wasn't touched until 1992. (See below for more on the islands.) +# +# From Rui Pedro Salgueiro (1992-11-12): +# Portugal has recently (September, 27) changed timezone +# (from WET to MET or CET) to harmonize with EEC. +# +# Martin Bruckmann (1996-02-29) reports via Peter Ilieve +# that Portugal is reverting to 0:00 by not moving its clocks this spring. +# The new Prime Minister was fed up with getting up in the dark in the winter. +# +# From Paul Eggert (1996-11-12): +# IATA SSIM (1991-09) reports several 1991-09 and 1992-09 transitions +# at 02:00u, not 01:00u. Assume that these are typos. # # Zone NAME STDOFF RULES FORMAT [UNTIL] #STDOFF -0:36:44.68 Zone Europe/Lisbon -0:36:45 - LMT 1884 -0:36:45 - LMT 1912 Jan 1 0:00u # Lisbon MT - 0:00 Port WE%sT 1966 Apr 3 2:00 + 0:00 Port WE%sT 1966 Oct 2 2:00s 1:00 - CET 1976 Sep 26 1:00 - 0:00 Port WE%sT 1983 Sep 25 1:00s - 0:00 W-Eur WE%sT 1992 Sep 27 1:00s + 0:00 Port WE%sT 1986 + 0:00 EU WE%sT 1992 Sep 27 1:00u 1:00 EU CE%sT 1996 Mar 31 1:00u 0:00 EU WE%sT + +# From Tim Parenti (2024-07-01): +# For the Azores and Madeira, legislation was followed from the laws currently +# in force as listed at: +# https://oal.ul.pt/hora-legal/legislacao/ +# working backward through references of revocation and abrogation to +# Decreto-Lei 47233 of 1966-10-01, the last time DST was abolished across the +# mainland and its adjacent islands. Because of that reference, it is +# therefore assumed that DST rules in the islands prior to 1966 were like that +# of the mainland, though most legislation of the time didn't explicitly +# specify DST practices for the islands. Zone Atlantic/Azores -1:42:40 - LMT 1884 # Ponta Delgada -1:54:32 - HMT 1912 Jan 1 2:00u # Horta MT # Vanguard section, for zic and other parsers that support %z. -# -2:00 Port %z 1966 Apr 3 2:00 -# -1:00 Port %z 1983 Sep 25 1:00s -# -1:00 W-Eur %z 1992 Sep 27 1:00s + -2:00 Port %z 1966 Oct 2 2:00s +# From Tim Parenti (2024-07-01): +# While Decreto-Lei 309/76 of 1976-04-27 reintroduced DST on the mainland by +# falling back on 1976-09-26, it assigned the Permanent Time Commission to +# study and propose revisions for the Azores and Madeira. Decreto Regional +# 9/77/A of 1977-05-17 affirmed that "the legal time remained unchanged in the +# Azores" at UT-1, and would remain there year-round. +# https://dre.pt/dr/detalhe/decreto-regional/9-1977-252066 +# +# Decreto Regional 2/82/A, published 1982-03-02, adopted DST in the same +# fashion as the mainland used at the time. +# https://dre.pt/dr/detalhe/decreto-regional/2-1982-599965 +# Though transitions in the Azores officially remained at 0:00s through 1992, +# this was equivalent to the EU-style 1:00u adopted by the mainland in 1986, so +# model it as such. + -1:00 - %z 1982 Mar 28 0:00s + -1:00 Port %z 1986 # Rearguard section, for parsers lacking %z; see ziguard.awk. - -2:00 Port -02/-01 1942 Apr 25 22:00s - -2:00 Port +00 1942 Aug 15 22:00s - -2:00 Port -02/-01 1943 Apr 17 22:00s - -2:00 Port +00 1943 Aug 28 22:00s - -2:00 Port -02/-01 1944 Apr 22 22:00s - -2:00 Port +00 1944 Aug 26 22:00s - -2:00 Port -02/-01 1945 Apr 21 22:00s - -2:00 Port +00 1945 Aug 25 22:00s - -2:00 Port -02/-01 1966 Apr 3 2:00 - -1:00 Port -01/+00 1983 Sep 25 1:00s - -1:00 W-Eur -01/+00 1992 Sep 27 1:00s +# -2:00 Port -02/-01 1942 Apr 25 22:00s +# -2:00 Port +00 1942 Aug 15 22:00s +# -2:00 Port -02/-01 1943 Apr 17 22:00s +# -2:00 Port +00 1943 Aug 28 22:00s +# -2:00 Port -02/-01 1944 Apr 22 22:00s +# -2:00 Port +00 1944 Aug 26 22:00s +# -2:00 Port -02/-01 1945 Apr 21 22:00s +# -2:00 Port +00 1945 Aug 25 22:00s +# -2:00 Port -02/-01 1966 Oct 2 2:00s +# -1:00 - -01 1982 Mar 28 0:00s +# -1:00 Port -01/+00 1986 # End of rearguard section. - 0:00 EU WE%sT 1993 Mar 28 1:00u - -1:00 EU -01/+00 +# +# From Paul Eggert (1996-11-12): +# IATA SSIM (1991/1992) reports that the Azores were at -1:00. +# IATA SSIM (1993-02) says +0:00; later issues (through 1996-09) say -1:00. +# +# From Tim Parenti (2024-07-01): +# After mainland Portugal had shifted forward an hour from 1992-09-27, Decreto +# Legislativo Regional 29/92/A of 1992-12-23 sought to "reduce the time +# difference" by shifting the Azores forward as well from 1992-12-27. Just six +# months later, this was revoked by Decreto Legislativo Regional 9/93/A, citing +# "major changes in work habits and way of life." Though the revocation didn't +# give a transition time, it was signed Wednesday 1993-06-16; assume it took +# effect later that evening, and that an EU-style spring forward (to +01) was +# still observed in the interim on 1993-03-28. +# https://dre.pt/dr/detalhe/decreto-legislativo-regional/29-1992-621553 +# https://dre.pt/dr/detalhe/decreto-legislativo-regional/9-1993-389633 + -1:00 EU %z 1992 Dec 27 1:00s + 0:00 EU WE%sT 1993 Jun 17 1:00u + -1:00 EU %z + Zone Atlantic/Madeira -1:07:36 - LMT 1884 # Funchal -1:07:36 - FMT 1912 Jan 1 1:00u # Funchal MT # Vanguard section, for zic and other parsers that support %z. -# -1:00 Port %z 1966 Apr 3 2:00 + -1:00 Port %z 1966 Oct 2 2:00s # Rearguard section, for parsers lacking %z; see ziguard.awk. - -1:00 Port -01/+00 1942 Apr 25 22:00s - -1:00 Port +01 1942 Aug 15 22:00s - -1:00 Port -01/+00 1943 Apr 17 22:00s - -1:00 Port +01 1943 Aug 28 22:00s - -1:00 Port -01/+00 1944 Apr 22 22:00s - -1:00 Port +01 1944 Aug 26 22:00s - -1:00 Port -01/+00 1945 Apr 21 22:00s - -1:00 Port +01 1945 Aug 25 22:00s - -1:00 Port -01/+00 1966 Apr 3 2:00 +# -1:00 Port -01/+00 1942 Apr 25 22:00s +# -1:00 Port +01 1942 Aug 15 22:00s +# -1:00 Port -01/+00 1943 Apr 17 22:00s +# -1:00 Port +01 1943 Aug 28 22:00s +# -1:00 Port -01/+00 1944 Apr 22 22:00s +# -1:00 Port +01 1944 Aug 26 22:00s +# -1:00 Port -01/+00 1945 Apr 21 22:00s +# -1:00 Port +01 1945 Aug 25 22:00s +# -1:00 Port -01/+00 1966 Oct 2 2:00s # End of rearguard section. - 0:00 Port WE%sT 1983 Sep 25 1:00s +# +# From Tim Parenti (2024-07-01): +# Decreto Regional 5/82/M, published 1982-04-03, established DST transitions at +# 0:00u, which for Madeira is equivalent to the mainland's rules (0:00s) at the +# time. It came into effect the day following its publication, Sunday +# 1982-04-04, thus resuming Madeira's DST practice about a week later than the +# mainland and the Azores. +# https://dre.pt/dr/detalhe/decreto-regional/5-1982-608273 +# +# Decreto Legislativo Regional 18/86/M, published 1986-10-01, adopted EU-style +# rules (1:00u) and entered into immediate force after being signed on +# 1986-07-31. +# https://dre.pt/dr/detalhe/decreto-legislativo-regional/18-1986-221705 + 0:00 - WET 1982 Apr 4 + 0:00 Port WE%sT 1986 Jul 31 0:00 EU WE%sT # Romania @@ -2433,7 +2619,7 @@ Zone Europe/Kaliningrad 1:22:00 - LMT 1893 Apr 2:00 Poland EE%sT 1946 Apr 7 3:00 Russia MSK/MSD 1989 Mar 26 2:00s 2:00 Russia EE%sT 2011 Mar 27 2:00s - 3:00 - +03 2014 Oct 26 2:00s + 3:00 - %z 2014 Oct 26 2:00s 2:00 - EET @@ -2683,14 +2869,14 @@ Zone Europe/Simferopol 2:16:24 - LMT 1880 # http://publication.pravo.gov.ru/Document/View/0001201602150056 Zone Europe/Astrakhan 3:12:12 - LMT 1924 May - 3:00 - +03 1930 Jun 21 - 4:00 Russia +04/+05 1989 Mar 26 2:00s - 3:00 Russia +03/+04 1991 Mar 31 2:00s - 4:00 - +04 1992 Mar 29 2:00s - 3:00 Russia +03/+04 2011 Mar 27 2:00s - 4:00 - +04 2014 Oct 26 2:00s - 3:00 - +03 2016 Mar 27 2:00s - 4:00 - +04 + 3:00 - %z 1930 Jun 21 + 4:00 Russia %z 1989 Mar 26 2:00s + 3:00 Russia %z 1991 Mar 31 2:00s + 4:00 - %z 1992 Mar 29 2:00s + 3:00 Russia %z 2011 Mar 27 2:00s + 4:00 - %z 2014 Oct 26 2:00s + 3:00 - %z 2016 Mar 27 2:00s + 4:00 - %z # From Paul Eggert (2016-11-11): # Europe/Volgograd covers: @@ -2720,15 +2906,15 @@ Zone Europe/Astrakhan 3:12:12 - LMT 1924 May # http://publication.pravo.gov.ru/Document/View/0001202012220002 Zone Europe/Volgograd 2:57:40 - LMT 1920 Jan 3 - 3:00 - +03 1930 Jun 21 - 4:00 - +04 1961 Nov 11 - 4:00 Russia +04/+05 1988 Mar 27 2:00s + 3:00 - %z 1930 Jun 21 + 4:00 - %z 1961 Nov 11 + 4:00 Russia %z 1988 Mar 27 2:00s 3:00 Russia MSK/MSD 1991 Mar 31 2:00s - 4:00 - +04 1992 Mar 29 2:00s + 4:00 - %z 1992 Mar 29 2:00s 3:00 Russia MSK/MSD 2011 Mar 27 2:00s 4:00 - MSK 2014 Oct 26 2:00s 3:00 - MSK 2018 Oct 28 2:00s - 4:00 - +04 2020 Dec 27 2:00s + 4:00 - %z 2020 Dec 27 2:00s 3:00 - MSK # From Paul Eggert (2016-11-11): @@ -2743,14 +2929,14 @@ Zone Europe/Volgograd 2:57:40 - LMT 1920 Jan 3 # http://publication.pravo.gov.ru/Document/View/0001201611220031 Zone Europe/Saratov 3:04:18 - LMT 1919 Jul 1 0:00u - 3:00 - +03 1930 Jun 21 - 4:00 Russia +04/+05 1988 Mar 27 2:00s - 3:00 Russia +03/+04 1991 Mar 31 2:00s - 4:00 - +04 1992 Mar 29 2:00s - 3:00 Russia +03/+04 2011 Mar 27 2:00s - 4:00 - +04 2014 Oct 26 2:00s - 3:00 - +03 2016 Dec 4 2:00s - 4:00 - +04 + 3:00 - %z 1930 Jun 21 + 4:00 Russia %z 1988 Mar 27 2:00s + 3:00 Russia %z 1991 Mar 31 2:00s + 4:00 - %z 1992 Mar 29 2:00s + 3:00 Russia %z 2011 Mar 27 2:00s + 4:00 - %z 2014 Oct 26 2:00s + 3:00 - %z 2016 Dec 4 2:00s + 4:00 - %z # From Paul Eggert (2016-03-18): # Europe/Kirov covers: @@ -2758,10 +2944,10 @@ Zone Europe/Saratov 3:04:18 - LMT 1919 Jul 1 0:00u # The 1989 transition is from USSR act No. 227 (1989-03-14). # Zone Europe/Kirov 3:18:48 - LMT 1919 Jul 1 0:00u - 3:00 - +03 1930 Jun 21 - 4:00 Russia +04/+05 1989 Mar 26 2:00s + 3:00 - %z 1930 Jun 21 + 4:00 Russia %z 1989 Mar 26 2:00s 3:00 Russia MSK/MSD 1991 Mar 31 2:00s - 4:00 - +04 1992 Mar 29 2:00s + 4:00 - %z 1992 Mar 29 2:00s 3:00 Russia MSK/MSD 2011 Mar 27 2:00s 4:00 - MSK 2014 Oct 26 2:00s 3:00 - MSK @@ -2776,15 +2962,15 @@ Zone Europe/Kirov 3:18:48 - LMT 1919 Jul 1 0:00u # The 1989 transition is from USSR act No. 227 (1989-03-14). Zone Europe/Samara 3:20:20 - LMT 1919 Jul 1 0:00u - 3:00 - +03 1930 Jun 21 - 4:00 - +04 1935 Jan 27 - 4:00 Russia +04/+05 1989 Mar 26 2:00s - 3:00 Russia +03/+04 1991 Mar 31 2:00s - 2:00 Russia +02/+03 1991 Sep 29 2:00s - 3:00 - +03 1991 Oct 20 3:00 - 4:00 Russia +04/+05 2010 Mar 28 2:00s - 3:00 Russia +03/+04 2011 Mar 27 2:00s - 4:00 - +04 + 3:00 - %z 1930 Jun 21 + 4:00 - %z 1935 Jan 27 + 4:00 Russia %z 1989 Mar 26 2:00s + 3:00 Russia %z 1991 Mar 31 2:00s + 2:00 Russia %z 1991 Sep 29 2:00s + 3:00 - %z 1991 Oct 20 3:00 + 4:00 Russia %z 2010 Mar 28 2:00s + 3:00 Russia %z 2011 Mar 27 2:00s + 4:00 - %z # From Paul Eggert (2016-03-18): # Europe/Ulyanovsk covers: @@ -2800,14 +2986,14 @@ Zone Europe/Samara 3:20:20 - LMT 1919 Jul 1 0:00u # http://publication.pravo.gov.ru/Document/View/0001201603090051 Zone Europe/Ulyanovsk 3:13:36 - LMT 1919 Jul 1 0:00u - 3:00 - +03 1930 Jun 21 - 4:00 Russia +04/+05 1989 Mar 26 2:00s - 3:00 Russia +03/+04 1991 Mar 31 2:00s - 2:00 Russia +02/+03 1992 Jan 19 2:00s - 3:00 Russia +03/+04 2011 Mar 27 2:00s - 4:00 - +04 2014 Oct 26 2:00s - 3:00 - +03 2016 Mar 27 2:00s - 4:00 - +04 + 3:00 - %z 1930 Jun 21 + 4:00 Russia %z 1989 Mar 26 2:00s + 3:00 Russia %z 1991 Mar 31 2:00s + 2:00 Russia %z 1992 Jan 19 2:00s + 3:00 Russia %z 2011 Mar 27 2:00s + 4:00 - %z 2014 Oct 26 2:00s + 3:00 - %z 2016 Mar 27 2:00s + 4:00 - %z # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25): # Asia/Yekaterinburg covers... @@ -2832,12 +3018,12 @@ Zone Europe/Ulyanovsk 3:13:36 - LMT 1919 Jul 1 0:00u #STDOFF 4:02:32.9 Zone Asia/Yekaterinburg 4:02:33 - LMT 1916 Jul 3 3:45:05 - PMT 1919 Jul 15 4:00 - 4:00 - +04 1930 Jun 21 - 5:00 Russia +05/+06 1991 Mar 31 2:00s - 4:00 Russia +04/+05 1992 Jan 19 2:00s - 5:00 Russia +05/+06 2011 Mar 27 2:00s - 6:00 - +06 2014 Oct 26 2:00s - 5:00 - +05 + 4:00 - %z 1930 Jun 21 + 5:00 Russia %z 1991 Mar 31 2:00s + 4:00 Russia %z 1992 Jan 19 2:00s + 5:00 Russia %z 2011 Mar 27 2:00s + 6:00 - %z 2014 Oct 26 2:00s + 5:00 - %z # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25): @@ -2847,12 +3033,12 @@ Zone Asia/Yekaterinburg 4:02:33 - LMT 1916 Jul 3 # Byalokoz 1919 says Omsk was 4:53:30. Zone Asia/Omsk 4:53:30 - LMT 1919 Nov 14 - 5:00 - +05 1930 Jun 21 - 6:00 Russia +06/+07 1991 Mar 31 2:00s - 5:00 Russia +05/+06 1992 Jan 19 2:00s - 6:00 Russia +06/+07 2011 Mar 27 2:00s - 7:00 - +07 2014 Oct 26 2:00s - 6:00 - +06 + 5:00 - %z 1930 Jun 21 + 6:00 Russia %z 1991 Mar 31 2:00s + 5:00 Russia %z 1992 Jan 19 2:00s + 6:00 Russia %z 2011 Mar 27 2:00s + 7:00 - %z 2014 Oct 26 2:00s + 6:00 - %z # From Paul Eggert (2016-02-22): # Asia/Barnaul covers: @@ -2885,14 +3071,14 @@ Zone Asia/Omsk 4:53:30 - LMT 1919 Nov 14 # http://publication.pravo.gov.ru/Document/View/0001201603090038 Zone Asia/Barnaul 5:35:00 - LMT 1919 Dec 10 - 6:00 - +06 1930 Jun 21 - 7:00 Russia +07/+08 1991 Mar 31 2:00s - 6:00 Russia +06/+07 1992 Jan 19 2:00s - 7:00 Russia +07/+08 1995 May 28 - 6:00 Russia +06/+07 2011 Mar 27 2:00s - 7:00 - +07 2014 Oct 26 2:00s - 6:00 - +06 2016 Mar 27 2:00s - 7:00 - +07 + 6:00 - %z 1930 Jun 21 + 7:00 Russia %z 1991 Mar 31 2:00s + 6:00 Russia %z 1992 Jan 19 2:00s + 7:00 Russia %z 1995 May 28 + 6:00 Russia %z 2011 Mar 27 2:00s + 7:00 - %z 2014 Oct 26 2:00s + 6:00 - %z 2016 Mar 27 2:00s + 7:00 - %z # From Paul Eggert (2016-03-18): # Asia/Novosibirsk covers: @@ -2906,14 +3092,14 @@ Zone Asia/Barnaul 5:35:00 - LMT 1919 Dec 10 # http://publication.pravo.gov.ru/Document/View/0001201607040064 Zone Asia/Novosibirsk 5:31:40 - LMT 1919 Dec 14 6:00 - 6:00 - +06 1930 Jun 21 - 7:00 Russia +07/+08 1991 Mar 31 2:00s - 6:00 Russia +06/+07 1992 Jan 19 2:00s - 7:00 Russia +07/+08 1993 May 23 # say Shanks & P. - 6:00 Russia +06/+07 2011 Mar 27 2:00s - 7:00 - +07 2014 Oct 26 2:00s - 6:00 - +06 2016 Jul 24 2:00s - 7:00 - +07 + 6:00 - %z 1930 Jun 21 + 7:00 Russia %z 1991 Mar 31 2:00s + 6:00 Russia %z 1992 Jan 19 2:00s + 7:00 Russia %z 1993 May 23 # say Shanks & P. + 6:00 Russia %z 2011 Mar 27 2:00s + 7:00 - %z 2014 Oct 26 2:00s + 6:00 - %z 2016 Jul 24 2:00s + 7:00 - %z # From Paul Eggert (2016-03-18): # Asia/Tomsk covers: @@ -2958,14 +3144,14 @@ Zone Asia/Novosibirsk 5:31:40 - LMT 1919 Dec 14 6:00 # http://publication.pravo.gov.ru/Document/View/0001201604260048 Zone Asia/Tomsk 5:39:51 - LMT 1919 Dec 22 - 6:00 - +06 1930 Jun 21 - 7:00 Russia +07/+08 1991 Mar 31 2:00s - 6:00 Russia +06/+07 1992 Jan 19 2:00s - 7:00 Russia +07/+08 2002 May 1 3:00 - 6:00 Russia +06/+07 2011 Mar 27 2:00s - 7:00 - +07 2014 Oct 26 2:00s - 6:00 - +06 2016 May 29 2:00s - 7:00 - +07 + 6:00 - %z 1930 Jun 21 + 7:00 Russia %z 1991 Mar 31 2:00s + 6:00 Russia %z 1992 Jan 19 2:00s + 7:00 Russia %z 2002 May 1 3:00 + 6:00 Russia %z 2011 Mar 27 2:00s + 7:00 - %z 2014 Oct 26 2:00s + 6:00 - %z 2016 May 29 2:00s + 7:00 - %z # From Tim Parenti (2014-07-03): @@ -2996,12 +3182,12 @@ Zone Asia/Tomsk 5:39:51 - LMT 1919 Dec 22 # realigning itself with KRAT. Zone Asia/Novokuznetsk 5:48:48 - LMT 1924 May 1 - 6:00 - +06 1930 Jun 21 - 7:00 Russia +07/+08 1991 Mar 31 2:00s - 6:00 Russia +06/+07 1992 Jan 19 2:00s - 7:00 Russia +07/+08 2010 Mar 28 2:00s - 6:00 Russia +06/+07 2011 Mar 27 2:00s - 7:00 - +07 + 6:00 - %z 1930 Jun 21 + 7:00 Russia %z 1991 Mar 31 2:00s + 6:00 Russia %z 1992 Jan 19 2:00s + 7:00 Russia %z 2010 Mar 28 2:00s + 6:00 Russia %z 2011 Mar 27 2:00s + 7:00 - %z # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25): # Asia/Krasnoyarsk covers... @@ -3015,12 +3201,12 @@ Zone Asia/Novokuznetsk 5:48:48 - LMT 1924 May 1 # Byalokoz 1919 says Krasnoyarsk was 6:11:26. Zone Asia/Krasnoyarsk 6:11:26 - LMT 1920 Jan 6 - 6:00 - +06 1930 Jun 21 - 7:00 Russia +07/+08 1991 Mar 31 2:00s - 6:00 Russia +06/+07 1992 Jan 19 2:00s - 7:00 Russia +07/+08 2011 Mar 27 2:00s - 8:00 - +08 2014 Oct 26 2:00s - 7:00 - +07 + 6:00 - %z 1930 Jun 21 + 7:00 Russia %z 1991 Mar 31 2:00s + 6:00 Russia %z 1992 Jan 19 2:00s + 7:00 Russia %z 2011 Mar 27 2:00s + 8:00 - %z 2014 Oct 26 2:00s + 7:00 - %z # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25): @@ -3037,12 +3223,12 @@ Zone Asia/Krasnoyarsk 6:11:26 - LMT 1920 Jan 6 Zone Asia/Irkutsk 6:57:05 - LMT 1880 6:57:05 - IMT 1920 Jan 25 # Irkutsk Mean Time - 7:00 - +07 1930 Jun 21 - 8:00 Russia +08/+09 1991 Mar 31 2:00s - 7:00 Russia +07/+08 1992 Jan 19 2:00s - 8:00 Russia +08/+09 2011 Mar 27 2:00s - 9:00 - +09 2014 Oct 26 2:00s - 8:00 - +08 + 7:00 - %z 1930 Jun 21 + 8:00 Russia %z 1991 Mar 31 2:00s + 7:00 Russia %z 1992 Jan 19 2:00s + 8:00 Russia %z 2011 Mar 27 2:00s + 9:00 - %z 2014 Oct 26 2:00s + 8:00 - %z # From Tim Parenti (2014-07-06): @@ -3059,13 +3245,13 @@ Zone Asia/Irkutsk 6:57:05 - LMT 1880 # http://publication.pravo.gov.ru/Document/View/0001201512300107 Zone Asia/Chita 7:33:52 - LMT 1919 Dec 15 - 8:00 - +08 1930 Jun 21 - 9:00 Russia +09/+10 1991 Mar 31 2:00s - 8:00 Russia +08/+09 1992 Jan 19 2:00s - 9:00 Russia +09/+10 2011 Mar 27 2:00s - 10:00 - +10 2014 Oct 26 2:00s - 8:00 - +08 2016 Mar 27 2:00 - 9:00 - +09 + 8:00 - %z 1930 Jun 21 + 9:00 Russia %z 1991 Mar 31 2:00s + 8:00 Russia %z 1992 Jan 19 2:00s + 9:00 Russia %z 2011 Mar 27 2:00s + 10:00 - %z 2014 Oct 26 2:00s + 8:00 - %z 2016 Mar 27 2:00 + 9:00 - %z # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2009-11-29): @@ -3105,12 +3291,12 @@ Zone Asia/Chita 7:33:52 - LMT 1919 Dec 15 # Byalokoz 1919 says Yakutsk was 8:38:58. Zone Asia/Yakutsk 8:38:58 - LMT 1919 Dec 15 - 8:00 - +08 1930 Jun 21 - 9:00 Russia +09/+10 1991 Mar 31 2:00s - 8:00 Russia +08/+09 1992 Jan 19 2:00s - 9:00 Russia +09/+10 2011 Mar 27 2:00s - 10:00 - +10 2014 Oct 26 2:00s - 9:00 - +09 + 8:00 - %z 1930 Jun 21 + 9:00 Russia %z 1991 Mar 31 2:00s + 8:00 Russia %z 1992 Jan 19 2:00s + 9:00 Russia %z 2011 Mar 27 2:00s + 10:00 - %z 2014 Oct 26 2:00s + 9:00 - %z # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2009-11-29): @@ -3128,12 +3314,12 @@ Zone Asia/Yakutsk 8:38:58 - LMT 1919 Dec 15 # Go with Byalokoz. Zone Asia/Vladivostok 8:47:31 - LMT 1922 Nov 15 - 9:00 - +09 1930 Jun 21 - 10:00 Russia +10/+11 1991 Mar 31 2:00s - 9:00 Russia +09/+10 1992 Jan 19 2:00s - 10:00 Russia +10/+11 2011 Mar 27 2:00s - 11:00 - +11 2014 Oct 26 2:00s - 10:00 - +10 + 9:00 - %z 1930 Jun 21 + 10:00 Russia %z 1991 Mar 31 2:00s + 9:00 Russia %z 1992 Jan 19 2:00s + 10:00 Russia %z 2011 Mar 27 2:00s + 11:00 - %z 2014 Oct 26 2:00s + 10:00 - %z # From Tim Parenti (2014-07-03): @@ -3151,14 +3337,14 @@ Zone Asia/Vladivostok 8:47:31 - LMT 1922 Nov 15 # This transition is no doubt wrong, but we have no better info. Zone Asia/Khandyga 9:02:13 - LMT 1919 Dec 15 - 8:00 - +08 1930 Jun 21 - 9:00 Russia +09/+10 1991 Mar 31 2:00s - 8:00 Russia +08/+09 1992 Jan 19 2:00s - 9:00 Russia +09/+10 2004 - 10:00 Russia +10/+11 2011 Mar 27 2:00s - 11:00 - +11 2011 Sep 13 0:00s # Decree 725? - 10:00 - +10 2014 Oct 26 2:00s - 9:00 - +09 + 8:00 - %z 1930 Jun 21 + 9:00 Russia %z 1991 Mar 31 2:00s + 8:00 Russia %z 1992 Jan 19 2:00s + 9:00 Russia %z 2004 + 10:00 Russia %z 2011 Mar 27 2:00s + 11:00 - %z 2011 Sep 13 0:00s # Decree 725? + 10:00 - %z 2014 Oct 26 2:00s + 9:00 - %z # From Tim Parenti (2014-07-03): @@ -3174,14 +3360,14 @@ Zone Asia/Khandyga 9:02:13 - LMT 1919 Dec 15 # The Zone name should be Asia/Yuzhno-Sakhalinsk, but that's too long. Zone Asia/Sakhalin 9:30:48 - LMT 1905 Aug 23 - 9:00 - +09 1945 Aug 25 - 11:00 Russia +11/+12 1991 Mar 31 2:00s # Sakhalin T - 10:00 Russia +10/+11 1992 Jan 19 2:00s - 11:00 Russia +11/+12 1997 Mar lastSun 2:00s - 10:00 Russia +10/+11 2011 Mar 27 2:00s - 11:00 - +11 2014 Oct 26 2:00s - 10:00 - +10 2016 Mar 27 2:00s - 11:00 - +11 + 9:00 - %z 1945 Aug 25 + 11:00 Russia %z 1991 Mar 31 2:00s # Sakhalin T + 10:00 Russia %z 1992 Jan 19 2:00s + 11:00 Russia %z 1997 Mar lastSun 2:00s + 10:00 Russia %z 2011 Mar 27 2:00s + 11:00 - %z 2014 Oct 26 2:00s + 10:00 - %z 2016 Mar 27 2:00s + 11:00 - %z # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2009-11-29): @@ -3204,13 +3390,13 @@ Zone Asia/Sakhalin 9:30:48 - LMT 1905 Aug 23 # http://publication.pravo.gov.ru/Document/View/0001201604050038 Zone Asia/Magadan 10:03:12 - LMT 1924 May 2 - 10:00 - +10 1930 Jun 21 # Magadan Time - 11:00 Russia +11/+12 1991 Mar 31 2:00s - 10:00 Russia +10/+11 1992 Jan 19 2:00s - 11:00 Russia +11/+12 2011 Mar 27 2:00s - 12:00 - +12 2014 Oct 26 2:00s - 10:00 - +10 2016 Apr 24 2:00s - 11:00 - +11 + 10:00 - %z 1930 Jun 21 # Magadan Time + 11:00 Russia %z 1991 Mar 31 2:00s + 10:00 Russia %z 1992 Jan 19 2:00s + 11:00 Russia %z 2011 Mar 27 2:00s + 12:00 - %z 2014 Oct 26 2:00s + 10:00 - %z 2016 Apr 24 2:00s + 11:00 - %z # From Tim Parenti (2014-07-06): @@ -3255,12 +3441,12 @@ Zone Asia/Magadan 10:03:12 - LMT 1924 May 2 # Go with Srednekolymsk. Zone Asia/Srednekolymsk 10:14:52 - LMT 1924 May 2 - 10:00 - +10 1930 Jun 21 - 11:00 Russia +11/+12 1991 Mar 31 2:00s - 10:00 Russia +10/+11 1992 Jan 19 2:00s - 11:00 Russia +11/+12 2011 Mar 27 2:00s - 12:00 - +12 2014 Oct 26 2:00s - 11:00 - +11 + 10:00 - %z 1930 Jun 21 + 11:00 Russia %z 1991 Mar 31 2:00s + 10:00 Russia %z 1992 Jan 19 2:00s + 11:00 Russia %z 2011 Mar 27 2:00s + 12:00 - %z 2014 Oct 26 2:00s + 11:00 - %z # From Tim Parenti (2014-07-03): @@ -3278,14 +3464,14 @@ Zone Asia/Srednekolymsk 10:14:52 - LMT 1924 May 2 # UTC+12 since at least then, too. Zone Asia/Ust-Nera 9:32:54 - LMT 1919 Dec 15 - 8:00 - +08 1930 Jun 21 - 9:00 Russia +09/+10 1981 Apr 1 - 11:00 Russia +11/+12 1991 Mar 31 2:00s - 10:00 Russia +10/+11 1992 Jan 19 2:00s - 11:00 Russia +11/+12 2011 Mar 27 2:00s - 12:00 - +12 2011 Sep 13 0:00s # Decree 725? - 11:00 - +11 2014 Oct 26 2:00s - 10:00 - +10 + 8:00 - %z 1930 Jun 21 + 9:00 Russia %z 1981 Apr 1 + 11:00 Russia %z 1991 Mar 31 2:00s + 10:00 Russia %z 1992 Jan 19 2:00s + 11:00 Russia %z 2011 Mar 27 2:00s + 12:00 - %z 2011 Sep 13 0:00s # Decree 725? + 11:00 - %z 2014 Oct 26 2:00s + 10:00 - %z # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25): @@ -3298,12 +3484,12 @@ Zone Asia/Ust-Nera 9:32:54 - LMT 1919 Dec 15 # The Zone name should be Asia/Petropavlovsk-Kamchatski or perhaps # Asia/Petropavlovsk-Kamchatsky, but these are too long. Zone Asia/Kamchatka 10:34:36 - LMT 1922 Nov 10 - 11:00 - +11 1930 Jun 21 - 12:00 Russia +12/+13 1991 Mar 31 2:00s - 11:00 Russia +11/+12 1992 Jan 19 2:00s - 12:00 Russia +12/+13 2010 Mar 28 2:00s - 11:00 Russia +11/+12 2011 Mar 27 2:00s - 12:00 - +12 + 11:00 - %z 1930 Jun 21 + 12:00 Russia %z 1991 Mar 31 2:00s + 11:00 Russia %z 1992 Jan 19 2:00s + 12:00 Russia %z 2010 Mar 28 2:00s + 11:00 Russia %z 2011 Mar 27 2:00s + 12:00 - %z # From Tim Parenti (2014-07-03): @@ -3311,13 +3497,13 @@ Zone Asia/Kamchatka 10:34:36 - LMT 1922 Nov 10 # 87 RU-CHU Chukotka Autonomous Okrug Zone Asia/Anadyr 11:49:56 - LMT 1924 May 2 - 12:00 - +12 1930 Jun 21 - 13:00 Russia +13/+14 1982 Apr 1 0:00s - 12:00 Russia +12/+13 1991 Mar 31 2:00s - 11:00 Russia +11/+12 1992 Jan 19 2:00s - 12:00 Russia +12/+13 2010 Mar 28 2:00s - 11:00 Russia +11/+12 2011 Mar 27 2:00s - 12:00 - +12 + 12:00 - %z 1930 Jun 21 + 13:00 Russia %z 1982 Apr 1 0:00s + 12:00 Russia %z 1991 Mar 31 2:00s + 11:00 Russia %z 1992 Jan 19 2:00s + 12:00 Russia %z 2010 Mar 28 2:00s + 11:00 Russia %z 2011 Mar 27 2:00s + 12:00 - %z # Bosnia & Herzegovina # Croatia @@ -3436,7 +3622,7 @@ Zone Africa/Ceuta -0:21:16 - LMT 1901 Jan 1 0:00u 1:00 - CET 1986 1:00 EU CE%sT Zone Atlantic/Canary -1:01:36 - LMT 1922 Mar # Las Palmas de Gran C. - -1:00 - -01 1946 Sep 30 1:00 + -1:00 - %z 1946 Sep 30 1:00 0:00 - WET 1980 Apr 6 0:00s 0:00 1:00 WEST 1980 Sep 28 1:00u 0:00 EU WE%sT @@ -3517,8 +3703,8 @@ Zone Atlantic/Canary -1:01:36 - LMT 1922 Mar # Las Palmas de Gran C. # but if no one is present after 11 at night, could be postponed until one # hour before the beginning of service. -# From Paul Eggert (2013-09-11): -# Round BMT to the nearest even second, 0:29:46. +# From Paul Eggert (2024-05-24): +# Express BMT as 0:29:45.500, approximately the same precision 7° 26' 22.50". # # We can find no reliable source for Shanks's assertion that all of Switzerland # except Geneva switched to Bern Mean Time at 00:00 on 1848-09-12. This book: @@ -3557,6 +3743,7 @@ Rule Swiss 1941 1942 - May Mon>=1 1:00 1:00 S Rule Swiss 1941 1942 - Oct Mon>=1 2:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Europe/Zurich 0:34:08 - LMT 1853 Jul 16 # See above comment. + #STDOFF 0:29:45.500 0:29:46 - BMT 1894 Jun # Bern Mean Time 1:00 Swiss CE%sT 1981 1:00 EU CE%sT @@ -3754,7 +3941,7 @@ Rule Turkey 1996 2006 - Oct lastSun 1:00s 0 - Zone Europe/Istanbul 1:55:52 - LMT 1880 1:56:56 - IMT 1910 Oct # Istanbul Mean Time? 2:00 Turkey EE%sT 1978 Jun 29 - 3:00 Turkey +03/+04 1984 Nov 1 2:00 + 3:00 Turkey %z 1984 Nov 1 2:00 2:00 Turkey EE%sT 2007 2:00 EU EE%sT 2011 Mar 27 1:00u 2:00 - EET 2011 Mar 28 1:00u @@ -3763,7 +3950,7 @@ Zone Europe/Istanbul 1:55:52 - LMT 1880 2:00 EU EE%sT 2015 Oct 25 1:00u 2:00 1:00 EEST 2015 Nov 8 1:00u 2:00 EU EE%sT 2016 Sep 7 - 3:00 - +03 + 3:00 - %z # Ukraine # diff --git a/src/java.base/share/data/tzdata/leapseconds b/src/java.base/share/data/tzdata/leapseconds index 8e7df3de984fb..63a76620dbfed 100644 --- a/src/java.base/share/data/tzdata/leapseconds +++ b/src/java.base/share/data/tzdata/leapseconds @@ -92,11 +92,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 2024 Dec 28 00:00:00 +#Expires 2025 Jun 28 00:00:00 # POSIX timestamps for the data in this file: -#updated 1704708379 (2024-01-08 10:06:19 UTC) -#expires 1735344000 (2024-12-28 00:00:00 UTC) +#updated 1720104763 (2024-07-04 14:52:43 UTC) +#expires 1751068800 (2025-06-28 00:00:00 UTC) # Updated through IERS Bulletin C (https://hpiers.obspm.fr/iers/bul/bulc/bulletinc.dat) -# File expires on 28 December 2024 +# File expires on 28 June 2025 diff --git a/src/java.base/share/data/tzdata/northamerica b/src/java.base/share/data/tzdata/northamerica index a8b2ef3f7fa5f..c95e7d0e643e7 100644 --- a/src/java.base/share/data/tzdata/northamerica +++ b/src/java.base/share/data/tzdata/northamerica @@ -208,26 +208,6 @@ Rule US 1987 2006 - Apr Sun>=1 2:00 1:00 D Rule US 2007 max - Mar Sun>=8 2:00 1:00 D Rule US 2007 max - Nov Sun>=1 2:00 0 S -# From Arthur David Olson, 2005-12-19 -# We generate the files specified below to guard against old files with -# obsolete information being left in the time zone binary directory. -# We limit the list to names that have appeared in previous versions of -# this time zone package. -# We do these as separate Zones rather than as Links to avoid problems if -# a particular place changes whether it observes DST. -# We put these specifications here in the northamerica file both to -# increase the chances that they'll actually get compiled and to -# avoid the need to duplicate the US rules in another file. - -# Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone EST -5:00 - EST -Zone MST -7:00 - MST -Zone HST -10:00 - HST -Zone EST5EDT -5:00 US E%sT -Zone CST6CDT -6:00 US C%sT -Zone MST7MDT -7:00 US M%sT -Zone PST8PDT -8:00 US P%sT - # From U. S. Naval Observatory (1989-01-19): # USA EASTERN 5 H BEHIND UTC NEW YORK, WASHINGTON # USA EASTERN 4 H BEHIND UTC APR 3 - OCT 30 @@ -2396,6 +2376,81 @@ Zone America/Dawson -9:17:40 - LMT 1900 Aug 20 # the researchers who prepared the Decrees page failed to find some of # the relevant documents. +# From Heitor David Pinto (2024-08-04): +# In 1931, the decree implementing DST specified that it would take +# effect on 30 April.... +# https://www.dof.gob.mx/nota_to_imagen_fs.php?cod_diario=192270&pagina=2&seccion=1 +# +# In 1981, the decree changing Campeche, Yucatán and Quintana Roo to UTC-5 +# specified that it would enter into force on 26 December 1981 at 2:00.... +# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4705667&fecha=23/12/1981&cod_diario=202796 +# +# In 1982, the decree returning Campeche and Yucatán to UTC-6 specified that +# it would enter into force on 2 November 1982 at 2:00.... +# https://www.dof.gob.mx/nota_to_imagen_fs.php?cod_diario=205689&pagina=3&seccion=0 +# +# Quintana Roo changed to UTC-6 on 4 January 1983 at 0:00, and again +# to UTC-5 on 26 October 1997 at 2:00.... +# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4787355&fecha=28/12/1982&cod_diario=206112 +# https://www.dof.gob.mx/nota_to_imagen_fs.php?cod_diario=209559&pagina=15&seccion=0 +# +# Durango, Coahuila, Nuevo León and Tamaulipas were set to UTC-7 on 1 January +# 1922, and changed to UTC-6 on 10 June 1927. Then Durango, Coahuila and +# Nuevo León (but not Tamaulipas) returned to UTC-7 on 15 November 1930, +# observed DST in 1931, and changed again to UTC-6 on 1 April 1932.... +# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4441846&fecha=29/12/1921&cod_diario=187468 +# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4541520&fecha=09/06/1927&cod_diario=193920 +# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4491963&fecha=15/11/1930&cod_diario=190835 +# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4418437&fecha=21/01/1932&cod_diario=185588 +# +# ... the ... 10 June 1927 ... decree only said 10 June 1927, without +# specifying a time, so I suppose that it should be considered at 0:00. +# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4541520&fecha=09/06/1927&cod_diario=193920 +# +# In 1942, the decree changing Baja California, Baja California Sur, Sonora, +# Sinaloa and Nayarit to UTC-7 was published on 24 April, but it said that it +# would apply from 1 April, so it's unclear when the change actually +# occurred. The database currently shows 24 April 1942. +# https://www.dof.gob.mx/nota_to_imagen_fs.php?cod_diario=192203&pagina=2&seccion=1 +# +# Baja California Sur, Sonora, Sinaloa and Nayarit never used UTC-8. The ... +# 14 January 1949 ... change [to UTC-8] only occurred in Baja California. +# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4515613&fecha=13/01/1949&cod_diario=192309 +# +# In 1945, the decree changing Baja California to UTC-8 specified that it +# would take effect on the third day from its publication. +# It was published on 12 November, so it would take effect on 15 November.... +# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4555049&fecha=12/11/1945&cod_diario=194763 +# +# In 1948, the decree changing Baja California to UTC-7 specified that it +# would take effect on "this date". The decree was made on 13 March, +# but published on 5 April, so it's unclear when the change actually occurred. +# The database currently shows 5 April 1948. +# https://www.dof.gob.mx/nota_to_imagen_fs.php?cod_diario=188624&pagina=2&seccion=0 +# +# In 1949, the decree changing Baja California to UTC-8 was published on 13 +# January, but it said that it would apply from 1 January, so it's unclear when +# the change actually occurred. The database currently shows 14 January 1949. +# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4515613&fecha=13/01/1949&cod_diario=192309 +# +# Baja California also observed UTC-7 from 1 May to 24 September 1950, +# from 29 April to 30 September 1951 at 2:00, +# and from 27 April to 28 September 1952 at 2:00.... +# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4600403&fecha=29/04/1950&cod_diario=197505 +# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4623553&fecha=23/09/1950&cod_diario=198805 +# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4469444&fecha=27/04/1951&cod_diario=189317 +# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4533868&fecha=10/03/1952&cod_diario=193465 +# +# All changes in Baja California from 1948 to 1952 match those in California, +# on the same dates or with a difference of one day. +# So it may be easier to implement these changes as DST with rule CA +# during this whole period. +# +# From Paul Eggert (2024-08-18): +# For now, maintain the slightly-different history for Baja California, +# as we have no information on whether 1948/1952 clocks in Tijuana followed +# the decrees or followed San Diego. + # From Alan Perry (1996-02-15): # A guy from our Mexico subsidiary finally found the Presidential Decree # outlining the timezone changes in Mexico. @@ -2599,7 +2654,7 @@ Zone America/Dawson -9:17:40 - LMT 1900 Aug 20 # http://puentelibre.mx/noticia/ciudad_juarez_cambio_horario_noviembre_2022/ # Rule NAME FROM TO - IN ON AT SAVE LETTER/S -Rule Mexico 1931 only - May 1 23:00 1:00 D +Rule Mexico 1931 only - April 30 0:00 1:00 D Rule Mexico 1931 only - Oct 1 0:00 0 S Rule Mexico 1939 only - Feb 5 0:00 1:00 D Rule Mexico 1939 only - Jun 25 0:00 0 S @@ -2618,14 +2673,16 @@ Rule Mexico 2002 2022 - Oct lastSun 2:00 0 S # Zone NAME STDOFF RULES FORMAT [UNTIL] # Quintana Roo; represented by Cancún Zone America/Cancun -5:47:04 - LMT 1922 Jan 1 6:00u - -6:00 - CST 1981 Dec 23 + -6:00 - CST 1981 Dec 26 2:00 + -5:00 - EST 1983 Jan 4 0:00 + -6:00 Mexico C%sT 1997 Oct 26 2:00 -5:00 Mexico E%sT 1998 Aug 2 2:00 -6:00 Mexico C%sT 2015 Feb 1 2:00 -5:00 - EST # Campeche, Yucatán; represented by Mérida Zone America/Merida -5:58:28 - LMT 1922 Jan 1 6:00u - -6:00 - CST 1981 Dec 23 - -5:00 - EST 1982 Dec 2 + -6:00 - CST 1981 Dec 26 2:00 + -5:00 - EST 1982 Nov 2 2:00 -6:00 Mexico C%sT # Coahuila, Nuevo León, Tamaulipas (near US border) # This includes the following municipios: @@ -2642,12 +2699,15 @@ Zone America/Matamoros -6:30:00 - LMT 1922 Jan 1 6:00u -6:00 US C%sT # Durango; Coahuila, Nuevo León, Tamaulipas (away from US border) Zone America/Monterrey -6:41:16 - LMT 1922 Jan 1 6:00u + -7:00 - MST 1927 Jun 10 + -6:00 - CST 1930 Nov 15 + -7:00 Mexico M%sT 1932 Apr 1 -6:00 - CST 1988 -6:00 US C%sT 1989 -6:00 Mexico C%sT # Central Mexico Zone America/Mexico_City -6:36:36 - LMT 1922 Jan 1 7:00u - -7:00 - MST 1927 Jun 10 23:00 + -7:00 - MST 1927 Jun 10 -6:00 - CST 1930 Nov 15 -7:00 Mexico M%sT 1932 Apr 1 -6:00 Mexico C%sT 2001 Sep 30 2:00 @@ -2658,7 +2718,7 @@ Zone America/Mexico_City -6:36:36 - LMT 1922 Jan 1 7:00u # Práxedis G Guerrero. # http://gaceta.diputados.gob.mx/PDF/65/2a022/nov/20221124-VII.pdf Zone America/Ciudad_Juarez -7:05:56 - LMT 1922 Jan 1 7:00u - -7:00 - MST 1927 Jun 10 23:00 + -7:00 - MST 1927 Jun 10 -6:00 - CST 1930 Nov 15 -7:00 Mexico M%sT 1932 Apr 1 -6:00 - CST 1996 @@ -2673,7 +2733,7 @@ Zone America/Ciudad_Juarez -7:05:56 - LMT 1922 Jan 1 7:00u # Benavides. # http://gaceta.diputados.gob.mx/PDF/65/2a022/nov/20221124-VII.pdf Zone America/Ojinaga -6:57:40 - LMT 1922 Jan 1 7:00u - -7:00 - MST 1927 Jun 10 23:00 + -7:00 - MST 1927 Jun 10 -6:00 - CST 1930 Nov 15 -7:00 Mexico M%sT 1932 Apr 1 -6:00 - CST 1996 @@ -2685,7 +2745,7 @@ Zone America/Ojinaga -6:57:40 - LMT 1922 Jan 1 7:00u -6:00 US C%sT # Chihuahua (away from US border) Zone America/Chihuahua -7:04:20 - LMT 1922 Jan 1 7:00u - -7:00 - MST 1927 Jun 10 23:00 + -7:00 - MST 1927 Jun 10 -6:00 - CST 1930 Nov 15 -7:00 Mexico M%sT 1932 Apr 1 -6:00 - CST 1996 @@ -2695,23 +2755,21 @@ Zone America/Chihuahua -7:04:20 - LMT 1922 Jan 1 7:00u -6:00 - CST # Sonora Zone America/Hermosillo -7:23:52 - LMT 1922 Jan 1 7:00u - -7:00 - MST 1927 Jun 10 23:00 + -7:00 - MST 1927 Jun 10 -6:00 - CST 1930 Nov 15 -7:00 Mexico M%sT 1932 Apr 1 -6:00 - CST 1942 Apr 24 - -7:00 - MST 1949 Jan 14 - -8:00 - PST 1970 + -7:00 - MST 1996 -7:00 Mexico M%sT 1999 -7:00 - MST # Baja California Sur, Nayarit (except Bahía de Banderas), Sinaloa Zone America/Mazatlan -7:05:40 - LMT 1922 Jan 1 7:00u - -7:00 - MST 1927 Jun 10 23:00 + -7:00 - MST 1927 Jun 10 -6:00 - CST 1930 Nov 15 -7:00 Mexico M%sT 1932 Apr 1 -6:00 - CST 1942 Apr 24 - -7:00 - MST 1949 Jan 14 - -8:00 - PST 1970 + -7:00 - MST 1970 -7:00 Mexico M%sT # Bahía de Banderas @@ -2744,27 +2802,32 @@ Zone America/Mazatlan -7:05:40 - LMT 1922 Jan 1 7:00u # Use "Bahia_Banderas" to keep the name to fourteen characters. Zone America/Bahia_Banderas -7:01:00 - LMT 1922 Jan 1 7:00u - -7:00 - MST 1927 Jun 10 23:00 + -7:00 - MST 1927 Jun 10 -6:00 - CST 1930 Nov 15 -7:00 Mexico M%sT 1932 Apr 1 -6:00 - CST 1942 Apr 24 - -7:00 - MST 1949 Jan 14 - -8:00 - PST 1970 + -7:00 - MST 1970 -7:00 Mexico M%sT 2010 Apr 4 2:00 -6:00 Mexico C%sT # Baja California Zone America/Tijuana -7:48:04 - LMT 1922 Jan 1 7:00u -7:00 - MST 1924 - -8:00 - PST 1927 Jun 10 23:00 + -8:00 - PST 1927 Jun 10 -7:00 - MST 1930 Nov 15 -8:00 - PST 1931 Apr 1 -8:00 1:00 PDT 1931 Sep 30 -8:00 - PST 1942 Apr 24 -8:00 1:00 PWT 1945 Aug 14 23:00u - -8:00 1:00 PPT 1945 Nov 12 # Peace + -8:00 1:00 PPT 1945 Nov 15 # Peace -8:00 - PST 1948 Apr 5 -8:00 1:00 PDT 1949 Jan 14 + -8:00 - PST 1950 May 1 + -8:00 1:00 PDT 1950 Sep 24 + -8:00 - PST 1951 Apr 29 2:00 + -8:00 1:00 PDT 1951 Sep 30 2:00 + -8:00 - PST 1952 Apr 27 2:00 + -8:00 1:00 PDT 1952 Sep 28 2:00 -8:00 - PST 1954 -8:00 CA P%sT 1961 -8:00 - PST 1976 @@ -3573,8 +3636,8 @@ Zone America/Puerto_Rico -4:24:25 - LMT 1899 Mar 28 12:00 # San Juan # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/Miquelon -3:44:40 - LMT 1911 Jun 15 # St Pierre -4:00 - AST 1980 May - -3:00 - -03 1987 - -3:00 Canada -03/-02 + -3:00 - %z 1987 + -3:00 Canada %z # Turks and Caicos # diff --git a/src/java.base/share/data/tzdata/southamerica b/src/java.base/share/data/tzdata/southamerica index d77acc088570b..3824202546afa 100644 --- a/src/java.base/share/data/tzdata/southamerica +++ b/src/java.base/share/data/tzdata/southamerica @@ -425,11 +425,11 @@ Rule Arg 2008 only - Oct Sun>=15 0:00 1:00 - Zone America/Argentina/Buenos_Aires -3:53:48 - LMT 1894 Oct 31 #STDOFF -4:16:48.25 -4:16:48 - CMT 1920 May # Córdoba Mean Time - -4:00 - -04 1930 Dec - -4:00 Arg -04/-03 1969 Oct 5 - -3:00 Arg -03/-02 1999 Oct 3 - -4:00 Arg -04/-03 2000 Mar 3 - -3:00 Arg -03/-02 + -4:00 - %z 1930 Dec + -4:00 Arg %z 1969 Oct 5 + -3:00 Arg %z 1999 Oct 3 + -4:00 Arg %z 2000 Mar 3 + -3:00 Arg %z # # Córdoba (CB), Santa Fe (SF), Entre Ríos (ER), Corrientes (CN), Misiones (MN), # Chaco (CC), Formosa (FM), Santiago del Estero (SE) @@ -444,120 +444,120 @@ Zone America/Argentina/Buenos_Aires -3:53:48 - LMT 1894 Oct 31 #STDOFF -4:16:48.25 Zone America/Argentina/Cordoba -4:16:48 - LMT 1894 Oct 31 -4:16:48 - CMT 1920 May - -4:00 - -04 1930 Dec - -4:00 Arg -04/-03 1969 Oct 5 - -3:00 Arg -03/-02 1991 Mar 3 - -4:00 - -04 1991 Oct 20 - -3:00 Arg -03/-02 1999 Oct 3 - -4:00 Arg -04/-03 2000 Mar 3 - -3:00 Arg -03/-02 + -4:00 - %z 1930 Dec + -4:00 Arg %z 1969 Oct 5 + -3:00 Arg %z 1991 Mar 3 + -4:00 - %z 1991 Oct 20 + -3:00 Arg %z 1999 Oct 3 + -4:00 Arg %z 2000 Mar 3 + -3:00 Arg %z # # Salta (SA), La Pampa (LP), Neuquén (NQ), Rio Negro (RN) Zone America/Argentina/Salta -4:21:40 - LMT 1894 Oct 31 #STDOFF -4:16:48.25 -4:16:48 - CMT 1920 May - -4:00 - -04 1930 Dec - -4:00 Arg -04/-03 1969 Oct 5 - -3:00 Arg -03/-02 1991 Mar 3 - -4:00 - -04 1991 Oct 20 - -3:00 Arg -03/-02 1999 Oct 3 - -4:00 Arg -04/-03 2000 Mar 3 - -3:00 Arg -03/-02 2008 Oct 18 - -3:00 - -03 + -4:00 - %z 1930 Dec + -4:00 Arg %z 1969 Oct 5 + -3:00 Arg %z 1991 Mar 3 + -4:00 - %z 1991 Oct 20 + -3:00 Arg %z 1999 Oct 3 + -4:00 Arg %z 2000 Mar 3 + -3:00 Arg %z 2008 Oct 18 + -3:00 - %z # # Tucumán (TM) Zone America/Argentina/Tucuman -4:20:52 - LMT 1894 Oct 31 #STDOFF -4:16:48.25 -4:16:48 - CMT 1920 May - -4:00 - -04 1930 Dec - -4:00 Arg -04/-03 1969 Oct 5 - -3:00 Arg -03/-02 1991 Mar 3 - -4:00 - -04 1991 Oct 20 - -3:00 Arg -03/-02 1999 Oct 3 - -4:00 Arg -04/-03 2000 Mar 3 - -3:00 - -03 2004 Jun 1 - -4:00 - -04 2004 Jun 13 - -3:00 Arg -03/-02 + -4:00 - %z 1930 Dec + -4:00 Arg %z 1969 Oct 5 + -3:00 Arg %z 1991 Mar 3 + -4:00 - %z 1991 Oct 20 + -3:00 Arg %z 1999 Oct 3 + -4:00 Arg %z 2000 Mar 3 + -3:00 - %z 2004 Jun 1 + -4:00 - %z 2004 Jun 13 + -3:00 Arg %z # # La Rioja (LR) Zone America/Argentina/La_Rioja -4:27:24 - LMT 1894 Oct 31 #STDOFF -4:16:48.25 -4:16:48 - CMT 1920 May - -4:00 - -04 1930 Dec - -4:00 Arg -04/-03 1969 Oct 5 - -3:00 Arg -03/-02 1991 Mar 1 - -4:00 - -04 1991 May 7 - -3:00 Arg -03/-02 1999 Oct 3 - -4:00 Arg -04/-03 2000 Mar 3 - -3:00 - -03 2004 Jun 1 - -4:00 - -04 2004 Jun 20 - -3:00 Arg -03/-02 2008 Oct 18 - -3:00 - -03 + -4:00 - %z 1930 Dec + -4:00 Arg %z 1969 Oct 5 + -3:00 Arg %z 1991 Mar 1 + -4:00 - %z 1991 May 7 + -3:00 Arg %z 1999 Oct 3 + -4:00 Arg %z 2000 Mar 3 + -3:00 - %z 2004 Jun 1 + -4:00 - %z 2004 Jun 20 + -3:00 Arg %z 2008 Oct 18 + -3:00 - %z # # San Juan (SJ) Zone America/Argentina/San_Juan -4:34:04 - LMT 1894 Oct 31 #STDOFF -4:16:48.25 -4:16:48 - CMT 1920 May - -4:00 - -04 1930 Dec - -4:00 Arg -04/-03 1969 Oct 5 - -3:00 Arg -03/-02 1991 Mar 1 - -4:00 - -04 1991 May 7 - -3:00 Arg -03/-02 1999 Oct 3 - -4:00 Arg -04/-03 2000 Mar 3 - -3:00 - -03 2004 May 31 - -4:00 - -04 2004 Jul 25 - -3:00 Arg -03/-02 2008 Oct 18 - -3:00 - -03 + -4:00 - %z 1930 Dec + -4:00 Arg %z 1969 Oct 5 + -3:00 Arg %z 1991 Mar 1 + -4:00 - %z 1991 May 7 + -3:00 Arg %z 1999 Oct 3 + -4:00 Arg %z 2000 Mar 3 + -3:00 - %z 2004 May 31 + -4:00 - %z 2004 Jul 25 + -3:00 Arg %z 2008 Oct 18 + -3:00 - %z # # Jujuy (JY) Zone America/Argentina/Jujuy -4:21:12 - LMT 1894 Oct 31 #STDOFF -4:16:48.25 -4:16:48 - CMT 1920 May - -4:00 - -04 1930 Dec - -4:00 Arg -04/-03 1969 Oct 5 - -3:00 Arg -03/-02 1990 Mar 4 - -4:00 - -04 1990 Oct 28 - -4:00 1:00 -03 1991 Mar 17 - -4:00 - -04 1991 Oct 6 - -3:00 1:00 -02 1992 - -3:00 Arg -03/-02 1999 Oct 3 - -4:00 Arg -04/-03 2000 Mar 3 - -3:00 Arg -03/-02 2008 Oct 18 - -3:00 - -03 + -4:00 - %z 1930 Dec + -4:00 Arg %z 1969 Oct 5 + -3:00 Arg %z 1990 Mar 4 + -4:00 - %z 1990 Oct 28 + -4:00 1:00 %z 1991 Mar 17 + -4:00 - %z 1991 Oct 6 + -3:00 1:00 %z 1992 + -3:00 Arg %z 1999 Oct 3 + -4:00 Arg %z 2000 Mar 3 + -3:00 Arg %z 2008 Oct 18 + -3:00 - %z # # Catamarca (CT), Chubut (CH) Zone America/Argentina/Catamarca -4:23:08 - LMT 1894 Oct 31 #STDOFF -4:16:48.25 -4:16:48 - CMT 1920 May - -4:00 - -04 1930 Dec - -4:00 Arg -04/-03 1969 Oct 5 - -3:00 Arg -03/-02 1991 Mar 3 - -4:00 - -04 1991 Oct 20 - -3:00 Arg -03/-02 1999 Oct 3 - -4:00 Arg -04/-03 2000 Mar 3 - -3:00 - -03 2004 Jun 1 - -4:00 - -04 2004 Jun 20 - -3:00 Arg -03/-02 2008 Oct 18 - -3:00 - -03 + -4:00 - %z 1930 Dec + -4:00 Arg %z 1969 Oct 5 + -3:00 Arg %z 1991 Mar 3 + -4:00 - %z 1991 Oct 20 + -3:00 Arg %z 1999 Oct 3 + -4:00 Arg %z 2000 Mar 3 + -3:00 - %z 2004 Jun 1 + -4:00 - %z 2004 Jun 20 + -3:00 Arg %z 2008 Oct 18 + -3:00 - %z # # Mendoza (MZ) Zone America/Argentina/Mendoza -4:35:16 - LMT 1894 Oct 31 #STDOFF -4:16:48.25 -4:16:48 - CMT 1920 May - -4:00 - -04 1930 Dec - -4:00 Arg -04/-03 1969 Oct 5 - -3:00 Arg -03/-02 1990 Mar 4 - -4:00 - -04 1990 Oct 15 - -4:00 1:00 -03 1991 Mar 1 - -4:00 - -04 1991 Oct 15 - -4:00 1:00 -03 1992 Mar 1 - -4:00 - -04 1992 Oct 18 - -3:00 Arg -03/-02 1999 Oct 3 - -4:00 Arg -04/-03 2000 Mar 3 - -3:00 - -03 2004 May 23 - -4:00 - -04 2004 Sep 26 - -3:00 Arg -03/-02 2008 Oct 18 - -3:00 - -03 + -4:00 - %z 1930 Dec + -4:00 Arg %z 1969 Oct 5 + -3:00 Arg %z 1990 Mar 4 + -4:00 - %z 1990 Oct 15 + -4:00 1:00 %z 1991 Mar 1 + -4:00 - %z 1991 Oct 15 + -4:00 1:00 %z 1992 Mar 1 + -4:00 - %z 1992 Oct 18 + -3:00 Arg %z 1999 Oct 3 + -4:00 Arg %z 2000 Mar 3 + -3:00 - %z 2004 May 23 + -4:00 - %z 2004 Sep 26 + -3:00 Arg %z 2008 Oct 18 + -3:00 - %z # # San Luis (SL) @@ -567,53 +567,53 @@ Rule SanLuis 2007 2008 - Oct Sun>=8 0:00 1:00 - Zone America/Argentina/San_Luis -4:25:24 - LMT 1894 Oct 31 #STDOFF -4:16:48.25 -4:16:48 - CMT 1920 May - -4:00 - -04 1930 Dec - -4:00 Arg -04/-03 1969 Oct 5 - -3:00 Arg -03/-02 1990 - -3:00 1:00 -02 1990 Mar 14 - -4:00 - -04 1990 Oct 15 - -4:00 1:00 -03 1991 Mar 1 - -4:00 - -04 1991 Jun 1 - -3:00 - -03 1999 Oct 3 - -4:00 1:00 -03 2000 Mar 3 - -3:00 - -03 2004 May 31 - -4:00 - -04 2004 Jul 25 - -3:00 Arg -03/-02 2008 Jan 21 - -4:00 SanLuis -04/-03 2009 Oct 11 - -3:00 - -03 + -4:00 - %z 1930 Dec + -4:00 Arg %z 1969 Oct 5 + -3:00 Arg %z 1990 + -3:00 1:00 %z 1990 Mar 14 + -4:00 - %z 1990 Oct 15 + -4:00 1:00 %z 1991 Mar 1 + -4:00 - %z 1991 Jun 1 + -3:00 - %z 1999 Oct 3 + -4:00 1:00 %z 2000 Mar 3 + -3:00 - %z 2004 May 31 + -4:00 - %z 2004 Jul 25 + -3:00 Arg %z 2008 Jan 21 + -4:00 SanLuis %z 2009 Oct 11 + -3:00 - %z # # Santa Cruz (SC) Zone America/Argentina/Rio_Gallegos -4:36:52 - LMT 1894 Oct 31 #STDOFF -4:16:48.25 -4:16:48 - CMT 1920 May - -4:00 - -04 1930 Dec - -4:00 Arg -04/-03 1969 Oct 5 - -3:00 Arg -03/-02 1999 Oct 3 - -4:00 Arg -04/-03 2000 Mar 3 - -3:00 - -03 2004 Jun 1 - -4:00 - -04 2004 Jun 20 - -3:00 Arg -03/-02 2008 Oct 18 - -3:00 - -03 + -4:00 - %z 1930 Dec + -4:00 Arg %z 1969 Oct 5 + -3:00 Arg %z 1999 Oct 3 + -4:00 Arg %z 2000 Mar 3 + -3:00 - %z 2004 Jun 1 + -4:00 - %z 2004 Jun 20 + -3:00 Arg %z 2008 Oct 18 + -3:00 - %z # # Tierra del Fuego, Antártida e Islas del Atlántico Sur (TF) Zone America/Argentina/Ushuaia -4:33:12 - LMT 1894 Oct 31 #STDOFF -4:16:48.25 -4:16:48 - CMT 1920 May - -4:00 - -04 1930 Dec - -4:00 Arg -04/-03 1969 Oct 5 - -3:00 Arg -03/-02 1999 Oct 3 - -4:00 Arg -04/-03 2000 Mar 3 - -3:00 - -03 2004 May 30 - -4:00 - -04 2004 Jun 20 - -3:00 Arg -03/-02 2008 Oct 18 - -3:00 - -03 + -4:00 - %z 1930 Dec + -4:00 Arg %z 1969 Oct 5 + -3:00 Arg %z 1999 Oct 3 + -4:00 Arg %z 2000 Mar 3 + -3:00 - %z 2004 May 30 + -4:00 - %z 2004 Jun 20 + -3:00 Arg %z 2008 Oct 18 + -3:00 - %z # Bolivia # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/La_Paz -4:32:36 - LMT 1890 -4:32:36 - CMT 1931 Oct 15 # Calamarca MT -4:32:36 1:00 BST 1932 Mar 21 # Bolivia ST - -4:00 - -04 + -4:00 - %z # Brazil @@ -984,12 +984,12 @@ Rule Brazil 2018 only - Nov Sun>=1 0:00 1:00 - # # Fernando de Noronha (administratively part of PE) Zone America/Noronha -2:09:40 - LMT 1914 - -2:00 Brazil -02/-01 1990 Sep 17 - -2:00 - -02 1999 Sep 30 - -2:00 Brazil -02/-01 2000 Oct 15 - -2:00 - -02 2001 Sep 13 - -2:00 Brazil -02/-01 2002 Oct 1 - -2:00 - -02 + -2:00 Brazil %z 1990 Sep 17 + -2:00 - %z 1999 Sep 30 + -2:00 Brazil %z 2000 Oct 15 + -2:00 - %z 2001 Sep 13 + -2:00 Brazil %z 2002 Oct 1 + -2:00 - %z # Other Atlantic islands have no permanent settlement. # These include Trindade and Martim Vaz (administratively part of ES), # Rocas Atoll (RN), and the St Peter and St Paul Archipelago (PE). @@ -1002,119 +1002,119 @@ Zone America/Noronha -2:09:40 - LMT 1914 # In the north a very small part from the river Javary (now Jari I guess, # the border with Amapá) to the Amazon, then to the Xingu. Zone America/Belem -3:13:56 - LMT 1914 - -3:00 Brazil -03/-02 1988 Sep 12 - -3:00 - -03 + -3:00 Brazil %z 1988 Sep 12 + -3:00 - %z # # west Pará (PA) # West Pará includes Altamira, Óbidos, Prainha, Oriximiná, and Santarém. Zone America/Santarem -3:38:48 - LMT 1914 - -4:00 Brazil -04/-03 1988 Sep 12 - -4:00 - -04 2008 Jun 24 0:00 - -3:00 - -03 + -4:00 Brazil %z 1988 Sep 12 + -4:00 - %z 2008 Jun 24 0:00 + -3:00 - %z # # Maranhão (MA), Piauí (PI), Ceará (CE), Rio Grande do Norte (RN), # Paraíba (PB) Zone America/Fortaleza -2:34:00 - LMT 1914 - -3:00 Brazil -03/-02 1990 Sep 17 - -3:00 - -03 1999 Sep 30 - -3:00 Brazil -03/-02 2000 Oct 22 - -3:00 - -03 2001 Sep 13 - -3:00 Brazil -03/-02 2002 Oct 1 - -3:00 - -03 + -3:00 Brazil %z 1990 Sep 17 + -3:00 - %z 1999 Sep 30 + -3:00 Brazil %z 2000 Oct 22 + -3:00 - %z 2001 Sep 13 + -3:00 Brazil %z 2002 Oct 1 + -3:00 - %z # # Pernambuco (PE) (except Atlantic islands) Zone America/Recife -2:19:36 - LMT 1914 - -3:00 Brazil -03/-02 1990 Sep 17 - -3:00 - -03 1999 Sep 30 - -3:00 Brazil -03/-02 2000 Oct 15 - -3:00 - -03 2001 Sep 13 - -3:00 Brazil -03/-02 2002 Oct 1 - -3:00 - -03 + -3:00 Brazil %z 1990 Sep 17 + -3:00 - %z 1999 Sep 30 + -3:00 Brazil %z 2000 Oct 15 + -3:00 - %z 2001 Sep 13 + -3:00 Brazil %z 2002 Oct 1 + -3:00 - %z # # Tocantins (TO) Zone America/Araguaina -3:12:48 - LMT 1914 - -3:00 Brazil -03/-02 1990 Sep 17 - -3:00 - -03 1995 Sep 14 - -3:00 Brazil -03/-02 2003 Sep 24 - -3:00 - -03 2012 Oct 21 - -3:00 Brazil -03/-02 2013 Sep - -3:00 - -03 + -3:00 Brazil %z 1990 Sep 17 + -3:00 - %z 1995 Sep 14 + -3:00 Brazil %z 2003 Sep 24 + -3:00 - %z 2012 Oct 21 + -3:00 Brazil %z 2013 Sep + -3:00 - %z # # Alagoas (AL), Sergipe (SE) Zone America/Maceio -2:22:52 - LMT 1914 - -3:00 Brazil -03/-02 1990 Sep 17 - -3:00 - -03 1995 Oct 13 - -3:00 Brazil -03/-02 1996 Sep 4 - -3:00 - -03 1999 Sep 30 - -3:00 Brazil -03/-02 2000 Oct 22 - -3:00 - -03 2001 Sep 13 - -3:00 Brazil -03/-02 2002 Oct 1 - -3:00 - -03 + -3:00 Brazil %z 1990 Sep 17 + -3:00 - %z 1995 Oct 13 + -3:00 Brazil %z 1996 Sep 4 + -3:00 - %z 1999 Sep 30 + -3:00 Brazil %z 2000 Oct 22 + -3:00 - %z 2001 Sep 13 + -3:00 Brazil %z 2002 Oct 1 + -3:00 - %z # # Bahia (BA) # There are too many Salvadors elsewhere, so use America/Bahia instead # of America/Salvador. Zone America/Bahia -2:34:04 - LMT 1914 - -3:00 Brazil -03/-02 2003 Sep 24 - -3:00 - -03 2011 Oct 16 - -3:00 Brazil -03/-02 2012 Oct 21 - -3:00 - -03 + -3:00 Brazil %z 2003 Sep 24 + -3:00 - %z 2011 Oct 16 + -3:00 Brazil %z 2012 Oct 21 + -3:00 - %z # # Goiás (GO), Distrito Federal (DF), Minas Gerais (MG), # Espírito Santo (ES), Rio de Janeiro (RJ), São Paulo (SP), Paraná (PR), # Santa Catarina (SC), Rio Grande do Sul (RS) Zone America/Sao_Paulo -3:06:28 - LMT 1914 - -3:00 Brazil -03/-02 1963 Oct 23 0:00 - -3:00 1:00 -02 1964 - -3:00 Brazil -03/-02 + -3:00 Brazil %z 1963 Oct 23 0:00 + -3:00 1:00 %z 1964 + -3:00 Brazil %z # # Mato Grosso do Sul (MS) Zone America/Campo_Grande -3:38:28 - LMT 1914 - -4:00 Brazil -04/-03 + -4:00 Brazil %z # # Mato Grosso (MT) Zone America/Cuiaba -3:44:20 - LMT 1914 - -4:00 Brazil -04/-03 2003 Sep 24 - -4:00 - -04 2004 Oct 1 - -4:00 Brazil -04/-03 + -4:00 Brazil %z 2003 Sep 24 + -4:00 - %z 2004 Oct 1 + -4:00 Brazil %z # # Rondônia (RO) Zone America/Porto_Velho -4:15:36 - LMT 1914 - -4:00 Brazil -04/-03 1988 Sep 12 - -4:00 - -04 + -4:00 Brazil %z 1988 Sep 12 + -4:00 - %z # # Roraima (RR) Zone America/Boa_Vista -4:02:40 - LMT 1914 - -4:00 Brazil -04/-03 1988 Sep 12 - -4:00 - -04 1999 Sep 30 - -4:00 Brazil -04/-03 2000 Oct 15 - -4:00 - -04 + -4:00 Brazil %z 1988 Sep 12 + -4:00 - %z 1999 Sep 30 + -4:00 Brazil %z 2000 Oct 15 + -4:00 - %z # # east Amazonas (AM): Boca do Acre, Jutaí, Manaus, Floriano Peixoto # The great circle line from Tabatinga to Porto Acre divides # east from west Amazonas. Zone America/Manaus -4:00:04 - LMT 1914 - -4:00 Brazil -04/-03 1988 Sep 12 - -4:00 - -04 1993 Sep 28 - -4:00 Brazil -04/-03 1994 Sep 22 - -4:00 - -04 + -4:00 Brazil %z 1988 Sep 12 + -4:00 - %z 1993 Sep 28 + -4:00 Brazil %z 1994 Sep 22 + -4:00 - %z # # west Amazonas (AM): Atalaia do Norte, Boca do Maoco, Benjamin Constant, # Eirunepé, Envira, Ipixuna Zone America/Eirunepe -4:39:28 - LMT 1914 - -5:00 Brazil -05/-04 1988 Sep 12 - -5:00 - -05 1993 Sep 28 - -5:00 Brazil -05/-04 1994 Sep 22 - -5:00 - -05 2008 Jun 24 0:00 - -4:00 - -04 2013 Nov 10 - -5:00 - -05 + -5:00 Brazil %z 1988 Sep 12 + -5:00 - %z 1993 Sep 28 + -5:00 Brazil %z 1994 Sep 22 + -5:00 - %z 2008 Jun 24 0:00 + -4:00 - %z 2013 Nov 10 + -5:00 - %z # # Acre (AC) Zone America/Rio_Branco -4:31:12 - LMT 1914 - -5:00 Brazil -05/-04 1988 Sep 12 - -5:00 - -05 2008 Jun 24 0:00 - -4:00 - -04 2013 Nov 10 - -5:00 - -05 + -5:00 Brazil %z 1988 Sep 12 + -5:00 - %z 2008 Jun 24 0:00 + -4:00 - %z 2013 Nov 10 + -5:00 - %z # Chile @@ -1382,36 +1382,36 @@ Rule Chile 2023 max - Sep Sun>=2 4:00u 1:00 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/Santiago -4:42:45 - LMT 1890 -4:42:45 - SMT 1910 Jan 10 # Santiago Mean Time - -5:00 - -05 1916 Jul 1 + -5:00 - %z 1916 Jul 1 -4:42:45 - SMT 1918 Sep 10 - -4:00 - -04 1919 Jul 1 + -4:00 - %z 1919 Jul 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 - -4:00 - -04 1946 Jul 14 24:00 - -4:00 1:00 -03 1946 Aug 28 24:00 # central CL - -5:00 1:00 -04 1947 Mar 31 24:00 - -5:00 - -05 1947 May 21 23:00 - -4:00 Chile -04/-03 + -5:00 Chile %z 1932 Sep 1 + -4:00 - %z 1942 Jun 1 + -5:00 - %z 1942 Aug 1 + -4:00 - %z 1946 Jul 14 24:00 + -4:00 1:00 %z 1946 Aug 28 24:00 # central CL + -5:00 1:00 %z 1947 Mar 31 24:00 + -5:00 - %z 1947 May 21 23:00 + -4:00 Chile %z Zone America/Punta_Arenas -4:43:40 - LMT 1890 -4:42:45 - SMT 1910 Jan 10 - -5:00 - -05 1916 Jul 1 + -5:00 - %z 1916 Jul 1 -4:42:45 - SMT 1918 Sep 10 - -4:00 - -04 1919 Jul 1 + -4:00 - %z 1919 Jul 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 - -4:00 - -04 1946 Aug 28 24:00 - -5:00 1:00 -04 1947 Mar 31 24:00 - -5:00 - -05 1947 May 21 23:00 - -4:00 Chile -04/-03 2016 Dec 4 - -3:00 - -03 + -5:00 Chile %z 1932 Sep 1 + -4:00 - %z 1942 Jun 1 + -5:00 - %z 1942 Aug 1 + -4:00 - %z 1946 Aug 28 24:00 + -5:00 1:00 %z 1947 Mar 31 24:00 + -5:00 - %z 1947 May 21 23:00 + -4:00 Chile %z 2016 Dec 4 + -3:00 - %z Zone Pacific/Easter -7:17:28 - LMT 1890 -7:17:28 - EMT 1932 Sep # Easter Mean Time - -7:00 Chile -07/-06 1982 Mar 14 3:00u # Easter Time - -6:00 Chile -06/-05 + -7:00 Chile %z 1982 Mar 14 3:00u # Easter Time + -6:00 Chile %z # # Salas y Gómez Island is uninhabited. # Other Chilean locations, including Juan Fernández Is, Desventuradas Is, @@ -1431,10 +1431,10 @@ Zone Pacific/Easter -7:17:28 - LMT 1890 # # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Antarctica/Palmer 0 - -00 1965 - -4:00 Arg -04/-03 1969 Oct 5 - -3:00 Arg -03/-02 1982 May - -4:00 Chile -04/-03 2016 Dec 4 - -3:00 - -03 + -4:00 Arg %z 1969 Oct 5 + -3:00 Arg %z 1982 May + -4:00 Chile %z 2016 Dec 4 + -3:00 - %z # Colombia @@ -1453,7 +1453,7 @@ Rule CO 1993 only - Feb 6 24:00 0 - #STDOFF -4:56:16.4 Zone America/Bogota -4:56:16 - LMT 1884 Mar 13 -4:56:16 - BMT 1914 Nov 23 # Bogotá Mean Time - -5:00 CO -05/-04 + -5:00 CO %z # Malpelo, Providencia, San Andres # no information; probably like America/Bogota @@ -1484,10 +1484,10 @@ Rule Ecuador 1993 only - Feb 5 0:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/Guayaquil -5:19:20 - LMT 1890 -5:14:00 - QMT 1931 # Quito Mean Time - -5:00 Ecuador -05/-04 + -5:00 Ecuador %z Zone Pacific/Galapagos -5:58:24 - LMT 1931 # Puerto Baquerizo Moreno - -5:00 - -05 1986 - -6:00 Ecuador -06/-05 + -5:00 - %z 1986 + -6:00 Ecuador %z # Falklands @@ -1587,10 +1587,10 @@ Rule Falk 2001 2010 - Sep Sun>=1 2:00 1:00 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Atlantic/Stanley -3:51:24 - LMT 1890 -3:51:24 - SMT 1912 Mar 12 # Stanley Mean Time - -4:00 Falk -04/-03 1983 May - -3:00 Falk -03/-02 1985 Sep 15 - -4:00 Falk -04/-03 2010 Sep 5 2:00 - -3:00 - -03 + -4:00 Falk %z 1983 May + -3:00 Falk %z 1985 Sep 15 + -4:00 Falk %z 2010 Sep 5 2:00 + -3:00 - %z # French Guiana # For the 1911/1912 establishment of standard time in French possessions, see: @@ -1598,8 +1598,8 @@ Zone Atlantic/Stanley -3:51:24 - LMT 1890 # page 752, 18b. # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/Cayenne -3:29:20 - LMT 1911 Jul 1 - -4:00 - -04 1967 Oct - -3:00 - -03 + -4:00 - %z 1967 Oct + -3:00 - %z # Guyana @@ -1633,10 +1633,10 @@ Zone America/Cayenne -3:29:20 - LMT 1911 Jul 1 # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/Guyana -3:52:39 - LMT 1911 Aug 1 # Georgetown - -4:00 - -04 1915 Mar 1 - -3:45 - -0345 1975 Aug 1 - -3:00 - -03 1992 Mar 29 1:00 - -4:00 - -04 + -4:00 - %z 1915 Mar 1 + -3:45 - %z 1975 Aug 1 + -3:00 - %z 1992 Mar 29 1:00 + -4:00 - %z # Paraguay # @@ -1734,9 +1734,9 @@ Rule Para 2013 max - Mar Sun>=22 0:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/Asuncion -3:50:40 - LMT 1890 -3:50:40 - AMT 1931 Oct 10 # Asunción Mean Time - -4:00 - -04 1972 Oct - -3:00 - -03 1974 Apr - -4:00 Para -04/-03 + -4:00 - %z 1972 Oct + -3:00 - %z 1974 Apr + -4:00 Para %z # Peru # @@ -1763,12 +1763,12 @@ Rule Peru 1994 only - Apr 1 0:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/Lima -5:08:12 - LMT 1890 -5:08:36 - LMT 1908 Jul 28 # Lima Mean Time? - -5:00 Peru -05/-04 + -5:00 Peru %z # South Georgia # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Atlantic/South_Georgia -2:26:08 - LMT 1890 # Grytviken - -2:00 - -02 + -2:00 - %z # South Sandwich Is # uninhabited; scientific personnel have wintered @@ -1778,8 +1778,8 @@ Zone Atlantic/South_Georgia -2:26:08 - LMT 1890 # Grytviken Zone America/Paramaribo -3:40:40 - LMT 1911 -3:40:52 - PMT 1935 # Paramaribo Mean Time -3:40:36 - PMT 1945 Oct # The capital moved? - -3:30 - -0330 1984 Oct - -3:00 - -03 + -3:30 - %z 1984 Oct + -3:00 - %z # Uruguay # From Paul Eggert (1993-11-18): @@ -1994,15 +1994,15 @@ Rule Uruguay 2006 2014 - Oct Sun>=1 2:00 1:00 - # This Zone can be simplified once we assume zic %z. Zone America/Montevideo -3:44:51 - LMT 1908 Jun 10 -3:44:51 - MMT 1920 May 1 # Montevideo MT - -4:00 - -04 1923 Oct 1 - -3:30 Uruguay -0330/-03 1942 Dec 14 - -3:00 Uruguay -03/-0230 1960 - -3:00 Uruguay -03/-02 1968 - -3:00 Uruguay -03/-0230 1970 - -3:00 Uruguay -03/-02 1974 - -3:00 Uruguay -03/-0130 1974 Mar 10 - -3:00 Uruguay -03/-0230 1974 Dec 22 - -3:00 Uruguay -03/-02 + -4:00 - %z 1923 Oct 1 + -3:30 Uruguay %z 1942 Dec 14 + -3:00 Uruguay %z 1960 + -3:00 Uruguay %z 1968 + -3:00 Uruguay %z 1970 + -3:00 Uruguay %z 1974 + -3:00 Uruguay %z 1974 Mar 10 + -3:00 Uruguay %z 1974 Dec 22 + -3:00 Uruguay %z # Venezuela # @@ -2036,7 +2036,7 @@ Zone America/Montevideo -3:44:51 - LMT 1908 Jun 10 # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/Caracas -4:27:44 - LMT 1890 -4:27:40 - CMT 1912 Feb 12 # Caracas Mean Time? - -4:30 - -0430 1965 Jan 1 0:00 - -4:00 - -04 2007 Dec 9 3:00 - -4:30 - -0430 2016 May 1 2:30 - -4:00 - -04 + -4:30 - %z 1965 Jan 1 0:00 + -4:00 - %z 2007 Dec 9 3:00 + -4:30 - %z 2016 May 1 2:30 + -4:00 - %z diff --git a/src/java.base/share/data/tzdata/zone.tab b/src/java.base/share/data/tzdata/zone.tab index 0a01e8777dd25..b90ab4e4b25fb 100644 --- a/src/java.base/share/data/tzdata/zone.tab +++ b/src/java.base/share/data/tzdata/zone.tab @@ -287,8 +287,7 @@ MK +4159+02126 Europe/Skopje ML +1239-00800 Africa/Bamako MM +1647+09610 Asia/Yangon MN +4755+10653 Asia/Ulaanbaatar most of Mongolia -MN +4801+09139 Asia/Hovd Bayan-Olgiy, Govi-Altai, Hovd, Uvs, Zavkhan -MN +4804+11430 Asia/Choibalsan Dornod, Sukhbaatar +MN +4801+09139 Asia/Hovd Bayan-Olgii, Hovd, Uvs MO +221150+1133230 Asia/Macau MP +1512+14545 Pacific/Saipan MQ +1436-06105 America/Martinique diff --git a/test/jdk/java/text/Format/DateFormat/TimeZoneNameTest.java b/test/jdk/java/text/Format/DateFormat/TimeZoneNameTest.java index 8ce11445ca0e0..e74bd41ddf9f6 100644 --- a/test/jdk/java/text/Format/DateFormat/TimeZoneNameTest.java +++ b/test/jdk/java/text/Format/DateFormat/TimeZoneNameTest.java @@ -75,7 +75,7 @@ static void initAll() { "N", "GMT", "GMT", "Greenwich Mean Time", "GMT", "Greenwich Mean Time", "N", "Europe/London", "GMT", "Greenwich Mean Time", "BST", "British Summer Time", "N", "Europe/Paris", "CET", "Central European Standard Time", "CEST", "Central European Summer Time", - "N", "WET", "WET", "GMT", "WEST", "GMT+01:00", + "N", "WET", "WET", "Western European Standard Time", "WEST", "Western European Summer Time", "N", "Europe/Berlin", "CET", "Central European Standard Time", "CEST", "Central European Summer Time", "N", "Asia/Jerusalem", "IST", "Israel Standard Time", "IDT", "Israel Daylight Time", "N", "Europe/Helsinki", "EET", "Eastern European Standard Time", "EEST", "Eastern European Summer Time", diff --git a/test/jdk/java/time/tck/java/time/TCKZoneId.java b/test/jdk/java/time/tck/java/time/TCKZoneId.java index a90c9abf48e37..a1d0065d39e68 100644 --- a/test/jdk/java/time/tck/java/time/TCKZoneId.java +++ b/test/jdk/java/time/tck/java/time/TCKZoneId.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * 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,11 +96,11 @@ public class TCKZoneId extends AbstractTCKTest { //----------------------------------------------------------------------- // SHORT_IDS //----------------------------------------------------------------------- - public void test_constant_OLD_IDS_POST_2005() { + public void test_constant_OLD_IDS_POST_2024b() { Map ids = ZoneId.SHORT_IDS; - assertEquals(ids.get("EST"), "-05:00"); - assertEquals(ids.get("MST"), "-07:00"); - assertEquals(ids.get("HST"), "-10:00"); + assertEquals(ids.get("EST"), "America/Panama"); + assertEquals(ids.get("MST"), "America/Phoenix"); + assertEquals(ids.get("HST"), "Pacific/Honolulu"); assertEquals(ids.get("ACT"), "Australia/Darwin"); assertEquals(ids.get("AET"), "Australia/Sydney"); assertEquals(ids.get("AGT"), "America/Argentina/Buenos_Aires"); @@ -129,7 +129,7 @@ public void test_constant_OLD_IDS_POST_2005() { } @Test(expectedExceptions=UnsupportedOperationException.class) - public void test_constant_OLD_IDS_POST_2005_immutable() { + public void test_constant_OLD_IDS_POST_2024b_immutable() { Map ids = ZoneId.SHORT_IDS; ids.clear(); } diff --git a/test/jdk/java/util/TimeZone/OldIDMappingTest.java b/test/jdk/java/util/TimeZone/OldIDMappingTest.java index 8436080b0416f..9cc5acb87ff2f 100644 --- a/test/jdk/java/util/TimeZone/OldIDMappingTest.java +++ b/test/jdk/java/util/TimeZone/OldIDMappingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ public class OldIDMappingTest { // Add known new mappings newmap.put("EST", "EST"); newmap.put("MST", "MST"); - newmap.put("HST", "HST"); } public static void main(String[] args) { diff --git a/test/jdk/java/util/TimeZone/TimeZoneData/VERSION b/test/jdk/java/util/TimeZone/TimeZoneData/VERSION index bf027918ce734..f40be22e9abc1 100644 --- a/test/jdk/java/util/TimeZone/TimeZoneData/VERSION +++ b/test/jdk/java/util/TimeZone/TimeZoneData/VERSION @@ -1 +1 @@ -tzdata2024a +tzdata2024b diff --git a/test/jdk/java/util/TimeZone/TimeZoneData/aliases.txt b/test/jdk/java/util/TimeZone/TimeZoneData/aliases.txt index 82bad17c55320..3217f68b82578 100644 --- a/test/jdk/java/util/TimeZone/TimeZoneData/aliases.txt +++ b/test/jdk/java/util/TimeZone/TimeZoneData/aliases.txt @@ -15,6 +15,8 @@ Link America/Rio_Branco Brazil/Acre #= America/Porto_Acre Link America/Noronha Brazil/DeNoronha Link America/Sao_Paulo Brazil/East Link America/Manaus Brazil/West +Link Europe/Brussels CET +Link America/Chicago CST6CDT Link America/Halifax Canada/Atlantic Link America/Winnipeg Canada/Central Link America/Toronto Canada/Eastern @@ -26,6 +28,9 @@ Link America/Whitehorse Canada/Yukon Link America/Santiago Chile/Continental Link Pacific/Easter Chile/EasterIsland Link America/Havana Cuba +Link Europe/Athens EET +Link America/Panama EST +Link America/New_York EST5EDT Link Africa/Cairo Egypt Link Europe/Dublin Eire Link Etc/GMT Etc/GMT+0 @@ -49,6 +54,9 @@ Link America/Jamaica Jamaica Link Asia/Tokyo Japan Link Pacific/Kwajalein Kwajalein Link Africa/Tripoli Libya +Link Europe/Brussels MET +Link America/Phoenix MST +Link America/Denver MST7MDT Link America/Tijuana Mexico/BajaNorte Link America/Mazatlan Mexico/BajaSur Link America/Mexico_City Mexico/General @@ -212,6 +220,7 @@ Link America/Denver America/Shiprock Link America/Toronto America/Thunder_Bay Link America/Edmonton America/Yellowknife Link Pacific/Auckland Antarctica/South_Pole +Link Asia/Ulaanbaatar Asia/Choibalsan Link Asia/Shanghai Asia/Chongqing Link Asia/Shanghai Asia/Harbin Link Asia/Urumqi Asia/Kashgar @@ -226,6 +235,7 @@ Link Europe/Kyiv Europe/Zaporozhye Link Pacific/Kanton Pacific/Enderbury Link Pacific/Honolulu Pacific/Johnston Link Pacific/Port_Moresby Pacific/Yap +Link Europe/Lisbon WET Link Africa/Nairobi Africa/Asmera #= Africa/Asmara Link America/Nuuk America/Godthab Link Asia/Ashgabat Asia/Ashkhabad @@ -243,5 +253,7 @@ Link Asia/Ulaanbaatar Asia/Ulan_Bator Link Atlantic/Faroe Atlantic/Faeroe Link Europe/Kyiv Europe/Kiev Link Asia/Nicosia Europe/Nicosia +Link Pacific/Honolulu HST +Link America/Los_Angeles PST8PDT Link Pacific/Guadalcanal Pacific/Ponape #= Pacific/Pohnpei Link Pacific/Port_Moresby Pacific/Truk #= Pacific/Chuuk diff --git a/test/jdk/java/util/TimeZone/TimeZoneData/displaynames.txt b/test/jdk/java/util/TimeZone/TimeZoneData/displaynames.txt index 2bcccf8f88005..e7b6ea8bf3cb7 100644 --- a/test/jdk/java/util/TimeZone/TimeZoneData/displaynames.txt +++ b/test/jdk/java/util/TimeZone/TimeZoneData/displaynames.txt @@ -122,11 +122,6 @@ Australia/Lindeman AEST AEDT Australia/Melbourne AEST AEDT Australia/Perth AWST AWDT Australia/Sydney AEST AEDT -CET CET CEST -CST6CDT CST CDT -EET EET EEST -EST EST -EST5EDT EST EDT Europe/Andorra CET CEST Europe/Athens EET EEST Europe/Belgrade CET CEST @@ -159,13 +154,7 @@ Europe/Vilnius EET EEST Europe/Volgograd MSK Europe/Warsaw CET CEST Europe/Zurich CET CEST -HST HST -MET MET MEST -MST MST -MST7MDT MST MDT -PST8PDT PST PDT Pacific/Auckland NZST NZDT Pacific/Guam ChST Pacific/Honolulu HST Pacific/Pago_Pago SST -WET WET WEST diff --git a/test/jdk/sun/util/calendar/zi/TestZoneInfo310.java b/test/jdk/sun/util/calendar/zi/TestZoneInfo310.java index 1ac4b01f1456c..0b6570b74dc73 100644 --- a/test/jdk/sun/util/calendar/zi/TestZoneInfo310.java +++ b/test/jdk/sun/util/calendar/zi/TestZoneInfo310.java @@ -280,5 +280,4 @@ private static ZoneInfoOld toZoneInfoOld(TimeZone tz) throws Exception { willGMTOffsetChange.getBoolean(tz)); } - } diff --git a/test/jdk/sun/util/calendar/zi/ZoneInfoOld.java b/test/jdk/sun/util/calendar/zi/ZoneInfoOld.java index 40f9cb9056cc9..2219814f8eadc 100644 --- a/test/jdk/sun/util/calendar/zi/ZoneInfoOld.java +++ b/test/jdk/sun/util/calendar/zi/ZoneInfoOld.java @@ -93,9 +93,9 @@ public class ZoneInfoOld extends TimeZone { } // IDs having conflicting data between Olson and JDK 1.1 - static final String[] conflictingIDs = { - "EST", "MST", "HST" - }; + static final Map conflictingIDs = Map.of( + "EST", "America/Panama", + "MST", "America/Phoenix"); private static final CalendarSystem gcal = CalendarSystem.getGregorianCalendar(); @@ -843,10 +843,8 @@ public synchronized static Map getAliasTable() { aliases = ZoneInfoFile.getZoneAliases(); if (aliases != null) { if (!USE_OLDMAPPING) { - // Remove the conflicting IDs from the alias table. - for (String key : conflictingIDs) { - aliases.remove(key); - } + // Replace old mappings from `jdk11_backward` + aliases.putAll(conflictingIDs); } aliasTable = new SoftReference>(aliases); } diff --git a/test/jdk/sun/util/resources/TimeZone/Bug4848242.java b/test/jdk/sun/util/resources/TimeZone/Bug4848242.java index 99f66340316d9..68962f135d0d3 100644 --- a/test/jdk/sun/util/resources/TimeZone/Bug4848242.java +++ b/test/jdk/sun/util/resources/TimeZone/Bug4848242.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ public class Bug4848242 { public static void main(String[] args) { - getTzInfo("de", "DE"); getTzInfo("es", "ES"); getTzInfo("fr", "FR"); getTzInfo("it", "IT"); @@ -46,7 +45,6 @@ static void getTzInfo(String langName, String locName) { Locale tzLocale = Locale.of(langName, locName); TimeZone euroTz = TimeZone.getTimeZone("MET"); - System.out.println("Locale is " + langName + "_" + locName); if ( euroTz.getID().equalsIgnoreCase("GMT") ) { @@ -56,13 +54,13 @@ static void getTzInfo(String langName, String locName) // get the timezone info System.out.println(euroTz.getDisplayName(false, TimeZone.SHORT, tzLocale)); - if(!euroTz.getDisplayName(false, TimeZone.SHORT, tzLocale).equals("MET")) - throw new RuntimeException("Timezone name is incorrect (should be MET)\n"); + if (!euroTz.getDisplayName(false, TimeZone.SHORT, tzLocale).equals("CET")) + throw new RuntimeException("Timezone name is incorrect (should be CET)\n"); System.out.println(euroTz.getDisplayName(false, TimeZone.LONG, tzLocale)); System.out.println(euroTz.getDisplayName(true, TimeZone.SHORT, tzLocale)); - if(!euroTz.getDisplayName(true, TimeZone.SHORT, tzLocale).equals("MEST")) - throw new RuntimeException("Summer timezone name is incorrect (should be MEST)\n"); + if (!euroTz.getDisplayName(true, TimeZone.SHORT, tzLocale).equals("CEST")) + throw new RuntimeException("Summer timezone name is incorrect (should be CEST)\n"); System.out.println(euroTz.getDisplayName(true, TimeZone.LONG, tzLocale) + "\n"); } From c81aa7551c37cc025c9054db08472b8abb2cbcb5 Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Wed, 16 Oct 2024 10:17:47 +0000 Subject: [PATCH 087/118] 8331051: Add an `@since` checker test for `java.base` module Reviewed-by: jlahoda, jjg --- test/jdk/TEST.groups | 9 +- test/jdk/tools/sincechecker/SinceChecker.java | 948 ++++++++++++++++++ .../java_base/CheckSince_javaBase.java | 34 + 3 files changed, 989 insertions(+), 2 deletions(-) create mode 100644 test/jdk/tools/sincechecker/SinceChecker.java create mode 100644 test/jdk/tools/sincechecker/modules/java_base/CheckSince_javaBase.java diff --git a/test/jdk/TEST.groups b/test/jdk/TEST.groups index d51fcec733b3c..e7ee8990f94fb 100644 --- a/test/jdk/TEST.groups +++ b/test/jdk/TEST.groups @@ -1,4 +1,4 @@ -# Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -91,7 +91,8 @@ tier3 = \ :jdk_svc \ -:jdk_svc_sanity \ -:svc_tools \ - :jdk_jpackage + :jdk_jpackage \ + :jdk_since_checks # Everything not in other tiers tier4 = \ @@ -666,3 +667,7 @@ jdk_containers_extended = \ jdk_core_no_security = \ :jdk_core \ -:jdk_security + +# Set of tests for `@since` checks in source code documentation +jdk_since_checks = \ + tools/sincechecker/modules/java_base/CheckSince_javaBase.java diff --git a/test/jdk/tools/sincechecker/SinceChecker.java b/test/jdk/tools/sincechecker/SinceChecker.java new file mode 100644 index 0000000000000..860db6a2798fd --- /dev/null +++ b/test/jdk/tools/sincechecker/SinceChecker.java @@ -0,0 +1,948 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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.File; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.lang.Runtime.Version; +import java.net.URI; +import java.nio.file.*; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import javax.lang.model.element.*; +import javax.lang.model.util.ElementFilter; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; +import javax.tools.*; +import javax.tools.JavaFileManager.Location; +import com.sun.source.tree.*; +import com.sun.source.util.JavacTask; +import com.sun.source.util.TreePathScanner; +import com.sun.source.util.Trees; +import com.sun.tools.javac.api.JavacTaskImpl; +import com.sun.tools.javac.code.Flags; +import com.sun.tools.javac.code.Symbol; +import com.sun.tools.javac.util.Pair; +import jtreg.SkippedException; + +/* +This checker checks the values of the `@since` tag found in the documentation comment for an element against +the release in which the element first appeared. +The source code containing the documentation comments is read from `src.zip` in the release of JDK used to run the test. +The releases used to determine the expected value of `@since` tags are taken from the historical data built into `javac`. + +The `@since` checker works as a two-step process: +In the first step, we process JDKs 9-current, only classfiles, + producing a map ` => ``. + - "version(s)", because we handle versioning of Preview API, so there may be two versions + (we use a class with two fields for preview and stable), + one when it was introduced as a preview, and one when it went out of preview. More on that below. + - For each Element, we compute the unique ID, look into the map, and if there's nothing, + record the current version as the originating version. + - At the end of this step we have a map of the Real since values + +In the second step, we look at "effective" `@since` tags in the mainline sources, from `src.zip` + (if the test run doesn't have it, we throw a `jtreg.SkippedException`) + - We only check the specific MODULE whose name was passed as an argument in the test. + In that module, we look for unqualified exports and test those packages. + - The `@since` checker verifies that for every API element, the real since value and + the effective since value are the same, and reports an error if they are not. + +Important note : We only check code written since JDK 9 as the releases used to determine the expected value + of @since tags are taken from the historical data built into javac which only goes back that far + +note on rules for Real and effective `@since: + +Real since value of an API element is computed as the oldest release in which the given API element was introduced. +That is: +- for modules, packages, classes and interfaces, the release in which the element with the given qualified name was introduced +- for constructors, the release in which the constructor with the given VM descriptor was introduced +- for methods and fields, the release in which the given method or field with the given VM descriptor became a member + of its enclosing class or interface, whether direct or inherited + +Effective since value of an API element is computed as follows: +- if the given element has a @since tag in its javadoc, it is used +- in all other cases, return the effective since value of the enclosing element + + +Special Handling for preview method, as per JEP 12: +- When an element is still marked as preview, the `@since` should be the first JDK release where the element was added. +- If the element is no longer marked as preview, the `@since` should be the first JDK release where it was no longer preview. + +note on legacy preview: Until JDK 14, the preview APIs were not marked in any machine-understandable way. + It was deprecated, and had a comment in the javadoc. + and the use of `@PreviewFeature` only became standard in JDK 17. + So the checker has an explicit knowledge of these preview elements. + +note: The `` for methods looks like + `method: .()`. +it is somewhat inspired from the VM Method Descriptors. But we use the erased return so that methods +that were later generified remain the same. + +usage: the checker is run from a module specific test + `@run main SinceChecker [--exclude package1,package2 | --exclude package1 package2]` +*/ + +public class SinceChecker { + private final Map> LEGACY_PREVIEW_METHODS = new HashMap<>(); + private final Map classDictionary = new HashMap<>(); + private final JavaCompiler tool; + private int errorCount = 0; + + // packages to skip during the test + private static final Set EXCLUDE_LIST = new HashSet<>(); + + public static class IntroducedIn { + public String introducedPreview; + public String introducedStable; + } + + public static void main(String[] args) throws Exception { + if (args.length == 0) { + throw new IllegalArgumentException("Test module not specified"); + } + String moduleName = args[0]; + boolean excludeFlag = false; + + for (int i = 1; i < args.length; i++) { + if ("--exclude".equals(args[i])) { + excludeFlag = true; + continue; + } + + if (excludeFlag) { + if (args[i].contains(",")) { + EXCLUDE_LIST.addAll(Arrays.asList(args[i].split(","))); + } else { + EXCLUDE_LIST.add(args[i]); + } + } + } + + SinceChecker sinceCheckerTestHelper = new SinceChecker(moduleName); + sinceCheckerTestHelper.checkModule(moduleName); + } + + private void error(String message) { + System.err.println(message); + errorCount++; + } + + private SinceChecker(String moduleName) throws IOException { + tool = ToolProvider.getSystemJavaCompiler(); + for (int i = 9; i <= Runtime.version().feature(); i++) { + DiagnosticListener noErrors = d -> { + if (!d.getCode().equals("compiler.err.module.not.found")) { + error(d.getMessage(null)); + } + }; + JavacTask ct = (JavacTask) tool.getTask(null, + null, + noErrors, + List.of("--add-modules", moduleName, "--release", String.valueOf(i)), + null, + Collections.singletonList(SimpleJavaFileObject.forSource(URI.create("myfo:/Test.java"), ""))); + ct.analyze(); + + String version = String.valueOf(i); + Elements elements = ct.getElements(); + elements.getModuleElement("java.base"); // forces module graph to be instantiated + elements.getAllModuleElements().forEach(me -> + processModuleElement(me, version, ct)); + } + } + + private void processModuleElement(ModuleElement moduleElement, String releaseVersion, JavacTask ct) { + processElement(moduleElement, moduleElement, ct.getTypes(), releaseVersion); + for (ModuleElement.ExportsDirective ed : ElementFilter.exportsIn(moduleElement.getDirectives())) { + if (ed.getTargetModules() == null) { + processPackageElement(ed.getPackage(), releaseVersion, ct); + } + } + } + + private void processPackageElement(PackageElement pe, String releaseVersion, JavacTask ct) { + processElement(pe, pe, ct.getTypes(), releaseVersion); + List typeElements = ElementFilter.typesIn(pe.getEnclosedElements()); + for (TypeElement te : typeElements) { + processClassElement(te, releaseVersion, ct.getTypes(), ct.getElements()); + } + } + + /// JDK documentation only contains public and protected declarations + private boolean isDocumented(Element te) { + Set mod = te.getModifiers(); + return mod.contains(Modifier.PUBLIC) || mod.contains(Modifier.PROTECTED); + } + + private boolean isMember(Element e) { + var kind = e.getKind(); + return kind.isField() || switch (kind) { + case METHOD, CONSTRUCTOR -> true; + default -> false; + }; + } + + private void processClassElement(TypeElement te, String version, Types types, Elements elements) { + if (!isDocumented(te)) { + return; + } + processElement(te.getEnclosingElement(), te, types, version); + elements.getAllMembers(te).stream() + .filter(this::isDocumented) + .filter(this::isMember) + .forEach(element -> processElement(te, element, types, version)); + te.getEnclosedElements().stream() + .filter(element -> element.getKind().isDeclaredType()) + .map(TypeElement.class::cast) + .forEach(nestedClass -> processClassElement(nestedClass, version, types, elements)); + } + + private void processElement(Element explicitOwner, Element element, Types types, String version) { + String uniqueId = getElementName(explicitOwner, element, types); + IntroducedIn introduced = classDictionary.computeIfAbsent(uniqueId, _ -> new IntroducedIn()); + if (isPreview(element, uniqueId, version)) { + if (introduced.introducedPreview == null) { + introduced.introducedPreview = version; + } + } else { + if (introduced.introducedStable == null) { + introduced.introducedStable = version; + } + } + } + + private boolean isPreview(Element el, String uniqueId, String currentVersion) { + while (el != null) { + Symbol s = (Symbol) el; + if ((s.flags() & Flags.PREVIEW_API) != 0) { + return true; + } + el = el.getEnclosingElement(); + } + + return LEGACY_PREVIEW_METHODS.getOrDefault(currentVersion, Set.of()) + .contains(uniqueId); + } + + private void checkModule(String moduleName) throws Exception { + Path home = Paths.get(System.getProperty("java.home")); + Path srcZip = home.resolve("lib").resolve("src.zip"); + if (Files.notExists(srcZip)) { + //possibly running over an exploded JDK build, attempt to find a + //co-located full JDK image with src.zip: + Path testJdk = Paths.get(System.getProperty("test.jdk")); + srcZip = testJdk.getParent().resolve("images").resolve("jdk").resolve("lib").resolve("src.zip"); + } + if (!Files.isReadable(srcZip)) { + throw new SkippedException("Skipping Test because src.zip wasn't found or couldn't be read"); + } + URI uri = URI.create("jar:" + srcZip.toUri()); + try (FileSystem zipFO = FileSystems.newFileSystem(uri, Collections.emptyMap())) { + Path root = zipFO.getRootDirectories().iterator().next(); + Path moduleDirectory = root.resolve(moduleName); + try (StandardJavaFileManager fm = + tool.getStandardFileManager(null, null, null)) { + JavacTask ct = (JavacTask) tool.getTask(null, + fm, + null, + List.of("--add-modules", moduleName, "-d", "."), + null, + Collections.singletonList(SimpleJavaFileObject.forSource(URI.create("myfo:/Test.java"), ""))); + ct.analyze(); + Elements elements = ct.getElements(); + elements.getModuleElement("java.base"); + try (EffectiveSourceSinceHelper javadocHelper = EffectiveSourceSinceHelper.create(ct, List.of(root), this)) { + processModuleCheck(elements.getModuleElement(moduleName), ct, moduleDirectory, javadocHelper); + } catch (Exception e) { + e.printStackTrace(); + error("Initiating javadocHelper Failed " + e); + } + if (errorCount > 0) { + throw new Exception("The `@since` checker found " + errorCount + " problems"); + } + } + } + } + + private boolean isExcluded(ModuleElement.ExportsDirective ed ){ + return EXCLUDE_LIST.stream().anyMatch(excludePackage -> + ed.getPackage().toString().equals(excludePackage) || + ed.getPackage().toString().startsWith(excludePackage + ".")); + } + + private void processModuleCheck(ModuleElement moduleElement, JavacTask ct, Path moduleDirectory, EffectiveSourceSinceHelper javadocHelper) { + if (moduleElement == null) { + error("Module element: was null because `elements.getModuleElement(moduleName)` returns null." + + "fixes are needed for this Module"); + } + String moduleVersion = getModuleVersionFromFile(moduleDirectory); + checkModuleOrPackage(javadocHelper, moduleVersion, moduleElement, ct, "Module: "); + for (ModuleElement.ExportsDirective ed : ElementFilter.exportsIn(moduleElement.getDirectives())) { + if (ed.getTargetModules() == null) { + String packageVersion = getPackageVersionFromFile(moduleDirectory, ed); + if (packageVersion != null && !isExcluded(ed)) { + checkModuleOrPackage(javadocHelper, packageVersion, ed.getPackage(), ct, "Package: "); + analyzePackageCheck(ed.getPackage(), ct, javadocHelper); + } // Skip the package if packageVersion is null + } + } + } + + private void checkModuleOrPackage(EffectiveSourceSinceHelper javadocHelper, String moduleVersion, Element moduleElement, JavacTask ct, String elementCategory) { + String id = getElementName(moduleElement, moduleElement, ct.getTypes()); + var elementInfo = classDictionary.get(id); + if (elementInfo == null) { + error("Element :" + id + " was not mapped"); + return; + } + String version = elementInfo.introducedStable; + if (moduleVersion == null) { + error("Unable to retrieve `@since` for " + elementCategory + id); + } else { + String position = javadocHelper.getElementPosition(id); + checkEquals(position, moduleVersion, version, id); + } + } + + private String getModuleVersionFromFile(Path moduleDirectory) { + Path moduleInfoFile = moduleDirectory.resolve("module-info.java"); + String version = null; + if (Files.exists(moduleInfoFile)) { + try { + String moduleInfoContent = Files.readString(moduleInfoFile); + var extractedVersion = extractSinceVersionFromText(moduleInfoContent); + if (extractedVersion != null) { + version = extractedVersion.toString(); + } + } catch (IOException e) { + error("module-info.java not found or couldn't be opened AND this module has no unqualified exports"); + } + } + return version; + } + + private String getPackageVersionFromFile(Path moduleDirectory, ModuleElement.ExportsDirective ed) { + Path pkgInfo = moduleDirectory.resolve(ed.getPackage() + .getQualifiedName() + .toString() + .replace(".", File.separator) + ) + .resolve("package-info.java"); + + if (!Files.exists(pkgInfo)) { + return null; // Skip if the file does not exist + } + + String packageTopVersion = null; + try { + String packageContent = Files.readString(pkgInfo); + var extractedVersion = extractSinceVersionFromText(packageContent); + if (extractedVersion != null) { + packageTopVersion = extractedVersion.toString(); + } else { + error(ed.getPackage().getQualifiedName() + ": package-info.java exists but doesn't contain @since"); + } + } catch (IOException e) { + error(ed.getPackage().getQualifiedName() + ": package-info.java couldn't be opened"); + } + return packageTopVersion; + } + + private void analyzePackageCheck(PackageElement pe, JavacTask ct, EffectiveSourceSinceHelper javadocHelper) { + List typeElements = ElementFilter.typesIn(pe.getEnclosedElements()); + for (TypeElement te : typeElements) { + analyzeClassCheck(te, null, javadocHelper, ct.getTypes(), ct.getElements()); + } + } + + private boolean isNotCommonRecordMethod(TypeElement te, Element element, Types types) { + var isRecord = te.getKind() == ElementKind.RECORD; + if (!isRecord) { + return true; + } + String uniqueId = getElementName(te, element, types); + boolean isCommonMethod = uniqueId.endsWith(".toString()") || + uniqueId.endsWith(".hashCode()") || + uniqueId.endsWith(".equals(java.lang.Object)"); + if (isCommonMethod) { + return false; + } + for (var parameter : te.getEnclosedElements()) { + if (parameter.getKind() == ElementKind.RECORD_COMPONENT) { + if (uniqueId.endsWith(String.format("%s.%s()", te.getSimpleName(), parameter.getSimpleName().toString()))) { + return false; + } + } + } + return true; + } + + private void analyzeClassCheck(TypeElement te, String version, EffectiveSourceSinceHelper javadocHelper, + Types types, Elements elementUtils) { + String currentjdkVersion = String.valueOf(Runtime.version().feature()); + if (!isDocumented(te)) { + return; + } + checkElement(te.getEnclosingElement(), te, types, javadocHelper, version, elementUtils); + te.getEnclosedElements().stream().filter(this::isDocumented) + .filter(this::isMember) + .filter(element -> isNotCommonRecordMethod(te, element, types)) + .forEach(element -> checkElement(te, element, types, javadocHelper, version, elementUtils)); + te.getEnclosedElements().stream() + .filter(element -> element.getKind().isDeclaredType()) + .map(TypeElement.class::cast) + .forEach(nestedClass -> analyzeClassCheck(nestedClass, currentjdkVersion, javadocHelper, types, elementUtils)); + } + + private void checkElement(Element explicitOwner, Element element, Types types, + EffectiveSourceSinceHelper javadocHelper, String currentVersion, Elements elementUtils) { + String uniqueId = getElementName(explicitOwner, element, types); + + if (element.getKind() == ElementKind.METHOD && + element.getEnclosingElement().getKind() == ElementKind.ENUM && + (uniqueId.contains(".values()") || uniqueId.contains(".valueOf(java.lang.String)"))) { + //mandated enum type methods + return; + } + String sinceVersion = null; + var effectiveSince = javadocHelper.effectiveSinceVersion(explicitOwner, element, types, elementUtils); + if (effectiveSince == null) { + // Skip the element if the java file doesn't exist in src.zip + return; + } + sinceVersion = effectiveSince.toString(); + IntroducedIn mappedVersion = classDictionary.get(uniqueId); + if (mappedVersion == null) { + error("Element: " + uniqueId + " was not mapped"); + return; + } + String realMappedVersion = null; + try { + realMappedVersion = isPreview(element, uniqueId, currentVersion) ? + mappedVersion.introducedPreview : + mappedVersion.introducedStable; + } catch (Exception e) { + error("For element " + element + "mappedVersion" + mappedVersion + " is null " + e); + } + String position = javadocHelper.getElementPosition(uniqueId); + checkEquals(position, sinceVersion, realMappedVersion, uniqueId); + } + + private Version extractSinceVersionFromText(String documentation) { + Pattern pattern = Pattern.compile("@since\\s+(\\d+(?:\\.\\d+)?)"); + Matcher matcher = pattern.matcher(documentation); + if (matcher.find()) { + String versionString = matcher.group(1); + try { + if (versionString.equals("1.0")) { + versionString = "1"; //ended up being necessary + } else if (versionString.startsWith("1.")) { + versionString = versionString.substring(2); + } + return Version.parse(versionString); + } catch (NumberFormatException ex) { + error("`@since` value that cannot be parsed: " + versionString); + return null; + } + } else { + return null; + } + } + + private void checkEquals(String prefix, String sinceVersion, String mappedVersion, String name) { + if (sinceVersion == null || mappedVersion == null) { + error(name + ": NULL value for either real or effective `@since` . real/mapped version is=" + + mappedVersion + " while the `@since` in the source code is= " + sinceVersion); + return; + } + if (Integer.parseInt(sinceVersion) < 9) { + sinceVersion = "9"; + } + if (!sinceVersion.equals(mappedVersion)) { + String message = getWrongSinceMessage(prefix, sinceVersion, mappedVersion, name); + error(message); + } + } + private static String getWrongSinceMessage(String prefix, String sinceVersion, String mappedVersion, String elementSimpleName) { + String message; + if (mappedVersion.equals("9")) { + message = elementSimpleName + ": `@since` version is " + sinceVersion + " but the element exists before JDK 10"; + } else { + message = elementSimpleName + ": `@since` version: " + sinceVersion + "; should be: " + mappedVersion; + } + return prefix + message; + } + + private static String getElementName(Element owner, Element element, Types types) { + String prefix = ""; + String suffix = ""; + ElementKind kind = element.getKind(); + if (kind.isField()) { + TypeElement te = (TypeElement) owner; + prefix = "field"; + suffix = ": " + te.getQualifiedName() + ":" + element.getSimpleName(); + } else if (kind == ElementKind.METHOD || kind == ElementKind.CONSTRUCTOR) { + prefix = "method"; + TypeElement te = (TypeElement) owner; + ExecutableElement executableElement = (ExecutableElement) element; + String returnType = types.erasure(executableElement.getReturnType()).toString(); + String methodName = executableElement.getSimpleName().toString(); + String descriptor = executableElement.getParameters().stream() + .map(p -> types.erasure(p.asType()).toString()) + .collect(Collectors.joining(",", "(", ")")); + suffix = ": " + returnType + " " + te.getQualifiedName() + "." + methodName + descriptor; + } else if (kind.isDeclaredType()) { + if (kind.isClass()) { + prefix = "class"; + } else if (kind.isInterface()) { + prefix = "interface"; + } + suffix = ": " + ((TypeElement) element).getQualifiedName(); + } else if (kind == ElementKind.PACKAGE) { + prefix = "package"; + suffix = ": " + ((PackageElement) element).getQualifiedName(); + } else if (kind == ElementKind.MODULE) { + prefix = "module"; + suffix = ": " + ((ModuleElement) element).getQualifiedName(); + } + return prefix + suffix; + } + + //these were preview in before the introduction of the @PreviewFeature + { + LEGACY_PREVIEW_METHODS.put("9", Set.of( + "module: jdk.nio.mapmode", + "module: java.transaction.xa", + "module: jdk.unsupported.desktop", + "module: jdk.jpackage", + "module: java.net.http" + )); + LEGACY_PREVIEW_METHODS.put("10", Set.of( + "module: jdk.nio.mapmode", + "module: java.transaction.xa", + "module: java.net.http", + "module: jdk.unsupported.desktop", + "module: jdk.jpackage" + )); + LEGACY_PREVIEW_METHODS.put("11", Set.of( + "module: jdk.nio.mapmode", + "module: jdk.jpackage" + )); + LEGACY_PREVIEW_METHODS.put("12", Set.of( + "module: jdk.nio.mapmode", + "module: jdk.jpackage", + "method: com.sun.source.tree.ExpressionTree com.sun.source.tree.BreakTree.getValue()", + "method: java.util.List com.sun.source.tree.CaseTree.getExpressions()", + "method: com.sun.source.tree.Tree com.sun.source.tree.CaseTree.getBody()", + "method: com.sun.source.tree.CaseTree.CaseKind com.sun.source.tree.CaseTree.getCaseKind()", + "class: com.sun.source.tree.CaseTree.CaseKind", + "field: com.sun.source.tree.CaseTree.CaseKind:STATEMENT", + "field: com.sun.source.tree.CaseTree.CaseKind:RULE", + "field: com.sun.source.tree.Tree.Kind:SWITCH_EXPRESSION", + "interface: com.sun.source.tree.SwitchExpressionTree", + "method: com.sun.source.tree.ExpressionTree com.sun.source.tree.SwitchExpressionTree.getExpression()", + "method: java.util.List com.sun.source.tree.SwitchExpressionTree.getCases()", + "method: java.lang.Object com.sun.source.tree.TreeVisitor.visitSwitchExpression(com.sun.source.tree.SwitchExpressionTree,java.lang.Object)", + "method: java.lang.Object com.sun.source.util.TreeScanner.visitSwitchExpression(com.sun.source.tree.SwitchExpressionTree,java.lang.Object)", + "method: java.lang.Object com.sun.source.util.SimpleTreeVisitor.visitSwitchExpression(com.sun.source.tree.SwitchExpressionTree,java.lang.Object)" + )); + + LEGACY_PREVIEW_METHODS.put("13", Set.of( + "module: jdk.nio.mapmode", + "module: jdk.jpackage", + "method: java.util.List com.sun.source.tree.CaseTree.getExpressions()", + "method: com.sun.source.tree.Tree com.sun.source.tree.CaseTree.getBody()", + "method: com.sun.source.tree.CaseTree.CaseKind com.sun.source.tree.CaseTree.getCaseKind()", + "class: com.sun.source.tree.CaseTree.CaseKind", + "field: com.sun.source.tree.CaseTree.CaseKind:STATEMENT", + "field: com.sun.source.tree.CaseTree.CaseKind:RULE", + "field: com.sun.source.tree.Tree.Kind:SWITCH_EXPRESSION", + "interface: com.sun.source.tree.SwitchExpressionTree", + "method: com.sun.source.tree.ExpressionTree com.sun.source.tree.SwitchExpressionTree.getExpression()", + "method: java.util.List com.sun.source.tree.SwitchExpressionTree.getCases()", + "method: java.lang.Object com.sun.source.tree.TreeVisitor.visitSwitchExpression(com.sun.source.tree.SwitchExpressionTree,java.lang.Object)", + "method: java.lang.Object com.sun.source.util.TreeScanner.visitSwitchExpression(com.sun.source.tree.SwitchExpressionTree,java.lang.Object)", + "method: java.lang.Object com.sun.source.util.SimpleTreeVisitor.visitSwitchExpression(com.sun.source.tree.SwitchExpressionTree,java.lang.Object)", + "method: java.lang.String java.lang.String.stripIndent()", + "method: java.lang.String java.lang.String.translateEscapes()", + "method: java.lang.String java.lang.String.formatted(java.lang.Object[])", + "class: javax.swing.plaf.basic.motif.MotifLookAndFeel", + "field: com.sun.source.tree.Tree.Kind:YIELD", + "interface: com.sun.source.tree.YieldTree", + "method: com.sun.source.tree.ExpressionTree com.sun.source.tree.YieldTree.getValue()", + "method: java.lang.Object com.sun.source.tree.TreeVisitor.visitYield(com.sun.source.tree.YieldTree,java.lang.Object)", + "method: java.lang.Object com.sun.source.util.SimpleTreeVisitor.visitYield(com.sun.source.tree.YieldTree,java.lang.Object)", + "method: java.lang.Object com.sun.source.util.TreeScanner.visitYield(com.sun.source.tree.YieldTree,java.lang.Object)" + )); + + LEGACY_PREVIEW_METHODS.put("14", Set.of( + "module: jdk.jpackage", + "class: javax.swing.plaf.basic.motif.MotifLookAndFeel", + "field: jdk.jshell.Snippet.SubKind:RECORD_SUBKIND", + "class: javax.lang.model.element.RecordComponentElement", + "method: javax.lang.model.type.TypeMirror javax.lang.model.element.RecordComponentElement.asType()", + "method: java.lang.Object javax.lang.model.element.ElementVisitor.visitRecordComponent(javax.lang.model.element.RecordComponentElement,java.lang.Object)", + "class: javax.lang.model.util.ElementScanner14", + "class: javax.lang.model.util.AbstractElementVisitor14", + "class: javax.lang.model.util.SimpleElementVisitor14", + "method: java.lang.Object javax.lang.model.util.ElementKindVisitor6.visitTypeAsRecord(javax.lang.model.element.TypeElement,java.lang.Object)", + "class: javax.lang.model.util.ElementKindVisitor14", + "method: javax.lang.model.element.RecordComponentElement javax.lang.model.util.Elements.recordComponentFor(javax.lang.model.element.ExecutableElement)", + "method: java.util.List javax.lang.model.util.ElementFilter.recordComponentsIn(java.lang.Iterable)", + "method: java.util.Set javax.lang.model.util.ElementFilter.recordComponentsIn(java.util.Set)", + "method: java.util.List javax.lang.model.element.TypeElement.getRecordComponents()", + "field: javax.lang.model.element.ElementKind:RECORD", + "field: javax.lang.model.element.ElementKind:RECORD_COMPONENT", + "field: javax.lang.model.element.ElementKind:BINDING_VARIABLE", + "field: com.sun.source.tree.Tree.Kind:RECORD", + "field: sun.reflect.annotation.TypeAnnotation.TypeAnnotationTarget:RECORD_COMPONENT", + "class: java.lang.reflect.RecordComponent", + "class: java.lang.runtime.ObjectMethods", + "field: java.lang.annotation.ElementType:RECORD_COMPONENT", + "method: boolean java.lang.Class.isRecord()", + "method: java.lang.reflect.RecordComponent[] java.lang.Class.getRecordComponents()", + "class: java.lang.Record", + "interface: com.sun.source.tree.PatternTree", + "field: com.sun.source.tree.Tree.Kind:BINDING_PATTERN", + "method: com.sun.source.tree.PatternTree com.sun.source.tree.InstanceOfTree.getPattern()", + "interface: com.sun.source.tree.BindingPatternTree", + "method: java.lang.Object com.sun.source.tree.TreeVisitor.visitBindingPattern(com.sun.source.tree.BindingPatternTree,java.lang.Object)" + )); + + LEGACY_PREVIEW_METHODS.put("15", Set.of( + "module: jdk.jpackage", + "field: jdk.jshell.Snippet.SubKind:RECORD_SUBKIND", + "class: javax.lang.model.element.RecordComponentElement", + "method: javax.lang.model.type.TypeMirror javax.lang.model.element.RecordComponentElement.asType()", + "method: java.lang.Object javax.lang.model.element.ElementVisitor.visitRecordComponent(javax.lang.model.element.RecordComponentElement,java.lang.Object)", + "class: javax.lang.model.util.ElementScanner14", + "class: javax.lang.model.util.AbstractElementVisitor14", + "class: javax.lang.model.util.SimpleElementVisitor14", + "method: java.lang.Object javax.lang.model.util.ElementKindVisitor6.visitTypeAsRecord(javax.lang.model.element.TypeElement,java.lang.Object)", + "class: javax.lang.model.util.ElementKindVisitor14", + "method: javax.lang.model.element.RecordComponentElement javax.lang.model.util.Elements.recordComponentFor(javax.lang.model.element.ExecutableElement)", + "method: java.util.List javax.lang.model.util.ElementFilter.recordComponentsIn(java.lang.Iterable)", + "method: java.util.Set javax.lang.model.util.ElementFilter.recordComponentsIn(java.util.Set)", + "method: java.util.List javax.lang.model.element.TypeElement.getRecordComponents()", + "field: javax.lang.model.element.ElementKind:RECORD", + "field: javax.lang.model.element.ElementKind:RECORD_COMPONENT", + "field: javax.lang.model.element.ElementKind:BINDING_VARIABLE", + "field: com.sun.source.tree.Tree.Kind:RECORD", + "field: sun.reflect.annotation.TypeAnnotation.TypeAnnotationTarget:RECORD_COMPONENT", + "class: java.lang.reflect.RecordComponent", + "class: java.lang.runtime.ObjectMethods", + "field: java.lang.annotation.ElementType:RECORD_COMPONENT", + "class: java.lang.Record", + "method: boolean java.lang.Class.isRecord()", + "method: java.lang.reflect.RecordComponent[] java.lang.Class.getRecordComponents()", + "field: javax.lang.model.element.Modifier:SEALED", + "field: javax.lang.model.element.Modifier:NON_SEALED", + "method: javax.lang.model.element.TypeElement:getPermittedSubclasses:()", + "method: java.util.List com.sun.source.tree.ClassTree.getPermitsClause()", + "method: boolean java.lang.Class.isSealed()", + "method: java.lang.constant.ClassDesc[] java.lang.Class.permittedSubclasses()", + "interface: com.sun.source.tree.PatternTree", + "field: com.sun.source.tree.Tree.Kind:BINDING_PATTERN", + "method: com.sun.source.tree.PatternTree com.sun.source.tree.InstanceOfTree.getPattern()", + "interface: com.sun.source.tree.BindingPatternTree", + "method: java.lang.Object com.sun.source.tree.TreeVisitor.visitBindingPattern(com.sun.source.tree.BindingPatternTree,java.lang.Object)" + )); + + LEGACY_PREVIEW_METHODS.put("16", Set.of( + "field: jdk.jshell.Snippet.SubKind:RECORD_SUBKIND", + "field: javax.lang.model.element.Modifier:SEALED", + "field: javax.lang.model.element.Modifier:NON_SEALED", + "method: javax.lang.model.element.TypeElement:getPermittedSubclasses:()", + "method: java.util.List com.sun.source.tree.ClassTree.getPermitsClause()", + "method: boolean java.lang.Class.isSealed()", + "method: java.lang.constant.ClassDesc[] java.lang.Class.permittedSubclasses()" + )); + + // java.lang.foreign existed since JDK 19 and wasn't annotated - went out of preview in JDK 22 + LEGACY_PREVIEW_METHODS.put("19", Set.of( + "package: java.lang.foreign" + )); + LEGACY_PREVIEW_METHODS.put("20", Set.of( + "package: java.lang.foreign" + )); + LEGACY_PREVIEW_METHODS.put("21", Set.of( + "package: java.lang.foreign" + )); + } + + /** + * Helper to find javadoc and resolve @inheritDoc and the effective since version. + */ + + private final class EffectiveSourceSinceHelper implements AutoCloseable { + private static final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + private final JavaFileManager baseFileManager; + private final StandardJavaFileManager fm; + private final Set seenLookupElements = new HashSet<>(); + private final Map signature2Source = new HashMap<>(); + private final Map signature2Location = new HashMap<>(); + + /** + * Create the helper. + * + * @param mainTask JavacTask from which the further Elements originate + * @param sourceLocations paths where source files should be searched + * @param validator enclosing class of the helper, typically the object invoking this method + * @return a EffectiveSourceSinceHelper + */ + + public static EffectiveSourceSinceHelper create(JavacTask mainTask, Collection sourceLocations, SinceChecker validator) { + StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null); + try { + fm.setLocationFromPaths(StandardLocation.MODULE_SOURCE_PATH, sourceLocations); + return validator.new EffectiveSourceSinceHelper(mainTask, fm); + } catch (IOException ex) { + try { + fm.close(); + } catch (IOException closeEx) { + ex.addSuppressed(closeEx); + } + throw new UncheckedIOException(ex); + } + } + + private EffectiveSourceSinceHelper(JavacTask mainTask, StandardJavaFileManager fm) { + this.baseFileManager = ((JavacTaskImpl) mainTask).getContext().get(JavaFileManager.class); + this.fm = fm; + } + + public Version effectiveSinceVersion(Element owner, Element element, Types typeUtils, Elements elementUtils) { + String handle = getElementName(owner, element, typeUtils); + Version since = signature2Source.get(handle); + + if (since == null) { + try { + Element lookupElement = switch (element.getKind()) { + case MODULE, PACKAGE -> element; + default -> elementUtils.getOutermostTypeElement(element); + }; + + if (lookupElement == null) + return null; + + String lookupHandle = getElementName(owner, element, typeUtils); + + if (!seenLookupElements.add(lookupHandle)) { + //we've already processed this top-level, don't try to compute + //the values again: + return null; + } + + Pair source = findSource(lookupElement, elementUtils); + + if (source == null) + return null; + + fillElementCache(source.fst, source.snd, source.fst.getTypes(), source.fst.getElements()); + since = signature2Source.get(handle); + + } catch (IOException ex) { + error("JavadocHelper failed for " + element); + } + } + + return since; + } + + private String getElementPosition(String signature) { + return signature2Location.getOrDefault(signature, ""); + } + + //where: + private void fillElementCache(JavacTask task, CompilationUnitTree cut, Types typeUtils, Elements elementUtils) { + Trees trees = Trees.instance(task); + String fileName = cut.getSourceFile().getName(); + + new TreePathScanner() { + @Override + public Void visitMethod(MethodTree node, Void p) { + handleDeclaration(node, fileName); + return null; + } + + @Override + public Void visitClass(ClassTree node, Void p) { + handleDeclaration(node, fileName); + return super.visitClass(node, p); + } + + @Override + public Void visitVariable(VariableTree node, Void p) { + handleDeclaration(node, fileName); + return null; + } + + @Override + public Void visitModule(ModuleTree node, Void p) { + handleDeclaration(node, fileName); + return null; + } + + @Override + public Void visitBlock(BlockTree node, Void p) { + return null; + } + + @Override + public Void visitPackage(PackageTree node, Void p) { + if (cut.getSourceFile().isNameCompatible("package-info", JavaFileObject.Kind.SOURCE)) { + handleDeclaration(node, fileName); + } + return super.visitPackage(node, p); + } + + private void handleDeclaration(Tree node, String fileName) { + Element currentElement = trees.getElement(getCurrentPath()); + + if (currentElement != null) { + long startPosition = trees.getSourcePositions().getStartPosition(cut, node); + long lineNumber = cut.getLineMap().getLineNumber(startPosition); + String filePathWithLineNumber = String.format("src%s:%s ", fileName, lineNumber); + + signature2Source.put(getElementName(currentElement.getEnclosingElement(), currentElement, typeUtils), computeSinceVersion(currentElement, typeUtils, elementUtils)); + signature2Location.put(getElementName(currentElement.getEnclosingElement(), currentElement, typeUtils), filePathWithLineNumber); + } + } + }.scan(cut, null); + } + + private Version computeSinceVersion(Element element, Types types, + Elements elementUtils) { + String docComment = elementUtils.getDocComment(element); + Version version = null; + if (docComment != null) { + version = extractSinceVersionFromText(docComment); + } + + if (version != null) { + return version; //explicit @since has an absolute priority + } + + if (element.getKind() != ElementKind.MODULE) { + version = effectiveSinceVersion(element.getEnclosingElement().getEnclosingElement(), element.getEnclosingElement(), types, elementUtils); + } + + return version; + } + + private Pair findSource(Element forElement, Elements elementUtils) throws IOException { + String moduleName = elementUtils.getModuleOf(forElement).getQualifiedName().toString(); + String binaryName = switch (forElement.getKind()) { + case MODULE -> "module-info"; + case PACKAGE -> ((QualifiedNameable) forElement).getQualifiedName() + ".package-info"; + default -> elementUtils.getBinaryName((TypeElement) forElement).toString(); + }; + Location packageLocationForModule = fm.getLocationForModule(StandardLocation.MODULE_SOURCE_PATH, moduleName); + JavaFileObject jfo = fm.getJavaFileForInput(packageLocationForModule, + binaryName, + JavaFileObject.Kind.SOURCE); + + if (jfo == null) + return null; + + List jfos = Arrays.asList(jfo); + JavaFileManager patchFM = moduleName != null + ? new PatchModuleFileManager(baseFileManager, jfo, moduleName) + : baseFileManager; + JavacTaskImpl task = (JavacTaskImpl) compiler.getTask(null, patchFM, d -> { + }, null, null, jfos); + Iterable cuts = task.parse(); + + task.enter(); + + return Pair.of(task, cuts.iterator().next()); + } + + @Override + public void close() throws IOException { + fm.close(); + } + + /** + * Manages files within a patch module. + * Provides custom behavior for handling file locations within a patch module. + * Includes methods to specify module locations, infer module names and determine + * if a location belongs to the patch module path. + */ + private static final class PatchModuleFileManager + extends ForwardingJavaFileManager { + + private final JavaFileObject file; + private final String moduleName; + + public PatchModuleFileManager(JavaFileManager fileManager, + JavaFileObject file, + String moduleName) { + super(fileManager); + this.file = file; + this.moduleName = moduleName; + } + + @Override + public Location getLocationForModule(Location location, + JavaFileObject fo) throws IOException { + return fo == file + ? PATCH_LOCATION + : super.getLocationForModule(location, fo); + } + + @Override + public String inferModuleName(Location location) throws IOException { + return location == PATCH_LOCATION + ? moduleName + : super.inferModuleName(location); + } + + @Override + public boolean hasLocation(Location location) { + return location == StandardLocation.PATCH_MODULE_PATH || + super.hasLocation(location); + } + + private static final Location PATCH_LOCATION = new Location() { + @Override + public String getName() { + return "PATCH_LOCATION"; + } + + @Override + public boolean isOutputLocation() { + return false; + } + + @Override + public boolean isModuleOrientedLocation() { + return false; + } + }; + } + } +} diff --git a/test/jdk/tools/sincechecker/modules/java_base/CheckSince_javaBase.java b/test/jdk/tools/sincechecker/modules/java_base/CheckSince_javaBase.java new file mode 100644 index 0000000000000..6d0b9d0e932e8 --- /dev/null +++ b/test/jdk/tools/sincechecker/modules/java_base/CheckSince_javaBase.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 8331051 + * @summary Test for `@since` for java.base module + * @library /test/lib + * /test/jdk/tools/sincechecker + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.util + * jdk.compiler/com.sun.tools.javac.code + * @run main SinceChecker java.base --exclude java.lang.classfile + */ From 1cc32237aee03a38bfb0f6679f7328a682ad6ea9 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 16 Oct 2024 13:36:58 +0000 Subject: [PATCH 088/118] 8336911: ZGC: Division by zero in heuristics after JDK-8332717 Reviewed-by: aboldtch, eosterlund --- src/hotspot/share/gc/z/zDirector.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/hotspot/share/gc/z/zDirector.cpp b/src/hotspot/share/gc/z/zDirector.cpp index 481525c425af0..3c0cb660206a2 100644 --- a/src/hotspot/share/gc/z/zDirector.cpp +++ b/src/hotspot/share/gc/z/zDirector.cpp @@ -535,6 +535,19 @@ static double calculate_young_to_old_worker_ratio(const ZDirectorStats& stats) { const size_t reclaimed_per_old_gc = stats._old_stats._stat_heap._reclaimed_avg; const double current_young_bytes_freed_per_gc_time = double(reclaimed_per_young_gc) / double(young_gc_time); const double current_old_bytes_freed_per_gc_time = double(reclaimed_per_old_gc) / double(old_gc_time); + + if (current_young_bytes_freed_per_gc_time == 0.0) { + if (current_old_bytes_freed_per_gc_time == 0.0) { + // Neither young nor old collections have reclaimed any memory. + // Give them equal priority. + return 1.0; + } + + // Only old collections have reclaimed memory. + // Prioritize old. + return ZOldGCThreads; + } + const double old_vs_young_efficiency_ratio = current_old_bytes_freed_per_gc_time / current_young_bytes_freed_per_gc_time; return old_vs_young_efficiency_ratio; From 7625b29920e95f9b754057fe0a2c4ab0afa5cb0c Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 16 Oct 2024 14:08:10 +0000 Subject: [PATCH 089/118] 8329597: C2: Intrinsify Reference.clear Reviewed-by: rcastanedalo, eosterlund, kvn --- .../gc/z/zBarrierSetAssembler_aarch64.cpp | 10 +- .../gc/z/zBarrierSetAssembler_aarch64.hpp | 4 +- src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad | 3 +- .../cpu/ppc/gc/z/zBarrierSetAssembler_ppc.cpp | 2 + src/hotspot/cpu/ppc/gc/z/z_ppc.ad | 3 +- .../riscv/gc/z/zBarrierSetAssembler_riscv.cpp | 2 + src/hotspot/cpu/riscv/gc/z/z_riscv.ad | 3 +- .../cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp | 2 + src/hotspot/cpu/x86/gc/z/z_x86_64.ad | 3 +- src/hotspot/share/classfile/vmIntrinsics.hpp | 2 + src/hotspot/share/classfile/vmSymbols.hpp | 1 + src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp | 5 + .../shenandoah/c2/shenandoahBarrierSetC2.cpp | 7 + src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp | 14 +- src/hotspot/share/gc/z/c2/zBarrierSetC2.hpp | 6 +- src/hotspot/share/gc/z/zBarrierSetRuntime.cpp | 8 + src/hotspot/share/gc/z/zBarrierSetRuntime.hpp | 2 + src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 1 + src/hotspot/share/opto/c2compiler.cpp | 2 + src/hotspot/share/opto/library_call.cpp | 44 ++++++ src/hotspot/share/opto/library_call.hpp | 1 + .../java/lang/ref/PhantomReference.java | 13 ++ .../classes/java/lang/ref/Reference.java | 20 ++- .../share/native/libjava/PhantomReference.c | 6 + .../c2/irTests/gc/ReferenceClearTests.java | 138 ++++++++++++++++++ .../bench/java/lang/ref/ReferenceClear.java | 81 ++++++++++ 26 files changed, 362 insertions(+), 21 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/gc/ReferenceClearTests.java create mode 100644 test/micro/org/openjdk/bench/java/lang/ref/ReferenceClear.java diff --git a/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp index 466e77a4460d0..3f1898b6742e1 100644 --- a/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp @@ -1189,6 +1189,8 @@ void ZBarrierSetAssembler::generate_c2_store_barrier_stub(MacroAssembler* masm, __ lea(rscratch1, RuntimeAddress(ZBarrierSetRuntime::store_barrier_on_native_oop_field_without_healing_addr())); } else if (stub->is_atomic()) { __ lea(rscratch1, RuntimeAddress(ZBarrierSetRuntime::store_barrier_on_oop_field_with_healing_addr())); + } else if (stub->is_nokeepalive()) { + __ lea(rscratch1, RuntimeAddress(ZBarrierSetRuntime::no_keepalive_store_barrier_on_oop_field_without_healing_addr())); } else { __ lea(rscratch1, RuntimeAddress(ZBarrierSetRuntime::store_barrier_on_oop_field_without_healing_addr())); } @@ -1307,11 +1309,11 @@ Label* ZLoadBarrierStubC2Aarch64::entry() { return ZBarrierStubC2::entry(); } -ZStoreBarrierStubC2Aarch64::ZStoreBarrierStubC2Aarch64(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic) - : ZStoreBarrierStubC2(node, ref_addr, new_zaddress, new_zpointer, is_native, is_atomic), _deferred_emit(false) {} +ZStoreBarrierStubC2Aarch64::ZStoreBarrierStubC2Aarch64(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic, bool is_nokeepalive) + : ZStoreBarrierStubC2(node, ref_addr, new_zaddress, new_zpointer, is_native, is_atomic, is_nokeepalive), _deferred_emit(false) {} -ZStoreBarrierStubC2Aarch64* ZStoreBarrierStubC2Aarch64::create(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic) { - ZStoreBarrierStubC2Aarch64* const stub = new (Compile::current()->comp_arena()) ZStoreBarrierStubC2Aarch64(node, ref_addr, new_zaddress, new_zpointer, is_native, is_atomic); +ZStoreBarrierStubC2Aarch64* ZStoreBarrierStubC2Aarch64::create(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic, bool is_nokeepalive) { + ZStoreBarrierStubC2Aarch64* const stub = new (Compile::current()->comp_arena()) ZStoreBarrierStubC2Aarch64(node, ref_addr, new_zaddress, new_zpointer, is_native, is_atomic, is_nokeepalive); register_stub(stub); return stub; } diff --git a/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.hpp index 2f716140ed19d..ad3a171c10370 100644 --- a/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.hpp @@ -280,10 +280,10 @@ class ZStoreBarrierStubC2Aarch64 : public ZStoreBarrierStubC2 { private: bool _deferred_emit; - ZStoreBarrierStubC2Aarch64(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic); + ZStoreBarrierStubC2Aarch64(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic, bool is_nokeepalive); public: - static ZStoreBarrierStubC2Aarch64* create(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic); + static ZStoreBarrierStubC2Aarch64* create(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic, bool is_nokeepalive); virtual void emit_code(MacroAssembler& masm); }; diff --git a/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad b/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad index 56d4538477920..088f92a01573e 100644 --- a/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad +++ b/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad @@ -91,7 +91,8 @@ static void z_store_barrier(MacroAssembler* masm, const MachNode* node, Address z_color(masm, node, rnew_zpointer, rnew_zaddress); } else { bool is_native = (node->barrier_data() & ZBarrierNative) != 0; - ZStoreBarrierStubC2Aarch64* const stub = ZStoreBarrierStubC2Aarch64::create(node, ref_addr, rnew_zaddress, rnew_zpointer, is_native, is_atomic); + bool is_nokeepalive = (node->barrier_data() & ZBarrierNoKeepalive) != 0; + ZStoreBarrierStubC2Aarch64* const stub = ZStoreBarrierStubC2Aarch64::create(node, ref_addr, rnew_zaddress, rnew_zpointer, is_native, is_atomic, is_nokeepalive); ZBarrierSetAssembler* bs_asm = ZBarrierSet::assembler(); bs_asm->store_barrier_fast(masm, ref_addr, rnew_zaddress, rnew_zpointer, tmp, true /* in_nmethod */, is_atomic, *stub->entry(), *stub->continuation()); } diff --git a/src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.cpp index 89ab1b1edeeb4..8a65022126e66 100644 --- a/src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.cpp @@ -943,6 +943,8 @@ void ZBarrierSetAssembler::generate_c2_store_barrier_stub(MacroAssembler* masm, __ call_VM_leaf(ZBarrierSetRuntime::store_barrier_on_native_oop_field_without_healing_addr(), R3_ARG1); } else if (stub->is_atomic()) { __ call_VM_leaf(ZBarrierSetRuntime::store_barrier_on_oop_field_with_healing_addr(), R3_ARG1); + } else if (stub->is_nokeepalive()) { + __ call_VM_leaf(ZBarrierSetRuntime::no_keepalive_store_barrier_on_oop_field_without_healing_addr(), R3_ARG1); } else { __ call_VM_leaf(ZBarrierSetRuntime::store_barrier_on_oop_field_without_healing_addr(), R3_ARG1); } diff --git a/src/hotspot/cpu/ppc/gc/z/z_ppc.ad b/src/hotspot/cpu/ppc/gc/z/z_ppc.ad index 017574d40ff8b..bb696a4738f40 100644 --- a/src/hotspot/cpu/ppc/gc/z/z_ppc.ad +++ b/src/hotspot/cpu/ppc/gc/z/z_ppc.ad @@ -83,7 +83,8 @@ static void z_store_barrier(MacroAssembler* masm, const MachNode* node, Register z_color(masm, rnew_zpointer, rnew_zaddress); } else { bool is_native = (node->barrier_data() & ZBarrierNative) != 0; - ZStoreBarrierStubC2* const stub = ZStoreBarrierStubC2::create(node, Address(ref_base, disp), rnew_zaddress, rnew_zpointer, is_native, is_atomic); + bool is_nokeepalive = (node->barrier_data() & ZBarrierNoKeepalive) != 0; + ZStoreBarrierStubC2* const stub = ZStoreBarrierStubC2::create(node, Address(ref_base, disp), rnew_zaddress, rnew_zpointer, is_native, is_atomic, is_nokeepalive); ZBarrierSetAssembler* bs_asm = ZBarrierSet::assembler(); bs_asm->store_barrier_fast(masm, ref_base, disp, rnew_zaddress, rnew_zpointer, true /* in_nmethod */, is_atomic, *stub->entry(), *stub->continuation()); } diff --git a/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp index cbb918ade00fe..4a82bd9c2d09a 100644 --- a/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp @@ -761,6 +761,8 @@ void ZBarrierSetAssembler::generate_c2_store_barrier_stub(MacroAssembler* masm, __ la(t0, RuntimeAddress(ZBarrierSetRuntime::store_barrier_on_native_oop_field_without_healing_addr())); } else if (stub->is_atomic()) { __ la(t0, RuntimeAddress(ZBarrierSetRuntime::store_barrier_on_oop_field_with_healing_addr())); + } else if (stub->is_nokeepalive()) { + __ la(t0, RuntimeAddress(ZBarrierSetRuntime::no_keepalive_store_barrier_on_oop_field_without_healing_addr())); } else { __ la(t0, RuntimeAddress(ZBarrierSetRuntime::store_barrier_on_oop_field_without_healing_addr())); } diff --git a/src/hotspot/cpu/riscv/gc/z/z_riscv.ad b/src/hotspot/cpu/riscv/gc/z/z_riscv.ad index 5b545fe801203..24669f45eb4d2 100644 --- a/src/hotspot/cpu/riscv/gc/z/z_riscv.ad +++ b/src/hotspot/cpu/riscv/gc/z/z_riscv.ad @@ -82,7 +82,8 @@ static void z_store_barrier(MacroAssembler* masm, const MachNode* node, Address z_color(masm, node, rnew_zpointer, rnew_zaddress, tmp); } else { bool is_native = (node->barrier_data() & ZBarrierNative) != 0; - ZStoreBarrierStubC2* const stub = ZStoreBarrierStubC2::create(node, ref_addr, rnew_zaddress, rnew_zpointer, is_native, is_atomic); + bool is_nokeepalive = (node->barrier_data() & ZBarrierNoKeepalive) != 0; + ZStoreBarrierStubC2* const stub = ZStoreBarrierStubC2::create(node, ref_addr, rnew_zaddress, rnew_zpointer, is_native, is_atomic, is_nokeepalive); ZBarrierSetAssembler* bs_asm = ZBarrierSet::assembler(); bs_asm->store_barrier_fast(masm, ref_addr, rnew_zaddress, rnew_zpointer, tmp, true /* in_nmethod */, is_atomic, *stub->entry(), *stub->continuation()); } diff --git a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp index 65d7c1e3303ba..bc51a2b446848 100644 --- a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp @@ -1260,6 +1260,8 @@ void ZBarrierSetAssembler::generate_c2_store_barrier_stub(MacroAssembler* masm, __ call(RuntimeAddress(ZBarrierSetRuntime::store_barrier_on_native_oop_field_without_healing_addr())); } else if (stub->is_atomic()) { __ call(RuntimeAddress(ZBarrierSetRuntime::store_barrier_on_oop_field_with_healing_addr())); + } else if (stub->is_nokeepalive()) { + __ call(RuntimeAddress(ZBarrierSetRuntime::no_keepalive_store_barrier_on_oop_field_without_healing_addr())); } else { __ call(RuntimeAddress(ZBarrierSetRuntime::store_barrier_on_oop_field_without_healing_addr())); } diff --git a/src/hotspot/cpu/x86/gc/z/z_x86_64.ad b/src/hotspot/cpu/x86/gc/z/z_x86_64.ad index 455d622acdf17..f55ad70e8616e 100644 --- a/src/hotspot/cpu/x86/gc/z/z_x86_64.ad +++ b/src/hotspot/cpu/x86/gc/z/z_x86_64.ad @@ -91,7 +91,8 @@ static void z_store_barrier(MacroAssembler* masm, const MachNode* node, Address } } else { bool is_native = (node->barrier_data() & ZBarrierNative) != 0; - ZStoreBarrierStubC2* const stub = ZStoreBarrierStubC2::create(node, ref_addr, rnew_zaddress, rnew_zpointer, is_native, is_atomic); + bool is_nokeepalive = (node->barrier_data() & ZBarrierNoKeepalive) != 0; + ZStoreBarrierStubC2* const stub = ZStoreBarrierStubC2::create(node, ref_addr, rnew_zaddress, rnew_zpointer, is_native, is_atomic, is_nokeepalive); ZBarrierSetAssembler* bs_asm = ZBarrierSet::assembler(); bs_asm->store_barrier_fast(masm, ref_addr, rnew_zaddress, rnew_zpointer, true /* in_nmethod */, is_atomic, *stub->entry(), *stub->continuation()); } diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp index b6ce21797a618..9bb8b2179ae01 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.hpp +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp @@ -469,6 +469,8 @@ class methodHandle; do_intrinsic(_Reference_get, java_lang_ref_Reference, get_name, void_object_signature, F_R) \ do_intrinsic(_Reference_refersTo0, java_lang_ref_Reference, refersTo0_name, object_boolean_signature, F_RN) \ do_intrinsic(_PhantomReference_refersTo0, java_lang_ref_PhantomReference, refersTo0_name, object_boolean_signature, F_RN) \ + do_intrinsic(_Reference_clear0, java_lang_ref_Reference, clear0_name, void_method_signature, F_RN) \ + do_intrinsic(_PhantomReference_clear0, java_lang_ref_PhantomReference, clear0_name, void_method_signature, F_RN) \ \ /* support for com.sun.crypto.provider.AESCrypt and some of its callers */ \ do_class(com_sun_crypto_provider_aescrypt, "com/sun/crypto/provider/AESCrypt") \ diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index a65ab86fa0a8d..3de6d81f10607 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -426,6 +426,7 @@ class SerializeClosure; template(cs_name, "cs") \ template(get_name, "get") \ template(refersTo0_name, "refersTo0") \ + template(clear0_name, "clear0") \ template(put_name, "put") \ template(type_name, "type") \ template(findNative_name, "findNative") \ diff --git a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp index 4ec7e10cd9a86..edbf0e902392b 100644 --- a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp +++ b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp @@ -327,6 +327,7 @@ Node* G1BarrierSetC2::store_at_resolved(C2Access& access, C2AccessValue& val) co bool in_heap = (decorators & IN_HEAP) != 0; bool tightly_coupled_alloc = (decorators & C2_TIGHTLY_COUPLED_ALLOC) != 0; bool need_store_barrier = !(tightly_coupled_alloc && use_ReduceInitialCardMarks()) && (in_heap || anonymous); + bool no_keepalive = (decorators & AS_NO_KEEPALIVE) != 0; if (access.is_oop() && need_store_barrier) { access.set_barrier_data(get_store_barrier(access)); if (tightly_coupled_alloc) { @@ -336,6 +337,10 @@ Node* G1BarrierSetC2::store_at_resolved(C2Access& access, C2AccessValue& val) co access.set_barrier_data(access.barrier_data() & ~G1C2BarrierPre); } } + if (no_keepalive) { + // No keep-alive means no need for the pre-barrier. + access.set_barrier_data(access.barrier_data() & ~G1C2BarrierPre); + } return BarrierSetC2::store_at_resolved(access, val); } diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp index 7ac9dcc2e8134..691c78cd02486 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp @@ -480,10 +480,17 @@ Node* ShenandoahBarrierSetC2::store_at_resolved(C2Access& access, C2AccessValue& const TypePtr* adr_type = access.addr().type(); Node* adr = access.addr().node(); + bool no_keepalive = (decorators & AS_NO_KEEPALIVE) != 0; + if (!access.is_oop()) { return BarrierSetC2::store_at_resolved(access, val); } + if (no_keepalive) { + // No keep-alive means no need for the pre-barrier. + return BarrierSetC2::store_at_resolved(access, val); + } + if (access.is_parse_access()) { C2ParseAccess& parse_access = static_cast(access); GraphKit* kit = parse_access.kit(); diff --git a/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp b/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp index a46681d131c94..12ee400eb2da2 100644 --- a/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp +++ b/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp @@ -239,21 +239,23 @@ void ZLoadBarrierStubC2::emit_code(MacroAssembler& masm) { ZBarrierSet::assembler()->generate_c2_load_barrier_stub(&masm, static_cast(this)); } -ZStoreBarrierStubC2* ZStoreBarrierStubC2::create(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic) { +ZStoreBarrierStubC2* ZStoreBarrierStubC2::create(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic, bool is_nokeepalive) { AARCH64_ONLY(fatal("Should use ZStoreBarrierStubC2Aarch64::create")); - ZStoreBarrierStubC2* const stub = new (Compile::current()->comp_arena()) ZStoreBarrierStubC2(node, ref_addr, new_zaddress, new_zpointer, is_native, is_atomic); + ZStoreBarrierStubC2* const stub = new (Compile::current()->comp_arena()) ZStoreBarrierStubC2(node, ref_addr, new_zaddress, new_zpointer, is_native, is_atomic, is_nokeepalive); register_stub(stub); return stub; } -ZStoreBarrierStubC2::ZStoreBarrierStubC2(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic) +ZStoreBarrierStubC2::ZStoreBarrierStubC2(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, + bool is_native, bool is_atomic, bool is_nokeepalive) : ZBarrierStubC2(node), _ref_addr(ref_addr), _new_zaddress(new_zaddress), _new_zpointer(new_zpointer), _is_native(is_native), - _is_atomic(is_atomic) {} + _is_atomic(is_atomic), + _is_nokeepalive(is_nokeepalive) {} Address ZStoreBarrierStubC2::ref_addr() const { return _ref_addr; @@ -275,6 +277,10 @@ bool ZStoreBarrierStubC2::is_atomic() const { return _is_atomic; } +bool ZStoreBarrierStubC2::is_nokeepalive() const { + return _is_nokeepalive; +} + void ZStoreBarrierStubC2::emit_code(MacroAssembler& masm) { ZBarrierSet::assembler()->generate_c2_store_barrier_stub(&masm, static_cast(this)); } diff --git a/src/hotspot/share/gc/z/c2/zBarrierSetC2.hpp b/src/hotspot/share/gc/z/c2/zBarrierSetC2.hpp index bf46780226eea..58f75441b910c 100644 --- a/src/hotspot/share/gc/z/c2/zBarrierSetC2.hpp +++ b/src/hotspot/share/gc/z/c2/zBarrierSetC2.hpp @@ -79,18 +79,20 @@ class ZStoreBarrierStubC2 : public ZBarrierStubC2 { const Register _new_zpointer; const bool _is_native; const bool _is_atomic; + const bool _is_nokeepalive; protected: - ZStoreBarrierStubC2(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic); + ZStoreBarrierStubC2(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic, bool is_nokeepalive); public: - static ZStoreBarrierStubC2* create(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic); + static ZStoreBarrierStubC2* create(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic, bool is_nokeepalive); Address ref_addr() const; Register new_zaddress() const; Register new_zpointer() const; bool is_native() const; bool is_atomic() const; + bool is_nokeepalive() const; virtual void emit_code(MacroAssembler& masm); }; diff --git a/src/hotspot/share/gc/z/zBarrierSetRuntime.cpp b/src/hotspot/share/gc/z/zBarrierSetRuntime.cpp index b41fec3d0a552..c267d9bb24aa6 100644 --- a/src/hotspot/share/gc/z/zBarrierSetRuntime.cpp +++ b/src/hotspot/share/gc/z/zBarrierSetRuntime.cpp @@ -59,6 +59,10 @@ JRT_LEAF(void, ZBarrierSetRuntime::store_barrier_on_oop_field_without_healing(oo ZBarrier::store_barrier_on_heap_oop_field((zpointer*)p, false /* heal */); JRT_END +JRT_LEAF(void, ZBarrierSetRuntime::no_keepalive_store_barrier_on_oop_field_without_healing(oop* p)) + ZBarrier::no_keep_alive_store_barrier_on_heap_oop_field((zpointer*)p); +JRT_END + JRT_LEAF(void, ZBarrierSetRuntime::store_barrier_on_native_oop_field_without_healing(oop* p)) ZBarrier::store_barrier_on_native_oop_field((zpointer*)p, false /* heal */); JRT_END @@ -126,6 +130,10 @@ address ZBarrierSetRuntime::store_barrier_on_oop_field_without_healing_addr() { return reinterpret_cast
      (store_barrier_on_oop_field_without_healing); } +address ZBarrierSetRuntime::no_keepalive_store_barrier_on_oop_field_without_healing_addr() { + return reinterpret_cast
      (no_keepalive_store_barrier_on_oop_field_without_healing); +} + address ZBarrierSetRuntime::store_barrier_on_native_oop_field_without_healing_addr() { return reinterpret_cast
      (store_barrier_on_native_oop_field_without_healing); } diff --git a/src/hotspot/share/gc/z/zBarrierSetRuntime.hpp b/src/hotspot/share/gc/z/zBarrierSetRuntime.hpp index 8a81f162bf1ef..8d59be02e68c9 100644 --- a/src/hotspot/share/gc/z/zBarrierSetRuntime.hpp +++ b/src/hotspot/share/gc/z/zBarrierSetRuntime.hpp @@ -40,6 +40,7 @@ class ZBarrierSetRuntime : public AllStatic { static oopDesc* no_keepalive_load_barrier_on_phantom_oop_field_preloaded(oopDesc* o, oop* p); static void store_barrier_on_oop_field_with_healing(oop* p); static void store_barrier_on_oop_field_without_healing(oop* p); + static void no_keepalive_store_barrier_on_oop_field_without_healing(oop* p); static void store_barrier_on_native_oop_field_without_healing(oop* p); static void load_barrier_on_oop_array(oop* p, size_t length); static void clone(oopDesc* src, oopDesc* dst, size_t size); @@ -54,6 +55,7 @@ class ZBarrierSetRuntime : public AllStatic { static address no_keepalive_load_barrier_on_phantom_oop_field_preloaded_addr(); static address store_barrier_on_oop_field_with_healing_addr(); static address store_barrier_on_oop_field_without_healing_addr(); + static address no_keepalive_store_barrier_on_oop_field_without_healing_addr(); static address store_barrier_on_native_oop_field_without_healing_addr(); static address load_barrier_on_oop_array_addr(); static address clone_addr(); diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 05081197c4bd5..a26cd5efe23b1 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -847,6 +847,7 @@ ZGC_ONLY(DECLARE_FUNCTION_FROM_ADDR(declare_function_with_value, ZBarrierSetRuntime::load_barrier_on_oop_field_preloaded_store_good)) \ ZGC_ONLY(DECLARE_FUNCTION_FROM_ADDR(declare_function_with_value, ZBarrierSetRuntime::no_keepalive_load_barrier_on_weak_oop_field_preloaded)) \ ZGC_ONLY(DECLARE_FUNCTION_FROM_ADDR(declare_function_with_value, ZBarrierSetRuntime::no_keepalive_load_barrier_on_phantom_oop_field_preloaded)) \ + ZGC_ONLY(DECLARE_FUNCTION_FROM_ADDR(declare_function_with_value, ZBarrierSetRuntime::no_keepalive_store_barrier_on_oop_field_without_healing)) \ ZGC_ONLY(DECLARE_FUNCTION_FROM_ADDR(declare_function_with_value, ZBarrierSetRuntime::store_barrier_on_native_oop_field_without_healing)) \ ZGC_ONLY(DECLARE_FUNCTION_FROM_ADDR(declare_function_with_value, ZBarrierSetRuntime::store_barrier_on_oop_field_with_healing)) \ ZGC_ONLY(DECLARE_FUNCTION_FROM_ADDR(declare_function_with_value, ZBarrierSetRuntime::store_barrier_on_oop_field_without_healing)) \ diff --git a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp index 151c320cadde6..1a00f17f50530 100644 --- a/src/hotspot/share/opto/c2compiler.cpp +++ b/src/hotspot/share/opto/c2compiler.cpp @@ -766,6 +766,8 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) { case vmIntrinsics::_Reference_get: case vmIntrinsics::_Reference_refersTo0: case vmIntrinsics::_PhantomReference_refersTo0: + case vmIntrinsics::_Reference_clear0: + case vmIntrinsics::_PhantomReference_clear0: case vmIntrinsics::_Class_cast: case vmIntrinsics::_aescrypt_encryptBlock: case vmIntrinsics::_aescrypt_decryptBlock: diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 4ab4eea6f8f68..49750cd2697e9 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -580,6 +580,8 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_Reference_get: return inline_reference_get(); case vmIntrinsics::_Reference_refersTo0: return inline_reference_refersTo0(false); case vmIntrinsics::_PhantomReference_refersTo0: return inline_reference_refersTo0(true); + case vmIntrinsics::_Reference_clear0: return inline_reference_clear0(false); + case vmIntrinsics::_PhantomReference_clear0: return inline_reference_clear0(true); case vmIntrinsics::_Class_cast: return inline_Class_cast(); @@ -6962,6 +6964,48 @@ bool LibraryCallKit::inline_reference_refersTo0(bool is_phantom) { return true; } +//----------------------------inline_reference_clear0---------------------------- +// void java.lang.ref.Reference.clear0(); +// void java.lang.ref.PhantomReference.clear0(); +bool LibraryCallKit::inline_reference_clear0(bool is_phantom) { + // This matches the implementation in JVM_ReferenceClear, see the comments there. + + // Get arguments + Node* reference_obj = null_check_receiver(); + if (stopped()) return true; + + // Common access parameters + DecoratorSet decorators = IN_HEAP | AS_NO_KEEPALIVE; + decorators |= (is_phantom ? ON_PHANTOM_OOP_REF : ON_WEAK_OOP_REF); + Node* referent_field_addr = basic_plus_adr(reference_obj, java_lang_ref_Reference::referent_offset()); + const TypePtr* referent_field_addr_type = _gvn.type(referent_field_addr)->isa_ptr(); + const Type* val_type = TypeOopPtr::make_from_klass(env()->Object_klass()); + + Node* referent = access_load_at(reference_obj, + referent_field_addr, + referent_field_addr_type, + val_type, + T_OBJECT, + decorators); + + IdealKit ideal(this); +#define __ ideal. + __ if_then(referent, BoolTest::ne, null()); + sync_kit(ideal); + access_store_at(reference_obj, + referent_field_addr, + referent_field_addr_type, + null(), + val_type, + T_OBJECT, + decorators); + __ sync_kit(this); + __ end_if(); + final_sync(ideal); +#undef __ + + return true; +} Node* LibraryCallKit::load_field_from_object(Node* fromObj, const char* fieldName, const char* fieldTypeString, DecoratorSet decorators, bool is_static, diff --git a/src/hotspot/share/opto/library_call.hpp b/src/hotspot/share/opto/library_call.hpp index 4a85304517479..c9b2a02d3f1ab 100644 --- a/src/hotspot/share/opto/library_call.hpp +++ b/src/hotspot/share/opto/library_call.hpp @@ -297,6 +297,7 @@ class LibraryCallKit : public GraphKit { bool inline_divmod_methods(vmIntrinsics::ID id); bool inline_reference_get(); bool inline_reference_refersTo0(bool is_phantom); + bool inline_reference_clear0(bool is_phantom); bool inline_Class_cast(); bool inline_aescrypt_Block(vmIntrinsics::ID id); bool inline_cipherBlockChaining_AESCrypt(vmIntrinsics::ID id); 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 e474748349776..47a989cde4689 100644 --- a/src/java.base/share/classes/java/lang/ref/PhantomReference.java +++ b/src/java.base/share/classes/java/lang/ref/PhantomReference.java @@ -77,6 +77,19 @@ boolean refersToImpl(T obj) { @IntrinsicCandidate private native boolean refersTo0(Object o); + /* Override the implementation of Reference.clear. + * Phantom references are weaker than finalization, so the referent + * access needs to be handled differently for garbage collectors that + * do reference processing concurrently. + */ + @Override + void clearImpl() { + clear0(); + } + + @IntrinsicCandidate + private native void clear0(); + /** * Creates a new phantom reference that refers to the given object and * is registered with the given queue. 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 747aa64902f8e..88cd2a3190b71 100644 --- a/src/java.base/share/classes/java/lang/ref/Reference.java +++ b/src/java.base/share/classes/java/lang/ref/Reference.java @@ -403,13 +403,23 @@ boolean refersToImpl(T obj) { * necessary. */ public void clear() { - clear0(); + clearImpl(); } - /* Implementation of clear(), also used by enqueue(). A simple - * assignment of the referent field won't do for some garbage - * collectors. + /* Implementation of clear(). A simple assignment of the referent field + * won't do for some garbage collectors. There is the override for phantom + * references, which requires different semantics. This method is also + * used by enqueue(). + * + *

      This method exists only to avoid making clear0() virtual. Making + * clear0() virtual has the undesirable effect of C2 often preferring + * to call the native implementation over the intrinsic. */ + void clearImpl() { + clear0(); + } + + @IntrinsicCandidate private native void clear0(); /* -- Operations on inactive FinalReferences -- */ @@ -511,7 +521,7 @@ public boolean isEnqueued() { * it was not registered with a queue when it was created */ public boolean enqueue() { - clear0(); // Intentionally clear0() rather than clear() + clearImpl(); // Intentionally clearImpl() to dispatch to overridden method, if needed return this.queue.enqueue(this); } diff --git a/src/java.base/share/native/libjava/PhantomReference.c b/src/java.base/share/native/libjava/PhantomReference.c index b6d6e7297f104..54d4b7681dd51 100644 --- a/src/java.base/share/native/libjava/PhantomReference.c +++ b/src/java.base/share/native/libjava/PhantomReference.c @@ -31,3 +31,9 @@ Java_java_lang_ref_PhantomReference_refersTo0(JNIEnv *env, jobject ref, jobject { return JVM_PhantomReferenceRefersTo(env, ref, o); } + +JNIEXPORT void JNICALL +Java_java_lang_ref_PhantomReference_clear0(JNIEnv *env, jobject ref) +{ + JVM_ReferenceClear(env, ref); +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/gc/ReferenceClearTests.java b/test/hotspot/jtreg/compiler/c2/irTests/gc/ReferenceClearTests.java new file mode 100644 index 0000000000000..c56ffc88778ae --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/gc/ReferenceClearTests.java @@ -0,0 +1,138 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package compiler.c2.irTests.gc; + +import jdk.test.lib.Asserts; +import compiler.lib.ir_framework.*; +import jdk.test.whitebox.gc.GC; + +import java.lang.ref.*; +import java.util.*; + +/* + * @test + * @bug 8329597 + * @summary Test that Reference.clear intrinsics are properly handled + * @library /test/lib / + * @build jdk.test.whitebox.WhiteBox + * @requires vm.compiler2.enabled + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI compiler.c2.irTests.gc.ReferenceClearTests + + */ +public class ReferenceClearTests { + + private static String[] args(String... add) { + List args = new ArrayList<>(); + + // Use PerMethodTrapLimit=0 to compile all branches in the intrinsics. + args.add("-XX:PerMethodTrapLimit=0"); + + // Forcefully inline all methods to reach the intrinsic code. + args.add("-XX:CompileCommand=inline,compiler.c2.irTests.gc.ReferenceClearTests::*"); + args.add("-XX:CompileCommand=inline,java.lang.ref.Reference::*"); + args.add("-XX:CompileCommand=inline,java.lang.ref.PhantomReference::*"); + + // Mix in test config code. + args.addAll(Arrays.asList(add)); + + return args.toArray(new String[0]); + } + + public static void main(String[] args) { + TestFramework framework = new TestFramework(); + + int idx = 0; + if (GC.isSelectedErgonomically() && GC.Serial.isSupported()) { + // Serial does not have SATB/keep-alive barriers at all. + // There are inter-generational barriers on stores, but they are + // folded away for null stores like clear(). + framework.addScenarios(new Scenario(idx++, args( + "-XX:+UseSerialGC" + ))); + } + if (GC.isSelectedErgonomically() && GC.Parallel.isSupported()) { + // Parallel does not have SATB/keep-alive barriers at all. + // There are inter-generational barriers on stores, but they + // should be folded away for null stores like clear(). + framework.addScenarios(new Scenario(idx++, args( + "-XX:+UseParallelGC" + ))); + } + if (GC.isSelectedErgonomically() && GC.G1.isSupported()) { + // G1 does not have barriers in C2 IR. + framework.addScenarios(new Scenario(idx++, args( + "-XX:+UseG1GC" + ))); + } + if (GC.isSelectedErgonomically() && GC.Shenandoah.isSupported()) { + // Shenandoah has SATB/keep-alive barriers, but they should not be + // present clear()-s. There are load-reference barriers, which would + // confuse the tests, so we enable only SATB barriers. + framework.addScenarios(new Scenario(idx++, args( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:ShenandoahGCMode=passive", + "-XX:+ShenandoahSATBBarrier", + "-XX:+UseShenandoahGC" + ))); + } + if (GC.isSelectedErgonomically() && GC.Z.isSupported()) { + // Z does not have barriers in C2 IR. + framework.addScenarios(new Scenario(idx++, args( + "-XX:+UseZGC" + ))); + } + framework.start(); + } + + static final Object REF = new Object(); + + static final SoftReference SR = new SoftReference<>(REF); + static final WeakReference WR = new WeakReference<>(REF); + static final PhantomReference PR = new PhantomReference<>(REF, null); + + // We assert there is only a single load and a single store of Reference.referent. + // This serves as signal that no GC barriers are emitted in IR. + + @Test + @IR(counts = { IRNode.STORE, "1", + IRNode.LOAD, "1" }) + public void soft() { + SR.clear(); + } + + @Test + @IR(counts = { IRNode.STORE, "1", + IRNode.LOAD, "1" }) + public void weak() { + WR.clear(); + } + + @Test + @IR(counts = { IRNode.STORE, "1", + IRNode.LOAD, "1" }) + public void phantom() { + PR.clear(); + } + +} diff --git a/test/micro/org/openjdk/bench/java/lang/ref/ReferenceClear.java b/test/micro/org/openjdk/bench/java/lang/ref/ReferenceClear.java new file mode 100644 index 0000000000000..6a7b4d6997056 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/ref/ReferenceClear.java @@ -0,0 +1,81 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.lang.ref; + +import java.lang.ref.*; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; + +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@BenchmarkMode(Mode.AverageTime) +@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Fork(3) +public class ReferenceClear { + + final Reference soft = new SoftReference<>(new Object()); + final Reference weak = new WeakReference<>(new Object()); + final Reference phantom = new PhantomReference<>(new Object(), null); + + @Benchmark + public void soft() { + soft.clear(); + } + + @Benchmark + public void soft_new(Blackhole bh) { + Object ref = new Object(); + bh.consume(ref); + Reference soft = new SoftReference<>(ref); + soft.clear(); + } + + @Benchmark + public void weak() { + weak.clear(); + } + + @Benchmark + public void weak_new(Blackhole bh) { + Object ref = new Object(); + bh.consume(ref); + Reference weak = new WeakReference<>(ref); + weak.clear(); + } + + @Benchmark + public void phantom() { + phantom.clear(); + } + + @Benchmark + public void phantom_new(Blackhole bh) { + Object ref = new Object(); + bh.consume(ref); + Reference phantom = new PhantomReference<>(ref, null); + phantom.clear(); + } + +} From c34fb2c989562206a2506a2fbbfb584e223bb828 Mon Sep 17 00:00:00 2001 From: Gerard Ziemski Date: Wed, 16 Oct 2024 15:32:07 +0000 Subject: [PATCH 090/118] 8338883: Show warning when CreateCoredumpOnCrash set, but core dump will not happen Reviewed-by: dholmes, jsjolen --- src/hotspot/os/posix/os_posix.cpp | 67 +++++++++---------- src/hotspot/os/windows/os_windows.cpp | 60 ++++++++++------- src/hotspot/share/runtime/os.hpp | 2 +- src/hotspot/share/runtime/threads.cpp | 6 ++ src/hotspot/share/utilities/vmError.cpp | 4 +- .../ErrorHandling/CreateCoredumpOnCrash.java | 58 +++++++++++++--- 6 files changed, 124 insertions(+), 73 deletions(-) diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index cc29f209160ee..78fd2a678886e 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -104,49 +104,44 @@ static int clock_tics_per_sec = 100; size_t os::_os_min_stack_allowed = PTHREAD_STACK_MIN; // Check core dump limit and report possible place where core can be found -void os::check_dump_limit(char* buffer, size_t bufferSize) { +void os::check_core_dump_prerequisites(char* buffer, size_t bufferSize, bool check_only) { if (!FLAG_IS_DEFAULT(CreateCoredumpOnCrash) && !CreateCoredumpOnCrash) { jio_snprintf(buffer, bufferSize, "CreateCoredumpOnCrash is disabled from command line"); VMError::record_coredump_status(buffer, false); - return; - } - - int n; - struct rlimit rlim; - bool success; - - char core_path[PATH_MAX]; - n = get_core_path(core_path, PATH_MAX); - - if (n <= 0) { - jio_snprintf(buffer, bufferSize, "core.%d (may not exist)", current_process_id()); - success = true; + } else { + struct rlimit rlim; + bool success = true; + bool warn = true; + char core_path[PATH_MAX]; + if (get_core_path(core_path, PATH_MAX) <= 0) { + jio_snprintf(buffer, bufferSize, "core.%d (may not exist)", current_process_id()); #ifdef LINUX - } else if (core_path[0] == '"') { // redirect to user process - jio_snprintf(buffer, bufferSize, "Core dumps may be processed with %s", core_path); - success = true; + } else if (core_path[0] == '"') { // redirect to user process + jio_snprintf(buffer, bufferSize, "Core dumps may be processed with %s", core_path); #endif - } else if (getrlimit(RLIMIT_CORE, &rlim) != 0) { - jio_snprintf(buffer, bufferSize, "%s (may not exist)", core_path); - success = true; - } else { - switch(rlim.rlim_cur) { - case RLIM_INFINITY: - jio_snprintf(buffer, bufferSize, "%s", core_path); - success = true; - break; - case 0: - jio_snprintf(buffer, bufferSize, "Core dumps have been disabled. To enable core dumping, try \"ulimit -c unlimited\" before starting Java again"); - success = false; - break; - default: - jio_snprintf(buffer, bufferSize, "%s (max size " UINT64_FORMAT " k). To ensure a full core dump, try \"ulimit -c unlimited\" before starting Java again", core_path, uint64_t(rlim.rlim_cur) / K); - success = true; - break; + } else if (getrlimit(RLIMIT_CORE, &rlim) != 0) { + jio_snprintf(buffer, bufferSize, "%s (may not exist)", core_path); + } else { + switch(rlim.rlim_cur) { + case RLIM_INFINITY: + jio_snprintf(buffer, bufferSize, "%s", core_path); + warn = false; + break; + case 0: + jio_snprintf(buffer, bufferSize, "Core dumps have been disabled. To enable core dumping, try \"ulimit -c unlimited\" before starting Java again"); + success = false; + break; + default: + jio_snprintf(buffer, bufferSize, "%s (max size " UINT64_FORMAT " k). To ensure a full core dump, try \"ulimit -c unlimited\" before starting Java again", core_path, uint64_t(rlim.rlim_cur) / K); + break; + } + } + if (!check_only) { + VMError::record_coredump_status(buffer, success); + } else if (warn) { + warning("CreateCoredumpOnCrash specified, but %s", buffer); } } - - VMError::record_coredump_status(buffer, success); } bool os::committed_in_range(address start, size_t size, address& committed_start, size_t& committed_size) { diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 0d5727b98f443..fe093aee116b6 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -1287,38 +1287,50 @@ void os::shutdown() { static HANDLE dumpFile = nullptr; -// Check if dump file can be created. -void os::check_dump_limit(char* buffer, size_t buffsz) { - bool status = true; +// Check if core dump is active and if a core dump file can be created +void os::check_core_dump_prerequisites(char* buffer, size_t bufferSize, bool check_only) { if (!FLAG_IS_DEFAULT(CreateCoredumpOnCrash) && !CreateCoredumpOnCrash) { - jio_snprintf(buffer, buffsz, "CreateCoredumpOnCrash is disabled from command line"); - status = false; - } - + jio_snprintf(buffer, bufferSize, "CreateCoredumpOnCrash is disabled from command line"); + VMError::record_coredump_status(buffer, false); + } else { + bool success = true; + bool warn = true; #ifndef ASSERT - if (!os::win32::is_windows_server() && FLAG_IS_DEFAULT(CreateCoredumpOnCrash)) { - jio_snprintf(buffer, buffsz, "Minidumps are not enabled by default on client versions of Windows"); - status = false; - } + if (!os::win32::is_windows_server() && FLAG_IS_DEFAULT(CreateCoredumpOnCrash)) { + jio_snprintf(buffer, bufferSize, "Minidumps are not enabled by default on client versions of Windows"); + success = false; + warn = true; + } #endif - if (status) { - const char* cwd = get_current_directory(nullptr, 0); - int pid = current_process_id(); - if (cwd != nullptr) { - jio_snprintf(buffer, buffsz, "%s\\hs_err_pid%u.mdmp", cwd, pid); - } else { - jio_snprintf(buffer, buffsz, ".\\hs_err_pid%u.mdmp", pid); + if (success) { + if (!check_only) { + const char* cwd = get_current_directory(nullptr, 0); + int pid = current_process_id(); + if (cwd != nullptr) { + jio_snprintf(buffer, bufferSize, "%s\\hs_err_pid%u.mdmp", cwd, pid); + } else { + jio_snprintf(buffer, bufferSize, ".\\hs_err_pid%u.mdmp", pid); + } + + if (dumpFile == nullptr && + (dumpFile = CreateFile(buffer, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr)) + == INVALID_HANDLE_VALUE) { + jio_snprintf(buffer, bufferSize, "Failed to create minidump file (0x%x).", GetLastError()); + success = false; + } + } else { + // For now on Windows, there are no more checks that we can do + warn = false; + } } - if (dumpFile == nullptr && - (dumpFile = CreateFile(buffer, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr)) - == INVALID_HANDLE_VALUE) { - jio_snprintf(buffer, buffsz, "Failed to create minidump file (0x%x).", GetLastError()); - status = false; + if (!check_only) { + VMError::record_coredump_status(buffer, success); + } else if (warn) { + warning("CreateCoredumpOnCrash specified, but %s", buffer); } } - VMError::record_coredump_status(buffer, status); } void os::abort(bool dump_core, void* siginfo, const void* context) { diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index 35a5be77b6058..65071769bc4cb 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -939,7 +939,7 @@ class os: AllStatic { // provided buffer as a scratch buffer. The status message which will be written // into the error log either is file location or a short error message, depending // on the checking result. - static void check_dump_limit(char* buffer, size_t bufferSize); + static void check_core_dump_prerequisites(char* buffer, size_t bufferSize, bool check_only = false); // Get the default path to the core file // Returns the length of the string diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp index 45aaa769856af..b2edad395cef0 100644 --- a/src/hotspot/share/runtime/threads.cpp +++ b/src/hotspot/share/runtime/threads.cpp @@ -65,6 +65,7 @@ #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/flags/jvmFlagLimit.hpp" #include "runtime/globals.hpp" +#include "runtime/globals_extension.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/java.hpp" @@ -665,6 +666,11 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { log_info(os)("Initialized VM with process ID %d", os::current_process_id()); + if (!FLAG_IS_DEFAULT(CreateCoredumpOnCrash) && CreateCoredumpOnCrash) { + char buffer[2*JVM_MAXPATHLEN]; + os::check_core_dump_prerequisites(buffer, sizeof(buffer), true); + } + // Signal Dispatcher needs to be started before VMInit event is posted os::initialize_jdk_signal_support(CHECK_JNI_ERR); diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index 0b3ccf9c747aa..7bbb978b8064f 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, 2020 SAP SE. All rights reserved. * Copyright (c) 2023, Red Hat, Inc. and/or its affiliates. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -1696,7 +1696,7 @@ void VMError::report_and_die(int id, const char* message, const char* detail_fmt ShowMessageBoxOnError = false; } - os::check_dump_limit(buffer, sizeof(buffer)); + os::check_core_dump_prerequisites(buffer, sizeof(buffer)); // reset signal handlers or exception filter; make sure recursive crashes // are handled properly. diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/CreateCoredumpOnCrash.java b/test/hotspot/jtreg/runtime/ErrorHandling/CreateCoredumpOnCrash.java index 73efc0e5e4605..76ea10d77cbbe 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/CreateCoredumpOnCrash.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/CreateCoredumpOnCrash.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * 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,6 +29,7 @@ * java.management * jdk.internal.jvmstat/sun.jvmstat.monitor * @run driver CreateCoredumpOnCrash + * @requires vm.flagless */ import jdk.test.lib.process.ProcessTools; @@ -43,24 +44,61 @@ public static void main(String[] args) { } } + private static String ulimitString(int limit) { + String string = "ulimit -c "; + if (limit != Integer.MAX_VALUE) { + string += limit; + } else { + string += "unlimited"; + } + return string+";"; + } + public static void main(String[] args) throws Exception { runTest("-XX:-CreateCoredumpOnCrash").shouldContain("CreateCoredumpOnCrash turned off, no core file dumped") - .shouldNotHaveExitValue(0); + .shouldNotHaveExitValue(0); if (Platform.isWindows()) { // The old CreateMinidumpOnCrash option should still work runTest("-XX:-CreateMinidumpOnCrash").shouldContain("CreateCoredumpOnCrash turned off, no core file dumped") - .shouldNotHaveExitValue(0); + .shouldNotHaveExitValue(0); } else { - runTest("-XX:+CreateCoredumpOnCrash").shouldNotContain("CreateCoredumpOnCrash turned off, no core file dumped") - .shouldNotHaveExitValue(0); - } + String exec_cmd[] = {"sh", "-c", "ulimit -c"}; + OutputAnalyzer oa = new OutputAnalyzer(Runtime.getRuntime().exec(exec_cmd)); + oa.shouldHaveExitValue(0); + if (!oa.contains("0\n")) { + oa = runTest("-XX:+CreateCoredumpOnCrash"); + oa.shouldContain("Core dump will be written."); + oa.shouldNotHaveExitValue(0); + oa = runTest("-XX:+CreateCoredumpOnCrash", ulimitString(1024)); + oa.shouldContain("warning: CreateCoredumpOnCrash specified, but"); + oa.shouldNotHaveExitValue(0); + + oa = runTest("-XX:+CreateCoredumpOnCrash", ulimitString(0)); + oa.shouldContain("warning: CreateCoredumpOnCrash specified, but"); + oa.shouldNotHaveExitValue(0); + } else { + throw new Exception("ulimit is not set correctly, try 'ulimit -c unlimited' and re-run."); + } + } } + public static OutputAnalyzer runTest(String option) throws Exception { - return new OutputAnalyzer( - ProcessTools.createLimitedTestJavaProcessBuilder( - "-Xmx128m", "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED", option, Crasher.class.getName()) - .start()); + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-Xmx128m", + "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED", + option, Crasher.class.getName()); + return new OutputAnalyzer(pb.start()); + } + public static OutputAnalyzer runTest(String option, String limit) throws Exception { + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-Xmx128m", + "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED", + option, new String("'"+Crasher.class.getName()+"'")); + String args = ""; + for (String s:pb.command()) { + args += s+" "; + } + String exec_cmd[] = {"sh", "-c", limit+args}; + return new OutputAnalyzer(Runtime.getRuntime().exec(exec_cmd)); } } From 709914fc92dd180c8f081ff70ef476554a04f4ce Mon Sep 17 00:00:00 2001 From: Jatin Bhateja Date: Wed, 16 Oct 2024 16:08:02 +0000 Subject: [PATCH 091/118] 8338023: Support two vector selectFrom API Reviewed-by: psandoz, epeter, sviswanathan --- src/hotspot/cpu/x86/assembler_x86.cpp | 72 +++-- src/hotspot/cpu/x86/assembler_x86.hpp | 7 +- src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp | 27 ++ src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp | 2 + src/hotspot/cpu/x86/x86.ad | 27 ++ src/hotspot/share/adlc/formssel.cpp | 2 +- src/hotspot/share/classfile/vmIntrinsics.hpp | 11 + src/hotspot/share/opto/c2compiler.cpp | 1 + src/hotspot/share/opto/classes.hpp | 1 + src/hotspot/share/opto/library_call.cpp | 2 + src/hotspot/share/opto/library_call.hpp | 1 + src/hotspot/share/opto/matcher.cpp | 1 + src/hotspot/share/opto/vectorIntrinsics.cpp | 185 ++++++++++++- src/hotspot/share/opto/vectornode.cpp | 2 + src/hotspot/share/opto/vectornode.hpp | 15 ++ .../jdk/internal/vm/vector/VectorSupport.java | 18 ++ .../jdk/incubator/vector/Byte128Vector.java | 7 + .../jdk/incubator/vector/Byte256Vector.java | 7 + .../jdk/incubator/vector/Byte512Vector.java | 7 + .../jdk/incubator/vector/Byte64Vector.java | 7 + .../jdk/incubator/vector/ByteMaxVector.java | 7 + .../jdk/incubator/vector/ByteVector.java | 29 ++ .../jdk/incubator/vector/Double128Vector.java | 7 + .../jdk/incubator/vector/Double256Vector.java | 7 + .../jdk/incubator/vector/Double512Vector.java | 7 + .../jdk/incubator/vector/Double64Vector.java | 7 + .../jdk/incubator/vector/DoubleMaxVector.java | 7 + .../jdk/incubator/vector/DoubleVector.java | 29 ++ .../jdk/incubator/vector/Float128Vector.java | 7 + .../jdk/incubator/vector/Float256Vector.java | 7 + .../jdk/incubator/vector/Float512Vector.java | 7 + .../jdk/incubator/vector/Float64Vector.java | 7 + .../jdk/incubator/vector/FloatMaxVector.java | 7 + .../jdk/incubator/vector/FloatVector.java | 29 ++ .../jdk/incubator/vector/Int128Vector.java | 7 + .../jdk/incubator/vector/Int256Vector.java | 7 + .../jdk/incubator/vector/Int512Vector.java | 7 + .../jdk/incubator/vector/Int64Vector.java | 7 + .../jdk/incubator/vector/IntMaxVector.java | 7 + .../jdk/incubator/vector/IntVector.java | 29 ++ .../jdk/incubator/vector/Long128Vector.java | 7 + .../jdk/incubator/vector/Long256Vector.java | 7 + .../jdk/incubator/vector/Long512Vector.java | 7 + .../jdk/incubator/vector/Long64Vector.java | 7 + .../jdk/incubator/vector/LongMaxVector.java | 7 + .../jdk/incubator/vector/LongVector.java | 29 ++ .../jdk/incubator/vector/Short128Vector.java | 7 + .../jdk/incubator/vector/Short256Vector.java | 7 + .../jdk/incubator/vector/Short512Vector.java | 7 + .../jdk/incubator/vector/Short64Vector.java | 7 + .../jdk/incubator/vector/ShortMaxVector.java | 7 + .../jdk/incubator/vector/ShortVector.java | 29 ++ .../classes/jdk/incubator/vector/Vector.java | 55 ++++ .../jdk/incubator/vector/VectorOperators.java | 1 + .../incubator/vector/X-Vector.java.template | 29 ++ .../vector/X-VectorBits.java.template | 7 + .../incubator/vector/Byte128VectorTests.java | 55 ++++ .../incubator/vector/Byte256VectorTests.java | 55 ++++ .../incubator/vector/Byte512VectorTests.java | 55 ++++ .../incubator/vector/Byte64VectorTests.java | 55 ++++ .../incubator/vector/ByteMaxVectorTests.java | 55 ++++ .../vector/Double128VectorTests.java | 55 ++++ .../vector/Double256VectorTests.java | 55 ++++ .../vector/Double512VectorTests.java | 55 ++++ .../incubator/vector/Double64VectorTests.java | 55 ++++ .../vector/DoubleMaxVectorTests.java | 55 ++++ .../incubator/vector/Float128VectorTests.java | 55 ++++ .../incubator/vector/Float256VectorTests.java | 55 ++++ .../incubator/vector/Float512VectorTests.java | 55 ++++ .../incubator/vector/Float64VectorTests.java | 55 ++++ .../incubator/vector/FloatMaxVectorTests.java | 55 ++++ .../incubator/vector/Int128VectorTests.java | 55 ++++ .../incubator/vector/Int256VectorTests.java | 55 ++++ .../incubator/vector/Int512VectorTests.java | 55 ++++ .../incubator/vector/Int64VectorTests.java | 55 ++++ .../incubator/vector/IntMaxVectorTests.java | 55 ++++ .../incubator/vector/Long128VectorTests.java | 55 ++++ .../incubator/vector/Long256VectorTests.java | 55 ++++ .../incubator/vector/Long512VectorTests.java | 55 ++++ .../incubator/vector/Long64VectorTests.java | 55 ++++ .../incubator/vector/LongMaxVectorTests.java | 55 ++++ .../incubator/vector/Short128VectorTests.java | 55 ++++ .../incubator/vector/Short256VectorTests.java | 55 ++++ .../incubator/vector/Short512VectorTests.java | 55 ++++ .../incubator/vector/Short64VectorTests.java | 55 ++++ .../incubator/vector/ShortMaxVectorTests.java | 55 ++++ .../templates/Unit-Miscellaneous.template | 18 ++ .../vector/templates/Unit-header.template | 37 +++ .../incubator/vector/SelectFromBenchmark.java | 251 ++++++++++++++++++ 89 files changed, 2787 insertions(+), 19 deletions(-) create mode 100644 test/micro/org/openjdk/bench/jdk/incubator/vector/SelectFromBenchmark.java diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp index c1679cd111f5a..8b61fd27de0f0 100644 --- a/src/hotspot/cpu/x86/assembler_x86.cpp +++ b/src/hotspot/cpu/x86/assembler_x86.cpp @@ -4738,22 +4738,6 @@ void Assembler::vpermpd(XMMRegister dst, XMMRegister src, int imm8, int vector_l emit_int24(0x01, (0xC0 | encode), imm8); } -void Assembler::evpermi2q(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { - assert(VM_Version::supports_evex(), ""); - InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); - attributes.set_is_evex_instruction(); - int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); - emit_int16(0x76, (0xC0 | encode)); -} - -void Assembler::evpermt2b(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { - assert(VM_Version::supports_avx512_vbmi(), ""); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); - attributes.set_is_evex_instruction(); - int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); - emit_int16(0x7D, (0xC0 | encode)); -} - void Assembler::evpmultishiftqb(XMMRegister dst, XMMRegister ctl, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx512_vbmi(), ""); InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); @@ -16103,3 +16087,59 @@ void InstructionAttr::set_address_attributes(int tuple_type, int input_size_in_b _input_size_in_bits = input_size_in_bits; } } + +void Assembler::evpermi2b(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx512_vbmi() && (vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x75, (0xC0 | encode)); +} + +void Assembler::evpermi2w(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx512bw() && (vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x75, (0xC0 | encode)); +} + +void Assembler::evpermi2d(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_evex() && (vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x76, (0xC0 | encode)); +} + +void Assembler::evpermi2q(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_evex() && (vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x76, (0xC0 | encode)); +} + +void Assembler::evpermi2ps(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_evex() && (vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x77, (0xC0 | encode)); +} + +void Assembler::evpermi2pd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_evex() && (vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl()), ""); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x77, (0xC0 | encode)); +} + +void Assembler::evpermt2b(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx512_vbmi(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x7D, (0xC0 | encode)); +} diff --git a/src/hotspot/cpu/x86/assembler_x86.hpp b/src/hotspot/cpu/x86/assembler_x86.hpp index eace7bb9cc169..696fff5e3eb79 100644 --- a/src/hotspot/cpu/x86/assembler_x86.hpp +++ b/src/hotspot/cpu/x86/assembler_x86.hpp @@ -1962,9 +1962,14 @@ class Assembler : public AbstractAssembler { void vpermilps(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void vpermilpd(XMMRegister dst, XMMRegister src, int imm8, int vector_len); void vpermpd(XMMRegister dst, XMMRegister src, int imm8, int vector_len); + void evpmultishiftqb(XMMRegister dst, XMMRegister ctl, XMMRegister src, int vector_len); + void evpermi2b(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void evpermi2w(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void evpermi2d(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void evpermi2q(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void evpermi2ps(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void evpermi2pd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void evpermt2b(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); - void evpmultishiftqb(XMMRegister dst, XMMRegister ctl, XMMRegister src, int vector_len); void pause(); diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index aba5344b7e434..0eab2de2c64a4 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -6475,3 +6475,30 @@ void C2_MacroAssembler::vector_rearrange_int_float(BasicType bt, XMMRegister dst vpermps(dst, shuffle, src, vlen_enc); } } + +void C2_MacroAssembler::select_from_two_vectors_evex(BasicType elem_bt, XMMRegister dst, XMMRegister src1, + XMMRegister src2, int vlen_enc) { + switch(elem_bt) { + case T_BYTE: + evpermi2b(dst, src1, src2, vlen_enc); + break; + case T_SHORT: + evpermi2w(dst, src1, src2, vlen_enc); + break; + case T_INT: + evpermi2d(dst, src1, src2, vlen_enc); + break; + case T_LONG: + evpermi2q(dst, src1, src2, vlen_enc); + break; + case T_FLOAT: + evpermi2ps(dst, src1, src2, vlen_enc); + break; + case T_DOUBLE: + evpermi2pd(dst, src1, src2, vlen_enc); + break; + default: + fatal("Unsupported type %s", type2name(elem_bt)); + break; + } +} diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp index af57546b3d143..5744fedcc64ec 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp @@ -505,4 +505,6 @@ void vgather8b_offset(BasicType elem_bt, XMMRegister dst, Register base, Register idx_base, Register offset, Register rtmp, int vlen_enc); + void select_from_two_vectors_evex(BasicType elem_bt, XMMRegister dst, XMMRegister src1, XMMRegister src2, int vlen_enc); + #endif // CPU_X86_C2_MACROASSEMBLER_X86_HPP diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index c88fa1ec5ce15..7684febb8ae46 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -1935,6 +1935,20 @@ bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType bt) { return false; } break; + case Op_SelectFromTwoVector: + if (size_in_bits < 128 || (size_in_bits < 512 && !VM_Version::supports_avx512vl())) { + return false; + } + if (bt == T_SHORT && !VM_Version::supports_avx512bw()) { + return false; + } + if (bt == T_BYTE && !VM_Version::supports_avx512_vbmi()) { + return false; + } + if ((bt == T_INT || bt == T_FLOAT || bt == T_DOUBLE) && !VM_Version::supports_evex()) { + return false; + } + break; case Op_MaskAll: if (!VM_Version::supports_evex()) { return false; @@ -10468,3 +10482,16 @@ instruct DoubleClassCheck_reg_reg_vfpclass(rRegI dst, regD src, kReg ktmp, rFlag %} ins_pipe(pipe_slow); %} + + +instruct vector_selectfrom_twovectors_reg_evex(vec index, vec src1, vec src2) +%{ + match(Set index (SelectFromTwoVector (Binary index src1) src2)); + format %{ "select_from_two_vector $index, $src1, $src2 \t!" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + BasicType bt = Matcher::vector_element_basic_type(this); + __ select_from_two_vectors_evex(bt, $index$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vlen_enc); + %} + ins_pipe(pipe_slow); +%} diff --git a/src/hotspot/share/adlc/formssel.cpp b/src/hotspot/share/adlc/formssel.cpp index ac2d3d94153f7..e7dd00fa3909c 100644 --- a/src/hotspot/share/adlc/formssel.cpp +++ b/src/hotspot/share/adlc/formssel.cpp @@ -4355,7 +4355,7 @@ bool MatchRule::is_vector() const { "Replicate","ReverseV","ReverseBytesV", "RoundDoubleModeV","RotateLeftV" , "RotateRightV", "LoadVector","StoreVector", "LoadVectorGather", "StoreVectorScatter", "LoadVectorGatherMasked", "StoreVectorScatterMasked", - "VectorTest", "VectorLoadMask", "VectorStoreMask", "VectorBlend", "VectorInsert", + "SelectFromTwoVector", "VectorTest", "VectorLoadMask", "VectorStoreMask", "VectorBlend", "VectorInsert", "VectorRearrange", "VectorLoadShuffle", "VectorLoadConst", "VectorCastB2X", "VectorCastS2X", "VectorCastI2X", "VectorCastL2X", "VectorCastF2X", "VectorCastD2X", "VectorCastF2HF", "VectorCastHF2F", diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp index 9bb8b2179ae01..54912a5ded72f 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.hpp +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp @@ -981,6 +981,17 @@ class methodHandle; "Ljdk/internal/vm/vector/VectorSupport$Vector;") \ do_name(vector_ternary_op_name, "ternaryOp") \ \ + do_intrinsic(_VectorSelectFromTwoVectorOp, jdk_internal_vm_vector_VectorSupport, vector_select_from_op_name, vector_select_from_op_sig, F_S) \ + do_signature(vector_select_from_op_sig, "(Ljava/lang/Class;" \ + "Ljava/lang/Class;" \ + "I" \ + "Ljdk/internal/vm/vector/VectorSupport$Vector;" \ + "Ljdk/internal/vm/vector/VectorSupport$Vector;" \ + "Ljdk/internal/vm/vector/VectorSupport$Vector;" \ + "Ljdk/internal/vm/vector/VectorSupport$SelectFromTwoVector;)" \ + "Ljdk/internal/vm/vector/VectorSupport$Vector;") \ + do_name(vector_select_from_op_name, "selectFromTwoVectorOp") \ + \ do_intrinsic(_VectorFromBitsCoerced, jdk_internal_vm_vector_VectorSupport, vector_frombits_coerced_name, vector_frombits_coerced_sig, F_S) \ do_signature(vector_frombits_coerced_sig, "(Ljava/lang/Class;" \ "Ljava/lang/Class;" \ diff --git a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp index 1a00f17f50530..fa0abf2deb12c 100644 --- a/src/hotspot/share/opto/c2compiler.cpp +++ b/src/hotspot/share/opto/c2compiler.cpp @@ -818,6 +818,7 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) { case vmIntrinsics::_VectorLoadMaskedOp: case vmIntrinsics::_VectorStoreOp: case vmIntrinsics::_VectorStoreMaskedOp: + case vmIntrinsics::_VectorSelectFromTwoVectorOp: case vmIntrinsics::_VectorGatherOp: case vmIntrinsics::_VectorScatterOp: case vmIntrinsics::_VectorReductionCoerced: diff --git a/src/hotspot/share/opto/classes.hpp b/src/hotspot/share/opto/classes.hpp index 215e48ef9da9c..de6d48ebdf99c 100644 --- a/src/hotspot/share/opto/classes.hpp +++ b/src/hotspot/share/opto/classes.hpp @@ -482,6 +482,7 @@ macro(Digit) macro(LowerCase) macro(UpperCase) macro(Whitespace) +macro(SelectFromTwoVector) macro(VectorBox) macro(VectorBoxAllocate) macro(VectorUnbox) diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 49750cd2697e9..c7c9da18e5412 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -755,6 +755,8 @@ bool LibraryCallKit::try_to_inline(int predicate) { return inline_vector_extract(); case vmIntrinsics::_VectorCompressExpand: return inline_vector_compress_expand(); + case vmIntrinsics::_VectorSelectFromTwoVectorOp: + return inline_vector_select_from_two_vectors(); case vmIntrinsics::_IndexVector: return inline_index_vector(); case vmIntrinsics::_IndexPartiallyInUpperRange: diff --git a/src/hotspot/share/opto/library_call.hpp b/src/hotspot/share/opto/library_call.hpp index c9b2a02d3f1ab..c5437e3bf73f0 100644 --- a/src/hotspot/share/opto/library_call.hpp +++ b/src/hotspot/share/opto/library_call.hpp @@ -374,6 +374,7 @@ class LibraryCallKit : public GraphKit { bool inline_vector_compress_expand(); bool inline_index_vector(); bool inline_index_partially_in_upper_range(); + bool inline_vector_select_from_two_vectors(); Node* gen_call_to_vector_math(int vector_api_op_id, BasicType bt, int num_elem, Node* opd1, Node* opd2); diff --git a/src/hotspot/share/opto/matcher.cpp b/src/hotspot/share/opto/matcher.cpp index 2031b09ca9d18..920178a0d0407 100644 --- a/src/hotspot/share/opto/matcher.cpp +++ b/src/hotspot/share/opto/matcher.cpp @@ -2436,6 +2436,7 @@ void Matcher::find_shared_post_visit(Node* n, uint opcode) { n->del_req(4); break; } + case Op_SelectFromTwoVector: case Op_LoopLimit: { Node* pair1 = new BinaryNode(n->in(1), n->in(2)); n->set_req(1, pair1); diff --git a/src/hotspot/share/opto/vectorIntrinsics.cpp b/src/hotspot/share/opto/vectorIntrinsics.cpp index 838f87eac011f..fe1807b9588c5 100644 --- a/src/hotspot/share/opto/vectorIntrinsics.cpp +++ b/src/hotspot/share/opto/vectorIntrinsics.cpp @@ -2356,9 +2356,10 @@ bool LibraryCallKit::inline_vector_broadcast_int() { } Node* cnt = argument(6); + const TypeInt* cnt_type = cnt->bottom_type()->isa_int(); + ciKlass* vbox_klass = vector_klass->const_oop()->as_instance()->java_lang_Class_klass(); const TypeInstPtr* vbox_type = TypeInstPtr::make_exact(TypePtr::NotNull, vbox_klass); - const TypeInt* cnt_type = cnt->bottom_type()->isa_int(); // If CPU supports vector constant rotate instructions pass it directly bool is_const_rotate = is_rotate && cnt_type && cnt_type->is_con() && @@ -2841,6 +2842,188 @@ bool LibraryCallKit::inline_vector_extract() { return true; } +static Node* LowerSelectFromTwoVectorOperation(PhaseGVN& phase, Node* index_vec, Node* src1, Node* src2, const TypeVect* vt) { + int num_elem = vt->length(); + BasicType elem_bt = vt->element_basic_type(); + + // Lower selectFrom operation into its constituent operations. + // SelectFromTwoVectorNode = + // (VectorBlend + // (VectorRearrange SRC1 (WRAPED_INDEX AND (VLEN-1)) + // (VectorRearrange SRC2 (WRAPED_INDEX AND (VLEN-1)) + // MASK) + // Where + // WRAPED_INDEX are computed by wrapping incoming indexes + // to two vector index range [0, VLEN*2) and + // MASK = WRAPED_INDEX < VLEN + // + // IR lowering prevents intrinsification failure and associated argument + // boxing penalties. + // + + const TypeVect* index_vect_type = index_vec->bottom_type()->is_vect(); + BasicType index_elem_bt = index_vect_type->element_basic_type(); + + // Downcast index vector to a type agnostic shuffle representation, shuffle + // indices are held in a byte vector which are later transformed to target + // specific permutation index format by subsequent VectorLoadShuffle. + int cast_vopc = VectorCastNode::opcode(0, index_elem_bt, true); + Node* index_byte_vec = phase.transform(VectorCastNode::make(cast_vopc, index_vec, T_BYTE, num_elem)); + + // Wrap indexes into two vector index range [0, VLEN * 2) + Node* two_vect_lane_cnt_m1 = phase.makecon(TypeInt::make(2 * num_elem - 1)); + Node* bcast_two_vect_lane_cnt_m1_vec = phase.transform(VectorNode::scalar2vector(two_vect_lane_cnt_m1, num_elem, + Type::get_const_basic_type(T_BYTE), false)); + index_byte_vec = phase.transform(VectorNode::make(Op_AndV, index_byte_vec, bcast_two_vect_lane_cnt_m1_vec, + index_byte_vec->bottom_type()->is_vect())); + + // Compute the blend mask for merging two independently permitted vectors + // using shuffle index in two vector index range [0, VLEN * 2). + BoolTest::mask pred = BoolTest::le; + ConINode* pred_node = phase.makecon(TypeInt::make(pred))->as_ConI(); + const TypeVect* vmask_type = TypeVect::makemask(T_BYTE, num_elem); + Node* lane_cnt_m1 = phase.makecon(TypeInt::make(num_elem - 1)); + Node* bcast_lane_cnt_m1_vec = phase.transform(VectorNode::scalar2vector(lane_cnt_m1, num_elem, + Type::get_const_basic_type(T_BYTE), false)); + Node* mask = phase.transform(new VectorMaskCmpNode(pred, index_byte_vec, bcast_lane_cnt_m1_vec, pred_node, vmask_type)); + + // Rearrange expects the indexes to lie within single vector index range [0, VLEN). + index_byte_vec = phase.transform(VectorNode::make(Op_AndV, index_byte_vec, bcast_lane_cnt_m1_vec, + index_byte_vec->bottom_type()->is_vect())); + + // Load indexes from byte vector and appropriately transform them to target + // specific permutation index format. + index_vec = phase.transform(new VectorLoadShuffleNode(index_byte_vec, index_vect_type)); + + vmask_type = TypeVect::makemask(elem_bt, num_elem); + mask = phase.transform(new VectorMaskCastNode(mask, vmask_type)); + + Node* p1 = phase.transform(new VectorRearrangeNode(src1, index_vec)); + Node* p2 = phase.transform(new VectorRearrangeNode(src2, index_vec)); + + return new VectorBlendNode(p2, p1, mask); +} + +// public static +// , +// E> +// V selectFromTwoVectorOp(Class vClass, Class eClass, int length, +// V v1, V v2, V v3, +// SelectFromTwoVector defaultImpl) +bool LibraryCallKit::inline_vector_select_from_two_vectors() { + const TypeInstPtr* vector_klass = gvn().type(argument(0))->isa_instptr(); + const TypeInstPtr* elem_klass = gvn().type(argument(1))->isa_instptr(); + const TypeInt* vlen = gvn().type(argument(2))->isa_int(); + + if (vector_klass == nullptr || elem_klass == nullptr || vlen == nullptr || vector_klass->const_oop() == nullptr || + elem_klass->const_oop() == nullptr ||!vlen->is_con()) { + log_if_needed(" ** missing constant: vclass=%s etype=%s vlen=%s", + NodeClassNames[argument(0)->Opcode()], + NodeClassNames[argument(1)->Opcode()], + NodeClassNames[argument(2)->Opcode()]); + return false; // not enough info for intrinsification + } + + if (!is_klass_initialized(vector_klass)) { + log_if_needed(" ** klass argument not initialized"); + return false; + } + + ciType* elem_type = elem_klass->const_oop()->as_instance()->java_mirror_type(); + if (!elem_type->is_primitive_type()) { + log_if_needed(" ** not a primitive bt=%d", elem_type->basic_type()); + return false; // should be primitive type + } + + int num_elem = vlen->get_con(); + if (!is_power_of_2(num_elem)) { + log_if_needed(" ** vlen is not power of two=%d", num_elem); + return false; + } + + BasicType elem_bt = elem_type->basic_type(); + BasicType index_elem_bt = elem_bt; + if (elem_bt == T_FLOAT) { + index_elem_bt = T_INT; + } else if (elem_bt == T_DOUBLE) { + index_elem_bt = T_LONG; + } + + bool lowerSelectFromOp = false; + if (!arch_supports_vector(Op_SelectFromTwoVector, num_elem, elem_bt, VecMaskNotUsed)) { + int cast_vopc = VectorCastNode::opcode(-1, elem_bt, true); + if (!arch_supports_vector(Op_VectorMaskCmp, num_elem, T_BYTE, VecMaskNotUsed) || + !arch_supports_vector(Op_AndV, num_elem, T_BYTE, VecMaskNotUsed) || + !arch_supports_vector(Op_VectorMaskCast, num_elem, elem_bt, VecMaskNotUsed) || + !arch_supports_vector(Op_VectorBlend, num_elem, elem_bt, VecMaskUseLoad) || + !arch_supports_vector(Op_VectorRearrange, num_elem, elem_bt, VecMaskNotUsed) || + !arch_supports_vector(cast_vopc, num_elem, T_BYTE, VecMaskNotUsed) || + !arch_supports_vector(Op_VectorLoadShuffle, num_elem, index_elem_bt, VecMaskNotUsed) || + !arch_supports_vector(Op_Replicate, num_elem, T_BYTE, VecMaskNotUsed)) { + log_if_needed(" ** not supported: opc=%d vlen=%d etype=%s ismask=useload", + Op_SelectFromTwoVector, num_elem, type2name(elem_bt)); + return false; // not supported + } + lowerSelectFromOp = true; + } + + int cast_vopc = VectorCastNode::opcode(-1, elem_bt, true); + if (!lowerSelectFromOp) { + if (!arch_supports_vector(Op_AndV, num_elem, index_elem_bt, VecMaskNotUsed) || + !arch_supports_vector(Op_Replicate, num_elem, index_elem_bt, VecMaskNotUsed) || + (is_floating_point_type(elem_bt) && + !arch_supports_vector(cast_vopc, num_elem, index_elem_bt, VecMaskNotUsed))) { + log_if_needed(" ** index wrapping not supported: vlen=%d etype=%s" , + num_elem, type2name(elem_bt)); + return false; // not supported + } + } + + ciKlass* vbox_klass = vector_klass->const_oop()->as_instance()->java_lang_Class_klass(); + const TypeInstPtr* vbox_type = TypeInstPtr::make_exact(TypePtr::NotNull, vbox_klass); + + Node* opd1 = unbox_vector(argument(3), vbox_type, elem_bt, num_elem); + if (opd1 == nullptr) { + log_if_needed(" ** unbox failed v1=%s", + NodeClassNames[argument(3)->Opcode()]); + return false; + } + Node* opd2 = unbox_vector(argument(4), vbox_type, elem_bt, num_elem); + if (opd2 == nullptr) { + log_if_needed(" ** unbox failed v2=%s", + NodeClassNames[argument(4)->Opcode()]); + return false; + } + Node* opd3 = unbox_vector(argument(5), vbox_type, elem_bt, num_elem); + if (opd3 == nullptr) { + log_if_needed(" ** unbox failed v3=%s", + NodeClassNames[argument(5)->Opcode()]); + return false; + } + + const TypeVect* vt = TypeVect::make(elem_bt, num_elem); + + Node* operation = nullptr; + if (lowerSelectFromOp) { + operation = gvn().transform(LowerSelectFromTwoVectorOperation(gvn(), opd1, opd2, opd3, vt)); + } else { + if (index_elem_bt != elem_bt) { + opd1 = gvn().transform(VectorCastNode::make(cast_vopc, opd1, index_elem_bt, num_elem)); + } + int indexRangeMask = 2 * num_elem - 1; + Node* wrap_mask = gvn().makecon(TypeInteger::make(indexRangeMask, indexRangeMask, Type::WidenMin, index_elem_bt != T_LONG ? T_INT : index_elem_bt)); + Node* wrap_mask_vec = gvn().transform(VectorNode::scalar2vector(wrap_mask, num_elem, Type::get_const_basic_type(index_elem_bt), false)); + opd1 = gvn().transform(VectorNode::make(Op_AndV, opd1, wrap_mask_vec, opd1->bottom_type()->is_vect())); + operation = gvn().transform(VectorNode::make(Op_SelectFromTwoVector, opd1, opd2, opd3, vt)); + } + + // Wrap it up in VectorBox to keep object type information. + Node* vbox = box_vector(operation, vbox_type, elem_bt, num_elem); + set_result(vbox); + C->set_max_vector_size(MAX2(C->max_vector_size(), (uint)(num_elem * type2aelembytes(elem_bt)))); + return true; +} + // public static // , // M extends VectorMask, diff --git a/src/hotspot/share/opto/vectornode.cpp b/src/hotspot/share/opto/vectornode.cpp index 094d4dca564a8..fc1c951cfbdee 100644 --- a/src/hotspot/share/opto/vectornode.cpp +++ b/src/hotspot/share/opto/vectornode.cpp @@ -781,6 +781,7 @@ VectorNode* VectorNode::make(int vopc, Node* n1, Node* n2, Node* n3, const TypeV switch (vopc) { case Op_FmaVD: return new FmaVDNode(n1, n2, n3, vt); case Op_FmaVF: return new FmaVFNode(n1, n2, n3, vt); + case Op_SelectFromTwoVector: return new SelectFromTwoVectorNode(n1, n2, n3, vt); case Op_SignumVD: return new SignumVDNode(n1, n2, n3, vt); case Op_SignumVF: return new SignumVFNode(n1, n2, n3, vt); default: @@ -2078,6 +2079,7 @@ Node* VectorBlendNode::Identity(PhaseGVN* phase) { return this; } + #ifndef PRODUCT void VectorBoxAllocateNode::dump_spec(outputStream *st) const { CallStaticJavaNode::dump_spec(st); diff --git a/src/hotspot/share/opto/vectornode.hpp b/src/hotspot/share/opto/vectornode.hpp index d23e6b8c9268d..256664983ff74 100644 --- a/src/hotspot/share/opto/vectornode.hpp +++ b/src/hotspot/share/opto/vectornode.hpp @@ -1612,6 +1612,21 @@ class VectorRearrangeNode : public VectorNode { Node* vec_shuffle() const { return in(2); } }; + +// Select elements from two source vectors based on the wrapped indexes held in +// the first vector. +class SelectFromTwoVectorNode : public VectorNode { +public: + SelectFromTwoVectorNode(Node* indexes, Node* src1, Node* src2, const TypeVect* vt) + : VectorNode(indexes, src1, src2, vt) { + assert(is_integral_type(indexes->bottom_type()->is_vect()->element_basic_type()), + "indexes must be an integral vector"); + } + + virtual int Opcode() const; +}; + + class VectorLoadShuffleNode : public VectorNode { public: VectorLoadShuffleNode(Node* in, const TypeVect* vt) diff --git a/src/java.base/share/classes/jdk/internal/vm/vector/VectorSupport.java b/src/java.base/share/classes/jdk/internal/vm/vector/VectorSupport.java index 5c4040d912804..63cab418d4648 100644 --- a/src/java.base/share/classes/jdk/internal/vm/vector/VectorSupport.java +++ b/src/java.base/share/classes/jdk/internal/vm/vector/VectorSupport.java @@ -395,6 +395,24 @@ VM binaryOp(int oprId, assert isNonCapturingLambda(defaultImpl) : defaultImpl; return defaultImpl.apply(v1, v2, m); } + /* ============================================================================ */ + + public interface SelectFromTwoVector> { + V apply(V v1, V v2, V v3); + } + + @IntrinsicCandidate + public static + , + E> + V selectFromTwoVectorOp(Class vClass, Class eClass, int length, + V v1, V v2, V v3, + SelectFromTwoVector defaultImpl) { + assert isNonCapturingLambda(defaultImpl) : defaultImpl; + return defaultImpl.apply(v1, v2, v3); + } + + /* ============================================================================ */ /* ============================================================================ */ diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte128Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte128Vector.java index 0bc25958a7617..3cf25d46f441e 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte128Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte128Vector.java @@ -506,6 +506,13 @@ public Byte128Vector selectFrom(Vector v, Byte128Mask.class, (Byte128Mask) m); // specialize } + @Override + @ForceInline + public Byte128Vector selectFrom(Vector v1, + Vector v2) { + return (Byte128Vector) + super.selectFromTemplate((Byte128Vector) v1, (Byte128Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte256Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte256Vector.java index 639646aa77ad5..cb9f2679dcafa 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte256Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte256Vector.java @@ -506,6 +506,13 @@ public Byte256Vector selectFrom(Vector v, Byte256Mask.class, (Byte256Mask) m); // specialize } + @Override + @ForceInline + public Byte256Vector selectFrom(Vector v1, + Vector v2) { + return (Byte256Vector) + super.selectFromTemplate((Byte256Vector) v1, (Byte256Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte512Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte512Vector.java index 2d8151f6800f3..f5ff05757039d 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte512Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte512Vector.java @@ -506,6 +506,13 @@ public Byte512Vector selectFrom(Vector v, Byte512Mask.class, (Byte512Mask) m); // specialize } + @Override + @ForceInline + public Byte512Vector selectFrom(Vector v1, + Vector v2) { + return (Byte512Vector) + super.selectFromTemplate((Byte512Vector) v1, (Byte512Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte64Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte64Vector.java index bc8ed7d704d96..37e8978d7e802 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte64Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte64Vector.java @@ -506,6 +506,13 @@ public Byte64Vector selectFrom(Vector v, Byte64Mask.class, (Byte64Mask) m); // specialize } + @Override + @ForceInline + public Byte64Vector selectFrom(Vector v1, + Vector v2) { + return (Byte64Vector) + super.selectFromTemplate((Byte64Vector) v1, (Byte64Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteMaxVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteMaxVector.java index 597afd8d165b3..17dcf193ceb98 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteMaxVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteMaxVector.java @@ -506,6 +506,13 @@ public ByteMaxVector selectFrom(Vector v, ByteMaxMask.class, (ByteMaxMask) m); // specialize } + @Override + @ForceInline + public ByteMaxVector selectFrom(Vector v1, + Vector v2) { + return (ByteMaxVector) + super.selectFromTemplate((ByteMaxVector) v1, (ByteMaxVector) v2); // specialize + } @ForceInline @Override 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 a23bbc7f70957..11c0fda80a4b8 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 @@ -536,6 +536,19 @@ static ByteVector compressHelper(Vector v, VectorMask m) { return r; } + static ByteVector selectFromTwoVectorHelper(Vector indexes, Vector src1, Vector src2) { + int vlen = indexes.length(); + byte[] res = new byte[vlen]; + byte[] vecPayload1 = ((ByteVector)indexes).vec(); + byte[] vecPayload2 = ((ByteVector)src1).vec(); + byte[] vecPayload3 = ((ByteVector)src2).vec(); + for (int i = 0; i < vlen; i++) { + int wrapped_index = VectorIntrinsics.wrapToRange((int)vecPayload1[i], 2 * vlen); + res[i] = wrapped_index >= vlen ? vecPayload3[wrapped_index - vlen] : vecPayload2[wrapped_index]; + } + return ((ByteVector)src1).vectorFactory(res); + } + // Static factories (other than memory operations) // Note: A surprising behavior in javadoc @@ -2575,6 +2588,22 @@ ByteVector selectFromTemplate(ByteVector v, v2.rearrange(v1.toShuffle(), _m)); } + + /** + * {@inheritDoc} + */ + @Override + public abstract + ByteVector selectFrom(Vector v1, Vector v2); + + + /*package-private*/ + @ForceInline + final ByteVector selectFromTemplate(ByteVector v1, ByteVector v2) { + return VectorSupport.selectFromTwoVectorOp(getClass(), byte.class, length(), this, v1, v2, + (vec1, vec2, vec3) -> selectFromTwoVectorHelper(vec1, vec2, vec3)); + } + /// Ternary operations /** diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double128Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double128Vector.java index 00840026fff9f..3760749264562 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double128Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double128Vector.java @@ -493,6 +493,13 @@ public Double128Vector selectFrom(Vector v, Double128Mask.class, (Double128Mask) m); // specialize } + @Override + @ForceInline + public Double128Vector selectFrom(Vector v1, + Vector v2) { + return (Double128Vector) + super.selectFromTemplate((Double128Vector) v1, (Double128Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double256Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double256Vector.java index 4b42deba73841..2e31a80255091 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double256Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double256Vector.java @@ -493,6 +493,13 @@ public Double256Vector selectFrom(Vector v, Double256Mask.class, (Double256Mask) m); // specialize } + @Override + @ForceInline + public Double256Vector selectFrom(Vector v1, + Vector v2) { + return (Double256Vector) + super.selectFromTemplate((Double256Vector) v1, (Double256Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double512Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double512Vector.java index c188f990c335f..6ed3dd7325c28 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double512Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double512Vector.java @@ -493,6 +493,13 @@ public Double512Vector selectFrom(Vector v, Double512Mask.class, (Double512Mask) m); // specialize } + @Override + @ForceInline + public Double512Vector selectFrom(Vector v1, + Vector v2) { + return (Double512Vector) + super.selectFromTemplate((Double512Vector) v1, (Double512Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double64Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double64Vector.java index 032fa1ac277d9..2e1b21350012a 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double64Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double64Vector.java @@ -493,6 +493,13 @@ public Double64Vector selectFrom(Vector v, Double64Mask.class, (Double64Mask) m); // specialize } + @Override + @ForceInline + public Double64Vector selectFrom(Vector v1, + Vector v2) { + return (Double64Vector) + super.selectFromTemplate((Double64Vector) v1, (Double64Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleMaxVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleMaxVector.java index 7251ec82aa63c..8d69b6fcbc730 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleMaxVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleMaxVector.java @@ -493,6 +493,13 @@ public DoubleMaxVector selectFrom(Vector v, DoubleMaxMask.class, (DoubleMaxMask) m); // specialize } + @Override + @ForceInline + public DoubleMaxVector selectFrom(Vector v1, + Vector v2) { + return (DoubleMaxVector) + super.selectFromTemplate((DoubleMaxVector) v1, (DoubleMaxVector) v2); // specialize + } @ForceInline @Override 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 6cc12048d4632..d7fc2cfa97d1c 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 @@ -525,6 +525,19 @@ static DoubleVector compressHelper(Vector v, VectorMask m) { return r; } + static DoubleVector selectFromTwoVectorHelper(Vector indexes, Vector src1, Vector src2) { + int vlen = indexes.length(); + double[] res = new double[vlen]; + double[] vecPayload1 = ((DoubleVector)indexes).vec(); + double[] vecPayload2 = ((DoubleVector)src1).vec(); + double[] vecPayload3 = ((DoubleVector)src2).vec(); + for (int i = 0; i < vlen; i++) { + int wrapped_index = VectorIntrinsics.wrapToRange((int)vecPayload1[i], 2 * vlen); + res[i] = wrapped_index >= vlen ? vecPayload3[wrapped_index - vlen] : vecPayload2[wrapped_index]; + } + return ((DoubleVector)src1).vectorFactory(res); + } + // Static factories (other than memory operations) // Note: A surprising behavior in javadoc @@ -2417,6 +2430,22 @@ DoubleVector selectFromTemplate(DoubleVector v, v2.rearrange(v1.toShuffle(), _m)); } + + /** + * {@inheritDoc} + */ + @Override + public abstract + DoubleVector selectFrom(Vector v1, Vector v2); + + + /*package-private*/ + @ForceInline + final DoubleVector selectFromTemplate(DoubleVector v1, DoubleVector v2) { + return VectorSupport.selectFromTwoVectorOp(getClass(), double.class, length(), this, v1, v2, + (vec1, vec2, vec3) -> selectFromTwoVectorHelper(vec1, vec2, vec3)); + } + /// Ternary operations diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float128Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float128Vector.java index 2e016725f812b..79239532cc69b 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float128Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float128Vector.java @@ -493,6 +493,13 @@ public Float128Vector selectFrom(Vector v, Float128Mask.class, (Float128Mask) m); // specialize } + @Override + @ForceInline + public Float128Vector selectFrom(Vector v1, + Vector v2) { + return (Float128Vector) + super.selectFromTemplate((Float128Vector) v1, (Float128Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float256Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float256Vector.java index 00e6083588339..5f5a26fd316a3 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float256Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float256Vector.java @@ -493,6 +493,13 @@ public Float256Vector selectFrom(Vector v, Float256Mask.class, (Float256Mask) m); // specialize } + @Override + @ForceInline + public Float256Vector selectFrom(Vector v1, + Vector v2) { + return (Float256Vector) + super.selectFromTemplate((Float256Vector) v1, (Float256Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float512Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float512Vector.java index 1f2a792c52c2e..f8c191ea016e3 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float512Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float512Vector.java @@ -493,6 +493,13 @@ public Float512Vector selectFrom(Vector v, Float512Mask.class, (Float512Mask) m); // specialize } + @Override + @ForceInline + public Float512Vector selectFrom(Vector v1, + Vector v2) { + return (Float512Vector) + super.selectFromTemplate((Float512Vector) v1, (Float512Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float64Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float64Vector.java index 6c913ce84a9ba..9496e5988680b 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float64Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float64Vector.java @@ -493,6 +493,13 @@ public Float64Vector selectFrom(Vector v, Float64Mask.class, (Float64Mask) m); // specialize } + @Override + @ForceInline + public Float64Vector selectFrom(Vector v1, + Vector v2) { + return (Float64Vector) + super.selectFromTemplate((Float64Vector) v1, (Float64Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatMaxVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatMaxVector.java index b9a0a93f91253..6f093957262aa 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatMaxVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatMaxVector.java @@ -493,6 +493,13 @@ public FloatMaxVector selectFrom(Vector v, FloatMaxMask.class, (FloatMaxMask) m); // specialize } + @Override + @ForceInline + public FloatMaxVector selectFrom(Vector v1, + Vector v2) { + return (FloatMaxVector) + super.selectFromTemplate((FloatMaxVector) v1, (FloatMaxVector) v2); // specialize + } @ForceInline @Override 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 b962dc55ce351..098eed06095af 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 @@ -525,6 +525,19 @@ static FloatVector compressHelper(Vector v, VectorMask m) { return r; } + static FloatVector selectFromTwoVectorHelper(Vector indexes, Vector src1, Vector src2) { + int vlen = indexes.length(); + float[] res = new float[vlen]; + float[] vecPayload1 = ((FloatVector)indexes).vec(); + float[] vecPayload2 = ((FloatVector)src1).vec(); + float[] vecPayload3 = ((FloatVector)src2).vec(); + for (int i = 0; i < vlen; i++) { + int wrapped_index = VectorIntrinsics.wrapToRange((int)vecPayload1[i], 2 * vlen); + res[i] = wrapped_index >= vlen ? vecPayload3[wrapped_index - vlen] : vecPayload2[wrapped_index]; + } + return ((FloatVector)src1).vectorFactory(res); + } + // Static factories (other than memory operations) // Note: A surprising behavior in javadoc @@ -2429,6 +2442,22 @@ FloatVector selectFromTemplate(FloatVector v, v2.rearrange(v1.toShuffle(), _m)); } + + /** + * {@inheritDoc} + */ + @Override + public abstract + FloatVector selectFrom(Vector v1, Vector v2); + + + /*package-private*/ + @ForceInline + final FloatVector selectFromTemplate(FloatVector v1, FloatVector v2) { + return VectorSupport.selectFromTwoVectorOp(getClass(), float.class, length(), this, v1, v2, + (vec1, vec2, vec3) -> selectFromTwoVectorHelper(vec1, vec2, vec3)); + } + /// Ternary operations diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int128Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int128Vector.java index f7135e19cb6e2..4aa1e8044b092 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int128Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int128Vector.java @@ -506,6 +506,13 @@ public Int128Vector selectFrom(Vector v, Int128Mask.class, (Int128Mask) m); // specialize } + @Override + @ForceInline + public Int128Vector selectFrom(Vector v1, + Vector v2) { + return (Int128Vector) + super.selectFromTemplate((Int128Vector) v1, (Int128Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int256Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int256Vector.java index 474ff974b3169..753f96f216ff3 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int256Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int256Vector.java @@ -506,6 +506,13 @@ public Int256Vector selectFrom(Vector v, Int256Mask.class, (Int256Mask) m); // specialize } + @Override + @ForceInline + public Int256Vector selectFrom(Vector v1, + Vector v2) { + return (Int256Vector) + super.selectFromTemplate((Int256Vector) v1, (Int256Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int512Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int512Vector.java index 9fec8c0c99f13..8e6ed6fc882e8 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int512Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int512Vector.java @@ -506,6 +506,13 @@ public Int512Vector selectFrom(Vector v, Int512Mask.class, (Int512Mask) m); // specialize } + @Override + @ForceInline + public Int512Vector selectFrom(Vector v1, + Vector v2) { + return (Int512Vector) + super.selectFromTemplate((Int512Vector) v1, (Int512Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int64Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int64Vector.java index 3b3c0723ee1a3..98cd39d9beb03 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int64Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int64Vector.java @@ -506,6 +506,13 @@ public Int64Vector selectFrom(Vector v, Int64Mask.class, (Int64Mask) m); // specialize } + @Override + @ForceInline + public Int64Vector selectFrom(Vector v1, + Vector v2) { + return (Int64Vector) + super.selectFromTemplate((Int64Vector) v1, (Int64Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntMaxVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntMaxVector.java index 5738cb7a4bc94..f301161b980af 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntMaxVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntMaxVector.java @@ -506,6 +506,13 @@ public IntMaxVector selectFrom(Vector v, IntMaxMask.class, (IntMaxMask) m); // specialize } + @Override + @ForceInline + public IntMaxVector selectFrom(Vector v1, + Vector v2) { + return (IntMaxVector) + super.selectFromTemplate((IntMaxVector) v1, (IntMaxVector) v2); // specialize + } @ForceInline @Override 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 16b5ceecba35e..b61e2fc991efd 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 @@ -536,6 +536,19 @@ static IntVector compressHelper(Vector v, VectorMask m) { return r; } + static IntVector selectFromTwoVectorHelper(Vector indexes, Vector src1, Vector src2) { + int vlen = indexes.length(); + int[] res = new int[vlen]; + int[] vecPayload1 = ((IntVector)indexes).vec(); + int[] vecPayload2 = ((IntVector)src1).vec(); + int[] vecPayload3 = ((IntVector)src2).vec(); + for (int i = 0; i < vlen; i++) { + int wrapped_index = VectorIntrinsics.wrapToRange((int)vecPayload1[i], 2 * vlen); + res[i] = wrapped_index >= vlen ? vecPayload3[wrapped_index - vlen] : vecPayload2[wrapped_index]; + } + return ((IntVector)src1).vectorFactory(res); + } + // Static factories (other than memory operations) // Note: A surprising behavior in javadoc @@ -2560,6 +2573,22 @@ IntVector selectFromTemplate(IntVector v, v2.rearrange(v1.toShuffle(), _m)); } + + /** + * {@inheritDoc} + */ + @Override + public abstract + IntVector selectFrom(Vector v1, Vector v2); + + + /*package-private*/ + @ForceInline + final IntVector selectFromTemplate(IntVector v1, IntVector v2) { + return VectorSupport.selectFromTwoVectorOp(getClass(), int.class, length(), this, v1, v2, + (vec1, vec2, vec3) -> selectFromTwoVectorHelper(vec1, vec2, vec3)); + } + /// Ternary operations /** diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long128Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long128Vector.java index 567789627c6cb..c65816a4d6c88 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long128Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long128Vector.java @@ -496,6 +496,13 @@ public Long128Vector selectFrom(Vector v, Long128Mask.class, (Long128Mask) m); // specialize } + @Override + @ForceInline + public Long128Vector selectFrom(Vector v1, + Vector v2) { + return (Long128Vector) + super.selectFromTemplate((Long128Vector) v1, (Long128Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long256Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long256Vector.java index 5ef0f121464f6..7ca3e43e92b87 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long256Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long256Vector.java @@ -496,6 +496,13 @@ public Long256Vector selectFrom(Vector v, Long256Mask.class, (Long256Mask) m); // specialize } + @Override + @ForceInline + public Long256Vector selectFrom(Vector v1, + Vector v2) { + return (Long256Vector) + super.selectFromTemplate((Long256Vector) v1, (Long256Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long512Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long512Vector.java index acdb471609f22..317cac1f11085 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long512Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long512Vector.java @@ -496,6 +496,13 @@ public Long512Vector selectFrom(Vector v, Long512Mask.class, (Long512Mask) m); // specialize } + @Override + @ForceInline + public Long512Vector selectFrom(Vector v1, + Vector v2) { + return (Long512Vector) + super.selectFromTemplate((Long512Vector) v1, (Long512Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long64Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long64Vector.java index 627f7437367cb..b13712595dbdd 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long64Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long64Vector.java @@ -496,6 +496,13 @@ public Long64Vector selectFrom(Vector v, Long64Mask.class, (Long64Mask) m); // specialize } + @Override + @ForceInline + public Long64Vector selectFrom(Vector v1, + Vector v2) { + return (Long64Vector) + super.selectFromTemplate((Long64Vector) v1, (Long64Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongMaxVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongMaxVector.java index aec3bb89fcd02..9edc442be88ac 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongMaxVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongMaxVector.java @@ -496,6 +496,13 @@ public LongMaxVector selectFrom(Vector v, LongMaxMask.class, (LongMaxMask) m); // specialize } + @Override + @ForceInline + public LongMaxVector selectFrom(Vector v1, + Vector v2) { + return (LongMaxVector) + super.selectFromTemplate((LongMaxVector) v1, (LongMaxVector) v2); // specialize + } @ForceInline @Override 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 15ac2bc7b7f6c..68166bd985232 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 @@ -536,6 +536,19 @@ static LongVector compressHelper(Vector v, VectorMask m) { return r; } + static LongVector selectFromTwoVectorHelper(Vector indexes, Vector src1, Vector src2) { + int vlen = indexes.length(); + long[] res = new long[vlen]; + long[] vecPayload1 = ((LongVector)indexes).vec(); + long[] vecPayload2 = ((LongVector)src1).vec(); + long[] vecPayload3 = ((LongVector)src2).vec(); + for (int i = 0; i < vlen; i++) { + int wrapped_index = VectorIntrinsics.wrapToRange((int)vecPayload1[i], 2 * vlen); + res[i] = wrapped_index >= vlen ? vecPayload3[wrapped_index - vlen] : vecPayload2[wrapped_index]; + } + return ((LongVector)src1).vectorFactory(res); + } + // Static factories (other than memory operations) // Note: A surprising behavior in javadoc @@ -2426,6 +2439,22 @@ LongVector selectFromTemplate(LongVector v, v2.rearrange(v1.toShuffle(), _m)); } + + /** + * {@inheritDoc} + */ + @Override + public abstract + LongVector selectFrom(Vector v1, Vector v2); + + + /*package-private*/ + @ForceInline + final LongVector selectFromTemplate(LongVector v1, LongVector v2) { + return VectorSupport.selectFromTwoVectorOp(getClass(), long.class, length(), this, v1, v2, + (vec1, vec2, vec3) -> selectFromTwoVectorHelper(vec1, vec2, vec3)); + } + /// Ternary operations /** diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short128Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short128Vector.java index fe34886512a13..b013e4b282586 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short128Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short128Vector.java @@ -506,6 +506,13 @@ public Short128Vector selectFrom(Vector v, Short128Mask.class, (Short128Mask) m); // specialize } + @Override + @ForceInline + public Short128Vector selectFrom(Vector v1, + Vector v2) { + return (Short128Vector) + super.selectFromTemplate((Short128Vector) v1, (Short128Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short256Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short256Vector.java index 243e24ad26bef..af4c862eaf3b6 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short256Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short256Vector.java @@ -506,6 +506,13 @@ public Short256Vector selectFrom(Vector v, Short256Mask.class, (Short256Mask) m); // specialize } + @Override + @ForceInline + public Short256Vector selectFrom(Vector v1, + Vector v2) { + return (Short256Vector) + super.selectFromTemplate((Short256Vector) v1, (Short256Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short512Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short512Vector.java index 4114783608960..3bb019f3b7cbf 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short512Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short512Vector.java @@ -506,6 +506,13 @@ public Short512Vector selectFrom(Vector v, Short512Mask.class, (Short512Mask) m); // specialize } + @Override + @ForceInline + public Short512Vector selectFrom(Vector v1, + Vector v2) { + return (Short512Vector) + super.selectFromTemplate((Short512Vector) v1, (Short512Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short64Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short64Vector.java index d80d4c4e2ec52..905e313e95c1c 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short64Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short64Vector.java @@ -506,6 +506,13 @@ public Short64Vector selectFrom(Vector v, Short64Mask.class, (Short64Mask) m); // specialize } + @Override + @ForceInline + public Short64Vector selectFrom(Vector v1, + Vector v2) { + return (Short64Vector) + super.selectFromTemplate((Short64Vector) v1, (Short64Vector) v2); // specialize + } @ForceInline @Override diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortMaxVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortMaxVector.java index 799483a667590..5bb1beee6edd2 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortMaxVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortMaxVector.java @@ -506,6 +506,13 @@ public ShortMaxVector selectFrom(Vector v, ShortMaxMask.class, (ShortMaxMask) m); // specialize } + @Override + @ForceInline + public ShortMaxVector selectFrom(Vector v1, + Vector v2) { + return (ShortMaxVector) + super.selectFromTemplate((ShortMaxVector) v1, (ShortMaxVector) v2); // specialize + } @ForceInline @Override 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 fb0512fd5b9ea..2f1ea210b904c 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 @@ -536,6 +536,19 @@ static ShortVector compressHelper(Vector v, VectorMask m) { return r; } + static ShortVector selectFromTwoVectorHelper(Vector indexes, Vector src1, Vector src2) { + int vlen = indexes.length(); + short[] res = new short[vlen]; + short[] vecPayload1 = ((ShortVector)indexes).vec(); + short[] vecPayload2 = ((ShortVector)src1).vec(); + short[] vecPayload3 = ((ShortVector)src2).vec(); + for (int i = 0; i < vlen; i++) { + int wrapped_index = VectorIntrinsics.wrapToRange((int)vecPayload1[i], 2 * vlen); + res[i] = wrapped_index >= vlen ? vecPayload3[wrapped_index - vlen] : vecPayload2[wrapped_index]; + } + return ((ShortVector)src1).vectorFactory(res); + } + // Static factories (other than memory operations) // Note: A surprising behavior in javadoc @@ -2576,6 +2589,22 @@ ShortVector selectFromTemplate(ShortVector v, v2.rearrange(v1.toShuffle(), _m)); } + + /** + * {@inheritDoc} + */ + @Override + public abstract + ShortVector selectFrom(Vector v1, Vector v2); + + + /*package-private*/ + @ForceInline + final ShortVector selectFromTemplate(ShortVector v1, ShortVector v2) { + return VectorSupport.selectFromTwoVectorOp(getClass(), short.class, length(), this, v1, v2, + (vec1, vec2, vec3) -> selectFromTwoVectorHelper(vec1, vec2, vec3)); + } + /// Ternary operations /** diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Vector.java index fda073f686389..5b6dd3d09ac10 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Vector.java @@ -2756,6 +2756,61 @@ public abstract VectorMask compare(VectorOperators.Comparison op, */ public abstract Vector selectFrom(Vector v); + /** + * Using values stored in the lanes of this vector, + * assemble values stored in the second vector {@code v1} + * and third vector {@code v2}. The second and third vectors thus + * serve as a table, whose elements are selected by indexes + * in this vector. + * + * This is a cross-lane operation that rearranges the lane + * elements of the argument vectors, under the control of + * this vector. + * + * For each lane {@code N} of this vector, and for each lane + * value {@code I=wrapIndex(this.lane(N)} in this vector, + * the output lane {@code N} obtains the value from + * the second vector at lane {@code I} if {@code I < VLENGTH}. + * Otherwise, the output lane {@code N} obtains the value from + * the third vector at lane {@code I - VLENGTH}. + * + * Here, {@code VLENGTH} is the result of {@code this.length()}, + * and for integral values {@code wrapIndex} computes the result of + * {@code Math.floorMod(E, 2 * VLENGTH)}, where {@code E} is the index + * to be wrapped. As long as {@code VLENGTH} is a power of two, then the + * result is also equal to {@code E & (2 * VLENGTH - 1)}. + * + * For floating point values {@code wrapIndex} computes + * {@code Math.floorMod(convert(E), 2 * VLENGTH)}, where {@code convert} + * converts the floating point value to an integral value with the same + * number of representational bits - as in converting a double value to + * a long value ({@code (long)doubleVal}), or a float value to an int value + * ({@code (int)floatVal}). + * + * In this way, the result contains only values stored in the + * argument vectors {@code v1} and {@code v2}, but presented in + * an order which depends on the index values in {@code this}. + * + * The result for integral values is the same as the expression + * {@snippet lang=java : + * v1.rearrange( + * this.lanewise(VectorOperators.AND, 2 * VLENGTH - 1).toShuffle(), + * v2) + * } + * when {@code VLENGTH} is a power of two. + * The lane-wise {@code AND} operation results in a vector whose + * elements are in the range {@code [0, 2 * VLENGTH - 1])}. The shuffle + * conversion results in a partially wrapped shuffle whose indexes are + * in the range {@code [-VLENGTH, VLENGTH - 1])}, where exceptional + * indexes are used to select elements in the third vector. + * + * @param v1 the first input vector + * @param v2 the second input vector + * @return the rearrangement of lane elements of {@code v1} and {@code v2} + * @see #rearrange(VectorShuffle,Vector) + */ + public abstract Vector selectFrom(Vector v1, Vector v2); + /** * Using index values stored in the lanes of this vector, * assemble values stored in second vector, under the control diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorOperators.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorOperators.java index 507fe84bfbad3..38c4b1c94feb6 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorOperators.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorOperators.java @@ -563,6 +563,7 @@ static boolean opKind(Operator op, int bit) { public static final /*bitwise*/ Associative OR = assoc("OR", "|", VectorSupport.VECTOR_OP_OR, VO_NOFP+VO_ASSOC); /*package-private*/ /** Version of OR which works on float and double too. */ static final Associative OR_UNCHECKED = assoc("OR_UNCHECKED", "|", VectorSupport.VECTOR_OP_OR, VO_ASSOC+VO_PRIVATE); + /** Produce {@code a^b}. Integral only. */ public static final /*bitwise*/ Associative XOR = assoc("XOR", "^", VectorSupport.VECTOR_OP_XOR, VO_NOFP+VO_ASSOC); 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 fcc128ea8c7b0..b9a48005ccf32 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 @@ -550,6 +550,19 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { return r; } + static $abstractvectortype$ selectFromTwoVectorHelper(Vector<$Boxtype$> indexes, Vector<$Boxtype$> src1, Vector<$Boxtype$> src2) { + int vlen = indexes.length(); + $type$[] res = new $type$[vlen]; + $type$[] vecPayload1 = (($abstractvectortype$)indexes).vec(); + $type$[] vecPayload2 = (($abstractvectortype$)src1).vec(); + $type$[] vecPayload3 = (($abstractvectortype$)src2).vec(); + for (int i = 0; i < vlen; i++) { + int wrapped_index = VectorIntrinsics.wrapToRange((int)vecPayload1[i], 2 * vlen); + res[i] = wrapped_index >= vlen ? vecPayload3[wrapped_index - vlen] : vecPayload2[wrapped_index]; + } + return (($abstractvectortype$)src1).vectorFactory(res); + } + // Static factories (other than memory operations) // Note: A surprising behavior in javadoc @@ -2952,6 +2965,22 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { v2.rearrange(v1.toShuffle(), _m)); } + + /** + * {@inheritDoc} + */ + @Override + public abstract + $abstractvectortype$ selectFrom(Vector<$Boxtype$> v1, Vector<$Boxtype$> v2); + + + /*package-private*/ + @ForceInline + final $abstractvectortype$ selectFromTemplate($abstractvectortype$ v1, $abstractvectortype$ v2) { + return VectorSupport.selectFromTwoVectorOp(getClass(), $type$.class, length(), this, v1, v2, + (vec1, vec2, vec3) -> selectFromTwoVectorHelper(vec1, vec2, vec3)); + } + /// Ternary operations #if[BITWISE] diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-VectorBits.java.template b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-VectorBits.java.template index 483962b4e0670..9752a795ea79d 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-VectorBits.java.template +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-VectorBits.java.template @@ -512,6 +512,13 @@ final class $vectortype$ extends $abstractvectortype$ { $masktype$.class, ($masktype$) m); // specialize } + @Override + @ForceInline + public $vectortype$ selectFrom(Vector<$Boxtype$> v1, + Vector<$Boxtype$> v2) { + return ($vectortype$) + super.selectFromTemplate(($vectortype$) v1, ($vectortype$) v2); // specialize + } #if[FP] @ForceInline diff --git a/test/jdk/jdk/incubator/vector/Byte128VectorTests.java b/test/jdk/jdk/incubator/vector/Byte128VectorTests.java index 77d0dd20974bc..eda803b3f35ab 100644 --- a/test/jdk/jdk/incubator/vector/Byte128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte128VectorTests.java @@ -302,6 +302,25 @@ static void assertexpandArraysEquals(byte[] r, byte[] a, boolean[] m, int vector } } + static void assertSelectFromTwoVectorEquals(byte[] r, byte[] order, byte[] a, byte[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(byte[] r, byte[] a, byte[] order, int vector_len) { int i = 0, j = 0; try { @@ -962,6 +981,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> BYTE_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("byte[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(RAND.nextInt())); + }) + ); + + static final List>> BYTE_GENERATOR_SELECT_FROM_TRIPLES = + BYTE_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] byteBinaryOpProvider() { return BYTE_GENERATOR_PAIRS.stream().map(List::toArray). @@ -989,6 +1020,12 @@ public Object[][] byteTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] byteSelectFromTwoVectorOpProvider() { + return BYTE_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] byteTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -5746,6 +5783,24 @@ static void SelectFromByte128VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "byteSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorByte128VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] idx = fc.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + ByteVector idxv = ByteVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "byteUnaryOpSelectFromMaskProvider") static void SelectFromByte128VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Byte256VectorTests.java b/test/jdk/jdk/incubator/vector/Byte256VectorTests.java index 31e38f633fff8..06cc13c0b128e 100644 --- a/test/jdk/jdk/incubator/vector/Byte256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte256VectorTests.java @@ -302,6 +302,25 @@ static void assertexpandArraysEquals(byte[] r, byte[] a, boolean[] m, int vector } } + static void assertSelectFromTwoVectorEquals(byte[] r, byte[] order, byte[] a, byte[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(byte[] r, byte[] a, byte[] order, int vector_len) { int i = 0, j = 0; try { @@ -962,6 +981,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> BYTE_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("byte[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(RAND.nextInt())); + }) + ); + + static final List>> BYTE_GENERATOR_SELECT_FROM_TRIPLES = + BYTE_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] byteBinaryOpProvider() { return BYTE_GENERATOR_PAIRS.stream().map(List::toArray). @@ -989,6 +1020,12 @@ public Object[][] byteTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] byteSelectFromTwoVectorOpProvider() { + return BYTE_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] byteTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -5746,6 +5783,24 @@ static void SelectFromByte256VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "byteSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorByte256VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] idx = fc.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + ByteVector idxv = ByteVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "byteUnaryOpSelectFromMaskProvider") static void SelectFromByte256VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Byte512VectorTests.java b/test/jdk/jdk/incubator/vector/Byte512VectorTests.java index 9204c3ed1ad37..a75aa42ef20fa 100644 --- a/test/jdk/jdk/incubator/vector/Byte512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte512VectorTests.java @@ -302,6 +302,25 @@ static void assertexpandArraysEquals(byte[] r, byte[] a, boolean[] m, int vector } } + static void assertSelectFromTwoVectorEquals(byte[] r, byte[] order, byte[] a, byte[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(byte[] r, byte[] a, byte[] order, int vector_len) { int i = 0, j = 0; try { @@ -962,6 +981,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> BYTE_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("byte[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(RAND.nextInt())); + }) + ); + + static final List>> BYTE_GENERATOR_SELECT_FROM_TRIPLES = + BYTE_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] byteBinaryOpProvider() { return BYTE_GENERATOR_PAIRS.stream().map(List::toArray). @@ -989,6 +1020,12 @@ public Object[][] byteTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] byteSelectFromTwoVectorOpProvider() { + return BYTE_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] byteTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -5746,6 +5783,24 @@ static void SelectFromByte512VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "byteSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorByte512VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] idx = fc.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + ByteVector idxv = ByteVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "byteUnaryOpSelectFromMaskProvider") static void SelectFromByte512VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Byte64VectorTests.java b/test/jdk/jdk/incubator/vector/Byte64VectorTests.java index 9af640a313393..b621c28a779fb 100644 --- a/test/jdk/jdk/incubator/vector/Byte64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte64VectorTests.java @@ -302,6 +302,25 @@ static void assertexpandArraysEquals(byte[] r, byte[] a, boolean[] m, int vector } } + static void assertSelectFromTwoVectorEquals(byte[] r, byte[] order, byte[] a, byte[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(byte[] r, byte[] a, byte[] order, int vector_len) { int i = 0, j = 0; try { @@ -962,6 +981,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> BYTE_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("byte[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(RAND.nextInt())); + }) + ); + + static final List>> BYTE_GENERATOR_SELECT_FROM_TRIPLES = + BYTE_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] byteBinaryOpProvider() { return BYTE_GENERATOR_PAIRS.stream().map(List::toArray). @@ -989,6 +1020,12 @@ public Object[][] byteTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] byteSelectFromTwoVectorOpProvider() { + return BYTE_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] byteTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -5746,6 +5783,24 @@ static void SelectFromByte64VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "byteSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorByte64VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] idx = fc.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + ByteVector idxv = ByteVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "byteUnaryOpSelectFromMaskProvider") static void SelectFromByte64VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java b/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java index 1c0d5362b536c..bbd354c958a2a 100644 --- a/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java @@ -307,6 +307,25 @@ static void assertexpandArraysEquals(byte[] r, byte[] a, boolean[] m, int vector } } + static void assertSelectFromTwoVectorEquals(byte[] r, byte[] order, byte[] a, byte[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(byte[] r, byte[] a, byte[] order, int vector_len) { int i = 0, j = 0; try { @@ -967,6 +986,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> BYTE_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("byte[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (byte)(RAND.nextInt())); + }) + ); + + static final List>> BYTE_GENERATOR_SELECT_FROM_TRIPLES = + BYTE_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] byteBinaryOpProvider() { return BYTE_GENERATOR_PAIRS.stream().map(List::toArray). @@ -994,6 +1025,12 @@ public Object[][] byteTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] byteSelectFromTwoVectorOpProvider() { + return BYTE_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] byteTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -5751,6 +5788,24 @@ static void SelectFromByteMaxVectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "byteSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorByteMaxVectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); + byte[] idx = fc.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ByteVector bv = ByteVector.fromArray(SPECIES, b, i); + ByteVector idxv = ByteVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "byteUnaryOpSelectFromMaskProvider") static void SelectFromByteMaxVectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Double128VectorTests.java b/test/jdk/jdk/incubator/vector/Double128VectorTests.java index 4efeb8f205991..05678c4290beb 100644 --- a/test/jdk/jdk/incubator/vector/Double128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double128VectorTests.java @@ -321,6 +321,25 @@ static void assertexpandArraysEquals(double[] r, double[] a, boolean[] m, int ve } } + static void assertSelectFromTwoVectorEquals(double[] r, double[] order, double[] a, double[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(double[] r, double[] a, double[] order, int vector_len) { int i = 0, j = 0; try { @@ -1108,6 +1127,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> DOUBLE_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("double[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (double)(RAND.nextInt())); + }) + ); + + static final List>> DOUBLE_GENERATOR_SELECT_FROM_TRIPLES = + DOUBLE_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] doubleBinaryOpProvider() { return DOUBLE_GENERATOR_PAIRS.stream().map(List::toArray). @@ -1135,6 +1166,12 @@ public Object[][] doubleTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] doubleSelectFromTwoVectorOpProvider() { + return DOUBLE_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] doubleTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -4799,6 +4836,24 @@ static void SelectFromDouble128VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "doubleSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorDouble128VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + double[] a = fa.apply(SPECIES.length()); + double[] b = fb.apply(SPECIES.length()); + double[] idx = fc.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + DoubleVector bv = DoubleVector.fromArray(SPECIES, b, i); + DoubleVector idxv = DoubleVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "doubleUnaryOpSelectFromMaskProvider") static void SelectFromDouble128VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Double256VectorTests.java b/test/jdk/jdk/incubator/vector/Double256VectorTests.java index 04b0e7dc0d68e..fe59fc85a2ed1 100644 --- a/test/jdk/jdk/incubator/vector/Double256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double256VectorTests.java @@ -321,6 +321,25 @@ static void assertexpandArraysEquals(double[] r, double[] a, boolean[] m, int ve } } + static void assertSelectFromTwoVectorEquals(double[] r, double[] order, double[] a, double[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(double[] r, double[] a, double[] order, int vector_len) { int i = 0, j = 0; try { @@ -1108,6 +1127,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> DOUBLE_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("double[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (double)(RAND.nextInt())); + }) + ); + + static final List>> DOUBLE_GENERATOR_SELECT_FROM_TRIPLES = + DOUBLE_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] doubleBinaryOpProvider() { return DOUBLE_GENERATOR_PAIRS.stream().map(List::toArray). @@ -1135,6 +1166,12 @@ public Object[][] doubleTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] doubleSelectFromTwoVectorOpProvider() { + return DOUBLE_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] doubleTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -4799,6 +4836,24 @@ static void SelectFromDouble256VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "doubleSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorDouble256VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + double[] a = fa.apply(SPECIES.length()); + double[] b = fb.apply(SPECIES.length()); + double[] idx = fc.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + DoubleVector bv = DoubleVector.fromArray(SPECIES, b, i); + DoubleVector idxv = DoubleVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "doubleUnaryOpSelectFromMaskProvider") static void SelectFromDouble256VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Double512VectorTests.java b/test/jdk/jdk/incubator/vector/Double512VectorTests.java index ad03b8b5c7b48..1e5b68ab98925 100644 --- a/test/jdk/jdk/incubator/vector/Double512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double512VectorTests.java @@ -321,6 +321,25 @@ static void assertexpandArraysEquals(double[] r, double[] a, boolean[] m, int ve } } + static void assertSelectFromTwoVectorEquals(double[] r, double[] order, double[] a, double[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(double[] r, double[] a, double[] order, int vector_len) { int i = 0, j = 0; try { @@ -1108,6 +1127,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> DOUBLE_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("double[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (double)(RAND.nextInt())); + }) + ); + + static final List>> DOUBLE_GENERATOR_SELECT_FROM_TRIPLES = + DOUBLE_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] doubleBinaryOpProvider() { return DOUBLE_GENERATOR_PAIRS.stream().map(List::toArray). @@ -1135,6 +1166,12 @@ public Object[][] doubleTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] doubleSelectFromTwoVectorOpProvider() { + return DOUBLE_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] doubleTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -4799,6 +4836,24 @@ static void SelectFromDouble512VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "doubleSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorDouble512VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + double[] a = fa.apply(SPECIES.length()); + double[] b = fb.apply(SPECIES.length()); + double[] idx = fc.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + DoubleVector bv = DoubleVector.fromArray(SPECIES, b, i); + DoubleVector idxv = DoubleVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "doubleUnaryOpSelectFromMaskProvider") static void SelectFromDouble512VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Double64VectorTests.java b/test/jdk/jdk/incubator/vector/Double64VectorTests.java index 9321215c3de73..b56b4d237f45c 100644 --- a/test/jdk/jdk/incubator/vector/Double64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double64VectorTests.java @@ -321,6 +321,25 @@ static void assertexpandArraysEquals(double[] r, double[] a, boolean[] m, int ve } } + static void assertSelectFromTwoVectorEquals(double[] r, double[] order, double[] a, double[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(double[] r, double[] a, double[] order, int vector_len) { int i = 0, j = 0; try { @@ -1108,6 +1127,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> DOUBLE_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("double[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (double)(RAND.nextInt())); + }) + ); + + static final List>> DOUBLE_GENERATOR_SELECT_FROM_TRIPLES = + DOUBLE_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] doubleBinaryOpProvider() { return DOUBLE_GENERATOR_PAIRS.stream().map(List::toArray). @@ -1135,6 +1166,12 @@ public Object[][] doubleTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] doubleSelectFromTwoVectorOpProvider() { + return DOUBLE_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] doubleTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -4799,6 +4836,24 @@ static void SelectFromDouble64VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "doubleSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorDouble64VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + double[] a = fa.apply(SPECIES.length()); + double[] b = fb.apply(SPECIES.length()); + double[] idx = fc.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + DoubleVector bv = DoubleVector.fromArray(SPECIES, b, i); + DoubleVector idxv = DoubleVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "doubleUnaryOpSelectFromMaskProvider") static void SelectFromDouble64VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java index a6b80376196c6..43da4f5763641 100644 --- a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java @@ -326,6 +326,25 @@ static void assertexpandArraysEquals(double[] r, double[] a, boolean[] m, int ve } } + static void assertSelectFromTwoVectorEquals(double[] r, double[] order, double[] a, double[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(double[] r, double[] a, double[] order, int vector_len) { int i = 0, j = 0; try { @@ -1113,6 +1132,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> DOUBLE_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("double[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (double)(RAND.nextInt())); + }) + ); + + static final List>> DOUBLE_GENERATOR_SELECT_FROM_TRIPLES = + DOUBLE_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] doubleBinaryOpProvider() { return DOUBLE_GENERATOR_PAIRS.stream().map(List::toArray). @@ -1140,6 +1171,12 @@ public Object[][] doubleTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] doubleSelectFromTwoVectorOpProvider() { + return DOUBLE_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] doubleTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -4804,6 +4841,24 @@ static void SelectFromDoubleMaxVectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "doubleSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorDoubleMaxVectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + double[] a = fa.apply(SPECIES.length()); + double[] b = fb.apply(SPECIES.length()); + double[] idx = fc.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + DoubleVector bv = DoubleVector.fromArray(SPECIES, b, i); + DoubleVector idxv = DoubleVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "doubleUnaryOpSelectFromMaskProvider") static void SelectFromDoubleMaxVectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Float128VectorTests.java b/test/jdk/jdk/incubator/vector/Float128VectorTests.java index 6bad90985442e..549199513d532 100644 --- a/test/jdk/jdk/incubator/vector/Float128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float128VectorTests.java @@ -321,6 +321,25 @@ static void assertexpandArraysEquals(float[] r, float[] a, boolean[] m, int vect } } + static void assertSelectFromTwoVectorEquals(float[] r, float[] order, float[] a, float[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(float[] r, float[] a, float[] order, int vector_len) { int i = 0, j = 0; try { @@ -1119,6 +1138,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> FLOAT_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("float[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (float)(RAND.nextInt())); + }) + ); + + static final List>> FLOAT_GENERATOR_SELECT_FROM_TRIPLES = + FLOAT_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] floatBinaryOpProvider() { return FLOAT_GENERATOR_PAIRS.stream().map(List::toArray). @@ -1146,6 +1177,12 @@ public Object[][] floatTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] floatSelectFromTwoVectorOpProvider() { + return FLOAT_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] floatTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -4778,6 +4815,24 @@ static void SelectFromFloat128VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "floatSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorFloat128VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + float[] a = fa.apply(SPECIES.length()); + float[] b = fb.apply(SPECIES.length()); + float[] idx = fc.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + FloatVector bv = FloatVector.fromArray(SPECIES, b, i); + FloatVector idxv = FloatVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "floatUnaryOpSelectFromMaskProvider") static void SelectFromFloat128VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Float256VectorTests.java b/test/jdk/jdk/incubator/vector/Float256VectorTests.java index e714ace5a7814..6d17727c3257e 100644 --- a/test/jdk/jdk/incubator/vector/Float256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float256VectorTests.java @@ -321,6 +321,25 @@ static void assertexpandArraysEquals(float[] r, float[] a, boolean[] m, int vect } } + static void assertSelectFromTwoVectorEquals(float[] r, float[] order, float[] a, float[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(float[] r, float[] a, float[] order, int vector_len) { int i = 0, j = 0; try { @@ -1119,6 +1138,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> FLOAT_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("float[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (float)(RAND.nextInt())); + }) + ); + + static final List>> FLOAT_GENERATOR_SELECT_FROM_TRIPLES = + FLOAT_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] floatBinaryOpProvider() { return FLOAT_GENERATOR_PAIRS.stream().map(List::toArray). @@ -1146,6 +1177,12 @@ public Object[][] floatTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] floatSelectFromTwoVectorOpProvider() { + return FLOAT_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] floatTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -4778,6 +4815,24 @@ static void SelectFromFloat256VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "floatSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorFloat256VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + float[] a = fa.apply(SPECIES.length()); + float[] b = fb.apply(SPECIES.length()); + float[] idx = fc.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + FloatVector bv = FloatVector.fromArray(SPECIES, b, i); + FloatVector idxv = FloatVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "floatUnaryOpSelectFromMaskProvider") static void SelectFromFloat256VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Float512VectorTests.java b/test/jdk/jdk/incubator/vector/Float512VectorTests.java index f3c5a316c79db..c2290eb708066 100644 --- a/test/jdk/jdk/incubator/vector/Float512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float512VectorTests.java @@ -321,6 +321,25 @@ static void assertexpandArraysEquals(float[] r, float[] a, boolean[] m, int vect } } + static void assertSelectFromTwoVectorEquals(float[] r, float[] order, float[] a, float[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(float[] r, float[] a, float[] order, int vector_len) { int i = 0, j = 0; try { @@ -1119,6 +1138,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> FLOAT_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("float[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (float)(RAND.nextInt())); + }) + ); + + static final List>> FLOAT_GENERATOR_SELECT_FROM_TRIPLES = + FLOAT_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] floatBinaryOpProvider() { return FLOAT_GENERATOR_PAIRS.stream().map(List::toArray). @@ -1146,6 +1177,12 @@ public Object[][] floatTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] floatSelectFromTwoVectorOpProvider() { + return FLOAT_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] floatTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -4778,6 +4815,24 @@ static void SelectFromFloat512VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "floatSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorFloat512VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + float[] a = fa.apply(SPECIES.length()); + float[] b = fb.apply(SPECIES.length()); + float[] idx = fc.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + FloatVector bv = FloatVector.fromArray(SPECIES, b, i); + FloatVector idxv = FloatVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "floatUnaryOpSelectFromMaskProvider") static void SelectFromFloat512VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Float64VectorTests.java b/test/jdk/jdk/incubator/vector/Float64VectorTests.java index 378c2ae783fea..0d50726f644fd 100644 --- a/test/jdk/jdk/incubator/vector/Float64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float64VectorTests.java @@ -321,6 +321,25 @@ static void assertexpandArraysEquals(float[] r, float[] a, boolean[] m, int vect } } + static void assertSelectFromTwoVectorEquals(float[] r, float[] order, float[] a, float[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(float[] r, float[] a, float[] order, int vector_len) { int i = 0, j = 0; try { @@ -1119,6 +1138,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> FLOAT_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("float[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (float)(RAND.nextInt())); + }) + ); + + static final List>> FLOAT_GENERATOR_SELECT_FROM_TRIPLES = + FLOAT_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] floatBinaryOpProvider() { return FLOAT_GENERATOR_PAIRS.stream().map(List::toArray). @@ -1146,6 +1177,12 @@ public Object[][] floatTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] floatSelectFromTwoVectorOpProvider() { + return FLOAT_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] floatTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -4778,6 +4815,24 @@ static void SelectFromFloat64VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "floatSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorFloat64VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + float[] a = fa.apply(SPECIES.length()); + float[] b = fb.apply(SPECIES.length()); + float[] idx = fc.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + FloatVector bv = FloatVector.fromArray(SPECIES, b, i); + FloatVector idxv = FloatVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "floatUnaryOpSelectFromMaskProvider") static void SelectFromFloat64VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java index a2dc38413ec35..6a0b1301ab328 100644 --- a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java @@ -326,6 +326,25 @@ static void assertexpandArraysEquals(float[] r, float[] a, boolean[] m, int vect } } + static void assertSelectFromTwoVectorEquals(float[] r, float[] order, float[] a, float[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(float[] r, float[] a, float[] order, int vector_len) { int i = 0, j = 0; try { @@ -1124,6 +1143,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> FLOAT_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("float[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (float)(RAND.nextInt())); + }) + ); + + static final List>> FLOAT_GENERATOR_SELECT_FROM_TRIPLES = + FLOAT_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] floatBinaryOpProvider() { return FLOAT_GENERATOR_PAIRS.stream().map(List::toArray). @@ -1151,6 +1182,12 @@ public Object[][] floatTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] floatSelectFromTwoVectorOpProvider() { + return FLOAT_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] floatTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -4783,6 +4820,24 @@ static void SelectFromFloatMaxVectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "floatSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorFloatMaxVectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + float[] a = fa.apply(SPECIES.length()); + float[] b = fb.apply(SPECIES.length()); + float[] idx = fc.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + FloatVector bv = FloatVector.fromArray(SPECIES, b, i); + FloatVector idxv = FloatVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "floatUnaryOpSelectFromMaskProvider") static void SelectFromFloatMaxVectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Int128VectorTests.java b/test/jdk/jdk/incubator/vector/Int128VectorTests.java index 1ee0bbc319717..528d26a952b8a 100644 --- a/test/jdk/jdk/incubator/vector/Int128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int128VectorTests.java @@ -302,6 +302,25 @@ static void assertexpandArraysEquals(int[] r, int[] a, boolean[] m, int vector_l } } + static void assertSelectFromTwoVectorEquals(int[] r, int[] order, int[] a, int[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(int[] r, int[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -952,6 +971,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> INT_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("int[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(RAND.nextInt())); + }) + ); + + static final List>> INT_GENERATOR_SELECT_FROM_TRIPLES = + INT_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] intBinaryOpProvider() { return INT_GENERATOR_PAIRS.stream().map(List::toArray). @@ -979,6 +1010,12 @@ public Object[][] intTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] intSelectFromTwoVectorOpProvider() { + return INT_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] intTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -5779,6 +5816,24 @@ static void SelectFromInt128VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "intSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorInt128VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] idx = fc.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + IntVector idxv = IntVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "intUnaryOpShuffleMaskProvider") static void SelectFromInt128VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Int256VectorTests.java b/test/jdk/jdk/incubator/vector/Int256VectorTests.java index 5257af21c942d..09561e0f3c431 100644 --- a/test/jdk/jdk/incubator/vector/Int256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int256VectorTests.java @@ -302,6 +302,25 @@ static void assertexpandArraysEquals(int[] r, int[] a, boolean[] m, int vector_l } } + static void assertSelectFromTwoVectorEquals(int[] r, int[] order, int[] a, int[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(int[] r, int[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -952,6 +971,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> INT_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("int[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(RAND.nextInt())); + }) + ); + + static final List>> INT_GENERATOR_SELECT_FROM_TRIPLES = + INT_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] intBinaryOpProvider() { return INT_GENERATOR_PAIRS.stream().map(List::toArray). @@ -979,6 +1010,12 @@ public Object[][] intTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] intSelectFromTwoVectorOpProvider() { + return INT_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] intTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -5779,6 +5816,24 @@ static void SelectFromInt256VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "intSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorInt256VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] idx = fc.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + IntVector idxv = IntVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "intUnaryOpShuffleMaskProvider") static void SelectFromInt256VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Int512VectorTests.java b/test/jdk/jdk/incubator/vector/Int512VectorTests.java index 6d4633cc7ae1c..e6d1aa68f56f6 100644 --- a/test/jdk/jdk/incubator/vector/Int512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int512VectorTests.java @@ -302,6 +302,25 @@ static void assertexpandArraysEquals(int[] r, int[] a, boolean[] m, int vector_l } } + static void assertSelectFromTwoVectorEquals(int[] r, int[] order, int[] a, int[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(int[] r, int[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -952,6 +971,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> INT_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("int[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(RAND.nextInt())); + }) + ); + + static final List>> INT_GENERATOR_SELECT_FROM_TRIPLES = + INT_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] intBinaryOpProvider() { return INT_GENERATOR_PAIRS.stream().map(List::toArray). @@ -979,6 +1010,12 @@ public Object[][] intTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] intSelectFromTwoVectorOpProvider() { + return INT_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] intTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -5779,6 +5816,24 @@ static void SelectFromInt512VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "intSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorInt512VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] idx = fc.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + IntVector idxv = IntVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "intUnaryOpShuffleMaskProvider") static void SelectFromInt512VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Int64VectorTests.java b/test/jdk/jdk/incubator/vector/Int64VectorTests.java index 7bd1543ed5c69..4435d31cd044d 100644 --- a/test/jdk/jdk/incubator/vector/Int64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int64VectorTests.java @@ -302,6 +302,25 @@ static void assertexpandArraysEquals(int[] r, int[] a, boolean[] m, int vector_l } } + static void assertSelectFromTwoVectorEquals(int[] r, int[] order, int[] a, int[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(int[] r, int[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -952,6 +971,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> INT_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("int[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(RAND.nextInt())); + }) + ); + + static final List>> INT_GENERATOR_SELECT_FROM_TRIPLES = + INT_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] intBinaryOpProvider() { return INT_GENERATOR_PAIRS.stream().map(List::toArray). @@ -979,6 +1010,12 @@ public Object[][] intTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] intSelectFromTwoVectorOpProvider() { + return INT_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] intTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -5779,6 +5816,24 @@ static void SelectFromInt64VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "intSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorInt64VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] idx = fc.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + IntVector idxv = IntVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "intUnaryOpShuffleMaskProvider") static void SelectFromInt64VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java b/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java index 71d1ce594f909..94dce66d95105 100644 --- a/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java @@ -307,6 +307,25 @@ static void assertexpandArraysEquals(int[] r, int[] a, boolean[] m, int vector_l } } + static void assertSelectFromTwoVectorEquals(int[] r, int[] order, int[] a, int[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(int[] r, int[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -957,6 +976,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> INT_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("int[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (int)(RAND.nextInt())); + }) + ); + + static final List>> INT_GENERATOR_SELECT_FROM_TRIPLES = + INT_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] intBinaryOpProvider() { return INT_GENERATOR_PAIRS.stream().map(List::toArray). @@ -984,6 +1015,12 @@ public Object[][] intTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] intSelectFromTwoVectorOpProvider() { + return INT_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] intTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -5784,6 +5821,24 @@ static void SelectFromIntMaxVectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "intSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorIntMaxVectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); + int[] idx = fc.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + IntVector bv = IntVector.fromArray(SPECIES, b, i); + IntVector idxv = IntVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "intUnaryOpShuffleMaskProvider") static void SelectFromIntMaxVectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Long128VectorTests.java b/test/jdk/jdk/incubator/vector/Long128VectorTests.java index bcec2dee9fe3c..7e6bf6b7b815d 100644 --- a/test/jdk/jdk/incubator/vector/Long128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long128VectorTests.java @@ -259,6 +259,25 @@ static void assertexpandArraysEquals(long[] r, long[] a, boolean[] m, int vector } } + static void assertSelectFromTwoVectorEquals(long[] r, long[] order, long[] a, long[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(long[] r, long[] a, long[] order, int vector_len) { int i = 0, j = 0; try { @@ -942,6 +961,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> LONG_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("long[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(RAND.nextInt())); + }) + ); + + static final List>> LONG_GENERATOR_SELECT_FROM_TRIPLES = + LONG_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] longBinaryOpProvider() { return LONG_GENERATOR_PAIRS.stream().map(List::toArray). @@ -969,6 +1000,12 @@ public Object[][] longTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] longSelectFromTwoVectorOpProvider() { + return LONG_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] longTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -5665,6 +5702,24 @@ static void SelectFromLong128VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "longSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorLong128VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] idx = fc.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + LongVector idxv = LongVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "longUnaryOpSelectFromMaskProvider") static void SelectFromLong128VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Long256VectorTests.java b/test/jdk/jdk/incubator/vector/Long256VectorTests.java index e8f2fb1301cf8..299b7007ba5c1 100644 --- a/test/jdk/jdk/incubator/vector/Long256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long256VectorTests.java @@ -259,6 +259,25 @@ static void assertexpandArraysEquals(long[] r, long[] a, boolean[] m, int vector } } + static void assertSelectFromTwoVectorEquals(long[] r, long[] order, long[] a, long[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(long[] r, long[] a, long[] order, int vector_len) { int i = 0, j = 0; try { @@ -942,6 +961,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> LONG_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("long[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(RAND.nextInt())); + }) + ); + + static final List>> LONG_GENERATOR_SELECT_FROM_TRIPLES = + LONG_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] longBinaryOpProvider() { return LONG_GENERATOR_PAIRS.stream().map(List::toArray). @@ -969,6 +1000,12 @@ public Object[][] longTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] longSelectFromTwoVectorOpProvider() { + return LONG_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] longTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -5665,6 +5702,24 @@ static void SelectFromLong256VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "longSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorLong256VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] idx = fc.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + LongVector idxv = LongVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "longUnaryOpSelectFromMaskProvider") static void SelectFromLong256VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Long512VectorTests.java b/test/jdk/jdk/incubator/vector/Long512VectorTests.java index 022f1490fcc1e..e6eafa02ed00e 100644 --- a/test/jdk/jdk/incubator/vector/Long512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long512VectorTests.java @@ -259,6 +259,25 @@ static void assertexpandArraysEquals(long[] r, long[] a, boolean[] m, int vector } } + static void assertSelectFromTwoVectorEquals(long[] r, long[] order, long[] a, long[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(long[] r, long[] a, long[] order, int vector_len) { int i = 0, j = 0; try { @@ -942,6 +961,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> LONG_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("long[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(RAND.nextInt())); + }) + ); + + static final List>> LONG_GENERATOR_SELECT_FROM_TRIPLES = + LONG_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] longBinaryOpProvider() { return LONG_GENERATOR_PAIRS.stream().map(List::toArray). @@ -969,6 +1000,12 @@ public Object[][] longTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] longSelectFromTwoVectorOpProvider() { + return LONG_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] longTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -5665,6 +5702,24 @@ static void SelectFromLong512VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "longSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorLong512VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] idx = fc.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + LongVector idxv = LongVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "longUnaryOpSelectFromMaskProvider") static void SelectFromLong512VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Long64VectorTests.java b/test/jdk/jdk/incubator/vector/Long64VectorTests.java index fe886bf93d870..035db048eb840 100644 --- a/test/jdk/jdk/incubator/vector/Long64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long64VectorTests.java @@ -259,6 +259,25 @@ static void assertexpandArraysEquals(long[] r, long[] a, boolean[] m, int vector } } + static void assertSelectFromTwoVectorEquals(long[] r, long[] order, long[] a, long[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(long[] r, long[] a, long[] order, int vector_len) { int i = 0, j = 0; try { @@ -942,6 +961,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> LONG_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("long[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(RAND.nextInt())); + }) + ); + + static final List>> LONG_GENERATOR_SELECT_FROM_TRIPLES = + LONG_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] longBinaryOpProvider() { return LONG_GENERATOR_PAIRS.stream().map(List::toArray). @@ -969,6 +1000,12 @@ public Object[][] longTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] longSelectFromTwoVectorOpProvider() { + return LONG_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] longTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -5665,6 +5702,24 @@ static void SelectFromLong64VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "longSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorLong64VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] idx = fc.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + LongVector idxv = LongVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "longUnaryOpSelectFromMaskProvider") static void SelectFromLong64VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java b/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java index b77d6eeb118a8..68ea78db4f0ec 100644 --- a/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java @@ -264,6 +264,25 @@ static void assertexpandArraysEquals(long[] r, long[] a, boolean[] m, int vector } } + static void assertSelectFromTwoVectorEquals(long[] r, long[] order, long[] a, long[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(long[] r, long[] a, long[] order, int vector_len) { int i = 0, j = 0; try { @@ -947,6 +966,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> LONG_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("long[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (long)(RAND.nextInt())); + }) + ); + + static final List>> LONG_GENERATOR_SELECT_FROM_TRIPLES = + LONG_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] longBinaryOpProvider() { return LONG_GENERATOR_PAIRS.stream().map(List::toArray). @@ -974,6 +1005,12 @@ public Object[][] longTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] longSelectFromTwoVectorOpProvider() { + return LONG_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] longTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -5670,6 +5707,24 @@ static void SelectFromLongMaxVectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "longSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorLongMaxVectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); + long[] idx = fc.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + LongVector bv = LongVector.fromArray(SPECIES, b, i); + LongVector idxv = LongVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "longUnaryOpSelectFromMaskProvider") static void SelectFromLongMaxVectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Short128VectorTests.java b/test/jdk/jdk/incubator/vector/Short128VectorTests.java index 2a82ada044e31..2103be0994ccd 100644 --- a/test/jdk/jdk/incubator/vector/Short128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short128VectorTests.java @@ -302,6 +302,25 @@ static void assertexpandArraysEquals(short[] r, short[] a, boolean[] m, int vect } } + static void assertSelectFromTwoVectorEquals(short[] r, short[] order, short[] a, short[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(short[] r, short[] a, short[] order, int vector_len) { int i = 0, j = 0; try { @@ -952,6 +971,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> SHORT_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("short[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(RAND.nextInt())); + }) + ); + + static final List>> SHORT_GENERATOR_SELECT_FROM_TRIPLES = + SHORT_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] shortBinaryOpProvider() { return SHORT_GENERATOR_PAIRS.stream().map(List::toArray). @@ -979,6 +1010,12 @@ public Object[][] shortTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] shortSelectFromTwoVectorOpProvider() { + return SHORT_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] shortTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -5726,6 +5763,24 @@ static void SelectFromShort128VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "shortSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorShort128VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] idx = fc.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + ShortVector idxv = ShortVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "shortUnaryOpSelectFromMaskProvider") static void SelectFromShort128VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Short256VectorTests.java b/test/jdk/jdk/incubator/vector/Short256VectorTests.java index 69a8432acef3c..feed6bbe5f3ee 100644 --- a/test/jdk/jdk/incubator/vector/Short256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short256VectorTests.java @@ -302,6 +302,25 @@ static void assertexpandArraysEquals(short[] r, short[] a, boolean[] m, int vect } } + static void assertSelectFromTwoVectorEquals(short[] r, short[] order, short[] a, short[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(short[] r, short[] a, short[] order, int vector_len) { int i = 0, j = 0; try { @@ -952,6 +971,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> SHORT_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("short[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(RAND.nextInt())); + }) + ); + + static final List>> SHORT_GENERATOR_SELECT_FROM_TRIPLES = + SHORT_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] shortBinaryOpProvider() { return SHORT_GENERATOR_PAIRS.stream().map(List::toArray). @@ -979,6 +1010,12 @@ public Object[][] shortTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] shortSelectFromTwoVectorOpProvider() { + return SHORT_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] shortTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -5726,6 +5763,24 @@ static void SelectFromShort256VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "shortSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorShort256VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] idx = fc.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + ShortVector idxv = ShortVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "shortUnaryOpSelectFromMaskProvider") static void SelectFromShort256VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Short512VectorTests.java b/test/jdk/jdk/incubator/vector/Short512VectorTests.java index 8e892a8a48e69..a1a1ac6bc3799 100644 --- a/test/jdk/jdk/incubator/vector/Short512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short512VectorTests.java @@ -302,6 +302,25 @@ static void assertexpandArraysEquals(short[] r, short[] a, boolean[] m, int vect } } + static void assertSelectFromTwoVectorEquals(short[] r, short[] order, short[] a, short[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(short[] r, short[] a, short[] order, int vector_len) { int i = 0, j = 0; try { @@ -952,6 +971,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> SHORT_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("short[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(RAND.nextInt())); + }) + ); + + static final List>> SHORT_GENERATOR_SELECT_FROM_TRIPLES = + SHORT_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] shortBinaryOpProvider() { return SHORT_GENERATOR_PAIRS.stream().map(List::toArray). @@ -979,6 +1010,12 @@ public Object[][] shortTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] shortSelectFromTwoVectorOpProvider() { + return SHORT_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] shortTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -5726,6 +5763,24 @@ static void SelectFromShort512VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "shortSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorShort512VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] idx = fc.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + ShortVector idxv = ShortVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "shortUnaryOpSelectFromMaskProvider") static void SelectFromShort512VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/Short64VectorTests.java b/test/jdk/jdk/incubator/vector/Short64VectorTests.java index 97658d4257dfd..cc14cccd1198f 100644 --- a/test/jdk/jdk/incubator/vector/Short64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short64VectorTests.java @@ -302,6 +302,25 @@ static void assertexpandArraysEquals(short[] r, short[] a, boolean[] m, int vect } } + static void assertSelectFromTwoVectorEquals(short[] r, short[] order, short[] a, short[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(short[] r, short[] a, short[] order, int vector_len) { int i = 0, j = 0; try { @@ -952,6 +971,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> SHORT_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("short[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(RAND.nextInt())); + }) + ); + + static final List>> SHORT_GENERATOR_SELECT_FROM_TRIPLES = + SHORT_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] shortBinaryOpProvider() { return SHORT_GENERATOR_PAIRS.stream().map(List::toArray). @@ -979,6 +1010,12 @@ public Object[][] shortTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] shortSelectFromTwoVectorOpProvider() { + return SHORT_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] shortTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -5726,6 +5763,24 @@ static void SelectFromShort64VectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "shortSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorShort64VectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] idx = fc.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + ShortVector idxv = ShortVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "shortUnaryOpSelectFromMaskProvider") static void SelectFromShort64VectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java b/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java index 0857c13ef3c43..a557494f74c96 100644 --- a/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java @@ -307,6 +307,25 @@ static void assertexpandArraysEquals(short[] r, short[] a, boolean[] m, int vect } } + static void assertSelectFromTwoVectorEquals(short[] r, short[] order, short[] a, short[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals(short[] r, short[] a, short[] order, int vector_len) { int i = 0, j = 0; try { @@ -957,6 +976,18 @@ public Object[][] boolUnaryOpProvider() { flatMap(pair -> SHORT_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("short[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (short)(RAND.nextInt())); + }) + ); + + static final List>> SHORT_GENERATOR_SELECT_FROM_TRIPLES = + SHORT_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] shortBinaryOpProvider() { return SHORT_GENERATOR_PAIRS.stream().map(List::toArray). @@ -984,6 +1015,12 @@ public Object[][] shortTernaryOpProvider() { toArray(Object[][]::new); } + @DataProvider + public Object[][] shortSelectFromTwoVectorOpProvider() { + return SHORT_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] shortTernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). @@ -5731,6 +5768,24 @@ static void SelectFromShortMaxVectorTests(IntFunction fa, assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "shortSelectFromTwoVectorOpProvider") + static void SelectFromTwoVectorShortMaxVectorTests(IntFunction fa, IntFunction fb, IntFunction fc) { + short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); + short[] idx = fc.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ShortVector bv = ShortVector.fromArray(SPECIES, b, i); + ShortVector idxv = ShortVector.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + @Test(dataProvider = "shortUnaryOpSelectFromMaskProvider") static void SelectFromShortMaxVectorTestsMaskedSmokeTest(IntFunction fa, BiFunction fs, diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Miscellaneous.template b/test/jdk/jdk/incubator/vector/templates/Unit-Miscellaneous.template index 0d3b310f60f04..9a020c66d52f8 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Miscellaneous.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-Miscellaneous.template @@ -297,6 +297,24 @@ assertSelectFromArraysEquals(r, a, order, SPECIES.length()); } + @Test(dataProvider = "$type$SelectFromTwoVectorOpProvider") + static void SelectFromTwoVector$vectorteststype$(IntFunction<$type$[]> fa, IntFunction<$type$[]> fb, IntFunction<$type$[]> fc) { + $type$[] a = fa.apply(SPECIES.length()); + $type$[] b = fb.apply(SPECIES.length()); + $type$[] idx = fc.apply(SPECIES.length()); + $type$[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < idx.length; i += SPECIES.length()) { + $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); + $abstractvectortype$ bv = $abstractvectortype$.fromArray(SPECIES, b, i); + $abstractvectortype$ idxv = $abstractvectortype$.fromArray(SPECIES, idx, i); + idxv.selectFrom(av, bv).intoArray(r, i); + } + } + assertSelectFromTwoVectorEquals(r, idx, a, b, SPECIES.length()); + } + #if[Int] @Test(dataProvider = "$type$UnaryOpShuffleMaskProvider") #else[Int] diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-header.template b/test/jdk/jdk/incubator/vector/templates/Unit-header.template index 42440881771a3..2f33ede458a3e 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-header.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-header.template @@ -397,6 +397,25 @@ relativeError)); } } + static void assertSelectFromTwoVectorEquals($type$[] r, $type$[] order, $type$[] a, $type$[] b, int vector_len) { + int i = 0, j = 0; + boolean is_exceptional_idx = false; + int idx = 0, wrapped_index = 0, oidx = 0; + try { + for (; i < a.length; i += vector_len) { + for (j = 0; j < vector_len; j++) { + idx = i + j; + wrapped_index = Math.floorMod((int)order[idx], 2 * vector_len); + is_exceptional_idx = wrapped_index >= vector_len; + oidx = is_exceptional_idx ? (wrapped_index - vector_len) : wrapped_index; + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx])); + } + } + } catch (AssertionError e) { + Assert.assertEquals(r[idx], (is_exceptional_idx ? b[i + oidx] : a[i + oidx]), "at index #" + idx + ", order = " + order[idx] + ", a = " + a[i + oidx] + ", b = " + b[i + oidx]); + } + } + static void assertSelectFromArraysEquals($type$[] r, $type$[] a, $type$[] order, int vector_len) { int i = 0, j = 0; try { @@ -1221,6 +1240,18 @@ relativeError)); flatMap(pair -> $TYPE$_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); + static final List> SELECT_FROM_INDEX_GENERATORS = List.of( + withToString("$type$[0..VECLEN*2)", (int s) -> { + return fill(s * BUFFER_REPS, + i -> ($type$)(RAND.nextInt())); + }) + ); + + static final List>> $TYPE$_GENERATOR_SELECT_FROM_TRIPLES = + $TYPE$_GENERATOR_PAIRS.stream(). + flatMap(pair -> SELECT_FROM_INDEX_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). + collect(Collectors.toList()); + @DataProvider public Object[][] $type$BinaryOpProvider() { return $TYPE$_GENERATOR_PAIRS.stream().map(List::toArray). @@ -1248,6 +1279,12 @@ relativeError)); toArray(Object[][]::new); } + @DataProvider + public Object[][] $type$SelectFromTwoVectorOpProvider() { + return $TYPE$_GENERATOR_SELECT_FROM_TRIPLES.stream().map(List::toArray). + toArray(Object[][]::new); + } + @DataProvider public Object[][] $type$TernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/SelectFromBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/SelectFromBenchmark.java new file mode 100644 index 0000000000000..18614617e6c5e --- /dev/null +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/SelectFromBenchmark.java @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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.jdk.incubator.vector; + +import java.util.Random; +import java.util.Arrays; +import jdk.incubator.vector.*; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; + +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@State(Scope.Thread) +@Fork(jvmArgsPrepend = {"--add-modules=jdk.incubator.vector"}) +public class SelectFromBenchmark { + @Param({"1024","2048"}) + int size; + + byte[] byteindex; + byte[] bytesrc1; + byte[] bytesrc2; + byte[] byteres; + + short[] shortindex; + short[] shortsrc1; + short[] shortsrc2; + short[] shortres; + + int[] intindex; + int[] intsrc1; + int[] intsrc2; + int[] intres; + + long[] longindex; + long[] longsrc1; + long[] longsrc2; + long[] longres; + + float[] floatindex; + float[] floatsrc1; + float[] floatsrc2; + float[] floatres; + + double[] doubleindex; + double[] doublesrc1; + double[] doublesrc2; + double[] doubleres; + + @Setup(Level.Trial) + public void BmSetup() { + Random r = new Random(1024); + byteindex = new byte[size]; + bytesrc1 = new byte[size]; + bytesrc2 = new byte[size]; + byteres = new byte[size]; + + shortindex = new short[size]; + shortsrc1 = new short[size]; + shortsrc2 = new short[size]; + shortres = new short[size]; + + intindex = new int[size]; + intsrc1 = new int[size]; + intsrc2 = new int[size]; + intres = new int[size]; + + longindex = new long[size]; + longsrc1 = new long[size]; + longsrc2 = new long[size]; + longres = new long[size]; + + floatindex = new float[size]; + floatsrc1 = new float[size]; + floatsrc2 = new float[size]; + floatres = new float[size]; + + doubleindex = new double[size]; + doublesrc1 = new double[size]; + doublesrc2 = new double[size]; + doubleres = new double[size]; + + Arrays.fill(bytesrc1, (byte)1); + Arrays.fill(bytesrc2, (byte)2); + + Arrays.fill(shortsrc1, (short)1); + Arrays.fill(shortsrc2, (short)2); + + Arrays.fill(intsrc1, 1); + Arrays.fill(intsrc2, 2); + + Arrays.fill(longsrc1, 1); + Arrays.fill(longsrc2, 2); + + Arrays.fill(floatsrc1, 1.0f); + Arrays.fill(floatsrc2, 2.0f); + + Arrays.fill(doublesrc1, 1.0); + Arrays.fill(doublesrc2, 2.0); + + for (int i = 0; i < size; i++) { + byteindex[i] = (byte)((ByteVector.SPECIES_PREFERRED.length() - 1) & i); + shortindex[i] = (short)((ShortVector.SPECIES_PREFERRED.length() - 1) & i); + intindex[i] = (int)((IntVector.SPECIES_PREFERRED.length() - 1) & i); + longindex[i] = (long)((LongVector.SPECIES_PREFERRED.length() - 1) & i); + floatindex[i] = (float)((FloatVector.SPECIES_PREFERRED.length() - 1) & i); + doubleindex[i] = (double)((DoubleVector.SPECIES_PREFERRED.length() - 1) & i); + } + } + + @Benchmark + public void selectFromByteVector() { + for (int j = 0; j < size; j += ByteVector.SPECIES_PREFERRED.length()) { + ByteVector.fromArray(ByteVector.SPECIES_PREFERRED, byteindex, j) + .selectFrom(ByteVector.fromArray(ByteVector.SPECIES_PREFERRED, bytesrc1, j), + ByteVector.fromArray(ByteVector.SPECIES_PREFERRED, bytesrc2, j)) + .intoArray(byteres, j); + } + } + + @Benchmark + public void rearrangeFromByteVector() { + for (int j = 0; j < size; j += ByteVector.SPECIES_PREFERRED.length()) { + ByteVector.fromArray(ByteVector.SPECIES_PREFERRED, bytesrc1, j) + .rearrange(ByteVector.fromArray(ByteVector.SPECIES_PREFERRED, byteindex, j).toShuffle(), + ByteVector.fromArray(ByteVector.SPECIES_PREFERRED, bytesrc2, j)) + .intoArray(byteres, j); + } + } + + @Benchmark + public void selectFromShortVector() { + for (int j = 0; j < size; j += ShortVector.SPECIES_PREFERRED.length()) { + ShortVector.fromArray(ShortVector.SPECIES_PREFERRED, shortindex, j) + .selectFrom(ShortVector.fromArray(ShortVector.SPECIES_PREFERRED, shortsrc1, j), + ShortVector.fromArray(ShortVector.SPECIES_PREFERRED, shortsrc2, j)) + .intoArray(shortres, j); + } + } + + @Benchmark + public void rearrangeFromShortVector() { + for (int j = 0; j < size; j += ShortVector.SPECIES_PREFERRED.length()) { + ShortVector.fromArray(ShortVector.SPECIES_PREFERRED, shortsrc1, j) + .rearrange(ShortVector.fromArray(ShortVector.SPECIES_PREFERRED, shortindex, j).toShuffle(), + ShortVector.fromArray(ShortVector.SPECIES_PREFERRED, shortsrc2, j)) + .intoArray(shortres, j); + } + } + + @Benchmark + public void selectFromIntVector() { + for (int j = 0; j < size; j += IntVector.SPECIES_PREFERRED.length()) { + IntVector.fromArray(IntVector.SPECIES_PREFERRED, intindex, j) + .selectFrom(IntVector.fromArray(IntVector.SPECIES_PREFERRED, intsrc1, j), + IntVector.fromArray(IntVector.SPECIES_PREFERRED, intsrc2, j)) + .intoArray(intres, j); + } + } + + @Benchmark + public void rearrangeFromIntVector() { + for (int j = 0; j < size; j += IntVector.SPECIES_PREFERRED.length()) { + IntVector.fromArray(IntVector.SPECIES_PREFERRED, intsrc1, j) + .rearrange(IntVector.fromArray(IntVector.SPECIES_PREFERRED, intindex, j).toShuffle(), + IntVector.fromArray(IntVector.SPECIES_PREFERRED, intsrc2, j)) + .intoArray(intres, j); + } + } + + @Benchmark + public void selectFromLongVector() { + for (int j = 0; j < size; j += LongVector.SPECIES_PREFERRED.length()) { + LongVector.fromArray(LongVector.SPECIES_PREFERRED, longindex, j) + .selectFrom(LongVector.fromArray(LongVector.SPECIES_PREFERRED, longsrc1, j), + LongVector.fromArray(LongVector.SPECIES_PREFERRED, longsrc2, j)) + .intoArray(longres, j); + } + } + + @Benchmark + public void rearrangeFromLongVector() { + for (int j = 0; j < size; j += LongVector.SPECIES_PREFERRED.length()) { + LongVector.fromArray(LongVector.SPECIES_PREFERRED, longsrc1, j) + .rearrange(LongVector.fromArray(LongVector.SPECIES_PREFERRED, longindex, j).toShuffle(), + LongVector.fromArray(LongVector.SPECIES_PREFERRED, longsrc2, j)) + .intoArray(longres, j); + } + } + + @Benchmark + public void selectFromFloatVector() { + for (int j = 0; j < size; j += FloatVector.SPECIES_PREFERRED.length()) { + FloatVector.fromArray(FloatVector.SPECIES_PREFERRED, floatindex, j) + .selectFrom(FloatVector.fromArray(FloatVector.SPECIES_PREFERRED, floatsrc1, j), + FloatVector.fromArray(FloatVector.SPECIES_PREFERRED, floatsrc2, j)) + .intoArray(floatres, j); + } + } + + @Benchmark + public void rearrangeFromFloatVector() { + for (int j = 0; j < size; j += FloatVector.SPECIES_PREFERRED.length()) { + FloatVector.fromArray(FloatVector.SPECIES_PREFERRED, floatsrc1, j) + .rearrange(FloatVector.fromArray(FloatVector.SPECIES_PREFERRED, floatindex, j).toShuffle(), + FloatVector.fromArray(FloatVector.SPECIES_PREFERRED, floatsrc2, j)) + .intoArray(floatres, j); + } + } + + @Benchmark + public void selectFromDoubleVector() { + for (int j = 0; j < size; j += DoubleVector.SPECIES_PREFERRED.length()) { + DoubleVector.fromArray(DoubleVector.SPECIES_PREFERRED, doubleindex, j) + .selectFrom(DoubleVector.fromArray(DoubleVector.SPECIES_PREFERRED, doublesrc1, j), + DoubleVector.fromArray(DoubleVector.SPECIES_PREFERRED, doublesrc2, j)) + .intoArray(doubleres, j); + } + } + + @Benchmark + public void rearrangeFromDoubleVector() { + for (int j = 0; j < size; j += DoubleVector.SPECIES_PREFERRED.length()) { + DoubleVector.fromArray(DoubleVector.SPECIES_PREFERRED, doublesrc1, j) + .rearrange(DoubleVector.fromArray(DoubleVector.SPECIES_PREFERRED, doubleindex, j).toShuffle(), + DoubleVector.fromArray(DoubleVector.SPECIES_PREFERRED, doublesrc2, j)) + .intoArray(doubleres, j); + } + } +} From 44151f475fca3cf03299319b2ac9ddc533ba134d Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Wed, 16 Oct 2024 16:27:57 +0000 Subject: [PATCH 092/118] 8342145: File libCreationTimeHelper.c compile fails on Alpine Reviewed-by: mbaesken --- .../BasicFileAttributeView/libCreationTimeHelper.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/libCreationTimeHelper.c b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/libCreationTimeHelper.c index fb518b3b701eb..0686cc790da41 100644 --- a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/libCreationTimeHelper.c +++ b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/libCreationTimeHelper.c @@ -25,8 +25,8 @@ #if defined(__linux__) #include #include +#include #include -#include #include #ifndef STATX_BASIC_STATS #define STATX_BASIC_STATS 0x000007ffU @@ -44,13 +44,20 @@ #define AT_FDCWD -100 #endif +#ifndef __GLIBC__ +// Alpine doesn't know these types, define them +typedef unsigned int __uint32_t; +typedef unsigned short __uint16_t; +typedef unsigned long int __uint64_t; +#endif + /* * Timestamp structure for the timestamps in struct statx. */ struct my_statx_timestamp { - __int64_t tv_sec; + int64_t tv_sec; __uint32_t tv_nsec; - __int32_t __reserved; + int32_t __reserved; }; /* From d4f0ba73f653a3886b17f283b9b6a92db1af52aa Mon Sep 17 00:00:00 2001 From: Jatin Bhateja Date: Wed, 16 Oct 2024 18:26:54 +0000 Subject: [PATCH 093/118] 8342439: Build failure after 8338023 Reviewed-by: liach --- src/hotspot/share/opto/vectorIntrinsics.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/opto/vectorIntrinsics.cpp b/src/hotspot/share/opto/vectorIntrinsics.cpp index fe1807b9588c5..6b7483b131ffa 100644 --- a/src/hotspot/share/opto/vectorIntrinsics.cpp +++ b/src/hotspot/share/opto/vectorIntrinsics.cpp @@ -2873,7 +2873,7 @@ static Node* LowerSelectFromTwoVectorOperation(PhaseGVN& phase, Node* index_vec, // Wrap indexes into two vector index range [0, VLEN * 2) Node* two_vect_lane_cnt_m1 = phase.makecon(TypeInt::make(2 * num_elem - 1)); Node* bcast_two_vect_lane_cnt_m1_vec = phase.transform(VectorNode::scalar2vector(two_vect_lane_cnt_m1, num_elem, - Type::get_const_basic_type(T_BYTE), false)); + T_BYTE, false)); index_byte_vec = phase.transform(VectorNode::make(Op_AndV, index_byte_vec, bcast_two_vect_lane_cnt_m1_vec, index_byte_vec->bottom_type()->is_vect())); @@ -2884,7 +2884,7 @@ static Node* LowerSelectFromTwoVectorOperation(PhaseGVN& phase, Node* index_vec, const TypeVect* vmask_type = TypeVect::makemask(T_BYTE, num_elem); Node* lane_cnt_m1 = phase.makecon(TypeInt::make(num_elem - 1)); Node* bcast_lane_cnt_m1_vec = phase.transform(VectorNode::scalar2vector(lane_cnt_m1, num_elem, - Type::get_const_basic_type(T_BYTE), false)); + T_BYTE, false)); Node* mask = phase.transform(new VectorMaskCmpNode(pred, index_byte_vec, bcast_lane_cnt_m1_vec, pred_node, vmask_type)); // Rearrange expects the indexes to lie within single vector index range [0, VLEN). @@ -3012,7 +3012,7 @@ bool LibraryCallKit::inline_vector_select_from_two_vectors() { } int indexRangeMask = 2 * num_elem - 1; Node* wrap_mask = gvn().makecon(TypeInteger::make(indexRangeMask, indexRangeMask, Type::WidenMin, index_elem_bt != T_LONG ? T_INT : index_elem_bt)); - Node* wrap_mask_vec = gvn().transform(VectorNode::scalar2vector(wrap_mask, num_elem, Type::get_const_basic_type(index_elem_bt), false)); + Node* wrap_mask_vec = gvn().transform(VectorNode::scalar2vector(wrap_mask, num_elem, index_elem_bt, false)); opd1 = gvn().transform(VectorNode::make(Op_AndV, opd1, wrap_mask_vec, opd1->bottom_type()->is_vect())); operation = gvn().transform(VectorNode::make(Op_SelectFromTwoVector, opd1, opd2, opd3, vt)); } From ed6809666b12b0de66f68d5e7e389dde1708aaf3 Mon Sep 17 00:00:00 2001 From: Richard Reingruber Date: Wed, 16 Oct 2024 19:17:27 +0000 Subject: [PATCH 094/118] 8341862: PPC64: C1 unwind_handler fails to unlock synchronized methods with LM_MONITOR Reviewed-by: mdoerr, mbaesken --- src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp | 6 +++++- src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp index 684c06614a97a..92a39e6e3565b 100644 --- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp @@ -213,7 +213,11 @@ int LIR_Assembler::emit_unwind_handler() { if (method()->is_synchronized()) { monitor_address(0, FrameMap::R4_opr); stub = new MonitorExitStub(FrameMap::R4_opr, true, 0); - __ unlock_object(R5, R6, R4, *stub->entry()); + if (LockingMode == LM_MONITOR) { + __ b(*stub->entry()); + } else { + __ unlock_object(R5, R6, R4, *stub->entry()); + } __ bind(*stub->continuation()); } diff --git a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp index 83fad376d292a..ea4d76e200fc2 100644 --- a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp @@ -114,6 +114,8 @@ void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox /*check without membar and ldarx first*/true); // If compare/exchange succeeded we found an unlocked object and we now have locked it // hence we are done. + } else { + assert(false, "Unhandled LockingMode:%d", LockingMode); } b(done); @@ -168,6 +170,8 @@ void C1_MacroAssembler::unlock_object(Register Rmark, Register Roop, Register Rb MacroAssembler::cmpxchgx_hint_release_lock(), noreg, &slow_int); + } else { + assert(false, "Unhandled LockingMode:%d", LockingMode); } b(done); bind(slow_int); From 285385247aaa262866697ed848040f05f4d94988 Mon Sep 17 00:00:00 2001 From: Yudi Zheng Date: Wed, 16 Oct 2024 19:58:27 +0000 Subject: [PATCH 095/118] 8342332: [JVMCI] Export CompilerToVM::Data::dtanh Reviewed-by: never --- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index a26cd5efe23b1..02e6eaf40f375 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -132,6 +132,7 @@ static_field(CompilerToVM::Data, dsin, address) \ static_field(CompilerToVM::Data, dcos, address) \ static_field(CompilerToVM::Data, dtan, address) \ + static_field(CompilerToVM::Data, dtanh, address) \ static_field(CompilerToVM::Data, dexp, address) \ static_field(CompilerToVM::Data, dlog, address) \ static_field(CompilerToVM::Data, dlog10, address) \ From b4ab290fd7c3d914154755a1539b48ba33338c26 Mon Sep 17 00:00:00 2001 From: Valerie Peng Date: Wed, 16 Oct 2024 21:26:57 +0000 Subject: [PATCH 096/118] 8331959: Update PKCS#11 Cryptographic Token Interface to v3.1 Reviewed-by: weijun, ascarpino --- .../share/legal/pkcs11cryptotoken.md | 24 +- .../share/native/libj2pkcs11/pkcs11.h | 18 +- .../share/native/libj2pkcs11/pkcs11f.h | 17 +- .../share/native/libj2pkcs11/pkcs11t.h | 287 +++++++++++------- 4 files changed, 215 insertions(+), 131 deletions(-) diff --git a/src/jdk.crypto.cryptoki/share/legal/pkcs11cryptotoken.md b/src/jdk.crypto.cryptoki/share/legal/pkcs11cryptotoken.md index 08d1e3c713d92..7877f54fe6e39 100644 --- a/src/jdk.crypto.cryptoki/share/legal/pkcs11cryptotoken.md +++ b/src/jdk.crypto.cryptoki/share/legal/pkcs11cryptotoken.md @@ -1,16 +1,16 @@ -## OASIS PKCS #11 Cryptographic Token Interface v3.0 +## OASIS PKCS #11 Cryptographic Token Interface v3.1 ### OASIS PKCS #11 Cryptographic Token Interface License
       
      -Copyright © OASIS Open 2020. All Rights Reserved.
      +Copyright © OASIS Open 2023. All Rights Reserved.
       
      -    All capitalized terms in the following text have the meanings
      +All capitalized terms in the following text have the meanings
       assigned to them in the OASIS Intellectual Property Rights Policy (the
       "OASIS IPR Policy"). The full Policy may be found at the OASIS website:
      -[http://www.oasis-open.org/policies-guidelines/ipr]
      +[https://www.oasis-open.org/policies-guidelines/ipr/].
       
      -    This document and translations of it may be copied and furnished to
      +This document and translations of it may be copied and furnished to
       others, and derivative works that comment on or otherwise explain it or
       assist in its implementation may be prepared, copied, published, and
       distributed, in whole or in part, without restriction of any kind,
      @@ -23,10 +23,10 @@ Committee (in which case the rules applicable to copyrights, as set
       forth in the OASIS IPR Policy, must be followed) or as required to
       translate it into languages other than English.
       
      -    The limited permissions granted above are perpetual and will not be
      +The limited permissions granted above are perpetual and will not be
       revoked by OASIS or its successors or assigns.
       
      -    This document and the information contained herein is provided on an
      +This document and the information contained herein is provided on an
       "AS IS" basis and OASIS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
       INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
       INFORMATION HEREIN WILL NOT INFRINGE ANY OWNERSHIP RIGHTS OR ANY IMPLIED
      @@ -35,7 +35,11 @@ AND ITS MEMBERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR
       CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THIS DOCUMENT OR ANY
       PART THEREOF.
       
      -    [OASIS requests that any OASIS Party or any other party that
      +As stated in the OASIS IPR Policy, the following three paragraphs in
      +brackets apply to OASIS Standards Final Deliverable documents (Committee
      +Specifications, OASIS Standards, or Approved Errata).
      +
      +[OASIS requests that any OASIS Party or any other party that
       believes it has patent claims that would necessarily be infringed by
       implementations of this OASIS Standards Final Deliverable, to notify
       OASIS TC Administrator and provide an indication of its willingness to
      @@ -43,7 +47,7 @@ grant patent licenses to such patent claims in a manner consistent with
       the IPR Mode of the OASIS Technical Committee that produced this
       deliverable.]
       
      -    [OASIS invites any party to contact the OASIS TC Administrator if it
      +[OASIS invites any party to contact the OASIS TC Administrator if it
       is aware of a claim of ownership of any patent claims that would
       necessarily be infringed by implementations of this OASIS Standards
       Final Deliverable by a patent holder that is not willing to provide a
      @@ -52,7 +56,7 @@ of the OASIS Technical Committee that produced this OASIS Standards
       Final Deliverable. OASIS may include such claims on its website, but
       disclaims any obligation to do so.]
       
      -    [OASIS takes no position regarding the validity or scope of any
      +[OASIS takes no position regarding the validity or scope of any
       intellectual property or other rights that might be claimed to pertain
       to the implementation or use of the technology described in this OASIS
       Standards Final Deliverable or the extent to which any license under
      diff --git a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11.h b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11.h
      index 5b050def5205f..5933da0e3b75c 100644
      --- a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11.h
      +++ b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11.h
      @@ -1,8 +1,11 @@
      -/* Copyright (c) OASIS Open 2016-2019. All Rights Reserved.
      - * Distributed under the terms of the OASIS IPR Policy,
      - * [http://www.oasis-open.org/policies-guidelines/ipr], AS-IS, WITHOUT ANY
      - * IMPLIED OR EXPRESS WARRANTY; there is no warranty of MERCHANTABILITY, FITNESS FOR A
      - * PARTICULAR PURPOSE or NONINFRINGEMENT of the rights of others.
      +/*
      + * PKCS #11 Specification Version 3.1
      + * OASIS Standard
      + * 23 July 2023
      + * Copyright (c) OASIS Open 2023. All Rights Reserved.
      + * Source: https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/os/include/pkcs11-v3.1/
      + * Latest stage of narrative specification: https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/pkcs11-spec-v3.1.html
      + * TC IPR Statement: https://www.oasis-open.org/committees/pkcs11/ipr.php
        */
       
       #ifndef _PKCS11_H_
      @@ -47,7 +50,7 @@ extern "C" {
        *
        * typedef CK_BYTE CK_PTR CK_BYTE_PTR;
        *
      - * If you're using windows, it might be defined by:
      + * If you're using Windows, it might be defined by:
        *
        * #define CK_PTR *
        *
      @@ -65,7 +68,7 @@ extern "C" {
        *   CK_VOID_PTR pReserved
        * );
        *
      - * If you're using Windows to declare a function in a Win32 cryptoki .dll,
      + * If you're using Windows to declare a function in a Win32 Cryptoki .dll,
        * it might be defined by:
        *
        * #define CK_DECLARE_FUNCTION(returnType, name) \
      @@ -241,4 +244,3 @@ struct CK_FUNCTION_LIST {
       
       #endif /* _PKCS11_H_ */
       
      -
      diff --git a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11f.h b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11f.h
      index 0553c1dc73ca2..80c43400d05f8 100644
      --- a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11f.h
      +++ b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11f.h
      @@ -1,12 +1,11 @@
      -/* Copyright (c) OASIS Open 2016, 2019. All Rights Reserved./
      - * /Distributed under the terms of the OASIS IPR Policy,
      - * [http://www.oasis-open.org/policies-guidelines/ipr], AS-IS, WITHOUT ANY
      - * IMPLIED OR EXPRESS WARRANTY; there is no warranty of MERCHANTABILITY, FITNESS FOR A
      - * PARTICULAR PURPOSE or NONINFRINGEMENT of the rights of others.
      - */
      -
      -/* Latest version of the specification:
      - * http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html
      +/*
      + * PKCS #11 Specification Version 3.1
      + * OASIS Standard
      + * 23 July 2023
      + * Copyright (c) OASIS Open 2023. All Rights Reserved.
      + * Source: https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/os/include/pkcs11-v3.1/
      + * Latest stage of narrative specification: https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/pkcs11-spec-v3.1.html
      + * TC IPR Statement: https://www.oasis-open.org/committees/pkcs11/ipr.php
        */
       
       /* This header file contains pretty much everything about all the
      diff --git a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11t.h b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11t.h
      index ab6ef326e8bd6..79d7cf7d7dae7 100644
      --- a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11t.h
      +++ b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11t.h
      @@ -1,12 +1,11 @@
      -/* Copyright (c) OASIS Open 2016, 2019. All Rights Reserved./
      - * /Distributed under the terms of the OASIS IPR Policy,
      - * [http://www.oasis-open.org/policies-guidelines/ipr], AS-IS, WITHOUT ANY
      - * IMPLIED OR EXPRESS WARRANTY; there is no warranty of MERCHANTABILITY, FITNESS FOR A
      - * PARTICULAR PURPOSE or NONINFRINGEMENT of the rights of others.
      - */
      -
      -/* Latest version of the specification:
      - * http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html
      +/*
      + * PKCS #11 Specification Version 3.1
      + * OASIS Standard
      + * 23 July 2023
      + * Copyright (c) OASIS Open 2023. All Rights Reserved.
      + * Source: https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/os/include/pkcs11-v3.1/
      + * Latest stage of narrative specification: https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/pkcs11-spec-v3.1.html
      + * TC IPR Statement: https://www.oasis-open.org/committees/pkcs11/ipr.php
        */
       
       /* See top of pkcs11.h for information about the macros that
      @@ -18,7 +17,7 @@
       #define _PKCS11T_H_ 1
       
       #define CRYPTOKI_VERSION_MAJOR          3
      -#define CRYPTOKI_VERSION_MINOR          0
      +#define CRYPTOKI_VERSION_MINOR          1
       #define CRYPTOKI_VERSION_AMENDMENT      0
       
       #define CK_TRUE         1
      @@ -329,8 +328,11 @@ typedef CK_OBJECT_CLASS CK_PTR CK_OBJECT_CLASS_PTR;
       #define CKP_EXTENDED_PROVIDER         0x00000002UL
       #define CKP_AUTHENTICATION_TOKEN      0x00000003UL
       #define CKP_PUBLIC_CERTIFICATES_TOKEN 0x00000004UL
      +#define CKP_COMPLETE_PROVIDER         0x00000005UL
      +#define CKP_HKDF_TLS_TOKEN            0x00000006UL
       #define CKP_VENDOR_DEFINED            0x80000000UL
       
      +
       /* CK_HW_FEATURE_TYPE is a value that identifies the hardware feature type
        * of an object with CK_OBJECT_CLASS equal to CKO_HW_FEATURE.
        */
      @@ -409,9 +411,11 @@ typedef CK_ULONG          CK_KEY_TYPE;
       #define CKK_EC_EDWARDS          0x00000040UL
       #define CKK_EC_MONTGOMERY       0x00000041UL
       #define CKK_HKDF                0x00000042UL
      +
       #define CKK_SHA512_224_HMAC     0x00000043UL
       #define CKK_SHA512_256_HMAC     0x00000044UL
       #define CKK_SHA512_T_HMAC       0x00000045UL
      +#define CKK_HSS                 0x00000046UL
       
       #define CKK_VENDOR_DEFINED      0x80000000UL
       
      @@ -481,9 +485,9 @@ typedef CK_ULONG          CK_ATTRIBUTE_TYPE;
       #define CKA_CERTIFICATE_CATEGORY        0x00000087UL
       #define CKA_JAVA_MIDP_SECURITY_DOMAIN   0x00000088UL
       #define CKA_URL                         0x00000089UL
      -#define CKA_HASH_OF_SUBJECT_PUBLIC_KEY  0x0000008AUL
      -#define CKA_HASH_OF_ISSUER_PUBLIC_KEY   0x0000008BUL
      -#define CKA_NAME_HASH_ALGORITHM         0x0000008CUL
      +#define CKA_HASH_OF_SUBJECT_PUBLIC_KEY  0x0000008aUL
      +#define CKA_HASH_OF_ISSUER_PUBLIC_KEY   0x0000008bUL
      +#define CKA_NAME_HASH_ALGORITHM         0x0000008cUL
       #define CKA_CHECK_VALUE                 0x00000090UL
       
       #define CKA_KEY_TYPE           0x00000100UL
      @@ -496,9 +500,9 @@ typedef CK_ULONG          CK_ATTRIBUTE_TYPE;
       #define CKA_UNWRAP             0x00000107UL
       #define CKA_SIGN               0x00000108UL
       #define CKA_SIGN_RECOVER       0x00000109UL
      -#define CKA_VERIFY             0x0000010AUL
      -#define CKA_VERIFY_RECOVER     0x0000010BUL
      -#define CKA_DERIVE             0x0000010CUL
      +#define CKA_VERIFY             0x0000010aUL
      +#define CKA_VERIFY_RECOVER     0x0000010bUL
      +#define CKA_DERIVE             0x0000010cUL
       #define CKA_START_DATE         0x00000110UL
       #define CKA_END_DATE           0x00000111UL
       #define CKA_MODULUS            0x00000120UL
      @@ -555,12 +559,12 @@ typedef CK_ULONG          CK_ATTRIBUTE_TYPE;
       #define CKA_OTP_TIME_REQUIREMENT      0x00000225UL
       #define CKA_OTP_COUNTER_REQUIREMENT   0x00000226UL
       #define CKA_OTP_PIN_REQUIREMENT       0x00000227UL
      -#define CKA_OTP_COUNTER               0x0000022EUL
      -#define CKA_OTP_TIME                  0x0000022FUL
      -#define CKA_OTP_USER_IDENTIFIER       0x0000022AUL
      -#define CKA_OTP_SERVICE_IDENTIFIER    0x0000022BUL
      -#define CKA_OTP_SERVICE_LOGO          0x0000022CUL
      -#define CKA_OTP_SERVICE_LOGO_TYPE     0x0000022DUL
      +#define CKA_OTP_COUNTER               0x0000022eUL
      +#define CKA_OTP_TIME                  0x0000022fUL
      +#define CKA_OTP_USER_IDENTIFIER       0x0000022aUL
      +#define CKA_OTP_SERVICE_IDENTIFIER    0x0000022bUL
      +#define CKA_OTP_SERVICE_LOGO          0x0000022cUL
      +#define CKA_OTP_SERVICE_LOGO_TYPE     0x0000022dUL
       
       #define CKA_GOSTR3410_PARAMS            0x00000250UL
       #define CKA_GOSTR3411_PARAMS            0x00000251UL
      @@ -586,6 +590,7 @@ typedef CK_ULONG          CK_ATTRIBUTE_TYPE;
       #define CKA_SUPPORTED_CMS_ATTRIBUTES    0x00000503UL
       #define CKA_ALLOWED_MECHANISMS          (CKF_ARRAY_ATTRIBUTE|0x00000600UL)
       #define CKA_PROFILE_ID                  0x00000601UL
      +
       #define CKA_X2RATCHET_BAG               0x00000602UL
       #define CKA_X2RATCHET_BAGSIZE           0x00000603UL
       #define CKA_X2RATCHET_BOBS1STMSG        0x00000604UL
      @@ -603,6 +608,13 @@ typedef CK_ULONG          CK_ATTRIBUTE_TYPE;
       #define CKA_X2RATCHET_NS                0x00000610UL
       #define CKA_X2RATCHET_PNS               0x00000611UL
       #define CKA_X2RATCHET_RK                0x00000612UL
      +/* HSS */
      +#define CKA_HSS_LEVELS                  0x00000617UL
      +#define CKA_HSS_LMS_TYPE                0x00000618UL
      +#define CKA_HSS_LMOTS_TYPE              0x00000619UL
      +#define CKA_HSS_LMS_TYPES               0x0000061aUL
      +#define CKA_HSS_LMOTS_TYPES             0x0000061bUL
      +#define CKA_HSS_KEYS_REMAINING          0x0000061cUL
       
       #define CKA_VENDOR_DEFINED              0x80000000UL
       
      @@ -644,11 +656,11 @@ typedef CK_ULONG          CK_MECHANISM_TYPE;
       #define CKM_RIPEMD160_RSA_PKCS         0x00000008UL
       #define CKM_RSA_PKCS_OAEP              0x00000009UL
       
      -#define CKM_RSA_X9_31_KEY_PAIR_GEN     0x0000000AUL
      -#define CKM_RSA_X9_31                  0x0000000BUL
      -#define CKM_SHA1_RSA_X9_31             0x0000000CUL
      -#define CKM_RSA_PKCS_PSS               0x0000000DUL
      -#define CKM_SHA1_RSA_PKCS_PSS          0x0000000EUL
      +#define CKM_RSA_X9_31_KEY_PAIR_GEN     0x0000000aUL
      +#define CKM_RSA_X9_31                  0x0000000bUL
      +#define CKM_SHA1_RSA_X9_31             0x0000000cUL
      +#define CKM_RSA_PKCS_PSS               0x0000000dUL
      +#define CKM_SHA1_RSA_PKCS_PSS          0x0000000eUL
       
       #define CKM_DSA_KEY_PAIR_GEN           0x00000010UL
       #define CKM_DSA                        0x00000011UL
      @@ -659,8 +671,8 @@ typedef CK_ULONG          CK_MECHANISM_TYPE;
       #define CKM_DSA_SHA512                 0x00000016UL
       #define CKM_DSA_SHA3_224               0x00000018UL
       #define CKM_DSA_SHA3_256               0x00000019UL
      -#define CKM_DSA_SHA3_384               0x0000001AUL
      -#define CKM_DSA_SHA3_512               0x0000001BUL
      +#define CKM_DSA_SHA3_384               0x0000001aUL
      +#define CKM_DSA_SHA3_512               0x0000001bUL
       
       #define CKM_DH_PKCS_KEY_PAIR_GEN       0x00000020UL
       #define CKM_DH_PKCS_DERIVE             0x00000021UL
      @@ -682,12 +694,12 @@ typedef CK_ULONG          CK_MECHANISM_TYPE;
       
       #define CKM_SHA512_224                 0x00000048UL
       #define CKM_SHA512_224_HMAC            0x00000049UL
      -#define CKM_SHA512_224_HMAC_GENERAL    0x0000004AUL
      -#define CKM_SHA512_224_KEY_DERIVATION  0x0000004BUL
      -#define CKM_SHA512_256                 0x0000004CUL
      -#define CKM_SHA512_256_HMAC            0x0000004DUL
      -#define CKM_SHA512_256_HMAC_GENERAL    0x0000004EUL
      -#define CKM_SHA512_256_KEY_DERIVATION  0x0000004FUL
      +#define CKM_SHA512_224_HMAC_GENERAL    0x0000004aUL
      +#define CKM_SHA512_224_KEY_DERIVATION  0x0000004bUL
      +#define CKM_SHA512_256                 0x0000004cUL
      +#define CKM_SHA512_256_HMAC            0x0000004dUL
      +#define CKM_SHA512_256_HMAC_GENERAL    0x0000004eUL
      +#define CKM_SHA512_256_KEY_DERIVATION  0x0000004fUL
       
       #define CKM_SHA512_T                   0x00000050UL
       #define CKM_SHA512_T_HMAC              0x00000051UL
      @@ -781,25 +793,25 @@ typedef CK_ULONG          CK_MECHANISM_TYPE;
       #define CKM_SECURID                    0x00000282UL
       #define CKM_HOTP_KEY_GEN               0x00000290UL
       #define CKM_HOTP                       0x00000291UL
      -#define CKM_ACTI                       0x000002A0UL
      -#define CKM_ACTI_KEY_GEN               0x000002A1UL
      -
      -#define CKM_SHA3_256                   0x000002B0UL
      -#define CKM_SHA3_256_HMAC              0x000002B1UL
      -#define CKM_SHA3_256_HMAC_GENERAL      0x000002B2UL
      -#define CKM_SHA3_256_KEY_GEN           0x000002B3UL
      -#define CKM_SHA3_224                   0x000002B5UL
      -#define CKM_SHA3_224_HMAC              0x000002B6UL
      -#define CKM_SHA3_224_HMAC_GENERAL      0x000002B7UL
      -#define CKM_SHA3_224_KEY_GEN           0x000002B8UL
      -#define CKM_SHA3_384                   0x000002C0UL
      -#define CKM_SHA3_384_HMAC              0x000002C1UL
      -#define CKM_SHA3_384_HMAC_GENERAL      0x000002C2UL
      -#define CKM_SHA3_384_KEY_GEN           0x000002C3UL
      -#define CKM_SHA3_512                   0x000002D0UL
      -#define CKM_SHA3_512_HMAC              0x000002D1UL
      -#define CKM_SHA3_512_HMAC_GENERAL      0x000002D2UL
      -#define CKM_SHA3_512_KEY_GEN           0x000002D3UL
      +#define CKM_ACTI                       0x000002a0UL
      +#define CKM_ACTI_KEY_GEN               0x000002a1UL
      +
      +#define CKM_SHA3_256                   0x000002b0UL
      +#define CKM_SHA3_256_HMAC              0x000002b1UL
      +#define CKM_SHA3_256_HMAC_GENERAL      0x000002b2UL
      +#define CKM_SHA3_256_KEY_GEN           0x000002b3UL
      +#define CKM_SHA3_224                   0x000002b5UL
      +#define CKM_SHA3_224_HMAC              0x000002b6UL
      +#define CKM_SHA3_224_HMAC_GENERAL      0x000002b7UL
      +#define CKM_SHA3_224_KEY_GEN           0x000002b8UL
      +#define CKM_SHA3_384                   0x000002c0UL
      +#define CKM_SHA3_384_HMAC              0x000002c1UL
      +#define CKM_SHA3_384_HMAC_GENERAL      0x000002c2UL
      +#define CKM_SHA3_384_KEY_GEN           0x000002c3UL
      +#define CKM_SHA3_512                   0x000002d0UL
      +#define CKM_SHA3_512_HMAC              0x000002d1UL
      +#define CKM_SHA3_512_HMAC_GENERAL      0x000002d2UL
      +#define CKM_SHA3_512_KEY_GEN           0x000002d3UL
       
       
       #define CKM_CAST_KEY_GEN               0x00000300UL
      @@ -870,9 +882,9 @@ typedef CK_ULONG          CK_MECHANISM_TYPE;
       #define CKM_SHA3_256_KEY_DERIVATION    0x00000397UL
       #define CKM_SHA3_224_KEY_DERIVATION    0x00000398UL
       #define CKM_SHA3_384_KEY_DERIVATION    0x00000399UL
      -#define CKM_SHA3_512_KEY_DERIVATION    0x0000039AUL
      -#define CKM_SHAKE_128_KEY_DERIVATION   0x0000039BUL
      -#define CKM_SHAKE_256_KEY_DERIVATION   0x0000039CUL
      +#define CKM_SHA3_512_KEY_DERIVATION    0x0000039aUL
      +#define CKM_SHAKE_128_KEY_DERIVATION   0x0000039bUL
      +#define CKM_SHAKE_256_KEY_DERIVATION   0x0000039cUL
       #define CKM_SHA3_256_KEY_DERIVE  CKM_SHA3_256_KEY_DERIVATION
       #define CKM_SHA3_224_KEY_DERIVE  CKM_SHA3_224_KEY_DERIVATION
       #define CKM_SHA3_384_KEY_DERIVE  CKM_SHA3_384_KEY_DERIVATION
      @@ -880,40 +892,42 @@ typedef CK_ULONG          CK_MECHANISM_TYPE;
       #define CKM_SHAKE_128_KEY_DERIVE CKM_SHAKE_128_KEY_DERIVATION
       #define CKM_SHAKE_256_KEY_DERIVE CKM_SHAKE_256_KEY_DERIVATION
       
      -#define CKM_PBE_MD2_DES_CBC            0x000003A0UL
      -#define CKM_PBE_MD5_DES_CBC            0x000003A1UL
      -#define CKM_PBE_MD5_CAST_CBC           0x000003A2UL
      -#define CKM_PBE_MD5_CAST3_CBC          0x000003A3UL
      -#define CKM_PBE_MD5_CAST5_CBC          0x000003A4UL /* Deprecated */
      -#define CKM_PBE_MD5_CAST128_CBC        0x000003A4UL
      -#define CKM_PBE_SHA1_CAST5_CBC         0x000003A5UL /* Deprecated */
      -#define CKM_PBE_SHA1_CAST128_CBC       0x000003A5UL
      -#define CKM_PBE_SHA1_RC4_128           0x000003A6UL
      -#define CKM_PBE_SHA1_RC4_40            0x000003A7UL
      -#define CKM_PBE_SHA1_DES3_EDE_CBC      0x000003A8UL
      -#define CKM_PBE_SHA1_DES2_EDE_CBC      0x000003A9UL
      -#define CKM_PBE_SHA1_RC2_128_CBC       0x000003AAUL
      -#define CKM_PBE_SHA1_RC2_40_CBC        0x000003ABUL
      -
      -#define CKM_PKCS5_PBKD2                0x000003B0UL
      -
      -#define CKM_PBA_SHA1_WITH_SHA1_HMAC    0x000003C0UL
      -
      -#define CKM_WTLS_PRE_MASTER_KEY_GEN         0x000003D0UL
      -#define CKM_WTLS_MASTER_KEY_DERIVE          0x000003D1UL
      -#define CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC   0x000003D2UL
      -#define CKM_WTLS_PRF                        0x000003D3UL
      -#define CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE  0x000003D4UL
      -#define CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE  0x000003D5UL
      -
      -#define CKM_TLS12_MAC                       0x000003D8UL
      -#define CKM_TLS12_KDF                       0x000003D9UL
      -#define CKM_TLS12_MASTER_KEY_DERIVE         0x000003E0UL
      -#define CKM_TLS12_KEY_AND_MAC_DERIVE        0x000003E1UL
      -#define CKM_TLS12_MASTER_KEY_DERIVE_DH      0x000003E2UL
      -#define CKM_TLS12_KEY_SAFE_DERIVE           0x000003E3UL
      -#define CKM_TLS_MAC                         0x000003E4UL
      -#define CKM_TLS_KDF                         0x000003E5UL
      +#define CKM_PBE_MD2_DES_CBC            0x000003a0UL
      +#define CKM_PBE_MD5_DES_CBC            0x000003a1UL
      +#define CKM_PBE_MD5_CAST_CBC           0x000003a2UL
      +#define CKM_PBE_MD5_CAST3_CBC          0x000003a3UL
      +#define CKM_PBE_MD5_CAST5_CBC          0x000003a4UL /* Deprecated */
      +#define CKM_PBE_MD5_CAST128_CBC        0x000003a4UL
      +#define CKM_PBE_SHA1_CAST5_CBC         0x000003a5UL /* Deprecated */
      +#define CKM_PBE_SHA1_CAST128_CBC       0x000003a5UL
      +#define CKM_PBE_SHA1_RC4_128           0x000003a6UL
      +#define CKM_PBE_SHA1_RC4_40            0x000003a7UL
      +#define CKM_PBE_SHA1_DES3_EDE_CBC      0x000003a8UL
      +#define CKM_PBE_SHA1_DES2_EDE_CBC      0x000003a9UL
      +#define CKM_PBE_SHA1_RC2_128_CBC       0x000003aaUL
      +#define CKM_PBE_SHA1_RC2_40_CBC        0x000003abUL
      +
      +#define CKM_PKCS5_PBKD2                0x000003b0UL
      +
      +#define CKM_PBA_SHA1_WITH_SHA1_HMAC    0x000003c0UL
      +
      +#define CKM_WTLS_PRE_MASTER_KEY_GEN         0x000003d0UL
      +#define CKM_WTLS_MASTER_KEY_DERIVE          0x000003d1UL
      +#define CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC   0x000003d2UL
      +#define CKM_WTLS_PRF                        0x000003d3UL
      +#define CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE  0x000003d4UL
      +#define CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE  0x000003d5UL
      +
      +#define CKM_TLS10_MAC_SERVER                0x000003d6UL
      +#define CKM_TLS10_MAC_CLIENT                0x000003d7UL
      +#define CKM_TLS12_MAC                       0x000003d8UL
      +#define CKM_TLS12_KDF                       0x000003d9UL
      +#define CKM_TLS12_MASTER_KEY_DERIVE         0x000003e0UL
      +#define CKM_TLS12_KEY_AND_MAC_DERIVE        0x000003e1UL
      +#define CKM_TLS12_MASTER_KEY_DERIVE_DH      0x000003e2UL
      +#define CKM_TLS12_KEY_SAFE_DERIVE           0x000003e3UL
      +#define CKM_TLS_MAC                         0x000003e4UL
      +#define CKM_TLS_KDF                         0x000003e5UL
       
       #define CKM_KEY_WRAP_LYNKS             0x00000400UL
       #define CKM_KEY_WRAP_SET_OAEP          0x00000401UL
      @@ -983,7 +997,7 @@ typedef CK_ULONG          CK_MECHANISM_TYPE;
       #define CKM_ECDSA_SHA256               0x00001044UL
       #define CKM_ECDSA_SHA384               0x00001045UL
       #define CKM_ECDSA_SHA512               0x00001046UL
      -#define CKM_EC_KEY_PAIR_GEN_W_EXTRA_BITS 0x0000140BUL
      +#define CKM_EC_KEY_PAIR_GEN_W_EXTRA_BITS 0x0000140bUL
       
       #define CKM_ECDH1_DERIVE               0x00001050UL
       #define CKM_ECDH1_COFACTOR_DERIVE      0x00001051UL
      @@ -1012,12 +1026,12 @@ typedef CK_ULONG          CK_MECHANISM_TYPE;
       #define CKM_AES_GCM                    0x00001087UL
       #define CKM_AES_CCM                    0x00001088UL
       #define CKM_AES_CTS                    0x00001089UL
      -#define CKM_AES_CMAC                   0x0000108AUL
      -#define CKM_AES_CMAC_GENERAL           0x0000108BUL
      +#define CKM_AES_CMAC                   0x0000108aUL
      +#define CKM_AES_CMAC_GENERAL           0x0000108bUL
       
      -#define CKM_AES_XCBC_MAC               0x0000108CUL
      -#define CKM_AES_XCBC_MAC_96            0x0000108DUL
      -#define CKM_AES_GMAC                   0x0000108EUL
      +#define CKM_AES_XCBC_MAC               0x0000108cUL
      +#define CKM_AES_XCBC_MAC_96            0x0000108dUL
      +#define CKM_AES_GMAC                   0x0000108eUL
       
       #define CKM_BLOWFISH_KEY_GEN           0x00001090UL
       #define CKM_BLOWFISH_CBC               0x00001091UL
      @@ -1066,6 +1080,7 @@ typedef CK_ULONG          CK_MECHANISM_TYPE;
       #define CKM_AES_KEY_WRAP               0x00002109UL     /* WAS: 0x00001090 */
       #define CKM_AES_KEY_WRAP_PAD           0x0000210AUL     /* WAS: 0x00001091 */
       #define CKM_AES_KEY_WRAP_KWP           0x0000210BUL
      +#define CKM_AES_KEY_WRAP_PKCS7         0x0000210CUL
       
       #define CKM_RSA_PKCS_TPM_1_1           0x00004001UL
       #define CKM_RSA_PKCS_OAEP_TPM_1_1      0x00004002UL
      @@ -1125,6 +1140,14 @@ typedef CK_ULONG          CK_MECHANISM_TYPE;
       #define CKM_SP800_108_FEEDBACK_KDF     0x000003adUL
       #define CKM_SP800_108_DOUBLE_PIPELINE_KDF 0x000003aeUL
       
      +#define CKM_IKE2_PRF_PLUS_DERIVE       0x0000402eUL
      +#define CKM_IKE_PRF_DERIVE             0x0000402fUL
      +#define CKM_IKE1_PRF_DERIVE            0x00004030UL
      +#define CKM_IKE1_EXTENDED_DERIVE       0x00004031UL
      +#define CKM_HSS_KEY_PAIR_GEN           0x00004032UL
      +#define CKM_HSS                        0x00004033UL
      +
      +
       #define CKM_VENDOR_DEFINED             0x80000000UL
       
       typedef CK_MECHANISM_TYPE CK_PTR CK_MECHANISM_TYPE_PTR;
      @@ -1320,6 +1343,7 @@ typedef CK_ULONG          CK_RV;
       #define CKR_FUNCTION_REJECTED                 0x00000200UL
       #define CKR_TOKEN_RESOURCE_EXCEEDED           0x00000201UL
       #define CKR_OPERATION_CANCEL_FAILED           0x00000202UL
      +#define CKR_KEY_EXHAUSTED                     0x00000203UL
       
       #define CKR_VENDOR_DEFINED                    0x80000000UL
       
      @@ -1436,6 +1460,7 @@ typedef CK_RSA_PKCS_MGF_TYPE CK_PTR CK_RSA_PKCS_MGF_TYPE_PTR;
       #define CKG_MGF1_SHA3_384     0x00000008UL
       #define CKG_MGF1_SHA3_512     0x00000009UL
       
      +
       /* CK_RSA_PKCS_OAEP_SOURCE_TYPE  is used to indicate the source
        * of the encoding parameter when formatting a message block
        * for the PKCS #1 OAEP encryption scheme.
      @@ -1701,8 +1726,7 @@ typedef struct CK_DES_CBC_ENCRYPT_DATA_PARAMS {
           CK_ULONG    length;
       } CK_DES_CBC_ENCRYPT_DATA_PARAMS;
       
      -typedef CK_DES_CBC_ENCRYPT_DATA_PARAMS CK_PTR \
      -        CK_DES_CBC_ENCRYPT_DATA_PARAMS_PTR;
      +typedef CK_DES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_DES_CBC_ENCRYPT_DATA_PARAMS_PTR;
       
       typedef struct CK_AES_CBC_ENCRYPT_DATA_PARAMS {
           CK_BYTE     iv[16];
      @@ -1710,8 +1734,7 @@ typedef struct CK_AES_CBC_ENCRYPT_DATA_PARAMS {
           CK_ULONG    length;
       } CK_AES_CBC_ENCRYPT_DATA_PARAMS;
       
      -typedef CK_AES_CBC_ENCRYPT_DATA_PARAMS CK_PTR \
      -        CK_AES_CBC_ENCRYPT_DATA_PARAMS_PTR;
      +typedef CK_AES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_AES_CBC_ENCRYPT_DATA_PARAMS_PTR;
       
       /* CK_SKIPJACK_PRIVATE_WRAP_PARAMS provides the parameters to the
        * CKM_SKIPJACK_PRIVATE_WRAP mechanism
      @@ -2051,6 +2074,7 @@ typedef CK_ULONG CK_GENERATOR_FUNCTION;
       #define CKG_GENERATE         0x00000001UL
       #define CKG_GENERATE_COUNTER 0x00000002UL
       #define CKG_GENERATE_RANDOM  0x00000003UL
      +#define CKG_GENERATE_COUNTER_XOR 0x00000004UL
       
       typedef struct CK_GCM_MESSAGE_PARAMS {
           CK_BYTE_PTR           pIv;
      @@ -2061,7 +2085,7 @@ typedef struct CK_GCM_MESSAGE_PARAMS {
           CK_ULONG              ulTagBits;
       } CK_GCM_MESSAGE_PARAMS;
       
      -typedef CK_GCM_MESSAGE_PARAMS CK_GCM_MESSAGE_PARAMS_PTR;
      +typedef CK_GCM_MESSAGE_PARAMS CK_PTR CK_GCM_MESSAGE_PARAMS_PTR;
       
       typedef struct CK_CCM_PARAMS {
           CK_ULONG    ulDataLen;
      @@ -2084,7 +2108,7 @@ typedef struct CK_CCM_MESSAGE_PARAMS {
           CK_ULONG              ulMACLen;
       } CK_CCM_MESSAGE_PARAMS;
       
      -typedef CK_CCM_MESSAGE_PARAMS CK_CCM_MESSAGE_PARAMS_PTR;
      +typedef CK_CCM_MESSAGE_PARAMS CK_PTR CK_CCM_MESSAGE_PARAMS_PTR;
       
       /* Deprecated. Use CK_GCM_PARAMS */
       typedef struct CK_AES_GCM_PARAMS {
      @@ -2339,7 +2363,6 @@ typedef struct CK_SALSA20_PARAMS {
           CK_BYTE_PTR pNonce;
           CK_ULONG    ulNonceBits;
       } CK_SALSA20_PARAMS;
      -
       typedef CK_SALSA20_PARAMS CK_PTR CK_SALSA20_PARAMS_PTR;
       
       typedef struct CK_SALSA20_CHACHA20_POLY1305_PARAMS {
      @@ -2423,6 +2446,7 @@ typedef struct CK_XEDDSA_PARAMS {
       } CK_XEDDSA_PARAMS;
       typedef CK_XEDDSA_PARAMS CK_PTR CK_XEDDSA_PARAMS_PTR;
       
      +/* HKDF params */
       typedef struct CK_HKDF_PARAMS {
           CK_BBOOL          bExtract;
           CK_BBOOL          bExpand;
      @@ -2440,5 +2464,60 @@ typedef CK_HKDF_PARAMS CK_PTR CK_HKDF_PARAMS_PTR;
       #define CKF_HKDF_SALT_DATA   0x00000002UL
       #define CKF_HKDF_SALT_KEY    0x00000004UL
       
      +/* HSS */
      +typedef CK_ULONG                   CK_HSS_LEVELS;
      +typedef CK_ULONG                   CK_LMS_TYPE;
      +typedef CK_ULONG                   CK_LMOTS_TYPE;
      +
      +typedef struct specifiedParams {
      +    CK_HSS_LEVELS levels;
      +    CK_LMS_TYPE   lm_type[8];
      +    CK_LMOTS_TYPE lm_ots_type[8];
      +} specifiedParams;
      +
      +/* IKE Params */
      +typedef struct CK_IKE2_PRF_PLUS_DERIVE_PARAMS {
      +    CK_MECHANISM_TYPE prfMechanism;
      +    CK_BBOOL          bHasSeedKey;
      +    CK_OBJECT_HANDLE  hSeedKey;
      +    CK_BYTE_PTR       pSeedData;
      +    CK_ULONG          ulSeedDataLen;
      +} CK_IKE2_PRF_PLUS_DERIVE_PARAMS;
      +typedef CK_IKE2_PRF_PLUS_DERIVE_PARAMS CK_PTR CK_IKE2_PRF_PLUS_DERIVE_PARAMS_PTR;
      +
      +typedef struct CK_IKE_PRF_DERIVE_PARAMS {
      +    CK_MECHANISM_TYPE prfMechanism;
      +    CK_BBOOL          bDataAsKey;
      +    CK_BBOOL          bRekey;
      +    CK_BYTE_PTR       pNi;
      +    CK_ULONG          ulNiLen;
      +    CK_BYTE_PTR       pNr;
      +    CK_ULONG          ulNrLen;
      +    CK_OBJECT_HANDLE  hNewKey;
      +} CK_IKE_PRF_DERIVE_PARAMS;
      +typedef CK_IKE_PRF_DERIVE_PARAMS CK_PTR CK_IKE_PRF_DERIVE_PARAMS_PTR;
      +
      +typedef struct CK_IKE1_PRF_DERIVE_PARAMS {
      +    CK_MECHANISM_TYPE prfMechanism;
      +    CK_BBOOL          bHasPrevKey;
      +    CK_OBJECT_HANDLE  hKeygxy;
      +    CK_OBJECT_HANDLE  hPrevKey;
      +    CK_BYTE_PTR       pCKYi;
      +    CK_ULONG          ulCKYiLen;
      +    CK_BYTE_PTR       pCKYr;
      +    CK_ULONG          ulCKYrLen;
      +    CK_BYTE           keyNumber;
      +} CK_IKE1_PRF_DERIVE_PARAMS;
      +typedef CK_IKE1_PRF_DERIVE_PARAMS CK_PTR CK_IKE1_PRF_DERIVE_PARAMS_PTR;
      +
      +typedef struct CK_IKE1_EXTENDED_DERIVE_PARAMS {
      +    CK_MECHANISM_TYPE prfMechanism;
      +    CK_BBOOL          bHasKeygxy;
      +    CK_OBJECT_HANDLE  hKeygxy;
      +    CK_BYTE_PTR       pExtraData;
      +    CK_ULONG          ulExtraDataLen;
      +} CK_IKE1_EXTENDED_DERIVE_PARAMS;
      +typedef CK_IKE1_EXTENDED_DERIVE_PARAMS CK_PTR CK_IKE1_EXTENDED_DERIVE_PARAMS_PTR;
      +
       #endif /* _PKCS11T_H_ */
       
      
      From 4e703b285b5b34fdfb342d194cd744660d4c2be1 Mon Sep 17 00:00:00 2001
      From: Alisen Chung 
      Date: Wed, 16 Oct 2024 21:57:15 +0000
      Subject: [PATCH 097/118] 8340140: Open some dialog awt tests 3
      
      Reviewed-by: prr, honkar
      ---
       .../java/awt/Dialog/ClosingParentTest.java    | 100 +++++++++++++++++
       .../awt/Dialog/FileDialogEmptyTitleTest.java  |  59 ++++++++++
       .../java/awt/Dialog/FileDialogUIUpdate.java   |  83 ++++++++++++++
       .../awt/Dialog/MenuAndModalDialogTest.java    | 104 ++++++++++++++++++
       4 files changed, 346 insertions(+)
       create mode 100644 test/jdk/java/awt/Dialog/ClosingParentTest.java
       create mode 100644 test/jdk/java/awt/Dialog/FileDialogEmptyTitleTest.java
       create mode 100644 test/jdk/java/awt/Dialog/FileDialogUIUpdate.java
       create mode 100644 test/jdk/java/awt/Dialog/MenuAndModalDialogTest.java
      
      diff --git a/test/jdk/java/awt/Dialog/ClosingParentTest.java b/test/jdk/java/awt/Dialog/ClosingParentTest.java
      new file mode 100644
      index 0000000000000..9b2750ab95fa2
      --- /dev/null
      +++ b/test/jdk/java/awt/Dialog/ClosingParentTest.java
      @@ -0,0 +1,100 @@
      +/*
      + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved.
      + * 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.Button;
      +import java.awt.Dialog;
      +import java.awt.Frame;
      +import java.awt.event.ActionEvent;
      +import java.awt.event.ActionListener;
      +import java.awt.event.WindowEvent;
      +import java.awt.event.WindowAdapter;
      +
      +/*
      + * @test
      + * @bug 4336913
      + * @summary On Windows, disable parent window controls while modal dialog is being created.
      + * @library /java/awt/regtesthelpers
      + * @build PassFailJFrame
      + * @run main/manual ClosingParentTest
      + */
      +
      +public class ClosingParentTest {
      +
      +    static String instructions = """
      +            When the test starts, you will see a Frame with a Button
      +            titled 'Show modal dialog with delay'. Press this button
      +            and before the modal Dialog is shown, try to close the
      +            Frame using X button or system menu for windowing systems
      +            which don't provide X button in Window decorations. The
      +            delay before Dialog showing is 5 seconds.
      +            If in test output you see message about WINDOW_CLOSING
      +            being dispatched, then test fails. If no such message
      +            is printed, the test passes.
      +            """;
      +
      +    public static void main(String[] args) throws Exception {
      +        PassFailJFrame.builder()
      +                .title("ClosingParentTest")
      +                .instructions(instructions)
      +                .testTimeOut(5)
      +                .rows(10)
      +                .columns(35)
      +                .testUI(ClosingParentTest::createGUI)
      +                .build()
      +                .awaitAndCheck();
      +    }
      +
      +    public static Frame createGUI() {
      +        Frame frame = new Frame("Main Frame");
      +        Dialog dialog = new Dialog(frame, true);
      +
      +        Button button = new Button("Show modal dialog with delay");
      +        button.addActionListener(new ActionListener() {
      +            public void actionPerformed(ActionEvent e) {
      +                try {
      +                    Thread.currentThread().sleep(5000);
      +                } catch (InterruptedException x) {
      +                    x.printStackTrace();
      +                }
      +
      +                dialog.setVisible(true);
      +            }
      +        });
      +        frame.add(button);
      +        frame.pack();
      +        frame.addWindowListener(new WindowAdapter() {
      +            public void windowClosing(WindowEvent e) {
      +                System.out.println("WINDOW_CLOSING dispatched on the frame");
      +            }
      +        });
      +
      +        dialog.setSize(100, 100);
      +        dialog.addWindowListener(new WindowAdapter() {
      +            public void windowClosing(WindowEvent e) {
      +                dialog.dispose();
      +            }
      +        });
      +
      +        return frame;
      +    }
      +}
      diff --git a/test/jdk/java/awt/Dialog/FileDialogEmptyTitleTest.java b/test/jdk/java/awt/Dialog/FileDialogEmptyTitleTest.java
      new file mode 100644
      index 0000000000000..d288a7c18f65f
      --- /dev/null
      +++ b/test/jdk/java/awt/Dialog/FileDialogEmptyTitleTest.java
      @@ -0,0 +1,59 @@
      +/*
      + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved.
      + * 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.FileDialog;
      +import java.awt.Frame;
      +
      +/*
      + * @test
      + * @bug 4177831
      + * @summary solaris: default FileDialog title is not empty
      + * @library /java/awt/regtesthelpers
      + * @build PassFailJFrame
      + * @run main/manual FileDialogEmptyTitleTest
      + */
      +
      +public class FileDialogEmptyTitleTest {
      +    static String instructions = """
      +            Test passes if title of file dialog is empty,
      +            otherwise test failed.
      +            """;
      +
      +    public static void main(String[] args) throws Exception {
      +        PassFailJFrame.builder()
      +                .title("FileDialogEmptyTitleTest")
      +                .instructions(instructions)
      +                .testTimeOut(5)
      +                .rows(10)
      +                .columns(35)
      +                .testUI(FileDialogEmptyTitleTest::createGUI)
      +                .build()
      +                .awaitAndCheck();
      +    }
      +
      +    public static FileDialog createGUI() {
      +        Frame frame = new Frame("invisible dialog owner");
      +        FileDialog fileDialog = new FileDialog(frame);
      +        return fileDialog;
      +    }
      +}
      diff --git a/test/jdk/java/awt/Dialog/FileDialogUIUpdate.java b/test/jdk/java/awt/Dialog/FileDialogUIUpdate.java
      new file mode 100644
      index 0000000000000..f97d947991b43
      --- /dev/null
      +++ b/test/jdk/java/awt/Dialog/FileDialogUIUpdate.java
      @@ -0,0 +1,83 @@
      +/*
      + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
      + * 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.Button;
      +import java.awt.FileDialog;
      +import java.awt.Frame;
      +import java.awt.event.ActionEvent;
      +import java.awt.event.ActionListener;
      +
      +/*
      + * @test
      + * @bug 4859390
      + * @requires (os.family == "windows")
      + * @summary Verify that FileDialog matches the look
      +    of the native windows FileDialog
      + * @library /java/awt/regtesthelpers
      + * @build PassFailJFrame
      + * @run main/manual FileDialogUIUpdate
      + */
      +
      +public class FileDialogUIUpdate extends Frame {
      +    static String instructions = """
      +            Click the button to show the FileDialog. Then open the Paint
      +            application (usually found in Program Files->Accessories).
      +            Select File->Open from Paint to display a native Open dialog.
      +            Compare the native dialog to the AWT FileDialog.
      +            Specifically, confirm that the Places Bar icons are along the left side (or
      +            not, if the native dialog doesn't have them), and that the
      +            dialogs are both resizable (or not).
      +            If the file dialogs both look the same press Pass.  If not,
      +            press Fail.
      +            """;
      +
      +    public static void main(String[] args) throws Exception {
      +        PassFailJFrame.builder()
      +                .title("FileDialogUIUpdate")
      +                .instructions(instructions)
      +                .testTimeOut(5)
      +                .rows(12)
      +                .columns(35)
      +                .testUI(FileDialogUIUpdate::new)
      +                .build()
      +                .awaitAndCheck();
      +    }
      +
      +    public FileDialogUIUpdate() {
      +        final FileDialog fd = new FileDialog(new Frame("FileDialogUIUpdate frame"),
      +                "Open FileDialog");
      +        Button showButton = new Button("Show FileDialog");
      +        setLayout(new BorderLayout());
      +
      +        fd.setDirectory("c:/");
      +        showButton.addActionListener(new ActionListener() {
      +            public void actionPerformed(ActionEvent e) {
      +                fd.setVisible(true);
      +            }
      +        });
      +
      +        add(showButton);
      +        setSize(200, 200);
      +    }
      +}
      diff --git a/test/jdk/java/awt/Dialog/MenuAndModalDialogTest.java b/test/jdk/java/awt/Dialog/MenuAndModalDialogTest.java
      new file mode 100644
      index 0000000000000..c22116ff8df1c
      --- /dev/null
      +++ b/test/jdk/java/awt/Dialog/MenuAndModalDialogTest.java
      @@ -0,0 +1,104 @@
      +/*
      + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
      + * 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.Button;
      +import java.awt.Dialog;
      +import java.awt.Frame;
      +import java.awt.Menu;
      +import java.awt.MenuBar;
      +import java.awt.MenuItem;
      +import java.awt.event.ActionEvent;
      +import java.awt.event.ActionListener;
      +
      +/*
      + * @test
      + * @bug 4070085
      + * @summary Java program locks up X server
      + * @library /java/awt/regtesthelpers
      + * @build PassFailJFrame
      + * @run main/manual MenuAndModalDialogTest
      + */
      +
      +public class MenuAndModalDialogTest {
      +    static Frame frame;
      +    static String instructions = """
      +            1. Bring up the File Menu and leave it up.
      +            2. In a few seconds, the modal dialog will appear.
      +            3. Verify that your system does not lock up when you push the "OK" button.
      +            """;
      +
      +    public static void main(String[] args) throws Exception {
      +        PassFailJFrame pf = PassFailJFrame.builder()
      +                .title("MenuAndModalDialogTest")
      +                .instructions(instructions)
      +                .testTimeOut(5)
      +                .rows(10)
      +                .columns(35)
      +                .testUI(MenuAndModalDialogTest::createFrame)
      +                .build();
      +
      +        // Allow time to pop up the menu
      +        try {
      +            Thread.currentThread().sleep(5000);
      +        } catch (InterruptedException exception) {
      +        }
      +
      +        createDialog();
      +        pf.awaitAndCheck();
      +    }
      +
      +    public static Frame createFrame() {
      +        frame = new Frame("MenuAndModalDialogTest frame");
      +
      +        MenuBar menuBar = new MenuBar();
      +        frame.setMenuBar(menuBar);
      +
      +        Menu file = new Menu("File");
      +        menuBar.add(file);
      +
      +        MenuItem menuItem = new MenuItem("A Menu Entry");
      +        file.add(menuItem);
      +
      +        frame.setSize(200, 200);
      +        frame.setLocationRelativeTo(null);
      +        return frame;
      +    }
      +
      +    public static void createDialog() {
      +        Dialog dialog = new Dialog(frame);
      +
      +        Button button = new Button("OK");
      +        dialog.add(button);
      +        button.addActionListener(
      +                new ActionListener() {
      +                    public void actionPerformed(ActionEvent e) {
      +                        dialog.dispose();
      +                    }
      +                }
      +        );
      +
      +        dialog.setSize(200, 200);
      +        dialog.setModal(true);
      +        dialog.setVisible(true);
      +    }
      +}
      
      From 3da68900818fc43b777098fe6e244779794d5294 Mon Sep 17 00:00:00 2001
      From: Vlad Zahorodnii 
      Date: Wed, 16 Oct 2024 23:32:41 +0000
      Subject: [PATCH 098/118] 8338751: ConfigureNotify behavior has changed in KWin
       6.2
      
      Reviewed-by: prr, azvegint, serb
      ---
       src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java | 1 +
       1 file changed, 1 insertion(+)
      
      diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java b/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java
      index 069e3b7559bea..1c0f8e27ffb74 100644
      --- a/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java
      +++ b/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java
      @@ -771,6 +771,7 @@ protected Point getNewLocation(XConfigureEvent xe, int leftInset, int topInset)
                   // TODO this should be the default for every case.
                   switch (runningWM) {
                       case XWM.CDE_WM:
      +                case XWM.KDE2_WM:
                       case XWM.MOTIF_WM:
                       case XWM.METACITY_WM:
                       case XWM.MUTTER_WM:
      
      From 58d39c317e332fda994f66529fcd1a0ea0e53151 Mon Sep 17 00:00:00 2001
      From: Tobias Hartmann 
      Date: Thu, 17 Oct 2024 05:03:09 +0000
      Subject: [PATCH 099/118] 8340313: Crash due to invalid oop in nmethod after C1
       patching
      
      Reviewed-by: tschatzl, kvn, dlong
      ---
       .../cpu/aarch64/nativeInst_aarch64.cpp        |   2 +-
       src/hotspot/cpu/ppc/nativeInst_ppc.cpp        |   4 +-
       src/hotspot/cpu/riscv/nativeInst_riscv.cpp    |   6 +-
       src/hotspot/cpu/s390/nativeInst_s390.cpp      |   4 +-
       src/hotspot/cpu/x86/nativeInst_x86.cpp        |   4 +-
       src/hotspot/share/c1/c1_Runtime1.cpp          |  12 +-
       src/hotspot/share/code/nmethod.cpp            |   2 +-
       src/hotspot/share/runtime/mutexLocker.cpp     |   2 -
       src/hotspot/share/runtime/mutexLocker.hpp     |   1 -
       .../compiler/c1/TestConcurrentPatching.java   | 145 ++++++++++++++++++
       10 files changed, 160 insertions(+), 22 deletions(-)
       create mode 100644 test/hotspot/jtreg/compiler/c1/TestConcurrentPatching.java
      
      diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp
      index 770ed2f6c3868..1f6d729238974 100644
      --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp
      +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp
      @@ -78,7 +78,7 @@ address NativeCall::destination() const {
       //
       // Used in the runtime linkage of calls; see class CompiledIC.
       void NativeCall::set_destination_mt_safe(address dest) {
      -  assert((Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) ||
      +  assert((CodeCache_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) ||
                CompiledICLocker::is_safe(addr_at(0)),
                "concurrent code patching");
       
      diff --git a/src/hotspot/cpu/ppc/nativeInst_ppc.cpp b/src/hotspot/cpu/ppc/nativeInst_ppc.cpp
      index 9520f6a94f2a4..f61328fc7360c 100644
      --- a/src/hotspot/cpu/ppc/nativeInst_ppc.cpp
      +++ b/src/hotspot/cpu/ppc/nativeInst_ppc.cpp
      @@ -92,10 +92,10 @@ address NativeCall::destination() const {
       // 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.
      +// during code generation, where no 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()) ||
      +         (CodeCache_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) ||
                CompiledICLocker::is_safe(addr_at(0)),
                "concurrent code patching");
       
      diff --git a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp
      index 6c9e0986869b6..2a5a8c85af0e7 100644
      --- a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp
      +++ b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp
      @@ -215,10 +215,10 @@ void NativeShortCall::print() {
       // 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.
      +// during code generation, where no lock is needed.
       bool NativeShortCall::set_destination_mt_safe(address dest, bool assert_lock) {
         assert(!assert_lock ||
      -         (Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) ||
      +         (CodeCache_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) ||
                CompiledICLocker::is_safe(instruction_address()),
                "concurrent code patching");
       
      @@ -386,7 +386,7 @@ void NativeFarCall::print() {
       bool NativeFarCall::set_destination_mt_safe(address dest, bool assert_lock) {
         assert(NativeFarCall::is_at(addr_at(0)), "unexpected code at call site");
         assert(!assert_lock ||
      -         (Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) ||
      +         (CodeCache_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) ||
                CompiledICLocker::is_safe(addr_at(0)),
                "concurrent code patching");
       
      diff --git a/src/hotspot/cpu/s390/nativeInst_s390.cpp b/src/hotspot/cpu/s390/nativeInst_s390.cpp
      index 9f083fa890454..4db73395d3a70 100644
      --- a/src/hotspot/cpu/s390/nativeInst_s390.cpp
      +++ b/src/hotspot/cpu/s390/nativeInst_s390.cpp
      @@ -658,8 +658,8 @@ void NativeGeneralJump::insert_unconditional(address code_pos, address entry) {
       
       void NativeGeneralJump::replace_mt_safe(address instr_addr, address code_buffer) {
         assert(((intptr_t)instr_addr & (BytesPerWord-1)) == 0, "requirement for mt safe patching");
      -  // Bytes_after_jump cannot change, because we own the Patching_lock.
      -  assert(Patching_lock->owned_by_self(), "must hold lock to patch instruction");
      +  // Bytes_after_jump cannot change, because we own the CodeCache_lock.
      +  assert(CodeCache_lock->owned_by_self(), "must hold lock to patch instruction");
         intptr_t bytes_after_jump = (*(intptr_t*)instr_addr)  & 0x000000000000ffffL; // 2 bytes after jump.
         intptr_t load_const_bytes = (*(intptr_t*)code_buffer) & 0xffffffffffff0000L;
         *(intptr_t*)instr_addr = load_const_bytes | bytes_after_jump;
      diff --git a/src/hotspot/cpu/x86/nativeInst_x86.cpp b/src/hotspot/cpu/x86/nativeInst_x86.cpp
      index 395c3219809de..d5021c29ed6b0 100644
      --- a/src/hotspot/cpu/x86/nativeInst_x86.cpp
      +++ b/src/hotspot/cpu/x86/nativeInst_x86.cpp
      @@ -81,7 +81,7 @@ void NativeCall::insert(address code_pos, address entry) {
       // (spinlock). Then patches the last byte, and then atomically replaces
       // the jmp's with the first 4 byte of the new instruction.
       void NativeCall::replace_mt_safe(address instr_addr, address code_buffer) {
      -  assert(Patching_lock->is_locked() ||
      +  assert(CodeCache_lock->is_locked() ||
                SafepointSynchronize::is_at_safepoint(), "concurrent code patching");
         assert (instr_addr != nullptr, "illegal address for code patching");
       
      @@ -144,7 +144,7 @@ void NativeCall::set_destination_mt_safe(address dest) {
         debug_only(verify());
         // Make sure patching code is locked.  No two threads can patch at the same
         // time but one may be executing this code.
      -  assert(Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint() ||
      +  assert(CodeCache_lock->is_locked() || SafepointSynchronize::is_at_safepoint() ||
                CompiledICLocker::is_safe(instruction_address()), "concurrent code patching");
         // Both C1 and C2 should now be generating code which aligns the patched address
         // to be within a single cache line.
      diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp
      index 915f00f77c523..3ebd1f42f366d 100644
      --- a/src/hotspot/share/c1/c1_Runtime1.cpp
      +++ b/src/hotspot/share/c1/c1_Runtime1.cpp
      @@ -887,7 +887,7 @@ static Klass* resolve_field_return_klass(const methodHandle& caller, int bci, TR
       //             movl reg, [reg1 + ]  (for field offsets)
       //             jmp continue
       //               
      -// patch_stub: jmp Runtim1::patch_code (through a runtime stub)
      +// patch_stub: jmp Runtime1::patch_code (through a runtime stub)
       //             jmp patch_site
       //
       // If the class is being initialized the patch body is rewritten and
      @@ -1103,7 +1103,7 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* current, C1StubId stub_id ))
         // Now copy code back
       
         {
      -    MutexLocker ml_patch (current, Patching_lock, Mutex::_no_safepoint_check_flag);
      +    MutexLocker ml_code (current, CodeCache_lock, Mutex::_no_safepoint_check_flag);
           //
           // Deoptimization may have happened while we waited for the lock.
           // In that case we don't bother to do any patching we just return
      @@ -1268,12 +1268,8 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* current, C1StubId stub_id ))
               }
             }
           }
      -  }
      -
      -  // If we are patching in a non-perm oop, make sure the nmethod
      -  // is on the right list.
      -  {
      -    MutexLocker ml_code (current, CodeCache_lock, Mutex::_no_safepoint_check_flag);
      +    // If we are patching in a non-perm oop, make sure the nmethod
      +    // is on the right list.
           nmethod* nm = CodeCache::find_nmethod(caller_frame.pc());
           guarantee(nm != nullptr, "only nmethods can contain non-perm oops");
       
      diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp
      index 0bab731ac565e..7fb72997749dc 100644
      --- a/src/hotspot/share/code/nmethod.cpp
      +++ b/src/hotspot/share/code/nmethod.cpp
      @@ -2048,7 +2048,7 @@ bool nmethod::make_not_entrant() {
         } // leave critical region under NMethodState_lock
       
       #if INCLUDE_JVMCI
      -  // Invalidate can't occur while holding the Patching lock
      +  // Invalidate can't occur while holding the NMethodState_lock
         JVMCINMethodData* nmethod_data = jvmci_nmethod_data();
         if (nmethod_data != nullptr) {
           nmethod_data->invalidate_nmethod_mirror(this);
      diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp
      index 769c7695192a8..a0a6e5626e45b 100644
      --- a/src/hotspot/share/runtime/mutexLocker.cpp
      +++ b/src/hotspot/share/runtime/mutexLocker.cpp
      @@ -36,7 +36,6 @@
       
       // Mutexes used in the VM (see comment in mutexLocker.hpp):
       
      -Mutex*   Patching_lock                = nullptr;
       Mutex*   NMethodState_lock            = nullptr;
       Monitor* SystemDictionary_lock        = nullptr;
       Mutex*   InvokeMethodTypeTable_lock   = nullptr;
      @@ -233,7 +232,6 @@ void mutex_init() {
         MUTEX_DEFN(Metaspace_lock                  , PaddedMutex  , nosafepoint-3);
         MUTEX_DEFN(MetaspaceCritical_lock          , PaddedMonitor, nosafepoint-1);
       
      -  MUTEX_DEFN(Patching_lock                   , PaddedMutex  , nosafepoint);      // used for safepointing and code patching.
         MUTEX_DEFN(MonitorDeflation_lock           , PaddedMonitor, nosafepoint);      // used for monitor deflation thread operations
         MUTEX_DEFN(Service_lock                    , PaddedMonitor, service);          // used for service thread operations
         MUTEX_DEFN(Notification_lock               , PaddedMonitor, service);          // used for notification thread operations
      diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp
      index 98cb27d0b812d..932ca5fce8242 100644
      --- a/src/hotspot/share/runtime/mutexLocker.hpp
      +++ b/src/hotspot/share/runtime/mutexLocker.hpp
      @@ -31,7 +31,6 @@
       
       // Mutexes used in the VM.
       
      -extern Mutex*   Patching_lock;                   // a lock used to guard code patching of compiled code
       extern Mutex*   NMethodState_lock;               // a lock used to guard a compiled method state
       extern Monitor* SystemDictionary_lock;           // a lock on the system dictionary
       extern Mutex*   InvokeMethodTypeTable_lock;
      diff --git a/test/hotspot/jtreg/compiler/c1/TestConcurrentPatching.java b/test/hotspot/jtreg/compiler/c1/TestConcurrentPatching.java
      new file mode 100644
      index 0000000000000..6a7179d0ce45f
      --- /dev/null
      +++ b/test/hotspot/jtreg/compiler/c1/TestConcurrentPatching.java
      @@ -0,0 +1,145 @@
      +/*
      + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
      + * 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.lang.reflect.Method;
      +import java.net.URL;
      +import java.net.URLClassLoader;
      +import java.util.ArrayList;
      +
      +/**
      +  * @test
      +  * @bug 8340313
      +  * @summary Test that concurrent patching of oop immediates is thread-safe in C1.
      +  * @run main/othervm/timeout=480 -Xcomp -XX:CompileCommand=compileonly,TestConcurrentPatching::* -XX:TieredStopAtLevel=1 TestConcurrentPatching
      +  */
      +
      +class MyClass { }
      +
      +class Holder {
      +    public static final MyClass OBJ1 = null;
      +    public static final MyClass OBJ2 = null;
      +    public static final MyClass OBJ3 = null;
      +    public static final MyClass OBJ4 = null;
      +    public static final MyClass OBJ5 = null;
      +    public static final MyClass OBJ6 = null;
      +    public static final MyClass OBJ7 = null;
      +    public static final MyClass OBJ8 = null;
      +    public static final MyClass OBJ9 = null;
      +    public static final MyClass OBJ10 = null;
      +    public static final MyClass OBJ11 = null;
      +    public static final MyClass OBJ12 = null;
      +    public static final MyClass OBJ13 = null;
      +    public static final MyClass OBJ14 = null;
      +    public static final MyClass OBJ15 = null;
      +    public static final MyClass OBJ16 = null;
      +    public static final MyClass OBJ17 = null;
      +    public static final MyClass OBJ18 = null;
      +    public static final MyClass OBJ19 = null;
      +    public static final MyClass OBJ20 = null;
      +}
      +
      +public class TestConcurrentPatching {
      +    // Increase to 100_000 for a good chance of reproducing the issue with a single run
      +    static final int ITERATIONS = 1000;
      +
      +    static Object field;
      +
      +    // 'Holder' class is unloaded on first execution and therefore field
      +    // accesses require patching when the method is C1 compiled (with -Xcomp).
      +    public static void test() {
      +        field = Holder.OBJ1;
      +        field = Holder.OBJ2;
      +        field = Holder.OBJ3;
      +        field = Holder.OBJ4;
      +        field = Holder.OBJ5;
      +        field = Holder.OBJ6;
      +        field = Holder.OBJ7;
      +        field = Holder.OBJ8;
      +        field = Holder.OBJ9;
      +        field = Holder.OBJ10;
      +        field = Holder.OBJ11;
      +        field = Holder.OBJ12;
      +        field = Holder.OBJ13;
      +        field = Holder.OBJ14;
      +        field = Holder.OBJ15;
      +        field = Holder.OBJ16;
      +        field = Holder.OBJ17;
      +        field = Holder.OBJ18;
      +        field = Holder.OBJ19;
      +        field = Holder.OBJ20;
      +    }
      +
      +    // Appendix of invokedynamic call sites is unloaded on first execution and
      +    // therefore requires patching when the method is C1 compiled (with -Xcomp).
      +    public static void testIndy() throws Throwable {
      +          field = (Runnable) () -> { };
      +          field = (Runnable) () -> { };
      +          field = (Runnable) () -> { };
      +          field = (Runnable) () -> { };
      +          field = (Runnable) () -> { };
      +          field = (Runnable) () -> { };
      +          field = (Runnable) () -> { };
      +          field = (Runnable) () -> { };
      +          field = (Runnable) () -> { };
      +          field = (Runnable) () -> { };
      +    }
      +
      +    // Run 'test' by multiple threads to trigger concurrent patching of field accesses
      +    static void runWithThreads(Method method) {
      +        ArrayList threads = new ArrayList<>();
      +        for (int threadIdx = 0; threadIdx < 10; threadIdx++) {
      +            threads.add(new Thread(() -> {
      +                try {
      +                    method.invoke(null);
      +                } catch (Exception e) {
      +                    throw new IllegalStateException(e);
      +                }
      +            }));
      +        }
      +        threads.forEach(Thread::start);
      +        threads.forEach(t -> {
      +            try {
      +                t.join();
      +            } catch (Throwable e) {
      +                throw new IllegalStateException(e);
      +            }
      +        });
      +    }
      +
      +    public static void main(String[] args) throws Exception {
      +        Class thisClass = TestConcurrentPatching.class;
      +        ClassLoader defaultLoader = thisClass.getClassLoader();
      +        URL classesDir = thisClass.getProtectionDomain().getCodeSource().getLocation();
      +
      +        // Load the test class multiple times with a separate class loader to make sure
      +        // that the 'Holder' class is unloaded for each compilation of method 'test'
      +        // and that the appendix of the invokedynamic call site is unloaded for each
      +        // compilation of method 'testIndy'.
      +        for (int i = 0; i < ITERATIONS; ++i) {
      +            URLClassLoader myLoader = URLClassLoader.newInstance(new URL[] {classesDir}, defaultLoader.getParent());
      +            Class testClass = Class.forName(thisClass.getCanonicalName(), true, myLoader);
      +            runWithThreads(testClass.getDeclaredMethod("test"));
      +            runWithThreads(testClass.getDeclaredMethod("testIndy"));
      +        }
      +    }
      +}
      
      From 22a1feea7484c9d640eeac22943d237a0e549942 Mon Sep 17 00:00:00 2001
      From: Christian Hagedorn 
      Date: Thu, 17 Oct 2024 05:08:59 +0000
      Subject: [PATCH 100/118] 8341328: Refactor initial Assertion Predicate
       creation into separate classes
      
      Reviewed-by: thartmann, kvn
      ---
       src/hotspot/share/opto/ifnode.cpp        |   3 +
       src/hotspot/share/opto/loopPredicate.cpp |  81 ++----
       src/hotspot/share/opto/loopTransform.cpp | 122 +++------
       src/hotspot/share/opto/loopnode.hpp      |  15 +-
       src/hotspot/share/opto/predicates.cpp    | 328 +++++++++++++++++++----
       src/hotspot/share/opto/predicates.hpp    |  91 +++++--
       6 files changed, 412 insertions(+), 228 deletions(-)
      
      diff --git a/src/hotspot/share/opto/ifnode.cpp b/src/hotspot/share/opto/ifnode.cpp
      index 4313b2cf907a9..093cafd1574db 100644
      --- a/src/hotspot/share/opto/ifnode.cpp
      +++ b/src/hotspot/share/opto/ifnode.cpp
      @@ -1849,6 +1849,9 @@ void IfNode::dump_spec(outputStream* st) const {
           case AssertionPredicateType::LastValue:
             st->print("#Last Value Assertion Predicate  ");
             break;
      +    case AssertionPredicateType::FinalIv:
      +      st->print("#Final IV Assertion Predicate  ");
      +      break;
           case AssertionPredicateType::None:
             // No Assertion Predicate
             break;
      diff --git a/src/hotspot/share/opto/loopPredicate.cpp b/src/hotspot/share/opto/loopPredicate.cpp
      index 5e585a406f20c..92f4e3582e96a 100644
      --- a/src/hotspot/share/opto/loopPredicate.cpp
      +++ b/src/hotspot/share/opto/loopPredicate.cpp
      @@ -1153,7 +1153,8 @@ void PhaseIdealLoop::loop_predication_follow_branches(Node *n, IdealLoopTree *lo
       
       bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNode* if_success_proj,
                                                         ParsePredicateSuccessProj* parse_predicate_proj, CountedLoopNode* cl,
      -                                                  ConNode* zero, Invariance& invar, Deoptimization::DeoptReason reason) {
      +                                                  ConNode* zero, Invariance& invar,
      +                                                  Deoptimization::DeoptReason deopt_reason) {
         // Following are changed to nonnull when a predicate can be hoisted
         IfNode*   iff  = if_success_proj->in(0)->as_If();
         Node*     test = iff->in(1);
      @@ -1165,7 +1166,7 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod
         if (invar.is_invariant(bol)) {
           C->print_method(PHASE_BEFORE_LOOP_PREDICATION_IC, 4, iff);
           // Invariant test
      -    IfProjNode* hoisted_check_predicate_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason,
      +    IfProjNode* hoisted_check_predicate_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, deopt_reason,
                                                                                  iff->Opcode());
           Node* ctrl = hoisted_check_predicate_proj->in(0)->as_If()->in(0);
           BoolNode* hoisted_check_predicate_bool = invar.clone(bol, ctrl)->as_Bool();
      @@ -1206,9 +1207,9 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod
           const Node*    cmp    = bol->in(1)->as_Cmp();
           Node*          idx    = cmp->in(1);
           assert(!invar.is_invariant(idx), "index is variant");
      -    Node* rng = cmp->in(2);
      -    assert(rng->Opcode() == Op_LoadRange || iff->is_RangeCheck() || _igvn.type(rng)->is_int()->_lo >= 0, "must be");
      -    assert(invar.is_invariant(rng), "range must be invariant");
      +    Node* range = cmp->in(2);
      +    assert(range->Opcode() == Op_LoadRange || iff->is_RangeCheck() || _igvn.type(range)->is_int()->_lo >= 0, "must be");
      +    assert(invar.is_invariant(range), "range must be invariant");
           int scale    = 1;
           Node* offset = zero;
           bool ok = is_scaled_iv_plus_offset(idx, cl->phi(), &scale, &offset);
      @@ -1237,7 +1238,7 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod
           // late schedule will place invariant things in the loop.
           ParsePredicateNode* parse_predicate = parse_predicate_proj->in(0)->as_ParsePredicate();
           Node* ctrl = parse_predicate->in(0);
      -    rng = invar.clone(rng, ctrl);
      +    range = invar.clone(range, ctrl);
           if (offset && offset != zero) {
             assert(invar.is_invariant(offset), "offset must be loop invariant");
             offset = invar.clone(offset, ctrl);
      @@ -1245,10 +1246,10 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod
           // If predicate expressions may overflow in the integer range, longs are used.
           bool overflow = false;
           // Test the lower bound
      -    BoolNode* lower_bound_bol = rc_predicate(ctrl, scale, offset, init, limit, stride, rng, false, overflow);
      +    BoolNode* lower_bound_bol = rc_predicate(ctrl, scale, offset, init, limit, stride, range, false, overflow);
       
           const int if_opcode = iff->Opcode();
      -    IfProjNode* lower_bound_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, overflow ? Op_If : if_opcode);
      +    IfProjNode* lower_bound_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, deopt_reason, overflow ? Op_If : if_opcode);
           IfNode* lower_bound_iff = lower_bound_proj->in(0)->as_If();
           _igvn.hash_delete(lower_bound_iff);
           lower_bound_iff->set_req(1, lower_bound_bol);
      @@ -1257,9 +1258,9 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod
           }
       
           // Test the upper bound
      -    BoolNode* upper_bound_bol = rc_predicate(lower_bound_proj, scale, offset, init, limit, stride, rng, true, overflow);
      +    BoolNode* upper_bound_bol = rc_predicate(lower_bound_proj, scale, offset, init, limit, stride, range, true, overflow);
       
      -    IfProjNode* upper_bound_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, overflow ? Op_If : if_opcode);
      +    IfProjNode* upper_bound_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, deopt_reason, overflow ? Op_If : if_opcode);
           assert(upper_bound_proj->in(0)->as_If()->in(0) == lower_bound_proj, "should dominate");
           IfNode* upper_bound_iff = upper_bound_proj->in(0)->as_If();
           _igvn.hash_delete(upper_bound_iff);
      @@ -1272,8 +1273,8 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod
           // upper bound test. We always need to create skeleton predicates in order to properly remove dead loops when later
           // splitting the predicated loop into (unreachable) sub-loops (i.e. done by unrolling, peeling, pre/main/post etc.).
           IfTrueNode* template_assertion_predicate_proj =
      -        add_template_assertion_predicate(iff, loop, hoisted_check_proj, parse_predicate_proj, upper_bound_proj, scale,
      -                                         offset, init, limit, stride, rng, overflow, reason);
      +        create_template_assertion_predicate(if_opcode, cl, parse_predicate_proj, upper_bound_proj, scale, offset, range,
      +                                            deopt_reason);
       
           // Eliminate the old range check in the loop body.
           // When a range check is eliminated, data dependent nodes (Load and range check CastII nodes) are now dependent on 2
      @@ -1309,53 +1310,15 @@ void PhaseIdealLoop::eliminate_hoisted_range_check(IfTrueNode* hoisted_check_pro
       // Each newly created Hoisted Check Predicate is accompanied by two Template Assertion Predicates. Later, we initialize
       // them by making a copy of them when splitting a loop into sub loops. The Assertion Predicates ensure that dead sub
       // loops are removed properly.
      -IfTrueNode* PhaseIdealLoop::add_template_assertion_predicate(IfNode* iff, IdealLoopTree* loop, IfProjNode* if_proj,
      -                                                             ParsePredicateSuccessProj* parse_predicate_proj,
      -                                                             IfProjNode* upper_bound_proj, const int scale, Node* offset,
      -                                                             Node* init, Node* limit, const jint stride,
      -                                                             Node* rng, bool& overflow, Deoptimization::DeoptReason reason) {
      -  // First predicate for the initial value on first loop iteration
      -  Node* opaque_init = new OpaqueLoopInitNode(C, init);
      -  register_new_node(opaque_init, upper_bound_proj);
      -  bool negate = (if_proj->_con != parse_predicate_proj->_con);
      -  BoolNode* bol = rc_predicate(upper_bound_proj, scale, offset, opaque_init, limit, stride, rng,
      -                               (stride > 0) != (scale > 0), overflow);
      -  Node* opaque_bol = new Opaque4Node(C, bol, _igvn.intcon(1)); // This will go away once loop opts are over
      -  C->add_template_assertion_predicate_opaq(opaque_bol);
      -  register_new_node(opaque_bol, upper_bound_proj);
      -  IfTrueNode* new_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, overflow ? Op_If : iff->Opcode(),
      -                                                     false NOT_PRODUCT(COMMA AssertionPredicateType::InitValue));
      -  _igvn.replace_input_of(new_proj->in(0), 1, opaque_bol);
      -  assert(opaque_init->outcnt() > 0, "should be used");
      -
      -  // Second predicate for init + (current stride - initial stride)
      -  // This is identical to the previous predicate initially but as
      -  // unrolling proceeds current stride is updated.
      -  Node* init_stride = loop->_head->as_CountedLoop()->stride();
      -  Node* opaque_stride = new OpaqueLoopStrideNode(C, init_stride);
      -  register_new_node(opaque_stride, new_proj);
      -  Node* max_value = new SubINode(opaque_stride, init_stride);
      -  register_new_node(max_value, new_proj);
      -  max_value = new AddINode(opaque_init, max_value);
      -  register_new_node(max_value, new_proj);
      -  // init + (current stride - initial stride) is within the loop so narrow its type by leveraging the type of the iv Phi
      -  const Type* type_iv = loop->_head->as_CountedLoop()->phi()->bottom_type();
      -  assert(!type_iv->is_int()->is_con(), "constant indicates one loop iteration for which we bailed out earlier");
      -  max_value = new CastIINode(new_proj, max_value, type_iv);
      -  register_new_node(max_value, new_proj);
      -
      -  bol = rc_predicate(new_proj, scale, offset, max_value, limit, stride, rng, (stride > 0) != (scale > 0),
      -                     overflow);
      -  opaque_bol = new Opaque4Node(C, bol, _igvn.intcon(1));
      -  C->add_template_assertion_predicate_opaq(opaque_bol);
      -  register_new_node(opaque_bol, new_proj);
      -  new_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, overflow ? Op_If : iff->Opcode(),
      -                                         false NOT_PRODUCT(COMMA AssertionPredicateType::LastValue));
      -  _igvn.replace_input_of(new_proj->in(0), 1, opaque_bol);
      -  assert(max_value->outcnt() > 0, "should be used");
      -  assert(assertion_predicate_has_loop_opaque_node(new_proj->in(0)->as_If()), "unexpected");
      -
      -  return new_proj;
      +IfTrueNode* PhaseIdealLoop::create_template_assertion_predicate(const int if_opcode, CountedLoopNode* loop_head,
      +                                                                ParsePredicateSuccessProj* parse_predicate_proj,
      +                                                                IfProjNode* new_control, const int scale, Node* offset,
      +                                                                Node* range, Deoptimization::DeoptReason deopt_reason) {
      +
      +  TemplateAssertionPredicateCreator template_assertion_predicate_creator(loop_head, scale, offset, range, this);
      +  return template_assertion_predicate_creator.create_with_uncommon_trap(new_control, parse_predicate_proj, deopt_reason,
      +                                                                        if_opcode);
      +
       }
       
       // Insert Hoisted Check Predicates for null checks and range checks and additional Template Assertion Predicates for
      diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp
      index c3cc8532e7d30..2286b30453434 100644
      --- a/src/hotspot/share/opto/loopTransform.cpp
      +++ b/src/hotspot/share/opto/loopTransform.cpp
      @@ -1461,12 +1461,13 @@ void PhaseIdealLoop::count_opaque_loop_nodes(Node* n, uint& init, uint& stride)
       
       // Create an Initialized Assertion Predicate from the template_assertion_predicate
       IfTrueNode* PhaseIdealLoop::create_initialized_assertion_predicate(IfNode* template_assertion_predicate, Node* new_init,
      -                                                                   Node* new_stride, Node* control) {
      +                                                                   Node* new_stride, Node* new_control) {
         assert(assertion_predicate_has_loop_opaque_node(template_assertion_predicate),
                "must find OpaqueLoop* nodes for Template Assertion Predicate");
      -  InitializedAssertionPredicateCreator initialized_assertion_predicate(template_assertion_predicate, new_init,
      -                                                                       new_stride, this);
      -  IfTrueNode* success_proj = initialized_assertion_predicate.create(control);
      +  InitializedAssertionPredicateCreator initialized_assertion_predicate(this);
      +  IfTrueNode* success_proj = initialized_assertion_predicate.create_from_template(template_assertion_predicate,
      +                                                                                  new_control, new_init, new_stride);
      +
         assert(!assertion_predicate_has_loop_opaque_node(success_proj->in(0)->as_If()),
                "Initialized Assertion Predicates do not have OpaqueLoop* nodes in the bool expression anymore");
         return success_proj;
      @@ -1477,30 +1478,18 @@ IfTrueNode* PhaseIdealLoop::create_initialized_assertion_predicate(IfNode* templ
       // We keep the Opaque4 node since it's still a template. Since the templates are eventually removed after loop opts,
       // these are never executed. We therefore insert a Halt node instead of an uncommon trap.
       Node* PhaseIdealLoop::clone_template_assertion_predicate(IfNode* iff, Node* new_init, Node* predicate, Node* uncommon_proj,
      -                                                         Node* control, IdealLoopTree* outer_loop, Node* input_proj) {
      +                                                         Node* control, IdealLoopTree* outer_loop, Node* new_control) {
         assert(assertion_predicate_has_loop_opaque_node(iff), "must find OpaqueLoop* nodes for Template Assertion Predicate");
         TemplateAssertionExpression template_assertion_expression(iff->in(1)->as_Opaque4());
         assert(new_init->is_OpaqueLoopInit(), "only for creating new Template Assertion Predicates");
         Opaque4Node* new_opaque_node = template_assertion_expression.clone_and_replace_init(new_init, control, this);
      -  Node* proj = predicate->clone();
      -  Node* other_proj = uncommon_proj->clone();
      -  Node* new_iff = iff->clone();
      -  new_iff->set_req(1, new_opaque_node);
      -  proj->set_req(0, new_iff);
      -  other_proj->set_req(0, new_iff);
      -  Node* frame = new ParmNode(C->start(), TypeFunc::FramePtr);
      -  register_new_node(frame, C->start());
      -  Node* halt = new HaltNode(other_proj, frame, "Template Assertion Predicates are always removed before code generation");
      -  _igvn.add_input_to(C->root(), halt);
      -  new_iff->set_req(0, input_proj);
      -
      -  register_control(new_iff, outer_loop == _ltree_root ? _ltree_root : outer_loop->_parent, input_proj);
      -  register_control(proj, outer_loop == _ltree_root ? _ltree_root : outer_loop->_parent, new_iff);
      -  register_control(other_proj, _ltree_root, new_iff);
      -  register_control(halt, _ltree_root, other_proj);
      -  assert(assertion_predicate_has_loop_opaque_node(proj->in(0)->as_If()),
      +  AssertionPredicateIfCreator assertion_predicate_if_creator(this);
      +  IfTrueNode* success_proj =
      +      assertion_predicate_if_creator.create_for_template(new_control, iff->Opcode(), new_opaque_node
      +                                                         NOT_PRODUCT(COMMA iff->assertion_predicate_type()));
      +  assert(assertion_predicate_has_loop_opaque_node(success_proj->in(0)->as_If()),
                "Template Assertion Predicates must have OpaqueLoop* nodes in the bool expression");
      -  return proj;
      +  return success_proj;
       }
       
       void PhaseIdealLoop::copy_assertion_predicates_to_main_loop(CountedLoopNode* pre_head, Node* init, Node* stride,
      @@ -2732,40 +2721,6 @@ bool PhaseIdealLoop::is_scaled_iv_plus_extra_offset(Node* exp1, Node* offset3, N
         return false;
       }
       
      -// Same as PhaseIdealLoop::duplicate_predicates() but for range checks
      -// eliminated by iteration splitting.
      -Node* PhaseIdealLoop::add_range_check_elimination_assertion_predicate(
      -    IdealLoopTree* loop, Node* ctrl, const int scale_con, Node* offset, Node* limit, jint stride_con, Node* value,
      -    const bool is_template NOT_PRODUCT(COMMA AssertionPredicateType assertion_predicate_type)) {
      -  bool overflow = false;
      -  BoolNode* bol = rc_predicate(ctrl, scale_con, offset, value, nullptr, stride_con,
      -                               limit, (stride_con > 0) != (scale_con > 0), overflow);
      -  Node* opaque_assertion_predicate;
      -  if (is_template) {
      -    opaque_assertion_predicate = new Opaque4Node(C, bol, _igvn.intcon(1));
      -  } else {
      -    opaque_assertion_predicate = new OpaqueInitializedAssertionPredicateNode(bol, C);
      -  }
      -  register_new_node(opaque_assertion_predicate, ctrl);
      -  IfNode* new_iff = nullptr;
      -  if (overflow) {
      -    new_iff = new IfNode(ctrl, opaque_assertion_predicate, PROB_MAX, COUNT_UNKNOWN);
      -  } else {
      -    new_iff = new RangeCheckNode(ctrl, opaque_assertion_predicate, PROB_MAX, COUNT_UNKNOWN);
      -  }
      -  register_control(new_iff, loop->_parent, ctrl);
      -  Node* iffalse = new IfFalseNode(new_iff);
      -  register_control(iffalse, _ltree_root, new_iff);
      -  ProjNode* iftrue = new IfTrueNode(new_iff);
      -  register_control(iftrue, loop->_parent, new_iff);
      -  Node *frame = new ParmNode(C->start(), TypeFunc::FramePtr);
      -  register_new_node(frame, C->start());
      -  Node* halt = new HaltNode(iffalse, frame, "range check predicate failed which is impossible");
      -  register_control(halt, _ltree_root, iffalse);
      -  _igvn.add_input_to(C->root(), halt);
      -  return iftrue;
      -}
      -
       //------------------------------do_range_check---------------------------------
       // Eliminate range-checks and other trip-counter vs loop-invariant tests.
       void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) {
      @@ -2974,45 +2929,39 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) {
                 Node* opaque_init = new OpaqueLoopInitNode(C, init);
                 register_new_node(opaque_init, loop_entry);
       
      +          InitializedAssertionPredicateCreator initialized_assertion_predicate_creator(this);
                 if (abs_stride_is_one) {
                   // If the main loop becomes empty and the array access for this range check is sunk out of the loop, the index
                   // for the array access will be set to the index value of the final iteration which could be out of loop.
      -            // Add an Assertion Predicate for that corner case. The final iv is computed from LoopLimit which is the
      -            // LoopNode::limit() only if abs(stride) == 1 otherwise the computation depends on LoopNode::init_trip() as
      -            // well. When LoopLimit only depends on LoopNode::limit(), there are cases where the zero trip guard for the
      -            // main loop doesn't constant fold after range check elimination but, the array access for the final
      +            // Add an Initialized Assertion Predicate for that corner case. The final iv is computed from LoopLimit which
      +            // is the LoopNode::limit() only if abs(stride) == 1 otherwise the computation depends on LoopNode::init_trip()
      +            // as well. When LoopLimit only depends on LoopNode::limit(), there are cases where the zero trip guard for
      +            // the main loop doesn't constant fold after range check elimination but, the array access for the final
                   // iteration of the main loop is out of bound and the index for that access is out of range for the range
                   // check CastII.
      -            loop_entry = add_range_check_elimination_assertion_predicate(loop, loop_entry, scale_con, int_offset,
      -                                                                         int_limit, stride_con, final_iv_placeholder, false);
      +            // Note that we do not need to emit a Template Assertion Predicate to update this predicate. When further
      +            // splitting this loop, the final IV will still be the same. When unrolling the loop, we will remove a
      +            // previously added Initialized Assertion Predicate here. But then abs(stride) is greater than 1, and we
      +            // cannot remove an empty loop with a constant limit when init is not a constant as well. We will use
      +            // a LoopLimitCheck node that can only be folded if the zero grip guard is also foldable.
      +            loop_entry = initialized_assertion_predicate_creator.create(final_iv_placeholder, loop_entry, stride_con,
      +                                                                        scale_con, int_offset, int_limit NOT_PRODUCT(
      +                                                                        COMMA AssertionPredicateType::FinalIv));
                   assert(!assertion_predicate_has_loop_opaque_node(loop_entry->in(0)->as_If()), "unexpected");
                 }
       
      -          // Initialized Assertion Predicate for the value of the initial main-loop.
      -          loop_entry = add_range_check_elimination_assertion_predicate(loop, loop_entry, scale_con, int_offset,
      -                                                                       int_limit, stride_con, init, false);
      -          assert(!assertion_predicate_has_loop_opaque_node(loop_entry->in(0)->as_If()), "unexpected");
      -
                 // Add two Template Assertion Predicates to create new Initialized Assertion Predicates from when either
                 // unrolling or splitting this main-loop further.
      -          loop_entry = add_range_check_elimination_assertion_predicate(
      -              loop, loop_entry, scale_con, int_offset, int_limit, stride_con, opaque_init, true
      -              NOT_PRODUCT(COMMA AssertionPredicateType::InitValue));
      +          TemplateAssertionPredicateCreator template_assertion_predicate_creator(cl, scale_con , int_offset, int_limit,
      +                                                                                 this);
      +          loop_entry = template_assertion_predicate_creator.create_with_halt(loop_entry);
                 assert(assertion_predicate_has_loop_opaque_node(loop_entry->in(0)->as_If()), "unexpected");
       
      -          Node* opaque_stride = new OpaqueLoopStrideNode(C, cl->stride());
      -          register_new_node(opaque_stride, loop_entry);
      -          Node* max_value = new SubINode(opaque_stride, cl->stride());
      -          register_new_node(max_value, loop_entry);
      -          max_value = new AddINode(opaque_init, max_value);
      -          register_new_node(max_value, loop_entry);
      -          // init + (current stride - initial stride) is within the loop so narrow its type by leveraging the type of the iv Phi
      -          max_value = new CastIINode(loop_entry, max_value, loop->_head->as_CountedLoop()->phi()->bottom_type());
      -          register_new_node(max_value, loop_entry);
      -          loop_entry = add_range_check_elimination_assertion_predicate(
      -              loop, loop_entry, scale_con, int_offset, int_limit, stride_con, max_value, true
      -              NOT_PRODUCT(COMMA AssertionPredicateType::LastValue));
      -          assert(assertion_predicate_has_loop_opaque_node(loop_entry->in(0)->as_If()), "unexpected");
      +          // Initialized Assertion Predicate for the value of the initial main-loop.
      +          loop_entry = initialized_assertion_predicate_creator.create(init, loop_entry, stride_con, scale_con,
      +                                                                      int_offset, int_limit NOT_PRODUCT(COMMA
      +                                                                      AssertionPredicateType::InitValue));
      +          assert(!assertion_predicate_has_loop_opaque_node(loop_entry->in(0)->as_If()), "unexpected");
       
               } else {
                 if (PrintOpto) {
      @@ -3072,9 +3021,6 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) {
                 --imax;
               }
             }
      -
      -      C->print_method(PHASE_AFTER_RANGE_CHECK_ELIMINATION, 4, cl);
      -
           } // End of is IF
         }
         if (loop_entry != cl->skip_strip_mined()->in(LoopNode::EntryControl)) {
      @@ -3138,6 +3084,8 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) {
         set_ctrl(opqzm, new_limit_ctrl);
         set_ctrl(iffm->in(1)->in(1), new_limit_ctrl);
         set_ctrl(iffm->in(1), new_limit_ctrl);
      +
      +  C->print_method(PHASE_AFTER_RANGE_CHECK_ELIMINATION, 4, cl);
       }
       
       // Adjust control for node and its inputs (and inputs of its inputs) to be above the pre end
      diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp
      index 3aa67bcb5cb8b..ef27eb652f744 100644
      --- a/src/hotspot/share/opto/loopnode.hpp
      +++ b/src/hotspot/share/opto/loopnode.hpp
      @@ -951,7 +951,7 @@ class PhaseIdealLoop : public PhaseTransform {
                                                     uint idx_after_post_before_pre, Node* zero_trip_guard_proj_main,
                                                     Node* zero_trip_guard_proj_post, const Node_List& old_new);
         Node* clone_template_assertion_predicate(IfNode* iff, Node* new_init, Node* predicate, Node* uncommon_proj, Node* control,
      -                                           IdealLoopTree* outer_loop, Node* input_proj);
      +                                           IdealLoopTree* outer_loop, Node* new_control);
         IfTrueNode* create_initialized_assertion_predicate(IfNode* template_assertion_predicate, Node* new_init,
                                                            Node* new_stride, Node* control);
         static void count_opaque_loop_nodes(Node* n, uint& init, uint& stride);
      @@ -1384,20 +1384,17 @@ class PhaseIdealLoop : public PhaseTransform {
        private:
         bool loop_predication_impl_helper(IdealLoopTree* loop, IfProjNode* if_success_proj,
                                           ParsePredicateSuccessProj* parse_predicate_proj, CountedLoopNode* cl, ConNode* zero,
      -                                    Invariance& invar, Deoptimization::DeoptReason reason);
      +                                    Invariance& invar, Deoptimization::DeoptReason deopt_reason);
         bool can_create_loop_predicates(const PredicateBlock* profiled_loop_predicate_block) const;
         bool loop_predication_should_follow_branches(IdealLoopTree* loop, float& loop_trip_cnt);
         void loop_predication_follow_branches(Node *c, IdealLoopTree *loop, float loop_trip_cnt,
                                               PathFrequency& pf, Node_Stack& stack, VectorSet& seen,
                                               Node_List& if_proj_list);
      -  IfTrueNode* add_template_assertion_predicate(IfNode* iff, IdealLoopTree* loop, IfProjNode* if_proj,
      -                                               ParsePredicateSuccessProj* parse_predicate_proj,
      -                                               IfProjNode* upper_bound_proj, int scale, Node* offset, Node* init, Node* limit,
      -                                               jint stride, Node* rng, bool& overflow, Deoptimization::DeoptReason reason);
      +  IfTrueNode* create_template_assertion_predicate(int if_opcode, CountedLoopNode* loop_head,
      +                                                  ParsePredicateSuccessProj* parse_predicate_proj,
      +                                                  IfProjNode* new_control, int scale, Node* offset,
      +                                                  Node* range, Deoptimization::DeoptReason deopt_reason);
         void eliminate_hoisted_range_check(IfTrueNode* hoisted_check_proj, IfTrueNode* template_assertion_predicate_proj);
      -  Node* add_range_check_elimination_assertion_predicate(
      -      IdealLoopTree* loop, Node* predicate_proj, int scale_con, Node* offset, Node* limit, int stride_con, Node* value,
      -      bool is_template NOT_PRODUCT(COMMA AssertionPredicateType assertion_predicate_type = AssertionPredicateType::None));
       
         // Helper function to collect predicate for eliminating the useless ones
         void eliminate_useless_predicates();
      diff --git a/src/hotspot/share/opto/predicates.cpp b/src/hotspot/share/opto/predicates.cpp
      index 18eea3a10bcc6..0e4f264f827d7 100644
      --- a/src/hotspot/share/opto/predicates.cpp
      +++ b/src/hotspot/share/opto/predicates.cpp
      @@ -23,7 +23,9 @@
        */
       
       #include "precompiled.hpp"
      +#include "opto/addnode.hpp"
       #include "opto/callnode.hpp"
      +#include "opto/castnode.hpp"
       #include "opto/loopnode.hpp"
       #include "opto/node.hpp"
       #include "opto/predicates.hpp"
      @@ -247,11 +249,11 @@ Opaque4Node* TemplateAssertionExpression::clone_and_replace_init(Node* new_init,
       
       // Same as clone() but instead of cloning the OpaqueLoopInit and OpaqueLoopStride node, we replace them with the provided
       // 'new_init' and 'new_stride' nodes, respectively.
      -Opaque4Node* TemplateAssertionExpression::clone_and_replace_init_and_stride(Node* new_init, Node* new_stride,
      -                                                                            Node* new_ctrl,
      +Opaque4Node* TemplateAssertionExpression::clone_and_replace_init_and_stride(Node* new_control, Node* new_init,
      +                                                                            Node* new_stride,
                                                                                   PhaseIdealLoop* phase) {
         ReplaceInitAndStrideStrategy replace_init_and_stride_strategy(new_init, new_stride);
      -  return clone(replace_init_and_stride_strategy, new_ctrl, phase);
      +  return clone(replace_init_and_stride_strategy, new_control, phase);
       }
       
       // Class to collect data nodes from a source to target nodes by following the inputs of the source node recursively.
      @@ -370,86 +372,296 @@ bool TemplateAssertionExpressionNode::is_template_assertion_predicate(Node* node
         return node->is_If() && node->in(1)->is_Opaque4();
       }
       
      -InitializedAssertionPredicateCreator::InitializedAssertionPredicateCreator(IfNode* template_assertion_predicate, Node* new_init,
      -                                                                           Node* new_stride, PhaseIdealLoop* phase)
      -    : _template_assertion_predicate(template_assertion_predicate),
      -      _new_init(new_init),
      -      _new_stride(new_stride),
      -      _phase(phase) {}
      +// This class creates the Assertion Predicate expression to be used for a Template or Initialized Assertion Predicate.
      +class AssertionPredicateExpressionCreator : public StackObj {
      +  PhaseIdealLoop* const _phase;
      +  const jint _stride;
      +  const int _scale;
      +  Node* const _offset;
      +  Node* const _range;
      +  const bool _upper;
       
      -// Create an Initialized Assertion Predicate at the provided control from the _template_assertion_predicate.
      -// We clone the Template Assertion Expression and replace:
      -// - Opaque4 with OpaqueInitializedAssertionPredicate
      -// - OpaqueLoop*Nodes with _new_init and _new_stride, respectively.
      + public:
      +  AssertionPredicateExpressionCreator(const int stride, const int scale, Node* offset, Node* range,
      +                                      PhaseIdealLoop* phase)
      +      : _phase(phase),
      +        _stride(stride),
      +        _scale(scale),
      +        _offset(offset),
      +        _range(range),
      +        _upper((_stride > 0) != (_scale > 0)) {} // Make sure rc_predicate() chooses the "scale*init + offset" case.
      +
      +  // Create the expression for a Template Assertion Predicate with an Opaque4 node.
      +  Opaque4Node* create_for_template(Node* new_control, Node* operand, bool& does_overflow) const {
      +    BoolNode* bool_for_expression =  _phase->rc_predicate(new_control, _scale, _offset, operand, nullptr,
      +                                                          _stride, _range, _upper, does_overflow);
      +    return create_opaque4_node(new_control, bool_for_expression);
      +  }
      +
      + private:
      +  Opaque4Node* create_opaque4_node(Node* new_control, BoolNode* bool_for_expression) const {
      +    Compile* C = _phase->C;
      +    Opaque4Node* new_expression = new Opaque4Node(C, bool_for_expression, _phase->igvn().intcon(1));
      +    C->add_template_assertion_predicate_opaq(new_expression);
      +    _phase->register_new_node(new_expression, new_control);
      +    return new_expression;
      +  }
      +
      + public:
      +  // Create the expression for an Initialized Assertion Predicate with an OpaqueInitializedAssertionPredicate node.
      +  OpaqueInitializedAssertionPredicateNode* create_for_initialized(Node* new_control, Node* operand,
      +                                                                  bool& does_overflow) const {
      +    BoolNode* bool_for_expression = _phase->rc_predicate(new_control, _scale, _offset, operand, nullptr,
      +                                                         _stride, _range, _upper, does_overflow);
      +    return create_opaque_initialized_assertion_predicate_node(new_control, bool_for_expression);
      +  }
      +
      + private:
      +  OpaqueInitializedAssertionPredicateNode* create_opaque_initialized_assertion_predicate_node(
      +      Node* new_control, BoolNode* bool_for_expression) const {
      +    OpaqueInitializedAssertionPredicateNode* new_expression =
      +        new OpaqueInitializedAssertionPredicateNode(bool_for_expression, _phase->C);
      +    _phase->register_new_node(new_expression, new_control);
      +    return new_expression;
      +  }
      +};
      +
      +// Creates an If with a success and a fail path with the given assertion_expression. The only difference to
      +// create_for_initialized() is that we use a template specific Halt message on the fail path.
      +IfTrueNode* AssertionPredicateIfCreator::create_for_template(Node* new_control, const int if_opcode,
      +                                                             Node* assertion_expression NOT_PRODUCT(COMMA
      +                                                             const AssertionPredicateType assertion_predicate_type)) {
      +  const char* halt_message = "Template Assertion Predicates are always removed before code generation";
      +  return create(new_control, if_opcode, assertion_expression, halt_message NOT_PRODUCT(COMMA assertion_predicate_type));
      +}
      +
      +// Creates an If with a success and a fail path with the given assertion_expression. The only difference to
      +// create_for_template() is that we use a initialized specific Halt message on the fail path.
      +IfTrueNode* AssertionPredicateIfCreator::create_for_initialized(Node* new_control, const int if_opcode,
      +                                                                Node* assertion_expression NOT_PRODUCT(COMMA
      +                                                                const AssertionPredicateType assertion_predicate_type)) {
      +  const char* halt_message = "Initialized Assertion Predicate cannot fail";
      +  return create(new_control, if_opcode, assertion_expression, halt_message NOT_PRODUCT(COMMA assertion_predicate_type));
      +}
      +
      +// Creates the If node for an Assertion Predicate with a success path and a fail path having a Halt node:
       //
      -//             /         init                 stride
      -//             |           |                    |
      -//             |  OpaqueLoopInitNode  OpaqueLoopStrideNode                      /       _new_init    _new_stride
      -//  Template   |                 \     /                                        |              \     /
      -//  Assertion  |                   ...                               Assertion  |                ...
      -//  Expression |                    |                                Expression |                 |
      -//             |                   Bool                                         |              new Bool
      -//             |                    |                                           |                 |
      -//             \                 Opaque4           ======>          control     \  OpaqueInitializedAssertionPredicate
      -//                                  |                                      \      /
      -//                                 If                                       new If
      -//                               /    \                                     /    \
      -//                         success     fail path                   new success   new Halt
      -//                           proj    (Halt or UCT)                     proj
      +//      new_control   assertion_expression
      +//                \   /
      +//                 If
      +//               /    \
      +//        success     fail path
      +//           proj      with Halt
       //
      -IfTrueNode* InitializedAssertionPredicateCreator::create(Node* control) {
      -  IdealLoopTree* loop = _phase->get_loop(control);
      -  OpaqueInitializedAssertionPredicateNode* assertion_expression = create_assertion_expression(control);
      -  IfNode* if_node = create_if_node(control, assertion_expression, loop);
      -  create_fail_path(if_node, loop);
      +IfTrueNode* AssertionPredicateIfCreator::create(Node* new_control, const int if_opcode, Node* assertion_expression,
      +                                                const char* halt_message NOT_PRODUCT(COMMA
      +                                                const AssertionPredicateType assertion_predicate_type)) {
      +  assert(assertion_expression->is_Opaque4() || assertion_expression->is_OpaqueInitializedAssertionPredicate(),
      +         "not a valid assertion expression");
      +  IdealLoopTree* loop = _phase->get_loop(new_control);
      +  IfNode* if_node = create_if_node(new_control, if_opcode, assertion_expression, loop
      +                                   NOT_PRODUCT(COMMA assertion_predicate_type));
      +  create_fail_path(if_node, loop, halt_message);
         return create_success_path(if_node, loop);
       }
       
      -// Create a new Assertion Expression to be used as bool input for the Initialized Assertion Predicate IfNode.
      -OpaqueInitializedAssertionPredicateNode* InitializedAssertionPredicateCreator::create_assertion_expression(Node* control) {
      -  Opaque4Node* template_opaque = _template_assertion_predicate->in(1)->as_Opaque4();
      -  TemplateAssertionExpression template_assertion_expression(template_opaque);
      -  Opaque4Node* tmp_opaque = template_assertion_expression.clone_and_replace_init_and_stride(_new_init, _new_stride,
      -                                                                                            control, _phase);
      -  OpaqueInitializedAssertionPredicateNode* assertion_expression =
      -      new OpaqueInitializedAssertionPredicateNode(tmp_opaque->in(1)->as_Bool(), _phase->C);
      -  _phase->register_new_node(assertion_expression, control);
      -  return assertion_expression;
      -}
      -
      -IfNode* InitializedAssertionPredicateCreator::create_if_node(Node* control,
      -                                                             OpaqueInitializedAssertionPredicateNode* assertion_expression,
      -                                                             IdealLoopTree* loop) {
      -  const int if_opcode = _template_assertion_predicate->Opcode();
      -  NOT_PRODUCT(const AssertionPredicateType assertion_predicate_type = _template_assertion_predicate->assertion_predicate_type();)
      -  IfNode* if_node = if_opcode == Op_If ?
      -      new IfNode(control, assertion_expression, PROB_MAX, COUNT_UNKNOWN NOT_PRODUCT(COMMA assertion_predicate_type)) :
      -      new RangeCheckNode(control, assertion_expression, PROB_MAX, COUNT_UNKNOWN NOT_PRODUCT(COMMA assertion_predicate_type));
      -  _phase->register_control(if_node, loop, control);
      +IfNode* AssertionPredicateIfCreator::create_if_node(Node* new_control, const int if_opcode, Node* assertion_expression,
      +                                                    IdealLoopTree* loop NOT_PRODUCT(COMMA
      +                                                    const AssertionPredicateType assertion_predicate_type)) {
      +  IfNode* if_node;
      +  if (if_opcode == Op_If) {
      +    if_node = new IfNode(new_control, assertion_expression, PROB_MAX, COUNT_UNKNOWN
      +                         NOT_PRODUCT(COMMA assertion_predicate_type));
      +  } else {
      +    assert(if_opcode == Op_RangeCheck, "must be range check");
      +    if_node = new RangeCheckNode(new_control, assertion_expression, PROB_MAX, COUNT_UNKNOWN
      +                                 NOT_PRODUCT(COMMA assertion_predicate_type));
      +  }
      +  _phase->register_control(if_node, loop, new_control);
         return if_node;
       }
       
      -IfTrueNode* InitializedAssertionPredicateCreator::create_success_path(IfNode* if_node, IdealLoopTree* loop) {
      +IfTrueNode* AssertionPredicateIfCreator::create_success_path(IfNode* if_node, IdealLoopTree* loop) {
         IfTrueNode* success_proj = new IfTrueNode(if_node);
         _phase->register_control(success_proj, loop, if_node);
         return success_proj;
       }
       
      -void InitializedAssertionPredicateCreator::create_fail_path(IfNode* if_node, IdealLoopTree* loop) {
      +void AssertionPredicateIfCreator::create_fail_path(IfNode* if_node, IdealLoopTree* loop, const char* halt_message) {
         IfFalseNode* fail_proj = new IfFalseNode(if_node);
         _phase->register_control(fail_proj, loop, if_node);
      -  create_halt_node(fail_proj, loop);
      +  create_halt_node(fail_proj, loop, halt_message);
       }
       
      -void InitializedAssertionPredicateCreator::create_halt_node(IfFalseNode* fail_proj, IdealLoopTree* loop) {
      +void AssertionPredicateIfCreator::create_halt_node(IfFalseNode* fail_proj, IdealLoopTree* loop,
      +                                                   const char* halt_message) {
         StartNode* start_node = _phase->C->start();
         Node* frame = new ParmNode(start_node, TypeFunc::FramePtr);
         _phase->register_new_node(frame, start_node);
      -  Node* halt = new HaltNode(fail_proj, frame, "Initialized Assertion Predicate cannot fail");
      +  Node* halt = new HaltNode(fail_proj, frame, halt_message);
         _phase->igvn().add_input_to(_phase->C->root(), halt);
         _phase->register_control(halt, loop, fail_proj);
       }
       
      +// Creates an init and last value Template Assertion Predicate connected together from a Parse Predicate with an UCT on
      +// the failing path. Returns the success projection of the last value Template Assertion Predicate.
      +IfTrueNode* TemplateAssertionPredicateCreator::create_with_uncommon_trap(
      +    Node* new_control, ParsePredicateSuccessProj* parse_predicate_success_proj,
      +    const Deoptimization::DeoptReason deopt_reason, const int if_opcode) {
      +  OpaqueLoopInitNode* opaque_init = create_opaque_init(new_control);
      +  bool does_overflow;
      +  Opaque4Node* template_assertion_predicate_expression = create_for_init_value(new_control, opaque_init,
      +                                                                               does_overflow);
      +  IfTrueNode* template_predicate_success_proj =
      +      create_if_node_with_uncommon_trap(template_assertion_predicate_expression, parse_predicate_success_proj,
      +                                        deopt_reason, if_opcode, does_overflow
      +                                        NOT_PRODUCT(COMMA AssertionPredicateType::InitValue));
      +  template_assertion_predicate_expression = create_for_last_value(template_predicate_success_proj, opaque_init,
      +                                                                  does_overflow);
      +  return create_if_node_with_uncommon_trap(template_assertion_predicate_expression, parse_predicate_success_proj,
      +                                           deopt_reason, if_opcode, does_overflow
      +                                           NOT_PRODUCT(COMMA AssertionPredicateType::LastValue));
      +}
      +
      +OpaqueLoopInitNode* TemplateAssertionPredicateCreator::create_opaque_init(Node* new_control) {
      +  OpaqueLoopInitNode* opaque_init = new OpaqueLoopInitNode(_phase->C, _loop_head->init_trip());
      +  _phase->register_new_node(opaque_init, new_control);
      +  return opaque_init;
      +}
      +
      +Opaque4Node* TemplateAssertionPredicateCreator::create_for_init_value(Node* new_control, OpaqueLoopInitNode* opaque_init,
      +                                                                      bool& does_overflow) const {
      +  AssertionPredicateExpressionCreator expression_creator(_loop_head->stride_con(), _scale, _offset, _range, _phase);
      +  return expression_creator.create_for_template(new_control, opaque_init, does_overflow);
      +}
      +
      +IfTrueNode* TemplateAssertionPredicateCreator::create_if_node_with_uncommon_trap(
      +    Opaque4Node* template_assertion_predicate_expression, ParsePredicateSuccessProj* parse_predicate_success_proj,
      +    const Deoptimization::DeoptReason deopt_reason, const int if_opcode, const bool does_overflow
      +    NOT_PRODUCT(COMMA AssertionPredicateType assertion_predicate_type)) {
      +  IfTrueNode* success_proj = _phase->create_new_if_for_predicate(parse_predicate_success_proj, nullptr, deopt_reason,
      +                                                                 does_overflow ? Op_If : if_opcode, false
      +                                                                 NOT_PRODUCT(COMMA assertion_predicate_type));
      +  _phase->igvn().replace_input_of(success_proj->in(0), 1, template_assertion_predicate_expression);
      +  return success_proj;
      +}
      +
      +Opaque4Node* TemplateAssertionPredicateCreator::create_for_last_value(Node* new_control, OpaqueLoopInitNode* opaque_init,
      +                                                                      bool& does_overflow) const {
      +  Node* last_value = create_last_value(new_control, opaque_init);
      +  AssertionPredicateExpressionCreator expression_creator(_loop_head->stride_con(), _scale, _offset, _range, _phase);
      +  return expression_creator.create_for_template(new_control, last_value, does_overflow);
      +}
      +
      +Node* TemplateAssertionPredicateCreator::create_last_value(Node* new_control, OpaqueLoopInitNode* opaque_init) const {
      +  Node* init_stride = _loop_head->stride();
      +  Node* opaque_stride = new OpaqueLoopStrideNode(_phase->C, init_stride);
      +  _phase->register_new_node(opaque_stride, new_control);
      +  Node* last_value = new SubINode(opaque_stride, init_stride);
      +  _phase->register_new_node(last_value, new_control);
      +  last_value = new AddINode(opaque_init, last_value);
      +  _phase->register_new_node(last_value, new_control);
      +  // init + (current stride - initial stride) is within the loop so narrow its type by leveraging the type of the iv phi
      +  last_value = new CastIINode(new_control, last_value, _loop_head->phi()->bottom_type());
      +  _phase->register_new_node(last_value, new_control);
      +  return last_value;
      +}
      +
      +IfTrueNode* TemplateAssertionPredicateCreator::create_if_node_with_halt(
      +    Node* new_control, Opaque4Node* template_assertion_predicate_expression, bool does_overflow
      +    NOT_PRODUCT(COMMA AssertionPredicateType assertion_predicate_type)) {
      +  AssertionPredicateIfCreator assertion_predicate_if_creator(_phase);
      +  return assertion_predicate_if_creator.create_for_template(new_control, does_overflow ? Op_If : Op_RangeCheck,
      +                                                            template_assertion_predicate_expression
      +                                                            NOT_PRODUCT(COMMA assertion_predicate_type));
      +}
      +
      +// Creates an init and last value Template Assertion Predicate connected together with a Halt node on the failing path.
      +// Returns the success projection of the last value Template Assertion Predicate latter.
      +IfTrueNode* TemplateAssertionPredicateCreator::create_with_halt(Node* new_control) {
      +  OpaqueLoopInitNode* opaque_init = create_opaque_init(new_control);
      +  bool does_overflow;
      +  Opaque4Node* template_assertion_predicate_expression = create_for_init_value(new_control, opaque_init,
      +                                                                               does_overflow);
      +  IfTrueNode* template_predicate_success_proj =
      +      create_if_node_with_halt(new_control, template_assertion_predicate_expression, does_overflow
      +                               NOT_PRODUCT(COMMA AssertionPredicateType::InitValue));
      +  template_assertion_predicate_expression = create_for_last_value(template_predicate_success_proj, opaque_init,
      +                                                                  does_overflow);
      +  return create_if_node_with_halt(template_predicate_success_proj, template_assertion_predicate_expression,
      +                                  does_overflow NOT_PRODUCT(COMMA AssertionPredicateType::LastValue));
      +}
      +
      +InitializedAssertionPredicateCreator::InitializedAssertionPredicateCreator(PhaseIdealLoop* phase)
      +    : _phase(phase) {}
      +
      +// Create an Initialized Assertion Predicate from the provided template_assertion_predicate at 'new_control'.
      +// We clone the Template Assertion Expression and replace:
      +// - Opaque4 with OpaqueInitializedAssertionPredicate
      +// - OpaqueLoop*Nodes with new_init and _ew_stride, respectively.
      +//
      +//             /         init                 stride
      +//             |           |                    |
      +//             |  OpaqueLoopInitNode  OpaqueLoopStrideNode                      /        new_init    new_stride
      +//  Template   |                 \     /                                        |              \     /
      +//  Assertion  |                   ...                               Assertion  |                ...
      +//  Expression |                    |                                Expression |                 |
      +//             |                   Bool                                         |              new Bool
      +//             |                    |                                           |                 |
      +//             \                 Opaque4           ======>      new_control     \  OpaqueInitializedAssertionPredicate
      +//                                  |                                      \      /
      +//                                 If                                       new If
      +//                               /    \                                     /    \
      +//                         success     fail path                   new success   new Halt
      +//                           proj    (Halt or UCT)                     proj
      +//
      +IfTrueNode* InitializedAssertionPredicateCreator::create_from_template(IfNode* template_assertion_predicate,
      +                                                                       Node* new_control, Node* new_init,
      +                                                                       Node* new_stride) {
      +  OpaqueInitializedAssertionPredicateNode* assertion_expression =
      +      create_assertion_expression_from_template(template_assertion_predicate, new_control, new_init, new_stride);
      +  return create_control_nodes(new_control, template_assertion_predicate->Opcode(), assertion_expression
      +                              NOT_PRODUCT(COMMA template_assertion_predicate->assertion_predicate_type()));
      +}
      +
      +// Create a new Initialized Assertion Predicate directly without a template.
      +IfTrueNode* InitializedAssertionPredicateCreator::create(Node* operand, Node* new_control, const jint stride,
      +                                                         const int scale, Node* offset, Node* range NOT_PRODUCT(COMMA
      +                                                         AssertionPredicateType assertion_predicate_type)) {
      +  AssertionPredicateExpressionCreator expression_creator(stride, scale, offset, range, _phase);
      +  bool does_overflow;
      +  OpaqueInitializedAssertionPredicateNode* assertion_expression =
      +      expression_creator.create_for_initialized(new_control, operand, does_overflow);
      +  return create_control_nodes(new_control, does_overflow ? Op_If : Op_RangeCheck, assertion_expression
      +                              NOT_PRODUCT(COMMA assertion_predicate_type));
      +}
      +
      +// Creates the CFG nodes for the Initialized Assertion Predicate.
      +IfTrueNode* InitializedAssertionPredicateCreator::create_control_nodes(
      +    Node* new_control, const int if_opcode, OpaqueInitializedAssertionPredicateNode* assertion_expression
      +    NOT_PRODUCT(COMMA AssertionPredicateType assertion_predicate_type)) {
      +  AssertionPredicateIfCreator assertion_predicate_if_creator(_phase);
      +  return assertion_predicate_if_creator.create_for_initialized(new_control, if_opcode, assertion_expression
      +                                                               NOT_PRODUCT(COMMA assertion_predicate_type));
      +}
      +
      +// Create a new Assertion Expression based from the given template to be used as bool input for the Initialized
      +// Assertion Predicate IfNode.
      +OpaqueInitializedAssertionPredicateNode*
      +InitializedAssertionPredicateCreator::create_assertion_expression_from_template(IfNode* template_assertion_predicate,
      +                                                                                Node* new_control, Node* new_init,
      +                                                                                Node* new_stride) {
      +  Opaque4Node* template_opaque = template_assertion_predicate->in(1)->as_Opaque4();
      +  TemplateAssertionExpression template_assertion_expression(template_opaque);
      +  Opaque4Node* tmp_opaque = template_assertion_expression.clone_and_replace_init_and_stride(new_control, new_init,
      +                                                                                            new_stride,
      +                                                                                            _phase);
      +  OpaqueInitializedAssertionPredicateNode* assertion_expression =
      +      new OpaqueInitializedAssertionPredicateNode(tmp_opaque->in(1)->as_Bool(), _phase->C);
      +  _phase->register_new_node(assertion_expression, new_control);
      +  return assertion_expression;
      +}
      +
       #ifndef PRODUCT
       void PredicateBlock::dump() const {
         dump("");
      diff --git a/src/hotspot/share/opto/predicates.hpp b/src/hotspot/share/opto/predicates.hpp
      index b38b888cc3dba..0a5d6226c8c94 100644
      --- a/src/hotspot/share/opto/predicates.hpp
      +++ b/src/hotspot/share/opto/predicates.hpp
      @@ -207,7 +207,9 @@ class TemplateAssertionPredicate;
       enum class AssertionPredicateType {
         None, // Not an Assertion Predicate
         InitValue,
      -  LastValue
      +  LastValue,
      +  // Used for the Initialized Assertion Predicate emitted during Range Check Elimination for the final IV value.
      +  FinalIv
       };
       #endif // NOT PRODUCT
       
      @@ -442,8 +444,9 @@ class TemplateAssertionExpression : public StackObj {
       
        public:
         Opaque4Node* clone(Node* new_ctrl, PhaseIdealLoop* phase);
      -  Opaque4Node* clone_and_replace_init(Node* new_init, Node* new_ctrl,PhaseIdealLoop* phase);
      -  Opaque4Node* clone_and_replace_init_and_stride(Node* new_init, Node* new_stride, Node* new_ctrl, PhaseIdealLoop* phase);
      +  Opaque4Node* clone_and_replace_init(Node* new_init, Node* new_ctrl, PhaseIdealLoop* phase);
      +  Opaque4Node* clone_and_replace_init_and_stride(Node* new_control, Node* new_init, Node* new_stride,
      +                                                 PhaseIdealLoop* phase);
       };
       
       // Class to represent a node being part of a Template Assertion Expression. Note that this is not an IR node.
      @@ -520,26 +523,84 @@ class TemplateAssertionExpressionNode : public StackObj {
         }
       };
       
      -// This class creates a new Initialized Assertion Predicate.
      +// This class is used to create the actual If node with a success path and a fail path with a Halt node.
      +class AssertionPredicateIfCreator : public StackObj {
      +  PhaseIdealLoop* const _phase;
      +
      + public:
      +  explicit AssertionPredicateIfCreator(PhaseIdealLoop* const phase) : _phase(phase) {}
      +  NONCOPYABLE(AssertionPredicateIfCreator);
      +
      +  IfTrueNode* create_for_initialized(Node* new_control, int if_opcode, Node* assertion_expression
      +                                     NOT_PRODUCT(COMMA const AssertionPredicateType assertion_predicate_type));
      +  IfTrueNode* create_for_template(Node* new_control, int if_opcode, Node* assertion_expression
      +                                  NOT_PRODUCT(COMMA const AssertionPredicateType assertion_predicate_type));
      + private:
      +  IfTrueNode* create(Node* new_control, int if_opcode, Node* assertion_expression, const char* halt_message
      +                     NOT_PRODUCT(COMMA const AssertionPredicateType assertion_predicate_type));
      +  IfNode* create_if_node(Node* new_control, int if_opcode, Node* assertion_expression, IdealLoopTree* loop
      +                         NOT_PRODUCT(COMMA const AssertionPredicateType assertion_predicate_type));
      +  IfTrueNode* create_success_path(IfNode* if_node, IdealLoopTree* loop);
      +  void create_fail_path(IfNode* if_node, IdealLoopTree* loop, const char* halt_message);
      +  void create_halt_node(IfFalseNode* fail_proj, IdealLoopTree* loop, const char* halt_message);
      +};
      +
      +// This class is used to create a Template Assertion Predicate either with an UCT or a Halt Node from scratch.
      +class TemplateAssertionPredicateCreator : public StackObj {
      +  CountedLoopNode* const _loop_head;
      +  const int _scale;
      +  Node* const _offset;
      +  Node* const _range;
      +  PhaseIdealLoop* const _phase;
      +
      +  OpaqueLoopInitNode* create_opaque_init(Node* new_control);
      +  Opaque4Node* create_for_init_value(Node* new_control, OpaqueLoopInitNode* opaque_init, bool& does_overflow) const;
      +  Opaque4Node* create_for_last_value(Node* new_control, OpaqueLoopInitNode* opaque_init, bool& does_overflow) const;
      +  Node* create_last_value(Node* new_control, OpaqueLoopInitNode* opaque_init) const;
      +  IfTrueNode* create_if_node_with_uncommon_trap(Opaque4Node* template_assertion_predicate_expression,
      +                                                ParsePredicateSuccessProj* parse_predicate_success_proj,
      +                                                Deoptimization::DeoptReason deopt_reason, int if_opcode,
      +                                                bool does_overflow
      +                                                NOT_PRODUCT(COMMA AssertionPredicateType assertion_predicate_type));
      +  IfTrueNode* create_if_node_with_halt(Node* new_control, Opaque4Node* template_assertion_predicate_expression,
      +                                       bool does_overflow
      +                                       NOT_PRODUCT(COMMA AssertionPredicateType assertion_predicate_type));
      +
      + public:
      +  TemplateAssertionPredicateCreator(CountedLoopNode* loop_head, int scale, Node* offset, Node* range,
      +                                    PhaseIdealLoop* phase)
      +      : _loop_head(loop_head),
      +        _scale(scale),
      +        _offset(offset),
      +        _range(range),
      +        _phase(phase) {}
      +  NONCOPYABLE(TemplateAssertionPredicateCreator);
      +
      +  IfTrueNode* create_with_uncommon_trap(Node* new_control, ParsePredicateSuccessProj* parse_predicate_success_proj,
      +                                        Deoptimization::DeoptReason deopt_reason, int if_opcode);
      +  IfTrueNode* create_with_halt(Node* new_control);
      +};
      +
      +// This class creates a new Initialized Assertion Predicate either from a template or from scratch.
       class InitializedAssertionPredicateCreator : public StackObj {
      -  IfNode* const _template_assertion_predicate;
      -  Node* const _new_init;
      -  Node* const _new_stride;
         PhaseIdealLoop* const _phase;
       
        public:
      -  InitializedAssertionPredicateCreator(IfNode* template_assertion_predicate, Node* new_init, Node* new_stride,
      -                                       PhaseIdealLoop* phase);
      +  explicit InitializedAssertionPredicateCreator(PhaseIdealLoop* phase);
         NONCOPYABLE(InitializedAssertionPredicateCreator);
       
      -  IfTrueNode* create(Node* control);
      +  IfTrueNode* create_from_template(IfNode* template_assertion_predicate, Node* new_control, Node* new_init,
      +                                   Node* new_stride);
      +  IfTrueNode* create(Node* operand, Node* new_control, jint stride, int scale, Node* offset, Node* range
      +                     NOT_PRODUCT(COMMA AssertionPredicateType assertion_predicate_type));
       
        private:
      -  OpaqueInitializedAssertionPredicateNode* create_assertion_expression(Node* control);
      -  IfNode* create_if_node(Node* control, OpaqueInitializedAssertionPredicateNode* assertion_expression, IdealLoopTree* loop);
      -  void create_fail_path(IfNode* if_node, IdealLoopTree* loop);
      -  void create_halt_node(IfFalseNode* fail_proj, IdealLoopTree* loop);
      -  IfTrueNode* create_success_path(IfNode* if_node, IdealLoopTree* loop);
      +  OpaqueInitializedAssertionPredicateNode* create_assertion_expression_from_template(IfNode* template_assertion_predicate,
      +                                                                                     Node* new_control, Node* new_init,
      +                                                                                     Node* new_stride);
      +  IfTrueNode* create_control_nodes(Node* new_control, int if_opcode,
      +                                   OpaqueInitializedAssertionPredicateNode* assertion_expression
      +                                   NOT_PRODUCT(COMMA AssertionPredicateType assertion_predicate_type));
       };
       
       // This class iterates through all predicates of a Regular Predicate Block and applies the given visitor to each.
      
      From f6fe5eaf1a24ba083e7ecf28b02290020ccab142 Mon Sep 17 00:00:00 2001
      From: Tejesh R 
      Date: Thu, 17 Oct 2024 05:48:45 +0000
      Subject: [PATCH 101/118] 8341072: Open source several AWT Canvas and Rectangle
       related tests
      
      Reviewed-by: prr
      ---
       test/jdk/java/awt/Canvas/MultiDitherTest.java | 422 ++++++++++++++++++
       .../java/awt/Canvas/MultiGraphicsTest.java    | 139 ++++++
       .../jdk/java/awt/Canvas/NoEventsLeakTest.java |  96 ++++
       test/jdk/java/awt/Canvas/duke_404.gif         | Bin 0 -> 5529 bytes
       .../java/awt/Rectangle/IntersectionTest.java  |  88 ++++
       5 files changed, 745 insertions(+)
       create mode 100644 test/jdk/java/awt/Canvas/MultiDitherTest.java
       create mode 100644 test/jdk/java/awt/Canvas/MultiGraphicsTest.java
       create mode 100644 test/jdk/java/awt/Canvas/NoEventsLeakTest.java
       create mode 100644 test/jdk/java/awt/Canvas/duke_404.gif
       create mode 100644 test/jdk/java/awt/Rectangle/IntersectionTest.java
      
      diff --git a/test/jdk/java/awt/Canvas/MultiDitherTest.java b/test/jdk/java/awt/Canvas/MultiDitherTest.java
      new file mode 100644
      index 0000000000000..ab592280c80b4
      --- /dev/null
      +++ b/test/jdk/java/awt/Canvas/MultiDitherTest.java
      @@ -0,0 +1,422 @@
      +/*
      + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
      + * 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 6616089
      + * @summary Displays a dithered Canvas on all available GraphicsConfigurations
      + * @library /java/awt/regtesthelpers
      + * @build PassFailJFrame
      + * @run main/manual MultiDitherTest
      + */
      +
      +import java.awt.BorderLayout;
      +import java.awt.Button;
      +import java.awt.Canvas;
      +import java.awt.Choice;
      +import java.awt.Color;
      +import java.awt.Dimension;
      +import java.awt.EventQueue;
      +import java.awt.FlowLayout;
      +import java.awt.FontMetrics;
      +import java.awt.Frame;
      +import java.awt.Graphics;
      +import java.awt.GraphicsConfiguration;
      +import java.awt.GraphicsDevice;
      +import java.awt.GraphicsEnvironment;
      +import java.awt.Image;
      +import java.awt.Label;
      +import java.awt.LayoutManager;
      +import java.awt.Panel;
      +import java.awt.TextField;
      +import java.awt.event.ActionEvent;
      +import java.awt.event.ActionListener;
      +import java.awt.event.WindowAdapter;
      +import java.awt.event.WindowEvent;
      +import java.awt.image.ColorModel;
      +import java.awt.image.MemoryImageSource;
      +import java.util.List;
      +
      +public class MultiDitherTest extends Panel implements Runnable {
      +    final static int NOOP = 0;
      +    final static int RED = 1;
      +    final static int GREEN = 2;
      +    final static int BLUE = 3;
      +    final static int ALPHA = 4;
      +    final static int SATURATION = 5;
      +    final static String calcString = "Calculating...";
      +    static LayoutManager dcLayout = new FlowLayout(FlowLayout.CENTER, 10, 5);
      +    Thread runner;
      +    DitherControls XControls;
      +    DitherControls YControls;
      +    DitherCanvas canvas;
      +
      +    public static void main(String[] args) throws Exception {
      +        String INSTRUCTIONS = """
      +                Depending on the GraphicsConfiguration, the dithering may be in
      +                color or in grayscale and/or display at a lower bitdepth.
      +                The number of GraphicsConfigurations will be printed in the
      +                TextArea below as the test is starting up.
      +                Ensure that there are as many Frames created as there are
      +                available GraphicsConfigurations.
      +                Examine each Frame to ensure it displays the dither pattern.
      +                If all Canvases display correctly, the test PASSES.
      +                Otherwise, the test FAILS.
      +                The GC button runs the garbage collector.
      +                This button can be ignored for now.
      +
      +                           """;
      +        PassFailJFrame passFailJFrame = PassFailJFrame.builder()
      +                .title("Test Instructions")
      +                .instructions(INSTRUCTIONS)
      +                .rows((int) INSTRUCTIONS.lines().count() + 2)
      +                .columns(35)
      +                .build();
      +
      +        EventQueue.invokeAndWait(() -> {
      +            for (Frame frame : MultiDitherTest.initialize()) {
      +                PassFailJFrame.addTestWindow(frame);
      +                frame.setVisible(true);
      +            }
      +        });
      +        passFailJFrame.awaitAndCheck();
      +    }
      +
      +    public MultiDitherTest(GraphicsConfiguration gc) {
      +        String xSpec, ySpec;
      +        int[] xValues = new int[2];
      +        int[] yValues = new int[2];
      +
      +        xSpec = "red";
      +        ySpec = "blue";
      +        int xMethod = colorMethod(xSpec, xValues);
      +        int yMethod = colorMethod(ySpec, yValues);
      +
      +        setLayout(new BorderLayout());
      +        XControls = new DitherControls(this, xValues[0], xValues[1],
      +                xMethod, false);
      +        YControls = new DitherControls(this, yValues[0], yValues[1],
      +                yMethod, true);
      +        YControls.addRenderButton();
      +        YControls.addGCButton();
      +        add("North", XControls);
      +        add("South", YControls);
      +        add("Center", canvas = new DitherCanvas(gc));
      +    }
      +
      +    private static List initialize() {
      +        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
      +        GraphicsDevice[] gds = ge.getScreenDevices();
      +        Frame[] frames = new Frame[0];
      +        System.out.println(gds.length + " screens detected");
      +
      +        for (int j = 0; j < gds.length; j++) {
      +
      +            GraphicsDevice gd = gds[j];
      +            GraphicsConfiguration[] gcs = gd.getConfigurations();
      +            frames = new Frame[gcs.length];
      +            System.out.println(gcs.length + " GraphicsConfigurations available on screen " + j);
      +            for (int i = 0; i < gcs.length; i++) {
      +                Frame f = new Frame("MultiDitherTest " + (i + 1), gcs[i]);
      +                f.setLayout(new BorderLayout());
      +                f.setLocation(gcs[i].getBounds().x + 100 + (i * 10),
      +                        gcs[i].getBounds().y + 100 + (i * 10));
      +                MultiDitherTest ditherTest = new MultiDitherTest(gcs[i]);
      +                f.add("Center", ditherTest);
      +                f.pack();
      +                f.addWindowListener(new WindowAdapter() {
      +                    public void windowClosing(WindowEvent ev) {
      +                        ev.getWindow().dispose();
      +                    }
      +                });
      +                f.setVisible(true);
      +                ditherTest.start();
      +                frames[i] = f;
      +            }
      +
      +        }
      +        return List.of(frames);
      +    }
      +
      +    int colorMethod(String s, int[] values) {
      +        int method = NOOP;
      +
      +        if (s == null) {
      +            s = "";
      +        }
      +
      +        String lower = s.toLowerCase();
      +        if (lower.startsWith("red")) {
      +            method = RED;
      +            lower = lower.substring(3);
      +        } else if (lower.startsWith("green")) {
      +            method = GREEN;
      +            lower = lower.substring(5);
      +        } else if (lower.startsWith("blue")) {
      +            method = BLUE;
      +            lower = lower.substring(4);
      +        } else if (lower.startsWith("alpha")) {
      +            method = ALPHA;
      +            lower = lower.substring(4);
      +        } else if (lower.startsWith("saturation")) {
      +            method = SATURATION;
      +            lower = lower.substring(10);
      +        }
      +
      +        if (method == NOOP) {
      +            values[0] = 0;
      +            values[1] = 0;
      +            return method;
      +        }
      +
      +        int begval = 0;
      +        int endval = 255;
      +
      +        try {
      +            int dash = lower.indexOf('-');
      +            if (dash < 0) {
      +                begval = endval = Integer.parseInt(lower);
      +            } else {
      +                begval = Integer.parseInt(lower.substring(0, dash));
      +                endval = Integer.parseInt(lower.substring(dash + 1));
      +            }
      +        } catch (Exception e) {
      +        }
      +
      +        if (begval < 0) {
      +            begval = 0;
      +        }
      +        if (endval < 0) {
      +            endval = 0;
      +        }
      +        if (begval > 255) {
      +            begval = 255;
      +        }
      +        if (endval > 255) {
      +            endval = 255;
      +        }
      +
      +        values[0] = begval;
      +        values[1] = endval;
      +
      +        return method;
      +    }
      +
      +    public void start() {
      +        runner = new Thread(this);
      +        runner.start();
      +    }
      +
      +    public void stop() {
      +        runner = null;
      +    }
      +
      +    public void destroy() {
      +        remove(XControls);
      +        remove(YControls);
      +        remove(canvas);
      +    }
      +
      +    void applyMethod(int[] c, int method, int step, int total, int[] values) {
      +        if (method == NOOP) {
      +            return;
      +        }
      +        int val = ((total < 2)
      +                ? values[0]
      +                : values[0] + ((values[1] - values[0]) * step / (total - 1)));
      +        switch (method) {
      +            case RED:
      +                c[0] = val;
      +                break;
      +            case GREEN:
      +                c[1] = val;
      +                break;
      +            case BLUE:
      +                c[2] = val;
      +                break;
      +            case ALPHA:
      +                c[3] = val;
      +                break;
      +            case SATURATION:
      +                int max = Math.max(Math.max(c[0], c[1]), c[2]);
      +                int min = max * (255 - val) / 255;
      +                if (c[0] == 0) c[0] = min;
      +                if (c[1] == 0) c[1] = min;
      +                if (c[2] == 0) c[2] = min;
      +                break;
      +        }
      +    }
      +
      +    public void run() {
      +        canvas.setImage(null);
      +        Image img = calculateImage();
      +        synchronized (this) {
      +            if (img != null && runner == Thread.currentThread()) {
      +                canvas.setImage(img);
      +            }
      +        }
      +    }
      +
      +    /**
      +     * Calculates and returns the image.  Halts the calculation and returns
      +     * null if the Application is stopped during the calculation.
      +     */
      +    Image calculateImage() {
      +        Thread me = Thread.currentThread();
      +
      +        int width = canvas.getSize().width;
      +        int height = canvas.getSize().height;
      +        int[] xValues = new int[2];
      +        int[] yValues = new int[2];
      +        int xMethod = XControls.getParams(xValues);
      +        int yMethod = YControls.getParams(yValues);
      +        int[] pixels = new int[width * height];
      +        int[] c = new int[4];
      +        int index = 0;
      +
      +        for (int j = 0; j < height; j++) {
      +            for (int i = 0; i < width; i++) {
      +                c[0] = c[1] = c[2] = 0;
      +                c[3] = 255;
      +                if (xMethod < yMethod) {
      +                    applyMethod(c, xMethod, i, width, xValues);
      +                    applyMethod(c, yMethod, j, height, yValues);
      +                } else {
      +                    applyMethod(c, yMethod, j, height, yValues);
      +                    applyMethod(c, xMethod, i, width, xValues);
      +                }
      +                pixels[index++] = ((c[3] << 24) |
      +                        (c[0] << 16) |
      +                        (c[1] << 8) |
      +                        (c[2] << 0));
      +            }
      +            // Poll once per row to see if we've been told to stop.
      +            if (runner != me) {
      +                return null;
      +            }
      +        }
      +
      +        return createImage(new MemoryImageSource(width, height,
      +                ColorModel.getRGBdefault(), pixels, 0, width));
      +    }
      +
      +    static class DitherCanvas extends Canvas {
      +        Image img;
      +        GraphicsConfiguration mGC;
      +
      +        public DitherCanvas(GraphicsConfiguration gc) {
      +            super(gc);
      +            mGC = gc;
      +        }
      +
      +        public GraphicsConfiguration getGraphicsConfig() {
      +            return mGC;
      +        }
      +
      +        public void paint(Graphics g) {
      +            int w = getSize().width;
      +            int h = getSize().height;
      +            if (img == null) {
      +                super.paint(g);
      +                g.setColor(Color.black);
      +                FontMetrics fm = g.getFontMetrics();
      +                int x = (w - fm.stringWidth(calcString)) / 2;
      +                int y = h / 2;
      +                g.drawString(calcString, x, y);
      +            } else {
      +                g.drawImage(img, 0, 0, w, h, this);
      +            }
      +        }
      +
      +        public void update(Graphics g) {
      +            paint(g);
      +        }
      +
      +        public Dimension getMinimumSize() {
      +            return new Dimension(20, 20);
      +        }
      +
      +        public Dimension getPreferredSize() {
      +            return new Dimension(200, 200);
      +        }
      +
      +        public Image getImage() {
      +            return img;
      +        }
      +
      +        public void setImage(Image img) {
      +            this.img = img;
      +            paint(getGraphics());
      +        }
      +    }
      +
      +    static class DitherControls extends Panel implements ActionListener {
      +        TextField start;
      +        TextField end;
      +        Button button;
      +        Choice choice;
      +        MultiDitherTest panel;
      +        Button gc;
      +
      +        public DitherControls(MultiDitherTest app, int s, int e, int type,
      +                              boolean vertical) {
      +            panel = app;
      +            setLayout(dcLayout);
      +            add(new Label(vertical ? "Vertical" : "Horizontal"));
      +            add(choice = new Choice());
      +            choice.addItem("Noop");
      +            choice.addItem("Red");
      +            choice.addItem("Green");
      +            choice.addItem("Blue");
      +            choice.addItem("Alpha");
      +            choice.addItem("Saturation");
      +            choice.select(type);
      +            add(start = new TextField(Integer.toString(s), 4));
      +            add(end = new TextField(Integer.toString(e), 4));
      +        }
      +
      +        public void addRenderButton() {
      +            add(button = new Button("New Image"));
      +            button.addActionListener(this);
      +        }
      +
      +        public void addGCButton() {
      +            add(gc = new Button("GC"));
      +            gc.addActionListener(this);
      +        }
      +
      +        public int getParams(int[] values) {
      +            values[0] = Integer.parseInt(start.getText());
      +            values[1] = Integer.parseInt(end.getText());
      +            return choice.getSelectedIndex();
      +        }
      +
      +        public void actionPerformed(ActionEvent e) {
      +            if (e.getSource() == button) {
      +                panel.start();
      +            } else if (e.getSource() == gc) {
      +                System.gc();
      +            }
      +        }
      +    }
      +}
      \ No newline at end of file
      diff --git a/test/jdk/java/awt/Canvas/MultiGraphicsTest.java b/test/jdk/java/awt/Canvas/MultiGraphicsTest.java
      new file mode 100644
      index 0000000000000..c38d6041c2b77
      --- /dev/null
      +++ b/test/jdk/java/awt/Canvas/MultiGraphicsTest.java
      @@ -0,0 +1,139 @@
      +/*
      + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
      + * 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 6616089
      + * @summary Display an image in all available GraphicsConfigurations
      + * @library /java/awt/regtesthelpers
      + * @build PassFailJFrame
      + * @run main/manual MultiGraphicsTest
      + */
      +
      +import java.awt.BorderLayout;
      +import java.awt.Canvas;
      +import java.awt.Dimension;
      +import java.awt.Frame;
      +import java.awt.Graphics;
      +import java.awt.GraphicsConfiguration;
      +import java.awt.GraphicsDevice;
      +import java.awt.GraphicsEnvironment;
      +import java.awt.Image;
      +import java.awt.MediaTracker;
      +import java.awt.Toolkit;
      +import java.awt.event.WindowAdapter;
      +import java.awt.event.WindowEvent;
      +import java.net.URL;
      +import java.util.List;
      +
      +public class MultiGraphicsTest extends Canvas {
      +    final static String IMAGEFILE = "duke_404.gif";
      +    static Image jim;
      +    MediaTracker tracker;
      +    int w, h;
      +
      +    public static void main(String[] args) throws Exception {
      +        String INSTRUCTIONS = """
      +                This test displays several Windows containing an image,
      +                one Window for each available GraphicsConfiguration.
      +                Depending on the GraphicsConfiguration, images may be
      +                displayed in color or in grayscale and/or displayed at a
      +                lower bitdepth.
      +                The number of GraphicsConfigurations will be printed below
      +                as the test is starting up.
      +                Ensure that there are as many Windows created as there are
      +                available GraphicsConfigurations.
      +                Examine each Window to ensure it displays Duke_404.
      +                If all Canvases display correctly, the test PASSES.
      +                Otherwise, the test FAILS."
      +                """;
      +        PassFailJFrame.builder()
      +                .title("Test Instructions")
      +                .instructions(INSTRUCTIONS)
      +                .rows((int) INSTRUCTIONS.lines().count() + 2)
      +                .columns(35)
      +                .testUI(initialize())
      +                .build()
      +                .awaitAndCheck();
      +    }
      +
      +    public MultiGraphicsTest(GraphicsConfiguration gc) {
      +        super(gc);
      +        tracker = new MediaTracker(this);
      +        tracker.addImage(jim, 0);
      +        try {
      +            tracker.waitForAll();
      +        } catch (java.lang.InterruptedException e) {
      +            System.err.println(e);
      +        }
      +        w = jim.getWidth(this);
      +        h = jim.getHeight(this);
      +    }
      +
      +    private static List initialize() {
      +        URL imgURL;
      +        imgURL = MultiGraphicsTest.class.getResource(IMAGEFILE);
      +        if (imgURL == null) {
      +            System.err.println("Unable to locate " + IMAGEFILE);
      +            return null;
      +        }
      +        jim = Toolkit.getDefaultToolkit().getImage(imgURL);
      +
      +        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
      +        GraphicsDevice gd = ge.getDefaultScreenDevice();
      +        GraphicsConfiguration[] gc = gd.getConfigurations();
      +        Frame[] frames = new Frame[gc.length];
      +        System.out.println(gc.length + " available GraphicsConfigurations");
      +        for (int i = 0; i < gc.length; i++) {
      +            Frame f = new Frame("GraphicsTest " + (i + 1));
      +            f.setLayout(new BorderLayout());
      +            f.setLocation(100 + (i * 10), 100 + (i * 10));
      +            MultiGraphicsTest gcTest = new MultiGraphicsTest(gc[i]);
      +            f.add("Center", gcTest);
      +            f.pack();
      +            f.addWindowListener(new WindowAdapter() {
      +                public void windowClosing(WindowEvent ev) {
      +                    ev.getWindow().setVisible(false);
      +                }
      +            });
      +            frames[i] = f;
      +        }
      +        return List.of(frames);
      +    }
      +
      +    public void paint(Graphics g) {
      +        g.drawImage(jim, 0, 0, w, h, this);
      +    }
      +
      +    public void update(Graphics g) {
      +        paint(g);
      +    }
      +
      +    public Dimension getMinimumSize() {
      +        return new Dimension(w, h);
      +    }
      +
      +    public Dimension getPreferredSize() {
      +        return new Dimension(w, h);
      +    }
      +}
      diff --git a/test/jdk/java/awt/Canvas/NoEventsLeakTest.java b/test/jdk/java/awt/Canvas/NoEventsLeakTest.java
      new file mode 100644
      index 0000000000000..4768775224a58
      --- /dev/null
      +++ b/test/jdk/java/awt/Canvas/NoEventsLeakTest.java
      @@ -0,0 +1,96 @@
      +/*
      + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
      + * 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 4250354
      + * @key headful
      + * @summary tests that JNI global refs are cleaned up correctly
      + * @run main/timeout=600 NoEventsLeakTest
      + */
      +
      +import java.awt.Canvas;
      +import java.awt.EventQueue;
      +import java.awt.Frame;
      +
      +public class NoEventsLeakTest extends Frame {
      +    static final int nLoopCount = 1000;
      +
      +    private static void initialize() {
      +        NoEventsLeakTest app = new NoEventsLeakTest();
      +        boolean result = app.run();
      +        if (result) {
      +            throw new RuntimeException("Memory leak in Component");
      +        }
      +        System.out.println("Test Passed");
      +    }
      +
      +    public boolean run() {
      +        setSize(10, 10);
      +        addNotify();
      +        for (int i = 0; i < nLoopCount; i++) {
      +            Canvas panel = new TestCanvas();
      +            add(panel, 0);
      +            remove(0);
      +            panel = null;
      +            System.gc();
      +        }
      +        try {
      +            Thread.currentThread().sleep(1000);
      +        } catch (InterruptedException e) {
      +        }
      +        System.gc();
      +        System.out.println("Checking");
      +        return ((TestCanvas.created - TestCanvas.finalized) > 800);
      +    }
      +
      +    public static void main(String[] args) throws Exception {
      +        EventQueue.invokeAndWait(NoEventsLeakTest::initialize);
      +    }
      +}
      +
      +class TestCanvas extends Canvas {
      +    static int finalized = 0;
      +    static int created = 0;
      +    static final int nLoopPrint = 100;
      +
      +    public TestCanvas() {
      +        if (created % nLoopPrint == 0) {
      +            System.out.println("Created " + getClass() + " " + created);
      +        }
      +        created++;
      +    }
      +
      +    @SuppressWarnings("removal")
      +    protected void finalize() {
      +        try {
      +            super.finalize();
      +            if (finalized % nLoopPrint == 0) {
      +                System.out.println("Finalized " + getClass() + " " + finalized);
      +            }
      +            finalized++;
      +        } catch (Throwable t) {
      +            System.out.println("Exception in " + getClass() + ": " + t);
      +        }
      +    }
      +}
      diff --git a/test/jdk/java/awt/Canvas/duke_404.gif b/test/jdk/java/awt/Canvas/duke_404.gif
      new file mode 100644
      index 0000000000000000000000000000000000000000..4958e0d0dfa8c059b704e11fe173f23091cfe8fd
      GIT binary patch
      literal 5529
      zcmWmB`6JVh5C@(K>XYx)-NeKppymWcs``g#**;)0yd+MuK)!p5{PMlCzR{ly){}mMUpS3jw
      zj<7@$L$!=D39JB&)-MX>2O6DdA6vi5yNF;eC0d-(GkrBNH(GV!H(q%I(VDRezO1Pk
      zvMr(RxcvFV-E*6A#x+U3+PY#2L9JHzrk`qI?@H6r?z(ub%-DR7IeYQdRC-#lj7*te
      z+XndA^hnN~bK#a3*`(}XrELkm-GBYBd7m$DSjh>5+R%u_?rwh@tJX%dZ*O!D9Jo=@D5?H5F6e(Ab2*
      z)t)>hZ$9190>Jd(a6OPL#vSXyXuv9IJ!nGf;O|$jozZR}ftTvhU_?vtJg3Ln1+T%YV{8ZFxSjM
      z?*qtir%~zny4-q(MzEb>DV}C;n>yS6@m5*j16|__c^^2XTE^i$%SXIR$Lf7T>S(Ze
      zj+acIOz#jFd2@6bREXCmTDSrRBgNrjxLeq`
      zodjEYZ`l7RQejg|kP|RYQa{T&%N+L9kPIa%b56Gk8e)!uEZfXY+j}|S5aQ~=4>-B8
      zrLZr7vJ8@hULpw~S#NhrA$KXlQrOBEBj-nDr}g5$(LRh+7OXe7;v5I$q6CcCqzm^V
      zuaJxkdYtg&VeSp}quu|F9s~ER_@0WB+9U=5bB=HXH&I>=QwH&b
      zt3$YRezbVIW*RHIXUI=4v~?&@H{Ix|AN5j-%#T`rNvnh$o8K#<65LdYh`q13{0S0@
      z=x@yF9yL04ZHl+_YijKF4!KQY-fnJmz
      zT3@Q@f3OKw9~BiiUINY}JsZ{8{ci5vn$Qc6Zs}&$t{YvG=_U;Tb#IzM2tECj2OTHr
      z{Is~e{tTFG5RmTyz9cci&bPkbSa!ob7x(=7j$d-+$PYh@-r*DA&NMXw{z_0%fyb=e
      z);r`RNF0f*OZ)q7rA5gQk`zs?t}-39$TEuRdz5K`PL%SQdi+cw%JreeCq9|aU{x{b
      z-uG;siSM%O;`)xk&Q_4hA}2QQOwY8}8TM{@%sbP%%OIr}=HpujYwhxXVhC0MOhUB1
      z1E5HGc}Kr4Tep`erpw%-w|Fq6aDTkkC^bEycF%Ph4{DYWSPi%14*d$o
      zQ*}eyj}(LYYi6i4UByq0b0ks?NK+jLm3R3?&`}q*%9B&MNUj~f6KatsZjrRufQ%Ekp|%O+hX`vAp-j4)gAI~s_#g=
      zlN}E>kCel7ifjj5xNv{EnlPtwC{M`v}?z26y3(J8h8M3UlWR^#@L5kT9`}_aPBv*a68=oS_cn5zAE}T^X#uk7(>T&;cs@`X7BvTNUojZ$Udf470lMx>$qj6TpfS&rQVDYW5ZQ}f%1
      zZufHn)cgIXFXQdJbG}l%$a@utH8)l3Y%m|UUgx7M8Ht2s?3#D>SX@m-x|*^Epd&bi^x;RlVcd-(DhP+oPiz2k@gYI>5BinIDCD!Kbxb6>FnT6}QwgvVZR76z@!c`5p&|2d+YC
      zA+v(s^4W9VS>@Z#*irW_1;b){VWRLmPRuqIa^Ul25nMIu6aBtVXGU7gMx@<4&~e%N
      zc5&lzFF2s5fPmhMWw_-A@3iBiAXp3oejG}cW*`ojXrx}IjN#RAh=
      zP%!JbjtW_P?8A3wXN=mib8}N`eWAaNHm^U*DwCRP!Gc@!{Ie&_eq;tNg&)KUfHWZJ
      zxe+=W3VJF7(-gXYGSRR4cJ=ZR>5$bD8GLG^w(ztKTuI1(rm}_sj-5=5%~CkZNyKdk
      zy>Egcs5l?(_I@B+H`Vg=Wz$BSCM^c+HV=!1t$l2b5lnZYwP#6gBirz1CX~&^{1W3bPp{^;
      zZg#==y<-MLr#I@JK?X=sVSrgW8@+Z5+K>x;6of2FB0lxy)Whj{7fR1MMY|`^L|@A<
      zL{wbLuNX)sy47aik^}qeE3Bu&XZRY5h^<@+!F2(<5>jdV&!)G^4TK(B%fgK#8Sx)p
      zRosiP1yp$%EkHH~a6WqANrc)ECJo4HHLuKojr0(AT;}+nUH8(|&V-6bjbeyx*e#T5
      zdwAfCltm?JM%m{clN$V>IlQ#ZXnK?L3}~YSaj*$KH)7
      z5oKvMEx?k?>OigNSZw7%N}Wf4?wPau#SM|i&S?HrYW~N7-?&&8^Q7+bOs(Jw7R`eN
      z6vR&*)ijBZGFGY^s-8qu{R2A~8GFmAy1@prRKl%R;A~QYK{&#i)MU*_|Mf}MQPc2k
      zN0fPnQ^iQsb$fnGPQ@O71FR5n+6Uv(gUIK&v=+E<9imusnw^a??hIG`wy3L=#)IGM
      z2WDh{L4dXhL(z&K*GBx4gWV7w*QtG6l7-+8#ds?bzkhC0P@=y;6*ayF-<>eFBo}Q~
      zY62XV)9CPBNH!mjo3&rVl_J+EqpC+-o#T;TMSy!oxzA;yxzyQKY0e|Ltb9IcFN8CK
      z;~J-6vnfu`jFHcbUHw%}_Q5Chd3dKg0vuqXt1@V0`1eXgbW&=eOCN?&
      zb=-@Z6L0++dv_VDKZkGXAVnFy3XGEW7ki^6VjzW$$^salw5?DK&H+5o{@WEPQK+dv>i5(j$!X!XzjY@rAAjU_2$Gtn7k`SiYk_YkwD>x
      zIyyz}JM33q162LG301FHbT5zGSZb
      zo$HiqK>oxX1M;LO#!A&!hFCY=d!l+sk-@T&gn+X!9WL%$p^ASia7%Cp*XJ^jg#Q
      znn@|biYctfwta9#<3M6cWTl}lAnR2C)H~FmzFXxgAO%7PNx{TQH%mBOtaJP9GXi=q
      zz9g~$-cKX}CVGkhceuIeYi{7MZE_$6zXF`p0|XYv9G)=}>YY^rqfK1hBo16k;00-5MRWjpf;fG+r>?NAwv^M;Gx9GhoNzpdJuV^T?+t~HsQ-8Y_&cvZi{~`D)gT0UtDouh{5ndipo&jtkf%#H&0S|1=qmF#FUgIPw6XbD(_op*PP1o1H
      z%V)p;@kgH!X1^b!b`znw560%ud*{$32y%!~G)*TJYxB(N
      znZV4EJC*t7EuZeldF%7uVwC%b-mwK~*%O7*iHpO9Aq^yLlABtDdNmq|0R!V~@&?ihAZvdJdw1YQKATa(nsUQc`9{b$--d_HAzOBCkG`p1T8bsS%6+71j_ATNU1(tg$`_jZOSY{9xYXl
      zTSLj#aT?e{sGw97Rh!M^6w3xUGkG}&u7O}!6)7o
      zr^}IkRwixv#2@4r_n;Y&W|A4=U+-gs4Ye7SJ=|W;Dqig$e^TW!fN2*~b@$ldT+A}MGZGsZmfQ_|D~8#(H~=>
      zf$llYH2-$NDleu?$9TCY7X9@sQkT8>H2Hz2Q|USP!w-ih|8*+uh~6HnLPyt<8
      
      literal 0
      HcmV?d00001
      
      diff --git a/test/jdk/java/awt/Rectangle/IntersectionTest.java b/test/jdk/java/awt/Rectangle/IntersectionTest.java
      new file mode 100644
      index 0000000000000..41680b2e7b6b1
      --- /dev/null
      +++ b/test/jdk/java/awt/Rectangle/IntersectionTest.java
      @@ -0,0 +1,88 @@
      +/*
      + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
      + * 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 4147957
      + * @key headful
      + * @summary Test to verify setClip with invalid rect changes rect to valid
      + * @run main IntersectionTest
      + */
      +
      +import java.awt.EventQueue;
      +import java.awt.Frame;
      +import java.awt.Graphics;
      +import java.awt.Panel;
      +import java.awt.Rectangle;
      +import java.awt.Robot;
      +
      +public class IntersectionTest {
      +    public static Frame frame;
      +
      +    public static void main(String[] args) throws Exception {
      +        Robot robot = new Robot();
      +        try {
      +            robot.setAutoDelay(100);
      +            EventQueue.invokeAndWait(() -> {
      +                TestFrame panel = new TestFrame();
      +                frame = new Frame("Rectangle Intersection Test");
      +                frame.add(panel);
      +
      +                frame.pack();
      +                frame.setVisible(true);
      +            });
      +            robot.waitForIdle();
      +            robot.delay(200);
      +        } finally {
      +            EventQueue.invokeAndWait(() -> {
      +                if (frame != null) {
      +                    frame.dispose();
      +                }
      +            });
      +        }
      +    }
      +}
      +
      +class TestFrame extends Panel {
      +    @Override
      +    public void paint(Graphics g) {
      +        Rectangle r1 = new Rectangle(0, 0, 100, 100);
      +        Rectangle r2 = new Rectangle(200, 200, 20, 20);
      +        Rectangle r3 = r1.intersection(r2);
      +        System.out.println("intersect:(" + (int) r3.getX() + "," +
      +                (int) r3.getY() + "," + (int) r3.getWidth() + "," +
      +                (int) r3.getHeight() + ")");
      +        g.setClip(r3);
      +        Rectangle r4 = g.getClipBounds();
      +        System.out.println("getClipBounds:(" + (int) r4.getX() + "," +
      +                (int) r4.getY() + "," + (int) r4.getWidth() + "," +
      +                (int) r4.getHeight() + ")");
      +
      +        if ((r4.getWidth() <= 0) || (r4.getHeight() <= 0)) {
      +            System.out.println("Test Passed");
      +        } else {
      +            throw new RuntimeException("IntersectionTest failed. " +
      +                    "Non-empty clip bounds.");
      +        }
      +    }
      +}
      
      From e0dabfb4bfd93a4407518177043d3dbc85c4bbd9 Mon Sep 17 00:00:00 2001
      From: Tejesh R 
      Date: Thu, 17 Oct 2024 06:38:23 +0000
      Subject: [PATCH 102/118] 8340279: Open source several AWT Dialog tests - Batch
       2
      
      Reviewed-by: abhiscxk, prr
      ---
       test/jdk/ProblemList.txt                      |   2 +
       .../DialogSystemMenu/DialogSystemMenu.java    | 122 ++++++++++++++
       .../awt/Dialog/DialogSystemMenu/icon24x24.gif | Bin 0 -> 108 bytes
       .../awt/Dialog/DialogSystemMenu/iconone.gif   | Bin 0 -> 109 bytes
       .../awt/Dialog/DialogSystemMenu/icontwo.gif   | Bin 0 -> 109 bytes
       .../java/awt/Dialog/FileDialogFilterTest.java |  68 ++++++++
       .../PrintToFileTest/PrintToFileFrame.java     |  40 +++++
       .../PrintToFileTest/PrintToFileGranted.java   |  70 ++++++++
       .../PrintToFileTest/PrintToFileRevoked.java   |  69 ++++++++
       .../java/awt/Dialog/PrintToFileTest/granted   |  10 ++
       .../java/awt/Dialog/PrintToFileTest/revoked   |   9 ++
       .../awt/Dialog/TopmostModalDialogTest.java    | 152 ++++++++++++++++++
       12 files changed, 542 insertions(+)
       create mode 100644 test/jdk/java/awt/Dialog/DialogSystemMenu/DialogSystemMenu.java
       create mode 100644 test/jdk/java/awt/Dialog/DialogSystemMenu/icon24x24.gif
       create mode 100644 test/jdk/java/awt/Dialog/DialogSystemMenu/iconone.gif
       create mode 100644 test/jdk/java/awt/Dialog/DialogSystemMenu/icontwo.gif
       create mode 100644 test/jdk/java/awt/Dialog/FileDialogFilterTest.java
       create mode 100644 test/jdk/java/awt/Dialog/PrintToFileTest/PrintToFileFrame.java
       create mode 100644 test/jdk/java/awt/Dialog/PrintToFileTest/PrintToFileGranted.java
       create mode 100644 test/jdk/java/awt/Dialog/PrintToFileTest/PrintToFileRevoked.java
       create mode 100644 test/jdk/java/awt/Dialog/PrintToFileTest/granted
       create mode 100644 test/jdk/java/awt/Dialog/PrintToFileTest/revoked
       create mode 100644 test/jdk/java/awt/Dialog/TopmostModalDialogTest.java
      
      diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt
      index 942e15002bdcb..8aa3fea3fdea1 100644
      --- a/test/jdk/ProblemList.txt
      +++ b/test/jdk/ProblemList.txt
      @@ -478,6 +478,8 @@ java/awt/KeyboardFocusmanager/ConsumeNextMnemonicKeyTypedTest/ConsumeNextMnemoni
       
       java/awt/Window/GetScreenLocation/GetScreenLocationTest.java 8225787 linux-x64
       java/awt/Dialog/MakeWindowAlwaysOnTop/MakeWindowAlwaysOnTop.java 8266243 macosx-aarch64
      +java/awt/Dialog/PrintToFileTest/PrintToFileRevoked.java 8029249 macosx-all
      +java/awt/Dialog/PrintToFileTest/PrintToFileGranted.java 8029249 macosx-all
       java/awt/Dialog/ChoiceModalDialogTest.java 8161475 macosx-all
       java/awt/Dialog/FileDialogUserFilterTest.java 8001142 generic-all
       
      diff --git a/test/jdk/java/awt/Dialog/DialogSystemMenu/DialogSystemMenu.java b/test/jdk/java/awt/Dialog/DialogSystemMenu/DialogSystemMenu.java
      new file mode 100644
      index 0000000000000..3f1639e90a41e
      --- /dev/null
      +++ b/test/jdk/java/awt/Dialog/DialogSystemMenu/DialogSystemMenu.java
      @@ -0,0 +1,122 @@
      +/*
      + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
      + * 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.Dialog;
      +import java.awt.Frame;
      +import java.awt.event.WindowListener;
      +import java.util.List;
      +
      +/*
      + * @test
      + * @bug 4058953 4094035
      + * @summary Test to verify system menu of a dialog on win32
      + * @requires (os.family == "windows")
      + * @library /java/awt/regtesthelpers
      + * @build PassFailJFrame
      + * @run main/manual DialogSystemMenu
      + */
      +
      +public class DialogSystemMenu {
      +    public static void main(String[] args) throws Exception {
      +        String INSTRUCTIONS = """
      +                1. Check the following on the first dialog window:
      +                    Right-clicking on the title bar
      +                    should bring up a system menu.
      +                    The system menu should not allow any
      +                    of the Maximize, Minimize and
      +                    Restore actions
      +
      +                2. The second dialog should be non-resizable
      +                    and have no application icon.
      +                """;
      +        PassFailJFrame.builder()
      +                .title("Test Instructions")
      +                .instructions(INSTRUCTIONS)
      +                .rows((int) INSTRUCTIONS.lines().count() + 2)
      +                .columns(35)
      +                .testUI(initialize())
      +                .build()
      +                .awaitAndCheck();
      +    }
      +
      +    public static List initialize() {
      +        Frame frame = new java.awt.Frame("Parent Frame");
      +        String txt = """
      +                This is a resizable dialog
      +                Right-clicking on the title bar
      +                should bring up a system menu
      +                The system menu should not
      +                allow any
      +                of the Maximize, Minimize and
      +                Restore actions
      +                """;
      +        String txt_non = """
      +                This is a non-resizable dialog
      +                It should be really non-resizable
      +                and have no application icon
      +                """;
      +        TestApp resizable = new TestApp(frame, "Test for 4058953", txt, true);
      +        resizable.setLocation(0, 0);
      +
      +        TestApp non_resizable = new TestApp(frame, "Test for 4094035", txt_non, false);
      +        non_resizable.setLocation(320, 0);
      +        return List.of(resizable, non_resizable);
      +    }
      +}
      +
      +
      +class TestApp extends Dialog implements WindowListener {
      +    public TestApp(java.awt.Frame parent, String title, String txt, boolean resize) {
      +        super(parent, title, false);
      +
      +        java.awt.TextArea ta = new java.awt.TextArea(txt);
      +        ta.setEditable(false);
      +        this.add(ta, "Center");
      +        this.addWindowListener(this);
      +        this.setSize(300, 200);
      +        this.setResizable(resize);
      +    }
      +
      +
      +    public void windowOpened(java.awt.event.WindowEvent myEvent) {
      +    }
      +
      +    public void windowClosed(java.awt.event.WindowEvent myEvent) {
      +    }
      +
      +    public void windowIconified(java.awt.event.WindowEvent myEvent) {
      +    }
      +
      +    public void windowDeiconified(java.awt.event.WindowEvent myEvent) {
      +    }
      +
      +    public void windowActivated(java.awt.event.WindowEvent myEvent) {
      +    }
      +
      +    public void windowDeactivated(java.awt.event.WindowEvent myEvent) {
      +    }
      +
      +    public void windowClosing(java.awt.event.WindowEvent myEvent) {
      +        this.dispose();
      +    }
      +}
      diff --git a/test/jdk/java/awt/Dialog/DialogSystemMenu/icon24x24.gif b/test/jdk/java/awt/Dialog/DialogSystemMenu/icon24x24.gif
      new file mode 100644
      index 0000000000000000000000000000000000000000..dfb9987339745f83f65005909bcd38c01ee8ce3c
      GIT binary patch
      literal 108
      zcmZ?wbh9u|lwgox_`tyM|Nnmm1_m7<2J$5s7?`|!`d4zk<$uVi80D$GH(Yvop@Kx-
      zqMJ4Tk{e&$+M07KO5f~O@xJAI^>>|Yvgdc7vG`@qR>gHYi&#~c#v2vSWeQY(dR%ID
      MNon_{oeT`t0M0-uUH||9
      
      literal 0
      HcmV?d00001
      
      diff --git a/test/jdk/java/awt/Dialog/DialogSystemMenu/iconone.gif b/test/jdk/java/awt/Dialog/DialogSystemMenu/iconone.gif
      new file mode 100644
      index 0000000000000000000000000000000000000000..698ba29d839e0d67621ecf3983a3e476cc0d9bab
      GIT binary patch
      literal 109
      zcmZ?wbhEHbRA5kG*vtR|4Pe{=rW$~}hK2(N4m310{0EBvXZR1MfHaT=1Uf)LpiTt_
      t1{NiQlb);hTD(5H`+tH)UrOe@j8*G$UhgZ=IbV`{zhd3{Ju-|8)&R|BDqsKr
      
      literal 0
      HcmV?d00001
      
      diff --git a/test/jdk/java/awt/Dialog/DialogSystemMenu/icontwo.gif b/test/jdk/java/awt/Dialog/DialogSystemMenu/icontwo.gif
      new file mode 100644
      index 0000000000000000000000000000000000000000..7f344ed1df07e4f9ee91f8cbcdc7b0050613f551
      GIT binary patch
      literal 109
      zcmZ?wbhEHbRA5kG*vtR|4Pe{=rW$~}hK2(N4m310{0EBvXZR1MfHaT=1Uf)LpiTt_
      t1{S4&6P~O0TD(5H`+tH)UrOe@j8*G$UhgZ=IbV`{zhd3{Ju-|8)&SANDt`a~
      
      literal 0
      HcmV?d00001
      
      diff --git a/test/jdk/java/awt/Dialog/FileDialogFilterTest.java b/test/jdk/java/awt/Dialog/FileDialogFilterTest.java
      new file mode 100644
      index 0000000000000..e30d8ea58a2d6
      --- /dev/null
      +++ b/test/jdk/java/awt/Dialog/FileDialogFilterTest.java
      @@ -0,0 +1,68 @@
      +/*
      + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved.
      + * 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.FileDialog;
      +import java.awt.Frame;
      +import java.io.File;
      +import java.io.FilenameFilter;
      +
      +/*
      + * @test
      + * @bug 4364256
      + * @summary Test to File Dialog filter
      + * @requires (os.family == "windows")
      + * @library /java/awt/regtesthelpers
      + * @build PassFailJFrame
      + * @run main/manual FileDialogFilterTest
      + */
      +
      +public class FileDialogFilterTest {
      +    public static void main(String[] args) throws Exception {
      +        String INSTRUCTIONS = """
      +                   Run the test, make sure a file dialog
      +                   comes up with no crash. If the file dialog
      +                   comes up successfully then press PASS, else FAIL.
      +                """;
      +        PassFailJFrame.builder()
      +                .title("Test Instructions")
      +                .instructions(INSTRUCTIONS)
      +                .rows((int) INSTRUCTIONS.lines().count() + 2)
      +                .columns(35)
      +                .testUI(initialize())
      +                .build()
      +                .awaitAndCheck();
      +    }
      +
      +    public static FileDialog initialize() {
      +        FileDialog fDlg = new FileDialog(new Frame());
      +        fDlg.addNotify();
      +        fDlg.setFilenameFilter(new MyFilter());
      +        return fDlg;
      +    }
      +}
      +
      +class MyFilter implements FilenameFilter {
      +    public boolean accept(File dir, String name) {
      +        return true;
      +    }
      +}
      diff --git a/test/jdk/java/awt/Dialog/PrintToFileTest/PrintToFileFrame.java b/test/jdk/java/awt/Dialog/PrintToFileTest/PrintToFileFrame.java
      new file mode 100644
      index 0000000000000..a117622d57003
      --- /dev/null
      +++ b/test/jdk/java/awt/Dialog/PrintToFileTest/PrintToFileFrame.java
      @@ -0,0 +1,40 @@
      +import java.awt.Button;
      +import java.awt.FlowLayout;
      +import java.awt.Frame;
      +import java.awt.PrintJob;
      +import java.awt.event.ActionEvent;
      +import java.awt.event.ActionListener;
      +
      +class PrintToFileFrame extends Frame implements ActionListener {
      +    Button nativeDlg = new Button("Show print dialog");
      +
      +    public PrintToFileFrame() {
      +        this.setLayout(new FlowLayout());
      +        add(nativeDlg);
      +        nativeDlg.addActionListener(this);
      +
      +        setSize(300, 300);
      +    }
      +
      +    @SuppressWarnings("removal")
      +    public void actionPerformed(ActionEvent ae) {
      +        if (System.getSecurityManager() == null) {
      +            throw new RuntimeException("Security manager isn't installed.");
      +        }
      +
      +        try {
      +            System.getSecurityManager().checkPrintJobAccess();
      +            System.out.println("checkPrintJobAccess - OK");
      +        } catch (SecurityException e) {
      +            System.out.println("checkPrintJobAccess - ERROR " + e);
      +        }
      +
      +        PrintJob printJob = getToolkit().getPrintJob(this, null, null);
      +
      +        if (printJob != null) {
      +            System.out.println("Print Job: " + printJob);
      +        } else {
      +            System.out.println("Print Job is null.");
      +        }
      +    }
      +}
      diff --git a/test/jdk/java/awt/Dialog/PrintToFileTest/PrintToFileGranted.java b/test/jdk/java/awt/Dialog/PrintToFileTest/PrintToFileGranted.java
      new file mode 100644
      index 0000000000000..05d73123d983a
      --- /dev/null
      +++ b/test/jdk/java/awt/Dialog/PrintToFileTest/PrintToFileGranted.java
      @@ -0,0 +1,70 @@
      +/*
      + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved.
      + * 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.print.PrinterJob;
      +
      +/*
      + * @test
      + * @bug 6275359
      + * @summary Test to verify system menu of a dialog on win32
      + * @requires (os.family == "windows")
      + * @library /java/awt/regtesthelpers
      + * @build PassFailJFrame
      + * @compile PrintToFileFrame.java
      + * @compile PrintToFileGranted.java
      + * @run main/manual/policy=granted/othervm PrintToFileGranted
      + */
      +
      +public class PrintToFileGranted {
      +    public static void main(String[] args) throws Exception {
      +        String INSTRUCTIONS;
      +        if (isPrintSupport()) {
      +            INSTRUCTIONS = """
      +                    1. Click on 'Show file dialog' button A print dialog will come up
      +                    2. If checkbox 'Print to file' is enabled then the test passed
      +                       else the test failed
      +                    3. Close the print dialog before pressing PASS or FAIL buttons
      +                    """;
      +        } else {
      +            INSTRUCTIONS = """
      +                    1. The test requires printer installed in your system,
      +                       but there is no printers found
      +                       Please install one and re-run the test
      +                    """;
      +        }
      +
      +        PassFailJFrame.builder()
      +                .title("Test Instructions")
      +                .instructions(INSTRUCTIONS)
      +                .rows((int) INSTRUCTIONS.lines().count() + 2)
      +                .columns(35)
      +                .testUI(new PrintToFileFrame())
      +                .build()
      +                .awaitAndCheck();
      +    }
      +
      +    public static boolean isPrintSupport() {
      +        PrinterJob pj = PrinterJob.getPrinterJob();
      +        return pj.getPrintService() != null;
      +    }
      +}
      diff --git a/test/jdk/java/awt/Dialog/PrintToFileTest/PrintToFileRevoked.java b/test/jdk/java/awt/Dialog/PrintToFileTest/PrintToFileRevoked.java
      new file mode 100644
      index 0000000000000..7c724e97bed53
      --- /dev/null
      +++ b/test/jdk/java/awt/Dialog/PrintToFileTest/PrintToFileRevoked.java
      @@ -0,0 +1,69 @@
      +/*
      + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved.
      + * 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.print.PrinterJob;
      +
      +/*
      + * @test
      + * @bug 6275359
      + * @summary Test to verify Printing ignores Security permissions
      + *          using native dialog
      + * @requires (os.family == "windows")
      + * @library /java/awt/regtesthelpers
      + * @build PassFailJFrame
      + * @compile PrintToFileRevoked.java
      + * @run main/manual/policy=revoked/othervm PrintToFileRevoked
      + */
      +
      +public class PrintToFileRevoked {
      +    public static void main(String[] args) throws Exception {
      +        String INSTRUCTIONS;
      +        if (isPrintSupport()) {
      +            INSTRUCTIONS = """
      +                    1. Click on 'Show file dialog' button A print dialog will come up
      +                    2. If checkbox 'Print to file' is disabled then the test passed
      +                       else the test failed
      +                    3. Close the print dialog before pressing PASS or FAIL buttons
      +                    """;
      +        } else {
      +            INSTRUCTIONS = """
      +                    1. The test requires printer installed in your system,
      +                       but there is no printers found
      +                       Please install one and re-run the test
      +                    """;
      +        }
      +        PassFailJFrame.builder()
      +                .title("Test Instructions")
      +                .instructions(INSTRUCTIONS)
      +                .rows((int) INSTRUCTIONS.lines().count() + 2)
      +                .columns(35)
      +                .testUI(new PrintToFileFrame())
      +                .build()
      +                .awaitAndCheck();
      +    }
      +
      +    public static boolean isPrintSupport() {
      +        PrinterJob pj = PrinterJob.getPrinterJob();
      +        return pj.getPrintService() != null;
      +    }
      +}
      diff --git a/test/jdk/java/awt/Dialog/PrintToFileTest/granted b/test/jdk/java/awt/Dialog/PrintToFileTest/granted
      new file mode 100644
      index 0000000000000..e73b0fdf3cdef
      --- /dev/null
      +++ b/test/jdk/java/awt/Dialog/PrintToFileTest/granted
      @@ -0,0 +1,10 @@
      +/* AUTOMATICALLY GENERATED ON Thu Jan 03 15:48:39 PST 2002*/
      +/* DO NOT EDIT */
      +
      +grant {
      + permission java.lang.RuntimePermission "queuePrintJob";
      + permission java.util.PropertyPermission "*", "read";
      + permission java.io.FilePermission "<>", "read";
      + permission java.io.FilePermission "<>", "write";
      + permission java.lang.RuntimePermission "accessClassInPackage.sun.util.locale.provider";
      +};
      diff --git a/test/jdk/java/awt/Dialog/PrintToFileTest/revoked b/test/jdk/java/awt/Dialog/PrintToFileTest/revoked
      new file mode 100644
      index 0000000000000..d2545e15e1155
      --- /dev/null
      +++ b/test/jdk/java/awt/Dialog/PrintToFileTest/revoked
      @@ -0,0 +1,9 @@
      +/* AUTOMATICALLY GENERATED ON Thu Jan 03 15:48:39 PST 2002*/
      +/* DO NOT EDIT */
      +
      +grant {
      + permission java.lang.RuntimePermission "queuePrintJob";
      + permission java.util.PropertyPermission "*", "read";
      + permission java.lang.RuntimePermission "accessClassInPackage.sun.util.locale.provider";
      +};
      +
      diff --git a/test/jdk/java/awt/Dialog/TopmostModalDialogTest.java b/test/jdk/java/awt/Dialog/TopmostModalDialogTest.java
      new file mode 100644
      index 0000000000000..7b91d47e248c4
      --- /dev/null
      +++ b/test/jdk/java/awt/Dialog/TopmostModalDialogTest.java
      @@ -0,0 +1,152 @@
      +/*
      + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
      + * 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.Button;
      +import java.awt.Dialog;
      +import java.awt.Frame;
      +import java.awt.GridLayout;
      +import java.awt.Window;
      +import java.awt.event.ActionEvent;
      +import java.awt.event.ActionListener;
      +import java.awt.event.WindowAdapter;
      +import java.awt.event.WindowEvent;
      +
      +/*
      + * @test
      + * @bug 4940645
      + * @summary Test to verify setAlwaysOnTop(true) does
      + *          work in modal dialog in Windows
      + * @requires (os.family == "windows" | os.family == "linux" )
      + * @library /java/awt/regtesthelpers
      + * @build PassFailJFrame
      + * @run main/manual TopmostModalDialogTest
      + */
      +
      +public class TopmostModalDialogTest {
      +    public static void main(String[] args) throws Exception {
      +        String INSTRUCTIONS = """
      +                (This test verifies that modal dialog can be made always on top
      +                This test should only be run on the platforms which support always-on-top windows
      +                Such platforms are: Windows, Linux with GNOME2/Metacity window manager,
      +                Solaris with GNOME2/Metacity window manager
      +                If you are not running on any of these platforms, please select 'Pass' to skip testing
      +                If you are unsure on which platform you are running please select 'Pass')
      +
      +                1. After test started you see a frame with \\"Main Frame\\" title
      +                   It contains three buttons. Every button starts one of test stage
      +                   You should test all three stages
      +                2. After you press button to start the stage. It shows modal dialog
      +                   This modal dialog should be always-on-top window
      +                3. Since it's a modal the only way to test this is try to cover it
      +                   using some native window
      +                4. If you will able to cover it be native window - test FAILS, otherwise - PASS
      +
      +                Note: in stages #2 and #3 dialog is initially shown as regular modal dialogs
      +                You will see \\"Let's wait\\" message in the message area below
      +                Please wait until message \\"Let's make it topmost\\" will be printed in the area
      +                After that you can continue testing.
      +                """;
      +        PassFailJFrame.builder()
      +                .title("Test Instructions")
      +                .instructions(INSTRUCTIONS)
      +                .rows((int) INSTRUCTIONS.lines().count() + 2)
      +                .columns(35)
      +                .testUI(initialize())
      +                .logArea(8)
      +                .build()
      +                .awaitAndCheck();
      +    }
      +
      +    public static Frame initialize() {
      +        final Tester tester = new Tester();
      +        Frame frame = new Frame("Main Frame");
      +        frame.setLayout(new GridLayout(3, 1));
      +        for (int i = 0; i < 3; i++) {
      +            Button btn = new Button("Stage #" + i);
      +            frame.add(btn);
      +            btn.addActionListener(tester);
      +        }
      +        frame.pack();
      +        return frame;
      +    }
      +}
      +
      +class Tester implements ActionListener {
      +    public void actionPerformed(ActionEvent e) {
      +        String command = e.getActionCommand();
      +        PassFailJFrame.log(command);
      +        int cmd = Integer.parseInt(command.substring(command.length() - 1));
      +        PassFailJFrame.log("" + cmd);
      +        Dialog dlg = new Dialog(new Frame(""), "Modal Dialog", true);
      +        dlg.setBounds(100, 100, 100, 100);
      +        dlg.addWindowListener(new WindowAdapter() {
      +            public void windowClosing(WindowEvent we) {
      +                Window self = we.getWindow();
      +                Window owner = self.getOwner();
      +                if (owner != null) {
      +                    owner.dispose();
      +                } else {
      +                    self.dispose();
      +                }
      +            }
      +        });
      +
      +        switch (cmd) {
      +            case 0:
      +                dlg.setAlwaysOnTop(true);
      +                dlg.setVisible(true);
      +                break;
      +            case 1:
      +                (new Thread(new TopmostMaker(dlg))).start();
      +                dlg.setVisible(true);
      +                break;
      +            case 2:
      +                dlg.setFocusableWindowState(false);
      +                (new Thread(new TopmostMaker(dlg))).start();
      +                dlg.setVisible(true);
      +                break;
      +            default:
      +                PassFailJFrame.log("Unsupported operation :(");
      +        }
      +    }
      +}
      +
      +class TopmostMaker implements Runnable {
      +    final Window wnd;
      +
      +    public TopmostMaker(Window wnd) {
      +        this.wnd = wnd;
      +    }
      +
      +    public void run() {
      +        PassFailJFrame.log("Let's wait");
      +        try {
      +            Thread.sleep(1000);
      +        } catch (InterruptedException ie) {
      +            PassFailJFrame.log("Test was interrupted. " + ie);
      +            ie.printStackTrace();
      +        }
      +        PassFailJFrame.log("Let's make it topmost");
      +        wnd.setAlwaysOnTop(true);
      +    }
      +}
      
      From fa39e84d64d79f6c66f98110e98d2562f35681e1 Mon Sep 17 00:00:00 2001
      From: Richard Reingruber 
      Date: Thu, 17 Oct 2024 07:19:54 +0000
      Subject: [PATCH 103/118] 8342042: PPC64: compiler_fast_unlock_object flags
       failure instead of success
      
      Reviewed-by: mdoerr, aboldtch, fbredberg
      ---
       src/hotspot/cpu/ppc/macroAssembler_ppc.cpp | 20 ++++++++------------
       1 file changed, 8 insertions(+), 12 deletions(-)
      
      diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp
      index a194c030a6124..0d7e202779fd2 100644
      --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp
      +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp
      @@ -2739,14 +2739,14 @@ void MacroAssembler::compiler_fast_unlock_object(ConditionRegister flag, Registe
         // Check if there is a successor.
         ld(temp, in_bytes(ObjectMonitor::succ_offset()), current_header);
         cmpdi(flag, temp, 0);
      -  bne(flag, success);  // If so we are done.
      +  // Invert equal bit
      +  crnand(flag, Assembler::equal, flag, Assembler::equal);
      +  beq(flag, success);  // If there is a successor we are done.
       
         // Save the monitor pointer in the current thread, so we can try
         // to reacquire the lock in SharedRuntime::monitor_exit_helper().
         std(current_header, in_bytes(JavaThread::unlocked_inflated_monitor_offset()), R16_thread);
      -
      -  crxor(flag, Assembler::equal, flag, Assembler::equal); // Set flag = NE => slow path
      -  b(failure);
      +  b(failure); // flag == NE
       
         // flag == EQ indicates success, decrement held monitor count
         // flag == NE indicates failure
      @@ -3053,7 +3053,6 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(ConditionRegister f
       
           bind(not_recursive);
       
      -    Label set_eq_unlocked;
           const Register t2 = tmp2;
       
           // Set owner to null.
      @@ -3075,17 +3074,14 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(ConditionRegister f
           // Check if there is a successor.
           ld(t, in_bytes(ObjectMonitor::succ_offset()), monitor);
           cmpdi(CCR0, t, 0);
      -    bne(CCR0, set_eq_unlocked); // If so we are done.
      +    // Invert equal bit
      +    crnand(flag, Assembler::equal, flag, Assembler::equal);
      +    beq(CCR0, unlocked); // If there is a successor we are done.
       
           // Save the monitor pointer in the current thread, so we can try
           // to reacquire the lock in SharedRuntime::monitor_exit_helper().
           std(monitor, in_bytes(JavaThread::unlocked_inflated_monitor_offset()), R16_thread);
      -
      -    crxor(CCR0, Assembler::equal, CCR0, Assembler::equal); // Set flag = NE => slow path
      -    b(slow_path);
      -
      -    bind(set_eq_unlocked);
      -    crorc(CCR0, Assembler::equal, CCR0, Assembler::equal); // Set flag = EQ => fast path
      +    b(slow_path); // flag == NE
         }
       
         bind(unlocked);
      
      From f9208fadde8141e18a025ddb6ce28423861ba391 Mon Sep 17 00:00:00 2001
      From: Richard Reingruber 
      Date: Thu, 17 Oct 2024 07:21:42 +0000
      Subject: [PATCH 104/118] 8341715: PPC64: ObjectMonitor::_owner should be reset
       unconditionally in nmethod unlocking
      
      Reviewed-by: mdoerr, lucy
      ---
       src/hotspot/cpu/ppc/macroAssembler_ppc.cpp | 33 +++++++++++++++++-----
       1 file changed, 26 insertions(+), 7 deletions(-)
      
      diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp
      index 0d7e202779fd2..f036caa0675d2 100644
      --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp
      +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp
      @@ -2651,7 +2651,19 @@ void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register
         // flag == NE indicates failure
         bind(success);
         inc_held_monitor_count(temp);
      +#ifdef ASSERT
      +  // Check that unlocked label is reached with flag == EQ.
      +  Label flag_correct;
      +  beq(flag, flag_correct);
      +  stop("compiler_fast_lock_object: Flag != EQ");
      +#endif
         bind(failure);
      +#ifdef ASSERT
      +  // Check that slow_path label is reached with flag == NE.
      +  bne(flag, flag_correct);
      +  stop("compiler_fast_lock_object: Flag != NE");
      +  bind(flag_correct);
      +#endif
       }
       
       void MacroAssembler::compiler_fast_unlock_object(ConditionRegister flag, Register oop, Register box,
      @@ -2701,17 +2713,12 @@ void MacroAssembler::compiler_fast_unlock_object(ConditionRegister flag, Registe
         bind(object_has_monitor);
         STATIC_ASSERT(markWord::monitor_value <= INT_MAX);
         addi(current_header, current_header, -(int)markWord::monitor_value); // monitor
      -  ld(temp,             in_bytes(ObjectMonitor::owner_offset()), current_header);
      -
      -  // In case of LM_LIGHTWEIGHT, we may reach here with (temp & ObjectMonitor::ANONYMOUS_OWNER) != 0.
      -  // This is handled like owner thread mismatches: We take the slow path.
      -  cmpd(flag, temp, R16_thread);
      -  bne(flag, failure);
       
         ld(displaced_header, in_bytes(ObjectMonitor::recursions_offset()), current_header);
      -
         addic_(displaced_header, displaced_header, -1);
         blt(CCR0, notRecursive); // Not recursive if negative after decrement.
      +
      +  // Recursive unlock
         std(displaced_header, in_bytes(ObjectMonitor::recursions_offset()), current_header);
         if (flag == CCR0) { // Otherwise, flag is already EQ, here.
           crorc(CCR0, Assembler::equal, CCR0, Assembler::equal); // Set CCR0 EQ
      @@ -2752,7 +2759,19 @@ void MacroAssembler::compiler_fast_unlock_object(ConditionRegister flag, Registe
         // flag == NE indicates failure
         bind(success);
         dec_held_monitor_count(temp);
      +#ifdef ASSERT
      +  // Check that unlocked label is reached with flag == EQ.
      +  Label flag_correct;
      +  beq(flag, flag_correct);
      +  stop("compiler_fast_unlock_object: Flag != EQ");
      +#endif
         bind(failure);
      +#ifdef ASSERT
      +  // Check that slow_path label is reached with flag == NE.
      +  bne(flag, flag_correct);
      +  stop("compiler_fast_unlock_object: Flag != NE");
      +  bind(flag_correct);
      +#endif
       }
       
       void MacroAssembler::compiler_fast_lock_lightweight_object(ConditionRegister flag, Register obj, Register box,
      
      From 8862ca076f9be1c0b5f4bc2639ab9c1f60de308c Mon Sep 17 00:00:00 2001
      From: Kevin Walls 
      Date: Thu, 17 Oct 2024 08:01:14 +0000
      Subject: [PATCH 105/118] 8342338: Remove redundant IIOPURLTest.java
      
      Reviewed-by: cjplummer, amenkov
      ---
       .../mandatory/connection/IIOPURLTest.java     | 79 -------------------
       1 file changed, 79 deletions(-)
       delete mode 100644 test/jdk/javax/management/remote/mandatory/connection/IIOPURLTest.java
      
      diff --git a/test/jdk/javax/management/remote/mandatory/connection/IIOPURLTest.java b/test/jdk/javax/management/remote/mandatory/connection/IIOPURLTest.java
      deleted file mode 100644
      index cdbf829a9b22e..0000000000000
      --- a/test/jdk/javax/management/remote/mandatory/connection/IIOPURLTest.java
      +++ /dev/null
      @@ -1,79 +0,0 @@
      -/*
      - * Copyright (c) 2003, 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.
      - */
      -
      -/*
      - * @test
      - * @bug 4886799
      - * @summary Check that IIOP URLs have /ior/ in the path
      - * @author Eamonn McManus
      - *
      - * @run clean IIOPURLTest
      - * @run build IIOPURLTest
      - * @run main IIOPURLTest
      - */
      -
      -import javax.management.MBeanServer;
      -import javax.management.MBeanServerConnection;
      -import javax.management.MBeanServerFactory;
      -import javax.management.Notification;
      -import javax.management.NotificationListener;
      -import javax.management.ObjectName;
      -
      -import javax.management.remote.JMXConnector;
      -import javax.management.remote.JMXConnectorFactory;
      -import javax.management.remote.JMXConnectorServer;
      -import javax.management.remote.JMXConnectorServerFactory;
      -import javax.management.remote.JMXServiceURL;
      -
      -public class IIOPURLTest {
      -
      -    public static void main(String[] args) throws Exception {
      -        JMXServiceURL inputAddr =
      -            new JMXServiceURL("service:jmx:iiop://");
      -        JMXConnectorServer s;
      -        try {
      -            s = JMXConnectorServerFactory.newJMXConnectorServer(inputAddr, null, null);
      -        } catch (java.net.MalformedURLException x) {
      -            try {
      -                Class.forName("javax.management.remote.rmi._RMIConnectionImpl_Tie");
      -                throw new RuntimeException("MalformedURLException thrown but iiop appears to be supported");
      -            } catch (ClassNotFoundException expected) { }
      -            System.out.println("IIOP protocol not supported, test skipped");
      -            return;
      -        }
      -        MBeanServer mbs = MBeanServerFactory.createMBeanServer();
      -        mbs.registerMBean(s, new ObjectName("a:b=c"));
      -        s.start();
      -        JMXServiceURL outputAddr = s.getAddress();
      -        if (!outputAddr.getURLPath().startsWith("/ior/IOR:")) {
      -            throw new RuntimeException("URL path should start with \"/ior/IOR:\": " +
      -                                       outputAddr);
      -        }
      -        System.out.println("IIOP URL path looks OK: " + outputAddr);
      -        JMXConnector c = JMXConnectorFactory.connect(outputAddr);
      -        System.out.println("Successfully got default domain: " +
      -                           c.getMBeanServerConnection().getDefaultDomain());
      -        c.close();
      -        s.stop();
      -    }
      -}
      
      From 7a64fbbb9292f4d65a6970206dec1a7d7645046b Mon Sep 17 00:00:00 2001
      From: Simon Tooke 
      Date: Thu, 17 Oct 2024 08:06:37 +0000
      Subject: [PATCH 106/118] 8338851: Hoist os::Posix::realpath() to
       os::realpath() and implement on Windows
      
      Reviewed-by: dholmes, stuefe, jwaters
      ---
       src/hotspot/os/aix/os_aix.cpp                 |  6 +-
       src/hotspot/os/bsd/os_bsd.cpp                 |  6 +-
       src/hotspot/os/linux/os_linux.cpp             |  6 +-
       src/hotspot/os/linux/os_perf_linux.cpp        |  2 +-
       src/hotspot/os/posix/os_posix.cpp             |  5 +-
       src/hotspot/os/posix/os_posix.hpp             |  7 --
       src/hotspot/os/windows/os_windows.cpp         | 22 +++++
       src/hotspot/share/runtime/os.hpp              |  7 ++
       .../share/services/diagnosticCommand.cpp      |  4 +-
       .../share/utilities/globalDefinitions.hpp     |  2 +-
       test/hotspot/gtest/runtime/test_os.cpp        | 80 +++++++++++++++++++
       11 files changed, 123 insertions(+), 24 deletions(-)
      
      diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp
      index 63aa53f0a2350..5022272d1b431 100644
      --- a/src/hotspot/os/aix/os_aix.cpp
      +++ b/src/hotspot/os/aix/os_aix.cpp
      @@ -1293,7 +1293,7 @@ void os::jvm_path(char *buf, jint buflen) {
         Dl_info dlinfo;
         int ret = dladdr(CAST_FROM_FN_PTR(void *, os::jvm_path), &dlinfo);
         assert(ret != 0, "cannot locate libjvm");
      -  char* rp = os::Posix::realpath((char *)dlinfo.dli_fname, buf, buflen);
      +  char* rp = os::realpath((char *)dlinfo.dli_fname, buf, buflen);
         assert(rp != nullptr, "error in realpath(): maybe the 'path' argument is too long?");
       
         if (Arguments::sun_java_launcher_is_altjvm()) {
      @@ -1324,7 +1324,7 @@ void os::jvm_path(char *buf, jint buflen) {
               }
               assert(strstr(p, "/libjvm") == p, "invalid library name");
       
      -        rp = os::Posix::realpath(java_home_var, buf, buflen);
      +        rp = os::realpath(java_home_var, buf, buflen);
               if (rp == nullptr) {
                 return;
               }
      @@ -1345,7 +1345,7 @@ void os::jvm_path(char *buf, jint buflen) {
                 snprintf(buf + len, buflen-len, "/hotspot/libjvm.so");
               } else {
                 // Go back to path of .so
      -          rp = os::Posix::realpath((char *)dlinfo.dli_fname, buf, buflen);
      +          rp = os::realpath((char *)dlinfo.dli_fname, buf, buflen);
                 if (rp == nullptr) {
                   return;
                 }
      diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp
      index 18818268c1f9a..6b3bf060d6f27 100644
      --- a/src/hotspot/os/bsd/os_bsd.cpp
      +++ b/src/hotspot/os/bsd/os_bsd.cpp
      @@ -1509,7 +1509,7 @@ void os::jvm_path(char *buf, jint buflen) {
         assert(ret, "cannot locate libjvm");
         char *rp = nullptr;
         if (ret && dli_fname[0] != '\0') {
      -    rp = os::Posix::realpath(dli_fname, buf, buflen);
      +    rp = os::realpath(dli_fname, buf, buflen);
         }
         if (rp == nullptr) {
           return;
      @@ -1541,7 +1541,7 @@ void os::jvm_path(char *buf, jint buflen) {
               p = strrchr(buf, '/');
               assert(strstr(p, "/libjvm") == p, "invalid library name");
       
      -        rp = os::Posix::realpath(java_home_var, buf, buflen);
      +        rp = os::realpath(java_home_var, buf, buflen);
               if (rp == nullptr) {
                 return;
               }
      @@ -1575,7 +1575,7 @@ void os::jvm_path(char *buf, jint buflen) {
                 snprintf(buf + len, buflen-len, "/libjvm%s", JNI_LIB_SUFFIX);
               } else {
                 // Fall back to path of current library
      -          rp = os::Posix::realpath(dli_fname, buf, buflen);
      +          rp = os::realpath(dli_fname, buf, buflen);
                 if (rp == nullptr) {
                   return;
                 }
      diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp
      index c80663fec3d3a..514268a7400bc 100644
      --- a/src/hotspot/os/linux/os_linux.cpp
      +++ b/src/hotspot/os/linux/os_linux.cpp
      @@ -2763,7 +2763,7 @@ void os::jvm_path(char *buf, jint buflen) {
         assert(ret, "cannot locate libjvm");
         char *rp = nullptr;
         if (ret && dli_fname[0] != '\0') {
      -    rp = os::Posix::realpath(dli_fname, buf, buflen);
      +    rp = os::realpath(dli_fname, buf, buflen);
         }
         if (rp == nullptr) {
           return;
      @@ -2797,7 +2797,7 @@ void os::jvm_path(char *buf, jint buflen) {
               }
               assert(strstr(p, "/libjvm") == p, "invalid library name");
       
      -        rp = os::Posix::realpath(java_home_var, buf, buflen);
      +        rp = os::realpath(java_home_var, buf, buflen);
               if (rp == nullptr) {
                 return;
               }
      @@ -2818,7 +2818,7 @@ void os::jvm_path(char *buf, jint buflen) {
                 snprintf(buf + len, buflen-len, "/hotspot/libjvm.so");
               } else {
                 // Go back to path of .so
      -          rp = os::Posix::realpath(dli_fname, buf, buflen);
      +          rp = os::realpath(dli_fname, buf, buflen);
                 if (rp == nullptr) {
                   return;
                 }
      diff --git a/src/hotspot/os/linux/os_perf_linux.cpp b/src/hotspot/os/linux/os_perf_linux.cpp
      index a31a58e55af93..996f83611b048 100644
      --- a/src/hotspot/os/linux/os_perf_linux.cpp
      +++ b/src/hotspot/os/linux/os_perf_linux.cpp
      @@ -789,7 +789,7 @@ char* SystemProcessInterface::SystemProcesses::ProcessIterator::get_exe_path() {
       
         jio_snprintf(buffer, PATH_MAX, "/proc/%s/exe", _entry->d_name);
         buffer[PATH_MAX - 1] = '\0';
      -  return os::Posix::realpath(buffer, _exePath, PATH_MAX);
      +  return os::realpath(buffer, _exePath, PATH_MAX);
       }
       
       char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const {
      diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp
      index 78fd2a678886e..75253843593c6 100644
      --- a/src/hotspot/os/posix/os_posix.cpp
      +++ b/src/hotspot/os/posix/os_posix.cpp
      @@ -1029,10 +1029,10 @@ char* os::Posix::describe_pthread_attr(char* buf, size_t buflen, const pthread_a
         return buf;
       }
       
      -char* os::Posix::realpath(const char* filename, char* outbuf, size_t outbuflen) {
      +char* os::realpath(const char* filename, char* outbuf, size_t outbuflen) {
       
         if (filename == nullptr || outbuf == nullptr || outbuflen < 1) {
      -    assert(false, "os::Posix::realpath: invalid arguments.");
      +    assert(false, "os::realpath: invalid arguments.");
           errno = EINVAL;
           return nullptr;
         }
      @@ -1067,7 +1067,6 @@ char* os::Posix::realpath(const char* filename, char* outbuf, size_t outbuflen)
           }
         }
         return result;
      -
       }
       
       int os::stat(const char *path, struct stat *sbuf) {
      diff --git a/src/hotspot/os/posix/os_posix.hpp b/src/hotspot/os/posix/os_posix.hpp
      index d872a6dae899e..cac5b250cdfa0 100644
      --- a/src/hotspot/os/posix/os_posix.hpp
      +++ b/src/hotspot/os/posix/os_posix.hpp
      @@ -73,13 +73,6 @@ class os::Posix {
         // to buf with len buflen; buf is returned.
         static char* describe_pthread_attr(char* buf, size_t buflen, const pthread_attr_t* attr);
       
      -  // A safe implementation of realpath which will not cause a buffer overflow if the resolved path
      -  //   is longer than PATH_MAX.
      -  // On success, returns 'outbuf', which now contains the path.
      -  // On error, it will return null and set errno. The content of 'outbuf' is undefined.
      -  // On truncation error ('outbuf' too small), it will return null and set errno to ENAMETOOLONG.
      -  static char* realpath(const char* filename, char* outbuf, size_t outbuflen);
      -
         // Returns true if given uid is root.
         static bool is_root(uid_t uid);
       
      diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp
      index fe093aee116b6..66a6a92f5e078 100644
      --- a/src/hotspot/os/windows/os_windows.cpp
      +++ b/src/hotspot/os/windows/os_windows.cpp
      @@ -5397,6 +5397,28 @@ void os::funlockfile(FILE* fp) {
         _unlock_file(fp);
       }
       
      +char* os::realpath(const char* filename, char* outbuf, size_t outbuflen) {
      +
      +  if (filename == nullptr || outbuf == nullptr || outbuflen < 1) {
      +    assert(false, "os::realpath: invalid arguments.");
      +    errno = EINVAL;
      +    return nullptr;
      +  }
      +
      +  char* result = nullptr;
      +  ALLOW_C_FUNCTION(::_fullpath, char* p = ::_fullpath(nullptr, filename, 0);)
      +  if (p != nullptr) {
      +    if (strlen(p) < outbuflen) {
      +      strcpy(outbuf, p);
      +      result = outbuf;
      +    } else {
      +      errno = ENAMETOOLONG;
      +    }
      +    ALLOW_C_FUNCTION(::free, ::free(p);) // *not* os::free
      +  }
      +  return result;
      +}
      +
       // Map a block of memory.
       char* os::pd_map_memory(int fd, const char* file_name, size_t file_offset,
                               char *addr, size_t bytes, bool read_only,
      diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp
      index 65071769bc4cb..323b8d2df8dbe 100644
      --- a/src/hotspot/share/runtime/os.hpp
      +++ b/src/hotspot/share/runtime/os.hpp
      @@ -668,6 +668,13 @@ class os: AllStatic {
         static void flockfile(FILE* fp);
         static void funlockfile(FILE* fp);
       
      +  // A safe implementation of realpath which will not cause a buffer overflow if the resolved path
      +  // is longer than PATH_MAX.
      +  // On success, returns 'outbuf', which now contains the path.
      +  // On error, it will return null and set errno. The content of 'outbuf' is undefined.
      +  // On truncation error ('outbuf' too small), it will return null and set errno to ENAMETOOLONG.
      +  static char* realpath(const char* filename, char* outbuf, size_t outbuflen);
      +
         static int compare_file_modified_times(const char* file1, const char* file2);
       
         static bool same_files(const char* file1, const char* file2);
      diff --git a/src/hotspot/share/services/diagnosticCommand.cpp b/src/hotspot/share/services/diagnosticCommand.cpp
      index 78c655a43fcf2..4263d2a1d4b56 100644
      --- a/src/hotspot/share/services/diagnosticCommand.cpp
      +++ b/src/hotspot/share/services/diagnosticCommand.cpp
      @@ -1202,12 +1202,10 @@ void SystemDumpMapDCmd::execute(DCmdSource source, TRAPS) {
             output()->print_cr("(NMT is disabled, will not annotate mappings).");
           }
           MemMapPrinter::print_all_mappings(&fs);
      -#ifndef _WIN64
           // For the readers convenience, resolve path name.
           char tmp[JVM_MAXPATHLEN];
      -    const char* absname = os::Posix::realpath(name, tmp, sizeof(tmp));
      +    const char* absname = os::realpath(name, tmp, sizeof(tmp));
           name = absname != nullptr ? absname : name;
      -#endif
           output()->print_cr("Memory map dumped to \"%s\".", name);
         } else {
           output()->print_cr("Failed to open \"%s\" for writing (%s).", name, os::strerror(errno));
      diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp
      index 6d385165b8b1b..25af626c6286b 100644
      --- a/src/hotspot/share/utilities/globalDefinitions.hpp
      +++ b/src/hotspot/share/utilities/globalDefinitions.hpp
      @@ -210,7 +210,7 @@ FORBID_C_FUNCTION(char* strdup(const char *s), "use os::strdup");
       FORBID_C_FUNCTION(char* strndup(const char *s, size_t n), "don't use");
       FORBID_C_FUNCTION(int posix_memalign(void **memptr, size_t alignment, size_t size), "don't use");
       FORBID_C_FUNCTION(void* aligned_alloc(size_t alignment, size_t size), "don't use");
      -FORBID_C_FUNCTION(char* realpath(const char* path, char* resolved_path), "use os::Posix::realpath");
      +FORBID_C_FUNCTION(char* realpath(const char* path, char* resolved_path), "use os::realpath");
       FORBID_C_FUNCTION(char* get_current_dir_name(void), "use os::get_current_directory()");
       FORBID_C_FUNCTION(char* getwd(char *buf), "use os::get_current_directory()");
       FORBID_C_FUNCTION(wchar_t* wcsdup(const wchar_t *s), "don't use");
      diff --git a/test/hotspot/gtest/runtime/test_os.cpp b/test/hotspot/gtest/runtime/test_os.cpp
      index 78e5212ab3709..fe3c634056c2f 100644
      --- a/test/hotspot/gtest/runtime/test_os.cpp
      +++ b/test/hotspot/gtest/runtime/test_os.cpp
      @@ -405,6 +405,86 @@ TEST_VM(os, jio_snprintf) {
         test_snprintf(jio_snprintf, false);
       }
       
      +#ifndef MAX_PATH
      +#define MAX_PATH    (2 * K)
      +#endif
      +
      +TEST_VM(os, realpath) {
      +  // POSIX requires that the file exists; Windows tests for a valid drive letter
      +  // but may or may not test if the file exists. */
      +  static const char* nosuchpath = "/1234567890123456789";
      +  static const char* tmppath = "/tmp";
      +
      +  char buffer[MAX_PATH];
      +
      +  // Test a non-existant path, but provide a short buffer.
      +  errno = 0;
      +  const char* returnedBuffer = os::realpath(nosuchpath, buffer, sizeof(nosuchpath) - 2);
      +  // Reports ENOENT on Linux, ENAMETOOLONG on Windows.
      +  EXPECT_TRUE(returnedBuffer == nullptr);
      +#ifdef _WINDOWS
      +  EXPECT_TRUE(errno == ENAMETOOLONG);
      +#else
      +  EXPECT_TRUE(errno == ENOENT);
      +#endif
      +
      +  // Test a non-existant path, but provide an adequate buffer.
      +  errno = 0;
      +  buffer[0] = 0;
      +  returnedBuffer = os::realpath(nosuchpath, buffer, sizeof(nosuchpath) + 3);
      +  // Reports ENOENT on Linux, may return 0 (and report an error) or buffer on some versions of Windows.
      +#ifdef _WINDOWS
      +  if (returnedBuffer != nullptr) {
      +    EXPECT_TRUE(returnedBuffer == buffer);
      +  } else {
      +    EXPECT_TRUE(errno != 0);
      +  }
      +#else
      +  EXPECT_TRUE(returnedBuffer == nullptr);
      +  EXPECT_TRUE(errno == ENOENT);
      +#endif
      +
      +  // Test an existing path using a large buffer.
      +  errno = 0;
      +  returnedBuffer = os::realpath(tmppath, buffer, MAX_PATH);
      +  EXPECT_TRUE(returnedBuffer == buffer);
      +
      +  // Test an existing path using a buffer that is too small on a normal macOS install.
      +  errno = 0;
      +  returnedBuffer = os::realpath(tmppath, buffer, strlen(tmppath) + 3);
      +  // On MacOS, /tmp is a symlink to /private/tmp, so doesn't fit in a small buffer.
      +#ifndef __APPLE__
      +  EXPECT_TRUE(returnedBuffer == buffer);
      +#else
      +  EXPECT_TRUE(returnedBuffer == nullptr);
      +  EXPECT_TRUE(errno == ENAMETOOLONG);
      +#endif
      +
      +  // Test an existing path using a buffer that is too small.
      +  errno = 0;
      +  returnedBuffer = os::realpath(tmppath, buffer, strlen(tmppath) - 1);
      +  EXPECT_TRUE(returnedBuffer == nullptr);
      +  EXPECT_TRUE(errno == ENAMETOOLONG);
      +
      +  // The following tests cause an assert inside os::realpath() in fastdebug mode:
      +#ifndef ASSERT
      +  errno = 0;
      +  returnedBuffer = os::realpath(nullptr, buffer, sizeof(buffer));
      +  EXPECT_TRUE(returnedBuffer == nullptr);
      +  EXPECT_TRUE(errno == EINVAL);
      +
      +  errno = 0;
      +  returnedBuffer = os::realpath(tmppath, nullptr, sizeof(buffer));
      +  EXPECT_TRUE(returnedBuffer == nullptr);
      +  EXPECT_TRUE(errno == EINVAL);
      +
      +  errno = 0;
      +  returnedBuffer = os::realpath(tmppath, buffer, 0);
      +  EXPECT_TRUE(returnedBuffer == nullptr);
      +  EXPECT_TRUE(errno == EINVAL);
      +#endif
      +}
      +
       #ifdef __APPLE__
       // Not all macOS versions can use os::reserve_memory (i.e. anon_mmap) API
       // to reserve executable memory, so before attempting to use it,
      
      From 1ea1f33f66326804ca2892fe0659a9acb7ee72ae Mon Sep 17 00:00:00 2001
      From: Alisen Chung 
      Date: Thu, 17 Oct 2024 08:43:07 +0000
      Subject: [PATCH 107/118] 8340336: Open some checkbox awt tests
      
      Reviewed-by: prr, honkar
      ---
       .../awt/Checkbox/AppearanceIfLargeFont.java   |  84 ++++++++++++
       .../Checkbox/CheckboxMenuItemEventsTest.java  | 120 ++++++++++++++++++
       test/jdk/java/awt/Container/ValidateTest.java |  78 ++++++++++++
       3 files changed, 282 insertions(+)
       create mode 100644 test/jdk/java/awt/Checkbox/AppearanceIfLargeFont.java
       create mode 100644 test/jdk/java/awt/Checkbox/CheckboxMenuItemEventsTest.java
       create mode 100644 test/jdk/java/awt/Container/ValidateTest.java
      
      diff --git a/test/jdk/java/awt/Checkbox/AppearanceIfLargeFont.java b/test/jdk/java/awt/Checkbox/AppearanceIfLargeFont.java
      new file mode 100644
      index 0000000000000..7995b43ed18d5
      --- /dev/null
      +++ b/test/jdk/java/awt/Checkbox/AppearanceIfLargeFont.java
      @@ -0,0 +1,84 @@
      +/*
      + * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved.
      + * 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.Button;
      +import java.awt.CheckboxMenuItem;
      +import java.awt.Frame;
      +import java.awt.PopupMenu;
      +import java.awt.event.ActionEvent;
      +import java.awt.event.ActionListener;
      +
      +/*
      + * @test
      + * @bug 6401956
      + * @summary The right mark of the CheckboxMenu item is broken
      + * @library /java/awt/regtesthelpers
      + * @build PassFailJFrame
      + * @run main/manual AppearanceIfLargeFont
      + */
      +
      +public class AppearanceIfLargeFont extends Frame {
      +    private static final String INSTRUCTIONS = """
      +            1) Make sure that font-size is large.
      +               You could change this using 'Appearance' dialog.
      +            2) Press button 'Press'
      +               You will see a menu item with check-mark.
      +            3) If check-mark is correctly painted then the test passed.
      +               Otherwise, test failed.
      +            """;
      +
      +    public static void main(String[] args) throws Exception {
      +        PassFailJFrame.builder()
      +                .title("AppearanceIfLargeFont")
      +                .instructions(INSTRUCTIONS)
      +                .columns(35)
      +                .testUI(AppearanceIfLargeFont::new)
      +                .build()
      +                .awaitAndCheck();
      +    }
      +
      +    public AppearanceIfLargeFont() {
      +        createComponents();
      +
      +        setSize(200, 200);
      +        validate();
      +    }
      +
      +    void createComponents() {
      +        final Button press = new Button("Press");
      +        final PopupMenu popup = new PopupMenu();
      +        press.add(popup);
      +        add(press);
      +
      +        CheckboxMenuItem item = new CheckboxMenuItem("CheckboxMenuItem", true);
      +        popup.add(item);
      +
      +        press.addActionListener(
      +                new ActionListener() {
      +                    public void actionPerformed(ActionEvent ae) {
      +                        popup.show(press, press.getSize().width, 0);
      +                    }
      +                }
      +        );
      +    }
      +}
      diff --git a/test/jdk/java/awt/Checkbox/CheckboxMenuItemEventsTest.java b/test/jdk/java/awt/Checkbox/CheckboxMenuItemEventsTest.java
      new file mode 100644
      index 0000000000000..425c24ba7ef42
      --- /dev/null
      +++ b/test/jdk/java/awt/Checkbox/CheckboxMenuItemEventsTest.java
      @@ -0,0 +1,120 @@
      +/*
      + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
      + * 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.Button;
      +import java.awt.CheckboxMenuItem;
      +import java.awt.Frame;
      +import java.awt.Panel;
      +import java.awt.PopupMenu;
      +import java.awt.TextArea;
      +import java.awt.event.ActionEvent;
      +import java.awt.event.ActionListener;
      +import java.awt.event.ItemEvent;
      +import java.awt.event.ItemListener;
      +
      +/*
      + * @test
      + * @bug 4814163 5005195
      + * @library /java/awt/regtesthelpers
      + * @build PassFailJFrame
      + * @summary Tests events fired by CheckboxMenuItem
      + * @run main/manual CheckboxMenuItemEventsTest
      +*/
      +
      +public class CheckboxMenuItemEventsTest extends Frame implements ActionListener {
      +    Button trigger;
      +    PopupMenu popup;
      +    TextArea ta;
      +
      +    class Listener implements ItemListener, ActionListener {
      +        public void itemStateChanged(ItemEvent e) {
      +            ta.append("CORRECT: ItemEvent fired\n");
      +        }
      +
      +        public void actionPerformed(ActionEvent e) {
      +            ta.append("ERROR: ActionEvent fired\n");
      +        }
      +    }
      +
      +    Listener listener = new Listener();
      +
      +    private static final String INSTRUCTIONS = """
      +            Press button to invoke popup menu
      +            When you press checkbox menu item
      +            Item state should toggle (on/off).
      +            ItemEvent should be displayed in log below.
      +            And ActionEvent should not be displayed
      +            Press PASS if ItemEvents are generated
      +            and ActionEvents are not, FAIL Otherwise.
      +            """;
      +
      +    public static void main(String[] args) throws Exception {
      +        PassFailJFrame.builder()
      +                .title("CheckboxMenuItemEventsTest")
      +                .instructions(INSTRUCTIONS)
      +                .columns(35)
      +                .testUI(CheckboxMenuItemEventsTest::new)
      +                .build()
      +                .awaitAndCheck();
      +    }
      +
      +    public CheckboxMenuItemEventsTest() {
      +        CheckboxMenuItem i1 = new CheckboxMenuItem("CheckBoxMenuItem 1");
      +        CheckboxMenuItem i2 = new CheckboxMenuItem("CheckBoxMenuItem 2");
      +        Panel p1 = new Panel();
      +        Panel p2 = new Panel();
      +
      +        setLayout(new BorderLayout());
      +        ta = new TextArea();
      +        p2.add(ta);
      +
      +        trigger = new Button("menu");
      +        trigger.addActionListener(this);
      +
      +        popup = new PopupMenu();
      +
      +        i1.addItemListener(listener);
      +        i1.addActionListener(listener);
      +        popup.add(i1);
      +        i2.addItemListener(listener);
      +        i2.addActionListener(listener);
      +        popup.add(i2);
      +
      +        trigger.add(popup);
      +
      +        p1.add(trigger);
      +
      +        add(p1, BorderLayout.NORTH);
      +        add(p2, BorderLayout.SOUTH);
      +
      +        pack();
      +        validate();
      +    }
      +
      +    public void actionPerformed(ActionEvent e) {
      +        if (e.getSource() == (Object) trigger) {
      +            popup.show(trigger, trigger.getSize().width, 0);
      +        }
      +    }
      +}
      diff --git a/test/jdk/java/awt/Container/ValidateTest.java b/test/jdk/java/awt/Container/ValidateTest.java
      new file mode 100644
      index 0000000000000..935766094cf75
      --- /dev/null
      +++ b/test/jdk/java/awt/Container/ValidateTest.java
      @@ -0,0 +1,78 @@
      +/*
      + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved.
      + * 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.EventQueue;
      +import java.awt.Frame;
      +import java.awt.GridLayout;
      +import java.awt.Panel;
      +
      +/*
      + * @test
      + * @bug 4136190
      + * @requires (os.family == "windows")
      + * @summary Recursive validation calls would cause major USER resource leakage
      + * @key headful
      + * @run main/timeout=30 ValidateTest
      + */
      +
      +public class ValidateTest {
      +    static Frame frame;
      +
      +    public static void main(String args[]) throws Exception {
      +        try {
      +            EventQueue.invokeAndWait(() -> {
      +                createGUI();
      +            });
      +        } finally {
      +            EventQueue.invokeAndWait(() -> {
      +                if (frame != null) {
      +                    frame.dispose();
      +                }
      +            });
      +        }
      +    }
      +
      +    public static void createGUI() {
      +        frame = new Frame("Test for 4136190 : JVM and win95 resource leakage issues");
      +        frame.setLayout(new GridLayout(1, 1));
      +        MyPanel panel = new MyPanel();
      +        frame.add(panel);
      +        frame.invalidate();
      +        frame.validate();
      +        frame.setSize(500, 400);
      +        frame.setVisible(true);
      +    }
      +
      +    static class MyPanel extends Panel {
      +        int recurseCounter = 0;
      +
      +        public void validate() {
      +            recurseCounter++;
      +            if (recurseCounter >= 100) {
      +                return;
      +            }
      +            getParent().validate();
      +            super.validate();
      +        }
      +    }
      +}
      \ No newline at end of file
      
      From 9bdface14719d53f40a6572f1c3d4b816c32438b Mon Sep 17 00:00:00 2001
      From: =?UTF-8?q?Ant=C3=B3n=20Seoane=20Ampudia?=
       
      Date: Thu, 17 Oct 2024 09:18:22 +0000
      Subject: [PATCH 108/118] 8341622: Tag-specific disabled default decorators for
       UnifiedLogging
      
      Reviewed-by: jsjolen, rcastanedalo, aboldtch
      ---
       .../share/logging/logConfiguration.cpp        |   2 +-
       src/hotspot/share/logging/logDecorators.cpp   |  32 +++++-
       src/hotspot/share/logging/logDecorators.hpp   |  52 ++++++++-
       src/hotspot/share/logging/logSelection.cpp    |  19 +++-
       src/hotspot/share/logging/logSelection.hpp    |   4 +-
       .../share/logging/logSelectionList.cpp        |  12 +-
       .../share/logging/logSelectionList.hpp        |   4 +-
       .../logging/test_logDefaultDecorators.cpp     | 104 ++++++++++++++++++
       .../logging/DefaultLogDecoratorsTest.java     |  84 ++++++++++++++
       9 files changed, 299 insertions(+), 14 deletions(-)
       create mode 100644 test/hotspot/gtest/logging/test_logDefaultDecorators.cpp
       create mode 100644 test/hotspot/jtreg/runtime/logging/DefaultLogDecoratorsTest.java
      
      diff --git a/src/hotspot/share/logging/logConfiguration.cpp b/src/hotspot/share/logging/logConfiguration.cpp
      index 87b195f4fbfdd..dfddfff2f05c0 100644
      --- a/src/hotspot/share/logging/logConfiguration.cpp
      +++ b/src/hotspot/share/logging/logConfiguration.cpp
      @@ -491,7 +491,7 @@ bool LogConfiguration::parse_log_arguments(const char* outputstr,
           return false;
         }
       
      -  LogDecorators decorators;
      +  LogDecorators decorators = selections.get_default_decorators();
         if (!decorators.parse(decoratorstr, errstream)) {
           return false;
         }
      diff --git a/src/hotspot/share/logging/logDecorators.cpp b/src/hotspot/share/logging/logDecorators.cpp
      index 91677b35d9f95..6c06bd4571627 100644
      --- a/src/hotspot/share/logging/logDecorators.cpp
      +++ b/src/hotspot/share/logging/logDecorators.cpp
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
        * 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 @@
       #include "logging/logDecorators.hpp"
       #include "runtime/os.hpp"
       
      +const LogLevelType AnyLevel = LogLevelType::NotMentioned;
      +
       template 
       struct AllBitmask {
         // Use recursive template deduction to calculate the bitmask of all decorations.
      @@ -45,6 +47,19 @@ const char* LogDecorators::_name[][2] = {
       #undef DECORATOR
       };
       
      +#define UNDECORATED_DEFAULTS \
      +  UNDECORATED_DEFAULT(AnyLevel, LOG_TAGS(jit, inlining))
      +
      +const LogDecorators::DefaultUndecoratedSelection LogDecorators::default_decorators[] = {
      +#define UNDECORATED_DEFAULT(level, ...) LogDecorators::DefaultUndecoratedSelection::make(),
      +  UNDECORATED_DEFAULTS
      +#undef UNDECORATED_DEFAULT
      +};
      +
      +#undef UNDERCORATED_DEFAULTS
      +
      +const size_t LogDecorators::number_of_default_decorators = ARRAY_SIZE(default_decorators);
      +
       LogDecorators::Decorator LogDecorators::from_string(const char* str) {
         for (size_t i = 0; i < Count; i++) {
           Decorator d = static_cast(i);
      @@ -57,7 +72,7 @@ LogDecorators::Decorator LogDecorators::from_string(const char* str) {
       
       bool LogDecorators::parse(const char* decorator_args, outputStream* errstream) {
         if (decorator_args == nullptr || strlen(decorator_args) == 0) {
      -    _decorators = DefaultDecoratorsMask;
      +    // No decorators supplied, keep default decorators
           return true;
         }
       
      @@ -93,3 +108,16 @@ bool LogDecorators::parse(const char* decorator_args, outputStream* errstream) {
         }
         return result;
       }
      +
      +bool LogDecorators::has_disabled_default_decorators(const LogSelection& selection, const DefaultUndecoratedSelection* defaults, size_t defaults_count) {
      +  for (size_t i = 0; i < defaults_count; ++i) {
      +    DefaultUndecoratedSelection current_default = defaults[i];
      +    const bool ignore_level = current_default.selection().level() == AnyLevel;
      +    const bool level_matches = ignore_level || selection.level() == current_default.selection().level();
      +    if (!level_matches) continue;
      +    if (selection.superset_of(current_default.selection())) {
      +      return true;
      +    }
      +  }
      +  return false;
      +}
      diff --git a/src/hotspot/share/logging/logDecorators.hpp b/src/hotspot/share/logging/logDecorators.hpp
      index b92de0fdb98ce..9e38f429974a1 100644
      --- a/src/hotspot/share/logging/logDecorators.hpp
      +++ b/src/hotspot/share/logging/logDecorators.hpp
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
        * 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 @@
       #define SHARE_LOGGING_LOGDECORATORS_HPP
       
       #include "utilities/globalDefinitions.hpp"
      +#include "logging/logSelection.hpp"
       
       class outputStream;
       
      @@ -59,6 +60,7 @@ class outputStream;
       // declared above. For example, logging with 'uptime, level, tags' decorators results in:
       // [0,943s][info   ][logging] message.
       class LogDecorators {
      +  friend class TestLogDecorators;
        public:
         enum Decorator {
       #define DECORATOR(name, abbr) name##_decorator,
      @@ -68,24 +70,48 @@ class LogDecorators {
           Invalid
         };
       
      +  class DefaultUndecoratedSelection {
      +    friend class TestLogDecorators;
      +    LogSelection _selection;
      +
      +    DefaultUndecoratedSelection() : _selection(LogSelection::Invalid) {}
      +
      +    DefaultUndecoratedSelection(LogLevelType level, LogTagType t0, LogTagType t1, LogTagType t2,
      +                                LogTagType t3, LogTagType t4) : _selection(LogSelection::Invalid) {
      +      LogTagType tag_arr[LogTag::MaxTags] = { t0, t1, t2, t3, t4 };
      +      _selection = LogSelection(tag_arr, false, level);
      +    }
      +
      +  public:
      +    template 
      +    static DefaultUndecoratedSelection make() {
      +      STATIC_ASSERT(GuardTag == LogTag::__NO_TAG);
      +      return DefaultUndecoratedSelection(Level, T0, T1, T2, T3, T4);
      +    }
      +
      +    const LogSelection& selection() const { return _selection; }
      +  };
      +
        private:
         uint _decorators;
         static const char* _name[][2];
      -  static const uint DefaultDecoratorsMask = (1 << uptime_decorator) | (1 << level_decorator) | (1 << tags_decorator);
      +  static const uint defaultsMask = (1 << uptime_decorator) | (1 << level_decorator) | (1 << tags_decorator);
      +  static const LogDecorators::DefaultUndecoratedSelection default_decorators[];
      +  static const size_t number_of_default_decorators;
       
         static uint mask(LogDecorators::Decorator decorator) {
           return 1 << decorator;
         }
       
      -  constexpr LogDecorators(uint mask) : _decorators(mask) {
      -  }
       
        public:
         static const LogDecorators None;
         static const LogDecorators All;
       
      -  LogDecorators() : _decorators(DefaultDecoratorsMask) {
      -  }
      +  constexpr LogDecorators(uint mask) : _decorators(mask) {}
      +
      +  LogDecorators() : _decorators(defaultsMask) {}
       
         void clear() {
           _decorators = 0;
      @@ -99,6 +125,20 @@ class LogDecorators {
           return _name[decorator][1];
         }
       
      +  template
      +  static uint mask_from_decorators(LogDecorators::Decorator first, Decorators... rest) {
      +    uint bitmask = 0;
      +    LogDecorators::Decorator decorators[1 + sizeof...(rest)] = { first, rest... };
      +    for (const LogDecorators::Decorator decorator : decorators) {
      +      bitmask |= mask(decorator);
      +    }
      +    return bitmask;
      +  }
      +
      +  // Check if we have some default decorators for a given LogSelection. If that is the case,
      +  // the output parameter mask will contain the defaults-specified decorators mask
      +  static bool has_disabled_default_decorators(const LogSelection& selection, const DefaultUndecoratedSelection* defaults = default_decorators, size_t defaults_count = number_of_default_decorators);
      +
         static LogDecorators::Decorator from_string(const char* str);
       
         void combine_with(const LogDecorators &source) {
      diff --git a/src/hotspot/share/logging/logSelection.cpp b/src/hotspot/share/logging/logSelection.cpp
      index 1e7ba3a887848..99ecc9f87f272 100644
      --- a/src/hotspot/share/logging/logSelection.cpp
      +++ b/src/hotspot/share/logging/logSelection.cpp
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
        * 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,6 +69,23 @@ bool LogSelection::operator!=(const LogSelection& ref) const {
         return !operator==(ref);
       }
       
      +bool LogSelection::superset_of(const LogSelection& other) const {
      +  bool match;
      +  for (size_t i = 0; i < other.ntags(); ++i) {
      +    match = false;
      +    for (size_t j = 0; j < _ntags; ++j) {
      +      if (other._tags[i] == _tags[j]) {
      +        match = true;
      +        break;
      +      }
      +    }
      +
      +    if (!match) return false;
      +  }
      +
      +  return true;
      +}
      +
       static LogSelection parse_internal(char *str, outputStream* errstream) {
         // Parse the level, if specified
         LogLevelType level = LogLevel::Unspecified;
      diff --git a/src/hotspot/share/logging/logSelection.hpp b/src/hotspot/share/logging/logSelection.hpp
      index 7f4c1fb8e95e3..4555590295a5d 100644
      --- a/src/hotspot/share/logging/logSelection.hpp
      +++ b/src/hotspot/share/logging/logSelection.hpp
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
        * 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,8 @@ class LogSelection : public StackObj {
         bool operator==(const LogSelection& ref) const;
         bool operator!=(const LogSelection& ref) const;
       
      +  bool superset_of(const LogSelection& ref) const;
      +
         size_t ntags() const;
         LogLevelType level() const;
         size_t tag_sets_selected() const;
      diff --git a/src/hotspot/share/logging/logSelectionList.cpp b/src/hotspot/share/logging/logSelectionList.cpp
      index 1eb4cca0c3e50..ac63f20512c2a 100644
      --- a/src/hotspot/share/logging/logSelectionList.cpp
      +++ b/src/hotspot/share/logging/logSelectionList.cpp
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
        * 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,6 +53,14 @@ bool LogSelectionList::verify_selections(outputStream* out) const {
         return valid;
       }
       
      +LogDecorators LogSelectionList::get_default_decorators() const {
      +  for (size_t i = 0; i < _nselections; ++i) {
      +    if (!LogDecorators::has_disabled_default_decorators(_selections[i])) {
      +      return LogDecorators();
      +    }
      +  }
      +  return LogDecorators::None;
      +}
       
       bool LogSelectionList::parse(const char* str, outputStream* errstream) {
         bool success = true;
      @@ -91,7 +99,7 @@ bool LogSelectionList::parse(const char* str, outputStream* errstream) {
       LogLevelType LogSelectionList::level_for(const LogTagSet& ts) const {
         // Return NotMentioned if the given tagset isn't covered by this expression.
         LogLevelType level = LogLevel::NotMentioned;
      -  for (size_t i= 0; i < _nselections; i++) {
      +  for (size_t i = 0; i < _nselections; i++) {
           if (_selections[i].selects(ts)) {
             level = _selections[i].level();
           }
      diff --git a/src/hotspot/share/logging/logSelectionList.hpp b/src/hotspot/share/logging/logSelectionList.hpp
      index 6bd2c6608bc87..0852348cc1463 100644
      --- a/src/hotspot/share/logging/logSelectionList.hpp
      +++ b/src/hotspot/share/logging/logSelectionList.hpp
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      @@ -60,6 +60,8 @@ class LogSelectionList : public StackObj {
         // Returns false if some invalid selection was found. If given an outputstream,
         // this function will list all the invalid selections on the stream.
         bool verify_selections(outputStream* out = nullptr) const;
      +
      +  LogDecorators get_default_decorators() const;
       };
       
       #endif // SHARE_LOGGING_LOGSELECTIONLIST_HPP
      diff --git a/test/hotspot/gtest/logging/test_logDefaultDecorators.cpp b/test/hotspot/gtest/logging/test_logDefaultDecorators.cpp
      new file mode 100644
      index 0000000000000..8ffe97da0dbc5
      --- /dev/null
      +++ b/test/hotspot/gtest/logging/test_logDefaultDecorators.cpp
      @@ -0,0 +1,104 @@
      +/*
      + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
      + * 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 "jvm.h"
      +#include "logging/logDecorators.hpp"
      +#include "logging/logTag.hpp"
      +#include "unittest.hpp"
      +
      +
      +class TestLogDecorators : public testing::Test {
      +  using LD = LogDecorators;
      +
      +  static const size_t defaults_cnt = 3;
      +  LD::DefaultUndecoratedSelection defaults[defaults_cnt] = {
      +    LD::DefaultUndecoratedSelection::make(),
      +    LD::DefaultUndecoratedSelection::make(),
      +    LD::DefaultUndecoratedSelection::make(),
      +  };
      +
      +public:
      +  void test_default_decorators() {
      +    LogTagType tags[LogTag::MaxTags] = { LogTag::__NO_TAG, LogTag::__NO_TAG, LogTag::__NO_TAG, LogTag::__NO_TAG, LogTag::__NO_TAG };
      +    bool result;
      +
      +    // If a -Xlog selection matches one of the undecorated defaults, the default decorators will be disabled
      +    tags[0] = LogTagType::_jit;
      +    result = LD::has_disabled_default_decorators(LogSelection(tags, false, LogLevelType::Trace), defaults, defaults_cnt);
      +    EXPECT_TRUE(result);
      +
      +
      +    // If a -Xlog selection contains one of the undecorated defaults, the default decorators will be disabled
      +    tags[0] = LogTagType::_jit;
      +    tags[1] = LogTagType::_inlining;
      +    result = LD::has_disabled_default_decorators(LogSelection(tags, false, LogLevelType::Trace), defaults, defaults_cnt);
      +    EXPECT_TRUE(result);
      +
      +
      +    // Wildcards are ignored
      +    tags[0] = LogTag::_compilation;
      +    result = LD::has_disabled_default_decorators(LogSelection(tags, true, LogLevelType::Debug), defaults, defaults_cnt);
      +    EXPECT_FALSE(result);
      +
      +
      +    // If there is no level match, default decorators are kept
      +    tags[0] = LogTagType::_gc;
      +    result = LD::has_disabled_default_decorators(LogSelection(tags, false, LogLevelType::Info), defaults, defaults_cnt);
      +    EXPECT_FALSE(result);
      +
      +
      +    // If NotMentioned is specified, it will match every level and so default decorators will never be added if there is a positive tagset match
      +    tags[0] = LogTagType::_ref;
      +    result = LD::has_disabled_default_decorators(LogSelection(tags, false, LogLevelType::Error), defaults, defaults_cnt);
      +    EXPECT_TRUE(result);
      +    result = LD::has_disabled_default_decorators(LogSelection(tags, false, LogLevelType::Warning), defaults, defaults_cnt);
      +    EXPECT_TRUE(result);
      +    result = LD::has_disabled_default_decorators(LogSelection(tags, false, LogLevelType::Info), defaults, defaults_cnt);
      +    EXPECT_TRUE(result);
      +    result = LD::has_disabled_default_decorators(LogSelection(tags, false, LogLevelType::Debug), defaults, defaults_cnt);
      +    EXPECT_TRUE(result);
      +    result = LD::has_disabled_default_decorators(LogSelection(tags, false, LogLevelType::Trace), defaults, defaults_cnt);
      +    EXPECT_TRUE(result);
      +  }
      +
      +  void test_mask_from_decorators() {
      +    // Single tags should yield 2^{decorator_value_in_enum}
      +    EXPECT_EQ(LD::mask_from_decorators(LD::time_decorator), (uint)(1 << LD::time_decorator));
      +    EXPECT_EQ(LD::mask_from_decorators(LD::pid_decorator),  (uint)(1 << LD::pid_decorator));
      +    EXPECT_EQ(LD::mask_from_decorators(LD::tid_decorator),  (uint)(1 << LD::tid_decorator));
      +    EXPECT_EQ(LD::mask_from_decorators(LD::tags_decorator), (uint)(1 << LD::tags_decorator));
      +
      +    // Combinations of decorators should fill the mask accordingly to their bitmask positions
      +    uint mask = (1 << LD::time_decorator) | (1 << LD::uptimemillis_decorator) | (1 << LD::tid_decorator);
      +    EXPECT_EQ(LD::mask_from_decorators(LD::time_decorator, LD::uptimemillis_decorator, LD::tid_decorator), mask);
      +  }
      +};
      +
      +TEST_VM_F(TestLogDecorators, MaskFromDecorators) {
      +  test_mask_from_decorators();
      +}
      +
      +TEST_VM_F(TestLogDecorators, HasDefaultDecorators) {
      +  test_default_decorators();
      +}
      diff --git a/test/hotspot/jtreg/runtime/logging/DefaultLogDecoratorsTest.java b/test/hotspot/jtreg/runtime/logging/DefaultLogDecoratorsTest.java
      new file mode 100644
      index 0000000000000..c237414562226
      --- /dev/null
      +++ b/test/hotspot/jtreg/runtime/logging/DefaultLogDecoratorsTest.java
      @@ -0,0 +1,84 @@
      +/*
      + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
      + * 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
      + * @requires vm.flagless
      + * @summary Running -Xlog with tags which have disabled default decorators should not yield decorated logs
      + * @library /test/lib
      + * @modules java.base/jdk.internal.misc
      + *          java.management
      + * @run driver DefaultLogDecoratorsTest
      + */
      +
      +import jdk.test.lib.process.OutputAnalyzer;
      +import jdk.test.lib.Platform;
      +import jdk.test.lib.process.ProcessTools;
      +import java.nio.file.Files;
      +import java.nio.file.Path;
      +import java.util.regex.Pattern;
      +import java.util.List;
      +import java.util.Arrays;
      +import java.util.ArrayList;
      +
      +public class DefaultLogDecoratorsTest {
      +    private static Pattern DECORATED_LINE = Pattern.compile("(\\[.+\\])+ .*");
      +
      +    private static void doTest(boolean shouldHave, String... xlog) throws Exception {
      +        List argsList = new ArrayList(Arrays.asList(xlog));
      +        argsList.add(InnerClass.class.getName());
      +        String[] args = argsList.toArray(new String[0]);
      +        ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(args);
      +        OutputAnalyzer output = new OutputAnalyzer(pb.start());
      +        output.shouldHaveExitValue(0);
      +        List allLines = Files.readAllLines(Path.of("decorators.log"));
      +        for (String line : allLines) {
      +            if (DECORATED_LINE.matcher(line).find() == !shouldHave) {
      +                throw new RuntimeException("Logging should " + (shouldHave ? "" : "not ") + "contain decorators!");
      +            }
      +        }
      +    }
      +
      +    public static void main(String[] args) throws Exception {
      +        // JIT inlining logging, as per defaults, shall have all decorators disabled
      +        doTest(false, "-Xlog:jit+inlining*=trace:decorators.log");
      +
      +        // If decorators are specified, the defaults are not taken into account
      +        doTest(true, "-Xlog:jit+inlining*=trace:decorators.log:time");
      +
      +        // Even if decorators are only supplied for another tag(s), the defaults are not taken into account
      +        doTest(true, "-Xlog:jit+inlining*=trace:decorators.log", "-Xlog:gc*=info:decorators.log:time");
      +
      +        // Defaults are not taken into account also when another tag implicitly imposes the "standard" defaults
      +        doTest(true, "-Xlog:jit+inlining*=trace:decorators.log", "-Xlog:gc*=info:decorators.log");
      +
      +        // Other logging shall not be affected by a tag with defaults
      +        doTest(true, "-Xlog:gc*=trace:decorators.log");
      +    }
      +
      +    public static class InnerClass {
      +        public static void main(String[] args) throws Exception {
      +            System.out.println("DefaultLogDecorators test");
      +        }
      +    }
      +}
      
      From 7ff4ea8d01c681b90ad59be04007557d84c8db94 Mon Sep 17 00:00:00 2001
      From: Jan Lahoda 
      Date: Thu, 17 Oct 2024 09:26:13 +0000
      Subject: [PATCH 109/118] 8341966: Broken annotated module may lead to an
       exception in javac
      
      Reviewed-by: asotona
      ---
       .../com/sun/tools/javac/jvm/ClassReader.java  |  4 +-
       .../javac/modules/AnnotationsOnModules.java   | 94 ++++++++++++++++++-
       2 files changed, 94 insertions(+), 4 deletions(-)
      
      diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java
      index 6abf9f057b043..233629e10bb56 100644
      --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java
      +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      @@ -2192,7 +2192,7 @@ public void visitCompoundAnnotationProxy(CompoundAnnotationProxy proxy) {
       
               Type resolvePossibleProxyType(Type t) {
                   if (t instanceof ProxyType proxyType) {
      -                Assert.check(requestingOwner.owner.kind == MDL);
      +                Assert.check(requestingOwner.owner instanceof ModuleSymbol);
                       ModuleSymbol prevCurrentModule = currentModule;
                       currentModule = (ModuleSymbol) requestingOwner.owner;
                       try {
      diff --git a/test/langtools/tools/javac/modules/AnnotationsOnModules.java b/test/langtools/tools/javac/modules/AnnotationsOnModules.java
      index bfae27d4d21db..909b5294d00d2 100644
      --- a/test/langtools/tools/javac/modules/AnnotationsOnModules.java
      +++ b/test/langtools/tools/javac/modules/AnnotationsOnModules.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
        * 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 8159602 8170549 8171255 8171322 8254023
      + * @bug 8159602 8170549 8171255 8171322 8254023 8341966
        * @summary Test annotations on module declaration.
        * @library /tools/lib
        * @enablePreview
      @@ -35,8 +35,10 @@
        */
       
       import java.io.File;
      +import java.io.OutputStream;
       import java.nio.file.Files;
       import java.nio.file.Path;
      +import java.util.ArrayList;
       import java.util.Arrays;
       import java.util.HashSet;
       import java.util.List;
      @@ -55,6 +57,7 @@
       import java.lang.classfile.*;
       import java.lang.classfile.ClassFile;
       import java.lang.classfile.attribute.*;
      +import java.lang.reflect.AccessFlag;
       import toolbox.JavacTask;
       import toolbox.Task;
       import toolbox.Task.OutputKind;
      @@ -726,6 +729,93 @@ public TestCase(String extraDecl, String decl, String use, String expectedAnnota
               }
           }
       
      +    @Test
      +    public void testBrokenModuleInfoClassWithAnnotation(Path base) throws Exception {
      +        Path lib = base.resolve("lib");
      +        tb.writeJavaFiles(lib,
      +                          """
      +                          @Deprecated
      +                          module m{}
      +                          """);
      +
      +        Path libClasses = base.resolve("lib-classes");
      +        Files.createDirectories(libClasses);
      +
      +        new JavacTask(tb)
      +            .options("--release", "21")
      +            .outdir(libClasses)
      +            .files(findJavaFiles(lib))
      +            .run()
      +            .writeAll();
      +
      +        Path modifiedModuleInfo = libClasses.resolve("module-info.class");
      +        ClassModel cm1 = ClassFile.of().parse(modifiedModuleInfo);
      +        byte[] newBytes = ClassFile.of().transformClass(cm1, (builder, element) -> {
      +            if (element instanceof ModuleAttribute attr) {
      +                List requires = new ArrayList<>();
      +
      +                for (ModuleRequireInfo mri : attr.requires()) {
      +                    if (mri.requires().name().equalsString("java.base")) {
      +                        requires.add(ModuleRequireInfo.of(mri.requires(),
      +                                                          List.of(AccessFlag.TRANSITIVE),
      +                                                          mri.requiresVersion()
      +                                                             .orElse(null)));
      +                    } else {
      +                        requires.add(mri);
      +                    }
      +                }
      +
      +                builder.accept(ModuleAttribute.of(attr.moduleName(),
      +                                                  attr.moduleFlagsMask(),
      +                                                  attr.moduleVersion()
      +                                                      .orElseGet(() -> null),
      +                                                  requires,
      +                                                  attr.exports(),
      +                                                  attr.opens(),
      +                                                  attr.uses(),
      +                                                  attr.provides()));
      +            } else {
      +                builder.accept(element);
      +            }
      +        });
      +
      +        try (OutputStream out = Files.newOutputStream(modifiedModuleInfo)) {
      +            out.write(newBytes);
      +        }
      +
      +        Path src = base.resolve("src");
      +        Path classes = base.resolve("classes");
      +
      +        tb.writeJavaFiles(src,
      +                          """
      +                          public class C {}
      +                          """);
      +
      +        Files.createDirectories(classes);
      +
      +        List actualErrors =
      +            new JavacTask(tb)
      +                .options("--module-path", libClasses.toString(),
      +                         "--add-modules", "m",
      +                         "-XDshould-stop.at=FLOW",
      +                         "-XDdev",
      +                         "-XDrawDiagnostics")
      +                .outdir(classes)
      +                .files(findJavaFiles(src))
      +                .run(Task.Expect.FAIL)
      +                .writeAll()
      +                .getOutputLines(OutputKind.DIRECT);
      +        List expectedErrors = List.of(
      +            "- compiler.err.cant.access: m.module-info, (compiler.misc.bad.class.file.header: module-info.class, (compiler.misc.bad.requires.flag: ACC_TRANSITIVE (0x0020))",
      +            "1 error"
      +        );
      +
      +        if (!expectedErrors.equals(actualErrors)) {
      +            throw new AssertionError("Unexpected errors, expected: " + expectedErrors +
      +                                     ", but got: " + actualErrors);
      +        }
      +    }
      +
           private static final String OPT_EXPECTED_ANNOTATIONS = "expectedAnnotations";
       
           @SupportedAnnotationTypes("*")
      
      From 3ebfc6c1e27119180700af5ea85e5fa6c1771050 Mon Sep 17 00:00:00 2001
      From: Shaojin Wen 
      Date: Thu, 17 Oct 2024 10:49:53 +0000
      Subject: [PATCH 110/118] 8342336: Optimize ClassFile imports
      
      Reviewed-by: liach
      ---
       .../java/lang/classfile/AccessFlags.java      |  3 +-
       .../java/lang/classfile/Annotation.java       |  5 +-
       .../lang/classfile/AnnotationElement.java     |  2 +-
       .../java/lang/classfile/AnnotationValue.java  | 13 +---
       .../java/lang/classfile/Attribute.java        | 39 +----------
       .../lang/classfile/AttributedElement.java     |  2 +-
       .../java/lang/classfile/Attributes.java       |  1 +
       .../lang/classfile/BootstrapMethodEntry.java  |  4 +-
       .../java/lang/classfile/BufWriter.java        |  1 +
       .../java/lang/classfile/ClassBuilder.java     | 10 ++-
       .../java/lang/classfile/ClassElement.java     | 26 +-------
       .../java/lang/classfile/ClassFile.java        | 23 +++----
       .../java/lang/classfile/ClassFileBuilder.java |  3 +-
       .../lang/classfile/ClassFileTransform.java    |  2 +-
       .../classfile/ClassHierarchyResolver.java     |  3 +-
       .../java/lang/classfile/ClassModel.java       |  6 +-
       .../java/lang/classfile/ClassReader.java      |  4 +-
       .../java/lang/classfile/ClassSignature.java   |  4 +-
       .../java/lang/classfile/ClassTransform.java   |  2 +-
       .../java/lang/classfile/CodeBuilder.java      | 54 ++--------------
       .../java/lang/classfile/CodeElement.java      |  1 +
       .../java/lang/classfile/CodeModel.java        |  5 +-
       .../java/lang/classfile/CompoundElement.java  |  1 +
       .../java/lang/classfile/FieldBuilder.java     |  5 +-
       .../java/lang/classfile/FieldElement.java     | 11 +---
       .../java/lang/classfile/FieldModel.java       |  2 +-
       .../java/lang/classfile/Instruction.java      | 27 +-------
       .../java/lang/classfile/Interfaces.java       |  2 +-
       .../java/lang/classfile/MethodBuilder.java    |  5 +-
       .../java/lang/classfile/MethodElement.java    | 15 +----
       .../java/lang/classfile/MethodModel.java      |  2 +-
       .../java/lang/classfile/MethodSignature.java  |  4 +-
       .../lang/classfile/PseudoInstruction.java     |  1 +
       .../java/lang/classfile/Signature.java        |  7 +-
       .../java/lang/classfile/Superclass.java       |  1 +
       .../java/lang/classfile/TypeAnnotation.java   |  4 +-
       .../classes/java/lang/classfile/TypeKind.java |  1 +
       .../attribute/AnnotationDefaultAttribute.java |  2 +-
       .../attribute/BootstrapMethodsAttribute.java  |  4 +-
       .../CharacterRangeTableAttribute.java         |  2 +-
       .../classfile/attribute/CodeAttribute.java    |  1 +
       .../attribute/CompilationIDAttribute.java     |  1 +
       .../attribute/ConstantValueAttribute.java     |  3 +-
       .../attribute/DeprecatedAttribute.java        |  1 +
       .../attribute/EnclosingMethodAttribute.java   |  8 +--
       .../attribute/ExceptionsAttribute.java        |  6 +-
       .../classfile/attribute/InnerClassInfo.java   |  7 +-
       .../attribute/InnerClassesAttribute.java      |  4 +-
       .../attribute/LineNumberTableAttribute.java   |  2 +-
       .../attribute/LocalVariableInfo.java          |  3 +-
       .../LocalVariableTableAttribute.java          |  4 +-
       .../attribute/LocalVariableTypeInfo.java      |  1 +
       .../LocalVariableTypeTableAttribute.java      |  4 +-
       .../attribute/MethodParameterInfo.java        |  6 +-
       .../attribute/MethodParametersAttribute.java  |  4 +-
       .../classfile/attribute/ModuleAttribute.java  | 16 ++---
       .../classfile/attribute/ModuleExportInfo.java |  9 ++-
       .../classfile/attribute/ModuleHashInfo.java   |  1 +
       .../attribute/ModuleHashesAttribute.java      |  3 +-
       .../attribute/ModuleMainClassAttribute.java   |  3 +-
       .../classfile/attribute/ModuleOpenInfo.java   |  7 +-
       .../attribute/ModulePackagesAttribute.java    |  7 +-
       .../attribute/ModuleProvideInfo.java          |  2 +-
       .../attribute/ModuleRequireInfo.java          |  8 +--
       .../attribute/ModuleResolutionAttribute.java  |  1 +
       .../attribute/ModuleTargetAttribute.java      |  1 +
       .../attribute/NestHostAttribute.java          |  3 +-
       .../attribute/NestMembersAttribute.java       |  6 +-
       .../PermittedSubclassesAttribute.java         |  6 +-
       .../classfile/attribute/RecordAttribute.java  |  4 +-
       .../attribute/RecordComponentInfo.java        |  6 +-
       .../RuntimeInvisibleAnnotationsAttribute.java | 10 ++-
       ...nvisibleParameterAnnotationsAttribute.java |  4 +-
       ...timeInvisibleTypeAnnotationsAttribute.java |  4 +-
       .../RuntimeVisibleAnnotationsAttribute.java   | 10 ++-
       ...eVisibleParameterAnnotationsAttribute.java |  4 +-
       ...untimeVisibleTypeAnnotationsAttribute.java |  4 +-
       .../attribute/SignatureAttribute.java         |  9 +--
       .../SourceDebugExtensionAttribute.java        |  1 +
       .../attribute/SourceFileAttribute.java        |  1 +
       .../attribute/SourceIDAttribute.java          |  1 +
       .../attribute/StackMapFrameInfo.java          |  4 +-
       .../attribute/StackMapTableAttribute.java     |  4 +-
       .../attribute/SyntheticAttribute.java         |  1 +
       .../classfile/attribute/UnknownAttribute.java |  1 +
       .../classfile/components/ClassPrinter.java    | 10 +--
       .../classfile/components/ClassRemapper.java   |  9 +--
       .../components/CodeLocalsShifter.java         |  5 +-
       .../classfile/components/CodeRelabeler.java   |  7 +-
       .../components/CodeStackTracker.java          |  5 +-
       .../snippet-files/PackageSnippets.java        | 26 +++-----
       .../AnnotationConstantValueEntry.java         |  1 +
       .../classfile/constantpool/ClassEntry.java    |  1 +
       .../constantpool/ConstantDynamicEntry.java    |  3 +-
       .../classfile/constantpool/ConstantPool.java  |  5 +-
       .../constantpool/ConstantPoolBuilder.java     | 17 ++---
       .../constantpool/ConstantValueEntry.java      |  1 +
       .../classfile/constantpool/DoubleEntry.java   |  1 +
       .../DynamicConstantPoolEntry.java             |  1 +
       .../classfile/constantpool/FieldRefEntry.java |  3 +-
       .../classfile/constantpool/FloatEntry.java    |  1 +
       .../classfile/constantpool/IntegerEntry.java  |  1 +
       .../constantpool/InterfaceMethodRefEntry.java |  3 +-
       .../constantpool/LoadableConstantEntry.java   |  3 +-
       .../classfile/constantpool/LongEntry.java     |  1 +
       .../constantpool/MethodRefEntry.java          |  3 +-
       .../classfile/constantpool/ModuleEntry.java   |  3 +-
       .../classfile/constantpool/PackageEntry.java  |  3 +-
       .../instruction/ArrayLoadInstruction.java     |  1 +
       .../instruction/ArrayStoreInstruction.java    |  1 +
       .../instruction/BranchInstruction.java        |  1 +
       .../classfile/instruction/CharacterRange.java |  1 +
       .../instruction/ConstantInstruction.java      |  4 +-
       .../instruction/ConvertInstruction.java       |  1 +
       .../instruction/DiscontinuedInstruction.java  |  1 +
       .../classfile/instruction/ExceptionCatch.java |  6 +-
       .../instruction/FieldInstruction.java         |  6 +-
       .../instruction/IncrementInstruction.java     |  1 +
       .../instruction/InvokeDynamicInstruction.java | 12 ++--
       .../instruction/InvokeInstruction.java        |  6 +-
       .../classfile/instruction/LabelTarget.java    |  1 +
       .../classfile/instruction/LineNumber.java     |  1 +
       .../instruction/LoadInstruction.java          |  1 +
       .../instruction/LookupSwitchInstruction.java  |  4 +-
       .../instruction/MonitorInstruction.java       |  1 +
       .../instruction/NewMultiArrayInstruction.java |  3 +-
       .../instruction/NewObjectInstruction.java     |  3 +-
       .../NewPrimitiveArrayInstruction.java         |  1 +
       .../NewReferenceArrayInstruction.java         |  3 +-
       .../classfile/instruction/NopInstruction.java |  1 +
       .../instruction/OperatorInstruction.java      |  1 +
       .../instruction/ReturnInstruction.java        |  1 +
       .../instruction/StackInstruction.java         |  1 +
       .../instruction/StoreInstruction.java         |  1 +
       .../classfile/instruction/SwitchCase.java     |  1 +
       .../instruction/TableSwitchInstruction.java   |  4 +-
       .../instruction/ThrowInstruction.java         |  1 +
       .../instruction/TypeCheckInstruction.java     |  6 +-
       .../snippet-files/PackageSnippets.java        | 32 ++--------
       .../classfile/impl/AbstractInstruction.java   | 43 ++-----------
       .../classfile/impl/AbstractPoolEntry.java     | 23 +------
       .../impl/AbstractPseudoInstruction.java       |  8 +--
       .../classfile/impl/AbstractUnboundModel.java  |  9 ++-
       .../classfile/impl/AccessFlagsImpl.java       |  2 +-
       .../classfile/impl/AnnotationImpl.java        | 11 +++-
       .../classfile/impl/AnnotationReader.java      | 21 +++---
       .../classfile/impl/AttributeHolder.java       |  3 +-
       .../classfile/impl/BlockCodeBuilderImpl.java  |  3 +-
       .../impl/BootstrapMethodEntryImpl.java        |  5 +-
       .../classfile/impl/BoundAttribute.java        | 10 +--
       .../classfile/impl/BoundLocalVariable.java    |  2 +-
       .../impl/BoundRecordComponentInfo.java        |  3 +-
       .../classfile/impl/BufWriterImpl.java         |  4 +-
       .../classfile/impl/BufferedCodeBuilder.java   |  5 +-
       .../classfile/impl/BufferedFieldBuilder.java  | 11 ++--
       .../classfile/impl/BufferedMethodBuilder.java | 15 +----
       .../classfile/impl/BytecodeHelpers.java       | 16 ++---
       .../classfile/impl/CatchBuilderImpl.java      |  1 -
       .../classfile/impl/ChainedClassBuilder.java   |  4 +-
       .../classfile/impl/ChainedCodeBuilder.java    |  3 +-
       .../classfile/impl/ChainedFieldBuilder.java   |  3 +-
       .../classfile/impl/ChainedMethodBuilder.java  |  3 +-
       .../classfile/impl/ClassFileImpl.java         | 10 +--
       .../classfile/impl/ClassHierarchyImpl.java    |  7 +-
       .../internal/classfile/impl/ClassImpl.java    | 33 ++--------
       .../classfile/impl/ClassPrinterImpl.java      | 51 +++++++--------
       .../classfile/impl/ClassReaderImpl.java       | 11 ++--
       .../classfile/impl/ClassRemapperImpl.java     | 64 ++-----------------
       .../jdk/internal/classfile/impl/CodeImpl.java | 13 ++--
       .../classfile/impl/CodeLocalsShifterImpl.java |  1 -
       .../classfile/impl/CodeRelabelerImpl.java     | 11 +---
       .../classfile/impl/CodeStackTrackerImpl.java  | 35 +---------
       .../classfile/impl/DirectClassBuilder.java    | 17 +----
       .../classfile/impl/DirectCodeBuilder.java     | 34 ++--------
       .../classfile/impl/DirectFieldBuilder.java    |  3 +-
       .../classfile/impl/DirectMethodBuilder.java   | 12 +---
       .../internal/classfile/impl/FieldImpl.java    | 10 ++-
       .../classfile/impl/InterfacesImpl.java        |  5 +-
       .../internal/classfile/impl/MethodImpl.java   |  3 +-
       .../internal/classfile/impl/MethodInfo.java   |  2 +-
       .../impl/ModuleAttributeBuilderImpl.java      | 14 ++--
       .../classfile/impl/SignaturesImpl.java        | 15 +++--
       .../classfile/impl/SplitConstantPool.java     | 11 ++--
       .../internal/classfile/impl/StackCounter.java |  2 +-
       .../classfile/impl/StackMapDecoder.java       |  7 +-
       .../classfile/impl/StackMapGenerator.java     |  6 +-
       .../classfile/impl/SuperclassImpl.java        |  2 +-
       .../classfile/impl/TargetInfoImpl.java        |  2 +-
       .../classfile/impl/TemporaryConstantPool.java | 26 +-------
       .../classfile/impl/TransformImpl.java         | 20 +-----
       .../classfile/impl/UnboundAttribute.java      | 64 ++-----------------
       .../jdk/internal/classfile/impl/Util.java     | 28 +++-----
       .../impl/verifier/ParserVerifier.java         | 33 ++++------
       .../impl/verifier/VerificationBytecodes.java  |  4 +-
       .../impl/verifier/VerificationTable.java      |  4 +-
       .../impl/verifier/VerificationType.java       |  3 +-
       .../impl/verifier/VerificationWrapper.java    | 18 +++---
       .../classfile/impl/verifier/VerifierImpl.java | 15 +++--
       198 files changed, 525 insertions(+), 1005 deletions(-)
      
      diff --git a/src/java.base/share/classes/java/lang/classfile/AccessFlags.java b/src/java.base/share/classes/java/lang/classfile/AccessFlags.java
      index 6c6ac75e64896..4abe17c1cf59e 100644
      --- a/src/java.base/share/classes/java/lang/classfile/AccessFlags.java
      +++ b/src/java.base/share/classes/java/lang/classfile/AccessFlags.java
      @@ -24,9 +24,10 @@
        */
       package java.lang.classfile;
       
      +import java.lang.reflect.AccessFlag;
       import java.util.Set;
      +
       import jdk.internal.classfile.impl.AccessFlagsImpl;
      -import java.lang.reflect.AccessFlag;
       import jdk.internal.javac.PreviewFeature;
       
       /**
      diff --git a/src/java.base/share/classes/java/lang/classfile/Annotation.java b/src/java.base/share/classes/java/lang/classfile/Annotation.java
      index 009248ffd7856..4f222084cb7ab 100644
      --- a/src/java.base/share/classes/java/lang/classfile/Annotation.java
      +++ b/src/java.base/share/classes/java/lang/classfile/Annotation.java
      @@ -29,12 +29,11 @@
       import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
       import java.lang.classfile.attribute.RuntimeVisibleParameterAnnotationsAttribute;
       import java.lang.classfile.constantpool.Utf8Entry;
      -import jdk.internal.classfile.impl.AnnotationImpl;
      -import jdk.internal.classfile.impl.TemporaryConstantPool;
      -
       import java.lang.constant.ClassDesc;
       import java.util.List;
       
      +import jdk.internal.classfile.impl.AnnotationImpl;
      +import jdk.internal.classfile.impl.TemporaryConstantPool;
       import jdk.internal.classfile.impl.Util;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java b/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java
      index 33bd410e78dce..7c4283c49bf4d 100644
      --- a/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java
      +++ b/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java
      @@ -24,9 +24,9 @@
        */
       package java.lang.classfile;
       
      +import java.lang.classfile.constantpool.Utf8Entry;
       import java.lang.constant.ClassDesc;
       
      -import java.lang.classfile.constantpool.Utf8Entry;
       import jdk.internal.classfile.impl.AnnotationImpl;
       import jdk.internal.classfile.impl.TemporaryConstantPool;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java b/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java
      index fe768e93b1308..e1e91f2c9edb1 100644
      --- a/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java
      +++ b/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java
      @@ -24,21 +24,14 @@
        */
       package java.lang.classfile;
       
      -import java.lang.classfile.constantpool.AnnotationConstantValueEntry;
      -import java.lang.classfile.constantpool.DoubleEntry;
      -import java.lang.classfile.constantpool.DynamicConstantPoolEntry;
      -import java.lang.classfile.constantpool.FloatEntry;
      -import java.lang.classfile.constantpool.IntegerEntry;
      -import java.lang.classfile.constantpool.LongEntry;
      -import java.lang.classfile.constantpool.Utf8Entry;
      -import jdk.internal.classfile.impl.AnnotationImpl;
      -import jdk.internal.classfile.impl.TemporaryConstantPool;
      -
      +import java.lang.classfile.constantpool.*;
       import java.lang.constant.ClassDesc;
       import java.lang.constant.Constable;
       import java.util.ArrayList;
       import java.util.List;
       
      +import jdk.internal.classfile.impl.AnnotationImpl;
      +import jdk.internal.classfile.impl.TemporaryConstantPool;
       import jdk.internal.classfile.impl.Util;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/Attribute.java b/src/java.base/share/classes/java/lang/classfile/Attribute.java
      index b9e3df8d2a2d3..e2f0072d3967f 100644
      --- a/src/java.base/share/classes/java/lang/classfile/Attribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/Attribute.java
      @@ -24,43 +24,8 @@
        */
       package java.lang.classfile;
       
      -import java.lang.classfile.attribute.AnnotationDefaultAttribute;
      -import java.lang.classfile.attribute.BootstrapMethodsAttribute;
      -import java.lang.classfile.attribute.CharacterRangeTableAttribute;
      -import java.lang.classfile.attribute.CodeAttribute;
      -import java.lang.classfile.attribute.CompilationIDAttribute;
      -import java.lang.classfile.attribute.ConstantValueAttribute;
      -import java.lang.classfile.attribute.DeprecatedAttribute;
      -import java.lang.classfile.attribute.EnclosingMethodAttribute;
      -import java.lang.classfile.attribute.ExceptionsAttribute;
      -import java.lang.classfile.attribute.InnerClassesAttribute;
      -import java.lang.classfile.attribute.LineNumberTableAttribute;
      -import java.lang.classfile.attribute.LocalVariableTableAttribute;
      -import java.lang.classfile.attribute.LocalVariableTypeTableAttribute;
      -import java.lang.classfile.attribute.MethodParametersAttribute;
      -import java.lang.classfile.attribute.ModuleAttribute;
      -import java.lang.classfile.attribute.ModuleHashesAttribute;
      -import java.lang.classfile.attribute.ModuleMainClassAttribute;
      -import java.lang.classfile.attribute.ModulePackagesAttribute;
      -import java.lang.classfile.attribute.ModuleResolutionAttribute;
      -import java.lang.classfile.attribute.ModuleTargetAttribute;
      -import java.lang.classfile.attribute.NestHostAttribute;
      -import java.lang.classfile.attribute.NestMembersAttribute;
      -import java.lang.classfile.attribute.PermittedSubclassesAttribute;
      -import java.lang.classfile.attribute.RecordAttribute;
      -import java.lang.classfile.attribute.RuntimeInvisibleAnnotationsAttribute;
      -import java.lang.classfile.attribute.RuntimeInvisibleParameterAnnotationsAttribute;
      -import java.lang.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute;
      -import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
      -import java.lang.classfile.attribute.RuntimeVisibleParameterAnnotationsAttribute;
      -import java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute;
      -import java.lang.classfile.attribute.SignatureAttribute;
      -import java.lang.classfile.attribute.SourceDebugExtensionAttribute;
      -import java.lang.classfile.attribute.SourceFileAttribute;
      -import java.lang.classfile.attribute.SourceIDAttribute;
      -import java.lang.classfile.attribute.StackMapTableAttribute;
      -import java.lang.classfile.attribute.SyntheticAttribute;
      -import java.lang.classfile.attribute.UnknownAttribute;
      +import java.lang.classfile.attribute.*;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/AttributedElement.java b/src/java.base/share/classes/java/lang/classfile/AttributedElement.java
      index 0caf231ec2a10..fb1bf817480e0 100644
      --- a/src/java.base/share/classes/java/lang/classfile/AttributedElement.java
      +++ b/src/java.base/share/classes/java/lang/classfile/AttributedElement.java
      @@ -24,12 +24,12 @@
        */
       package java.lang.classfile;
       
      +import java.lang.classfile.attribute.RecordComponentInfo;
       import java.util.ArrayList;
       import java.util.Collections;
       import java.util.List;
       import java.util.Optional;
       
      -import java.lang.classfile.attribute.RecordComponentInfo;
       import jdk.internal.classfile.impl.AbstractUnboundModel;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/Attributes.java b/src/java.base/share/classes/java/lang/classfile/Attributes.java
      index 1e91090f8afda..ad63eec75de39 100644
      --- a/src/java.base/share/classes/java/lang/classfile/Attributes.java
      +++ b/src/java.base/share/classes/java/lang/classfile/Attributes.java
      @@ -26,6 +26,7 @@
       
       import java.lang.classfile.AttributeMapper.AttributeStability;
       import java.lang.classfile.attribute.*;
      +
       import jdk.internal.classfile.impl.AbstractAttributeMapper.*;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/BootstrapMethodEntry.java b/src/java.base/share/classes/java/lang/classfile/BootstrapMethodEntry.java
      index 5ff3c449fe9ae..964976e0fd5ad 100644
      --- a/src/java.base/share/classes/java/lang/classfile/BootstrapMethodEntry.java
      +++ b/src/java.base/share/classes/java/lang/classfile/BootstrapMethodEntry.java
      @@ -25,11 +25,11 @@
       
       package java.lang.classfile;
       
      -import java.util.List;
      -
       import java.lang.classfile.constantpool.ConstantPool;
       import java.lang.classfile.constantpool.LoadableConstantEntry;
       import java.lang.classfile.constantpool.MethodHandleEntry;
      +import java.util.List;
      +
       import jdk.internal.classfile.impl.BootstrapMethodEntryImpl;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/BufWriter.java b/src/java.base/share/classes/java/lang/classfile/BufWriter.java
      index c71b44e7c0286..d60447c138843 100644
      --- a/src/java.base/share/classes/java/lang/classfile/BufWriter.java
      +++ b/src/java.base/share/classes/java/lang/classfile/BufWriter.java
      @@ -27,6 +27,7 @@
       import java.lang.classfile.constantpool.ConstantPool;
       import java.lang.classfile.constantpool.ConstantPoolBuilder;
       import java.lang.classfile.constantpool.PoolEntry;
      +
       import jdk.internal.classfile.impl.BufWriterImpl;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java b/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java
      index 905c7355c3406..71f1cc5319458 100644
      --- a/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java
      +++ b/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java
      @@ -25,22 +25,20 @@
       
       package java.lang.classfile;
       
      -
      +import java.lang.classfile.attribute.CodeAttribute;
      +import java.lang.classfile.constantpool.ClassEntry;
      +import java.lang.classfile.constantpool.Utf8Entry;
       import java.lang.constant.ClassDesc;
       import java.lang.constant.MethodTypeDesc;
      +import java.lang.reflect.AccessFlag;
       import java.util.Arrays;
       import java.util.List;
       import java.util.function.Consumer;
       
      -import java.lang.classfile.constantpool.ClassEntry;
      -import java.lang.classfile.constantpool.Utf8Entry;
      -
       import jdk.internal.classfile.impl.AccessFlagsImpl;
       import jdk.internal.classfile.impl.ChainedClassBuilder;
       import jdk.internal.classfile.impl.DirectClassBuilder;
       import jdk.internal.classfile.impl.Util;
      -import java.lang.reflect.AccessFlag;
      -import java.lang.classfile.attribute.CodeAttribute;
       import jdk.internal.javac.PreviewFeature;
       
       /**
      diff --git a/src/java.base/share/classes/java/lang/classfile/ClassElement.java b/src/java.base/share/classes/java/lang/classfile/ClassElement.java
      index 3852f7d12933a..6c918b7de4aab 100644
      --- a/src/java.base/share/classes/java/lang/classfile/ClassElement.java
      +++ b/src/java.base/share/classes/java/lang/classfile/ClassElement.java
      @@ -24,30 +24,8 @@
        */
       package java.lang.classfile;
       
      -import java.lang.classfile.attribute.CompilationIDAttribute;
      -import java.lang.classfile.attribute.DeprecatedAttribute;
      -import java.lang.classfile.attribute.EnclosingMethodAttribute;
      -import java.lang.classfile.attribute.InnerClassesAttribute;
      -import java.lang.classfile.attribute.ModuleAttribute;
      -import java.lang.classfile.attribute.ModuleHashesAttribute;
      -import java.lang.classfile.attribute.ModuleMainClassAttribute;
      -import java.lang.classfile.attribute.ModulePackagesAttribute;
      -import java.lang.classfile.attribute.ModuleResolutionAttribute;
      -import java.lang.classfile.attribute.ModuleTargetAttribute;
      -import java.lang.classfile.attribute.NestHostAttribute;
      -import java.lang.classfile.attribute.NestMembersAttribute;
      -import java.lang.classfile.attribute.PermittedSubclassesAttribute;
      -import java.lang.classfile.attribute.RecordAttribute;
      -import java.lang.classfile.attribute.RuntimeInvisibleAnnotationsAttribute;
      -import java.lang.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute;
      -import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
      -import java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute;
      -import java.lang.classfile.attribute.SignatureAttribute;
      -import java.lang.classfile.attribute.SourceDebugExtensionAttribute;
      -import java.lang.classfile.attribute.SourceFileAttribute;
      -import java.lang.classfile.attribute.SourceIDAttribute;
      -import java.lang.classfile.attribute.SyntheticAttribute;
      -import java.lang.classfile.attribute.UnknownAttribute;
      +import java.lang.classfile.attribute.*;
      +
       import jdk.internal.javac.PreviewFeature;
       
       /**
      diff --git a/src/java.base/share/classes/java/lang/classfile/ClassFile.java b/src/java.base/share/classes/java/lang/classfile/ClassFile.java
      index 284503ee62714..7051228c827b0 100644
      --- a/src/java.base/share/classes/java/lang/classfile/ClassFile.java
      +++ b/src/java.base/share/classes/java/lang/classfile/ClassFile.java
      @@ -25,27 +25,28 @@
       package java.lang.classfile;
       
       import java.io.IOException;
      +import java.lang.classfile.attribute.CharacterRangeInfo;
      +import java.lang.classfile.attribute.LocalVariableInfo;
      +import java.lang.classfile.attribute.LocalVariableTypeInfo;
      +import java.lang.classfile.attribute.ModuleAttribute;
      +import java.lang.classfile.constantpool.ClassEntry;
      +import java.lang.classfile.constantpool.ConstantPoolBuilder;
      +import java.lang.classfile.constantpool.Utf8Entry;
      +import java.lang.classfile.instruction.ExceptionCatch;
       import java.lang.constant.ClassDesc;
      +import java.lang.reflect.AccessFlag;
       import java.nio.file.Files;
       import java.nio.file.Path;
      +import java.util.List;
       import java.util.function.Consumer;
       import java.util.function.Function;
       
      -import java.lang.classfile.attribute.ModuleAttribute;
      -import java.lang.classfile.constantpool.ClassEntry;
      -import java.lang.classfile.constantpool.ConstantPoolBuilder;
      -import java.lang.classfile.constantpool.Utf8Entry;
       import jdk.internal.classfile.impl.ClassFileImpl;
       import jdk.internal.classfile.impl.TemporaryConstantPool;
      -import java.lang.reflect.AccessFlag;
      -import java.lang.classfile.attribute.CharacterRangeInfo;
      -import java.lang.classfile.attribute.LocalVariableInfo;
      -import java.lang.classfile.attribute.LocalVariableTypeInfo;
      -import java.lang.classfile.instruction.ExceptionCatch;
      -import java.util.List;
      +import jdk.internal.javac.PreviewFeature;
      +
       import static java.util.Objects.requireNonNull;
       import static jdk.internal.constant.ConstantUtils.CD_module_info;
      -import jdk.internal.javac.PreviewFeature;
       
       /**
        * Represents a context for parsing, transforming, and generating classfiles.
      diff --git a/src/java.base/share/classes/java/lang/classfile/ClassFileBuilder.java b/src/java.base/share/classes/java/lang/classfile/ClassFileBuilder.java
      index 56a2088370c6b..8b3f6544fff16 100644
      --- a/src/java.base/share/classes/java/lang/classfile/ClassFileBuilder.java
      +++ b/src/java.base/share/classes/java/lang/classfile/ClassFileBuilder.java
      @@ -24,11 +24,10 @@
        */
       package java.lang.classfile;
       
      +import java.lang.classfile.constantpool.ConstantPoolBuilder;
       import java.lang.constant.ClassDesc;
       import java.util.function.Consumer;
       
      -import java.lang.classfile.constantpool.ConstantPoolBuilder;
      -
       import jdk.internal.classfile.impl.TransformImpl;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/ClassFileTransform.java b/src/java.base/share/classes/java/lang/classfile/ClassFileTransform.java
      index 851f4deb03e92..b9c5210881cb9 100644
      --- a/src/java.base/share/classes/java/lang/classfile/ClassFileTransform.java
      +++ b/src/java.base/share/classes/java/lang/classfile/ClassFileTransform.java
      @@ -24,9 +24,9 @@
        */
       package java.lang.classfile;
       
      +import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
       import java.util.function.Supplier;
       
      -import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
       import jdk.internal.javac.PreviewFeature;
       
       /**
      diff --git a/src/java.base/share/classes/java/lang/classfile/ClassHierarchyResolver.java b/src/java.base/share/classes/java/lang/classfile/ClassHierarchyResolver.java
      index 3f16ce8402492..c2719e7aae062 100644
      --- a/src/java.base/share/classes/java/lang/classfile/ClassHierarchyResolver.java
      +++ b/src/java.base/share/classes/java/lang/classfile/ClassHierarchyResolver.java
      @@ -37,12 +37,11 @@
       import jdk.internal.classfile.impl.ClassHierarchyImpl.ClassLoadingClassHierarchyResolver;
       import jdk.internal.classfile.impl.ClassHierarchyImpl.StaticClassHierarchyResolver;
       import jdk.internal.classfile.impl.Util;
      +import jdk.internal.javac.PreviewFeature;
       
       import static java.lang.constant.ConstantDescs.CD_Object;
       import static java.util.Objects.requireNonNull;
       
      -import jdk.internal.javac.PreviewFeature;
      -
       /**
        * Provides class hierarchy information for generating correct stack maps
        * during code building.
      diff --git a/src/java.base/share/classes/java/lang/classfile/ClassModel.java b/src/java.base/share/classes/java/lang/classfile/ClassModel.java
      index c289f72f560f0..915b662b48838 100644
      --- a/src/java.base/share/classes/java/lang/classfile/ClassModel.java
      +++ b/src/java.base/share/classes/java/lang/classfile/ClassModel.java
      @@ -25,14 +25,12 @@
       
       package java.lang.classfile;
       
      +import java.lang.classfile.constantpool.ClassEntry;
      +import java.lang.classfile.constantpool.ConstantPool;
       import java.util.List;
       import java.util.Optional;
      -import java.util.function.Consumer;
       
      -import java.lang.classfile.constantpool.ClassEntry;
      -import java.lang.classfile.constantpool.ConstantPool;
       import jdk.internal.classfile.impl.ClassImpl;
      -import jdk.internal.classfile.impl.verifier.VerifierImpl;
       import jdk.internal.javac.PreviewFeature;
       
       /**
      diff --git a/src/java.base/share/classes/java/lang/classfile/ClassReader.java b/src/java.base/share/classes/java/lang/classfile/ClassReader.java
      index 735aae444fc0c..58ee2aae5e58e 100644
      --- a/src/java.base/share/classes/java/lang/classfile/ClassReader.java
      +++ b/src/java.base/share/classes/java/lang/classfile/ClassReader.java
      @@ -29,10 +29,10 @@
       import java.lang.classfile.constantpool.ConstantPoolException;
       import java.lang.classfile.constantpool.PoolEntry;
       import java.lang.classfile.constantpool.Utf8Entry;
      -import jdk.internal.classfile.impl.ClassReaderImpl;
      -
       import java.util.Optional;
       import java.util.function.Function;
      +
      +import jdk.internal.classfile.impl.ClassReaderImpl;
       import jdk.internal.javac.PreviewFeature;
       
       /**
      diff --git a/src/java.base/share/classes/java/lang/classfile/ClassSignature.java b/src/java.base/share/classes/java/lang/classfile/ClassSignature.java
      index 3b6b15f59f839..5a57144c4abce 100644
      --- a/src/java.base/share/classes/java/lang/classfile/ClassSignature.java
      +++ b/src/java.base/share/classes/java/lang/classfile/ClassSignature.java
      @@ -25,10 +25,12 @@
       package java.lang.classfile;
       
       import java.util.List;
      +
       import jdk.internal.classfile.impl.SignaturesImpl;
      -import static java.util.Objects.requireNonNull;
       import jdk.internal.javac.PreviewFeature;
       
      +import static java.util.Objects.requireNonNull;
      +
       /**
        * Models the generic signature of a class file, as defined by JVMS {@jvms 4.7.9}.
        *
      diff --git a/src/java.base/share/classes/java/lang/classfile/ClassTransform.java b/src/java.base/share/classes/java/lang/classfile/ClassTransform.java
      index 230b436b138ad..f512683a9b652 100644
      --- a/src/java.base/share/classes/java/lang/classfile/ClassTransform.java
      +++ b/src/java.base/share/classes/java/lang/classfile/ClassTransform.java
      @@ -24,11 +24,11 @@
        */
       package java.lang.classfile;
       
      +import java.lang.classfile.attribute.CodeAttribute;
       import java.util.function.Consumer;
       import java.util.function.Predicate;
       import java.util.function.Supplier;
       
      -import java.lang.classfile.attribute.CodeAttribute;
       import jdk.internal.classfile.impl.TransformImpl;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java
      index 7b27238bbdfae..11e83550d233d 100644
      --- a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java
      +++ b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java
      @@ -25,6 +25,8 @@
       
       package java.lang.classfile;
       
      +import java.lang.classfile.constantpool.*;
      +import java.lang.classfile.instruction.*;
       import java.lang.constant.ClassDesc;
       import java.lang.constant.ConstantDesc;
       import java.lang.constant.ConstantDescs;
      @@ -36,60 +38,12 @@
       import java.util.Optional;
       import java.util.function.Consumer;
       
      -import java.lang.classfile.constantpool.ClassEntry;
      -import java.lang.classfile.constantpool.FieldRefEntry;
      -import java.lang.classfile.constantpool.InterfaceMethodRefEntry;
      -import java.lang.classfile.constantpool.InvokeDynamicEntry;
      -import java.lang.classfile.constantpool.LoadableConstantEntry;
      -import java.lang.classfile.constantpool.MemberRefEntry;
      -import java.lang.classfile.constantpool.MethodRefEntry;
      -import java.lang.classfile.constantpool.MethodHandleEntry;
      -import java.lang.classfile.constantpool.NameAndTypeEntry;
      -import java.lang.classfile.constantpool.Utf8Entry;
      -import jdk.internal.classfile.impl.BlockCodeBuilderImpl;
      -import jdk.internal.classfile.impl.BytecodeHelpers;
      -import jdk.internal.classfile.impl.CatchBuilderImpl;
      -import jdk.internal.classfile.impl.ChainedCodeBuilder;
      -import jdk.internal.classfile.impl.LabelImpl;
      -import jdk.internal.classfile.impl.NonterminalCodeBuilder;
      -import jdk.internal.classfile.impl.TerminalCodeBuilder;
      -import java.lang.classfile.instruction.ArrayLoadInstruction;
      -import java.lang.classfile.instruction.ArrayStoreInstruction;
      -import java.lang.classfile.instruction.BranchInstruction;
      -import java.lang.classfile.instruction.CharacterRange;
      -import java.lang.classfile.instruction.ConstantInstruction;
      -import java.lang.classfile.instruction.ConvertInstruction;
      -import java.lang.classfile.instruction.ExceptionCatch;
      -import java.lang.classfile.instruction.FieldInstruction;
      -import java.lang.classfile.instruction.IncrementInstruction;
      -import java.lang.classfile.instruction.InvokeDynamicInstruction;
      -import java.lang.classfile.instruction.InvokeInstruction;
      -import java.lang.classfile.instruction.LineNumber;
      -import java.lang.classfile.instruction.LoadInstruction;
      -import java.lang.classfile.instruction.LocalVariable;
      -import java.lang.classfile.instruction.LocalVariableType;
      -import java.lang.classfile.instruction.LookupSwitchInstruction;
      -import java.lang.classfile.instruction.MonitorInstruction;
      -import java.lang.classfile.instruction.NewMultiArrayInstruction;
      -import java.lang.classfile.instruction.NewObjectInstruction;
      -import java.lang.classfile.instruction.NewPrimitiveArrayInstruction;
      -import java.lang.classfile.instruction.NewReferenceArrayInstruction;
      -import java.lang.classfile.instruction.NopInstruction;
      -import java.lang.classfile.instruction.OperatorInstruction;
      -import java.lang.classfile.instruction.ReturnInstruction;
      -import java.lang.classfile.instruction.StackInstruction;
      -import java.lang.classfile.instruction.StoreInstruction;
      -import java.lang.classfile.instruction.SwitchCase;
      -import java.lang.classfile.instruction.TableSwitchInstruction;
      -import java.lang.classfile.instruction.ThrowInstruction;
      -import java.lang.classfile.instruction.TypeCheckInstruction;
      +import jdk.internal.classfile.impl.*;
      +import jdk.internal.javac.PreviewFeature;
       
       import static java.util.Objects.requireNonNull;
       import static jdk.internal.classfile.impl.BytecodeHelpers.handleDescToHandleInfo;
       
      -import jdk.internal.classfile.impl.TransformImpl;
      -import jdk.internal.javac.PreviewFeature;
      -
       /**
        * A builder for code attributes (method bodies).  Builders are not created
        * directly; they are passed to handlers by methods such as {@link
      diff --git a/src/java.base/share/classes/java/lang/classfile/CodeElement.java b/src/java.base/share/classes/java/lang/classfile/CodeElement.java
      index cd4fafdd5bb9c..1cec4b8e6045f 100644
      --- a/src/java.base/share/classes/java/lang/classfile/CodeElement.java
      +++ b/src/java.base/share/classes/java/lang/classfile/CodeElement.java
      @@ -27,6 +27,7 @@
       import java.lang.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute;
       import java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute;
       import java.lang.classfile.attribute.StackMapTableAttribute;
      +
       import jdk.internal.javac.PreviewFeature;
       
       /**
      diff --git a/src/java.base/share/classes/java/lang/classfile/CodeModel.java b/src/java.base/share/classes/java/lang/classfile/CodeModel.java
      index ba816f2080581..759aacc18c94e 100644
      --- a/src/java.base/share/classes/java/lang/classfile/CodeModel.java
      +++ b/src/java.base/share/classes/java/lang/classfile/CodeModel.java
      @@ -25,13 +25,12 @@
       
       package java.lang.classfile;
       
      +import java.lang.classfile.attribute.CodeAttribute;
      +import java.lang.classfile.instruction.ExceptionCatch;
       import java.util.List;
       import java.util.Optional;
       
      -import java.lang.classfile.attribute.CodeAttribute;
       import jdk.internal.classfile.impl.BufferedCodeBuilder;
      -import jdk.internal.classfile.impl.CodeImpl;
      -import java.lang.classfile.instruction.ExceptionCatch;
       import jdk.internal.javac.PreviewFeature;
       
       /**
      diff --git a/src/java.base/share/classes/java/lang/classfile/CompoundElement.java b/src/java.base/share/classes/java/lang/classfile/CompoundElement.java
      index 9fcf02204cb13..5dfeac6f00d33 100644
      --- a/src/java.base/share/classes/java/lang/classfile/CompoundElement.java
      +++ b/src/java.base/share/classes/java/lang/classfile/CompoundElement.java
      @@ -33,6 +33,7 @@
       import java.util.function.Consumer;
       import java.util.stream.Stream;
       import java.util.stream.StreamSupport;
      +
       import jdk.internal.javac.PreviewFeature;
       
       /**
      diff --git a/src/java.base/share/classes/java/lang/classfile/FieldBuilder.java b/src/java.base/share/classes/java/lang/classfile/FieldBuilder.java
      index d9a8f6b2fc325..d318364465748 100644
      --- a/src/java.base/share/classes/java/lang/classfile/FieldBuilder.java
      +++ b/src/java.base/share/classes/java/lang/classfile/FieldBuilder.java
      @@ -26,13 +26,12 @@
       package java.lang.classfile;
       
       import java.lang.classfile.constantpool.Utf8Entry;
      +import java.lang.reflect.AccessFlag;
      +import java.util.function.Consumer;
       
       import jdk.internal.classfile.impl.AccessFlagsImpl;
       import jdk.internal.classfile.impl.ChainedFieldBuilder;
       import jdk.internal.classfile.impl.TerminalFieldBuilder;
      -import java.lang.reflect.AccessFlag;
      -
      -import java.util.function.Consumer;
       import jdk.internal.javac.PreviewFeature;
       
       /**
      diff --git a/src/java.base/share/classes/java/lang/classfile/FieldElement.java b/src/java.base/share/classes/java/lang/classfile/FieldElement.java
      index c41c9224bd39b..b4af99719818c 100644
      --- a/src/java.base/share/classes/java/lang/classfile/FieldElement.java
      +++ b/src/java.base/share/classes/java/lang/classfile/FieldElement.java
      @@ -24,15 +24,8 @@
        */
       package java.lang.classfile;
       
      -import java.lang.classfile.attribute.ConstantValueAttribute;
      -import java.lang.classfile.attribute.DeprecatedAttribute;
      -import java.lang.classfile.attribute.RuntimeInvisibleAnnotationsAttribute;
      -import java.lang.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute;
      -import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
      -import java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute;
      -import java.lang.classfile.attribute.SignatureAttribute;
      -import java.lang.classfile.attribute.SyntheticAttribute;
      -import java.lang.classfile.attribute.UnknownAttribute;
      +import java.lang.classfile.attribute.*;
      +
       import jdk.internal.javac.PreviewFeature;
       
       /**
      diff --git a/src/java.base/share/classes/java/lang/classfile/FieldModel.java b/src/java.base/share/classes/java/lang/classfile/FieldModel.java
      index 006103d5f9cbc..c45f3e88d5dcb 100644
      --- a/src/java.base/share/classes/java/lang/classfile/FieldModel.java
      +++ b/src/java.base/share/classes/java/lang/classfile/FieldModel.java
      @@ -25,10 +25,10 @@
       
       package java.lang.classfile;
       
      +import java.lang.classfile.constantpool.Utf8Entry;
       import java.lang.constant.ClassDesc;
       import java.util.Optional;
       
      -import java.lang.classfile.constantpool.Utf8Entry;
       import jdk.internal.classfile.impl.BufferedFieldBuilder;
       import jdk.internal.classfile.impl.FieldImpl;
       import jdk.internal.classfile.impl.Util;
      diff --git a/src/java.base/share/classes/java/lang/classfile/Instruction.java b/src/java.base/share/classes/java/lang/classfile/Instruction.java
      index 08255d8a5b106..210c1e1b0da7b 100644
      --- a/src/java.base/share/classes/java/lang/classfile/Instruction.java
      +++ b/src/java.base/share/classes/java/lang/classfile/Instruction.java
      @@ -25,32 +25,9 @@
       
       package java.lang.classfile;
       
      +import java.lang.classfile.instruction.*;
      +
       import jdk.internal.classfile.impl.AbstractInstruction;
      -import java.lang.classfile.instruction.ArrayLoadInstruction;
      -import java.lang.classfile.instruction.ArrayStoreInstruction;
      -import java.lang.classfile.instruction.BranchInstruction;
      -import java.lang.classfile.instruction.ConstantInstruction;
      -import java.lang.classfile.instruction.ConvertInstruction;
      -import java.lang.classfile.instruction.DiscontinuedInstruction;
      -import java.lang.classfile.instruction.FieldInstruction;
      -import java.lang.classfile.instruction.IncrementInstruction;
      -import java.lang.classfile.instruction.InvokeDynamicInstruction;
      -import java.lang.classfile.instruction.InvokeInstruction;
      -import java.lang.classfile.instruction.LoadInstruction;
      -import java.lang.classfile.instruction.LookupSwitchInstruction;
      -import java.lang.classfile.instruction.MonitorInstruction;
      -import java.lang.classfile.instruction.NewMultiArrayInstruction;
      -import java.lang.classfile.instruction.NewObjectInstruction;
      -import java.lang.classfile.instruction.NewPrimitiveArrayInstruction;
      -import java.lang.classfile.instruction.NewReferenceArrayInstruction;
      -import java.lang.classfile.instruction.NopInstruction;
      -import java.lang.classfile.instruction.OperatorInstruction;
      -import java.lang.classfile.instruction.ReturnInstruction;
      -import java.lang.classfile.instruction.StackInstruction;
      -import java.lang.classfile.instruction.StoreInstruction;
      -import java.lang.classfile.instruction.TableSwitchInstruction;
      -import java.lang.classfile.instruction.ThrowInstruction;
      -import java.lang.classfile.instruction.TypeCheckInstruction;
       import jdk.internal.javac.PreviewFeature;
       
       /**
      diff --git a/src/java.base/share/classes/java/lang/classfile/Interfaces.java b/src/java.base/share/classes/java/lang/classfile/Interfaces.java
      index 9092334bfb483..ff1dda17de8cd 100644
      --- a/src/java.base/share/classes/java/lang/classfile/Interfaces.java
      +++ b/src/java.base/share/classes/java/lang/classfile/Interfaces.java
      @@ -24,11 +24,11 @@
        */
       package java.lang.classfile;
       
      +import java.lang.classfile.constantpool.ClassEntry;
       import java.lang.constant.ClassDesc;
       import java.util.Arrays;
       import java.util.List;
       
      -import java.lang.classfile.constantpool.ClassEntry;
       import jdk.internal.classfile.impl.InterfacesImpl;
       import jdk.internal.classfile.impl.Util;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/MethodBuilder.java b/src/java.base/share/classes/java/lang/classfile/MethodBuilder.java
      index 7c230760f6934..6607d19b0acbe 100644
      --- a/src/java.base/share/classes/java/lang/classfile/MethodBuilder.java
      +++ b/src/java.base/share/classes/java/lang/classfile/MethodBuilder.java
      @@ -25,14 +25,13 @@
       
       package java.lang.classfile;
       
      -import java.util.function.Consumer;
      -
       import java.lang.classfile.constantpool.Utf8Entry;
      +import java.lang.reflect.AccessFlag;
      +import java.util.function.Consumer;
       
       import jdk.internal.classfile.impl.AccessFlagsImpl;
       import jdk.internal.classfile.impl.ChainedMethodBuilder;
       import jdk.internal.classfile.impl.TerminalMethodBuilder;
      -import java.lang.reflect.AccessFlag;
       import jdk.internal.javac.PreviewFeature;
       
       /**
      diff --git a/src/java.base/share/classes/java/lang/classfile/MethodElement.java b/src/java.base/share/classes/java/lang/classfile/MethodElement.java
      index a744952de7a99..dd23548c36022 100644
      --- a/src/java.base/share/classes/java/lang/classfile/MethodElement.java
      +++ b/src/java.base/share/classes/java/lang/classfile/MethodElement.java
      @@ -24,19 +24,8 @@
        */
       package java.lang.classfile;
       
      -import java.lang.classfile.attribute.AnnotationDefaultAttribute;
      -import java.lang.classfile.attribute.DeprecatedAttribute;
      -import java.lang.classfile.attribute.ExceptionsAttribute;
      -import java.lang.classfile.attribute.MethodParametersAttribute;
      -import java.lang.classfile.attribute.RuntimeInvisibleAnnotationsAttribute;
      -import java.lang.classfile.attribute.RuntimeInvisibleParameterAnnotationsAttribute;
      -import java.lang.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute;
      -import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
      -import java.lang.classfile.attribute.RuntimeVisibleParameterAnnotationsAttribute;
      -import java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute;
      -import java.lang.classfile.attribute.SignatureAttribute;
      -import java.lang.classfile.attribute.SyntheticAttribute;
      -import java.lang.classfile.attribute.UnknownAttribute;
      +import java.lang.classfile.attribute.*;
      +
       import jdk.internal.javac.PreviewFeature;
       
       /**
      diff --git a/src/java.base/share/classes/java/lang/classfile/MethodModel.java b/src/java.base/share/classes/java/lang/classfile/MethodModel.java
      index bd51f3c97d72e..568036e464d8b 100644
      --- a/src/java.base/share/classes/java/lang/classfile/MethodModel.java
      +++ b/src/java.base/share/classes/java/lang/classfile/MethodModel.java
      @@ -25,10 +25,10 @@
       
       package java.lang.classfile;
       
      +import java.lang.classfile.constantpool.Utf8Entry;
       import java.lang.constant.MethodTypeDesc;
       import java.util.Optional;
       
      -import java.lang.classfile.constantpool.Utf8Entry;
       import jdk.internal.classfile.impl.BufferedMethodBuilder;
       import jdk.internal.classfile.impl.MethodImpl;
       import jdk.internal.classfile.impl.Util;
      diff --git a/src/java.base/share/classes/java/lang/classfile/MethodSignature.java b/src/java.base/share/classes/java/lang/classfile/MethodSignature.java
      index 5e758b64be3f8..7235c368a4591 100644
      --- a/src/java.base/share/classes/java/lang/classfile/MethodSignature.java
      +++ b/src/java.base/share/classes/java/lang/classfile/MethodSignature.java
      @@ -26,11 +26,13 @@
       
       import java.lang.constant.MethodTypeDesc;
       import java.util.List;
      +
       import jdk.internal.classfile.impl.SignaturesImpl;
      -import static java.util.Objects.requireNonNull;
       import jdk.internal.classfile.impl.Util;
       import jdk.internal.javac.PreviewFeature;
       
      +import static java.util.Objects.requireNonNull;
      +
       /**
        * Models the generic signature of a method, as defined by JVMS {@jvms 4.7.9}.
        *
      diff --git a/src/java.base/share/classes/java/lang/classfile/PseudoInstruction.java b/src/java.base/share/classes/java/lang/classfile/PseudoInstruction.java
      index 8a2db569ba0c3..b152756acfd8d 100644
      --- a/src/java.base/share/classes/java/lang/classfile/PseudoInstruction.java
      +++ b/src/java.base/share/classes/java/lang/classfile/PseudoInstruction.java
      @@ -31,6 +31,7 @@
       import java.lang.classfile.instruction.LineNumber;
       import java.lang.classfile.instruction.LocalVariable;
       import java.lang.classfile.instruction.LocalVariableType;
      +
       import jdk.internal.classfile.impl.AbstractPseudoInstruction;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/Signature.java b/src/java.base/share/classes/java/lang/classfile/Signature.java
      index 739c3f1f3f397..7255a41528c01 100644
      --- a/src/java.base/share/classes/java/lang/classfile/Signature.java
      +++ b/src/java.base/share/classes/java/lang/classfile/Signature.java
      @@ -25,14 +25,15 @@
       package java.lang.classfile;
       
       import java.lang.constant.ClassDesc;
      -import jdk.internal.classfile.impl.SignaturesImpl;
      -
       import java.util.List;
      -import static java.util.Objects.requireNonNull;
       import java.util.Optional;
      +
      +import jdk.internal.classfile.impl.SignaturesImpl;
       import jdk.internal.classfile.impl.Util;
       import jdk.internal.javac.PreviewFeature;
       
      +import static java.util.Objects.requireNonNull;
      +
       /**
        * Models generic Java type signatures, as defined in JVMS {@jvms 4.7.9.1}.
        *
      diff --git a/src/java.base/share/classes/java/lang/classfile/Superclass.java b/src/java.base/share/classes/java/lang/classfile/Superclass.java
      index 70b18bb14d0e2..a69fac6341a11 100644
      --- a/src/java.base/share/classes/java/lang/classfile/Superclass.java
      +++ b/src/java.base/share/classes/java/lang/classfile/Superclass.java
      @@ -25,6 +25,7 @@
       package java.lang.classfile;
       
       import java.lang.classfile.constantpool.ClassEntry;
      +
       import jdk.internal.classfile.impl.SuperclassImpl;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java b/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java
      index 139c8eef835dc..38e5ea09a9328 100644
      --- a/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java
      +++ b/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java
      @@ -25,10 +25,10 @@
       
       package java.lang.classfile;
       
      -import java.util.List;
      -
       import java.lang.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute;
       import java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute;
      +import java.util.List;
      +
       import jdk.internal.classfile.impl.TargetInfoImpl;
       import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/TypeKind.java b/src/java.base/share/classes/java/lang/classfile/TypeKind.java
      index fdd8826f4eafd..bdbea7c8c54a3 100644
      --- a/src/java.base/share/classes/java/lang/classfile/TypeKind.java
      +++ b/src/java.base/share/classes/java/lang/classfile/TypeKind.java
      @@ -29,6 +29,7 @@
       import java.lang.constant.ClassDesc;
       import java.lang.constant.ConstantDescs;
       import java.lang.invoke.TypeDescriptor;
      +
       import jdk.internal.javac.PreviewFeature;
       import jdk.internal.vm.annotation.Stable;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/AnnotationDefaultAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/AnnotationDefaultAttribute.java
      index 018fcd65a34a9..4f147b0d63a47 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/AnnotationDefaultAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/AnnotationDefaultAttribute.java
      @@ -29,6 +29,7 @@
       import java.lang.classfile.Attribute;
       import java.lang.classfile.MethodElement;
       import java.lang.classfile.MethodModel;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.javac.PreviewFeature;
      @@ -66,5 +67,4 @@ public sealed interface AnnotationDefaultAttribute
           static AnnotationDefaultAttribute of(AnnotationValue annotationDefault) {
               return new UnboundAttribute.UnboundAnnotationDefaultAttribute(annotationDefault);
           }
      -
       }
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/BootstrapMethodsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/BootstrapMethodsAttribute.java
      index 7cc784af1f413..26ef1d3ddafc8 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/BootstrapMethodsAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/BootstrapMethodsAttribute.java
      @@ -25,11 +25,11 @@
       
       package java.lang.classfile.attribute;
       
      -import java.util.List;
      -
       import java.lang.classfile.Attribute;
       import java.lang.classfile.BootstrapMethodEntry;
       import java.lang.classfile.constantpool.ConstantPool;
      +import java.util.List;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeTableAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeTableAttribute.java
      index 7a8aac6b91e1a..a4b79be62f057 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeTableAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeTableAttribute.java
      @@ -25,9 +25,9 @@
       
       package java.lang.classfile.attribute;
       
      +import java.lang.classfile.Attribute;
       import java.util.List;
       
      -import java.lang.classfile.Attribute;
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/CodeAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/CodeAttribute.java
      index f0bab0fde110f..3342c2648ed93 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/CodeAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/CodeAttribute.java
      @@ -28,6 +28,7 @@
       import java.lang.classfile.Attribute;
       import java.lang.classfile.CodeModel;
       import java.lang.classfile.Label;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/CompilationIDAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/CompilationIDAttribute.java
      index ab6ab43c5aed4..292b449c628f1 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/CompilationIDAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/CompilationIDAttribute.java
      @@ -28,6 +28,7 @@
       import java.lang.classfile.Attribute;
       import java.lang.classfile.ClassElement;
       import java.lang.classfile.constantpool.Utf8Entry;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.TemporaryConstantPool;
       import jdk.internal.classfile.impl.UnboundAttribute;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ConstantValueAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ConstantValueAttribute.java
      index 390320c679c8a..cd87464855191 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/ConstantValueAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ConstantValueAttribute.java
      @@ -24,10 +24,11 @@
        */
       package java.lang.classfile.attribute;
       
      -import java.lang.constant.ConstantDesc;
       import java.lang.classfile.Attribute;
       import java.lang.classfile.FieldElement;
       import java.lang.classfile.constantpool.ConstantValueEntry;
      +import java.lang.constant.ConstantDesc;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.TemporaryConstantPool;
       import jdk.internal.classfile.impl.UnboundAttribute;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/DeprecatedAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/DeprecatedAttribute.java
      index f65f01f4e2a88..47c85c4b6c1d6 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/DeprecatedAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/DeprecatedAttribute.java
      @@ -28,6 +28,7 @@
       import java.lang.classfile.ClassElement;
       import java.lang.classfile.FieldElement;
       import java.lang.classfile.MethodElement;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/EnclosingMethodAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/EnclosingMethodAttribute.java
      index 2c91900850120..c760fdee04bbe 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/EnclosingMethodAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/EnclosingMethodAttribute.java
      @@ -24,15 +24,15 @@
        */
       package java.lang.classfile.attribute;
       
      -import java.lang.constant.ClassDesc;
      -import java.lang.constant.MethodTypeDesc;
      -import java.util.Optional;
      -
       import java.lang.classfile.Attribute;
       import java.lang.classfile.ClassElement;
       import java.lang.classfile.constantpool.ClassEntry;
       import java.lang.classfile.constantpool.NameAndTypeEntry;
       import java.lang.classfile.constantpool.Utf8Entry;
      +import java.lang.constant.ClassDesc;
      +import java.lang.constant.MethodTypeDesc;
      +import java.util.Optional;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.TemporaryConstantPool;
       import jdk.internal.classfile.impl.UnboundAttribute;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ExceptionsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ExceptionsAttribute.java
      index e12b9eb9fc3c7..91f07d94de90e 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/ExceptionsAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ExceptionsAttribute.java
      @@ -24,13 +24,13 @@
        */
       package java.lang.classfile.attribute;
       
      +import java.lang.classfile.Attribute;
      +import java.lang.classfile.MethodElement;
      +import java.lang.classfile.constantpool.ClassEntry;
       import java.lang.constant.ClassDesc;
       import java.util.Arrays;
       import java.util.List;
       
      -import java.lang.classfile.Attribute;
      -import java.lang.classfile.constantpool.ClassEntry;
      -import java.lang.classfile.MethodElement;
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.classfile.impl.Util;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassInfo.java
      index d6eaee796bae2..fca8cce7faae2 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassInfo.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassInfo.java
      @@ -24,13 +24,12 @@
        */
       package java.lang.classfile.attribute;
       
      -import java.lang.constant.ClassDesc;
      -import java.util.Optional;
      -import java.util.Set;
      -
       import java.lang.classfile.constantpool.ClassEntry;
       import java.lang.classfile.constantpool.Utf8Entry;
      +import java.lang.constant.ClassDesc;
       import java.lang.reflect.AccessFlag;
      +import java.util.Optional;
      +import java.util.Set;
       
       import jdk.internal.classfile.impl.TemporaryConstantPool;
       import jdk.internal.classfile.impl.UnboundAttribute;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassesAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassesAttribute.java
      index 0746d20b5b823..3b5d63822c498 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassesAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassesAttribute.java
      @@ -25,10 +25,10 @@
       
       package java.lang.classfile.attribute;
       
      -import java.util.List;
      -
       import java.lang.classfile.Attribute;
       import java.lang.classfile.ClassElement;
      +import java.util.List;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberTableAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberTableAttribute.java
      index a31f4919688b7..bb636a8113f73 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberTableAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberTableAttribute.java
      @@ -24,9 +24,9 @@
        */
       package java.lang.classfile.attribute;
       
      +import java.lang.classfile.Attribute;
       import java.util.List;
       
      -import java.lang.classfile.Attribute;
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableInfo.java
      index 0ef8542e05c55..177fc84248316 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableInfo.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableInfo.java
      @@ -24,8 +24,9 @@
        */
       package java.lang.classfile.attribute;
       
      -import java.lang.constant.ClassDesc;
       import java.lang.classfile.constantpool.Utf8Entry;
      +import java.lang.constant.ClassDesc;
      +
       import jdk.internal.classfile.impl.BoundLocalVariable;
       import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.classfile.impl.Util;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTableAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTableAttribute.java
      index 745b6d8e8e23f..ad4e732073e35 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTableAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTableAttribute.java
      @@ -25,10 +25,10 @@
       package java.lang.classfile.attribute;
       
       import java.lang.classfile.Attribute;
      +import java.util.List;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.UnboundAttribute;
      -
      -import java.util.List;
       import jdk.internal.javac.PreviewFeature;
       
       /**
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeInfo.java
      index e72c5984a370c..6ba5b409b5b72 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeInfo.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeInfo.java
      @@ -25,6 +25,7 @@
       package java.lang.classfile.attribute;
       
       import java.lang.classfile.constantpool.Utf8Entry;
      +
       import jdk.internal.classfile.impl.BoundLocalVariableType;
       import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeTableAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeTableAttribute.java
      index c2475530e6c53..084b72d68381a 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeTableAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeTableAttribute.java
      @@ -26,10 +26,10 @@
       package java.lang.classfile.attribute;
       
       import java.lang.classfile.Attribute;
      +import java.util.List;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.UnboundAttribute;
      -
      -import java.util.List;
       import jdk.internal.javac.PreviewFeature;
       
       /**
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/MethodParameterInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/MethodParameterInfo.java
      index e42caa74be356..b0961bf147691 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/MethodParameterInfo.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/MethodParameterInfo.java
      @@ -24,12 +24,12 @@
        */
       package java.lang.classfile.attribute;
       
      +import java.lang.classfile.ClassFile;
      +import java.lang.classfile.constantpool.Utf8Entry;
      +import java.lang.reflect.AccessFlag;
       import java.util.Optional;
       import java.util.Set;
       
      -import java.lang.classfile.constantpool.Utf8Entry;
      -import java.lang.reflect.AccessFlag;
      -import java.lang.classfile.ClassFile;
       import jdk.internal.classfile.impl.TemporaryConstantPool;
       import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.classfile.impl.Util;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/MethodParametersAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/MethodParametersAttribute.java
      index 81530086cdf3b..43a43d25bb733 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/MethodParametersAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/MethodParametersAttribute.java
      @@ -25,10 +25,10 @@
       
       package java.lang.classfile.attribute;
       
      -import java.util.List;
      -
       import java.lang.classfile.Attribute;
       import java.lang.classfile.MethodElement;
      +import java.util.List;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java
      index ec258611c70a1..7091bbd5c4276 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java
      @@ -24,24 +24,24 @@
        */
       package java.lang.classfile.attribute;
       
      -import java.lang.constant.ClassDesc;
      -import java.util.Collection;
       import java.lang.classfile.Attribute;
       import java.lang.classfile.ClassElement;
       import java.lang.classfile.constantpool.ClassEntry;
       import java.lang.classfile.constantpool.ModuleEntry;
       import java.lang.classfile.constantpool.Utf8Entry;
      -import jdk.internal.classfile.impl.BoundAttribute;
      -import jdk.internal.classfile.impl.UnboundAttribute;
      -
      +import java.lang.constant.ClassDesc;
      +import java.lang.constant.ModuleDesc;
      +import java.lang.constant.PackageDesc;
      +import java.lang.reflect.AccessFlag;
      +import java.util.Collection;
       import java.util.List;
       import java.util.Optional;
       import java.util.Set;
       import java.util.function.Consumer;
      -import java.lang.reflect.AccessFlag;
      -import java.lang.constant.ModuleDesc;
      -import java.lang.constant.PackageDesc;
      +
      +import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.ModuleAttributeBuilderImpl;
      +import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.classfile.impl.Util;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleExportInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleExportInfo.java
      index 88b446ab200ba..4a534894e9e16 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleExportInfo.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleExportInfo.java
      @@ -24,17 +24,16 @@
        */
       package java.lang.classfile.attribute;
       
      -import java.util.Collection;
      -import java.util.List;
      -import java.util.Set;
      -
      +import java.lang.classfile.ClassFile;
       import java.lang.classfile.constantpool.ModuleEntry;
       import java.lang.classfile.constantpool.PackageEntry;
       import java.lang.constant.ModuleDesc;
       import java.lang.constant.PackageDesc;
       import java.lang.reflect.AccessFlag;
      +import java.util.Collection;
      +import java.util.List;
      +import java.util.Set;
       
      -import java.lang.classfile.ClassFile;
       import jdk.internal.classfile.impl.TemporaryConstantPool;
       import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.classfile.impl.Util;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleHashInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleHashInfo.java
      index 88bb849db6fc2..0c85dd14125f9 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleHashInfo.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleHashInfo.java
      @@ -26,6 +26,7 @@
       
       import java.lang.classfile.constantpool.ModuleEntry;
       import java.lang.constant.ModuleDesc;
      +
       import jdk.internal.classfile.impl.TemporaryConstantPool;
       import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleHashesAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleHashesAttribute.java
      index d0ff0f8a1076b..0d2eb7014841c 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleHashesAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleHashesAttribute.java
      @@ -27,10 +27,9 @@
       
       import java.lang.classfile.Attribute;
       import java.lang.classfile.ClassElement;
      -
      +import java.lang.classfile.constantpool.Utf8Entry;
       import java.util.List;
       
      -import java.lang.classfile.constantpool.Utf8Entry;
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.TemporaryConstantPool;
       import jdk.internal.classfile.impl.UnboundAttribute;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleMainClassAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleMainClassAttribute.java
      index 91fe3c8f2d79c..67d6e5cc15c71 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleMainClassAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleMainClassAttribute.java
      @@ -25,10 +25,11 @@
       
       package java.lang.classfile.attribute;
       
      -import java.lang.constant.ClassDesc;
       import java.lang.classfile.Attribute;
       import java.lang.classfile.ClassElement;
       import java.lang.classfile.constantpool.ClassEntry;
      +import java.lang.constant.ClassDesc;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.TemporaryConstantPool;
       import jdk.internal.classfile.impl.UnboundAttribute;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleOpenInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleOpenInfo.java
      index 0fac2def865f6..7c5fe948d7807 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleOpenInfo.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleOpenInfo.java
      @@ -24,15 +24,14 @@
        */
       package java.lang.classfile.attribute;
       
      -import java.util.Collection;
      -import java.util.List;
      -import java.util.Set;
      -
       import java.lang.classfile.constantpool.ModuleEntry;
       import java.lang.classfile.constantpool.PackageEntry;
       import java.lang.constant.ModuleDesc;
       import java.lang.constant.PackageDesc;
       import java.lang.reflect.AccessFlag;
      +import java.util.Collection;
      +import java.util.List;
      +import java.util.Set;
       
       import jdk.internal.classfile.impl.TemporaryConstantPool;
       import jdk.internal.classfile.impl.UnboundAttribute;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModulePackagesAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModulePackagesAttribute.java
      index 30bc0e9827b5f..f2b34ad107dbe 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModulePackagesAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModulePackagesAttribute.java
      @@ -26,13 +26,12 @@
       
       import java.lang.classfile.Attribute;
       import java.lang.classfile.ClassElement;
      -import jdk.internal.classfile.impl.BoundAttribute;
      -
      +import java.lang.classfile.constantpool.PackageEntry;
      +import java.lang.constant.PackageDesc;
       import java.util.Arrays;
       import java.util.List;
       
      -import java.lang.classfile.constantpool.PackageEntry;
      -import java.lang.constant.PackageDesc;
      +import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.TemporaryConstantPool;
       import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleProvideInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleProvideInfo.java
      index eabdd735073e7..266c73de04f2b 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleProvideInfo.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleProvideInfo.java
      @@ -24,11 +24,11 @@
        */
       package java.lang.classfile.attribute;
       
      +import java.lang.classfile.constantpool.ClassEntry;
       import java.lang.constant.ClassDesc;
       import java.util.Arrays;
       import java.util.List;
       
      -import java.lang.classfile.constantpool.ClassEntry;
       import jdk.internal.classfile.impl.TemporaryConstantPool;
       import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.classfile.impl.Util;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleRequireInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleRequireInfo.java
      index 9220c9a6ce967..d072d0fead885 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleRequireInfo.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleRequireInfo.java
      @@ -24,14 +24,14 @@
        */
       package java.lang.classfile.attribute;
       
      +import java.lang.classfile.constantpool.ModuleEntry;
      +import java.lang.classfile.constantpool.Utf8Entry;
      +import java.lang.constant.ModuleDesc;
      +import java.lang.reflect.AccessFlag;
       import java.util.Collection;
       import java.util.Optional;
       import java.util.Set;
       
      -import java.lang.classfile.constantpool.ModuleEntry;
      -import java.lang.classfile.constantpool.Utf8Entry;
      -import java.lang.reflect.AccessFlag;
      -import java.lang.constant.ModuleDesc;
       import jdk.internal.classfile.impl.TemporaryConstantPool;
       import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.classfile.impl.Util;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleResolutionAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleResolutionAttribute.java
      index fcae1e8aac76c..a6b17fa404152 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleResolutionAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleResolutionAttribute.java
      @@ -27,6 +27,7 @@
       
       import java.lang.classfile.Attribute;
       import java.lang.classfile.ClassElement;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleTargetAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleTargetAttribute.java
      index 7086336547787..226412eccf34c 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleTargetAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleTargetAttribute.java
      @@ -28,6 +28,7 @@
       import java.lang.classfile.Attribute;
       import java.lang.classfile.ClassElement;
       import java.lang.classfile.constantpool.Utf8Entry;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.TemporaryConstantPool;
       import jdk.internal.classfile.impl.UnboundAttribute;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/NestHostAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/NestHostAttribute.java
      index 0961601e5d46d..6b69f9cbe080c 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/NestHostAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/NestHostAttribute.java
      @@ -25,10 +25,11 @@
       
       package java.lang.classfile.attribute;
       
      -import java.lang.constant.ClassDesc;
       import java.lang.classfile.Attribute;
       import java.lang.classfile.ClassElement;
       import java.lang.classfile.constantpool.ClassEntry;
      +import java.lang.constant.ClassDesc;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.TemporaryConstantPool;
       import jdk.internal.classfile.impl.UnboundAttribute;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/NestMembersAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/NestMembersAttribute.java
      index f184df7fff509..8826b4953a598 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/NestMembersAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/NestMembersAttribute.java
      @@ -24,13 +24,13 @@
        */
       package java.lang.classfile.attribute;
       
      +import java.lang.classfile.Attribute;
      +import java.lang.classfile.ClassElement;
      +import java.lang.classfile.constantpool.ClassEntry;
       import java.lang.constant.ClassDesc;
       import java.util.Arrays;
       import java.util.List;
       
      -import java.lang.classfile.Attribute;
      -import java.lang.classfile.ClassElement;
      -import java.lang.classfile.constantpool.ClassEntry;
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.classfile.impl.Util;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/PermittedSubclassesAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/PermittedSubclassesAttribute.java
      index 2d86d4d26e0a0..1242bc6e04543 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/PermittedSubclassesAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/PermittedSubclassesAttribute.java
      @@ -24,13 +24,13 @@
        */
       package java.lang.classfile.attribute;
       
      +import java.lang.classfile.Attribute;
      +import java.lang.classfile.ClassElement;
      +import java.lang.classfile.constantpool.ClassEntry;
       import java.lang.constant.ClassDesc;
       import java.util.Arrays;
       import java.util.List;
       
      -import java.lang.classfile.Attribute;
      -import java.lang.classfile.ClassElement;
      -import java.lang.classfile.constantpool.ClassEntry;
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.classfile.impl.Util;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RecordAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RecordAttribute.java
      index f79538a135cf9..7ef3b6f41b665 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/RecordAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RecordAttribute.java
      @@ -25,10 +25,10 @@
       
       package java.lang.classfile.attribute;
       
      -import java.util.List;
      -
       import java.lang.classfile.Attribute;
       import java.lang.classfile.ClassElement;
      +import java.util.List;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RecordComponentInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/RecordComponentInfo.java
      index 5a4c0d87b839a..ef6385653ed53 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/RecordComponentInfo.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RecordComponentInfo.java
      @@ -24,12 +24,12 @@
        */
       package java.lang.classfile.attribute;
       
      -import java.lang.constant.ClassDesc;
      -import java.util.List;
      -
       import java.lang.classfile.Attribute;
       import java.lang.classfile.AttributedElement;
       import java.lang.classfile.constantpool.Utf8Entry;
      +import java.lang.constant.ClassDesc;
      +import java.util.List;
      +
       import jdk.internal.classfile.impl.BoundRecordComponentInfo;
       import jdk.internal.classfile.impl.TemporaryConstantPool;
       import jdk.internal.classfile.impl.UnboundAttribute;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java
      index b467e8504fe06..05635af4beb4f 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java
      @@ -25,11 +25,15 @@
       
       package java.lang.classfile.attribute;
       
      -import java.lang.classfile.*;
      +import java.lang.classfile.Annotation;
      +import java.lang.classfile.Attribute;
      +import java.lang.classfile.ClassElement;
      +import java.lang.classfile.FieldElement;
      +import java.lang.classfile.MethodElement;
      +import java.util.List;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.UnboundAttribute;
      -
      -import java.util.List;
       import jdk.internal.javac.PreviewFeature;
       
       /**
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java
      index af495788afa45..edb82c49900ff 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java
      @@ -25,12 +25,12 @@
       
       package java.lang.classfile.attribute;
       
      -import java.util.List;
      -
       import java.lang.classfile.Annotation;
       import java.lang.classfile.Attribute;
       import java.lang.classfile.MethodElement;
       import java.lang.classfile.MethodModel;
      +import java.util.List;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java
      index 46dd2167541d9..df3a035d62099 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java
      @@ -25,14 +25,14 @@
       
       package java.lang.classfile.attribute;
       
      -import java.util.List;
      -
       import java.lang.classfile.Attribute;
       import java.lang.classfile.ClassElement;
       import java.lang.classfile.CodeElement;
       import java.lang.classfile.FieldElement;
       import java.lang.classfile.MethodElement;
       import java.lang.classfile.TypeAnnotation;
      +import java.util.List;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java
      index 4454dac62a95f..6909518881807 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java
      @@ -25,11 +25,15 @@
       
       package java.lang.classfile.attribute;
       
      -import java.lang.classfile.*;
      +import java.lang.classfile.Annotation;
      +import java.lang.classfile.Attribute;
      +import java.lang.classfile.ClassElement;
      +import java.lang.classfile.FieldElement;
      +import java.lang.classfile.MethodElement;
      +import java.util.List;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.UnboundAttribute;
      -
      -import java.util.List;
       import jdk.internal.javac.PreviewFeature;
       
       /**
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java
      index 59f648199ca49..ef58d21f14ac4 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java
      @@ -25,12 +25,12 @@
       
       package java.lang.classfile.attribute;
       
      -import java.util.List;
      -
       import java.lang.classfile.Annotation;
       import java.lang.classfile.Attribute;
       import java.lang.classfile.MethodElement;
       import java.lang.classfile.MethodModel;
      +import java.util.List;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java
      index 8bdf322803d83..20dc89d700cdd 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java
      @@ -25,14 +25,14 @@
       
       package java.lang.classfile.attribute;
       
      -import java.util.List;
      -
       import java.lang.classfile.Attribute;
       import java.lang.classfile.ClassElement;
       import java.lang.classfile.CodeElement;
       import java.lang.classfile.FieldElement;
       import java.lang.classfile.MethodElement;
       import java.lang.classfile.TypeAnnotation;
      +import java.util.List;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/SignatureAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/SignatureAttribute.java
      index 783b068c4e64c..ca4cc62852a5f 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/SignatureAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/SignatureAttribute.java
      @@ -25,15 +25,10 @@
       
       package java.lang.classfile.attribute;
       
      -import java.lang.classfile.Attribute;
      -import java.lang.classfile.ClassElement;
      -import java.lang.classfile.ClassSignature;
      -import java.lang.classfile.FieldElement;
      -import java.lang.classfile.MethodElement;
      +import java.lang.classfile.*;
       import java.lang.classfile.constantpool.Utf8Entry;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
      -import java.lang.classfile.MethodSignature;
      -import java.lang.classfile.Signature;
       import jdk.internal.classfile.impl.TemporaryConstantPool;
       import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/SourceDebugExtensionAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/SourceDebugExtensionAttribute.java
      index 719fb2d1171c1..e181b7fb14a2e 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/SourceDebugExtensionAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/SourceDebugExtensionAttribute.java
      @@ -27,6 +27,7 @@
       
       import java.lang.classfile.Attribute;
       import java.lang.classfile.ClassElement;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/SourceFileAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/SourceFileAttribute.java
      index abfa4eb05ffc9..d6c40058e7b74 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/SourceFileAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/SourceFileAttribute.java
      @@ -29,6 +29,7 @@
       import java.lang.classfile.ClassElement;
       import java.lang.classfile.ClassModel;
       import java.lang.classfile.constantpool.Utf8Entry;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.TemporaryConstantPool;
       import jdk.internal.classfile.impl.UnboundAttribute;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/SourceIDAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/SourceIDAttribute.java
      index a99a0bf49678c..69ff3bf57fd44 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/SourceIDAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/SourceIDAttribute.java
      @@ -29,6 +29,7 @@
       import java.lang.classfile.ClassElement;
       import java.lang.classfile.ClassModel;
       import java.lang.classfile.constantpool.Utf8Entry;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.TemporaryConstantPool;
       import jdk.internal.classfile.impl.UnboundAttribute;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java
      index 3415c89174ae9..d041a73c58a1c 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java
      @@ -25,11 +25,11 @@
       
       package java.lang.classfile.attribute;
       
      +import java.lang.classfile.Label;
      +import java.lang.classfile.constantpool.ClassEntry;
       import java.lang.constant.ClassDesc;
       import java.util.List;
       
      -import java.lang.classfile.Label;
      -import java.lang.classfile.constantpool.ClassEntry;
       import jdk.internal.classfile.impl.StackMapDecoder;
       import jdk.internal.classfile.impl.TemporaryConstantPool;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapTableAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapTableAttribute.java
      index 74dd567060eab..a8aef4795d78d 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapTableAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapTableAttribute.java
      @@ -25,10 +25,10 @@
       
       package java.lang.classfile.attribute;
       
      -import java.util.List;
      -
       import java.lang.classfile.Attribute;
       import java.lang.classfile.CodeElement;
      +import java.util.List;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/SyntheticAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/SyntheticAttribute.java
      index d1b7b8f0384dc..e5b5da7fbfe2e 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/SyntheticAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/SyntheticAttribute.java
      @@ -29,6 +29,7 @@
       import java.lang.classfile.ClassElement;
       import java.lang.classfile.FieldElement;
       import java.lang.classfile.MethodElement;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.UnboundAttribute;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/UnknownAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/UnknownAttribute.java
      index 4e66836fbdce1..5c1369e13080f 100644
      --- a/src/java.base/share/classes/java/lang/classfile/attribute/UnknownAttribute.java
      +++ b/src/java.base/share/classes/java/lang/classfile/attribute/UnknownAttribute.java
      @@ -29,6 +29,7 @@
       import java.lang.classfile.ClassElement;
       import java.lang.classfile.FieldElement;
       import java.lang.classfile.MethodElement;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/components/ClassPrinter.java b/src/java.base/share/classes/java/lang/classfile/components/ClassPrinter.java
      index c2e93a955ed45..85768cbe6a457 100644
      --- a/src/java.base/share/classes/java/lang/classfile/components/ClassPrinter.java
      +++ b/src/java.base/share/classes/java/lang/classfile/components/ClassPrinter.java
      @@ -24,16 +24,16 @@
        */
       package java.lang.classfile.components;
       
      +import java.lang.classfile.ClassModel;
      +import java.lang.classfile.CodeModel;
      +import java.lang.classfile.CompoundElement;
      +import java.lang.classfile.FieldModel;
      +import java.lang.classfile.MethodModel;
       import java.lang.constant.ConstantDesc;
       import java.util.List;
       import java.util.Map;
       import java.util.function.Consumer;
       import java.util.stream.Stream;
      -import java.lang.classfile.ClassModel;
      -import java.lang.classfile.FieldModel;
      -import java.lang.classfile.MethodModel;
      -import java.lang.classfile.CodeModel;
      -import java.lang.classfile.CompoundElement;
       
       import jdk.internal.classfile.impl.ClassPrinterImpl;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/components/ClassRemapper.java b/src/java.base/share/classes/java/lang/classfile/components/ClassRemapper.java
      index bcda36355870a..4f7bd3199d59d 100644
      --- a/src/java.base/share/classes/java/lang/classfile/components/ClassRemapper.java
      +++ b/src/java.base/share/classes/java/lang/classfile/components/ClassRemapper.java
      @@ -24,15 +24,16 @@
        */
       package java.lang.classfile.components;
       
      -import java.lang.constant.ClassDesc;
      -import java.util.Map;
      -import java.util.function.Function;
      +import java.lang.classfile.ClassFile;
       import java.lang.classfile.ClassModel;
       import java.lang.classfile.ClassTransform;
      -import java.lang.classfile.ClassFile;
       import java.lang.classfile.CodeTransform;
       import java.lang.classfile.FieldTransform;
       import java.lang.classfile.MethodTransform;
      +import java.lang.constant.ClassDesc;
      +import java.util.Map;
      +import java.util.function.Function;
      +
       import jdk.internal.classfile.impl.ClassRemapperImpl;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/components/CodeLocalsShifter.java b/src/java.base/share/classes/java/lang/classfile/components/CodeLocalsShifter.java
      index fa75e9f002b5e..4983872246102 100644
      --- a/src/java.base/share/classes/java/lang/classfile/components/CodeLocalsShifter.java
      +++ b/src/java.base/share/classes/java/lang/classfile/components/CodeLocalsShifter.java
      @@ -24,11 +24,12 @@
        */
       package java.lang.classfile.components;
       
      -import java.lang.constant.MethodTypeDesc;
      -import java.lang.reflect.AccessFlag;
       import java.lang.classfile.AccessFlags;
       import java.lang.classfile.CodeTransform;
       import java.lang.classfile.TypeKind;
      +import java.lang.constant.MethodTypeDesc;
      +import java.lang.reflect.AccessFlag;
      +
       import jdk.internal.classfile.impl.CodeLocalsShifterImpl;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/components/CodeRelabeler.java b/src/java.base/share/classes/java/lang/classfile/components/CodeRelabeler.java
      index 6ec3f9f792b72..247d712e4f382 100644
      --- a/src/java.base/share/classes/java/lang/classfile/components/CodeRelabeler.java
      +++ b/src/java.base/share/classes/java/lang/classfile/components/CodeRelabeler.java
      @@ -24,12 +24,13 @@
        */
       package java.lang.classfile.components;
       
      -import java.util.IdentityHashMap;
      -import java.util.Map;
      -import java.util.function.BiFunction;
       import java.lang.classfile.CodeBuilder;
       import java.lang.classfile.CodeTransform;
       import java.lang.classfile.Label;
      +import java.util.IdentityHashMap;
      +import java.util.Map;
      +import java.util.function.BiFunction;
      +
       import jdk.internal.classfile.impl.CodeRelabelerImpl;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/components/CodeStackTracker.java b/src/java.base/share/classes/java/lang/classfile/components/CodeStackTracker.java
      index 1b711cfad0ec3..1ee0b0948e112 100644
      --- a/src/java.base/share/classes/java/lang/classfile/components/CodeStackTracker.java
      +++ b/src/java.base/share/classes/java/lang/classfile/components/CodeStackTracker.java
      @@ -24,11 +24,12 @@
        */
       package java.lang.classfile.components;
       
      -import java.util.Collection;
      -import java.util.Optional;
       import java.lang.classfile.CodeTransform;
       import java.lang.classfile.Label;
       import java.lang.classfile.TypeKind;
      +import java.util.Collection;
      +import java.util.Optional;
      +
       import jdk.internal.classfile.impl.CodeStackTrackerImpl;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/components/snippet-files/PackageSnippets.java b/src/java.base/share/classes/java/lang/classfile/components/snippet-files/PackageSnippets.java
      index 2e7fb121a373b..87c2146a7acae 100644
      --- a/src/java.base/share/classes/java/lang/classfile/components/snippet-files/PackageSnippets.java
      +++ b/src/java.base/share/classes/java/lang/classfile/components/snippet-files/PackageSnippets.java
      @@ -24,32 +24,22 @@
        */
       package java.lang.classfile.components.snippets;
       
      +import java.lang.classfile.*;
      +import java.lang.classfile.components.ClassPrinter;
      +import java.lang.classfile.components.ClassRemapper;
      +import java.lang.classfile.components.CodeLocalsShifter;
      +import java.lang.classfile.components.CodeRelabeler;
      +import java.lang.classfile.instruction.InvokeInstruction;
      +import java.lang.classfile.instruction.ReturnInstruction;
      +import java.lang.classfile.instruction.StoreInstruction;
       import java.lang.constant.ClassDesc;
       import java.lang.constant.ConstantDesc;
      -
       import java.lang.constant.ConstantDescs;
       import java.lang.reflect.AccessFlag;
       import java.util.ArrayDeque;
       import java.util.Map;
       import java.util.function.Predicate;
       import java.util.stream.Collectors;
      -import java.lang.classfile.ClassFile;
      -import java.lang.classfile.ClassModel;
      -import java.lang.classfile.ClassTransform;
      -import java.lang.classfile.CodeModel;
      -import java.lang.classfile.CodeTransform;
      -import java.lang.classfile.FieldModel;
      -import java.lang.classfile.MethodModel;
      -import java.lang.classfile.TypeKind;
      -import java.lang.classfile.instruction.InvokeInstruction;
      -
      -import java.lang.classfile.MethodTransform;
      -import java.lang.classfile.components.ClassPrinter;
      -import java.lang.classfile.components.ClassRemapper;
      -import java.lang.classfile.components.CodeLocalsShifter;
      -import java.lang.classfile.components.CodeRelabeler;
      -import java.lang.classfile.instruction.ReturnInstruction;
      -import java.lang.classfile.instruction.StoreInstruction;
       
       class PackageSnippets {
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/AnnotationConstantValueEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/AnnotationConstantValueEntry.java
      index d405f68570ebe..6365fc3636a40 100644
      --- a/src/java.base/share/classes/java/lang/classfile/constantpool/AnnotationConstantValueEntry.java
      +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/AnnotationConstantValueEntry.java
      @@ -26,6 +26,7 @@
       
       import java.lang.classfile.AnnotationValue;
       import java.lang.constant.ConstantDesc;
      +
       import jdk.internal.javac.PreviewFeature;
       
       /**
      diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/ClassEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/ClassEntry.java
      index db2135c84f5d9..9e5f1f5204927 100644
      --- a/src/java.base/share/classes/java/lang/classfile/constantpool/ClassEntry.java
      +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/ClassEntry.java
      @@ -26,6 +26,7 @@
       
       import java.lang.constant.ClassDesc;
       import java.lang.constant.ConstantDesc;
      +
       import jdk.internal.classfile.impl.AbstractPoolEntry;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantDynamicEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantDynamicEntry.java
      index 507ff906274cb..7c55a09f3f4c8 100644
      --- a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantDynamicEntry.java
      +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantDynamicEntry.java
      @@ -25,13 +25,12 @@
       package java.lang.classfile.constantpool;
       
       import java.lang.classfile.TypeKind;
      -import jdk.internal.classfile.impl.Util;
      -
       import java.lang.constant.ClassDesc;
       import java.lang.constant.ConstantDesc;
       import java.lang.constant.DynamicConstantDesc;
       
       import jdk.internal.classfile.impl.AbstractPoolEntry;
      +import jdk.internal.classfile.impl.Util;
       import jdk.internal.javac.PreviewFeature;
       
       /**
      diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPool.java b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPool.java
      index ef6f75955b29e..0225f6ec77d8c 100644
      --- a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPool.java
      +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPool.java
      @@ -25,10 +25,11 @@
       
       package java.lang.classfile.constantpool;
       
      -import java.util.Iterator;
      -import java.util.NoSuchElementException;
       import java.lang.classfile.BootstrapMethodEntry;
       import java.lang.classfile.ClassReader;
      +import java.util.Iterator;
      +import java.util.NoSuchElementException;
      +
       import jdk.internal.javac.PreviewFeature;
       
       /**
      diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java
      index 12c9789133bb4..0ce4a6868c86a 100644
      --- a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java
      +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java
      @@ -24,26 +24,19 @@
        */
       package java.lang.classfile.constantpool;
       
      -import java.lang.constant.ClassDesc;
      -import java.lang.constant.ConstantDesc;
      -import java.lang.constant.DirectMethodHandleDesc;
      -import java.lang.constant.DynamicCallSiteDesc;
      -import java.lang.constant.DynamicConstantDesc;
      -import java.lang.constant.MethodTypeDesc;
      -import java.util.List;
      -
       import java.lang.classfile.BootstrapMethodEntry;
       import java.lang.classfile.ClassBuilder;
       import java.lang.classfile.ClassModel;
      -import jdk.internal.classfile.impl.ClassReaderImpl;
      -import java.lang.constant.ModuleDesc;
      -import java.lang.constant.PackageDesc;
      +import java.lang.constant.*;
      +import java.util.List;
      +
       import jdk.internal.classfile.impl.AbstractPoolEntry.ClassEntryImpl;
      -import jdk.internal.classfile.impl.AbstractPoolEntry.NameAndTypeEntryImpl;
      +import jdk.internal.classfile.impl.ClassReaderImpl;
       import jdk.internal.classfile.impl.SplitConstantPool;
       import jdk.internal.classfile.impl.TemporaryConstantPool;
       import jdk.internal.classfile.impl.Util;
       import jdk.internal.javac.PreviewFeature;
      +
       import static java.util.Objects.requireNonNull;
       
       /**
      diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantValueEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantValueEntry.java
      index 720e3fd5d5cc4..924d0aca71080 100644
      --- a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantValueEntry.java
      +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantValueEntry.java
      @@ -26,6 +26,7 @@
       
       import java.lang.classfile.Attributes;
       import java.lang.constant.ConstantDesc;
      +
       import jdk.internal.javac.PreviewFeature;
       
       /**
      diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/DoubleEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/DoubleEntry.java
      index 391dcf021eb4b..8dd4ba1ffd934 100644
      --- a/src/java.base/share/classes/java/lang/classfile/constantpool/DoubleEntry.java
      +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/DoubleEntry.java
      @@ -25,6 +25,7 @@
       package java.lang.classfile.constantpool;
       
       import java.lang.classfile.TypeKind;
      +
       import jdk.internal.classfile.impl.AbstractPoolEntry;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/DynamicConstantPoolEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/DynamicConstantPoolEntry.java
      index 41ed4b298047f..ac7630494100c 100644
      --- a/src/java.base/share/classes/java/lang/classfile/constantpool/DynamicConstantPoolEntry.java
      +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/DynamicConstantPoolEntry.java
      @@ -25,6 +25,7 @@
       package java.lang.classfile.constantpool;
       
       import java.lang.classfile.BootstrapMethodEntry;
      +
       import jdk.internal.javac.PreviewFeature;
       
       /**
      diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/FieldRefEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/FieldRefEntry.java
      index 75533770b3524..ab122f410b699 100644
      --- a/src/java.base/share/classes/java/lang/classfile/constantpool/FieldRefEntry.java
      +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/FieldRefEntry.java
      @@ -24,10 +24,11 @@
        */
       package java.lang.classfile.constantpool;
       
      +import java.lang.constant.ClassDesc;
      +
       import jdk.internal.classfile.impl.AbstractPoolEntry;
       import jdk.internal.classfile.impl.Util;
       import jdk.internal.javac.PreviewFeature;
      -import java.lang.constant.ClassDesc;
       
       /**
        * Models a {@code CONSTANT_Fieldref_info} constant in the constant pool of a
      diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/FloatEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/FloatEntry.java
      index d84cc903ea5ea..7a91dd111530f 100644
      --- a/src/java.base/share/classes/java/lang/classfile/constantpool/FloatEntry.java
      +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/FloatEntry.java
      @@ -25,6 +25,7 @@
       package java.lang.classfile.constantpool;
       
       import java.lang.classfile.TypeKind;
      +
       import jdk.internal.classfile.impl.AbstractPoolEntry;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/IntegerEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/IntegerEntry.java
      index 807ce188a6acb..7cd21e37db824 100644
      --- a/src/java.base/share/classes/java/lang/classfile/constantpool/IntegerEntry.java
      +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/IntegerEntry.java
      @@ -25,6 +25,7 @@
       package java.lang.classfile.constantpool;
       
       import java.lang.classfile.TypeKind;
      +
       import jdk.internal.classfile.impl.AbstractPoolEntry;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/InterfaceMethodRefEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/InterfaceMethodRefEntry.java
      index b97defdc1e148..8f15053e5b705 100644
      --- a/src/java.base/share/classes/java/lang/classfile/constantpool/InterfaceMethodRefEntry.java
      +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/InterfaceMethodRefEntry.java
      @@ -24,10 +24,11 @@
        */
       package java.lang.classfile.constantpool;
       
      +import java.lang.constant.MethodTypeDesc;
      +
       import jdk.internal.classfile.impl.AbstractPoolEntry;
       import jdk.internal.classfile.impl.Util;
       import jdk.internal.javac.PreviewFeature;
      -import java.lang.constant.MethodTypeDesc;
       
       /**
        * Models a {@code CONSTANT_InterfaceMethodRef_info} constant in the constant pool of a
      diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/LoadableConstantEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/LoadableConstantEntry.java
      index 6ae8e68787eaf..c963e2425eac4 100644
      --- a/src/java.base/share/classes/java/lang/classfile/constantpool/LoadableConstantEntry.java
      +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/LoadableConstantEntry.java
      @@ -24,8 +24,9 @@
        */
       package java.lang.classfile.constantpool;
       
      -import java.lang.constant.ConstantDesc;
       import java.lang.classfile.TypeKind;
      +import java.lang.constant.ConstantDesc;
      +
       import jdk.internal.javac.PreviewFeature;
       
       /**
      diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/LongEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/LongEntry.java
      index 975df03f04343..75e02b1944192 100644
      --- a/src/java.base/share/classes/java/lang/classfile/constantpool/LongEntry.java
      +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/LongEntry.java
      @@ -25,6 +25,7 @@
       package java.lang.classfile.constantpool;
       
       import java.lang.classfile.TypeKind;
      +
       import jdk.internal.classfile.impl.AbstractPoolEntry;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/MethodRefEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/MethodRefEntry.java
      index 3ff8dfdc0f462..ff3f5e5220ccd 100644
      --- a/src/java.base/share/classes/java/lang/classfile/constantpool/MethodRefEntry.java
      +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/MethodRefEntry.java
      @@ -24,10 +24,11 @@
        */
       package java.lang.classfile.constantpool;
       
      +import java.lang.constant.MethodTypeDesc;
      +
       import jdk.internal.classfile.impl.AbstractPoolEntry;
       import jdk.internal.classfile.impl.Util;
       import jdk.internal.javac.PreviewFeature;
      -import java.lang.constant.MethodTypeDesc;
       
       /**
        * Models a {@code CONSTANT_MethodRef_info} constant in the constant pool of a
      diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/ModuleEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/ModuleEntry.java
      index cbddf6b90e3a4..db7aa1f76fe1a 100644
      --- a/src/java.base/share/classes/java/lang/classfile/constantpool/ModuleEntry.java
      +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/ModuleEntry.java
      @@ -24,8 +24,9 @@
        */
       package java.lang.classfile.constantpool;
       
      -import jdk.internal.classfile.impl.AbstractPoolEntry;
       import java.lang.constant.ModuleDesc;
      +
      +import jdk.internal.classfile.impl.AbstractPoolEntry;
       import jdk.internal.javac.PreviewFeature;
       
       /**
      diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/PackageEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/PackageEntry.java
      index 1817aa647d4aa..5725d411028c1 100644
      --- a/src/java.base/share/classes/java/lang/classfile/constantpool/PackageEntry.java
      +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/PackageEntry.java
      @@ -24,8 +24,9 @@
        */
       package java.lang.classfile.constantpool;
       
      -import jdk.internal.classfile.impl.AbstractPoolEntry;
       import java.lang.constant.PackageDesc;
      +
      +import jdk.internal.classfile.impl.AbstractPoolEntry;
       import jdk.internal.javac.PreviewFeature;
       
       /**
      diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/ArrayLoadInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/ArrayLoadInstruction.java
      index e773d2da2ccae..b66627ef212a6 100644
      --- a/src/java.base/share/classes/java/lang/classfile/instruction/ArrayLoadInstruction.java
      +++ b/src/java.base/share/classes/java/lang/classfile/instruction/ArrayLoadInstruction.java
      @@ -29,6 +29,7 @@
       import java.lang.classfile.Instruction;
       import java.lang.classfile.Opcode;
       import java.lang.classfile.TypeKind;
      +
       import jdk.internal.classfile.impl.AbstractInstruction;
       import jdk.internal.classfile.impl.Util;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/ArrayStoreInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/ArrayStoreInstruction.java
      index 9b9ec6018d1f2..f009cfca36129 100644
      --- a/src/java.base/share/classes/java/lang/classfile/instruction/ArrayStoreInstruction.java
      +++ b/src/java.base/share/classes/java/lang/classfile/instruction/ArrayStoreInstruction.java
      @@ -29,6 +29,7 @@
       import java.lang.classfile.Instruction;
       import java.lang.classfile.Opcode;
       import java.lang.classfile.TypeKind;
      +
       import jdk.internal.classfile.impl.AbstractInstruction;
       import jdk.internal.classfile.impl.Util;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/BranchInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/BranchInstruction.java
      index 6ee47b7fbc2c1..6b2142fa0e101 100644
      --- a/src/java.base/share/classes/java/lang/classfile/instruction/BranchInstruction.java
      +++ b/src/java.base/share/classes/java/lang/classfile/instruction/BranchInstruction.java
      @@ -29,6 +29,7 @@
       import java.lang.classfile.Instruction;
       import java.lang.classfile.Label;
       import java.lang.classfile.Opcode;
      +
       import jdk.internal.classfile.impl.AbstractInstruction;
       import jdk.internal.classfile.impl.Util;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/CharacterRange.java b/src/java.base/share/classes/java/lang/classfile/instruction/CharacterRange.java
      index fca3279cd2228..3d04473ab3750 100644
      --- a/src/java.base/share/classes/java/lang/classfile/instruction/CharacterRange.java
      +++ b/src/java.base/share/classes/java/lang/classfile/instruction/CharacterRange.java
      @@ -31,6 +31,7 @@
       import java.lang.classfile.PseudoInstruction;
       import java.lang.classfile.attribute.CharacterRangeInfo;
       import java.lang.classfile.attribute.CharacterRangeTableAttribute;
      +
       import jdk.internal.classfile.impl.AbstractPseudoInstruction;
       import jdk.internal.classfile.impl.BoundCharacterRange;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/ConstantInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/ConstantInstruction.java
      index 6f07805a1e81c..c41793c614e7f 100644
      --- a/src/java.base/share/classes/java/lang/classfile/instruction/ConstantInstruction.java
      +++ b/src/java.base/share/classes/java/lang/classfile/instruction/ConstantInstruction.java
      @@ -24,14 +24,14 @@
        */
       package java.lang.classfile.instruction;
       
      -import java.lang.constant.ConstantDesc;
      -
       import java.lang.classfile.CodeElement;
       import java.lang.classfile.CodeModel;
       import java.lang.classfile.Instruction;
       import java.lang.classfile.Opcode;
       import java.lang.classfile.TypeKind;
       import java.lang.classfile.constantpool.LoadableConstantEntry;
      +import java.lang.constant.ConstantDesc;
      +
       import jdk.internal.classfile.impl.AbstractInstruction;
       import jdk.internal.classfile.impl.BytecodeHelpers;
       import jdk.internal.classfile.impl.Util;
      diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/ConvertInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/ConvertInstruction.java
      index daa7e60248470..ec48c2f46639f 100644
      --- a/src/java.base/share/classes/java/lang/classfile/instruction/ConvertInstruction.java
      +++ b/src/java.base/share/classes/java/lang/classfile/instruction/ConvertInstruction.java
      @@ -29,6 +29,7 @@
       import java.lang.classfile.Instruction;
       import java.lang.classfile.Opcode;
       import java.lang.classfile.TypeKind;
      +
       import jdk.internal.classfile.impl.AbstractInstruction;
       import jdk.internal.classfile.impl.BytecodeHelpers;
       import jdk.internal.classfile.impl.Util;
      diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/DiscontinuedInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/DiscontinuedInstruction.java
      index fc87dd274d36e..0e4718a1c77c8 100644
      --- a/src/java.base/share/classes/java/lang/classfile/instruction/DiscontinuedInstruction.java
      +++ b/src/java.base/share/classes/java/lang/classfile/instruction/DiscontinuedInstruction.java
      @@ -29,6 +29,7 @@
       import java.lang.classfile.Instruction;
       import java.lang.classfile.Label;
       import java.lang.classfile.Opcode;
      +
       import jdk.internal.classfile.impl.AbstractInstruction;
       import jdk.internal.classfile.impl.BytecodeHelpers;
       import jdk.internal.classfile.impl.Util;
      diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/ExceptionCatch.java b/src/java.base/share/classes/java/lang/classfile/instruction/ExceptionCatch.java
      index 9ed851fff88ed..22b6f632abcf3 100644
      --- a/src/java.base/share/classes/java/lang/classfile/instruction/ExceptionCatch.java
      +++ b/src/java.base/share/classes/java/lang/classfile/instruction/ExceptionCatch.java
      @@ -24,13 +24,13 @@
        */
       package java.lang.classfile.instruction;
       
      -import java.util.Optional;
      -
       import java.lang.classfile.CodeElement;
       import java.lang.classfile.CodeModel;
      -import java.lang.classfile.constantpool.ClassEntry;
       import java.lang.classfile.Label;
       import java.lang.classfile.PseudoInstruction;
      +import java.lang.classfile.constantpool.ClassEntry;
      +import java.util.Optional;
      +
       import jdk.internal.classfile.impl.AbstractPseudoInstruction;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/FieldInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/FieldInstruction.java
      index 43dbcccf75eaa..c8a82fe7dfa89 100644
      --- a/src/java.base/share/classes/java/lang/classfile/instruction/FieldInstruction.java
      +++ b/src/java.base/share/classes/java/lang/classfile/instruction/FieldInstruction.java
      @@ -24,16 +24,16 @@
        */
       package java.lang.classfile.instruction;
       
      -import java.lang.constant.ClassDesc;
      -
       import java.lang.classfile.CodeElement;
       import java.lang.classfile.CodeModel;
      -import java.lang.classfile.constantpool.ClassEntry;
       import java.lang.classfile.Instruction;
       import java.lang.classfile.Opcode;
      +import java.lang.classfile.constantpool.ClassEntry;
       import java.lang.classfile.constantpool.FieldRefEntry;
       import java.lang.classfile.constantpool.NameAndTypeEntry;
       import java.lang.classfile.constantpool.Utf8Entry;
      +import java.lang.constant.ClassDesc;
      +
       import jdk.internal.classfile.impl.AbstractInstruction;
       import jdk.internal.classfile.impl.TemporaryConstantPool;
       import jdk.internal.classfile.impl.Util;
      diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/IncrementInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/IncrementInstruction.java
      index bebb101d7f326..74fd6a4465a1f 100644
      --- a/src/java.base/share/classes/java/lang/classfile/instruction/IncrementInstruction.java
      +++ b/src/java.base/share/classes/java/lang/classfile/instruction/IncrementInstruction.java
      @@ -28,6 +28,7 @@
       import java.lang.classfile.CodeModel;
       import java.lang.classfile.Instruction;
       import java.lang.classfile.Opcode;
      +
       import jdk.internal.classfile.impl.AbstractInstruction;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/InvokeDynamicInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/InvokeDynamicInstruction.java
      index 708b284c0bf57..6df960b88fab8 100644
      --- a/src/java.base/share/classes/java/lang/classfile/instruction/InvokeDynamicInstruction.java
      +++ b/src/java.base/share/classes/java/lang/classfile/instruction/InvokeDynamicInstruction.java
      @@ -24,18 +24,18 @@
        */
       package java.lang.classfile.instruction;
       
      -import java.lang.constant.ConstantDesc;
      -import java.lang.constant.DirectMethodHandleDesc;
      -import java.lang.constant.MethodTypeDesc;
      -import java.util.List;
      -import java.util.function.Function;
      -
       import java.lang.classfile.CodeElement;
       import java.lang.classfile.CodeModel;
       import java.lang.classfile.Instruction;
       import java.lang.classfile.constantpool.InvokeDynamicEntry;
       import java.lang.classfile.constantpool.LoadableConstantEntry;
       import java.lang.classfile.constantpool.Utf8Entry;
      +import java.lang.constant.ConstantDesc;
      +import java.lang.constant.DirectMethodHandleDesc;
      +import java.lang.constant.MethodTypeDesc;
      +import java.util.List;
      +import java.util.function.Function;
      +
       import jdk.internal.classfile.impl.AbstractInstruction;
       import jdk.internal.classfile.impl.Util;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/InvokeInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/InvokeInstruction.java
      index 74b8dc942a271..41ca5fd1519ef 100644
      --- a/src/java.base/share/classes/java/lang/classfile/instruction/InvokeInstruction.java
      +++ b/src/java.base/share/classes/java/lang/classfile/instruction/InvokeInstruction.java
      @@ -24,18 +24,18 @@
        */
       package java.lang.classfile.instruction;
       
      -import java.lang.constant.MethodTypeDesc;
      -
       import java.lang.classfile.CodeElement;
       import java.lang.classfile.CodeModel;
      -import java.lang.classfile.constantpool.ClassEntry;
       import java.lang.classfile.Instruction;
       import java.lang.classfile.Opcode;
      +import java.lang.classfile.constantpool.ClassEntry;
       import java.lang.classfile.constantpool.InterfaceMethodRefEntry;
       import java.lang.classfile.constantpool.MemberRefEntry;
       import java.lang.classfile.constantpool.MethodRefEntry;
       import java.lang.classfile.constantpool.NameAndTypeEntry;
       import java.lang.classfile.constantpool.Utf8Entry;
      +import java.lang.constant.MethodTypeDesc;
      +
       import jdk.internal.classfile.impl.AbstractInstruction;
       import jdk.internal.classfile.impl.TemporaryConstantPool;
       import jdk.internal.classfile.impl.Util;
      diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/LabelTarget.java b/src/java.base/share/classes/java/lang/classfile/instruction/LabelTarget.java
      index 80b3ea4785d90..8682d0ee508e6 100644
      --- a/src/java.base/share/classes/java/lang/classfile/instruction/LabelTarget.java
      +++ b/src/java.base/share/classes/java/lang/classfile/instruction/LabelTarget.java
      @@ -28,6 +28,7 @@
       import java.lang.classfile.CodeModel;
       import java.lang.classfile.Label;
       import java.lang.classfile.PseudoInstruction;
      +
       import jdk.internal.classfile.impl.LabelImpl;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/LineNumber.java b/src/java.base/share/classes/java/lang/classfile/instruction/LineNumber.java
      index 3990fe1f5e286..a06e7cfcebac2 100644
      --- a/src/java.base/share/classes/java/lang/classfile/instruction/LineNumber.java
      +++ b/src/java.base/share/classes/java/lang/classfile/instruction/LineNumber.java
      @@ -29,6 +29,7 @@
       import java.lang.classfile.CodeModel;
       import java.lang.classfile.PseudoInstruction;
       import java.lang.classfile.attribute.LineNumberTableAttribute;
      +
       import jdk.internal.classfile.impl.LineNumberImpl;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/LoadInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/LoadInstruction.java
      index ea10ba6a0d0fb..ce6463ef92478 100644
      --- a/src/java.base/share/classes/java/lang/classfile/instruction/LoadInstruction.java
      +++ b/src/java.base/share/classes/java/lang/classfile/instruction/LoadInstruction.java
      @@ -29,6 +29,7 @@
       import java.lang.classfile.Instruction;
       import java.lang.classfile.Opcode;
       import java.lang.classfile.TypeKind;
      +
       import jdk.internal.classfile.impl.AbstractInstruction;
       import jdk.internal.classfile.impl.BytecodeHelpers;
       import jdk.internal.classfile.impl.Util;
      diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/LookupSwitchInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/LookupSwitchInstruction.java
      index 6ddbbde8cea86..ce6c0cce10999 100644
      --- a/src/java.base/share/classes/java/lang/classfile/instruction/LookupSwitchInstruction.java
      +++ b/src/java.base/share/classes/java/lang/classfile/instruction/LookupSwitchInstruction.java
      @@ -24,12 +24,12 @@
        */
       package java.lang.classfile.instruction;
       
      -import java.util.List;
      -
       import java.lang.classfile.CodeElement;
       import java.lang.classfile.CodeModel;
       import java.lang.classfile.Instruction;
       import java.lang.classfile.Label;
      +import java.util.List;
      +
       import jdk.internal.classfile.impl.AbstractInstruction;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/MonitorInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/MonitorInstruction.java
      index d0148b34aee65..9bec7805339d2 100644
      --- a/src/java.base/share/classes/java/lang/classfile/instruction/MonitorInstruction.java
      +++ b/src/java.base/share/classes/java/lang/classfile/instruction/MonitorInstruction.java
      @@ -28,6 +28,7 @@
       import java.lang.classfile.CodeModel;
       import java.lang.classfile.Instruction;
       import java.lang.classfile.Opcode;
      +
       import jdk.internal.classfile.impl.AbstractInstruction;
       import jdk.internal.classfile.impl.Util;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/NewMultiArrayInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/NewMultiArrayInstruction.java
      index 2c572c607b4f4..f5e0129205cfb 100644
      --- a/src/java.base/share/classes/java/lang/classfile/instruction/NewMultiArrayInstruction.java
      +++ b/src/java.base/share/classes/java/lang/classfile/instruction/NewMultiArrayInstruction.java
      @@ -26,8 +26,9 @@
       
       import java.lang.classfile.CodeElement;
       import java.lang.classfile.CodeModel;
      -import java.lang.classfile.constantpool.ClassEntry;
       import java.lang.classfile.Instruction;
      +import java.lang.classfile.constantpool.ClassEntry;
      +
       import jdk.internal.classfile.impl.AbstractInstruction;
       import jdk.internal.classfile.impl.BytecodeHelpers;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/NewObjectInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/NewObjectInstruction.java
      index fbfbb0da47b31..e6e8fc64d1763 100644
      --- a/src/java.base/share/classes/java/lang/classfile/instruction/NewObjectInstruction.java
      +++ b/src/java.base/share/classes/java/lang/classfile/instruction/NewObjectInstruction.java
      @@ -26,8 +26,9 @@
       
       import java.lang.classfile.CodeElement;
       import java.lang.classfile.CodeModel;
      -import java.lang.classfile.constantpool.ClassEntry;
       import java.lang.classfile.Instruction;
      +import java.lang.classfile.constantpool.ClassEntry;
      +
       import jdk.internal.classfile.impl.AbstractInstruction;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/NewPrimitiveArrayInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/NewPrimitiveArrayInstruction.java
      index cbc8f2068a8ad..4adc7536c2cfd 100644
      --- a/src/java.base/share/classes/java/lang/classfile/instruction/NewPrimitiveArrayInstruction.java
      +++ b/src/java.base/share/classes/java/lang/classfile/instruction/NewPrimitiveArrayInstruction.java
      @@ -28,6 +28,7 @@
       import java.lang.classfile.CodeModel;
       import java.lang.classfile.Instruction;
       import java.lang.classfile.TypeKind;
      +
       import jdk.internal.classfile.impl.AbstractInstruction;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/NewReferenceArrayInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/NewReferenceArrayInstruction.java
      index 7226850cc34cf..b622f915c464e 100644
      --- a/src/java.base/share/classes/java/lang/classfile/instruction/NewReferenceArrayInstruction.java
      +++ b/src/java.base/share/classes/java/lang/classfile/instruction/NewReferenceArrayInstruction.java
      @@ -26,8 +26,9 @@
       
       import java.lang.classfile.CodeElement;
       import java.lang.classfile.CodeModel;
      -import java.lang.classfile.constantpool.ClassEntry;
       import java.lang.classfile.Instruction;
      +import java.lang.classfile.constantpool.ClassEntry;
      +
       import jdk.internal.classfile.impl.AbstractInstruction;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/NopInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/NopInstruction.java
      index e47d2eb5f2b51..3183ad888161e 100644
      --- a/src/java.base/share/classes/java/lang/classfile/instruction/NopInstruction.java
      +++ b/src/java.base/share/classes/java/lang/classfile/instruction/NopInstruction.java
      @@ -27,6 +27,7 @@
       import java.lang.classfile.CodeElement;
       import java.lang.classfile.CodeModel;
       import java.lang.classfile.Instruction;
      +
       import jdk.internal.classfile.impl.AbstractInstruction;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/OperatorInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/OperatorInstruction.java
      index aeaa4109d7bd6..602f34ec03e0b 100644
      --- a/src/java.base/share/classes/java/lang/classfile/instruction/OperatorInstruction.java
      +++ b/src/java.base/share/classes/java/lang/classfile/instruction/OperatorInstruction.java
      @@ -29,6 +29,7 @@
       import java.lang.classfile.Instruction;
       import java.lang.classfile.Opcode;
       import java.lang.classfile.TypeKind;
      +
       import jdk.internal.classfile.impl.AbstractInstruction;
       import jdk.internal.classfile.impl.Util;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/ReturnInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/ReturnInstruction.java
      index fbfd22210d3dd..6596404a58282 100644
      --- a/src/java.base/share/classes/java/lang/classfile/instruction/ReturnInstruction.java
      +++ b/src/java.base/share/classes/java/lang/classfile/instruction/ReturnInstruction.java
      @@ -29,6 +29,7 @@
       import java.lang.classfile.Instruction;
       import java.lang.classfile.Opcode;
       import java.lang.classfile.TypeKind;
      +
       import jdk.internal.classfile.impl.AbstractInstruction;
       import jdk.internal.classfile.impl.BytecodeHelpers;
       import jdk.internal.classfile.impl.Util;
      diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/StackInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/StackInstruction.java
      index 9b2e0b6904387..17e9496652b90 100644
      --- a/src/java.base/share/classes/java/lang/classfile/instruction/StackInstruction.java
      +++ b/src/java.base/share/classes/java/lang/classfile/instruction/StackInstruction.java
      @@ -28,6 +28,7 @@
       import java.lang.classfile.CodeModel;
       import java.lang.classfile.Instruction;
       import java.lang.classfile.Opcode;
      +
       import jdk.internal.classfile.impl.AbstractInstruction;
       import jdk.internal.classfile.impl.Util;
       import jdk.internal.javac.PreviewFeature;
      diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/StoreInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/StoreInstruction.java
      index 5bfe13421da35..68bf54e61c28b 100644
      --- a/src/java.base/share/classes/java/lang/classfile/instruction/StoreInstruction.java
      +++ b/src/java.base/share/classes/java/lang/classfile/instruction/StoreInstruction.java
      @@ -29,6 +29,7 @@
       import java.lang.classfile.Instruction;
       import java.lang.classfile.Opcode;
       import java.lang.classfile.TypeKind;
      +
       import jdk.internal.classfile.impl.AbstractInstruction;
       import jdk.internal.classfile.impl.BytecodeHelpers;
       import jdk.internal.classfile.impl.Util;
      diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/SwitchCase.java b/src/java.base/share/classes/java/lang/classfile/instruction/SwitchCase.java
      index 0db88fa4b6338..6149945532bf1 100644
      --- a/src/java.base/share/classes/java/lang/classfile/instruction/SwitchCase.java
      +++ b/src/java.base/share/classes/java/lang/classfile/instruction/SwitchCase.java
      @@ -25,6 +25,7 @@
       package java.lang.classfile.instruction;
       
       import java.lang.classfile.Label;
      +
       import jdk.internal.classfile.impl.AbstractInstruction;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/TableSwitchInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/TableSwitchInstruction.java
      index bdcc2326f4a28..a8bce119db2f8 100644
      --- a/src/java.base/share/classes/java/lang/classfile/instruction/TableSwitchInstruction.java
      +++ b/src/java.base/share/classes/java/lang/classfile/instruction/TableSwitchInstruction.java
      @@ -24,12 +24,12 @@
        */
       package java.lang.classfile.instruction;
       
      -import java.util.List;
      -
       import java.lang.classfile.CodeElement;
       import java.lang.classfile.CodeModel;
       import java.lang.classfile.Instruction;
       import java.lang.classfile.Label;
      +import java.util.List;
      +
       import jdk.internal.classfile.impl.AbstractInstruction;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/ThrowInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/ThrowInstruction.java
      index 86c964cb61e12..68d861ba06dbe 100644
      --- a/src/java.base/share/classes/java/lang/classfile/instruction/ThrowInstruction.java
      +++ b/src/java.base/share/classes/java/lang/classfile/instruction/ThrowInstruction.java
      @@ -27,6 +27,7 @@
       import java.lang.classfile.CodeElement;
       import java.lang.classfile.CodeModel;
       import java.lang.classfile.Instruction;
      +
       import jdk.internal.classfile.impl.AbstractInstruction;
       import jdk.internal.javac.PreviewFeature;
       
      diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/TypeCheckInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/TypeCheckInstruction.java
      index d93f5244ca962..a4b9818a4bebd 100644
      --- a/src/java.base/share/classes/java/lang/classfile/instruction/TypeCheckInstruction.java
      +++ b/src/java.base/share/classes/java/lang/classfile/instruction/TypeCheckInstruction.java
      @@ -24,13 +24,13 @@
        */
       package java.lang.classfile.instruction;
       
      -import java.lang.constant.ClassDesc;
      -
       import java.lang.classfile.CodeElement;
       import java.lang.classfile.CodeModel;
      -import java.lang.classfile.constantpool.ClassEntry;
       import java.lang.classfile.Instruction;
       import java.lang.classfile.Opcode;
      +import java.lang.classfile.constantpool.ClassEntry;
      +import java.lang.constant.ClassDesc;
      +
       import jdk.internal.classfile.impl.AbstractInstruction;
       import jdk.internal.classfile.impl.TemporaryConstantPool;
       import jdk.internal.classfile.impl.Util;
      diff --git a/src/java.base/share/classes/java/lang/classfile/snippet-files/PackageSnippets.java b/src/java.base/share/classes/java/lang/classfile/snippet-files/PackageSnippets.java
      index 46e057210ac74..c6956d6d23a7f 100644
      --- a/src/java.base/share/classes/java/lang/classfile/snippet-files/PackageSnippets.java
      +++ b/src/java.base/share/classes/java/lang/classfile/snippet-files/PackageSnippets.java
      @@ -24,43 +24,25 @@
        */
       package java.lang.classfile.snippets;
       
      -import java.lang.classfile.ClassBuilder;
      +import java.lang.classfile.*;
      +import java.lang.classfile.components.ClassRemapper;
      +import java.lang.classfile.components.CodeLocalsShifter;
      +import java.lang.classfile.components.CodeRelabeler;
      +import java.lang.classfile.instruction.*;
       import java.lang.constant.ClassDesc;
       import java.lang.constant.ConstantDescs;
       import java.lang.constant.MethodTypeDesc;
       import java.lang.invoke.MethodHandles;
      +import java.lang.reflect.AccessFlag;
       import java.util.ArrayDeque;
       import java.util.HashSet;
      -import java.util.Set;
      -
      -import java.lang.reflect.AccessFlag;
       import java.util.Map;
      +import java.util.Set;
       import java.util.function.Predicate;
       import java.util.stream.Collectors;
       import java.util.stream.Stream;
       
      -import java.lang.classfile.ClassElement;
      -import java.lang.classfile.ClassHierarchyResolver;
      -import java.lang.classfile.ClassModel;
      -import java.lang.classfile.ClassTransform;
      -import java.lang.classfile.ClassFile;
      -import java.lang.classfile.ClassFileVersion;
      -import java.lang.classfile.CodeBuilder;
      -import java.lang.classfile.CodeElement;
      -import java.lang.classfile.CodeModel;
      -import java.lang.classfile.CodeTransform;
      -import java.lang.classfile.FieldModel;
      -import java.lang.classfile.MethodElement;
      -import java.lang.classfile.MethodModel;
      -import java.lang.classfile.Opcode;
      -import java.lang.classfile.PseudoInstruction;
      -import java.lang.classfile.TypeKind;
      -import java.lang.classfile.instruction.*;
      -
       import static java.util.stream.Collectors.toSet;
      -import java.lang.classfile.components.ClassRemapper;
      -import java.lang.classfile.components.CodeLocalsShifter;
      -import java.lang.classfile.components.CodeRelabeler;
       
       class PackageSnippets {
           void enumerateFieldsMethods1(byte[] bytes) {
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java
      index 23dad36b1b163..8795894530b17 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java
      @@ -24,47 +24,16 @@
        */
       package jdk.internal.classfile.impl;
       
      -import java.lang.classfile.constantpool.PoolEntry;
      -import java.lang.constant.ConstantDesc;
      -import java.util.ArrayList;
      -import java.util.Collections;
      -import java.util.List;
       import java.lang.classfile.Instruction;
      -import java.lang.classfile.constantpool.ClassEntry;
      -import java.lang.classfile.instruction.SwitchCase;
      -import java.lang.classfile.constantpool.FieldRefEntry;
      -import java.lang.classfile.constantpool.InterfaceMethodRefEntry;
      -import java.lang.classfile.constantpool.InvokeDynamicEntry;
      -import java.lang.classfile.constantpool.LoadableConstantEntry;
      -import java.lang.classfile.constantpool.MemberRefEntry;
      -import java.lang.classfile.instruction.ArrayLoadInstruction;
      -import java.lang.classfile.instruction.ArrayStoreInstruction;
      -import java.lang.classfile.instruction.BranchInstruction;
      -import java.lang.classfile.instruction.ConstantInstruction;
      -import java.lang.classfile.instruction.ConvertInstruction;
      -import java.lang.classfile.instruction.DiscontinuedInstruction;
      -import java.lang.classfile.instruction.FieldInstruction;
      -import java.lang.classfile.instruction.IncrementInstruction;
      -import java.lang.classfile.instruction.InvokeDynamicInstruction;
      -import java.lang.classfile.instruction.InvokeInstruction;
      -import java.lang.classfile.instruction.LoadInstruction;
      -import java.lang.classfile.instruction.LookupSwitchInstruction;
      -import java.lang.classfile.instruction.MonitorInstruction;
      -import java.lang.classfile.instruction.NewMultiArrayInstruction;
      -import java.lang.classfile.instruction.NewObjectInstruction;
      -import java.lang.classfile.instruction.NewPrimitiveArrayInstruction;
      -import java.lang.classfile.instruction.NewReferenceArrayInstruction;
      -import java.lang.classfile.instruction.NopInstruction;
      -import java.lang.classfile.instruction.OperatorInstruction;
      -import java.lang.classfile.instruction.ReturnInstruction;
      -import java.lang.classfile.instruction.StackInstruction;
      -import java.lang.classfile.instruction.StoreInstruction;
      -import java.lang.classfile.instruction.TableSwitchInstruction;
      -import java.lang.classfile.instruction.ThrowInstruction;
      -import java.lang.classfile.instruction.TypeCheckInstruction;
       import java.lang.classfile.Label;
       import java.lang.classfile.Opcode;
       import java.lang.classfile.TypeKind;
      +import java.lang.classfile.constantpool.*;
      +import java.lang.classfile.instruction.*;
      +import java.lang.constant.ConstantDesc;
      +import java.util.ArrayList;
      +import java.util.Collections;
      +import java.util.List;
       
       import static java.util.Objects.requireNonNull;
       
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java
      index 15b5262176441..e2a825498e8ad 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java
      @@ -24,33 +24,12 @@
        */
       package jdk.internal.classfile.impl;
       
      -import java.lang.classfile.constantpool.ConstantPoolException;
      +import java.lang.classfile.constantpool.*;
       import java.lang.constant.*;
       import java.lang.invoke.TypeDescriptor;
       import java.nio.charset.StandardCharsets;
       import java.util.Arrays;
       
      -import java.lang.classfile.constantpool.ClassEntry;
      -import java.lang.classfile.constantpool.ConstantDynamicEntry;
      -import java.lang.classfile.constantpool.ConstantPool;
      -import java.lang.classfile.constantpool.ConstantPoolBuilder;
      -import java.lang.classfile.constantpool.DoubleEntry;
      -import java.lang.classfile.constantpool.FieldRefEntry;
      -import java.lang.classfile.constantpool.FloatEntry;
      -import java.lang.classfile.constantpool.IntegerEntry;
      -import java.lang.classfile.constantpool.InterfaceMethodRefEntry;
      -import java.lang.classfile.constantpool.InvokeDynamicEntry;
      -import java.lang.classfile.constantpool.LongEntry;
      -import java.lang.classfile.constantpool.MemberRefEntry;
      -import java.lang.classfile.constantpool.MethodHandleEntry;
      -import java.lang.classfile.constantpool.MethodRefEntry;
      -import java.lang.classfile.constantpool.MethodTypeEntry;
      -import java.lang.classfile.constantpool.ModuleEntry;
      -import java.lang.classfile.constantpool.NameAndTypeEntry;
      -import java.lang.classfile.constantpool.PackageEntry;
      -import java.lang.classfile.constantpool.PoolEntry;
      -import java.lang.classfile.constantpool.StringEntry;
      -import java.lang.classfile.constantpool.Utf8Entry;
       import jdk.internal.access.JavaLangAccess;
       import jdk.internal.access.SharedSecrets;
       import jdk.internal.util.ArraysSupport;
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java
      index 596379305a9fe..ea3af78a600a0 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java
      @@ -24,17 +24,15 @@
        */
       package jdk.internal.classfile.impl;
       
      -import java.util.Optional;
      -
      -import java.lang.classfile.BufWriter;
      +import java.lang.classfile.Label;
      +import java.lang.classfile.PseudoInstruction;
       import java.lang.classfile.constantpool.ClassEntry;
       import java.lang.classfile.constantpool.Utf8Entry;
       import java.lang.classfile.instruction.CharacterRange;
       import java.lang.classfile.instruction.ExceptionCatch;
       import java.lang.classfile.instruction.LocalVariable;
       import java.lang.classfile.instruction.LocalVariableType;
      -import java.lang.classfile.Label;
      -import java.lang.classfile.PseudoInstruction;
      +import java.util.Optional;
       
       import static java.util.Objects.requireNonNull;
       
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractUnboundModel.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractUnboundModel.java
      index 9502ff7b246c9..1ff8c0014eaf8 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractUnboundModel.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractUnboundModel.java
      @@ -24,15 +24,14 @@
        */
       package jdk.internal.classfile.impl;
       
      -import java.util.Collections;
      -import java.util.List;
      -import java.util.function.Consumer;
      -import java.util.stream.Stream;
      -
       import java.lang.classfile.Attribute;
       import java.lang.classfile.AttributedElement;
       import java.lang.classfile.ClassFileElement;
       import java.lang.classfile.CompoundElement;
      +import java.util.Collections;
      +import java.util.List;
      +import java.util.function.Consumer;
      +import java.util.stream.Stream;
       
       public abstract sealed class AbstractUnboundModel
               extends AbstractElement
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AccessFlagsImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AccessFlagsImpl.java
      index 537110d2b23f6..ed682bbabb2b6 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AccessFlagsImpl.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AccessFlagsImpl.java
      @@ -24,9 +24,9 @@
        */
       package jdk.internal.classfile.impl;
       
      -import java.util.Set;
       import java.lang.classfile.AccessFlags;
       import java.lang.reflect.AccessFlag;
      +import java.util.Set;
       
       public final class AccessFlagsImpl extends AbstractElement
               implements AccessFlags {
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java
      index f1c7e6aaf658b..92b33d491cddb 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java
      @@ -24,9 +24,14 @@
        */
       package jdk.internal.classfile.impl;
       
      -import java.lang.classfile.*;
      -import java.lang.classfile.constantpool.*;
      -
      +import java.lang.classfile.Annotation;
      +import java.lang.classfile.AnnotationElement;
      +import java.lang.classfile.AnnotationValue;
      +import java.lang.classfile.constantpool.DoubleEntry;
      +import java.lang.classfile.constantpool.FloatEntry;
      +import java.lang.classfile.constantpool.IntegerEntry;
      +import java.lang.classfile.constantpool.LongEntry;
      +import java.lang.classfile.constantpool.Utf8Entry;
       import java.util.List;
       
       import static java.util.Objects.requireNonNull;
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java
      index 9724cff35ad6d..5c4058e6dce4e 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java
      @@ -25,22 +25,19 @@
       
       package jdk.internal.classfile.impl;
       
      -import java.lang.classfile.Annotation;
      -import java.lang.classfile.AnnotationElement;
      -import java.lang.classfile.AnnotationValue;
      -import java.lang.classfile.BufWriter;
      -import java.lang.classfile.ClassReader;
      -import java.lang.classfile.constantpool.*;
      -import java.lang.classfile.TypeAnnotation;
      +import java.lang.classfile.*;
      +import java.lang.classfile.constantpool.DoubleEntry;
      +import java.lang.classfile.constantpool.FloatEntry;
      +import java.lang.classfile.constantpool.IntegerEntry;
      +import java.lang.classfile.constantpool.LongEntry;
      +import java.lang.classfile.constantpool.Utf8Entry;
      +import java.util.List;
      +
      +import jdk.internal.access.SharedSecrets;
       
       import static java.lang.classfile.AnnotationValue.*;
       import static java.lang.classfile.TypeAnnotation.TargetInfo.*;
       
      -import java.util.List;
      -import java.lang.classfile.Label;
      -import java.lang.classfile.constantpool.Utf8Entry;
      -import jdk.internal.access.SharedSecrets;
      -
       public final class AnnotationReader {
           private AnnotationReader() { }
       
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AttributeHolder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AttributeHolder.java
      index 6060170a8d1c9..fffb963eab3c3 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AttributeHolder.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AttributeHolder.java
      @@ -24,10 +24,9 @@
        */
       package jdk.internal.classfile.impl;
       
      -import java.util.Arrays;
      -
       import java.lang.classfile.Attribute;
       import java.lang.classfile.AttributeMapper;
      +import java.util.Arrays;
       
       public class AttributeHolder {
           private static final Attribute[] EMPTY_ATTRIBUTE_ARRAY = {};
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java
      index 2fdc9f3642624..62d812ce8d41f 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java
      @@ -26,12 +26,11 @@
       
       import java.lang.classfile.CodeBuilder;
       import java.lang.classfile.CodeElement;
      +import java.lang.classfile.Instruction;
       import java.lang.classfile.Label;
       import java.lang.classfile.TypeKind;
       import java.lang.classfile.instruction.LabelTarget;
      -
       import java.util.Objects;
      -import java.lang.classfile.Instruction;
       
       import static java.util.Objects.requireNonNull;
       
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BootstrapMethodEntryImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BootstrapMethodEntryImpl.java
      index 267c11c584578..ed36b5ce172bf 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BootstrapMethodEntryImpl.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BootstrapMethodEntryImpl.java
      @@ -24,12 +24,11 @@
        */
       package jdk.internal.classfile.impl;
       
      -import java.util.List;
      -
      -import java.lang.classfile.constantpool.ConstantPool;
       import java.lang.classfile.BootstrapMethodEntry;
      +import java.lang.classfile.constantpool.ConstantPool;
       import java.lang.classfile.constantpool.LoadableConstantEntry;
       import java.lang.classfile.constantpool.MethodHandleEntry;
      +import java.util.List;
       
       import static jdk.internal.classfile.impl.AbstractPoolEntry.MethodHandleEntryImpl;
       
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java
      index 36ef2fa55ebef..59a2b03c91ed1 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java
      @@ -27,15 +27,7 @@
       
       import java.lang.classfile.*;
       import java.lang.classfile.attribute.*;
      -import java.lang.classfile.constantpool.ClassEntry;
      -import java.lang.classfile.constantpool.ConstantPool;
      -import java.lang.classfile.constantpool.ConstantValueEntry;
      -import java.lang.classfile.constantpool.LoadableConstantEntry;
      -import java.lang.classfile.constantpool.ModuleEntry;
      -import java.lang.classfile.constantpool.NameAndTypeEntry;
      -import java.lang.classfile.constantpool.PackageEntry;
      -import java.lang.classfile.constantpool.PoolEntry;
      -import java.lang.classfile.constantpool.Utf8Entry;
      +import java.lang.classfile.constantpool.*;
       import java.util.ArrayList;
       import java.util.Collections;
       import java.util.List;
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BoundLocalVariable.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BoundLocalVariable.java
      index 3bbcd243cc11e..cb2f9c1f1b7f7 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BoundLocalVariable.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BoundLocalVariable.java
      @@ -25,10 +25,10 @@
       
       package jdk.internal.classfile.impl;
       
      -import java.lang.constant.ClassDesc;
       import java.lang.classfile.attribute.LocalVariableInfo;
       import java.lang.classfile.constantpool.Utf8Entry;
       import java.lang.classfile.instruction.LocalVariable;
      +import java.lang.constant.ClassDesc;
       
       public final class BoundLocalVariable
               extends AbstractBoundLocalVariable
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BoundRecordComponentInfo.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BoundRecordComponentInfo.java
      index fd96b245af19b..c246199de50e8 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BoundRecordComponentInfo.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BoundRecordComponentInfo.java
      @@ -24,12 +24,11 @@
        */
       package jdk.internal.classfile.impl;
       
      -import java.util.List;
      -
       import java.lang.classfile.Attribute;
       import java.lang.classfile.ClassReader;
       import java.lang.classfile.attribute.RecordComponentInfo;
       import java.lang.classfile.constantpool.Utf8Entry;
      +import java.util.List;
       
       public final class BoundRecordComponentInfo
               implements RecordComponentInfo {
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java
      index 91b3b32190b81..db1300a809afc 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java
      @@ -25,14 +25,12 @@
        */
       package jdk.internal.classfile.impl;
       
      -
      -import java.util.Arrays;
      -
       import java.lang.classfile.BufWriter;
       import java.lang.classfile.constantpool.ClassEntry;
       import java.lang.classfile.constantpool.ConstantPool;
       import java.lang.classfile.constantpool.ConstantPoolBuilder;
       import java.lang.classfile.constantpool.PoolEntry;
      +import java.util.Arrays;
       
       import jdk.internal.access.JavaLangAccess;
       import jdk.internal.access.SharedSecrets;
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java
      index 4ed458c398309..86991843f57aa 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java
      @@ -27,12 +27,11 @@
       import java.lang.classfile.CodeBuilder;
       import java.lang.classfile.CodeElement;
       import java.lang.classfile.CodeModel;
      -import java.lang.classfile.TypeKind;
      -import java.lang.classfile.constantpool.ConstantPoolBuilder;
       import java.lang.classfile.Label;
       import java.lang.classfile.MethodModel;
      +import java.lang.classfile.TypeKind;
      +import java.lang.classfile.constantpool.ConstantPoolBuilder;
       import java.lang.classfile.instruction.ExceptionCatch;
      -
       import java.util.ArrayList;
       import java.util.List;
       import java.util.Optional;
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java
      index 0578cf85c4cc6..bd42d66dd3e9b 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java
      @@ -24,16 +24,19 @@
        */
       package jdk.internal.classfile.impl;
       
      +import java.lang.classfile.AccessFlags;
      +import java.lang.classfile.ClassModel;
      +import java.lang.classfile.FieldBuilder;
      +import java.lang.classfile.FieldElement;
      +import java.lang.classfile.FieldModel;
      +import java.lang.classfile.constantpool.ConstantPoolBuilder;
      +import java.lang.classfile.constantpool.Utf8Entry;
       import java.lang.reflect.AccessFlag;
       import java.util.ArrayList;
       import java.util.List;
       import java.util.Optional;
       import java.util.function.Consumer;
       
      -import java.lang.classfile.*;
      -import java.lang.classfile.constantpool.ConstantPoolBuilder;
      -import java.lang.classfile.constantpool.Utf8Entry;
      -
       import static java.util.Objects.requireNonNull;
       
       public final class BufferedFieldBuilder
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java
      index 8f511218d1e30..747fd876fbf5e 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java
      @@ -24,6 +24,9 @@
        */
       package jdk.internal.classfile.impl;
       
      +import java.lang.classfile.*;
      +import java.lang.classfile.constantpool.ConstantPoolBuilder;
      +import java.lang.classfile.constantpool.Utf8Entry;
       import java.lang.constant.MethodTypeDesc;
       import java.lang.reflect.AccessFlag;
       import java.util.ArrayList;
      @@ -31,18 +34,6 @@
       import java.util.Optional;
       import java.util.function.Consumer;
       
      -import java.lang.classfile.AccessFlags;
      -
      -import java.lang.classfile.ClassModel;
      -import java.lang.classfile.CodeBuilder;
      -import java.lang.classfile.CodeModel;
      -import java.lang.classfile.CodeTransform;
      -import java.lang.classfile.constantpool.ConstantPoolBuilder;
      -import java.lang.classfile.MethodBuilder;
      -import java.lang.classfile.MethodElement;
      -import java.lang.classfile.MethodModel;
      -import java.lang.classfile.constantpool.Utf8Entry;
      -
       import static java.util.Objects.requireNonNull;
       
       public final class BufferedMethodBuilder
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java
      index fde8905abc183..25daf4e4648ad 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java
      @@ -25,6 +25,10 @@
        */
       package jdk.internal.classfile.impl;
       
      +import java.lang.classfile.BootstrapMethodEntry;
      +import java.lang.classfile.Opcode;
      +import java.lang.classfile.TypeKind;
      +import java.lang.classfile.constantpool.*;
       import java.lang.constant.ClassDesc;
       import java.lang.constant.ConstantDesc;
       import java.lang.constant.ConstantDescs;
      @@ -35,18 +39,6 @@
       import java.util.ArrayList;
       import java.util.List;
       
      -import java.lang.classfile.BootstrapMethodEntry;
      -import java.lang.classfile.constantpool.ClassEntry;
      -import java.lang.classfile.constantpool.ConstantDynamicEntry;
      -import java.lang.classfile.constantpool.ConstantPoolBuilder;
      -import java.lang.classfile.Opcode;
      -import java.lang.classfile.TypeKind;
      -import java.lang.classfile.constantpool.LoadableConstantEntry;
      -import java.lang.classfile.constantpool.MemberRefEntry;
      -import java.lang.classfile.constantpool.MethodHandleEntry;
      -import java.lang.classfile.constantpool.NameAndTypeEntry;
      -import java.util.Objects;
      -
       import static java.util.Objects.requireNonNull;
       import static jdk.internal.classfile.impl.RawBytecodeHelper.*;
       
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/CatchBuilderImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/CatchBuilderImpl.java
      index 5d262c397f6ba..abb024cfa204d 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/CatchBuilderImpl.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/CatchBuilderImpl.java
      @@ -27,7 +27,6 @@
       import java.lang.classfile.CodeBuilder;
       import java.lang.classfile.Label;
       import java.lang.classfile.Opcode;
      -
       import java.lang.constant.ClassDesc;
       import java.lang.constant.ConstantDesc;
       import java.util.HashSet;
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java
      index ebf803f5f2725..48d5ceb72d641 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java
      @@ -24,12 +24,10 @@
        */
       package jdk.internal.classfile.impl;
       
      -import java.lang.constant.MethodTypeDesc;
      -import java.util.function.Consumer;
      -
       import java.lang.classfile.*;
       import java.lang.classfile.constantpool.ConstantPoolBuilder;
       import java.lang.classfile.constantpool.Utf8Entry;
      +import java.util.function.Consumer;
       
       import static java.util.Objects.requireNonNull;
       
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedCodeBuilder.java
      index fa02a346fabd8..9baa9f1212336 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedCodeBuilder.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedCodeBuilder.java
      @@ -26,9 +26,8 @@
       
       import java.lang.classfile.CodeBuilder;
       import java.lang.classfile.CodeElement;
      -import java.lang.classfile.TypeKind;
       import java.lang.classfile.Label;
      -
      +import java.lang.classfile.TypeKind;
       import java.util.function.Consumer;
       
       import static java.util.Objects.requireNonNull;
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedFieldBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedFieldBuilder.java
      index f9c2b50f414ac..13ca52f18de2f 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedFieldBuilder.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedFieldBuilder.java
      @@ -24,11 +24,10 @@
        */
       package jdk.internal.classfile.impl;
       
      -import java.util.function.Consumer;
      -
       import java.lang.classfile.FieldBuilder;
       import java.lang.classfile.FieldElement;
       import java.lang.classfile.constantpool.ConstantPoolBuilder;
      +import java.util.function.Consumer;
       
       import static java.util.Objects.requireNonNull;
       
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedMethodBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedMethodBuilder.java
      index 5bab6806b71b4..7bd0fc2ca1b23 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedMethodBuilder.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedMethodBuilder.java
      @@ -24,14 +24,13 @@
        */
       package jdk.internal.classfile.impl;
       
      -import java.util.function.Consumer;
      -
       import java.lang.classfile.CodeBuilder;
       import java.lang.classfile.CodeModel;
       import java.lang.classfile.CodeTransform;
       import java.lang.classfile.MethodBuilder;
       import java.lang.classfile.MethodElement;
       import java.lang.classfile.constantpool.ConstantPoolBuilder;
      +import java.util.function.Consumer;
       
       import static java.util.Objects.requireNonNull;
       
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java
      index ed81bcea009b8..3ab5d24f09cf0 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java
      @@ -25,19 +25,19 @@
       
       package jdk.internal.classfile.impl;
       
      -import java.util.List;
      -import java.util.function.Function;
      -import java.util.function.Consumer;
      -
       import java.lang.classfile.AttributeMapper;
      -import java.lang.classfile.ClassFile;
       import java.lang.classfile.ClassBuilder;
      +import java.lang.classfile.ClassFile;
       import java.lang.classfile.ClassHierarchyResolver;
       import java.lang.classfile.ClassModel;
       import java.lang.classfile.ClassTransform;
       import java.lang.classfile.constantpool.ClassEntry;
       import java.lang.classfile.constantpool.ConstantPoolBuilder;
       import java.lang.classfile.constantpool.Utf8Entry;
      +import java.util.List;
      +import java.util.function.Consumer;
      +import java.util.function.Function;
      +
       import jdk.internal.classfile.impl.verifier.VerifierImpl;
       
       import static java.util.Objects.requireNonNull;
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java
      index 9c2dd89553865..5be14f42baa1c 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java
      @@ -30,17 +30,16 @@
       import java.io.IOException;
       import java.io.InputStream;
       import java.io.UncheckedIOException;
      +import java.lang.classfile.ClassHierarchyResolver;
       import java.lang.constant.ClassDesc;
       import java.util.Collection;
       import java.util.HashMap;
       import java.util.Map;
       import java.util.function.Function;
       
      -import java.lang.classfile.ClassHierarchyResolver;
      -
      -import static java.lang.constant.ConstantDescs.CD_Object;
      -import static java.lang.classfile.ClassFile.*;
      +import static java.lang.classfile.ClassFile.ACC_INTERFACE;
       import static java.lang.classfile.constantpool.PoolEntry.*;
      +import static java.lang.constant.ConstantDescs.CD_Object;
       import static java.util.Objects.requireNonNull;
       import static jdk.internal.constant.ConstantUtils.referenceClassDesc;
       
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassImpl.java
      index c6b9be5c76a99..2e5c2c24651cb 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassImpl.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassImpl.java
      @@ -24,41 +24,20 @@
        */
       package jdk.internal.classfile.impl;
       
      +import java.lang.classfile.*;
      +import java.lang.classfile.attribute.*;
      +import java.lang.classfile.constantpool.ClassEntry;
      +import java.lang.classfile.constantpool.ConstantPool;
      +import java.lang.reflect.AccessFlag;
       import java.util.List;
       import java.util.Optional;
       import java.util.function.Consumer;
      -import java.lang.classfile.constantpool.ClassEntry;
      -import java.lang.reflect.AccessFlag;
      -import java.lang.classfile.AccessFlags;
      -import java.lang.classfile.Attribute;
      -import java.lang.classfile.Attributes;
      -import java.lang.classfile.ClassElement;
      -import java.lang.classfile.ClassModel;
      -import java.lang.classfile.ClassFile;
      -import java.lang.classfile.ClassFileVersion;
      -import java.lang.classfile.CustomAttribute;
      -import java.lang.classfile.constantpool.ConstantPool;
      -import java.lang.classfile.FieldModel;
      -import java.lang.classfile.Interfaces;
      -import java.lang.classfile.MethodModel;
      -import java.lang.classfile.Superclass;
      -import java.lang.classfile.attribute.InnerClassesAttribute;
      -import java.lang.classfile.attribute.ModuleAttribute;
      -import java.lang.classfile.attribute.ModuleHashesAttribute;
      -import java.lang.classfile.attribute.ModuleMainClassAttribute;
      -import java.lang.classfile.attribute.ModulePackagesAttribute;
      -import java.lang.classfile.attribute.ModuleResolutionAttribute;
      -import java.lang.classfile.attribute.ModuleTargetAttribute;
      -import java.lang.classfile.attribute.RuntimeInvisibleAnnotationsAttribute;
      -import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
      -import java.lang.classfile.attribute.SourceDebugExtensionAttribute;
      -import java.lang.classfile.attribute.SourceFileAttribute;
      +
       import jdk.internal.access.SharedSecrets;
       
       public final class ClassImpl
               extends AbstractElement
               implements ClassModel {
      -
           final ClassReaderImpl reader;
           private final int attributesPos;
           private final List methods;
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java
      index 9c42678428c46..b8fce2fd288c8 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java
      @@ -24,45 +24,38 @@
        */
       package jdk.internal.classfile.impl;
       
      +import java.lang.classfile.*;
      +import java.lang.classfile.AnnotationValue.*;
      +import java.lang.classfile.attribute.*;
      +import java.lang.classfile.attribute.StackMapFrameInfo.ObjectVerificationTypeInfo;
      +import java.lang.classfile.attribute.StackMapFrameInfo.SimpleVerificationTypeInfo;
      +import java.lang.classfile.attribute.StackMapFrameInfo.UninitializedVerificationTypeInfo;
      +import java.lang.classfile.attribute.StackMapFrameInfo.VerificationTypeInfo;
      +import java.lang.classfile.components.ClassPrinter.LeafNode;
      +import java.lang.classfile.components.ClassPrinter.ListNode;
      +import java.lang.classfile.components.ClassPrinter.MapNode;
      +import java.lang.classfile.components.ClassPrinter.Node;
      +import java.lang.classfile.components.ClassPrinter.Verbosity;
      +import java.lang.classfile.constantpool.*;
      +import java.lang.classfile.instruction.*;
       import java.lang.constant.ConstantDesc;
       import java.lang.constant.DirectMethodHandleDesc;
       import java.lang.reflect.AccessFlag;
      -import java.util.AbstractList;
      -import java.util.ArrayList;
      -import java.util.Arrays;
      -import java.util.Collection;
      -import java.util.Collections;
      -import java.util.LinkedHashMap;
      -import java.util.LinkedList;
      -import java.util.List;
      -import java.util.Map;
      +import java.util.*;
       import java.util.function.BiConsumer;
      -import java.util.Set;
       import java.util.function.Consumer;
       import java.util.stream.IntStream;
       import java.util.stream.Stream;
      -import java.lang.classfile.Annotation;
      -
      -import java.lang.classfile.AnnotationElement;
      -import java.lang.classfile.AnnotationValue;
      -import java.lang.classfile.AnnotationValue.*;
      -import java.lang.classfile.Attribute;
      -import java.lang.classfile.ClassModel;
      -import java.lang.classfile.components.ClassPrinter.*;
      -import java.lang.classfile.CodeModel;
      -import java.lang.classfile.Instruction;
      -import java.lang.classfile.MethodModel;
      -import java.lang.classfile.TypeAnnotation;
      -import java.lang.classfile.attribute.*;
      -import java.lang.classfile.attribute.StackMapFrameInfo.*;
      -import java.lang.classfile.constantpool.*;
      -import java.lang.classfile.instruction.*;
       
      -import java.lang.classfile.CompoundElement;
      -import java.lang.classfile.FieldModel;
      +import static java.lang.classfile.constantpool.PoolEntry.TAG_CLASS;
      +import static java.lang.classfile.constantpool.PoolEntry.TAG_DOUBLE;
      +import static java.lang.classfile.constantpool.PoolEntry.TAG_FLOAT;
      +import static java.lang.classfile.constantpool.PoolEntry.TAG_LONG;
      +import static java.lang.classfile.constantpool.PoolEntry.TAG_STRING;
       import static java.lang.classfile.constantpool.PoolEntry.*;
       import static java.util.Objects.requireNonNull;
      -import static jdk.internal.classfile.impl.ClassPrinterImpl.Style.*;
      +import static jdk.internal.classfile.impl.ClassPrinterImpl.Style.BLOCK;
      +import static jdk.internal.classfile.impl.ClassPrinterImpl.Style.FLOW;
       
       public final class ClassPrinterImpl {
       
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java
      index 0f183ad427f3d..d325100febfea 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java
      @@ -25,6 +25,13 @@
       
       package jdk.internal.classfile.impl;
       
      +import java.lang.classfile.*;
      +import java.lang.classfile.attribute.BootstrapMethodsAttribute;
      +import java.lang.classfile.constantpool.ClassEntry;
      +import java.lang.classfile.constantpool.ConstantPoolException;
      +import java.lang.classfile.constantpool.LoadableConstantEntry;
      +import java.lang.classfile.constantpool.PoolEntry;
      +import java.lang.classfile.constantpool.Utf8Entry;
       import java.util.ArrayList;
       import java.util.Arrays;
       import java.util.List;
      @@ -32,10 +39,6 @@
       import java.util.Optional;
       import java.util.function.Function;
       
      -import java.lang.classfile.*;
      -import java.lang.classfile.attribute.BootstrapMethodsAttribute;
      -import java.lang.classfile.constantpool.*;
      -
       import static java.lang.classfile.constantpool.PoolEntry.*;
       
       public final class ClassReaderImpl
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java
      index 1d1d028531ecb..cd9faaf2f9a1f 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java
      @@ -24,69 +24,13 @@
        */
       package jdk.internal.classfile.impl;
       
      -import java.lang.classfile.Annotation;
      -import java.lang.classfile.AnnotationElement;
      -import java.lang.classfile.AnnotationValue;
      -import java.lang.classfile.ClassBuilder;
      -import java.lang.classfile.ClassElement;
      -import java.lang.classfile.ClassSignature;
      -import java.lang.classfile.CodeBuilder;
      -import java.lang.classfile.CodeElement;
      -import java.lang.classfile.CodeModel;
      -import java.lang.classfile.CodeTransform;
      -import java.lang.classfile.FieldBuilder;
      -import java.lang.classfile.FieldElement;
      -import java.lang.classfile.FieldModel;
      -import java.lang.classfile.FieldTransform;
      -import java.lang.classfile.Interfaces;
      -import java.lang.classfile.MethodBuilder;
      -import java.lang.classfile.MethodElement;
      -import java.lang.classfile.MethodModel;
      -import java.lang.classfile.MethodSignature;
      -import java.lang.classfile.MethodTransform;
      -import java.lang.classfile.Signature;
      -import java.lang.classfile.Superclass;
      -import java.lang.classfile.TypeAnnotation;
      -import java.lang.classfile.attribute.AnnotationDefaultAttribute;
      -import java.lang.classfile.attribute.EnclosingMethodAttribute;
      -import java.lang.classfile.attribute.ExceptionsAttribute;
      -import java.lang.classfile.attribute.InnerClassInfo;
      -import java.lang.classfile.attribute.InnerClassesAttribute;
      -import java.lang.classfile.attribute.ModuleAttribute;
      -import java.lang.classfile.attribute.ModuleProvideInfo;
      -import java.lang.classfile.attribute.NestHostAttribute;
      -import java.lang.classfile.attribute.NestMembersAttribute;
      -import java.lang.classfile.attribute.PermittedSubclassesAttribute;
      -import java.lang.classfile.attribute.RecordAttribute;
      -import java.lang.classfile.attribute.RecordComponentInfo;
      -import java.lang.classfile.attribute.RuntimeInvisibleAnnotationsAttribute;
      -import java.lang.classfile.attribute.RuntimeInvisibleParameterAnnotationsAttribute;
      -import java.lang.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute;
      -import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
      -import java.lang.classfile.attribute.RuntimeVisibleParameterAnnotationsAttribute;
      -import java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute;
      -import java.lang.classfile.attribute.SignatureAttribute;
      +import java.lang.classfile.*;
      +import java.lang.classfile.attribute.*;
       import java.lang.classfile.components.ClassRemapper;
       import java.lang.classfile.constantpool.Utf8Entry;
       import java.lang.classfile.instruction.ConstantInstruction.LoadConstantInstruction;
      -import java.lang.classfile.instruction.ExceptionCatch;
      -import java.lang.classfile.instruction.FieldInstruction;
      -import java.lang.classfile.instruction.InvokeDynamicInstruction;
      -import java.lang.classfile.instruction.InvokeInstruction;
      -import java.lang.classfile.instruction.LocalVariable;
      -import java.lang.classfile.instruction.LocalVariableType;
      -import java.lang.classfile.instruction.NewMultiArrayInstruction;
      -import java.lang.classfile.instruction.NewObjectInstruction;
      -import java.lang.classfile.instruction.NewReferenceArrayInstruction;
      -import java.lang.classfile.instruction.TypeCheckInstruction;
      -
      -import java.lang.constant.ClassDesc;
      -import java.lang.constant.ConstantDesc;
      -import java.lang.constant.DirectMethodHandleDesc;
      -import java.lang.constant.DynamicCallSiteDesc;
      -import java.lang.constant.DynamicConstantDesc;
      -import java.lang.constant.MethodHandleDesc;
      -import java.lang.constant.MethodTypeDesc;
      +import java.lang.classfile.instruction.*;
      +import java.lang.constant.*;
       import java.util.List;
       import java.util.function.Function;
       
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java
      index aa9603b150855..47908b99f447c 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java
      @@ -24,13 +24,6 @@
        */
       package jdk.internal.classfile.impl;
       
      -import java.util.ArrayList;
      -import java.util.Collections;
      -import java.util.List;
      -import java.util.Objects;
      -import java.util.Optional;
      -import java.util.function.Consumer;
      -
       import java.lang.classfile.*;
       import java.lang.classfile.attribute.CodeAttribute;
       import java.lang.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute;
      @@ -38,6 +31,12 @@
       import java.lang.classfile.attribute.StackMapTableAttribute;
       import java.lang.classfile.constantpool.ClassEntry;
       import java.lang.classfile.instruction.*;
      +import java.util.ArrayList;
      +import java.util.Collections;
      +import java.util.List;
      +import java.util.Objects;
      +import java.util.Optional;
      +import java.util.function.Consumer;
       
       import static jdk.internal.classfile.impl.RawBytecodeHelper.*;
       
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeLocalsShifterImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeLocalsShifterImpl.java
      index 9c2554c054c40..7b7d04a8f1d14 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeLocalsShifterImpl.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeLocalsShifterImpl.java
      @@ -34,7 +34,6 @@
       import java.lang.classfile.instruction.LocalVariable;
       import java.lang.classfile.instruction.LocalVariableType;
       import java.lang.classfile.instruction.StoreInstruction;
      -
       import java.util.Arrays;
       
       public final class CodeLocalsShifterImpl implements CodeLocalsShifter {
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeRelabelerImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeRelabelerImpl.java
      index e60a906e189fc..af0a59978d7c4 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeRelabelerImpl.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeRelabelerImpl.java
      @@ -28,16 +28,7 @@
       import java.lang.classfile.CodeElement;
       import java.lang.classfile.Label;
       import java.lang.classfile.components.CodeRelabeler;
      -import java.lang.classfile.instruction.BranchInstruction;
      -import java.lang.classfile.instruction.CharacterRange;
      -import java.lang.classfile.instruction.ExceptionCatch;
      -import java.lang.classfile.instruction.LabelTarget;
      -import java.lang.classfile.instruction.LocalVariable;
      -import java.lang.classfile.instruction.LocalVariableType;
      -import java.lang.classfile.instruction.LookupSwitchInstruction;
      -import java.lang.classfile.instruction.SwitchCase;
      -import java.lang.classfile.instruction.TableSwitchInstruction;
      -
      +import java.lang.classfile.instruction.*;
       import java.util.function.BiFunction;
       
       public record CodeRelabelerImpl(BiFunction mapFunction) implements CodeRelabeler {
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeStackTrackerImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeStackTrackerImpl.java
      index 9288f9fa2a90b..2746caae0043e 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeStackTrackerImpl.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeStackTrackerImpl.java
      @@ -30,39 +30,8 @@
       import java.lang.classfile.Opcode;
       import java.lang.classfile.TypeKind;
       import java.lang.classfile.components.CodeStackTracker;
      -import java.lang.classfile.instruction.ArrayLoadInstruction;
      -import java.lang.classfile.instruction.ArrayStoreInstruction;
      -import java.lang.classfile.instruction.BranchInstruction;
      -import java.lang.classfile.instruction.ConstantInstruction;
      -import java.lang.classfile.instruction.ConvertInstruction;
      -import java.lang.classfile.instruction.ExceptionCatch;
      -import java.lang.classfile.instruction.FieldInstruction;
      -import java.lang.classfile.instruction.InvokeDynamicInstruction;
      -import java.lang.classfile.instruction.InvokeInstruction;
      -import java.lang.classfile.instruction.LabelTarget;
      -import java.lang.classfile.instruction.LoadInstruction;
      -import java.lang.classfile.instruction.LookupSwitchInstruction;
      -import java.lang.classfile.instruction.MonitorInstruction;
      -import java.lang.classfile.instruction.NewMultiArrayInstruction;
      -import java.lang.classfile.instruction.NewObjectInstruction;
      -import java.lang.classfile.instruction.NewPrimitiveArrayInstruction;
      -import java.lang.classfile.instruction.NewReferenceArrayInstruction;
      -import java.lang.classfile.instruction.NopInstruction;
      -import java.lang.classfile.instruction.OperatorInstruction;
      -import java.lang.classfile.instruction.ReturnInstruction;
      -import java.lang.classfile.instruction.StackInstruction;
      -import java.lang.classfile.instruction.StoreInstruction;
      -import java.lang.classfile.instruction.TableSwitchInstruction;
      -import java.lang.classfile.instruction.ThrowInstruction;
      -import java.lang.classfile.instruction.TypeCheckInstruction;
      -
      -import java.util.AbstractCollection;
      -import java.util.Collection;
      -import java.util.HashMap;
      -import java.util.Iterator;
      -import java.util.Map;
      -import java.util.NoSuchElementException;
      -import java.util.Optional;
      +import java.lang.classfile.instruction.*;
      +import java.util.*;
       import java.util.function.Consumer;
       
       public final class CodeStackTrackerImpl implements CodeStackTracker {
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java
      index d1131d94db769..6dc6251163989 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java
      @@ -26,26 +26,15 @@
       
       package jdk.internal.classfile.impl;
       
      +import java.lang.classfile.*;
      +import java.lang.classfile.constantpool.ClassEntry;
      +import java.lang.classfile.constantpool.Utf8Entry;
       import java.lang.constant.ConstantDescs;
       import java.util.Arrays;
       import java.util.Collections;
       import java.util.List;
       import java.util.function.Consumer;
       
      -import java.lang.classfile.ClassBuilder;
      -import java.lang.classfile.ClassElement;
      -import java.lang.classfile.ClassModel;
      -import java.lang.classfile.ClassFile;
      -import java.lang.classfile.CustomAttribute;
      -import java.lang.classfile.constantpool.ClassEntry;
      -import java.lang.classfile.FieldBuilder;
      -import java.lang.classfile.FieldModel;
      -import java.lang.classfile.FieldTransform;
      -import java.lang.classfile.MethodBuilder;
      -import java.lang.classfile.MethodModel;
      -import java.lang.classfile.MethodTransform;
      -import java.lang.classfile.constantpool.Utf8Entry;
      -
       import static java.util.Objects.requireNonNull;
       
       public final class DirectClassBuilder
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java
      index c00025e2a7e1e..6536faa8bea2b 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java
      @@ -25,42 +25,18 @@
        */
       package jdk.internal.classfile.impl;
       
      -import java.lang.constant.ClassDesc;
      -import java.lang.constant.MethodTypeDesc;
      -import java.lang.classfile.Attribute;
      -import java.lang.classfile.Attributes;
      -import java.lang.classfile.ClassFile;
      -import java.lang.classfile.CodeBuilder;
      -import java.lang.classfile.CodeElement;
      -import java.lang.classfile.CodeModel;
      -import java.lang.classfile.CustomAttribute;
      -import java.lang.classfile.Label;
      -import java.lang.classfile.Opcode;
      -import java.lang.classfile.TypeKind;
      +import java.lang.classfile.*;
       import java.lang.classfile.attribute.CodeAttribute;
       import java.lang.classfile.attribute.LineNumberTableAttribute;
      -import java.lang.classfile.constantpool.ClassEntry;
      -import java.lang.classfile.constantpool.ConstantPoolBuilder;
      -import java.lang.classfile.constantpool.DoubleEntry;
      -import java.lang.classfile.constantpool.FieldRefEntry;
      -import java.lang.classfile.constantpool.InterfaceMethodRefEntry;
      -import java.lang.classfile.constantpool.InvokeDynamicEntry;
      -import java.lang.classfile.constantpool.LoadableConstantEntry;
      -import java.lang.classfile.constantpool.LongEntry;
      -import java.lang.classfile.constantpool.MemberRefEntry;
      -import java.lang.classfile.constantpool.MethodRefEntry;
      +import java.lang.classfile.constantpool.*;
       import java.lang.classfile.instruction.CharacterRange;
       import java.lang.classfile.instruction.ExceptionCatch;
       import java.lang.classfile.instruction.LocalVariable;
       import java.lang.classfile.instruction.LocalVariableType;
       import java.lang.classfile.instruction.SwitchCase;
      -import java.util.ArrayList;
      -import java.util.Arrays;
      -import java.util.Comparator;
      -import java.util.HashMap;
      -import java.util.IdentityHashMap;
      -import java.util.List;
      -import java.util.Map;
      +import java.lang.constant.ClassDesc;
      +import java.lang.constant.MethodTypeDesc;
      +import java.util.*;
       import java.util.function.Consumer;
       import java.util.function.Function;
       
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectFieldBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectFieldBuilder.java
      index 222ed6b9792d2..1af3724766e06 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectFieldBuilder.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectFieldBuilder.java
      @@ -25,13 +25,12 @@
       
       package jdk.internal.classfile.impl;
       
      -import java.util.function.Consumer;
      -
       import java.lang.classfile.CustomAttribute;
       import java.lang.classfile.FieldBuilder;
       import java.lang.classfile.FieldElement;
       import java.lang.classfile.FieldModel;
       import java.lang.classfile.constantpool.Utf8Entry;
      +import java.util.function.Consumer;
       
       import static java.util.Objects.requireNonNull;
       
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java
      index cdd5f8155e1c7..938d6c088b7fb 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java
      @@ -25,19 +25,11 @@
       
       package jdk.internal.classfile.impl;
       
      +import java.lang.classfile.*;
      +import java.lang.classfile.constantpool.Utf8Entry;
       import java.lang.constant.MethodTypeDesc;
       import java.util.function.Consumer;
       
      -import java.lang.classfile.ClassFile;
      -import java.lang.classfile.CodeBuilder;
      -import java.lang.classfile.CodeModel;
      -import java.lang.classfile.CodeTransform;
      -import java.lang.classfile.CustomAttribute;
      -import java.lang.classfile.MethodBuilder;
      -import java.lang.classfile.MethodElement;
      -import java.lang.classfile.MethodModel;
      -import java.lang.classfile.constantpool.Utf8Entry;
      -
       import static java.util.Objects.requireNonNull;
       
       public final class DirectMethodBuilder
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/FieldImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/FieldImpl.java
      index 205e36588b421..a322c08a55a8a 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/FieldImpl.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/FieldImpl.java
      @@ -24,14 +24,18 @@
        */
       package jdk.internal.classfile.impl;
       
      +import java.lang.classfile.AccessFlags;
      +import java.lang.classfile.Attribute;
      +import java.lang.classfile.ClassModel;
      +import java.lang.classfile.ClassReader;
      +import java.lang.classfile.FieldElement;
      +import java.lang.classfile.FieldModel;
      +import java.lang.classfile.constantpool.Utf8Entry;
       import java.lang.reflect.AccessFlag;
       import java.util.List;
       import java.util.Optional;
       import java.util.function.Consumer;
       
      -import java.lang.classfile.*;
      -import java.lang.classfile.constantpool.Utf8Entry;
      -
       public final class FieldImpl
               extends AbstractElement
               implements FieldModel, Util.Writable {
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/InterfacesImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/InterfacesImpl.java
      index 242ec02c72371..72310b6498234 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/InterfacesImpl.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/InterfacesImpl.java
      @@ -24,12 +24,11 @@
        */
       package jdk.internal.classfile.impl;
       
      +import java.lang.classfile.Interfaces;
      +import java.lang.classfile.constantpool.ClassEntry;
       import java.util.List;
       import java.util.stream.Collectors;
       
      -import java.lang.classfile.constantpool.ClassEntry;
      -import java.lang.classfile.Interfaces;
      -
       public final class InterfacesImpl
               extends AbstractElement
               implements Interfaces {
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java
      index 4f7799d1fa7d5..10341f79135c5 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java
      @@ -24,10 +24,9 @@
        */
       package jdk.internal.classfile.impl;
       
      -import java.lang.constant.MethodTypeDesc;
       import java.lang.classfile.*;
       import java.lang.classfile.constantpool.Utf8Entry;
      -
      +import java.lang.constant.MethodTypeDesc;
       import java.lang.reflect.AccessFlag;
       import java.util.List;
       import java.util.Optional;
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/MethodInfo.java b/src/java.base/share/classes/jdk/internal/classfile/impl/MethodInfo.java
      index ce51144770676..2ecce31cb9114 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/MethodInfo.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/MethodInfo.java
      @@ -24,8 +24,8 @@
        */
       package jdk.internal.classfile.impl;
       
      -import java.lang.constant.MethodTypeDesc;
       import java.lang.classfile.constantpool.Utf8Entry;
      +import java.lang.constant.MethodTypeDesc;
       
       import static java.lang.classfile.ClassFile.ACC_STATIC;
       
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ModuleAttributeBuilderImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ModuleAttributeBuilderImpl.java
      index 873b32e4ad649..505bbfd6fea23 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ModuleAttributeBuilderImpl.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ModuleAttributeBuilderImpl.java
      @@ -25,16 +25,22 @@
       
       package jdk.internal.classfile.impl;
       
      -import java.lang.classfile.attribute.*;
      +import java.lang.classfile.attribute.ModuleAttribute;
       import java.lang.classfile.attribute.ModuleAttribute.ModuleAttributeBuilder;
      +import java.lang.classfile.attribute.ModuleExportInfo;
      +import java.lang.classfile.attribute.ModuleOpenInfo;
      +import java.lang.classfile.attribute.ModuleProvideInfo;
      +import java.lang.classfile.attribute.ModuleRequireInfo;
       import java.lang.classfile.constantpool.ClassEntry;
       import java.lang.classfile.constantpool.ModuleEntry;
       import java.lang.classfile.constantpool.Utf8Entry;
      +import java.lang.constant.ClassDesc;
       import java.lang.constant.ModuleDesc;
       import java.lang.constant.PackageDesc;
      -
      -import java.lang.constant.ClassDesc;
      -import java.util.*;
      +import java.util.ArrayList;
      +import java.util.LinkedHashSet;
      +import java.util.Objects;
      +import java.util.Set;
       
       public final class ModuleAttributeBuilderImpl
               implements ModuleAttributeBuilder {
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/SignaturesImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/SignaturesImpl.java
      index 77f6933a0c214..5486b58f04e3c 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/SignaturesImpl.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/SignaturesImpl.java
      @@ -24,15 +24,20 @@
        */
       package jdk.internal.classfile.impl;
       
      +import java.lang.classfile.ClassSignature;
      +import java.lang.classfile.MethodSignature;
      +import java.lang.classfile.Signature;
      +import java.lang.classfile.Signature.ArrayTypeSig;
      +import java.lang.classfile.Signature.ClassTypeSig;
      +import java.lang.classfile.Signature.RefTypeSig;
      +import java.lang.classfile.Signature.ThrowableSig;
      +import java.lang.classfile.Signature.TypeArg;
      +import java.lang.classfile.Signature.TypeParam;
       import java.util.ArrayList;
      +import java.util.Collections;
       import java.util.List;
       import java.util.Objects;
       import java.util.Optional;
      -import java.util.Collections;
      -import java.lang.classfile.ClassSignature;
      -import java.lang.classfile.MethodSignature;
      -import java.lang.classfile.Signature;
      -import java.lang.classfile.Signature.*;
       
       public final class SignaturesImpl {
       
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java
      index 4c76033885735..d1ae1066d13f8 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java
      @@ -24,16 +24,15 @@
        */
       package jdk.internal.classfile.impl;
       
      -import java.lang.constant.ClassDesc;
      -import java.lang.constant.MethodTypeDesc;
      -import java.util.Arrays;
      -import java.util.List;
      -
       import java.lang.classfile.Attributes;
      -import java.lang.classfile.ClassReader;
       import java.lang.classfile.BootstrapMethodEntry;
      +import java.lang.classfile.ClassReader;
       import java.lang.classfile.attribute.BootstrapMethodsAttribute;
       import java.lang.classfile.constantpool.*;
      +import java.lang.constant.ClassDesc;
      +import java.lang.constant.MethodTypeDesc;
      +import java.util.Arrays;
      +import java.util.List;
       
       import jdk.internal.constant.ConstantUtils;
       
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackCounter.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackCounter.java
      index 843528df84bb0..315aca9c35e32 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackCounter.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackCounter.java
      @@ -40,7 +40,7 @@
       import java.util.Queue;
       import java.util.stream.Collectors;
       
      -import static java.lang.classfile.ClassFile.*;
      +import static java.lang.classfile.ClassFile.ACC_STATIC;
       import static java.lang.classfile.constantpool.PoolEntry.*;
       import static jdk.internal.classfile.impl.RawBytecodeHelper.*;
       
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java
      index 28b877cd83c70..f8e58ed2242ab 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java
      @@ -30,7 +30,10 @@
       import java.lang.classfile.Label;
       import java.lang.classfile.MethodModel;
       import java.lang.classfile.attribute.StackMapFrameInfo;
      -import java.lang.classfile.attribute.StackMapFrameInfo.*;
      +import java.lang.classfile.attribute.StackMapFrameInfo.ObjectVerificationTypeInfo;
      +import java.lang.classfile.attribute.StackMapFrameInfo.SimpleVerificationTypeInfo;
      +import java.lang.classfile.attribute.StackMapFrameInfo.UninitializedVerificationTypeInfo;
      +import java.lang.classfile.attribute.StackMapFrameInfo.VerificationTypeInfo;
       import java.lang.classfile.constantpool.ClassEntry;
       import java.lang.constant.ConstantDescs;
       import java.lang.constant.MethodTypeDesc;
      @@ -40,7 +43,7 @@
       import java.util.List;
       import java.util.Objects;
       
      -import static java.lang.classfile.ClassFile.*;
      +import static java.lang.classfile.ClassFile.ACC_STATIC;
       import static java.lang.classfile.attribute.StackMapFrameInfo.VerificationTypeInfo.*;
       import static java.util.Objects.requireNonNull;
       
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java
      index 1af13267c8094..85ee77b172001 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java
      @@ -28,7 +28,6 @@
       
       import java.lang.classfile.Attribute;
       import java.lang.classfile.Attributes;
      -import java.lang.classfile.BufWriter;
       import java.lang.classfile.Label;
       import java.lang.classfile.attribute.StackMapTableAttribute;
       import java.lang.classfile.constantpool.ClassEntry;
      @@ -43,11 +42,12 @@
       import java.util.List;
       import java.util.Objects;
       import java.util.stream.Collectors;
      -import jdk.internal.constant.ReferenceClassDescImpl;
      +
       import jdk.internal.constant.PrimitiveClassDescImpl;
      +import jdk.internal.constant.ReferenceClassDescImpl;
       import jdk.internal.util.Preconditions;
       
      -import static java.lang.classfile.ClassFile.*;
      +import static java.lang.classfile.ClassFile.ACC_STATIC;
       import static java.lang.classfile.constantpool.PoolEntry.*;
       import static java.lang.constant.ConstantDescs.*;
       import static jdk.internal.classfile.impl.RawBytecodeHelper.*;
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/SuperclassImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/SuperclassImpl.java
      index 2e93c9b9d82ed..b30a1089f2643 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/SuperclassImpl.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/SuperclassImpl.java
      @@ -24,8 +24,8 @@
        */
       package jdk.internal.classfile.impl;
       
      -import java.lang.classfile.constantpool.ClassEntry;
       import java.lang.classfile.Superclass;
      +import java.lang.classfile.constantpool.ClassEntry;
       
       import static java.util.Objects.requireNonNull;
       
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java
      index f30597cb3c493..07aa3c8d8c88c 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java
      @@ -24,9 +24,9 @@
        */
       package jdk.internal.classfile.impl;
       
      -import java.util.List;
       import java.lang.classfile.Label;
       import java.lang.classfile.TypeAnnotation.*;
      +import java.util.List;
       
       import static java.util.Objects.requireNonNull;
       
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/TemporaryConstantPool.java b/src/java.base/share/classes/jdk/internal/classfile/impl/TemporaryConstantPool.java
      index 4fee9ba3d9510..83faf9c8802db 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/TemporaryConstantPool.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/TemporaryConstantPool.java
      @@ -24,30 +24,8 @@
        */
       package jdk.internal.classfile.impl;
       
      -import java.lang.classfile.*;
      -import java.lang.classfile.constantpool.ClassEntry;
      -import java.lang.classfile.constantpool.ConstantDynamicEntry;
      -import java.lang.classfile.constantpool.ConstantPool;
      -import java.lang.classfile.constantpool.ConstantPoolBuilder;
      -import java.lang.classfile.constantpool.DoubleEntry;
      -import java.lang.classfile.constantpool.FieldRefEntry;
      -import java.lang.classfile.constantpool.FloatEntry;
      -import java.lang.classfile.constantpool.IntegerEntry;
      -import java.lang.classfile.constantpool.InterfaceMethodRefEntry;
      -import java.lang.classfile.constantpool.InvokeDynamicEntry;
      -import java.lang.classfile.constantpool.LoadableConstantEntry;
      -import java.lang.classfile.constantpool.LongEntry;
      -import java.lang.classfile.constantpool.MemberRefEntry;
      -import java.lang.classfile.constantpool.MethodHandleEntry;
      -import java.lang.classfile.constantpool.MethodRefEntry;
      -import java.lang.classfile.constantpool.MethodTypeEntry;
      -import java.lang.classfile.constantpool.ModuleEntry;
      -import java.lang.classfile.constantpool.NameAndTypeEntry;
      -import java.lang.classfile.constantpool.PackageEntry;
      -import java.lang.classfile.constantpool.PoolEntry;
      -import java.lang.classfile.constantpool.StringEntry;
      -import java.lang.classfile.constantpool.Utf8Entry;
      -
      +import java.lang.classfile.BootstrapMethodEntry;
      +import java.lang.classfile.constantpool.*;
       import java.lang.constant.MethodTypeDesc;
       import java.util.List;
       import java.util.Objects;
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/TransformImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/TransformImpl.java
      index 8478b1a51f035..23387fcb098d0 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/TransformImpl.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/TransformImpl.java
      @@ -24,29 +24,11 @@
        */
       package jdk.internal.classfile.impl;
       
      -import java.lang.classfile.ClassFileBuilder;
      -import java.lang.classfile.ClassFileTransform;
      +import java.lang.classfile.*;
       import java.util.function.Consumer;
       import java.util.function.Predicate;
       import java.util.function.Supplier;
       
      -import java.lang.classfile.ClassBuilder;
      -import java.lang.classfile.ClassElement;
      -import java.lang.classfile.ClassTransform;
      -import java.lang.classfile.ClassFileElement;
      -import java.lang.classfile.CodeBuilder;
      -import java.lang.classfile.CodeElement;
      -import java.lang.classfile.CodeModel;
      -import java.lang.classfile.CodeTransform;
      -import java.lang.classfile.FieldBuilder;
      -import java.lang.classfile.FieldElement;
      -import java.lang.classfile.FieldModel;
      -import java.lang.classfile.FieldTransform;
      -import java.lang.classfile.MethodBuilder;
      -import java.lang.classfile.MethodElement;
      -import java.lang.classfile.MethodModel;
      -import java.lang.classfile.MethodTransform;
      -
       public final class TransformImpl {
           // ClassTransform
       
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java
      index a979a31c593c0..dfad66a897c27 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java
      @@ -24,71 +24,17 @@
        */
       package jdk.internal.classfile.impl;
       
      -import java.util.Collection;
      -import java.util.List;
      -import java.util.Optional;
      -
      -import java.lang.classfile.Annotation;
      -import java.lang.classfile.AnnotationValue;
      -import java.lang.classfile.Attribute;
      -import java.lang.classfile.AttributeMapper;
      -import java.lang.classfile.Attributes;
      -import java.lang.classfile.BootstrapMethodEntry;
      +import java.lang.classfile.*;
      +import java.lang.classfile.attribute.*;
       import java.lang.classfile.constantpool.ClassEntry;
      -import java.lang.classfile.TypeAnnotation;
      -import java.lang.classfile.attribute.AnnotationDefaultAttribute;
      -import java.lang.classfile.attribute.BootstrapMethodsAttribute;
      -import java.lang.classfile.attribute.CharacterRangeInfo;
      -import java.lang.classfile.attribute.CharacterRangeTableAttribute;
      -import java.lang.classfile.attribute.CompilationIDAttribute;
      -import java.lang.classfile.attribute.ConstantValueAttribute;
      -import java.lang.classfile.attribute.DeprecatedAttribute;
      -import java.lang.classfile.attribute.EnclosingMethodAttribute;
      -import java.lang.classfile.attribute.ExceptionsAttribute;
      -import java.lang.classfile.attribute.InnerClassInfo;
      -import java.lang.classfile.attribute.InnerClassesAttribute;
      -import java.lang.classfile.attribute.LineNumberInfo;
      -import java.lang.classfile.attribute.LineNumberTableAttribute;
      -import java.lang.classfile.attribute.LocalVariableInfo;
      -import java.lang.classfile.attribute.LocalVariableTableAttribute;
      -import java.lang.classfile.attribute.LocalVariableTypeInfo;
      -import java.lang.classfile.attribute.LocalVariableTypeTableAttribute;
      -import java.lang.classfile.attribute.MethodParameterInfo;
      -import java.lang.classfile.attribute.MethodParametersAttribute;
      -import java.lang.classfile.attribute.ModuleAttribute;
      -import java.lang.classfile.attribute.ModuleExportInfo;
      -import java.lang.classfile.attribute.ModuleHashInfo;
      -import java.lang.classfile.attribute.ModuleHashesAttribute;
      -import java.lang.classfile.attribute.ModuleMainClassAttribute;
      -import java.lang.classfile.attribute.ModuleOpenInfo;
      -import java.lang.classfile.attribute.ModulePackagesAttribute;
      -import java.lang.classfile.attribute.ModuleProvideInfo;
      -import java.lang.classfile.attribute.ModuleRequireInfo;
      -import java.lang.classfile.attribute.ModuleResolutionAttribute;
      -import java.lang.classfile.attribute.ModuleTargetAttribute;
      -import java.lang.classfile.attribute.NestHostAttribute;
      -import java.lang.classfile.attribute.NestMembersAttribute;
      -import java.lang.classfile.attribute.PermittedSubclassesAttribute;
      -import java.lang.classfile.attribute.RecordAttribute;
      -import java.lang.classfile.attribute.RecordComponentInfo;
      -import java.lang.classfile.attribute.RuntimeInvisibleAnnotationsAttribute;
      -import java.lang.classfile.attribute.RuntimeInvisibleParameterAnnotationsAttribute;
      -import java.lang.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute;
      -import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
      -import java.lang.classfile.attribute.RuntimeVisibleParameterAnnotationsAttribute;
      -import java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute;
      -import java.lang.classfile.attribute.SignatureAttribute;
      -import java.lang.classfile.attribute.SourceDebugExtensionAttribute;
      -import java.lang.classfile.attribute.SourceFileAttribute;
      -import java.lang.classfile.attribute.SourceIDAttribute;
      -import java.lang.classfile.attribute.StackMapTableAttribute;
      -import java.lang.classfile.attribute.StackMapFrameInfo;
      -import java.lang.classfile.attribute.SyntheticAttribute;
       import java.lang.classfile.constantpool.ConstantValueEntry;
       import java.lang.classfile.constantpool.ModuleEntry;
       import java.lang.classfile.constantpool.NameAndTypeEntry;
       import java.lang.classfile.constantpool.PackageEntry;
       import java.lang.classfile.constantpool.Utf8Entry;
      +import java.util.Collection;
      +import java.util.List;
      +import java.util.Optional;
       
       import jdk.internal.access.SharedSecrets;
       
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java
      index 0c4410bb5ea1c..352019dd9dace 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java
      @@ -24,40 +24,28 @@
        */
       package jdk.internal.classfile.impl;
       
      -import java.lang.classfile.CodeBuilder;
      -import java.lang.classfile.CustomAttribute;
      -import java.lang.classfile.FieldBuilder;
      -import java.lang.classfile.MethodBuilder;
      -import java.lang.classfile.PseudoInstruction;
      +import java.lang.classfile.*;
      +import java.lang.classfile.attribute.CodeAttribute;
      +import java.lang.classfile.components.ClassPrinter;
      +import java.lang.classfile.constantpool.ClassEntry;
      +import java.lang.classfile.constantpool.ModuleEntry;
       import java.lang.classfile.constantpool.PoolEntry;
       import java.lang.classfile.constantpool.Utf8Entry;
       import java.lang.constant.ClassDesc;
       import java.lang.constant.MethodTypeDesc;
      +import java.lang.constant.ModuleDesc;
      +import java.lang.reflect.AccessFlag;
       import java.util.AbstractList;
       import java.util.Collection;
       import java.util.List;
      +import java.util.function.Consumer;
       import java.util.function.Function;
       
      -import java.lang.classfile.Attribute;
      -import java.lang.classfile.AttributeMapper;
      -import java.lang.classfile.Attributes;
      -import java.lang.classfile.BufWriter;
      -import java.lang.classfile.ClassFile;
      -import java.lang.classfile.Opcode;
      -import java.lang.classfile.constantpool.ClassEntry;
      -import java.lang.classfile.constantpool.ModuleEntry;
      -import java.lang.classfile.constantpool.NameAndTypeEntry;
      -import java.lang.constant.ModuleDesc;
      -import java.lang.reflect.AccessFlag;
       import jdk.internal.access.SharedSecrets;
       import jdk.internal.vm.annotation.ForceInline;
       import jdk.internal.vm.annotation.Stable;
       
       import static java.lang.classfile.ClassFile.ACC_STATIC;
      -import java.lang.classfile.attribute.CodeAttribute;
      -import java.lang.classfile.components.ClassPrinter;
      -import java.util.function.Consumer;
      -
       import static jdk.internal.constant.PrimitiveClassDescImpl.CD_double;
       import static jdk.internal.constant.PrimitiveClassDescImpl.CD_long;
       import static jdk.internal.constant.PrimitiveClassDescImpl.CD_void;
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/ParserVerifier.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/ParserVerifier.java
      index ed735b41e0e78..521d74ae1332f 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/ParserVerifier.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/ParserVerifier.java
      @@ -24,38 +24,27 @@
        */
       package jdk.internal.classfile.impl.verifier;
       
      -import java.lang.classfile.Annotation;
      -import java.lang.classfile.AnnotationValue;
      -import java.lang.constant.ClassDesc;
      -import static java.lang.constant.ConstantDescs.CLASS_INIT_NAME;
      -import static java.lang.constant.ConstantDescs.INIT_NAME;
      -import java.util.ArrayList;
      -import java.util.HashSet;
      -import java.util.List;
      -import java.util.function.Consumer;
      -import java.util.stream.Collectors;
      -import java.lang.classfile.Attribute;
      -import java.lang.classfile.AttributedElement;
      -import java.lang.classfile.Attributes;
      -import java.lang.classfile.ClassModel;
      -import java.lang.classfile.ClassFileElement;
      -import java.lang.classfile.CodeModel;
      -import java.lang.classfile.CompoundElement;
      -import java.lang.classfile.CustomAttribute;
      -import java.lang.classfile.FieldModel;
      -import java.lang.classfile.MethodModel;
      -import java.lang.classfile.TypeAnnotation;
      -import java.lang.classfile.TypeKind;
      +import java.lang.classfile.*;
       import java.lang.classfile.attribute.*;
       import java.lang.classfile.constantpool.*;
      +import java.lang.constant.ClassDesc;
       import java.lang.constant.ConstantDescs;
       import java.lang.reflect.AccessFlag;
      +import java.util.ArrayList;
       import java.util.Collection;
      +import java.util.HashSet;
      +import java.util.List;
      +import java.util.function.Consumer;
       import java.util.function.Function;
       import java.util.function.ToIntFunction;
      +import java.util.stream.Collectors;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.Util;
       
      +import static java.lang.constant.ConstantDescs.CLASS_INIT_NAME;
      +import static java.lang.constant.ConstantDescs.INIT_NAME;
      +
       /**
        * ParserVerifier performs selected checks of the class file format according to
        * {@jvms 4.8 Format Checking}
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationBytecodes.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationBytecodes.java
      index 5aed968c6aefc..b12ec5101f5e5 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationBytecodes.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationBytecodes.java
      @@ -24,9 +24,9 @@
        */
       package jdk.internal.classfile.impl.verifier;
       
      -import static jdk.internal.classfile.impl.RawBytecodeHelper.*;
      -
       import jdk.internal.classfile.impl.verifier.VerificationSignature.BasicType;
      +
      +import static jdk.internal.classfile.impl.RawBytecodeHelper.*;
       import static jdk.internal.classfile.impl.verifier.VerificationSignature.BasicType.*;
       
       /**
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationTable.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationTable.java
      index db07e0aa45b96..af009297405e5 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationTable.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationTable.java
      @@ -24,7 +24,9 @@
        */
       package jdk.internal.classfile.impl.verifier;
       
      -import static jdk.internal.classfile.impl.verifier.VerificationType.*;
      +import static jdk.internal.classfile.impl.verifier.VerificationType.ITEM_Object;
      +import static jdk.internal.classfile.impl.verifier.VerificationType.ITEM_Uninitialized;
      +import static jdk.internal.classfile.impl.verifier.VerificationType.ITEM_UninitializedThis;
       
       /**
        * @see hotspot/share/classfile/stackMapTable.hpp
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationType.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationType.java
      index a2ecda88438a1..ff29d931332f5 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationType.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationType.java
      @@ -29,10 +29,11 @@
       import java.util.IdentityHashMap;
       import java.util.Map;
       import java.util.Objects;
      +
       import jdk.internal.classfile.impl.ClassHierarchyImpl;
       import jdk.internal.classfile.impl.Util;
      +
       import static jdk.internal.classfile.impl.verifier.VerifierImpl.*;
      -import static jdk.internal.classfile.impl.verifier.VerificationSignature.BasicType.*;
       
       /**
        * @see hotspot/share/classfile/verificationType.hpp
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationWrapper.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationWrapper.java
      index d34f579b1f4f3..c76d0789244b0 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationWrapper.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationWrapper.java
      @@ -25,21 +25,21 @@
        */
       package jdk.internal.classfile.impl.verifier;
       
      -import java.lang.constant.ClassDesc;
      -import java.util.LinkedList;
      -import java.util.List;
      -
      +import java.lang.classfile.Attributes;
      +import java.lang.classfile.ClassModel;
      +import java.lang.classfile.MethodModel;
      +import java.lang.classfile.attribute.LocalVariableInfo;
       import java.lang.classfile.constantpool.ClassEntry;
      +import java.lang.classfile.constantpool.ConstantPool;
       import java.lang.classfile.constantpool.DynamicConstantPoolEntry;
       import java.lang.classfile.constantpool.MemberRefEntry;
       import java.lang.classfile.constantpool.NameAndTypeEntry;
      +import java.lang.constant.ClassDesc;
       import java.lang.reflect.AccessFlag;
      +import java.util.LinkedList;
      +import java.util.List;
       import java.util.stream.Collectors;
      -import java.lang.classfile.ClassModel;
      -import java.lang.classfile.constantpool.ConstantPool;
      -import java.lang.classfile.MethodModel;
      -import java.lang.classfile.attribute.LocalVariableInfo;
      -import java.lang.classfile.Attributes;
      +
       import jdk.internal.classfile.impl.BoundAttribute;
       import jdk.internal.classfile.impl.CodeImpl;
       import jdk.internal.classfile.impl.Util;
      diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerifierImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerifierImpl.java
      index f41647788a175..ed93ff1fc5d67 100644
      --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerifierImpl.java
      +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerifierImpl.java
      @@ -24,20 +24,23 @@
        */
       package jdk.internal.classfile.impl.verifier;
       
      +import java.lang.classfile.ClassHierarchyResolver;
      +import java.lang.classfile.ClassModel;
      +import java.lang.classfile.components.ClassPrinter;
       import java.util.ArrayList;
       import java.util.Collections;
       import java.util.List;
       import java.util.function.Consumer;
      -import java.lang.classfile.ClassHierarchyResolver;
      -import java.lang.classfile.ClassModel;
      -import java.lang.classfile.components.ClassPrinter;
      +
       import jdk.internal.classfile.impl.ClassHierarchyImpl;
       import jdk.internal.classfile.impl.RawBytecodeHelper;
      -import static jdk.internal.classfile.impl.RawBytecodeHelper.*;
      -import jdk.internal.classfile.impl.verifier.VerificationWrapper.ConstantPoolWrapper;
      -import static jdk.internal.classfile.impl.verifier.VerificationSignature.BasicType.*;
       import jdk.internal.classfile.impl.verifier.VerificationSignature.BasicType;
      +import jdk.internal.classfile.impl.verifier.VerificationWrapper.ConstantPoolWrapper;
      +
      +import static jdk.internal.classfile.impl.RawBytecodeHelper.*;
       import static jdk.internal.classfile.impl.verifier.VerificationFrame.FLAG_THIS_UNINIT;
      +import static jdk.internal.classfile.impl.verifier.VerificationSignature.BasicType.T_BOOLEAN;
      +import static jdk.internal.classfile.impl.verifier.VerificationSignature.BasicType.T_LONG;
       
       /**
        * VerifierImpl performs selected checks and verifications of the class file
      
      From 8e16e67492a46c5ee1e6fdb8f86d061cb8d3169b Mon Sep 17 00:00:00 2001
      From: Ivan Walulya 
      Date: Thu, 17 Oct 2024 12:26:39 +0000
      Subject: [PATCH 111/118] 8342329: G1: Rename
       G1HeapRegionManager::_allocated_heapregions_length
      
      Reviewed-by: tschatzl, shade
      ---
       .../share/gc/g1/g1HeapRegionManager.cpp       | 34 +++++++++----------
       .../share/gc/g1/g1HeapRegionManager.hpp       |  8 ++---
       2 files changed, 21 insertions(+), 21 deletions(-)
      
      diff --git a/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp b/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp
      index 2369a0f7812ea..9fb56f7c58fb2 100644
      --- a/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp
      +++ b/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp
      @@ -66,7 +66,7 @@ G1HeapRegionManager::G1HeapRegionManager() :
         _bot_mapper(nullptr),
         _cardtable_mapper(nullptr),
         _committed_map(),
      -  _allocated_heapregions_length(0),
      +  _next_highest_used_hrm_index(0),
         _regions(), _heap_mapper(nullptr),
         _bitmap_mapper(nullptr),
         _free_list("Free list", new G1MasterFreeRegionListChecker())
      @@ -76,7 +76,7 @@ void G1HeapRegionManager::initialize(G1RegionToSpaceMapper* heap_storage,
                                            G1RegionToSpaceMapper* bitmap,
                                            G1RegionToSpaceMapper* bot,
                                            G1RegionToSpaceMapper* cardtable) {
      -  _allocated_heapregions_length = 0;
      +  _next_highest_used_hrm_index = 0;
       
         _heap_mapper = heap_storage;
       
      @@ -169,7 +169,7 @@ void G1HeapRegionManager::expand(uint start, uint num_regions, WorkerThreads* pr
             hr = new_heap_region(i);
             OrderAccess::storestore();
             _regions.set_by_index(i, hr);
      -      _allocated_heapregions_length = MAX2(_allocated_heapregions_length, i + 1);
      +      _next_highest_used_hrm_index = MAX2(_next_highest_used_hrm_index, i + 1);
           }
           G1HeapRegionPrinter::commit(hr);
         }
      @@ -489,7 +489,7 @@ uint G1HeapRegionManager::find_contiguous_allow_expand(uint num_regions) {
       G1HeapRegion* G1HeapRegionManager::next_region_in_heap(const G1HeapRegion* r) const {
         guarantee(r != nullptr, "Start region must be a valid region");
         guarantee(is_available(r->hrm_index()), "Trying to iterate starting from region %u which is not in the heap", r->hrm_index());
      -  for (uint i = r->hrm_index() + 1; i < _allocated_heapregions_length; i++) {
      +  for (uint i = r->hrm_index() + 1; i < _next_highest_used_hrm_index; i++) {
           G1HeapRegion* hr = _regions.get_by_index(i);
           if (is_available(i)) {
             return hr;
      @@ -583,8 +583,8 @@ void G1HeapRegionManager::par_iterate(G1HeapRegionClosure* blk, G1HeapRegionClai
       
       uint G1HeapRegionManager::shrink_by(uint num_regions_to_remove) {
         assert(length() > 0, "the region sequence should not be empty");
      -  assert(length() <= _allocated_heapregions_length, "invariant");
      -  assert(_allocated_heapregions_length > 0, "we should have at least one region committed");
      +  assert(length() <= _next_highest_used_hrm_index, "invariant");
      +  assert(_next_highest_used_hrm_index > 0, "we should have at least one region committed");
         assert(num_regions_to_remove < length(), "We should never remove all regions");
       
         if (num_regions_to_remove == 0) {
      @@ -592,7 +592,7 @@ uint G1HeapRegionManager::shrink_by(uint num_regions_to_remove) {
         }
       
         uint removed = 0;
      -  uint cur = _allocated_heapregions_length;
      +  uint cur = _next_highest_used_hrm_index;
         uint idx_last_found = 0;
         uint num_last_found = 0;
       
      @@ -624,7 +624,7 @@ void G1HeapRegionManager::shrink_at(uint index, size_t num_regions) {
       }
       
       uint G1HeapRegionManager::find_empty_from_idx_reverse(uint start_idx, uint* res_idx) const {
      -  guarantee(start_idx <= _allocated_heapregions_length, "checking");
      +  guarantee(start_idx <= _next_highest_used_hrm_index, "checking");
         guarantee(res_idx != nullptr, "checking");
       
         auto is_available_and_empty = [&] (uint index) {
      @@ -658,12 +658,12 @@ uint G1HeapRegionManager::find_empty_from_idx_reverse(uint start_idx, uint* res_
       }
       
       void G1HeapRegionManager::verify() {
      -  guarantee(length() <= _allocated_heapregions_length,
      -            "invariant: _length: %u _allocated_length: %u",
      -            length(), _allocated_heapregions_length);
      -  guarantee(_allocated_heapregions_length <= reserved_length(),
      -            "invariant: _allocated_length: %u _max_length: %u",
      -            _allocated_heapregions_length, reserved_length());
      +  guarantee(length() <= _next_highest_used_hrm_index,
      +            "invariant: _length: %u _next_highest_used_hrm_index: %u",
      +            length(), _next_highest_used_hrm_index);
      +  guarantee(_next_highest_used_hrm_index <= reserved_length(),
      +            "invariant: _next_highest_used_hrm_index: %u _max_length: %u",
      +            _next_highest_used_hrm_index, reserved_length());
         guarantee(length() <= max_length(),
                   "invariant: committed regions: %u max_regions: %u",
                   length(), max_length());
      @@ -671,7 +671,7 @@ void G1HeapRegionManager::verify() {
         bool prev_committed = true;
         uint num_committed = 0;
         HeapWord* prev_end = heap_bottom();
      -  for (uint i = 0; i < _allocated_heapregions_length; i++) {
      +  for (uint i = 0; i < _next_highest_used_hrm_index; i++) {
           if (!is_available(i)) {
             prev_committed = false;
             continue;
      @@ -693,7 +693,7 @@ void G1HeapRegionManager::verify() {
           prev_committed = true;
           prev_end = hr->end();
         }
      -  for (uint i = _allocated_heapregions_length; i < reserved_length(); i++) {
      +  for (uint i = _next_highest_used_hrm_index; i < reserved_length(); i++) {
           guarantee(_regions.get_by_index(i) == nullptr, "invariant i: %u", i);
         }
       
      @@ -708,7 +708,7 @@ void G1HeapRegionManager::verify_optional() {
       #endif // PRODUCT
       
       G1HeapRegionClaimer::G1HeapRegionClaimer(uint n_workers) :
      -    _n_workers(n_workers), _n_regions(G1CollectedHeap::heap()->_hrm._allocated_heapregions_length), _claims(nullptr) {
      +    _n_workers(n_workers), _n_regions(G1CollectedHeap::heap()->_hrm._next_highest_used_hrm_index), _claims(nullptr) {
         uint* new_claims = NEW_C_HEAP_ARRAY(uint, _n_regions, mtGC);
         memset(new_claims, Unclaimed, sizeof(*_claims) * _n_regions);
         _claims = new_claims;
      diff --git a/src/hotspot/share/gc/g1/g1HeapRegionManager.hpp b/src/hotspot/share/gc/g1/g1HeapRegionManager.hpp
      index 81bca4ce6381c..563140acf5b8f 100644
      --- a/src/hotspot/share/gc/g1/g1HeapRegionManager.hpp
      +++ b/src/hotspot/share/gc/g1/g1HeapRegionManager.hpp
      @@ -64,8 +64,8 @@ class G1HeapRegionTable : public G1BiasedMappedArray {
       //
       // * _num_committed (returned by length()) is the number of currently
       //   committed regions. These may not be contiguous.
      -// * _allocated_heapregions_length (not exposed outside this class) is the
      -//   number of regions+1 for which we have G1HeapRegions.
      +// * _next_highest_used_hrm_index (not exposed outside this class) is the
      +//   highest heap region index +1 for which we have G1HeapRegions.
       // * max_length() returns the maximum number of regions the heap may commit.
       // * reserved_length() returns the maximum number of regions the heap has reserved.
       //
      @@ -81,8 +81,8 @@ class G1HeapRegionManager: public CHeapObj {
         // can either be active (ready for use) or inactive (ready for uncommit).
         G1CommittedRegionMap _committed_map;
       
      -  // Internal only. The highest heap region +1 we allocated a G1HeapRegion instance for.
      -  uint _allocated_heapregions_length;
      +  // Internal only. The highest heap region index +1 we allocated a G1HeapRegion instance for.
      +  uint _next_highest_used_hrm_index;
       
         HeapWord* heap_bottom() const { return _regions.bottom_address_mapped(); }
         HeapWord* heap_end() const {return _regions.end_address_mapped(); }
      
      From d6f8b465e47d40220bdba6bf7502de90ee9fa7f7 Mon Sep 17 00:00:00 2001
      From: Thomas Schatzl 
      Date: Thu, 17 Oct 2024 12:31:43 +0000
      Subject: [PATCH 112/118] 8340389:
       vmTestbase/gc/gctests/PhantomReference/phantom001/TestDescription.java Test
       exit code: 97 with -Xcomp UseAVX=3
      
      Reviewed-by: shade, iwalulya
      ---
       .../gc/gctests/PhantomReference/phantom001/phantom001.java | 7 ++++---
       1 file changed, 4 insertions(+), 3 deletions(-)
      
      diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/PhantomReference/phantom001/phantom001.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/PhantomReference/phantom001/phantom001.java
      index d45adbf4efd1a..9f5fc94221ede 100644
      --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/PhantomReference/phantom001/phantom001.java
      +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/PhantomReference/phantom001/phantom001.java
      @@ -177,14 +177,15 @@ public void run() {
                   // If referent is finalizable, provoke GCs and wait for finalization.
                   if (type.equals("class")) {
                       progress("Waiting for finalization: " + type);
      +                WhiteBox.getWhiteBox().fullGC();
                       for (int checks = 0; !finalized && !shouldTerminate(); ++checks) {
      -                    // There are scenarios where one WB.fillGC() isn't enough,
      -                    // but 10 iterations really ought to be sufficient.
      +                    // Wait for up to 10 iterations that the finalizer has been run,
      +                    // this ought to be sufficient. Full GCs and other threads might
      +                    // starve out the finalizer thread, requiring more waiting.
                           if (checks > 10) {
                               fail("Waiting for finalization: " + type);
                               return;
                           }
      -                    WhiteBox.getWhiteBox().fullGC();
                           // Give some time for finalizer to run.
                           try {
                               Thread.sleep(checks * 100);
      
      From 363327e68644b710b0fd549e088beb5c8838a973 Mon Sep 17 00:00:00 2001
      From: Matias Saavedra Silva 
      Date: Thu, 17 Oct 2024 13:56:49 +0000
      Subject: [PATCH 113/118] 8341452: Test
       runtime/cds/appcds/DumpRuntimeClassesTest.java from JDK-8324259 is failing
      
      Reviewed-by: dholmes, iklam
      ---
       src/hotspot/share/cds/cdsProtectionDomain.cpp | 23 +++++++++--------
       src/hotspot/share/cds/cdsProtectionDomain.hpp |  1 +
       src/hotspot/share/cds/metaspaceShared.cpp     | 25 +++++++++----------
       src/hotspot/share/cds/metaspaceShared.hpp     |  1 +
       test/hotspot/jtreg/ProblemList-Xcomp.txt      |  2 --
       .../cds/appcds/DumpRuntimeClassesTest.java    |  3 +++
       6 files changed, 30 insertions(+), 25 deletions(-)
      
      diff --git a/src/hotspot/share/cds/cdsProtectionDomain.cpp b/src/hotspot/share/cds/cdsProtectionDomain.cpp
      index a4ffeea26dc4a..2eb47ff2788d9 100644
      --- a/src/hotspot/share/cds/cdsProtectionDomain.cpp
      +++ b/src/hotspot/share/cds/cdsProtectionDomain.cpp
      @@ -199,17 +199,9 @@ Handle CDSProtectionDomain::get_shared_jar_manifest(int shared_path_index, TRAPS
       Handle CDSProtectionDomain::get_shared_jar_url(int shared_path_index, TRAPS) {
         Handle url_h;
         if (shared_jar_url(shared_path_index) == nullptr) {
      -    JavaValue result(T_OBJECT);
           const char* path = FileMapInfo::shared_path_name(shared_path_index);
      -    Handle path_string = java_lang_String::create_from_str(path, CHECK_(url_h));
      -    Klass* classLoaders_klass =
      -        vmClasses::jdk_internal_loader_ClassLoaders_klass();
      -    JavaCalls::call_static(&result, classLoaders_klass,
      -                           vmSymbols::toFileURL_name(),
      -                           vmSymbols::toFileURL_signature(),
      -                           path_string, CHECK_(url_h));
      -
      -    atomic_set_shared_jar_url(shared_path_index, result.get_oop());
      +    oop result_oop = to_file_URL(path, url_h, CHECK_(url_h));
      +    atomic_set_shared_jar_url(shared_path_index, result_oop);
         }
       
         url_h = Handle(THREAD, shared_jar_url(shared_path_index));
      @@ -217,6 +209,17 @@ Handle CDSProtectionDomain::get_shared_jar_url(int shared_path_index, TRAPS) {
         return url_h;
       }
       
      +oop CDSProtectionDomain::to_file_URL(const char* path, Handle url_h, TRAPS) {
      +  JavaValue result(T_OBJECT);
      +  Handle path_string = java_lang_String::create_from_str(path, CHECK_NULL);
      +  JavaCalls::call_static(&result,
      +                         vmClasses::jdk_internal_loader_ClassLoaders_klass(),
      +                         vmSymbols::toFileURL_name(),
      +                         vmSymbols::toFileURL_signature(),
      +                         path_string, CHECK_NULL);
      +  return result.get_oop();
      +}
      +
       // Get the ProtectionDomain associated with the CodeSource from the classloader.
       Handle CDSProtectionDomain::get_protection_domain_from_classloader(Handle class_loader,
                                                                             Handle url, TRAPS) {
      diff --git a/src/hotspot/share/cds/cdsProtectionDomain.hpp b/src/hotspot/share/cds/cdsProtectionDomain.hpp
      index 0e688fcfa00e8..baab4ab0e728a 100644
      --- a/src/hotspot/share/cds/cdsProtectionDomain.hpp
      +++ b/src/hotspot/share/cds/cdsProtectionDomain.hpp
      @@ -80,6 +80,7 @@ class CDSProtectionDomain : AllStatic {
         static Handle create_jar_manifest(const char* man, size_t size, TRAPS);
         static Handle get_shared_jar_manifest(int shared_path_index, TRAPS);
         static Handle get_shared_jar_url(int shared_path_index, TRAPS);
      +  static oop to_file_URL(const char* path, Handle url_h, TRAPS);
         static Handle get_protection_domain_from_classloader(Handle class_loader,
                                                              Handle url, TRAPS);
         static Handle get_shared_protection_domain(Handle class_loader,
      diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp
      index 6f646e162ecac..efd7a906a46e9 100644
      --- a/src/hotspot/share/cds/metaspaceShared.cpp
      +++ b/src/hotspot/share/cds/metaspaceShared.cpp
      @@ -751,12 +751,21 @@ void MetaspaceShared::preload_classes(TRAPS) {
           }
         }
       
      -  // Exercise the manifest processing code to ensure classes used by CDS at runtime
      -  // are always archived
      +  // Some classes are used at CDS runtime but are not loaded, and therefore archived, at
      +  // dumptime. We can perform dummmy calls to these classes at dumptime to ensure they
      +  // are archived.
      +  exercise_runtime_cds_code(CHECK);
      +
      +  log_info(cds)("Loading classes to share: done.");
      +}
      +
      +void MetaspaceShared::exercise_runtime_cds_code(TRAPS) {
      +  // Exercise the manifest processing code
         const char* dummy = "Manifest-Version: 1.0\n";
         CDSProtectionDomain::create_jar_manifest(dummy, strlen(dummy), CHECK);
       
      -  log_info(cds)("Loading classes to share: done.");
      +  // Exercise FileSystem and URL code
      +  CDSProtectionDomain::to_file_URL("dummy.jar", Handle(), CHECK);
       }
       
       void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS) {
      @@ -799,16 +808,6 @@ void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS
         }
       #endif
       
      -  // Dummy call to load classes used at CDS runtime
      -  JavaValue result(T_OBJECT);
      -  Handle path_string = java_lang_String::create_from_str("dummy.jar", CHECK);
      -  JavaCalls::call_static(&result,
      -                         vmClasses::jdk_internal_loader_ClassLoaders_klass(),
      -                         vmSymbols::toFileURL_name(),
      -                         vmSymbols::toFileURL_signature(),
      -                         path_string,
      -                         CHECK);
      -
         VM_PopulateDumpSharedSpace op(builder);
         VMThread::execute(&op);
       
      diff --git a/src/hotspot/share/cds/metaspaceShared.hpp b/src/hotspot/share/cds/metaspaceShared.hpp
      index f26af21676a83..ecc158cc3efcf 100644
      --- a/src/hotspot/share/cds/metaspaceShared.hpp
      +++ b/src/hotspot/share/cds/metaspaceShared.hpp
      @@ -75,6 +75,7 @@ class MetaspaceShared : AllStatic {
       #endif
       
       private:
      +  static void exercise_runtime_cds_code(TRAPS) NOT_CDS_RETURN;
         static void preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS) NOT_CDS_RETURN;
         static void preload_classes(TRAPS) NOT_CDS_RETURN;
       
      diff --git a/test/hotspot/jtreg/ProblemList-Xcomp.txt b/test/hotspot/jtreg/ProblemList-Xcomp.txt
      index 2e9b6da3828ec..1d3342f9b7e8b 100644
      --- a/test/hotspot/jtreg/ProblemList-Xcomp.txt
      +++ b/test/hotspot/jtreg/ProblemList-Xcomp.txt
      @@ -56,6 +56,4 @@ compiler/cha/TypeProfileFinalMethod.java 8341039 generic-all
       
       gc/arguments/TestNewSizeFlags.java 8299116 macosx-aarch64
       
      -runtime/cds/appcds/DumpRuntimeClassesTest.java 8341452 generic-all
      -
       runtime/condy/escapeAnalysis/TestEscapeCondy.java 8339694 generic-all
      diff --git a/test/hotspot/jtreg/runtime/cds/appcds/DumpRuntimeClassesTest.java b/test/hotspot/jtreg/runtime/cds/appcds/DumpRuntimeClassesTest.java
      index 2e530a8d6ddab..c31d96b1c824d 100644
      --- a/test/hotspot/jtreg/runtime/cds/appcds/DumpRuntimeClassesTest.java
      +++ b/test/hotspot/jtreg/runtime/cds/appcds/DumpRuntimeClassesTest.java
      @@ -27,6 +27,9 @@
        * @summary Classes used by CDS at runtime should be in the archived
        * @bug 8324259
        * @requires vm.cds
      + * @requires vm.compMode != "Xcomp"
      + * @comment Running this test with -Xcomp may load other classes which
      + *          are not used in other modes
        * @library /test/lib
        * @compile test-classes/Hello.java
        * @run driver DumpRuntimeClassesTest
      
      From d915ac2abda9ff4cd8c7a628f08d7964bcf3f472 Mon Sep 17 00:00:00 2001
      From: Ramkumar Sunderbabu 
      Date: Thu, 17 Oct 2024 14:34:58 +0000
      Subject: [PATCH 114/118] 8339871: serviceability/sa/TestDebugInfoDecode.java
       should be driver
      
      Reviewed-by: cjplummer, lmesnik
      ---
       test/hotspot/jtreg/serviceability/sa/TestDebugInfoDecode.java | 4 ++--
       1 file changed, 2 insertions(+), 2 deletions(-)
      
      diff --git a/test/hotspot/jtreg/serviceability/sa/TestDebugInfoDecode.java b/test/hotspot/jtreg/serviceability/sa/TestDebugInfoDecode.java
      index 257f950b12f96..946189f11958a 100644
      --- a/test/hotspot/jtreg/serviceability/sa/TestDebugInfoDecode.java
      +++ b/test/hotspot/jtreg/serviceability/sa/TestDebugInfoDecode.java
      @@ -43,7 +43,7 @@
        *          jdk.hotspot.agent/sun.jvm.hotspot.code
        *          jdk.hotspot.agent/sun.jvm.hotspot.debugger
        *          jdk.hotspot.agent/sun.jvm.hotspot.runtime
      - * @run main/othervm/timeout=2400 -Xmx1g -Xcomp TestDebugInfoDecode
      + * @run driver TestDebugInfoDecode
        */
       
       public class TestDebugInfoDecode {
      @@ -107,7 +107,7 @@ public static void main (String... args) throws Exception {
               if (args == null || args.length == 0) {
                   try {
                       theApp = new LingeredApp();
      -                LingeredApp.startApp(theApp);
      +                LingeredApp.startApp(theApp, "-Xcomp");
                       createAnotherToAttach(theApp.getPid());
                   } finally {
                       LingeredApp.stopApp(theApp);
      
      From 7e98f5905b313f4e9bf638f87392b6a1b01df1f8 Mon Sep 17 00:00:00 2001
      From: Alisen Chung 
      Date: Thu, 17 Oct 2024 14:49:03 +0000
      Subject: [PATCH 115/118] 8340987: Open some TextArea awt tests 1
      
      Reviewed-by: prr, abhiscxk
      ---
       .../TextArea/TextAreaAppendScrollTest2.java   |  68 +++++++++++
       .../java/awt/TextArea/TextAreaAppendTest.java |  68 +++++++++++
       .../TextAreaCRLFAutoDetectManualTest.java     | 106 ++++++++++++++++++
       test/jdk/java/awt/TextArea/TextAreaLimit.java |  70 ++++++++++++
       4 files changed, 312 insertions(+)
       create mode 100644 test/jdk/java/awt/TextArea/TextAreaAppendScrollTest2.java
       create mode 100644 test/jdk/java/awt/TextArea/TextAreaAppendTest.java
       create mode 100644 test/jdk/java/awt/TextArea/TextAreaCRLFAutoDetectManualTest.java
       create mode 100644 test/jdk/java/awt/TextArea/TextAreaLimit.java
      
      diff --git a/test/jdk/java/awt/TextArea/TextAreaAppendScrollTest2.java b/test/jdk/java/awt/TextArea/TextAreaAppendScrollTest2.java
      new file mode 100644
      index 0000000000000..2f0e44b415e1f
      --- /dev/null
      +++ b/test/jdk/java/awt/TextArea/TextAreaAppendScrollTest2.java
      @@ -0,0 +1,68 @@
      +/*
      + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved.
      + * 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.Frame;
      +import java.awt.TextArea;
      +
      +/*
      + * @test
      + * @bug 6192116
      + * @summary Auto-scrolling does not work properly for TextArea when appending some text, on XToolkit
      + * @library /java/awt/regtesthelpers
      + * @build PassFailJFrame
      + * @run main/manual TextAreaAppendScrollTest2
      + */
      +
      +public class TextAreaAppendScrollTest2 extends Frame {
      +    TextArea area;
      +    private static final String INSTRUCTIONS = """
      +            Press pass if you see exclamation marks in the bottom of textarea.
      +            Press fail if you don't.
      +            """;
      +
      +    public static void main(String[] args) throws Exception {
      +        PassFailJFrame.builder()
      +                .title("TextAreaAppendScrollTest2")
      +                .instructions(INSTRUCTIONS)
      +                .rows((int) INSTRUCTIONS.lines().count() + 2)
      +                .columns(40)
      +                .testUI(TextAreaAppendScrollTest2::new)
      +                .build()
      +                .awaitAndCheck();
      +    }
      +
      +    public TextAreaAppendScrollTest2() {
      +        setLayout(new BorderLayout());
      +        area = new TextArea("AWT is cool ", 3, 3, TextArea.SCROLLBARS_NONE);
      +        add("Center", area);
      +        setSize(200, 200);
      +        StringBuilder coolStr = new StringBuilder("");
      +        // I count 15 lines with 12 cools per line
      +        for (int i = 0; i < 12 * 15; i++) {
      +            coolStr.append("cool ");
      +        }
      +        coolStr.append("!!!!!!!");
      +        area.append(coolStr.toString());
      +    }
      +}
      diff --git a/test/jdk/java/awt/TextArea/TextAreaAppendTest.java b/test/jdk/java/awt/TextArea/TextAreaAppendTest.java
      new file mode 100644
      index 0000000000000..c47d621e788a6
      --- /dev/null
      +++ b/test/jdk/java/awt/TextArea/TextAreaAppendTest.java
      @@ -0,0 +1,68 @@
      +/*
      + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved.
      + * 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.Frame;
      +import java.awt.TextArea;
      +
      +/*
      + * @test
      + * @bug 4118915
      + * @summary Test appending to a TextArea after the peer is created
      + * @library /java/awt/regtesthelpers
      + * @build PassFailJFrame
      + * @run main/manual TextAreaAppendTest
      + */
      +
      +public class TextAreaAppendTest {
      +    private static final String INSTRUCTIONS = """
      +            If all four lines are visible in TextArea, the test passed.
      +            If the last two lines have only one character visible, the test failed.
      +            """;
      +
      +    public static void main(String[] args) throws Exception {
      +        PassFailJFrame.builder()
      +                .title("TextAreaAppendTest")
      +                .instructions(INSTRUCTIONS)
      +                .rows((int) INSTRUCTIONS.lines().count() + 2)
      +                .columns(40)
      +                .testUI(TextAreaAppendTest::createGUI)
      +                .build()
      +                .awaitAndCheck();
      +    }
      +
      +    public static Frame createGUI() {
      +        Frame f = new Frame("TextAreaAppendTest");
      +        TextArea ta = new TextArea();
      +        f.add(ta);
      +        ta.append("line 1 (added before drawing)\n");
      +        ta.append("line 2 (added before drawing)\n");
      +
      +        f.pack();
      +        f.show();
      +
      +        ta.append("line 3 (added after drawing)\n");
      +        ta.append("line 4 (added after drawing)\n");
      +
      +        return f;
      +    }
      +}
      diff --git a/test/jdk/java/awt/TextArea/TextAreaCRLFAutoDetectManualTest.java b/test/jdk/java/awt/TextArea/TextAreaCRLFAutoDetectManualTest.java
      new file mode 100644
      index 0000000000000..c8c3f0662a5c2
      --- /dev/null
      +++ b/test/jdk/java/awt/TextArea/TextAreaCRLFAutoDetectManualTest.java
      @@ -0,0 +1,106 @@
      +/*
      + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
      + * 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.Button;
      +import java.awt.FlowLayout;
      +import java.awt.Frame;
      +import java.awt.GridLayout;
      +import java.awt.Panel;
      +import java.awt.TextArea;
      +import java.awt.TextField;
      +import java.awt.event.ActionEvent;
      +import java.awt.event.ActionListener;
      +
      +/*
      + * @test
      + * @bug 4800187
      + * @summary REGRESSION:show the wrong selection when there are \r characters in the text
      + * @library /java/awt/regtesthelpers
      + * @build PassFailJFrame
      + * @run main/manual TextAreaCRLFAutoDetectManualTest
      + */
      +
      +public class TextAreaCRLFAutoDetectManualTest {
      +    static int flag = 1;
      +
      +    private static final String INSTRUCTIONS = """
      +                Please click the button several times.
      +                If you see the text '679' selected on the left TextArea
      +                and the same text on the right TextArea
      +                each time you press the button,
      +                the test passed, else failed.
      +                """;
      +
      +    public static void main(String[] args) throws Exception {
      +        PassFailJFrame.builder()
      +                .title("TextAreaCRLFAutoDetectManualTest")
      +                .instructions(INSTRUCTIONS)
      +                .rows((int) INSTRUCTIONS.lines().count() + 2)
      +                .columns(40)
      +                .testUI(TextAreaCRLFAutoDetectManualTest::createGUI)
      +                .build()
      +                .awaitAndCheck();
      +    }
      +
      +    public static Frame createGUI() {
      +        Frame f = new Frame("TextAreaCRLFAutoDetectManualTest");
      +
      +        TextArea ta1 = new TextArea(5, 20);
      +        TextArea ta2 = new TextArea(5, 20);
      +
      +        TextField tf1 = new TextField("123", 20);
      +        TextField tf2 = new TextField("567", 20);
      +        TextField tf3 = new TextField("90", 20);
      +
      +        Button b = new Button("Click Me Several Times");
      +
      +        b.addActionListener(new ActionListener() {
      +            public void actionPerformed(ActionEvent evt) {
      +                ta1.setText("");
      +                ta2.setText("");
      +                flag++;
      +                String eoln = ((flag % 2) != 0) ? "\r\n" : "\n";
      +                ta1.setText(eoln + tf1.getText() + eoln + tf2.getText() + eoln + tf3.getText() + eoln);
      +                ta1.select(6, 10);
      +                ta2.setText(ta1.getSelectedText());
      +                ta1.requestFocus();
      +            }
      +        });
      +
      +        f.setLayout(new FlowLayout());
      +
      +        Panel tfpanel = new Panel();
      +        tfpanel.setLayout(new GridLayout(3, 1));
      +        tfpanel.add(tf1);
      +        tfpanel.add(tf2);
      +        tfpanel.add(tf3);
      +        f.add(tfpanel);
      +
      +        f.add(ta1);
      +        f.add(ta2);
      +        f.add(b);
      +
      +        f.pack();
      +        return f;
      +    }
      +}
      diff --git a/test/jdk/java/awt/TextArea/TextAreaLimit.java b/test/jdk/java/awt/TextArea/TextAreaLimit.java
      new file mode 100644
      index 0000000000000..424305c90ead1
      --- /dev/null
      +++ b/test/jdk/java/awt/TextArea/TextAreaLimit.java
      @@ -0,0 +1,70 @@
      +/*
      + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved.
      + * 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.Frame;
      +import java.awt.TextArea;
      +
      +/*
      + * @test
      + * @bug 4341196
      + * @summary Tests that TextArea can handle more than 64K of text
      + * @library /java/awt/regtesthelpers
      + * @build PassFailJFrame
      + * @run main/manual TextAreaLimit
      + */
      +
      +public class TextAreaLimit extends Frame {
      +    static TextArea text;
      +    private static final String INSTRUCTIONS = """
      +            You will see a text area with 40000 lines of text
      +            each with its own line number. If you see the caret after line 39999
      +            then test passes. Otherwise it fails.
      +            """;
      +
      +    public static void main(String[] args) throws Exception {
      +        PassFailJFrame.builder()
      +                .title("TextAreaLimit")
      +                .instructions(INSTRUCTIONS)
      +                .rows((int) INSTRUCTIONS.lines().count() + 2)
      +                .columns(40)
      +                .testUI(TextAreaLimit::new)
      +                .build()
      +                .awaitAndCheck();
      +    }
      +
      +    public TextAreaLimit() {
      +        setLayout(new BorderLayout());
      +
      +        text = new TextArea();
      +        add(text);
      +        StringBuffer buf = new StringBuffer();
      +        for (int i = 0; i < 40000; i++) {
      +            buf.append(i + "\n");
      +        }
      +        text.setText(buf.toString());
      +        text.setCaretPosition(buf.length());
      +        text.requestFocus();
      +        setSize(200, 200);
      +    }
      +}
      
      From 9a94884e428f9a6fee1aac2af0d0d057aef77e1b Mon Sep 17 00:00:00 2001
      From: Alisen Chung 
      Date: Thu, 17 Oct 2024 14:50:01 +0000
      Subject: [PATCH 116/118] 8341055: Open some TextArea awt tests 2
      
      Reviewed-by: prr, abhiscxk
      ---
       .../awt/TextArea/TextAreaHScrollbarTest.java  |  60 +++++++++
       .../TextArea/TextAreaLineScrollWrapTest.java  |  65 ++++++++++
       .../awt/TextArea/TextAreaScrollbarTest.java   | 116 ++++++++++++++++++
       .../jdk/java/awt/TextArea/TextScrollTest.java |  69 +++++++++++
       4 files changed, 310 insertions(+)
       create mode 100644 test/jdk/java/awt/TextArea/TextAreaHScrollbarTest.java
       create mode 100644 test/jdk/java/awt/TextArea/TextAreaLineScrollWrapTest.java
       create mode 100644 test/jdk/java/awt/TextArea/TextAreaScrollbarTest.java
       create mode 100644 test/jdk/java/awt/TextArea/TextScrollTest.java
      
      diff --git a/test/jdk/java/awt/TextArea/TextAreaHScrollbarTest.java b/test/jdk/java/awt/TextArea/TextAreaHScrollbarTest.java
      new file mode 100644
      index 0000000000000..3bf1c6997638e
      --- /dev/null
      +++ b/test/jdk/java/awt/TextArea/TextAreaHScrollbarTest.java
      @@ -0,0 +1,60 @@
      +/*
      + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved.
      + * 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.Frame;
      +import java.awt.TextArea;
      +
      +/*
      + * @test
      + * @bug 4648702
      + * @summary TextArea horizontal scrollbar behavior is incorrect
      + * @library /java/awt/regtesthelpers
      + * @build PassFailJFrame
      + * @run main/manual TextAreaHScrollbarTest
      + */
      +
      +public class TextAreaHScrollbarTest {
      +    private static final String INSTRUCTIONS = """
      +                Please look at the frame.
      +                If the vertical and horizontal scrollbars are visible
      +                the test passed else failed.
      +                """;
      +
      +    public static void main(String[] args) throws Exception {
      +        PassFailJFrame.builder()
      +                .title("TextAreaHScrollbarTest")
      +                .instructions(INSTRUCTIONS)
      +                .columns(40)
      +                .testUI(TextAreaHScrollbarTest::createGUI)
      +                .build()
      +                .awaitAndCheck();
      +    }
      +
      +    public static Frame createGUI() {
      +        Frame test = new Frame();
      +        test.add(new TextArea("TextAreaHScrollbarTest", 5, 60,
      +                TextArea.SCROLLBARS_BOTH));
      +        test.setSize(200, 100);
      +        return test;
      +    }
      +}
      diff --git a/test/jdk/java/awt/TextArea/TextAreaLineScrollWrapTest.java b/test/jdk/java/awt/TextArea/TextAreaLineScrollWrapTest.java
      new file mode 100644
      index 0000000000000..72ec7c08a6ce4
      --- /dev/null
      +++ b/test/jdk/java/awt/TextArea/TextAreaLineScrollWrapTest.java
      @@ -0,0 +1,65 @@
      +/*
      + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved.
      + * 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.Frame;
      +import java.awt.TextArea;
      +
      +/*
      + * @test
      + * @bug 4776535
      + * @summary Regression: line should not wrap around into multi lines in TextArea.
      + * @library /java/awt/regtesthelpers
      + * @build PassFailJFrame
      + * @run main/manual TextAreaLineScrollWrapTest
      + */
      +
      +public class TextAreaLineScrollWrapTest {
      +    private static final String INSTRUCTIONS = """
      +            You should see a frame "TextAreaLineScrollWrapTest" with
      +            a TextArea that contains a very long line.
      +            If the line is wrapped the test is failed.
      +
      +            Insert a lot of text lines and move a caret to the last one.
      +            If a caret hides and a content of the TextArea
      +            does not scroll the test is failed
      +            else the test is passed.
      +            """;
      +
      +    public static void main(String[] args) throws Exception {
      +        PassFailJFrame.builder()
      +                .title("TextAreaLineScrollWrapTest")
      +                .instructions(INSTRUCTIONS)
      +                .columns(40)
      +                .testUI(TextAreaLineScrollWrapTest::createGUI)
      +                .build()
      +                .awaitAndCheck();
      +    }
      +
      +    public static Frame createGUI() {
      +        Frame f = new Frame("TextAreaLineScrollWrapTest");
      +        f.add(new TextArea("long long long long long long long line...........",
      +                3, 4));
      +        f.setSize(100, 100);
      +        return f;
      +    }
      +}
      diff --git a/test/jdk/java/awt/TextArea/TextAreaScrollbarTest.java b/test/jdk/java/awt/TextArea/TextAreaScrollbarTest.java
      new file mode 100644
      index 0000000000000..ee61922fdb16b
      --- /dev/null
      +++ b/test/jdk/java/awt/TextArea/TextAreaScrollbarTest.java
      @@ -0,0 +1,116 @@
      +/*
      + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved.
      + * 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.Frame;
      +import java.awt.GridLayout;
      +import java.awt.Label;
      +import java.awt.TextArea;
      +
      +/*
      + * @test
      + * @bug 4158997
      + * @key headful
      + * @summary Make sure that the TextArea has both horizontal and
      + * vertical scrollbars when bad scrollbar arguments are passed
      + * into the constructor.
      + * @library /java/awt/regtesthelpers
      + * @build PassFailJFrame
      + * @run main/manual TextAreaScrollbarTest
      + */
      +
      +public class TextAreaScrollbarTest {
      +    private static final String INSTRUCTIONS = """
      +            Check to see that each TextArea has the specified
      +            number and placement of scrollbars, i.e., both scrollbars,
      +            horizontal only, vertical only, or no scrollbars at all.
      +            """;
      +
      +    public static void main(String[] args) throws Exception {
      +        PassFailJFrame.builder()
      +                .title("TextAreaScrollbarTest")
      +                .instructions(INSTRUCTIONS)
      +                .columns(35)
      +                .testUI(TestFrame::new)
      +                .build()
      +                .awaitAndCheck();
      +    }
      +}
      +
      +class TestFrame extends Frame {
      +    private String both = "Both Scrollbars  Both Scrollbars  Both Scrollbars\n";
      +    private String horiz = "Horizontal Scrollbar Only  Horizontal Scrollbar Only\n";
      +    private String vert = "Vertical Scrollbar Only  Vertical Scrollbar Only\n";
      +    private String none = "No Scrollbars  No Scrollbars  No Scrollbars  No Scrollbars\n";
      +
      +    public TestFrame() {
      +        super("Test frame");
      +
      +        // sets a GridLayout w/ 2 columns and an unspecified # of rows
      +        setLayout(new GridLayout(0, 2, 15, 5));
      +
      +        TextArea t1 = new TextArea(both + both + both + both + both + both, 3, 8, 0);
      +        add(new Label("TA should have both scrollbars: arg = 0"));
      +        add(t1);
      +
      +        TextArea t2 = new TextArea(both + both + both + both + both + both, 3, 8, -1);
      +        add(new Label("TA should have both scrollbars: arg = -1"));
      +        add(t2);
      +
      +        TextArea t3 = new TextArea(both + both + both + both + both + both, 3, 8, 4);
      +        add(new Label("TA should have both scrollbars: arg = 4"));
      +        add(t3);
      +
      +        TextArea t4 = new TextArea(horiz + horiz + horiz + horiz + horiz + horiz, 3, 8, 2);
      +        add(new Label("TA should have horizontal scrollbar: arg = 2"));
      +        add(t4);
      +
      +        TextArea t5 = new TextArea(vert + vert + vert + vert + vert + vert, 3, 8, 1);
      +        add(new Label("TA should have vertical scrollbar: arg = 1"));
      +        add(t5);
      +
      +        TextArea t6 = new TextArea(none + none + none + none + none + none, 3, 8, 3);
      +        add(new Label("TA should have no scrollbars: arg = 3"));
      +        add(t6);
      +
      +        TextArea t7 = new TextArea();
      +        t7.setText(both + both + both + both + both + both);
      +        add(new Label("Both scrollbars: TextArea()"));
      +        add(t7);
      +
      +        TextArea t8 = new TextArea(both + both + both + both + both + both);
      +        add(new Label("Both scrollbars: TextArea(String text)"));
      +        add(t8);
      +
      +        TextArea t9 = new TextArea(3, 8);
      +        t9.setText(both + both + both + both + both + both);
      +        add(new Label("Both scrollbars: TextArea(int rows, int columns)"));
      +        add(t9);
      +
      +        TextArea t10 = new TextArea(both + both + both + both + both + both, 3, 8);
      +        add(new Label("Both scrollbars: TextArea(text, rows, columns)"));
      +        add(t10);
      +
      +        setSize(600, 600);
      +    }
      +}
      +
      diff --git a/test/jdk/java/awt/TextArea/TextScrollTest.java b/test/jdk/java/awt/TextArea/TextScrollTest.java
      new file mode 100644
      index 0000000000000..4a92391e7af58
      --- /dev/null
      +++ b/test/jdk/java/awt/TextArea/TextScrollTest.java
      @@ -0,0 +1,69 @@
      +/*
      + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved.
      + * 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.Frame;
      +import java.awt.Panel;
      +import java.awt.TextArea;
      +
      +/*
      + * @test
      + * @bug 4127272
      + * @summary TextArea displays head of text when scrolling horizontal bar.
      + * @library /java/awt/regtesthelpers
      + * @build PassFailJFrame
      + * @run main/manual TextScrollTest
      + */
      +
      +public class TextScrollTest extends Frame {
      +    private static final String INSTRUCTIONS = """
      +            1. A TextArea whose content starts with the text ",
      +               'Scroll till the' will appear on the applet ",
      +            2. Use the Horizontal thumb button of the TextArea to view the entire",
      +               content of the TextArea",
      +            3. While scrolling, if the text 'Scroll till the' appears repeatedly, Click Fail  ",
      +               else Click Pass"
      +            """;
      +
      +    public static void main(String[] args) throws Exception {
      +        PassFailJFrame.builder()
      +                .title("TextScrollTest")
      +                .instructions(INSTRUCTIONS)
      +                .columns(40)
      +                .testUI(TextScrollTest::new)
      +                .build()
      +                .awaitAndCheck();
      +    }
      +
      +    public TextScrollTest() {
      +        this.setLayout(new BorderLayout());
      +
      +        Panel p = new Panel();
      +        TextArea ta = new TextArea("Scroll till the right end of the " +
      +                "TextArea is reached. Action Done?\n", 10, 20);
      +
      +        p.add(ta);
      +        add("Center", p);
      +        setSize(200, 200);
      +    }
      +}
      
      From 979895d175797a71c52da12f245d1040a27172cf Mon Sep 17 00:00:00 2001
      From: Aleksey Shipilev 
      Date: Thu, 17 Oct 2024 15:03:37 +0000
      Subject: [PATCH 117/118] 8342079: Shenandoah: Remove extra
       ShenandoahInitMarkRootsClosure
      
      Reviewed-by: wkemper, rkennke
      ---
       .../share/gc/shenandoah/shenandoahSTWMark.cpp | 32 ++-----------------
       1 file changed, 3 insertions(+), 29 deletions(-)
      
      diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp
      index 9a30b1fed8724..83e897994cb0b 100644
      --- a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp
      +++ b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp
      @@ -37,33 +37,6 @@
       #include "gc/shenandoah/shenandoahSTWMark.hpp"
       #include "gc/shenandoah/shenandoahVerifier.hpp"
       
      -template
      -class ShenandoahInitMarkRootsClosure : public OopClosure {
      -private:
      -  ShenandoahObjToScanQueue* const _queue;
      -  ShenandoahMarkingContext* const _mark_context;
      -
      -  template 
      -  inline void do_oop_work(T* p);
      -public:
      -  ShenandoahInitMarkRootsClosure(ShenandoahObjToScanQueue* q);
      -
      -  void do_oop(narrowOop* p) { do_oop_work(p); }
      -  void do_oop(oop* p)       { do_oop_work(p); }
      -};
      -
      -template 
      -ShenandoahInitMarkRootsClosure::ShenandoahInitMarkRootsClosure(ShenandoahObjToScanQueue* q) :
      -  _queue(q),
      -  _mark_context(ShenandoahHeap::heap()->marking_context()) {
      -}
      -
      -template 
      -template 
      -void ShenandoahInitMarkRootsClosure::do_oop_work(T* p) {
      -  ShenandoahMark::mark_through_ref(p, _queue, _mark_context, false);
      -}
      -
       class ShenandoahSTWMarkTask : public WorkerTask {
       private:
         ShenandoahSTWMark* const _mark;
      @@ -137,8 +110,9 @@ void ShenandoahSTWMark::mark() {
       }
       
       void ShenandoahSTWMark::mark_roots(uint worker_id) {
      -  ShenandoahInitMarkRootsClosure  init_mark(task_queues()->queue(worker_id));
      -  _root_scanner.roots_do(&init_mark, worker_id);
      +  ShenandoahReferenceProcessor* rp = ShenandoahHeap::heap()->ref_processor();
      +  ShenandoahMarkRefsClosure cl(task_queues()->queue(worker_id), rp);
      +  _root_scanner.roots_do(&cl, worker_id);
       }
       
       void ShenandoahSTWMark::finish_mark(uint worker_id) {
      
      From 236c71cad9fa269518456c11edcfb353bbfc084d Mon Sep 17 00:00:00 2001
      From: Alisen Chung 
      Date: Thu, 17 Oct 2024 15:10:38 +0000
      Subject: [PATCH 118/118] 8341376: Open some TextArea awt tests 4
      
      Reviewed-by: prr, abhiscxk
      ---
       .../TextArea/ScrollBarArrowScrollTest.java    | 65 ++++++++++++++++++
       .../java/awt/TextArea/WordWrappingTest.java   | 66 +++++++++++++++++++
       2 files changed, 131 insertions(+)
       create mode 100644 test/jdk/java/awt/TextArea/ScrollBarArrowScrollTest.java
       create mode 100644 test/jdk/java/awt/TextArea/WordWrappingTest.java
      
      diff --git a/test/jdk/java/awt/TextArea/ScrollBarArrowScrollTest.java b/test/jdk/java/awt/TextArea/ScrollBarArrowScrollTest.java
      new file mode 100644
      index 0000000000000..cf54bd5758558
      --- /dev/null
      +++ b/test/jdk/java/awt/TextArea/ScrollBarArrowScrollTest.java
      @@ -0,0 +1,65 @@
      +/*
      + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved.
      + * 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.Frame;
      +import java.awt.TextArea;
      +
      +/*
      + * @test
      + * @bug 6175401
      + * @summary Keeping the left arrow pressedon horiz scrollbar
      + *          does not scroll the text in TextArea, XToolkit
      + * @library /java/awt/regtesthelpers
      + * @build PassFailJFrame
      + * @run main/manual ScrollBarArrowScrollTest
      +*/
      +
      +
      +public class ScrollBarArrowScrollTest extends Frame {
      +    private static final String INSTRUCTIONS = """
      +                1) Make sure, that the TextArea component has focus.
      +                2) Press 'END' key in order to keep cursor at the end
      +                   of the text of the TextArea component.
      +                3) Click on the left arrow on the horizontal scrollbar
      +                   of the TextArea component and keep it pressed.
      +                4) If the text just scrolls once and stops, the test failed.
      +                   Otherwise, the test passed.
      +                """;
      +
      +    public static void main(String[] args) throws Exception {
      +        PassFailJFrame.builder()
      +                .title("ScrollBarArrowScrollTest")
      +                .instructions(INSTRUCTIONS)
      +                .columns(40)
      +                .testUI(ScrollBarArrowScrollTest::new)
      +                .build()
      +                .awaitAndCheck();
      +    }
      +
      +    public ScrollBarArrowScrollTest() {
      +        TextArea textarea = new TextArea("Very very very long string !!!! ", 10, 3);
      +        add(textarea);
      +        pack();
      +
      +    }
      +}
      diff --git a/test/jdk/java/awt/TextArea/WordWrappingTest.java b/test/jdk/java/awt/TextArea/WordWrappingTest.java
      new file mode 100644
      index 0000000000000..7309bc5100823
      --- /dev/null
      +++ b/test/jdk/java/awt/TextArea/WordWrappingTest.java
      @@ -0,0 +1,66 @@
      +/*
      + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved.
      + * 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.FlowLayout;
      +import java.awt.Frame;
      +import java.awt.TextArea;
      +
      +/*
      + * @test
      + * @bug 4992455
      + * @summary REGRESSION: TextArea does not wrap text in JDK 1.5 as JDK 1.4.x
      + * @library /java/awt/regtesthelpers
      + * @build PassFailJFrame
      + * @run main/manual WordWrappingTest
      +*/
      +
      +public class WordWrappingTest {
      +    private static final String INSTRUCTIONS = """
      +                Please look at the frame 'WordWrappingTest'
      +                It contains two TextAreas that have text 'This text should be wrapped.'
      +                One of them has a vertical scrollbar only. Another has no
      +                scrollbars at all.
      +                If their text is not wrapped at word boundaries and you partially see
      +                mentioned text, the test failed.
      +                """;
      +
      +    public static void main(String[] args) throws Exception {
      +        PassFailJFrame.builder()
      +                .title("WordWrappingTest")
      +                .instructions(INSTRUCTIONS)
      +                .testUI(WordWrappingTest::createGUI)
      +                .build()
      +                .awaitAndCheck();
      +    }
      +
      +    public static Frame createGUI() {
      +        Frame f = new Frame("WordWrappingTest");
      +        f.setLayout(new FlowLayout());
      +        f.add(new TextArea("This text should be wrapped.", 5, 10,
      +                TextArea.SCROLLBARS_VERTICAL_ONLY));
      +        f.add(new TextArea("This text should be wrapped.", 5, 10,
      +                TextArea.SCROLLBARS_NONE));
      +        f.pack();
      +        return f;
      +    }
      +}