From d91964411c13749ab09af0bb2d7027f2f0d817d3 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Wed, 25 Sep 2024 01:45:04 +0000 Subject: [PATCH 01/15] 8340717: Remove unused function declarations from java.c/java.h of the launcher Reviewed-by: alanb, dholmes, shade, jwaters --- src/java.base/share/native/libjli/java.c | 4 ---- src/java.base/share/native/libjli/java.h | 8 -------- 2 files changed, 12 deletions(-) diff --git a/src/java.base/share/native/libjli/java.c b/src/java.base/share/native/libjli/java.c index ca0bc4df3c7..d4e20fb21fe 100644 --- a/src/java.base/share/native/libjli/java.c +++ b/src/java.base/share/native/libjli/java.c @@ -118,7 +118,6 @@ static jclass GetApplicationClass(JNIEnv *env); static void TranslateApplicationArgs(int jargc, const char **jargv, int *pargc, char ***pargv); static jboolean AddApplicationOptions(int cpathc, const char **cpathv); -static void SetApplicationClassPath(const char**); static void PrintJavaVersion(JNIEnv *env); static void PrintUsage(JNIEnv* env, jboolean doXUsage); @@ -126,9 +125,6 @@ static void ShowSettings(JNIEnv* env, char *optString); static void ShowResolvedModules(JNIEnv* env); static void ListModules(JNIEnv* env); static void DescribeModule(JNIEnv* env, char* optString); -static jboolean ValidateModules(JNIEnv* env); - -static void SetPaths(int argc, char **argv); static void DumpState(); diff --git a/src/java.base/share/native/libjli/java.h b/src/java.base/share/native/libjli/java.h index 281964d815f..ce5224a7da3 100644 --- a/src/java.base/share/native/libjli/java.h +++ b/src/java.base/share/native/libjli/java.h @@ -48,8 +48,6 @@ # define MB (1024UL * KB) # define GB (1024UL * MB) -#define CURRENT_DATA_MODEL (CHAR_BIT * sizeof(void*)) - /* * Older versions of java launcher used to support JRE version selection - specifically, * the java launcher in JDK 1.8 can be used to launch a java application using a different @@ -103,17 +101,12 @@ JLI_Launch(int argc, char ** argv, /* main argc, argc */ jboolean LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn); -void -GetXUsagePath(char *buf, jint bufsize); - jboolean GetApplicationHome(char *buf, jint bufsize); jboolean GetApplicationHomeFromDll(char *buf, jint bufsize); -#define GetArch() GetArchPath(CURRENT_DATA_MODEL) - /* * Different platforms will implement this, here * pargc is a pointer to the original argc, @@ -149,7 +142,6 @@ void JLI_ShowMessage(const char * message, ...); */ JNIEXPORT void JNICALL JLI_ReportExceptionDescription(JNIEnv * env); -void PrintMachineDependentOptions(); /* * Block current thread and continue execution in new thread. From a190fe78de3edfeee6b49c331e258c313077d80b Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Wed, 25 Sep 2024 02:30:46 +0000 Subject: [PATCH 02/15] 8340708: Optimize StackMapGenerator::processMethod Reviewed-by: liach --- .../jdk/internal/classfile/impl/StackMapGenerator.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 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 f5cd9b80af8..3cf6770e49b 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 @@ -400,6 +400,8 @@ private static Type cpIndexToType(int index, ConstantPoolBuilder cp) { } private void processMethod() { + var frames = this.frames; + var currentFrame = this.currentFrame; currentFrame.setLocalsFromArg(methodName, methodDesc, isStatic, thisType); currentFrame.stackSize = 0; currentFrame.flags = 0; @@ -415,10 +417,10 @@ private void processMethod() { throw generatorError("Expecting a stack map frame"); } if (thisOffset == bcs.bci()) { + Frame nextFrame = frames.get(stackmapIndex++); if (!ncf) { - currentFrame.checkAssignableTo(frames.get(stackmapIndex)); + currentFrame.checkAssignableTo(nextFrame); } - Frame nextFrame = frames.get(stackmapIndex++); while (!nextFrame.dirty) { //skip unmatched frames if (stackmapIndex == frames.size()) return; //skip the rest of this round nextFrame = frames.get(stackmapIndex++); @@ -429,7 +431,7 @@ private void processMethod() { currentFrame.copyFrom(nextFrame); nextFrame.dirty = false; } else if (thisOffset < bcs.bci()) { - throw new ClassFormatError(String.format("Bad stack map offset %d", thisOffset)); + throw generatorError("Bad stack map offset"); } } else if (ncf) { throw generatorError("Expecting a stack map frame"); From 3f4fc02d5350c0f42ac3597fe6b9054ed3ed4641 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Wed, 25 Sep 2024 02:32:29 +0000 Subject: [PATCH 03/15] 8340587: Optimize StackMapGenerator$Frame::checkAssignableTo Reviewed-by: liach --- .../jdk/internal/classfile/impl/StackMapGenerator.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 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 3cf6770e49b..964a0dc2b27 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 @@ -1095,11 +1095,15 @@ void copyFrom(Frame src) { } void checkAssignableTo(Frame target) { + int localsSize = this.localsSize; + int stackSize = this.stackSize; if (target.flags == -1) { - target.locals = locals == null ? null : Arrays.copyOf(locals, localsSize); + target.locals = locals == null ? null : locals.clone(); target.localsSize = localsSize; - target.stack = stack == null ? null : Arrays.copyOf(stack, stackSize); - target.stackSize = stackSize; + if (stackSize > 0) { + target.stack = stack.clone(); + target.stackSize = stackSize; + } target.flags = flags; target.dirty = true; } else { From 8fcb947b520c897a8cf4e6363f6f787106f663d6 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Wed, 25 Sep 2024 02:35:41 +0000 Subject: [PATCH 04/15] 8340710: Optimize DirectClassBuilder::build Reviewed-by: liach --- .../classfile/impl/BufWriterImpl.java | 19 +++++++++++++++- .../classfile/impl/DirectClassBuilder.java | 22 +++++++++---------- .../classfile/impl/DirectCodeBuilder.java | 7 ++++++ .../jdk/internal/classfile/impl/Util.java | 17 +++++++++----- 4 files changed, 46 insertions(+), 19 deletions(-) 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 15d3c8f5b34..4cc6c205fe4 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 @@ -36,6 +36,7 @@ import jdk.internal.access.JavaLangAccess; import jdk.internal.access.SharedSecrets; +import jdk.internal.vm.annotation.ForceInline; public final class BufWriterImpl implements BufWriter { private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); @@ -99,6 +100,7 @@ public void writeU1(int x) { elems[offset++] = (byte) x; } + @ForceInline @Override public void writeU2(int x) { reserveSpace(2); @@ -283,14 +285,19 @@ public void copyTo(byte[] array, int bufferOffset) { // writeIndex methods ensure that any CP info written // is relative to the correct constant pool + @ForceInline @Override public void writeIndex(PoolEntry entry) { int idx = AbstractPoolEntry.maybeClone(constantPool, entry).index(); if (idx < 1 || idx > Character.MAX_VALUE) - throw new IllegalArgumentException(idx + " is not a valid index. Entry: " + entry); + throw invalidIndex(idx, entry); writeU2(idx); } + static IllegalArgumentException invalidIndex(int idx, PoolEntry entry) { + return new IllegalArgumentException(idx + " is not a valid index. Entry: " + entry); + } + @Override public void writeIndexOrZero(PoolEntry entry) { if (entry == null || entry.index() == 0) @@ -298,4 +305,14 @@ public void writeIndexOrZero(PoolEntry entry) { else writeIndex(entry); } + + /** + * Join head and tail into an exact-size buffer + */ + static byte[] join(BufWriterImpl head, BufWriterImpl tail) { + byte[] result = new byte[head.size() + tail.size()]; + head.copyTo(result, 0); + tail.copyTo(result, head.size()); + return result; + } } 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 6901ae7e24c..e92494e6992 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 @@ -175,14 +175,16 @@ public byte[] build() { // BSM writers until everything else is written. // Do this early because it might trigger CP activity + var constantPool = this.constantPool; ClassEntry superclass = superclassEntry; if (superclass != null) superclass = AbstractPoolEntry.maybeClone(constantPool, superclass); else if ((flags & ClassFile.ACC_MODULE) == 0 && !"java/lang/Object".equals(thisClassEntry.asInternalName())) superclass = constantPool.classEntry(ConstantDescs.CD_Object); - List ies = new ArrayList<>(interfaceEntries.size()); - for (ClassEntry ce : interfaceEntries) - ies.add(AbstractPoolEntry.maybeClone(constantPool, ce)); + int interfaceEntriesSize = interfaceEntries.size(); + List ies = new ArrayList<>(interfaceEntriesSize); + for (int i = 0; i < interfaceEntriesSize; i++) + ies.add(AbstractPoolEntry.maybeClone(constantPool, interfaceEntries.get(i))); // We maintain two writers, and then we join them at the end int size = sizeHint == 0 ? 256 : sizeHint; @@ -197,16 +199,15 @@ else if ((flags & ClassFile.ACC_MODULE) == 0 && !"java/lang/Object".equals(thisC attributes.writeTo(tail); // Now we have to append the BSM, if there is one - boolean written = constantPool.writeBootstrapMethods(tail); - if (written) { + if (constantPool.writeBootstrapMethods(tail)) { // Update attributes count tail.patchU2(attributesOffset, attributes.size() + 1); } // Now we can make the head - head.writeInt(ClassFile.MAGIC_NUMBER); - head.writeU2(minorVersion); - head.writeU2(majorVersion); + head.writeLong((((long) ClassFile.MAGIC_NUMBER) << 32) + | ((minorVersion & 0xFFFFL) << 16) + | (majorVersion & 0xFFFFL)); constantPool.writeTo(head); head.writeU2(flags); head.writeIndex(thisClassEntry); @@ -214,9 +215,6 @@ else if ((flags & ClassFile.ACC_MODULE) == 0 && !"java/lang/Object".equals(thisC Util.writeListIndices(head, ies); // Join head and tail into an exact-size buffer - byte[] result = new byte[head.size() + tail.size()]; - head.copyTo(result, 0); - tail.copyTo(result, head.size()); - return result; + return BufWriterImpl.join(head, tail); } } 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 a9be0695911..fd7a8e55bf8 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 @@ -190,6 +190,13 @@ private void writeExceptionHandlers(BufWriterImpl buf) { int pos = buf.size(); int handlersSize = handlers.size(); buf.writeU2(handlersSize); + if (handlersSize > 0) { + writeExceptionHandlers(buf, pos); + } + } + + private void writeExceptionHandlers(BufWriterImpl buf, int pos) { + int handlersSize = handlers.size(); for (AbstractPseudoInstruction.ExceptionCatchImpl h : handlers) { int startPc = labelToBci(h.tryStart()); int endPc = labelToBci(h.tryEnd()); 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 80d908f6ce7..e1e3f6fb3d2 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 @@ -50,6 +50,7 @@ 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; @@ -249,17 +250,21 @@ private static > void writeAttribute(BufWriterImpl writer } } + @ForceInline public static void writeAttributes(BufWriterImpl buf, List> list) { - buf.writeU2(list.size()); - for (var e : list) { - writeAttribute(buf, e); + int size = list.size(); + buf.writeU2(size); + for (int i = 0; i < size; i++) { + writeAttribute(buf, list.get(i)); } } + @ForceInline static void writeList(BufWriterImpl buf, List list) { - buf.writeU2(list.size()); - for (var e : list) { - e.writeTo(buf); + int size = list.size(); + buf.writeU2(size); + for (int i = 0; i < size; i++) { + list.get(i).writeTo(buf); } } From f66c92e9ea4fd53c632d564a1377dca65bfa9519 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Wed, 25 Sep 2024 03:07:45 +0000 Subject: [PATCH 05/15] 8339935: Open source several AWT focus tests - series 5 Reviewed-by: prr --- test/jdk/java/awt/Focus/DeiconifyTest.java | 79 +++++++++++++++++ .../java/awt/Focus/HiddenTraversalTest.java | 72 +++++++++++++++ .../java/awt/Focus/LightweightPopupTest.java | 87 +++++++++++++++++++ .../java/awt/Focus/ProxiedWindowHideTest.java | 77 ++++++++++++++++ 4 files changed, 315 insertions(+) create mode 100644 test/jdk/java/awt/Focus/DeiconifyTest.java create mode 100644 test/jdk/java/awt/Focus/HiddenTraversalTest.java create mode 100644 test/jdk/java/awt/Focus/LightweightPopupTest.java create mode 100644 test/jdk/java/awt/Focus/ProxiedWindowHideTest.java diff --git a/test/jdk/java/awt/Focus/DeiconifyTest.java b/test/jdk/java/awt/Focus/DeiconifyTest.java new file mode 100644 index 00000000000..e87b13b8e65 --- /dev/null +++ b/test/jdk/java/awt/Focus/DeiconifyTest.java @@ -0,0 +1,79 @@ +/* + * 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 4380809 + * @summary Focus disappears after deiconifying frame + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DeiconifyTest +*/ + +import java.awt.Button; +import java.awt.Frame; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; + +public class DeiconifyTest { + + private static final String INSTRUCTIONS = """ + 1. Activate frame \"Main frame\" + be sure that button has focus + 2. Minimize frame and then restore it. + If the button has focus then test passed, else failed"""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("DeiconifyTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int)INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(DeiconifyTest::createTestUI) + .logArea() + .build() + .awaitAndCheck(); + } + + private static Frame createTestUI() { + Frame frame = new Frame("Main frame"); + Button button = new Button("button"); + button.addFocusListener(new FocusListener() { + public void focusGained(FocusEvent fe) { + println("focus gained"); + } + public void focusLost(FocusEvent fe) { + println("focus lost"); + } + }); + frame.add(button); + frame.setSize(300, 100); + + return frame; + } + + static void println(String messageIn) { + PassFailJFrame.log(messageIn); + } +} + diff --git a/test/jdk/java/awt/Focus/HiddenTraversalTest.java b/test/jdk/java/awt/Focus/HiddenTraversalTest.java new file mode 100644 index 00000000000..59e7f477945 --- /dev/null +++ b/test/jdk/java/awt/Focus/HiddenTraversalTest.java @@ -0,0 +1,72 @@ +/* + * 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 4157017 + * @summary Checks whether focus can be traversed when component not visible + within parent container. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual HiddenTraversalTest +*/ + +import java.awt.Button; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Panel; + +public class HiddenTraversalTest { + + private static final String INSTRUCTIONS = """ + Examine the Frame. If six buttons are visible, resize the frame + so that only four are visible. If fewer than six buttons are + visible, do nothing.\n + Now, repeatedly press the tab key. Focus should cycle through the + visible and invisible buttons. If after six presses of the tab + button 'Button 0' has focus, the test passes. If focus is instead + stuck at 'Button 3', the test fails."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("HiddenTraversalTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(HiddenTraversalTest::createTestUI) + .build() + .awaitAndCheck(); + } + + private static Frame createTestUI() { + Frame f = new Frame("Focus test"); + Panel p = new Panel(new FlowLayout()); + for (int i = 0; i < 6; i++) { + p.add(new Button("Button " + i)); + } + f.add(p); + f.setSize(200, 100); + return f; + } + +} + diff --git a/test/jdk/java/awt/Focus/LightweightPopupTest.java b/test/jdk/java/awt/Focus/LightweightPopupTest.java new file mode 100644 index 00000000000..bc3dd0d038b --- /dev/null +++ b/test/jdk/java/awt/Focus/LightweightPopupTest.java @@ -0,0 +1,87 @@ +/* + * 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 4472032 + * @summary Switching between lightweight menus by horizontal arrow key works incorrect + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual LightweightPopupTest +*/ + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; + +public class LightweightPopupTest { + + private static final String INSTRUCTIONS = """ + When the test starts, you will see a frame titled + 'Lightweight Popup Test', which contains a button + (titled 'JButton') and two menus ('Menu 1' and 'Menu 2'). + Make sure that both menus, when expanded, fit entirely + into the frame. Now take the following steps: + 1. Click on 'JButton' to focus it. + 2. Click 'Menu 1' to expand it. + 3. Press right arrow to select 'Menu 2'. + Now check where the focus is. If it is on 'JButton' + (you can press space bar to see if it is there), then + the test failed. If 'JButton' is not focused, then + the test passed."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("LightweightPopupTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int)INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(LightweightPopupTest::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + + JFrame frame = new JFrame("Lightweight Popup Test"); + JButton button = new JButton("JButton"); + JMenuBar menuBar = new JMenuBar(); + JMenu menu1 = new JMenu("Menu 1"); + menu1.add(new JMenuItem("Menu Item 1")); + menu1.add(new JMenuItem("Menu Item 2")); + menuBar.add(menu1); + JMenu menu2 = new JMenu("Menu 2"); + menu2.add(new JMenuItem("Menu Item 3")); + menu2.add(new JMenuItem("Menu Item 4")); + menuBar.add(menu2); + + frame.add(button); + frame.setJMenuBar(menuBar); + frame.setSize(300, 200); + return frame; + } + +} + diff --git a/test/jdk/java/awt/Focus/ProxiedWindowHideTest.java b/test/jdk/java/awt/Focus/ProxiedWindowHideTest.java new file mode 100644 index 00000000000..a99ec4f0a0d --- /dev/null +++ b/test/jdk/java/awt/Focus/ProxiedWindowHideTest.java @@ -0,0 +1,77 @@ +/* + * 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 4396407 + * @summary Tests that after a proxied window is hidden, focus is being restored correctly + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ProxiedWindowHideTest +*/ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Container; +import javax.swing.Box; +import javax.swing.JComboBox; +import javax.swing.JFrame; + +public class ProxiedWindowHideTest { + + private static final String INSTRUCTIONS = """ + You will see a JFrame. + Click on JComboBox, list will expand then select any item in it. + After selection, list should collapse. + Click on Button('Push'). + If you are able to make it focused by mouse click, + (black rectangle will appear around it) the test is PASSED, + otherwise the test is FAILED."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("ProxiedWindowHideTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(ProxiedWindowHideTest::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + JFrame frame = new JFrame("ProxiedWindowHideTest frame"); + String[] petStrings = { "Bird", "Cat", "Dog", "Rabbit", "Pig" }; + JComboBox cb = new JComboBox(petStrings); + + cb.setLightWeightPopupEnabled(false); + Container parent = Box.createVerticalBox(); + parent.add(new Button("Push")); + parent.add(cb); + frame.add(parent, BorderLayout.CENTER); + frame.pack(); + return frame; + } + +} + From 544662f8e69ae1161b9fea1e01560729a53ac829 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Wed, 25 Sep 2024 12:15:07 +0000 Subject: [PATCH 06/15] 8339541: CSS rule is not specific enough Reviewed-by: jjg --- .../internal/doclets/formats/html/resources/stylesheet.css | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css index 1130f14dc35..97fcc91eadc 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css @@ -360,8 +360,11 @@ main { padding:10px 20px; position:relative; } -section[id$=-description] :is(dl, ol, ul, p, div, blockquote, pre):last-child, -section[id$=-description] :is(dl, ol, ul):last-child > :is(li, dd):last-child { +/* Compensate for non-collapsing margins between element description and summary tables */ +div.horizontal-scroll > section[id$=-description] > :is(dl, ol, ul, p, div, blockquote, pre):last-child, +div.horizontal-scroll > section[id$=-description] > :last-child > :is(li, dd):last-child, +section.class-description > div.horizontal-scroll > :is(dl, ol, ul, p, div, blockquote, pre):last-child, +section.class-description > div.horizontal-scroll > :last-child > :is(li, dd):last-child { margin-bottom:4px; } dl.notes > dt { From 0b2c3b114f086c7eece81ddb5063ccbd850b6bdd Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Wed, 25 Sep 2024 13:04:46 +0000 Subject: [PATCH 07/15] 8340885: Desugar ZipCoder.Comparison Reviewed-by: lancea, eirbjo --- .../share/classes/java/util/zip/ZipCoder.java | 43 +++++++++---------- .../share/classes/java/util/zip/ZipFile.java | 6 +-- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/java.base/share/classes/java/util/zip/ZipCoder.java b/src/java.base/share/classes/java/util/zip/ZipCoder.java index 6692703c1b3..8d4a05389ee 100644 --- a/src/java.base/share/classes/java/util/zip/ZipCoder.java +++ b/src/java.base/share/classes/java/util/zip/ZipCoder.java @@ -56,28 +56,27 @@ public static ZipCoder get(Charset charset) { } /** - * This enum represents the three possible return values for + * Constants representing the three possible return values for * {@link #compare(String, byte[], int, int, boolean)} when * this method compares a lookup name to a string encoded in the * CEN byte array. */ - enum Comparison { - /** + static final byte + /* * The lookup string is exactly equal * to the encoded string. - */ - EXACT_MATCH, - /** + */ + EXACT_MATCH = 0, + /* * The lookup string and the encoded string differs only * by the encoded string having a trailing '/' character. */ - DIRECTORY_MATCH, - /** + DIRECTORY_MATCH = 1, + /* * The lookup string and the encoded string do not match. * (They are neither an exact match or a directory match.) */ - NO_MATCH - } + NO_MATCH = 2; String toString(byte[] ba, int off, int length) { try { @@ -197,13 +196,13 @@ private CharsetEncoder encoder() { * The return values of this method are as follows: * * If the lookup name is exactly equal to the encoded string, return - * {@link Comparison#EXACT_MATCH}. + * {@link EXACT_MATCH}. * * If the parameter {@code matchDirectory} is {@code true} and the * two strings differ only by the encoded string having an extra - * trailing '/' character, then return {@link Comparison#DIRECTORY_MATCH}. + * trailing '/' character, then return {@link DIRECTORY_MATCH}. * - * Otherwise, return {@link Comparison#NO_MATCH} + * Otherwise, return {@link NO_MATCH} * * While a general implementation will need to decode bytes into a * String for comparison, this can be avoided if the String coder @@ -217,18 +216,18 @@ private CharsetEncoder encoder() { * a directory match will also be tested * */ - Comparison compare(String str, byte[] b, int off, int len, boolean matchDirectory) { + byte compare(String str, byte[] b, int off, int len, boolean matchDirectory) { String decoded = toString(b, off, len); if (decoded.startsWith(str)) { if (decoded.length() == str.length()) { - return Comparison.EXACT_MATCH; + return EXACT_MATCH; } else if (matchDirectory && decoded.length() == str.length() + 1 && decoded.endsWith("/") ) { - return Comparison.DIRECTORY_MATCH; + return DIRECTORY_MATCH; } } - return Comparison.NO_MATCH; + return NO_MATCH; } static final class UTF8ZipCoder extends ZipCoder { @@ -278,19 +277,19 @@ private boolean hasTrailingSlash(byte[] a, int end) { } @Override - Comparison compare(String str, byte[] b, int off, int len, boolean matchDirectory) { + byte compare(String str, byte[] b, int off, int len, boolean matchDirectory) { try { byte[] encoded = JLA.getBytesNoRepl(str, UTF_8.INSTANCE); int mismatch = Arrays.mismatch(encoded, 0, encoded.length, b, off, off+len); if (mismatch == -1) { - return Comparison.EXACT_MATCH; + return EXACT_MATCH; } else if (matchDirectory && len == mismatch + 1 && hasTrailingSlash(b, off + len)) { - return Comparison.DIRECTORY_MATCH; + return DIRECTORY_MATCH; } else { - return Comparison.NO_MATCH; + return NO_MATCH; } } catch (CharacterCodingException e) { - return Comparison.NO_MATCH; + return NO_MATCH; } } } diff --git a/src/java.base/share/classes/java/util/zip/ZipFile.java b/src/java.base/share/classes/java/util/zip/ZipFile.java index 333e3d01849..d54e6c1e4fc 100644 --- a/src/java.base/share/classes/java/util/zip/ZipFile.java +++ b/src/java.base/share/classes/java/util/zip/ZipFile.java @@ -1869,15 +1869,15 @@ private EntryPos getEntryPos(String name, boolean addSlash) { // Compare the lookup name with the name encoded in the CEN switch (zc.compare(name, cen, noff, nlen, addSlash)) { - case EXACT_MATCH: + case ZipCoder.EXACT_MATCH: // We found an exact match for "name" return new EntryPos(name, pos); - case DIRECTORY_MATCH: + case ZipCoder.DIRECTORY_MATCH: // We found the directory "name/" // Track its position, then continue the search for "name" dirPos = pos; break; - case NO_MATCH: + case ZipCoder.NO_MATCH: // Hash collision, continue searching } } From a3da51575a3cf847196b489317bb75d0dd6d2390 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Wed, 25 Sep 2024 13:12:47 +0000 Subject: [PATCH 08/15] 8340568: Incorrect escaping of single quotes when pretty-printing character literals Reviewed-by: mcimadamore --- .../com/sun/tools/javac/tree/Pretty.java | 2 +- .../tools/javac/tree/PrettyCharLiteral.java | 89 +++++++++++++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 test/langtools/tools/javac/tree/PrettyCharLiteral.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java index e97d07b1d2b..919b2325ef6 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java @@ -1467,7 +1467,7 @@ public void visitLiteral(JCLiteral tree) { break; case CHAR: print('\''); - print(Convert.quote(String.valueOf((char)((Number)tree.value).intValue()))); + print(Convert.quote((char)((Number)tree.value).intValue(), true)); print('\''); break; case BOOLEAN: diff --git a/test/langtools/tools/javac/tree/PrettyCharLiteral.java b/test/langtools/tools/javac/tree/PrettyCharLiteral.java new file mode 100644 index 00000000000..eced3209607 --- /dev/null +++ b/test/langtools/tools/javac/tree/PrettyCharLiteral.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2024, Google LLC. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8340568 + * @summary Incorrect escaping of single quotes when pretty-printing character literals + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.file + * jdk.compiler/com.sun.tools.javac.tree + * jdk.compiler/com.sun.tools.javac.util + */ + +import com.sun.tools.javac.file.JavacFileManager; +import com.sun.tools.javac.tree.Pretty; +import com.sun.tools.javac.tree.TreeMaker; +import com.sun.tools.javac.util.Context; + +import java.io.IOException; +import java.io.StringWriter; + +public class PrettyCharLiteral { + public static void main(String... args) throws Exception { + new PrettyCharLiteral().run(); + } + + private final TreeMaker make; + + private PrettyCharLiteral() { + Context ctx = new Context(); + JavacFileManager.preRegister(ctx); + this.make = TreeMaker.instance(ctx); + } + + void run() throws Exception { + assertEquals( + prettyPrintLiteral('\''), + """ + '\\'' + """.trim()); + assertEquals( + prettyPrintLiteral('"'), + """ + '"' + """.trim()); + assertEquals( + prettyPrintLiteral("'"), + """ + "'" + """.trim()); + assertEquals( + prettyPrintLiteral("\""), + """ + "\\"" + """.trim()); + } + + private void assertEquals(String actual, String expected) { + if (!actual.equals(expected)) { + throw new AssertionError("expected: " + expected + ", actual: " + actual); + } + } + + private String prettyPrintLiteral(Object value) throws IOException { + StringWriter sw = new StringWriter(); + new Pretty(sw, true).printExpr(make.Literal(value)); + return sw.toString(); + } +} From f74f2ac19367011363d5464dc40bd155582c04fe Mon Sep 17 00:00:00 2001 From: George Adams Date: Wed, 25 Sep 2024 16:25:23 +0000 Subject: [PATCH 09/15] 8340815: Add SECURITY.md file Reviewed-by: mr, jwaters, erikj --- SECURITY.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000000..f4c5e7e67cb --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,3 @@ +# JDK Vulnerabilities + +Please follow the process outlined in the [OpenJDK Vulnerability Policy](https://openjdk.org/groups/vulnerability/report) to disclose vulnerabilities in the JDK. From 6612e76cb2c9e156a87a177a2d8cf9ee3830000e Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Wed, 25 Sep 2024 16:36:28 +0000 Subject: [PATCH 10/15] 8340946: Add vmTestbase/gc/memory/Nio/Nio.java and java/nio/Buffer/LimitDirectMemory.java to problem list Reviewed-by: liach, dcubed, alanb --- test/hotspot/jtreg/ProblemList.txt | 1 + test/jdk/ProblemList.txt | 2 ++ 2 files changed, 3 insertions(+) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index bec3f64c7d8..aefe09fd3ae 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -174,6 +174,7 @@ vmTestbase/nsk/jvmti/scenarios/capability/CM03/cm03t001/TestDescription.java 807 vmTestbase/nsk/jvmti/InterruptThread/intrpthrd003/TestDescription.java 8288911 macosx-all vmTestbase/gc/lock/jni/jnilock002/TestDescription.java 8192647 generic-all +vmTestbase/gc/memory/Nio/Nio.java 8340728 generic-all vmTestbase/jit/escape/LockCoarsening/LockCoarsening001.java 8148743 generic-all vmTestbase/jit/escape/LockCoarsening/LockCoarsening002.java 8208259 generic-all diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 1727722335f..36043645ca9 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -563,6 +563,8 @@ java/net/Socket/asyncClose/Race.java 8317801 aix-ppc6 # jdk_nio +java/nio/Buffer/LimitDirectMemory.java 8340728 generic-all + java/nio/channels/AsynchronousSocketChannel/StressLoopback.java 8211851 aix-ppc64 java/nio/channels/Channels/SocketChannelStreams.java 8317838 aix-ppc64 From f4c3dfd6f8c5b26fbf4b6e75566c94553d2fdde9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eirik=20Bj=C3=B8rsn=C3=B8s?= Date: Wed, 25 Sep 2024 16:36:44 +0000 Subject: [PATCH 11/15] 8340684: Reading from an input stream backed by a closed ZipFile has no test coverage Reviewed-by: lancea --- .../java/util/zip/ZipFile/ReadAfterClose.java | 128 ++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 test/jdk/java/util/zip/ZipFile/ReadAfterClose.java diff --git a/test/jdk/java/util/zip/ZipFile/ReadAfterClose.java b/test/jdk/java/util/zip/ZipFile/ReadAfterClose.java new file mode 100644 index 00000000000..a083daf7668 --- /dev/null +++ b/test/jdk/java/util/zip/ZipFile/ReadAfterClose.java @@ -0,0 +1,128 @@ +/* + * 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 8340684 + @summary Verify unspecified, but long-standing behavior when reading + from an input stream obtained using ZipFile::getInputStream after + the ZipFile has been closed. + @run junit ReadAfterClose + */ + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.stream.Stream; +import java.util.zip.CRC32; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class ReadAfterClose { + + // ZIP file used in this test + private Path zip = Path.of("read-after-close.zip"); + + /** + * Create a sample ZIP file for use by this test + * @throws IOException if an unexpected IOException occurs + */ + @BeforeEach + public void setUp() throws IOException { + byte[] content = "hello".repeat(1000).getBytes(StandardCharsets.UTF_8); + try (OutputStream out = Files.newOutputStream(zip); + ZipOutputStream zo = new ZipOutputStream(out)) { + { + zo.putNextEntry(new ZipEntry("deflated.txt")); + zo.write(content); + } + { + ZipEntry entry = new ZipEntry("stored.txt"); + entry.setMethod(ZipEntry.STORED); + CRC32 crc = new CRC32(); + crc.update(content); + entry.setCrc(crc.getValue()); + entry.setSize(content.length); + zo.putNextEntry(entry); + zo.write(content); + } + } + } + + /** + * Delete the ZIP file produced by this test + * @throws IOException if an unexpected IOException occurs + */ + @AfterEach + public void cleanup() throws IOException { + Files.deleteIfExists(zip); + } + + /** + * Produce arguments with a variation of stored / deflated entries, + * and read behavior before closing the ZipFile. + * @return + */ + public static Stream arguments() { + return Stream.of( + Arguments.of("stored.txt", true), + Arguments.of("stored.txt", false), + Arguments.of("deflated.txt", true), + Arguments.of("deflated.txt", false) + ); + } + /** + * Attempting to read from an InputStream obtained by ZipFile.getInputStream + * after the backing ZipFile is closed should throw IOException + * + * @throws IOException if an unexpected IOException occurs + */ + @ParameterizedTest + @MethodSource("arguments") + public void readAfterClose(String entryName, boolean readFirst) throws IOException { + // Retain a reference to an input stream backed by a closed ZipFile + InputStream in; + try (ZipFile zf = new ZipFile(zip.toFile())) { + in = zf.getInputStream(new ZipEntry(entryName)); + // Optionally consume a single byte from the stream before closing + if (readFirst) { + in.read(); + } + } + + assertThrows(IOException.class, () -> { + in.read(); + }); + } +} \ No newline at end of file From 5cecbb320d0eab35c3eb386ac6886f7aa70f7882 Mon Sep 17 00:00:00 2001 From: Alexander Zuev Date: Wed, 25 Sep 2024 16:46:49 +0000 Subject: [PATCH 12/15] 8340228: Open source couple more miscellaneous AWT tests Reviewed-by: prr --- .../EditAndPrintTest/EditAndPrintTest.java | 152 ++++++++++++++++++ .../TextField/GetTextTest/GetTextTest.java | 104 ++++++++++++ .../SetEchoCharTest3/SetEchoCharTest3.java | 65 ++++++++ 3 files changed, 321 insertions(+) create mode 100644 test/jdk/java/awt/Desktop/EditAndPrintTest/EditAndPrintTest.java create mode 100644 test/jdk/java/awt/TextField/GetTextTest/GetTextTest.java create mode 100644 test/jdk/java/awt/TextField/SetEchoCharTest3/SetEchoCharTest3.java diff --git a/test/jdk/java/awt/Desktop/EditAndPrintTest/EditAndPrintTest.java b/test/jdk/java/awt/Desktop/EditAndPrintTest/EditAndPrintTest.java new file mode 100644 index 00000000000..3f161f7fcaf --- /dev/null +++ b/test/jdk/java/awt/Desktop/EditAndPrintTest/EditAndPrintTest.java @@ -0,0 +1,152 @@ +/* + * 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 + * @key printer + * @bug 6255196 + * @summary Verifies the function of methods edit(java.io.File file) and + * print(java.io.File file) + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual EditAndPrintTest + */ + +import java.awt.Desktop; +import java.awt.Desktop.Action; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import javax.swing.JPanel; + +public class EditAndPrintTest extends JPanel { + + static final String INSTRUCTIONS = """ + This test tries to edit and print a directory, which will expectedly raise IOException. + Then this test would edit and print a .txt file, which should be successful. + After test execution close the editor if it was launched by test. + If you see any EXCEPTION messages in the output press FAIL. + """; + + public EditAndPrintTest() { + 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(); + + if (!desktop.isSupported(Action.PRINT) && !desktop.isSupported(Action.EDIT)) { + PassFailJFrame.log("Neither EDIT nor PRINT actions are supported. Nothing to test."); + PassFailJFrame.forcePass(); + } + + /* + * Part 1: print or edit a directory, which should throw an IOException. + */ + File userHome = new File(System.getProperty("user.home")); + try { + if (desktop.isSupported(Action.EDIT)) { + PassFailJFrame.log("Trying to edit " + userHome); + desktop.edit(userHome); + PassFailJFrame.log("No exception has been thrown for editing " + + "directory " + userHome.getPath()); + PassFailJFrame.log("Test failed."); + } else { + PassFailJFrame.log("Action EDIT is unsupported."); + } + } catch (IOException e) { + PassFailJFrame.log("Expected IOException is caught."); + } + + try { + if (desktop.isSupported(Action.PRINT)) { + PassFailJFrame.log("Trying to print " + userHome); + desktop.print(userHome); + PassFailJFrame.log("No exception has been thrown for printing " + + "directory " + userHome.getPath()); + PassFailJFrame.log("Test failed."); + } else { + PassFailJFrame.log("Action PRINT is unsupported.\n"); + } + } catch (IOException e) { + PassFailJFrame.log("Expected IOException is caught."); + } + + /* + * Part 2: print or edit a normal .txt file, which may succeed if there + * is associated application to print or edit the given file. It fails + * otherwise. + */ + // Create a temp .txt file for test. + String testFilePath = System.getProperty("java.io.tmpdir") + File.separator + "JDIC-test.txt"; + File testFile = null; + try { + PassFailJFrame.log("Creating temporary file."); + testFile = File.createTempFile("JDIC-test", ".txt", new File(System.getProperty("java.io.tmpdir"))); + testFile.deleteOnExit(); + FileWriter writer = new FileWriter(testFile); + writer.write("This is a temp file used to test print() method of Desktop."); + writer.flush(); + writer.close(); + } catch (java.io.IOException ioe){ + PassFailJFrame.log("EXCEPTION: " + ioe.getMessage()); + PassFailJFrame.forceFail("Failed to create temp file for testing."); + } + + try { + if (desktop.isSupported(Action.EDIT)) { + PassFailJFrame.log("Try to edit " + testFile); + desktop.edit(testFile); + PassFailJFrame.log("Succeed."); + } + } catch (IOException e) { + PassFailJFrame.log("EXCEPTION: " + e.getMessage()); + } + + try { + if (desktop.isSupported(Action.PRINT)) { + PassFailJFrame.log("Trying to print " + testFile); + desktop.print(testFile); + PassFailJFrame.log("Succeed."); + } + } catch (IOException e) { + PassFailJFrame.log("EXCEPTION: " + e.getMessage()); + } + } + + public static void main(String args[]) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Edit and Print test") + .splitUI(EditAndPrintTest::new) + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 1) + .columns(60) + .logArea() + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/TextField/GetTextTest/GetTextTest.java b/test/jdk/java/awt/TextField/GetTextTest/GetTextTest.java new file mode 100644 index 00000000000..ab5aebc11d4 --- /dev/null +++ b/test/jdk/java/awt/TextField/GetTextTest/GetTextTest.java @@ -0,0 +1,104 @@ +/* + * 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. + */ + +/* + * @test + * @bug 4100188 + * @key headful + * @summary Make sure that TextFields contain all of, + * and exactly, the text that was entered into them. + * @run main GetTextTest + */ + +import java.awt.AWTException; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Point; +import java.awt.Robot; +import java.awt.TextField; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.lang.reflect.InvocationTargetException; + +public class GetTextTest extends Frame implements ActionListener { + private final String s = "test string"; + private volatile String ac; + private TextField t; + private Point location; + private Dimension size; + + public void setupGUI() { + setLayout(new FlowLayout(FlowLayout.LEFT)); + + t = new TextField(s, 32); + add(new Label("Hit after text")); + add(t); + t.addActionListener(this); + setLocationRelativeTo(null); + pack(); + setVisible(true); + } + + public void actionPerformed(ActionEvent evt) { + ac = evt.getActionCommand(); + } + + public void performTest() throws AWTException, InterruptedException, + InvocationTargetException { + EventQueue.invokeAndWait(() -> { + location = t.getLocationOnScreen(); + size = t.getSize(); + }); + Robot robot = new Robot(); + robot.setAutoDelay(50); + robot.delay(1000); + robot.waitForIdle(); + robot.mouseMove(location.x + size.width - 3, location.y + (size.height / 2)); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(1000); + robot.waitForIdle(); + robot.keyPress(KeyEvent.VK_ENTER); + robot.keyRelease(KeyEvent.VK_ENTER); + robot.delay(1000); + if (!s.equals(ac)) { + throw new RuntimeException("Action command should be the same as text field content"); + } + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException { + GetTextTest test = new GetTextTest(); + EventQueue.invokeAndWait(test::setupGUI); + try { + test.performTest(); + } finally { + EventQueue.invokeAndWait(test::dispose); + } + } +} diff --git a/test/jdk/java/awt/TextField/SetEchoCharTest3/SetEchoCharTest3.java b/test/jdk/java/awt/TextField/SetEchoCharTest3/SetEchoCharTest3.java new file mode 100644 index 00000000000..10779365def --- /dev/null +++ b/test/jdk/java/awt/TextField/SetEchoCharTest3/SetEchoCharTest3.java @@ -0,0 +1,65 @@ +/* + * 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 4222122 + * @summary TextField.setEchoCharacter() seems to be broken + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual SetEchoCharTest3 + */ + +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.TextField; +import java.lang.reflect.InvocationTargetException; + +public class SetEchoCharTest3 extends Frame { + static String INSTRUCTIONS = """ + Type in the text field and "*" characters should echo. + If only one "*" echoes and then the system beeps after + the second character is typed, then press Fail, otherwise press Pass. + """; + public SetEchoCharTest3() { + setLayout(new FlowLayout()); + add(new Label("Enter text:")); + TextField tf = new TextField(15); + tf.setEchoChar('*'); + add(tf); + pack(); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Set Echo Char Test 3") + .testUI(SetEchoCharTest3::new) + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 1) + .columns(40) + .build() + .awaitAndCheck(); + } +} From c9cf48094a13958ebcc4c3f319e4e3e8479f3a8e Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Wed, 25 Sep 2024 17:19:02 +0000 Subject: [PATCH 13/15] 8340956: ProblemList 4 java/nio/channels/DatagramChannel tests on macosx-all Reviewed-by: liach, alanb, darcy, dfuchs --- test/jdk/ProblemList.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 36043645ca9..8060792a51f 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -569,10 +569,13 @@ java/nio/channels/AsynchronousSocketChannel/StressLoopback.java 8211851 aix-ppc6 java/nio/channels/Channels/SocketChannelStreams.java 8317838 aix-ppc64 -java/nio/channels/DatagramChannel/AdaptorMulticasting.java 8308807 aix-ppc64 +java/nio/channels/DatagramChannel/AdaptorMulticasting.java 8308807,8144003 aix-ppc64,macosx-all java/nio/channels/DatagramChannel/AfterDisconnect.java 8308807 aix-ppc64 java/nio/channels/DatagramChannel/ManySourcesAndTargets.java 8264385 macosx-aarch64 java/nio/channels/DatagramChannel/Unref.java 8233437 generic-all +java/nio/channels/DatagramChannel/BasicMulticastTests.java 8144003 macosx-all +java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java 8144003 macosx-all +java/nio/channels/DatagramChannel/Promiscuous.java 8144003 macosx-all ############################################################################ From 9b859c42a08863f8f488a929a7b1a8e041621dd7 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Wed, 25 Sep 2024 18:29:30 +0000 Subject: [PATCH 14/15] 8340838: Clean up MutableCallSite to use explicit release fence instead of AtomicInteger Reviewed-by: jrose, redestad, shade --- .../share/classes/java/lang/invoke/MutableCallSite.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/java/lang/invoke/MutableCallSite.java b/src/java.base/share/classes/java/lang/invoke/MutableCallSite.java index 50ba77d8f96..65872e360a7 100644 --- a/src/java.base/share/classes/java/lang/invoke/MutableCallSite.java +++ b/src/java.base/share/classes/java/lang/invoke/MutableCallSite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2022, 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 @@ -26,7 +26,8 @@ package java.lang.invoke; import java.util.Objects; -import java.util.concurrent.atomic.AtomicInteger; + +import static java.lang.invoke.MethodHandleStatics.UNSAFE; /** * A {@code MutableCallSite} is a {@link CallSite} whose target variable @@ -274,11 +275,10 @@ public final MethodHandle dynamicInvoker() { */ public static void syncAll(MutableCallSite[] sites) { if (sites.length == 0) return; - STORE_BARRIER.lazySet(0); + UNSAFE.storeFence(); for (MutableCallSite site : sites) { Objects.requireNonNull(site); // trigger NPE on first null } // FIXME: NYI } - private static final AtomicInteger STORE_BARRIER = new AtomicInteger(); } From da9347245c5e00c5d1b71f3745e02d79a31e8211 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Wed, 25 Sep 2024 18:31:24 +0000 Subject: [PATCH 15/15] 8340831: Simplify simple validation for class definition in MethodHandles.Lookup Reviewed-by: redestad --- .../java/lang/invoke/MethodHandles.java | 185 ++++++++---------- .../share/classes/jdk/internal/misc/VM.java | 28 +-- 2 files changed, 85 insertions(+), 128 deletions(-) diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index 6a73266ae80..9e292373f9c 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -39,7 +39,9 @@ import sun.reflect.misc.ReflectUtil; import sun.security.util.SecurityConstants; +import java.lang.classfile.ClassFile; import java.lang.classfile.ClassModel; +import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDescs; import java.lang.invoke.LambdaForm.BasicType; import java.lang.invoke.MethodHandleImpl.Intrinsic; @@ -2242,85 +2244,70 @@ private static ClassFileDumper defaultDumper() { private static final ClassFileDumper DEFAULT_DUMPER = ClassFileDumper.getInstance( "jdk.invoke.MethodHandle.dumpClassFiles", "DUMP_CLASS_FILES"); - static class ClassFile { - final String name; // internal name - final int accessFlags; - final byte[] bytes; - ClassFile(String name, int accessFlags, byte[] bytes) { - this.name = name; - this.accessFlags = accessFlags; - this.bytes = bytes; + /** + * This method checks the class file version and the structure of `this_class`. + * and checks if the bytes is a class or interface (ACC_MODULE flag not set) + * that is in the named package. + * + * @throws IllegalArgumentException if ACC_MODULE flag is set in access flags + * or the class is not in the given package name. + */ + static String validateAndFindInternalName(byte[] bytes, String pkgName) { + int magic = readInt(bytes, 0); + if (magic != ClassFile.MAGIC_NUMBER) { + throw new ClassFormatError("Incompatible magic value: " + magic); } + // We have to read major and minor this way as ClassFile API throws IAE + // yet we want distinct ClassFormatError and UnsupportedClassVersionError + int minor = readUnsignedShort(bytes, 4); + int major = readUnsignedShort(bytes, 6); - static ClassFile newInstanceNoCheck(String name, byte[] bytes) { - return new ClassFile(name, 0, bytes); + if (!VM.isSupportedClassFileVersion(major, minor)) { + throw new UnsupportedClassVersionError("Unsupported class file version " + major + "." + minor); } - /** - * This method checks the class file version and the structure of `this_class`. - * and checks if the bytes is a class or interface (ACC_MODULE flag not set) - * that is in the named package. - * - * @throws IllegalArgumentException if ACC_MODULE flag is set in access flags - * or the class is not in the given package name. - */ - static ClassFile newInstance(byte[] bytes, String pkgName) { - var cf = readClassFile(bytes); - - // check if it's in the named package - int index = cf.name.lastIndexOf('/'); - String pn = (index == -1) ? "" : cf.name.substring(0, index).replace('/', '.'); - if (!pn.equals(pkgName)) { - throw newIllegalArgumentException(cf.name + " not in same package as lookup class"); - } - return cf; + String name; + ClassDesc sym; + int accessFlags; + try { + ClassModel cm = ClassFile.of().parse(bytes); + var thisClass = cm.thisClass(); + name = thisClass.asInternalName(); + sym = thisClass.asSymbol(); + accessFlags = cm.flags().flagsMask(); + } catch (IllegalArgumentException e) { + ClassFormatError cfe = new ClassFormatError(); + cfe.initCause(e); + throw cfe; + } + // must be a class or interface + if ((accessFlags & ACC_MODULE) != 0) { + throw newIllegalArgumentException("Not a class or interface: ACC_MODULE flag is set"); } - private static ClassFile readClassFile(byte[] bytes) { - int magic = readInt(bytes, 0); - if (magic != 0xCAFEBABE) { - throw new ClassFormatError("Incompatible magic value: " + magic); - } - int minor = readUnsignedShort(bytes, 4); - int major = readUnsignedShort(bytes, 6); - if (!VM.isSupportedClassFileVersion(major, minor)) { - throw new UnsupportedClassVersionError("Unsupported class file version " + major + "." + minor); - } - - String name; - int accessFlags; - try { - ClassModel cm = java.lang.classfile.ClassFile.of().parse(bytes); - name = cm.thisClass().asInternalName(); - accessFlags = cm.flags().flagsMask(); - } catch (IllegalArgumentException e) { - ClassFormatError cfe = new ClassFormatError(); - cfe.initCause(e); - throw cfe; - } - // must be a class or interface - if ((accessFlags & ACC_MODULE) != 0) { - throw newIllegalArgumentException("Not a class or interface: ACC_MODULE flag is set"); - } - return new ClassFile(name, accessFlags, bytes); + String pn = sym.packageName(); + if (!pn.equals(pkgName)) { + throw newIllegalArgumentException(name + " not in same package as lookup class"); } - private static int readInt(byte[] bytes, int offset) { - if ((offset+4) > bytes.length) { - throw new ClassFormatError("Invalid ClassFile structure"); - } - return ((bytes[offset] & 0xFF) << 24) - | ((bytes[offset + 1] & 0xFF) << 16) - | ((bytes[offset + 2] & 0xFF) << 8) - | (bytes[offset + 3] & 0xFF); + return name; + } + + private static int readInt(byte[] bytes, int offset) { + if ((offset + 4) > bytes.length) { + throw new ClassFormatError("Invalid ClassFile structure"); } + return ((bytes[offset] & 0xFF) << 24) + | ((bytes[offset + 1] & 0xFF) << 16) + | ((bytes[offset + 2] & 0xFF) << 8) + | (bytes[offset + 3] & 0xFF); + } - private static int readUnsignedShort(byte[] bytes, int offset) { - if ((offset+2) > bytes.length) { - throw new ClassFormatError("Invalid ClassFile structure"); - } - return ((bytes[offset] & 0xFF) << 8) | (bytes[offset + 1] & 0xFF); + private static int readUnsignedShort(byte[] bytes, int offset) { + if ((offset+2) > bytes.length) { + throw new ClassFormatError("Invalid ClassFile structure"); } + return ((bytes[offset] & 0xFF) << 8) | (bytes[offset + 1] & 0xFF); } /* @@ -2334,23 +2321,22 @@ private static int readUnsignedShort(byte[] bytes, int offset) { * {@code bytes} denotes a class in a different package than the lookup class */ private ClassDefiner makeClassDefiner(byte[] bytes) { - ClassFile cf = ClassFile.newInstance(bytes, lookupClass().getPackageName()); - return new ClassDefiner(this, cf, STRONG_LOADER_LINK, defaultDumper()); + var internalName = validateAndFindInternalName(bytes, lookupClass().getPackageName()); + return new ClassDefiner(this, internalName, bytes, STRONG_LOADER_LINK, defaultDumper()); } /** * Returns a ClassDefiner that creates a {@code Class} object of a normal class * from the given bytes. No package name check on the given bytes. * - * @param name internal name + * @param internalName internal name * @param bytes class bytes * @param dumper dumper to write the given bytes to the dumper's output directory * @return ClassDefiner that defines a normal class of the given bytes. */ - ClassDefiner makeClassDefiner(String name, byte[] bytes, ClassFileDumper dumper) { + ClassDefiner makeClassDefiner(String internalName, byte[] bytes, ClassFileDumper dumper) { // skip package name validation - ClassFile cf = ClassFile.newInstanceNoCheck(name, bytes); - return new ClassDefiner(this, cf, STRONG_LOADER_LINK, dumper); + return new ClassDefiner(this, internalName, bytes, STRONG_LOADER_LINK, dumper); } /** @@ -2368,8 +2354,8 @@ ClassDefiner makeClassDefiner(String name, byte[] bytes, ClassFileDumper dumper) * {@code bytes} denotes a class in a different package than the lookup class */ ClassDefiner makeHiddenClassDefiner(byte[] bytes, ClassFileDumper dumper) { - ClassFile cf = ClassFile.newInstance(bytes, lookupClass().getPackageName()); - return makeHiddenClassDefiner(cf, false, dumper, 0); + var internalName = validateAndFindInternalName(bytes, lookupClass().getPackageName()); + return makeHiddenClassDefiner(internalName, bytes, false, dumper, 0); } /** @@ -2391,51 +2377,53 @@ ClassDefiner makeHiddenClassDefiner(byte[] bytes, ClassFileDumper dumper) { private ClassDefiner makeHiddenClassDefiner(byte[] bytes, boolean accessVmAnnotations, int flags) { - ClassFile cf = ClassFile.newInstance(bytes, lookupClass().getPackageName()); - return makeHiddenClassDefiner(cf, accessVmAnnotations, defaultDumper(), flags); + var internalName = validateAndFindInternalName(bytes, lookupClass().getPackageName()); + return makeHiddenClassDefiner(internalName, bytes, accessVmAnnotations, defaultDumper(), flags); } /** * Returns a ClassDefiner that creates a {@code Class} object of a hidden class * from the given bytes and the given options. No package name check on the given bytes. * - * @param name internal name that specifies the prefix of the hidden class + * @param internalName internal name that specifies the prefix of the hidden class * @param bytes class bytes * @param dumper dumper to write the given bytes to the dumper's output directory * @return ClassDefiner that defines a hidden class of the given bytes and options. */ - ClassDefiner makeHiddenClassDefiner(String name, byte[] bytes, ClassFileDumper dumper) { + ClassDefiner makeHiddenClassDefiner(String internalName, byte[] bytes, ClassFileDumper dumper) { Objects.requireNonNull(dumper); // skip name and access flags validation - return makeHiddenClassDefiner(ClassFile.newInstanceNoCheck(name, bytes), false, dumper, 0); + return makeHiddenClassDefiner(internalName, bytes, false, dumper, 0); } /** * Returns a ClassDefiner that creates a {@code Class} object of a hidden class * from the given bytes and the given options. No package name check on the given bytes. * - * @param name internal name that specifies the prefix of the hidden class + * @param internalName internal name that specifies the prefix of the hidden class * @param bytes class bytes * @param flags class options flag mask * @param dumper dumper to write the given bytes to the dumper's output directory * @return ClassDefiner that defines a hidden class of the given bytes and options. */ - ClassDefiner makeHiddenClassDefiner(String name, byte[] bytes, ClassFileDumper dumper, int flags) { + ClassDefiner makeHiddenClassDefiner(String internalName, byte[] bytes, ClassFileDumper dumper, int flags) { Objects.requireNonNull(dumper); // skip name and access flags validation - return makeHiddenClassDefiner(ClassFile.newInstanceNoCheck(name, bytes), false, dumper, flags); + return makeHiddenClassDefiner(internalName, bytes, false, dumper, flags); } /** * Returns a ClassDefiner that creates a {@code Class} object of a hidden class * from the given class file and options. * - * @param cf ClassFile + * @param internalName internal name + * @param bytes Class byte array * @param flags class option flag mask * @param accessVmAnnotations true to give the hidden class access to VM annotations * @param dumper dumper to write the given bytes to the dumper's output directory */ - private ClassDefiner makeHiddenClassDefiner(ClassFile cf, + private ClassDefiner makeHiddenClassDefiner(String internalName, + byte[] bytes, boolean accessVmAnnotations, ClassFileDumper dumper, int flags) { @@ -2446,27 +2434,12 @@ private ClassDefiner makeHiddenClassDefiner(ClassFile cf, flags |= ACCESS_VM_ANNOTATIONS; } - return new ClassDefiner(this, cf, flags, dumper); + return new ClassDefiner(this, internalName, bytes, flags, dumper); } - static class ClassDefiner { - private final Lookup lookup; - private final String name; // internal name - private final byte[] bytes; - private final int classFlags; - private final ClassFileDumper dumper; - - private ClassDefiner(Lookup lookup, ClassFile cf, int flags, ClassFileDumper dumper) { - assert ((flags & HIDDEN_CLASS) != 0 || (flags & STRONG_LOADER_LINK) == STRONG_LOADER_LINK); - this.lookup = lookup; - this.bytes = cf.bytes; - this.name = cf.name; - this.classFlags = flags; - this.dumper = dumper; - } - - String internalName() { - return name; + record ClassDefiner(Lookup lookup, String internalName, byte[] bytes, int classFlags, ClassFileDumper dumper) { + ClassDefiner { + assert ((classFlags & HIDDEN_CLASS) != 0 || (classFlags & STRONG_LOADER_LINK) == STRONG_LOADER_LINK); } Class defineClass(boolean initialize) { @@ -2495,7 +2468,7 @@ Class defineClass(boolean initialize, Object classData) { Class c = null; try { c = SharedSecrets.getJavaLangAccess() - .defineClass(loader, lookupClass, name, bytes, pd, initialize, classFlags, classData); + .defineClass(loader, lookupClass, internalName, bytes, pd, initialize, classFlags, classData); assert !isNestmate() || c.getNestHost() == lookupClass.getNestHost(); return c; } finally { diff --git a/src/java.base/share/classes/jdk/internal/misc/VM.java b/src/java.base/share/classes/jdk/internal/misc/VM.java index de6f011fe8f..1c31ef5a184 100644 --- a/src/java.base/share/classes/jdk/internal/misc/VM.java +++ b/src/java.base/share/classes/jdk/internal/misc/VM.java @@ -28,6 +28,7 @@ import static java.lang.Thread.State.*; import java.io.PrintStream; +import java.lang.classfile.ClassFile; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -158,10 +159,6 @@ public static boolean isDirectMemoryPageAligned() { return pageAlignDirectMemory; } - private static int classFileMajorVersion; - private static int classFileMinorVersion; - private static final int PREVIEW_MINOR_VERSION = 65535; - /** * Tests if the given version is a supported {@code class} * file version. @@ -175,11 +172,11 @@ public static boolean isDirectMemoryPageAligned() { * @jvms 4.1 Table 4.1-A. class file format major versions */ public static boolean isSupportedClassFileVersion(int major, int minor) { - if (major < 45 || major > classFileMajorVersion) return false; + if (major < ClassFile.JAVA_1_VERSION || major > ClassFile.latestMajorVersion()) return false; // for major version is between 45 and 55 inclusive, the minor version may be any value - if (major < 56) return true; + if (major < ClassFile.JAVA_12_VERSION) return true; // otherwise, the minor version must be 0 or 65535 - return minor == 0 || minor == PREVIEW_MINOR_VERSION; + return minor == 0 || (minor == ClassFile.PREVIEW_MINOR_VERSION && major == ClassFile.latestMajorVersion()); } /** @@ -189,12 +186,8 @@ public static boolean isSupportedClassFileVersion(int major, int minor) { * major.minor version >= 53.0 */ public static boolean isSupportedModuleDescriptorVersion(int major, int minor) { - if (major < 53 || major > classFileMajorVersion) return false; - // for major version is between 45 and 55 inclusive, the minor version may be any value - if (major < 56) return true; - // otherwise, the minor version must be 0 or 65535 - // preview features do not apply to module-info.class but JVMS allows it - return minor == 0 || minor == PREVIEW_MINOR_VERSION; + if (major < ClassFile.JAVA_9_VERSION) return false; + return isSupportedClassFileVersion(major, minor); } /** @@ -271,15 +264,6 @@ public static void saveProperties(Map props) { s = props.get("sun.nio.PageAlignDirectMemory"); if ("true".equals(s)) pageAlignDirectMemory = true; - - s = props.get("java.class.version"); - int index = s.indexOf('.'); - try { - classFileMajorVersion = Integer.parseInt(s.substring(0, index)); - classFileMinorVersion = Integer.parseInt(s.substring(index + 1)); - } catch (NumberFormatException e) { - throw new InternalError(e); - } } // Initialize any miscellaneous operating system settings that need to be