From 1d55adee11fc2fdbf2e009e1308b763fd7217dad Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Thu, 2 Oct 2025 18:49:00 +0000 Subject: [PATCH 001/160] 8368989: Use NMethodMarkingScope and ThreadsClaimTokenScope in shenandoahSTWMark Reviewed-by: shade, ayang --- src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp index 260c1e0276f..53391a3e224 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp @@ -24,8 +24,7 @@ */ - -#include "gc/shared/strongRootsScope.hpp" +#include "code/nmethod.hpp" #include "gc/shared/taskTerminator.hpp" #include "gc/shared/workerThread.hpp" #include "gc/shenandoah/shenandoahClosures.inline.hpp" @@ -36,10 +35,13 @@ #include "gc/shenandoah/shenandoahRootProcessor.inline.hpp" #include "gc/shenandoah/shenandoahSTWMark.hpp" #include "gc/shenandoah/shenandoahVerifier.hpp" +#include "runtime/threads.hpp" class ShenandoahSTWMarkTask : public WorkerTask { private: ShenandoahSTWMark* const _mark; + NMethodMarkingScope _nmethod_marking_scope; + ThreadsClaimTokenScope _threads_claim_token_scope; public: ShenandoahSTWMarkTask(ShenandoahSTWMark* mark); @@ -48,7 +50,9 @@ public: ShenandoahSTWMarkTask::ShenandoahSTWMarkTask(ShenandoahSTWMark* mark) : WorkerTask("Shenandoah STW mark"), - _mark(mark) { + _mark(mark), + _nmethod_marking_scope(), + _threads_claim_token_scope() { } void ShenandoahSTWMarkTask::work(uint worker_id) { @@ -98,7 +102,6 @@ void ShenandoahSTWMark::mark() { _generation->scan_remembered_set(false /* is_concurrent */); } - StrongRootsScope scope(nworkers); ShenandoahSTWMarkTask task(this); heap->workers()->run_task(&task); From 3f27a03bba4760694a276376d08fb1ba97d08f7e Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Thu, 2 Oct 2025 20:00:58 +0000 Subject: [PATCH 002/160] 8368727: CDS custom loader support causes asserts during class unloading Reviewed-by: coleenp, dholmes --- .../classfile/systemDictionaryShared.cpp | 1 - src/hotspot/share/oops/klass.cpp | 7 ++- .../UnloadUnregisteredLoaderTest.java | 18 ++++++-- .../test-classes/CustomLoadee5.java | 2 +- .../UnloadUnregisteredLoader.java | 45 ++++++++++++++++++- 5 files changed, 61 insertions(+), 12 deletions(-) diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index da022436292..b092e71f4e7 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -174,7 +174,6 @@ InstanceKlass* SystemDictionaryShared::acquire_class_for_current_thread( // No longer holding SharedDictionary_lock // No need to lock, as can be held only by a single thread. - loader_data->add_class(ik); // Get the package entry. PackageEntry* pkg_entry = CDSProtectionDomain::get_package_entry_from_class(ik, class_loader); diff --git a/src/hotspot/share/oops/klass.cpp b/src/hotspot/share/oops/klass.cpp index b3386694b79..208a274d766 100644 --- a/src/hotspot/share/oops/klass.cpp +++ b/src/hotspot/share/oops/klass.cpp @@ -872,11 +872,10 @@ void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protec // modify the CLD list outside a safepoint. if (class_loader_data() == nullptr) { set_class_loader_data(loader_data); - - // Add to class loader list first before creating the mirror - // (same order as class file parsing) - loader_data->add_class(this); } + // Add to class loader list first before creating the mirror + // (same order as class file parsing) + loader_data->add_class(this); Handle loader(THREAD, loader_data->class_loader()); ModuleEntry* module_entry = nullptr; diff --git a/test/hotspot/jtreg/runtime/cds/appcds/customLoader/UnloadUnregisteredLoaderTest.java b/test/hotspot/jtreg/runtime/cds/appcds/customLoader/UnloadUnregisteredLoaderTest.java index b7f472f5c0e..db26c6cbd18 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/customLoader/UnloadUnregisteredLoaderTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/customLoader/UnloadUnregisteredLoaderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,9 +29,10 @@ * @requires vm.cds * @requires vm.cds.custom.loaders * @requires vm.opt.final.ClassUnloading - * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds /test/hotspot/jtreg/runtime/cds/appcds/test-classes * @build jdk.test.whitebox.WhiteBox jdk.test.lib.classloader.ClassUnloadCommon * @compile test-classes/UnloadUnregisteredLoader.java test-classes/CustomLoadee.java + * test-classes/CustomLoadee5.java test-classes/CustomLoadee5Child.java * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * jdk.test.lib.classloader.ClassUnloadCommon * jdk.test.lib.classloader.ClassUnloadCommon$1 @@ -49,12 +50,19 @@ public class UnloadUnregisteredLoaderTest { CDSOptions.disableRuntimePrefixForEpsilonGC(); } public static void main(String[] args) throws Exception { - String appJar1 = JarBuilder.build("UnloadUnregisteredLoader_app1", "UnloadUnregisteredLoader"); + String appJar1 = JarBuilder.build("UnloadUnregisteredLoader_app1", + "UnloadUnregisteredLoader", + "UnloadUnregisteredLoader$CustomLoader", + "CustomLoadee5", + "Util"); String appJar2 = JarBuilder.build(true, "UnloadUnregisteredLoader_app2", "jdk/test/lib/classloader/ClassUnloadCommon", "jdk/test/lib/classloader/ClassUnloadCommon$1", "jdk/test/lib/classloader/ClassUnloadCommon$TestFailure"); - String customJarPath = JarBuilder.build("UnloadUnregisteredLoader_custom", "CustomLoadee"); + String customJarPath = JarBuilder.build("UnloadUnregisteredLoader_custom", + "CustomLoadee", + "CustomLoadee5", + "CustomLoadee5Child"); String wbJar = JarBuilder.build(true, "WhiteBox", "jdk/test/whitebox/WhiteBox"); String use_whitebox_jar = "-Xbootclasspath/a:" + wbJar; @@ -66,6 +74,8 @@ public class UnloadUnregisteredLoaderTest { "jdk/test/lib/classloader/ClassUnloadCommon$TestFailure", "java/lang/Object id: 1", "CustomLoadee id: 2 super: 1 source: " + customJarPath, + "CustomLoadee5 id: 3 super: 1 source: " + customJarPath, + "CustomLoadee5Child id: 4 super: 3 source: " + customJarPath, }; OutputAnalyzer output; diff --git a/test/hotspot/jtreg/runtime/cds/appcds/customLoader/test-classes/CustomLoadee5.java b/test/hotspot/jtreg/runtime/cds/appcds/customLoader/test-classes/CustomLoadee5.java index f3cda51c9fa..ba9f6dafa95 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/customLoader/test-classes/CustomLoadee5.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/customLoader/test-classes/CustomLoadee5.java @@ -21,7 +21,7 @@ * questions. */ -class CustomLoadee5 { +public class CustomLoadee5 { public String toString() { return "this is CustomLoadee5"; } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/customLoader/test-classes/UnloadUnregisteredLoader.java b/test/hotspot/jtreg/runtime/cds/appcds/customLoader/test-classes/UnloadUnregisteredLoader.java index 0e0e814327e..e6bd7407466 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/customLoader/test-classes/UnloadUnregisteredLoader.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/customLoader/test-classes/UnloadUnregisteredLoader.java @@ -23,6 +23,7 @@ */ import java.io.File; +import java.io.InputStream; import java.net.URL; import java.net.URLClassLoader; import jdk.test.whitebox.WhiteBox; @@ -46,9 +47,11 @@ public class UnloadUnregisteredLoader { } } - public static void doit(URL urls[], String className, boolean isFirstTime) throws Exception { + public static void doit(URL urls[], String className, boolean isFirstTime) throws Exception { ClassLoader appLoader = UnloadUnregisteredLoader.class.getClassLoader(); - URLClassLoader custLoader = new URLClassLoader(urls, appLoader); + CustomLoader custLoader = new CustomLoader(urls, appLoader); + + // Part 1 -- load CustomLoadee. It should be loaded from archive when isFirstTime==true Class klass = custLoader.loadClass(className); WhiteBox wb = WhiteBox.getWhiteBox(); @@ -68,5 +71,43 @@ public class UnloadUnregisteredLoader { } } } + + // Part 2 + // + // CustomLoadee5 is never loaded from the archive, because the classfile bytes don't match + // CustomLoadee5Child is never loaded from the archive, its super is not loaded from the archive + try (InputStream in = appLoader.getResourceAsStream("CustomLoadee5.class")) { + byte[] b = in.readAllBytes(); + Util.replace(b, "this is", "DAS IST"); // Modify the bytecodes + Class c = custLoader.myDefineClass(b, 0, b.length); + System.out.println(c.newInstance()); + if (!"DAS IST CustomLoadee5".equals(c.newInstance().toString())) { + throw new RuntimeException("Bytecode modification not successful"); + } + if (wb.isSharedClass(c)) { + throw new RuntimeException(c + "should not be loaded from CDS"); + } + } + + // When isFirstTime==true, the VM will try to load the archived copy of CustomLoadee5Child, + // but it will fail (because CustomLoadee5 was not loaded from the archive) and will recover + // by decoding the class from its classfile data. + // This failure should not leave the JVM in an inconsistent state. + Class child = custLoader.loadClass("CustomLoadee5Child"); + if (wb.isSharedClass(child)) { + throw new RuntimeException(child + "should not be loaded from CDS"); + } + } + + static class CustomLoader extends URLClassLoader { + public CustomLoader(URL[] urls, ClassLoader parent) { + super(urls, parent); + } + + public Class myDefineClass(byte[] b, int off, int len) + throws ClassFormatError + { + return super.defineClass(b, off, len); + } } } From fa6e884105ac247b3b83a5a2329f9c18888bd7d0 Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Thu, 2 Oct 2025 22:09:14 +0000 Subject: [PATCH 003/160] 8298823: [macos] java/awt/Mouse/EnterExitEvents/DragWindowTest.java continues to fail with "No MouseReleased event on label!" Reviewed-by: aivanov, azvegint --- test/jdk/ProblemList.txt | 1 - .../Mouse/EnterExitEvents/DragWindowTest.java | 115 +++++++----------- 2 files changed, 46 insertions(+), 70 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 1602baa9894..8d13670805f 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -188,7 +188,6 @@ java/awt/Mixing/AWT_Mixing/JTextFieldOverlapping.java 8158801 windows-all java/awt/Mixing/AWT_Mixing/JToggleButtonInGlassPaneOverlapping.java 8158801 windows-all java/awt/Mixing/AWT_Mixing/JToggleButtonOverlapping.java 8158801 windows-all java/awt/Mixing/NonOpaqueInternalFrame.java 7124549 macosx-all -java/awt/Mouse/EnterExitEvents/DragWindowTest.java 8298823 macosx-all java/awt/Focus/ActualFocusedWindowTest/ActualFocusedWindowRetaining.java 6829264 generic-all java/awt/datatransfer/DragImage/MultiResolutionDragImageTest.java 8080982 generic-all java/awt/datatransfer/SystemFlavorMap/AddFlavorTest.java 8079268 linux-all diff --git a/test/jdk/java/awt/Mouse/EnterExitEvents/DragWindowTest.java b/test/jdk/java/awt/Mouse/EnterExitEvents/DragWindowTest.java index 4f789668c4a..2a77f294298 100644 --- a/test/jdk/java/awt/Mouse/EnterExitEvents/DragWindowTest.java +++ b/test/jdk/java/awt/Mouse/EnterExitEvents/DragWindowTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,11 +26,8 @@ * @key headful * @bug 7154048 * @summary Window created under a mouse does not receive mouse enter event. - * Mouse Entered/Exited events are wrongly generated during dragging the window - * from one component to another - * @library ../../regtesthelpers - * @build Util - * @author alexandr.scherbatiy area=awt.event + * Mouse Entered/Exited events are wrongly generated during dragging the + * window from one component to another * @run main DragWindowTest */ @@ -50,76 +47,67 @@ import javax.swing.JButton; import javax.swing.JPanel; import javax.swing.SwingUtilities; -import java.util.concurrent.Callable; - -import test.java.awt.regtesthelpers.Util; - public class DragWindowTest { - private static volatile int dragWindowMouseEnteredCount = 0; - private static volatile int dragWindowMouseReleasedCount = 0; private static volatile int buttonMouseEnteredCount = 0; private static volatile int labelMouseReleasedCount = 0; + + private static volatile Point pointToClick; + private static volatile Point pointToDrag; + private static MyDragWindow dragWindow; private static JLabel label; private static JButton button; + private static JFrame frame; public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + robot.setAutoDelay(100); - Robot robot = new Robot(); - robot.setAutoDelay(100); + SwingUtilities.invokeAndWait(DragWindowTest::createAndShowGUI); - SwingUtilities.invokeAndWait(new Runnable() { + robot.delay(250); + robot.waitForIdle(); - @Override - public void run() { - createAndShowGUI(); + SwingUtilities.invokeAndWait(() -> { + pointToClick = getCenterPoint(label); + pointToDrag = getCenterPoint(button); + }); + + robot.mouseMove(pointToClick.x, pointToClick.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(250); + + if (dragWindowMouseEnteredCount != 1) { + throw new RuntimeException("No MouseEntered event on Drag Window!"); } - }); - robot.delay(250); - robot.waitForIdle(); + // Reset entered count to check if mouse entered starting from here + buttonMouseEnteredCount = 0; + robot.mouseMove(pointToDrag.x, pointToDrag.y); + robot.waitForIdle(); + robot.delay(250); - Point pointToClick = Util.invokeOnEDT(new Callable() { - - @Override - public Point call() throws Exception { - return getCenterPoint(label); + if (buttonMouseEnteredCount != 0) { + throw new RuntimeException("Extra MouseEntered event on button!"); } - }); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(250); - robot.mouseMove(pointToClick.x, pointToClick.y); - robot.mousePress(InputEvent.BUTTON1_MASK); - robot.waitForIdle(); - - if (dragWindowMouseEnteredCount != 1) { - throw new RuntimeException("No MouseEntered event on Drag Window!"); - } - - Point pointToDrag = Util.invokeOnEDT(new Callable() { - - @Override - public Point call() throws Exception { - button.addMouseListener(new ButtonMouseListener()); - return getCenterPoint(button); + if (labelMouseReleasedCount != 1) { + throw new RuntimeException("No MouseReleased event on label!"); } - }); - - robot.mouseMove(pointToDrag.x, pointToDrag.y); - robot.waitForIdle(); - - if (buttonMouseEnteredCount != 0) { - throw new RuntimeException("Extra MouseEntered event on button!"); + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); } - - robot.mouseRelease(InputEvent.BUTTON1_MASK); - robot.waitForIdle(); - - if (labelMouseReleasedCount != 1) { - throw new RuntimeException("No MouseReleased event on label!"); - } - } private static Point getCenterPoint(Component comp) { @@ -129,8 +117,7 @@ public class DragWindowTest { } private static void createAndShowGUI() { - - JFrame frame = new JFrame("Main Frame"); + frame = new JFrame("DragWindowTest"); frame.setSize(300, 200); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); @@ -142,6 +129,7 @@ public class DragWindowTest { button = new JButton("Button"); Panel panel = new Panel(new BorderLayout()); + button.addMouseListener(new ButtonMouseListener()); panel.add(label, BorderLayout.NORTH); panel.add(button, BorderLayout.CENTER); @@ -149,7 +137,6 @@ public class DragWindowTest { frame.getContentPane().add(panel); frame.setLocationRelativeTo(null); frame.setVisible(true); - } private static Point getAbsoluteLocation(MouseEvent e) { @@ -157,7 +144,6 @@ public class DragWindowTest { } static class MyDragWindow extends Window { - static int d = 30; public MyDragWindow(Window parent, Point location) { @@ -176,8 +162,6 @@ public class DragWindowTest { } static class LabelMouseListener extends MouseAdapter { - - Point origin; Window parent; public LabelMouseListener(Window parent) { @@ -210,20 +194,13 @@ public class DragWindowTest { } static class DragWindowMouseListener extends MouseAdapter { - @Override public void mouseEntered(MouseEvent e) { dragWindowMouseEnteredCount++; } - - @Override - public void mouseReleased(MouseEvent e) { - dragWindowMouseReleasedCount++; - } } static class ButtonMouseListener extends MouseAdapter { - @Override public void mouseEntered(MouseEvent e) { buttonMouseEnteredCount++; From da7121aff9eccb046b82a75093034f1cdbd9b9e4 Mon Sep 17 00:00:00 2001 From: Dean Long Date: Thu, 2 Oct 2025 22:21:13 +0000 Subject: [PATCH 004/160] 8366461: Remove obsolete method handle invoke logic Reviewed-by: vlivanov, mhaessig --- src/hotspot/cpu/aarch64/aarch64.ad | 4 - .../cpu/aarch64/c1_FrameMap_aarch64.cpp | 7 -- src/hotspot/cpu/aarch64/frame_aarch64.cpp | 45 +------ src/hotspot/cpu/aarch64/frame_aarch64.hpp | 9 +- .../cpu/aarch64/frame_aarch64.inline.hpp | 3 - src/hotspot/cpu/arm/arm.ad | 36 ------ src/hotspot/cpu/arm/arm_32.ad | 5 +- src/hotspot/cpu/arm/c1_FrameMap_arm.cpp | 5 - src/hotspot/cpu/arm/c1_Runtime1_arm.cpp | 12 -- src/hotspot/cpu/arm/frame_arm.cpp | 50 -------- src/hotspot/cpu/arm/frame_arm.hpp | 11 +- src/hotspot/cpu/arm/frame_arm.inline.hpp | 4 +- src/hotspot/cpu/arm/register_arm.hpp | 3 +- src/hotspot/cpu/arm/runtime_arm.cpp | 5 - src/hotspot/cpu/ppc/c1_FrameMap_ppc.cpp | 9 -- src/hotspot/cpu/ppc/ppc.ad | 5 - src/hotspot/cpu/riscv/c1_FrameMap_riscv.cpp | 5 - src/hotspot/cpu/riscv/frame_riscv.cpp | 46 +------ src/hotspot/cpu/riscv/frame_riscv.hpp | 9 +- src/hotspot/cpu/riscv/frame_riscv.inline.hpp | 5 +- src/hotspot/cpu/riscv/riscv.ad | 4 - src/hotspot/cpu/s390/c1_FrameMap_s390.cpp | 7 -- src/hotspot/cpu/s390/s390.ad | 5 - src/hotspot/cpu/x86/c1_FrameMap_x86.cpp | 7 -- src/hotspot/cpu/x86/frame_x86.cpp | 44 +------ src/hotspot/cpu/x86/frame_x86.hpp | 9 +- src/hotspot/cpu/x86/frame_x86.inline.hpp | 3 - src/hotspot/cpu/x86/x86_64.ad | 5 - src/hotspot/os/posix/signals_posix.cpp | 4 +- src/hotspot/os/windows/os_windows.cpp | 4 +- src/hotspot/share/asm/codeBuffer.hpp | 2 - src/hotspot/share/c1/c1_Compilation.cpp | 9 -- src/hotspot/share/c1/c1_Compilation.hpp | 5 - src/hotspot/share/c1/c1_FrameMap.hpp | 3 - src/hotspot/share/c1/c1_IR.cpp | 4 +- src/hotspot/share/c1/c1_IR.hpp | 8 +- src/hotspot/share/c1/c1_LIR.cpp | 5 - src/hotspot/share/c1/c1_LIR.hpp | 3 - src/hotspot/share/c1/c1_LIRAssembler.cpp | 6 - src/hotspot/share/c1/c1_LIRGenerator.cpp | 19 --- src/hotspot/share/c1/c1_Runtime1.cpp | 7 -- src/hotspot/share/code/debugInfoRec.cpp | 2 - src/hotspot/share/code/debugInfoRec.hpp | 3 +- src/hotspot/share/code/nmethod.cpp | 30 ----- src/hotspot/share/code/nmethod.hpp | 11 -- src/hotspot/share/code/nmethod.inline.hpp | 6 +- src/hotspot/share/code/pcDesc.hpp | 14 +-- .../share/jvmci/jvmciCodeInstaller.cpp | 16 +-- .../share/jvmci/jvmciCodeInstaller.hpp | 6 +- src/hotspot/share/jvmci/jvmciRuntime.cpp | 8 -- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 1 - src/hotspot/share/opto/callGenerator.cpp | 4 - src/hotspot/share/opto/callnode.hpp | 4 - src/hotspot/share/opto/compile.cpp | 2 - src/hotspot/share/opto/compile.hpp | 6 - src/hotspot/share/opto/lcm.cpp | 11 -- src/hotspot/share/opto/machnode.cpp | 7 +- src/hotspot/share/opto/machnode.hpp | 1 - src/hotspot/share/opto/matcher.cpp | 115 ++---------------- src/hotspot/share/opto/matcher.hpp | 7 +- src/hotspot/share/opto/output.cpp | 17 --- src/hotspot/share/opto/runtime.cpp | 3 - src/hotspot/share/runtime/deoptimization.cpp | 7 +- src/hotspot/share/runtime/frame.cpp | 9 +- src/hotspot/share/runtime/frame.inline.hpp | 7 +- src/hotspot/share/runtime/javaThread.cpp | 1 - src/hotspot/share/runtime/javaThread.hpp | 3 - src/hotspot/share/runtime/sharedRuntime.cpp | 5 - src/hotspot/share/runtime/vmStructs.cpp | 3 - .../classes/sun/jvm/hotspot/code/NMethod.java | 18 +-- .../classes/sun/jvm/hotspot/code/PCDesc.java | 9 +- .../sun/jvm/hotspot/runtime/Frame.java | 20 ++- .../hotspot/runtime/aarch64/AARCH64Frame.java | 42 +------ .../jvm/hotspot/runtime/ppc64/PPC64Frame.java | 29 +---- .../hotspot/runtime/riscv64/RISCV64Frame.java | 42 +------ .../sun/jvm/hotspot/runtime/x86/X86Frame.java | 41 +------ 76 files changed, 74 insertions(+), 877 deletions(-) diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index e0459716122..51cdf8c71df 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -2568,10 +2568,6 @@ RegMask Matcher::modL_proj_mask() { return RegMask(); } -const RegMask Matcher::method_handle_invoke_SP_save_mask() { - return FP_REG_mask(); -} - bool size_fits_all_mem_uses(AddPNode* addp, int shift) { for (DUIterator_Fast imax, i = addp->fast_outs(imax); i < imax; i++) { Node* u = addp->fast_out(i); diff --git a/src/hotspot/cpu/aarch64/c1_FrameMap_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_FrameMap_aarch64.cpp index 9d30092b45a..83d0952dcb4 100644 --- a/src/hotspot/cpu/aarch64/c1_FrameMap_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_FrameMap_aarch64.cpp @@ -383,13 +383,6 @@ LIR_Opr FrameMap::stack_pointer() { return FrameMap::sp_opr; } - -// JSR 292 -LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() { - return LIR_OprFact::illegalOpr; // Not needed on aarch64 -} - - bool FrameMap::validate_frame() { return true; } diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.cpp b/src/hotspot/cpu/aarch64/frame_aarch64.cpp index aff50b9cf2f..bdbef53bfdb 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.cpp @@ -228,8 +228,7 @@ bool frame::safe_for_sender(JavaThread *thread) { nmethod* nm = sender_blob->as_nmethod_or_null(); if (nm != nullptr) { - if (nm->is_deopt_mh_entry(sender_pc) || nm->is_deopt_entry(sender_pc) || - nm->method()->is_method_handle_intrinsic()) { + if (nm->is_deopt_entry(sender_pc) || nm->method()->is_method_handle_intrinsic()) { return false; } } @@ -454,48 +453,6 @@ JavaThread** frame::saved_thread_address(const frame& f) { return thread_addr; } -//------------------------------------------------------------------------------ -// frame::verify_deopt_original_pc -// -// Verifies the calculated original PC of a deoptimization PC for the -// given unextended SP. -#ifdef ASSERT -void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp) { - frame fr; - - // This is ugly but it's better than to change {get,set}_original_pc - // to take an SP value as argument. And it's only a debugging - // method anyway. - fr._unextended_sp = unextended_sp; - - address original_pc = nm->get_original_pc(&fr); - assert(nm->insts_contains_inclusive(original_pc), - "original PC must be in the main code section of the compiled method (or must be immediately following it)"); -} -#endif - -//------------------------------------------------------------------------------ -// frame::adjust_unextended_sp -#ifdef ASSERT -void frame::adjust_unextended_sp() { - // On aarch64, sites calling method handle intrinsics and lambda forms are treated - // as any other call site. Therefore, no special action is needed when we are - // returning to any of these call sites. - - if (_cb != nullptr) { - nmethod* sender_nm = _cb->as_nmethod_or_null(); - if (sender_nm != nullptr) { - // If the sender PC is a deoptimization point, get the original PC. - if (sender_nm->is_deopt_entry(_pc) || - sender_nm->is_deopt_mh_entry(_pc)) { - verify_deopt_original_pc(sender_nm, _unextended_sp); - } - } - } -} -#endif - - //------------------------------------------------------------------------------ // frame::sender_for_interpreter_frame frame frame::sender_for_interpreter_frame(RegisterMap* map) const { diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.hpp b/src/hotspot/cpu/aarch64/frame_aarch64.hpp index da020b4234d..231710df7d7 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -141,8 +141,6 @@ int _offset_unextended_sp; // for use in stack-chunk frames }; - void adjust_unextended_sp() NOT_DEBUG_RETURN; - // true means _sp value is correct and we can use it to get the sender's sp // of the compiled frame, otherwise, _sp value may be invalid and we can use // _fp to get the sender's sp if PreserveFramePointer is enabled. @@ -152,11 +150,6 @@ return (intptr_t*) addr_at(offset); } -#ifdef ASSERT - // Used in frame::sender_for_{interpreter,compiled}_frame - static void verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp); -#endif - public: // Constructors diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp b/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp index 47ae93a4932..cb53d8663ad 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp @@ -116,8 +116,6 @@ inline void frame::init(intptr_t* sp, intptr_t* fp, address pc) { } inline void frame::setup(address pc) { - adjust_unextended_sp(); - address original_pc = get_deopt_original_pc(); if (original_pc != nullptr) { _pc = original_pc; @@ -223,7 +221,6 @@ inline frame::frame(intptr_t* sp, intptr_t* fp) { // assert(_pc != nullptr, "no pc?"); _cb = CodeCache::find_blob(_pc); - adjust_unextended_sp(); address original_pc = get_deopt_original_pc(); if (original_pc != nullptr) { diff --git a/src/hotspot/cpu/arm/arm.ad b/src/hotspot/cpu/arm/arm.ad index 2835a256153..68fece5263d 100644 --- a/src/hotspot/cpu/arm/arm.ad +++ b/src/hotspot/cpu/arm/arm.ad @@ -1154,10 +1154,6 @@ RegMask Matcher::modL_proj_mask() { return RegMask(); } -const RegMask Matcher::method_handle_invoke_SP_save_mask() { - return FP_REGP_mask(); -} - bool maybe_far_call(const CallNode *n) { return !MacroAssembler::_reachable_from_cache(n->as_Call()->entry_point()); } @@ -1248,23 +1244,6 @@ encode %{ __ set_inst_mark(mark); %} - enc_class preserve_SP %{ - // preserve mark - address mark = __ inst_mark(); - DEBUG_ONLY(int off0 = __ offset()); - // FP is preserved across all calls, even compiled calls. - // Use it to preserve SP in places where the callee might change the SP. - __ mov(Rmh_SP_save, SP); - DEBUG_ONLY(int off1 = __ offset()); - assert(off1 - off0 == 4, "correct size prediction"); - // restore mark - __ set_inst_mark(mark); - %} - - enc_class restore_SP %{ - __ mov(SP, Rmh_SP_save); - %} - enc_class Java_Dynamic_Call (method meth) %{ Register R8_ic_reg = reg_to_register_object(Matcher::inline_cache_reg_encode()); assert(R8_ic_reg == Ricklass, "should be"); @@ -8799,7 +8778,6 @@ instruct safePoint_poll(iRegP poll, R12RegI tmp, flagsReg icc) %{ // Call Java Static Instruction instruct CallStaticJavaDirect( method meth ) %{ match(CallStaticJava); - predicate(! ((CallStaticJavaNode*)n)->is_method_handle_invoke()); effect(USE meth); ins_cost(CALL_COST); @@ -8808,20 +8786,6 @@ instruct CallStaticJavaDirect( method meth ) %{ ins_pipe(simple_call); %} -// Call Java Static Instruction (method handle version) -instruct CallStaticJavaHandle( method meth ) %{ - match(CallStaticJava); - predicate(((CallStaticJavaNode*)n)->is_method_handle_invoke()); - effect(USE meth); - // FP is saved by all callees (for interpreter stack correction). - // We use it here for a similar purpose, in {preserve,restore}_FP. - - ins_cost(CALL_COST); - format %{ "CALL,static/MethodHandle ==> " %} - ins_encode( SetInstMark, preserve_SP, Java_Static_Call( meth ), restore_SP, call_epilog, ClearInstMark ); - ins_pipe(simple_call); -%} - // Call Java Dynamic Instruction instruct CallDynamicJavaDirect( method meth ) %{ match(CallDynamicJava); diff --git a/src/hotspot/cpu/arm/arm_32.ad b/src/hotspot/cpu/arm/arm_32.ad index 1c15d55fbc3..00bf3bd61e4 100644 --- a/src/hotspot/cpu/arm/arm_32.ad +++ b/src/hotspot/cpu/arm/arm_32.ad @@ -1,5 +1,5 @@ // -// Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -432,8 +432,7 @@ OptoRegPair c2::return_value(int ideal_reg) { int MachCallStaticJavaNode::ret_addr_offset() { bool far = (_method == nullptr) ? maybe_far_call(this) : !cache_reachable(); - return ((far ? 3 : 1) + (_method_handle_invoke ? 1 : 0)) * - NativeInstruction::instruction_size; + return (far ? 3 : 1) * NativeInstruction::instruction_size; } int MachCallDynamicJavaNode::ret_addr_offset() { diff --git a/src/hotspot/cpu/arm/c1_FrameMap_arm.cpp b/src/hotspot/cpu/arm/c1_FrameMap_arm.cpp index 0fd113c8ceb..a820da4d283 100644 --- a/src/hotspot/cpu/arm/c1_FrameMap_arm.cpp +++ b/src/hotspot/cpu/arm/c1_FrameMap_arm.cpp @@ -174,11 +174,6 @@ LIR_Opr FrameMap::stack_pointer() { return FrameMap::SP_opr; } -LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() { - assert(Rmh_SP_save == FP, "Fix register used for saving SP for MethodHandle calls"); - return FP_opr; -} - bool FrameMap::validate_frame() { int max_offset = in_bytes(framesize_in_bytes()); int java_index = 0; diff --git a/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp b/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp index 32da2c24d26..9983f2ce7a2 100644 --- a/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp +++ b/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp @@ -275,14 +275,6 @@ OopMapSet* Runtime1::generate_exception_throw(StubAssembler* sasm, address targe } -static void restore_sp_for_method_handle(StubAssembler* sasm) { - // Restore SP from its saved reg (FP) if the exception PC is a MethodHandle call site. - __ ldr_s32(Rtemp, Address(Rthread, JavaThread::is_method_handle_return_offset())); - __ cmp(Rtemp, 0); - __ mov(SP, Rmh_SP_save, ne); -} - - OopMapSet* Runtime1::generate_handle_exception(StubId id, StubAssembler* sasm) { __ block_comment("generate_handle_exception"); @@ -339,7 +331,6 @@ OopMapSet* Runtime1::generate_handle_exception(StubId id, StubAssembler* sasm) { break; case StubId::c1_handle_exception_from_callee_id: restore_live_registers_without_return(sasm); // must not jump immediately to handler - restore_sp_for_method_handle(sasm); __ ret(); break; default: ShouldNotReachHere(); @@ -372,9 +363,6 @@ void Runtime1::generate_unwind_exception(StubAssembler* sasm) { // Jump to handler __ verify_not_null_oop(Rexception_obj); - // JSR292 extension - restore_sp_for_method_handle(sasm); - __ jump(R0); } diff --git a/src/hotspot/cpu/arm/frame_arm.cpp b/src/hotspot/cpu/arm/frame_arm.cpp index 2722f93edec..7a23296a3d4 100644 --- a/src/hotspot/cpu/arm/frame_arm.cpp +++ b/src/hotspot/cpu/arm/frame_arm.cpp @@ -329,56 +329,6 @@ JavaThread** frame::saved_thread_address(const frame& f) { return nullptr; } -//------------------------------------------------------------------------------ -// frame::verify_deopt_original_pc -// -// Verifies the calculated original PC of a deoptimization PC for the -// given unextended SP. The unextended SP might also be the saved SP -// for MethodHandle call sites. -#ifdef ASSERT -void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp, bool is_method_handle_return) { - frame fr; - - // This is ugly but it's better than to change {get,set}_original_pc - // to take an SP value as argument. And it's only a debugging - // method anyway. - fr._unextended_sp = unextended_sp; - - address original_pc = nm->get_original_pc(&fr); - assert(nm->insts_contains_inclusive(original_pc), - "original PC must be in the main code section of the compiled method (or must be immediately following it)"); - assert(nm->is_method_handle_return(original_pc) == is_method_handle_return, "must be"); -} -#endif - -//------------------------------------------------------------------------------ -// frame::adjust_unextended_sp -void frame::adjust_unextended_sp() { - // same as on x86 - - // If we are returning to a compiled MethodHandle call site, the - // saved_fp will in fact be a saved value of the unextended SP. The - // simplest way to tell whether we are returning to such a call site - // is as follows: - - nmethod* sender_nm = (_cb == nullptr) ? nullptr : _cb->as_nmethod_or_null(); - if (sender_nm != nullptr) { - // If the sender PC is a deoptimization point, get the original - // PC. For MethodHandle call site the unextended_sp is stored in - // saved_fp. - if (sender_nm->is_deopt_mh_entry(_pc)) { - DEBUG_ONLY(verify_deopt_mh_original_pc(sender_nm, _fp)); - _unextended_sp = _fp; - } - else if (sender_nm->is_deopt_entry(_pc)) { - DEBUG_ONLY(verify_deopt_original_pc(sender_nm, _unextended_sp)); - } - else if (sender_nm->is_method_handle_return(_pc)) { - _unextended_sp = _fp; - } - } -} - //------------------------------------------------------------------------------ // frame::update_map_with_saved_link void frame::update_map_with_saved_link(RegisterMap* map, intptr_t** link_addr) { diff --git a/src/hotspot/cpu/arm/frame_arm.hpp b/src/hotspot/cpu/arm/frame_arm.hpp index dec27554a47..6d4ac042831 100644 --- a/src/hotspot/cpu/arm/frame_arm.hpp +++ b/src/hotspot/cpu/arm/frame_arm.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -85,20 +85,11 @@ // original sp. intptr_t* _unextended_sp; - void adjust_unextended_sp(); intptr_t* ptr_at_addr(int offset) const { return (intptr_t*) addr_at(offset); } -#ifdef ASSERT - // Used in frame::sender_for_{interpreter,compiled}_frame - static void verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp, bool is_method_handle_return = false); - static void verify_deopt_mh_original_pc(nmethod* nm, intptr_t* unextended_sp) { - verify_deopt_original_pc(nm, unextended_sp, true); - } -#endif - public: // Constructors diff --git a/src/hotspot/cpu/arm/frame_arm.inline.hpp b/src/hotspot/cpu/arm/frame_arm.inline.hpp index 4be190f0504..42e034cfdc7 100644 --- a/src/hotspot/cpu/arm/frame_arm.inline.hpp +++ b/src/hotspot/cpu/arm/frame_arm.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -112,8 +112,6 @@ inline void frame::init(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, add } inline void frame::setup(address pc) { - adjust_unextended_sp(); - address original_pc = get_deopt_original_pc(); if (original_pc != nullptr) { _pc = original_pc; diff --git a/src/hotspot/cpu/arm/register_arm.hpp b/src/hotspot/cpu/arm/register_arm.hpp index fca23d07fee..e0688af0d36 100644 --- a/src/hotspot/cpu/arm/register_arm.hpp +++ b/src/hotspot/cpu/arm/register_arm.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -364,7 +364,6 @@ class VFPSystemRegisterImpl : public AbstractRegisterImpl { // This does not seem to conflict with Rexception_pc // In case of issues, R3 might be OK but adapters calling the runtime would have to save it #define R5_mh R5 // MethodHandle register, used during the call setup -#define Rmh_SP_save FP // for C1 /* * C++ Interpreter Register Defines diff --git a/src/hotspot/cpu/arm/runtime_arm.cpp b/src/hotspot/cpu/arm/runtime_arm.cpp index ea4c9a76381..8d48de5795a 100644 --- a/src/hotspot/cpu/arm/runtime_arm.cpp +++ b/src/hotspot/cpu/arm/runtime_arm.cpp @@ -264,11 +264,6 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() { __ raw_pop(FP, LR); - // Restore SP from its saved reg (FP) if the exception PC is a MethodHandle call site. - __ ldr(Rtemp, Address(Rthread, JavaThread::is_method_handle_return_offset())); - __ cmp(Rtemp, 0); - __ mov(SP, Rmh_SP_save, ne); - // R0 contains handler address // Since this may be the deopt blob we must set R5 to look like we returned // from the original pc that threw the exception diff --git a/src/hotspot/cpu/ppc/c1_FrameMap_ppc.cpp b/src/hotspot/cpu/ppc/c1_FrameMap_ppc.cpp index 8ce324a570b..cb9368f2ce9 100644 --- a/src/hotspot/cpu/ppc/c1_FrameMap_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_FrameMap_ppc.cpp @@ -374,15 +374,6 @@ LIR_Opr FrameMap::stack_pointer() { return SP_opr; } - -// JSR 292 -// On PPC64, there is no need to save the SP, because neither -// method handle intrinsics, nor compiled lambda forms modify it. -LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() { - return LIR_OprFact::illegalOpr; -} - - bool FrameMap::validate_frame() { int max_offset = in_bytes(framesize_in_bytes()); int java_index = 0; diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index 290369360fc..2c83b2d5765 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -2473,10 +2473,6 @@ RegMask Matcher::modL_proj_mask() { return RegMask(); } -const RegMask Matcher::method_handle_invoke_SP_save_mask() { - return RegMask(); -} - %} //----------ENCODING BLOCK----------------------------------------------------- @@ -3434,7 +3430,6 @@ encode %{ // Create the call node. CallDynamicJavaDirectSchedNode *call = new CallDynamicJavaDirectSchedNode(); - call->_method_handle_invoke = _method_handle_invoke; call->_vtable_index = _vtable_index; call->_method = _method; call->_optimized_virtual = _optimized_virtual; diff --git a/src/hotspot/cpu/riscv/c1_FrameMap_riscv.cpp b/src/hotspot/cpu/riscv/c1_FrameMap_riscv.cpp index d3ccd46048b..b3a0b261f54 100644 --- a/src/hotspot/cpu/riscv/c1_FrameMap_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_FrameMap_riscv.cpp @@ -377,11 +377,6 @@ LIR_Opr FrameMap::stack_pointer() { return FrameMap::sp_opr; } -// JSR 292 -LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() { - return LIR_OprFact::illegalOpr; // Not needed on riscv -} - bool FrameMap::validate_frame() { return true; } diff --git a/src/hotspot/cpu/riscv/frame_riscv.cpp b/src/hotspot/cpu/riscv/frame_riscv.cpp index b677c980c78..19dbdd6aeae 100644 --- a/src/hotspot/cpu/riscv/frame_riscv.cpp +++ b/src/hotspot/cpu/riscv/frame_riscv.cpp @@ -217,8 +217,7 @@ bool frame::safe_for_sender(JavaThread *thread) { nmethod* nm = sender_blob->as_nmethod_or_null(); if (nm != nullptr) { - if (nm->is_deopt_mh_entry(sender_pc) || nm->is_deopt_entry(sender_pc) || - nm->method()->is_method_handle_intrinsic()) { + if (nm->is_deopt_entry(sender_pc) || nm->method()->is_method_handle_intrinsic()) { return false; } } @@ -427,49 +426,6 @@ JavaThread** frame::saved_thread_address(const frame& f) { return thread_addr; } -//------------------------------------------------------------------------------ -// frame::verify_deopt_original_pc -// -// Verifies the calculated original PC of a deoptimization PC for the -// given unextended SP. -#ifdef ASSERT -void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp) { - frame fr; - - // This is ugly but it's better than to change {get,set}_original_pc - // to take an SP value as argument. And it's only a debugging - // method anyway. - fr._unextended_sp = unextended_sp; - - assert_cond(nm != nullptr); - address original_pc = nm->get_original_pc(&fr); - assert(nm->insts_contains_inclusive(original_pc), - "original PC must be in the main code section of the compiled method (or must be immediately following it)"); -} -#endif - -//------------------------------------------------------------------------------ -// frame::adjust_unextended_sp -#ifdef ASSERT -void frame::adjust_unextended_sp() { - // On riscv, sites calling method handle intrinsics and lambda forms are treated - // as any other call site. Therefore, no special action is needed when we are - // returning to any of these call sites. - - if (_cb != nullptr) { - nmethod* sender_nm = _cb->as_nmethod_or_null(); - if (sender_nm != nullptr) { - // If the sender PC is a deoptimization point, get the original PC. - if (sender_nm->is_deopt_entry(_pc) || - sender_nm->is_deopt_mh_entry(_pc)) { - verify_deopt_original_pc(sender_nm, _unextended_sp); - } - } - } -} -#endif - - //------------------------------------------------------------------------------ // frame::sender_for_interpreter_frame frame frame::sender_for_interpreter_frame(RegisterMap* map) const { diff --git a/src/hotspot/cpu/riscv/frame_riscv.hpp b/src/hotspot/cpu/riscv/frame_riscv.hpp index b4540c45ab8..ce5a8dde230 100644 --- a/src/hotspot/cpu/riscv/frame_riscv.hpp +++ b/src/hotspot/cpu/riscv/frame_riscv.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -179,17 +179,10 @@ int _offset_unextended_sp; // for use in stack-chunk frames }; - void adjust_unextended_sp() NOT_DEBUG_RETURN; - intptr_t* ptr_at_addr(int offset) const { return (intptr_t*) addr_at(offset); } -#ifdef ASSERT - // Used in frame::sender_for_{interpreter,compiled}_frame - static void verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp); -#endif - public: // Constructors diff --git a/src/hotspot/cpu/riscv/frame_riscv.inline.hpp b/src/hotspot/cpu/riscv/frame_riscv.inline.hpp index fb31760e20b..51a203c548c 100644 --- a/src/hotspot/cpu/riscv/frame_riscv.inline.hpp +++ b/src/hotspot/cpu/riscv/frame_riscv.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -114,8 +114,6 @@ inline void frame::init(intptr_t* ptr_sp, intptr_t* ptr_fp, address pc) { } inline void frame::setup(address pc) { - adjust_unextended_sp(); - address original_pc = get_deopt_original_pc(); if (original_pc != nullptr) { _pc = original_pc; @@ -215,7 +213,6 @@ inline frame::frame(intptr_t* ptr_sp, intptr_t* ptr_fp) { // value. _cb = CodeCache::find_blob(_pc); - adjust_unextended_sp(); address original_pc = get_deopt_original_pc(); if (original_pc != nullptr) { diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index d816f2405c4..1f14c499c34 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -2152,10 +2152,6 @@ RegMask Matcher::modL_proj_mask() { return RegMask(); } -const RegMask Matcher::method_handle_invoke_SP_save_mask() { - return FP_REG_mask(); -} - bool size_fits_all_mem_uses(AddPNode* addp, int shift) { assert_cond(addp != nullptr); for (DUIterator_Fast imax, i = addp->fast_outs(imax); i < imax; i++) { diff --git a/src/hotspot/cpu/s390/c1_FrameMap_s390.cpp b/src/hotspot/cpu/s390/c1_FrameMap_s390.cpp index ddba445154a..e219e9bbb40 100644 --- a/src/hotspot/cpu/s390/c1_FrameMap_s390.cpp +++ b/src/hotspot/cpu/s390/c1_FrameMap_s390.cpp @@ -282,13 +282,6 @@ LIR_Opr FrameMap::stack_pointer() { return Z_SP_opr; } -// JSR 292 -// On ZARCH_64, there is no need to save the SP, because neither -// method handle intrinsics nor compiled lambda forms modify it. -LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() { - return LIR_OprFact::illegalOpr; -} - bool FrameMap::validate_frame() { return true; } diff --git a/src/hotspot/cpu/s390/s390.ad b/src/hotspot/cpu/s390/s390.ad index e9377733d2d..cfc8b19534b 100644 --- a/src/hotspot/cpu/s390/s390.ad +++ b/src/hotspot/cpu/s390/s390.ad @@ -1980,11 +1980,6 @@ RegMask Matcher::modL_proj_mask() { return _Z_RARG3_LONG_REG_mask; } -// Copied from sparc. -const RegMask Matcher::method_handle_invoke_SP_save_mask() { - return RegMask(); -} - // Should the matcher clone input 'm' of node 'n'? bool Matcher::pd_clone_node(Node* n, Node* m, Matcher::MStack& mstack) { if (is_encode_and_store_pattern(n, m)) { diff --git a/src/hotspot/cpu/x86/c1_FrameMap_x86.cpp b/src/hotspot/cpu/x86/c1_FrameMap_x86.cpp index bdbab432180..68c9814fd20 100644 --- a/src/hotspot/cpu/x86/c1_FrameMap_x86.cpp +++ b/src/hotspot/cpu/x86/c1_FrameMap_x86.cpp @@ -326,13 +326,6 @@ LIR_Opr FrameMap::stack_pointer() { return FrameMap::rsp_opr; } -// JSR 292 -// On x86, there is no need to save the SP, because neither -// method handle intrinsics, nor compiled lambda forms modify it. -LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() { - return LIR_OprFact::illegalOpr; -} - bool FrameMap::validate_frame() { return true; } diff --git a/src/hotspot/cpu/x86/frame_x86.cpp b/src/hotspot/cpu/x86/frame_x86.cpp index 46ffda93699..5f52f2fabf2 100644 --- a/src/hotspot/cpu/x86/frame_x86.cpp +++ b/src/hotspot/cpu/x86/frame_x86.cpp @@ -219,8 +219,7 @@ bool frame::safe_for_sender(JavaThread *thread) { nmethod* nm = sender_blob->as_nmethod_or_null(); if (nm != nullptr) { - if (nm->is_deopt_mh_entry(sender_pc) || nm->is_deopt_entry(sender_pc) || - nm->method()->is_method_handle_intrinsic()) { + if (nm->is_deopt_entry(sender_pc) || nm->method()->is_method_handle_intrinsic()) { return false; } } @@ -443,47 +442,6 @@ JavaThread** frame::saved_thread_address(const frame& f) { return thread_addr; } -//------------------------------------------------------------------------------ -// frame::verify_deopt_original_pc -// -// Verifies the calculated original PC of a deoptimization PC for the -// given unextended SP. -#ifdef ASSERT -void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp) { - frame fr; - - // This is ugly but it's better than to change {get,set}_original_pc - // to take an SP value as argument. And it's only a debugging - // method anyway. - fr._unextended_sp = unextended_sp; - - address original_pc = nm->get_original_pc(&fr); - assert(nm->insts_contains_inclusive(original_pc), - "original PC must be in the main code section of the compiled method (or must be immediately following it) original_pc: " INTPTR_FORMAT " unextended_sp: " INTPTR_FORMAT " name: %s", p2i(original_pc), p2i(unextended_sp), nm->name()); -} -#endif - -//------------------------------------------------------------------------------ -// frame::adjust_unextended_sp -#ifdef ASSERT -void frame::adjust_unextended_sp() { - // On x86, sites calling method handle intrinsics and lambda forms are treated - // as any other call site. Therefore, no special action is needed when we are - // returning to any of these call sites. - - if (_cb != nullptr) { - nmethod* sender_nm = _cb->as_nmethod_or_null(); - if (sender_nm != nullptr) { - // If the sender PC is a deoptimization point, get the original PC. - if (sender_nm->is_deopt_entry(_pc) || - sender_nm->is_deopt_mh_entry(_pc)) { - verify_deopt_original_pc(sender_nm, _unextended_sp); - } - } - } -} -#endif - //------------------------------------------------------------------------------ // frame::sender_for_interpreter_frame frame frame::sender_for_interpreter_frame(RegisterMap* map) const { diff --git a/src/hotspot/cpu/x86/frame_x86.hpp b/src/hotspot/cpu/x86/frame_x86.hpp index f3034ee9263..19f37c42cf4 100644 --- a/src/hotspot/cpu/x86/frame_x86.hpp +++ b/src/hotspot/cpu/x86/frame_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -138,17 +138,10 @@ int _offset_unextended_sp; // for use in stack-chunk frames }; - void adjust_unextended_sp() NOT_DEBUG_RETURN; - intptr_t* ptr_at_addr(int offset) const { return (intptr_t*) addr_at(offset); } -#ifdef ASSERT - // Used in frame::sender_for_{interpreter,compiled}_frame - static void verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp); -#endif - public: // Constructors diff --git a/src/hotspot/cpu/x86/frame_x86.inline.hpp b/src/hotspot/cpu/x86/frame_x86.inline.hpp index afc4ab8767b..ca51fe66786 100644 --- a/src/hotspot/cpu/x86/frame_x86.inline.hpp +++ b/src/hotspot/cpu/x86/frame_x86.inline.hpp @@ -111,8 +111,6 @@ inline void frame::init(intptr_t* sp, intptr_t* fp, address pc) { } inline void frame::setup(address pc) { - adjust_unextended_sp(); - address original_pc = get_deopt_original_pc(); if (original_pc != nullptr) { _pc = original_pc; @@ -209,7 +207,6 @@ inline frame::frame(intptr_t* sp, intptr_t* fp) { // assert(_pc != nullptr, "no pc?"); _cb = CodeCache::find_blob(_pc); - adjust_unextended_sp(); address original_pc = get_deopt_original_pc(); if (original_pc != nullptr) { diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index 0b254966db6..b40f9e2924a 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -1697,11 +1697,6 @@ RegMask Matcher::modL_proj_mask() { return LONG_RDX_REG_mask(); } -// Register for saving SP into on method handle invokes. Not used on x86_64. -const RegMask Matcher::method_handle_invoke_SP_save_mask() { - return NO_REG_mask(); -} - %} //----------ENCODING BLOCK----------------------------------------------------- diff --git a/src/hotspot/os/posix/signals_posix.cpp b/src/hotspot/os/posix/signals_posix.cpp index 886bd453415..714eac12d22 100644 --- a/src/hotspot/os/posix/signals_posix.cpp +++ b/src/hotspot/os/posix/signals_posix.cpp @@ -621,9 +621,7 @@ int JVM_HANDLE_XXX_SIGNAL(int sig, siginfo_t* info, if (cb != nullptr && cb->is_nmethod()) { nmethod* nm = cb->as_nmethod(); assert(nm->insts_contains_inclusive(pc), ""); - address deopt = nm->is_method_handle_return(pc) ? - nm->deopt_mh_handler_begin() : - nm->deopt_handler_begin(); + address deopt = nm->deopt_handler_begin(); assert(deopt != nullptr, ""); frame fr = os::fetch_frame_from_context(uc); diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 875e97ce038..c9ef08e3510 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -2797,9 +2797,7 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { if (cb != nullptr && cb->is_nmethod()) { nmethod* nm = cb->as_nmethod(); frame fr = os::fetch_frame_from_context((void*)exceptionInfo->ContextRecord); - address deopt = nm->is_method_handle_return(pc) ? - nm->deopt_mh_handler_begin() : - nm->deopt_handler_begin(); + address deopt = nm->deopt_handler_begin(); assert(nm->insts_contains_inclusive(pc), ""); nm->set_original_pc(&fr, pc); // Set pc to handler diff --git a/src/hotspot/share/asm/codeBuffer.hpp b/src/hotspot/share/asm/codeBuffer.hpp index 35bbd2f657f..430d4949467 100644 --- a/src/hotspot/share/asm/codeBuffer.hpp +++ b/src/hotspot/share/asm/codeBuffer.hpp @@ -57,7 +57,6 @@ public: OSR_Entry, Exceptions, // Offset where exception handler lives Deopt, // Offset where deopt handler lives - DeoptMH, // Offset where MethodHandle deopt handler lives UnwindHandler, // Offset to default unwind handler max_Entries }; @@ -77,7 +76,6 @@ public: _values[OSR_Entry ] = 0; _values[Exceptions ] = -1; _values[Deopt ] = -1; - _values[DeoptMH ] = -1; _values[UnwindHandler ] = -1; } diff --git a/src/hotspot/share/c1/c1_Compilation.cpp b/src/hotspot/share/c1/c1_Compilation.cpp index bb5ceb0106b..368cf604eeb 100644 --- a/src/hotspot/share/c1/c1_Compilation.cpp +++ b/src/hotspot/share/c1/c1_Compilation.cpp @@ -310,14 +310,6 @@ void Compilation::emit_code_epilog(LIR_Assembler* assembler) { code_offsets->set_value(CodeOffsets::Deopt, assembler->emit_deopt_handler()); CHECK_BAILOUT(); - // Emit the MethodHandle deopt handler code (if required). - if (has_method_handle_invokes()) { - // We can use the same code as for the normal deopt handler, we - // just need a different entry point address. - code_offsets->set_value(CodeOffsets::DeoptMH, assembler->emit_deopt_handler()); - CHECK_BAILOUT(); - } - // Emit the handler to remove the activation from the stack and // dispatch to the caller. offsets()->set_value(CodeOffsets::UnwindHandler, assembler->emit_unwind_handler()); @@ -574,7 +566,6 @@ Compilation::Compilation(AbstractCompiler* compiler, ciEnv* env, ciMethod* metho , _has_unsafe_access(false) , _has_irreducible_loops(false) , _would_profile(false) -, _has_method_handle_invokes(false) , _has_reserved_stack_access(method->has_reserved_stack_access()) , _has_monitors(method->is_synchronized() || method->has_monitor_bytecodes()) , _has_scoped_access(method->is_scoped()) diff --git a/src/hotspot/share/c1/c1_Compilation.hpp b/src/hotspot/share/c1/c1_Compilation.hpp index 0c6b95e66c5..5125e0bbe0a 100644 --- a/src/hotspot/share/c1/c1_Compilation.hpp +++ b/src/hotspot/share/c1/c1_Compilation.hpp @@ -79,7 +79,6 @@ class Compilation: public StackObj { bool _has_unsafe_access; bool _has_irreducible_loops; bool _would_profile; - bool _has_method_handle_invokes; // True if this method has MethodHandle invokes. bool _has_reserved_stack_access; bool _has_monitors; // Fastpath monitors detection for Continuations bool _has_scoped_access; // For shared scope closure @@ -180,10 +179,6 @@ class Compilation: public StackObj { // Statistics gathering void notice_inlined_method(ciMethod* method); - // JSR 292 - bool has_method_handle_invokes() const { return _has_method_handle_invokes; } - void set_has_method_handle_invokes(bool z) { _has_method_handle_invokes = z; } - bool has_reserved_stack_access() const { return _has_reserved_stack_access; } void set_has_reserved_stack_access(bool z) { _has_reserved_stack_access = z; } diff --git a/src/hotspot/share/c1/c1_FrameMap.hpp b/src/hotspot/share/c1/c1_FrameMap.hpp index f10c4d3f226..67ae92e9875 100644 --- a/src/hotspot/share/c1/c1_FrameMap.hpp +++ b/src/hotspot/share/c1/c1_FrameMap.hpp @@ -155,9 +155,6 @@ class FrameMap : public CompilationResourceObj { // Opr representing the stack_pointer on this platform static LIR_Opr stack_pointer(); - // JSR 292 - static LIR_Opr method_handle_invoke_SP_save_opr(); - static BasicTypeArray* signature_type_array_for(const ciMethod* method); // for outgoing calls, these also update the reserved area to diff --git a/src/hotspot/share/c1/c1_IR.cpp b/src/hotspot/share/c1/c1_IR.cpp index ae8332116b3..238a9bdda0d 100644 --- a/src/hotspot/share/c1/c1_IR.cpp +++ b/src/hotspot/share/c1/c1_IR.cpp @@ -190,7 +190,6 @@ CodeEmitInfo::CodeEmitInfo(ValueStack* stack, XHandlers* exception_handlers, boo , _exception_handlers(exception_handlers) , _oop_map(nullptr) , _stack(stack) - , _is_method_handle_invoke(false) , _deoptimize_on_exception(deoptimize_on_exception) , _force_reexecute(false) { assert(_stack != nullptr, "must be non null"); @@ -203,7 +202,6 @@ CodeEmitInfo::CodeEmitInfo(CodeEmitInfo* info, ValueStack* stack) , _exception_handlers(nullptr) , _oop_map(nullptr) , _stack(stack == nullptr ? info->_stack : stack) - , _is_method_handle_invoke(info->_is_method_handle_invoke) , _deoptimize_on_exception(info->_deoptimize_on_exception) , _force_reexecute(info->_force_reexecute) { @@ -218,7 +216,7 @@ void CodeEmitInfo::record_debug_info(DebugInformationRecorder* recorder, int pc_ // record the safepoint before recording the debug info for enclosing scopes recorder->add_safepoint(pc_offset, _oop_map->deep_copy()); bool reexecute = _force_reexecute || _scope_debug_info->should_reexecute(); - _scope_debug_info->record_debug_info(recorder, pc_offset, reexecute, _is_method_handle_invoke); + _scope_debug_info->record_debug_info(recorder, pc_offset, reexecute); recorder->end_safepoint(pc_offset); } diff --git a/src/hotspot/share/c1/c1_IR.hpp b/src/hotspot/share/c1/c1_IR.hpp index a9a7a026390..d6a4cddb9d7 100644 --- a/src/hotspot/share/c1/c1_IR.hpp +++ b/src/hotspot/share/c1/c1_IR.hpp @@ -234,7 +234,7 @@ class IRScopeDebugInfo: public CompilationResourceObj { //Whether we should reexecute this bytecode for deopt bool should_reexecute(); - void record_debug_info(DebugInformationRecorder* recorder, int pc_offset, bool reexecute, bool is_method_handle_invoke = false) { + void record_debug_info(DebugInformationRecorder* recorder, int pc_offset, bool reexecute) { if (caller() != nullptr) { // Order is significant: Must record caller first. caller()->record_debug_info(recorder, pc_offset, false/*reexecute*/); @@ -248,7 +248,7 @@ class IRScopeDebugInfo: public CompilationResourceObj { bool has_ea_local_in_scope = false; bool arg_escape = false; recorder->describe_scope(pc_offset, methodHandle(), scope()->method(), bci(), - reexecute, rethrow_exception, is_method_handle_invoke, return_oop, + reexecute, rethrow_exception, return_oop, has_ea_local_in_scope, arg_escape, locvals, expvals, monvals); } }; @@ -262,7 +262,6 @@ class CodeEmitInfo: public CompilationResourceObj { XHandlers* _exception_handlers; OopMap* _oop_map; ValueStack* _stack; // used by deoptimization (contains also monitors - bool _is_method_handle_invoke; // true if the associated call site is a MethodHandle call site. bool _deoptimize_on_exception; bool _force_reexecute; // force the reexecute flag on, used for patching stub @@ -288,9 +287,6 @@ class CodeEmitInfo: public CompilationResourceObj { void add_register_oop(LIR_Opr opr); void record_debug_info(DebugInformationRecorder* recorder, int pc_offset); - bool is_method_handle_invoke() const { return _is_method_handle_invoke; } - void set_is_method_handle_invoke(bool x) { _is_method_handle_invoke = x; } - bool force_reexecute() const { return _force_reexecute; } void set_force_reexecute() { _force_reexecute = true; } diff --git a/src/hotspot/share/c1/c1_LIR.cpp b/src/hotspot/share/c1/c1_LIR.cpp index f11e178bd55..012c0f92f25 100644 --- a/src/hotspot/share/c1/c1_LIR.cpp +++ b/src/hotspot/share/c1/c1_LIR.cpp @@ -709,11 +709,6 @@ void LIR_OpVisitState::visit(LIR_Op* op) { } if (opJavaCall->_info) do_info(opJavaCall->_info); - if (FrameMap::method_handle_invoke_SP_save_opr() != LIR_OprFact::illegalOpr && - opJavaCall->is_method_handle_invoke()) { - opJavaCall->_method_handle_invoke_SP_save_opr = FrameMap::method_handle_invoke_SP_save_opr(); - do_temp(opJavaCall->_method_handle_invoke_SP_save_opr); - } do_call(); if (opJavaCall->_result->is_valid()) do_output(opJavaCall->_result); diff --git a/src/hotspot/share/c1/c1_LIR.hpp b/src/hotspot/share/c1/c1_LIR.hpp index 0427c868e6f..847184731ce 100644 --- a/src/hotspot/share/c1/c1_LIR.hpp +++ b/src/hotspot/share/c1/c1_LIR.hpp @@ -1176,7 +1176,6 @@ class LIR_OpJavaCall: public LIR_OpCall { private: ciMethod* _method; LIR_Opr _receiver; - LIR_Opr _method_handle_invoke_SP_save_opr; // Used in LIR_OpVisitState::visit to store the reference to FrameMap::method_handle_invoke_SP_save_opr. public: LIR_OpJavaCall(LIR_Code code, ciMethod* method, @@ -1186,7 +1185,6 @@ class LIR_OpJavaCall: public LIR_OpCall { : LIR_OpCall(code, addr, result, arguments, info) , _method(method) , _receiver(receiver) - , _method_handle_invoke_SP_save_opr(LIR_OprFact::illegalOpr) { assert(is_in_range(code, begin_opJavaCall, end_opJavaCall), "code check"); } LIR_OpJavaCall(LIR_Code code, ciMethod* method, @@ -1195,7 +1193,6 @@ class LIR_OpJavaCall: public LIR_OpCall { : LIR_OpCall(code, (address)vtable_offset, result, arguments, info) , _method(method) , _receiver(receiver) - , _method_handle_invoke_SP_save_opr(LIR_OprFact::illegalOpr) { assert(is_in_range(code, begin_opJavaCall, end_opJavaCall), "code check"); } LIR_Opr receiver() const { return _receiver; } diff --git a/src/hotspot/share/c1/c1_LIRAssembler.cpp b/src/hotspot/share/c1/c1_LIRAssembler.cpp index 6dbd35f054f..e6963c00c6a 100644 --- a/src/hotspot/share/c1/c1_LIRAssembler.cpp +++ b/src/hotspot/share/c1/c1_LIRAssembler.cpp @@ -478,12 +478,6 @@ void LIR_Assembler::emit_call(LIR_OpJavaCall* op) { fatal("unexpected op code: %s", op->name()); break; } - - // JSR 292 - // Record if this method has MethodHandle invokes. - if (op->is_method_handle_invoke()) { - compilation()->set_has_method_handle_invokes(true); - } } diff --git a/src/hotspot/share/c1/c1_LIRGenerator.cpp b/src/hotspot/share/c1/c1_LIRGenerator.cpp index 66adfa5ed66..f6807abcd7a 100644 --- a/src/hotspot/share/c1/c1_LIRGenerator.cpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp @@ -2712,19 +2712,7 @@ void LIRGenerator::do_Invoke(Invoke* x) { // emit invoke code assert(receiver->is_illegal() || receiver->is_equal(LIR_Assembler::receiverOpr()), "must match"); - // JSR 292 - // Preserve the SP over MethodHandle call sites, if needed. ciMethod* target = x->target(); - bool is_method_handle_invoke = (// %%% FIXME: Are both of these relevant? - target->is_method_handle_intrinsic() || - target->is_compiled_lambda_form()); - if (is_method_handle_invoke) { - info->set_is_method_handle_invoke(true); - if(FrameMap::method_handle_invoke_SP_save_opr() != LIR_OprFact::illegalOpr) { - __ move(FrameMap::stack_pointer(), FrameMap::method_handle_invoke_SP_save_opr()); - } - } - switch (x->code()) { case Bytecodes::_invokestatic: __ call_static(target, result_register, @@ -2757,13 +2745,6 @@ void LIRGenerator::do_Invoke(Invoke* x) { break; } - // JSR 292 - // Restore the SP after MethodHandle call sites, if needed. - if (is_method_handle_invoke - && FrameMap::method_handle_invoke_SP_save_opr() != LIR_OprFact::illegalOpr) { - __ move(FrameMap::method_handle_invoke_SP_save_opr(), FrameMap::stack_pointer()); - } - if (result_register->is_valid()) { LIR_Opr result = rlock_result(x); __ move(result_register, result); diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp index 637c7c46ef4..a4c956ff5be 100644 --- a/src/hotspot/share/c1/c1_Runtime1.cpp +++ b/src/hotspot/share/c1/c1_Runtime1.cpp @@ -541,9 +541,6 @@ extern void vm_exit(int code); // unpack_with_exception entry instead. This makes life for the exception blob easier // because making that same check and diverting is painful from assembly language. JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* current, oopDesc* ex, address pc, nmethod*& nm)) - // Reset method handle flag. - current->set_is_method_handle_return(false); - Handle exception(current, ex); // This function is called when we are about to throw an exception. Therefore, @@ -622,8 +619,6 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* c if (guard_pages_enabled) { address fast_continuation = nm->handler_for_exception_and_pc(exception, pc); if (fast_continuation != nullptr) { - // Set flag if return address is a method handle call site. - current->set_is_method_handle_return(nm->is_method_handle_return(pc)); return fast_continuation; } } @@ -660,8 +655,6 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* c } current->set_vm_result_oop(exception()); - // Set flag if return address is a method handle call site. - current->set_is_method_handle_return(nm->is_method_handle_return(pc)); if (log_is_enabled(Info, exceptions)) { ResourceMark rm; diff --git a/src/hotspot/share/code/debugInfoRec.cpp b/src/hotspot/share/code/debugInfoRec.cpp index 8449f5d6929..41d944ec76f 100644 --- a/src/hotspot/share/code/debugInfoRec.cpp +++ b/src/hotspot/share/code/debugInfoRec.cpp @@ -283,7 +283,6 @@ void DebugInformationRecorder::describe_scope(int pc_offset, int bci, bool reexecute, bool rethrow_exception, - bool is_method_handle_invoke, bool return_oop, bool has_ea_local_in_scope, bool arg_escape, @@ -301,7 +300,6 @@ void DebugInformationRecorder::describe_scope(int pc_offset, // Record flags into pcDesc. last_pd->set_should_reexecute(reexecute); last_pd->set_rethrow_exception(rethrow_exception); - last_pd->set_is_method_handle_invoke(is_method_handle_invoke); last_pd->set_return_oop(return_oop); last_pd->set_has_ea_local_in_scope(has_ea_local_in_scope); last_pd->set_arg_escape(arg_escape); diff --git a/src/hotspot/share/code/debugInfoRec.hpp b/src/hotspot/share/code/debugInfoRec.hpp index f6d7cf6d278..d18208e17c4 100644 --- a/src/hotspot/share/code/debugInfoRec.hpp +++ b/src/hotspot/share/code/debugInfoRec.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -105,7 +105,6 @@ class DebugInformationRecorder: public ResourceObj { int bci, bool reexecute, bool rethrow_exception = false, - bool is_method_handle_invoke = false, bool return_oop = false, bool has_ea_local_in_scope = false, bool arg_escape = false, diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index c0091cd2f65..1540fa0333a 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -465,14 +465,6 @@ static int adjust_pcs_size(int pcs_size) { return nsize; } -bool nmethod::is_method_handle_return(address return_pc) { - if (!has_method_handle_invokes()) return false; - PcDesc* pd = pc_desc_at(return_pc); - if (pd == nullptr) - return false; - return pd->is_method_handle_invoke(); -} - // Returns a string version of the method state. const char* nmethod::state() const { int state = get_state(); @@ -1231,7 +1223,6 @@ void nmethod::init_defaults(CodeBuffer *code_buffer, CodeOffsets* offsets) { _state = not_installed; _has_unsafe_access = 0; - _has_method_handle_invokes = 0; _has_wide_vectors = 0; _has_monitors = 0; _has_scoped_access = 0; @@ -1310,7 +1301,6 @@ nmethod::nmethod( // Native wrappers do not have deopt handlers. Make the values // something that will never match a pc like the nmethod vtable entry _deopt_handler_offset = 0; - _deopt_mh_handler_offset = 0; _unwind_handler_offset = 0; CHECKED_CAST(_oops_size, uint16_t, align_up(code_buffer->total_oop_size(), oopSize)); @@ -1458,11 +1448,6 @@ nmethod::nmethod( } else { _deopt_handler_offset = -1; } - if (offsets->value(CodeOffsets::DeoptMH) != -1) { - _deopt_mh_handler_offset = code_offset() + offsets->value(CodeOffsets::DeoptMH); - } else { - _deopt_mh_handler_offset = -1; - } } else #endif { @@ -1472,11 +1457,6 @@ nmethod::nmethod( _exception_offset = _stub_offset + offsets->value(CodeOffsets::Exceptions); _deopt_handler_offset = _stub_offset + offsets->value(CodeOffsets::Deopt); - if (offsets->value(CodeOffsets::DeoptMH) != -1) { - _deopt_mh_handler_offset = _stub_offset + offsets->value(CodeOffsets::DeoptMH); - } else { - _deopt_mh_handler_offset = -1; - } } if (offsets->value(CodeOffsets::UnwindHandler) != -1) { // C1 generates UnwindHandler at the end of instructions section. @@ -2693,15 +2673,6 @@ void nmethod::copy_scopes_pcs(PcDesc* pcs, int count) { "must end with a sentinel"); #endif //ASSERT - // Search for MethodHandle invokes and tag the nmethod. - for (int i = 0; i < count; i++) { - if (pcs[i].is_method_handle_invoke()) { - set_has_method_handle_invokes(true); - break; - } - } - assert(has_method_handle_invokes() == (_deopt_mh_handler_offset != -1), "must have deopt mh handler"); - int size = count * sizeof(PcDesc); assert(scopes_pcs_size() >= size, "oob"); memcpy(scopes_pcs_begin(), pcs, size); @@ -3711,7 +3682,6 @@ const char* nmethod::nmethod_section_label(address pos) const { if (pos == code_begin()) label = "[Instructions begin]"; if (pos == entry_point()) label = "[Entry Point]"; if (pos == verified_entry_point()) label = "[Verified Entry Point]"; - if (has_method_handle_invokes() && (pos == deopt_mh_handler_begin())) label = "[Deopt MH Handler Code]"; if (pos == consts_begin() && pos != insts_begin()) label = "[Constants]"; // Check stub_code before checking exception_handler or deopt_handler. if (pos == this->stub_begin()) label = "[Stub Code]"; diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 8dfccb07891..1e876657098 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -226,9 +226,6 @@ class nmethod : public CodeBlob { // All deoptee's will resume execution at this location described by // this offset. int _deopt_handler_offset; - // All deoptee's at a MethodHandle call site will resume execution - // at this location described by this offset. - int _deopt_mh_handler_offset; // Offset (from insts_end) of the unwind handler if it exists int16_t _unwind_handler_offset; // Number of arguments passed on the stack @@ -267,7 +264,6 @@ class nmethod : public CodeBlob { // set during construction uint8_t _has_unsafe_access:1, // May fault due to unsafe access. - _has_method_handle_invokes:1,// Has this method MethodHandle invokes? _has_wide_vectors:1, // Preserve wide vectors at safepoints _has_monitors:1, // Fastpath monitor detection for continuations _has_scoped_access:1, // used by for shared scope closure (scopedMemoryAccess.cpp) @@ -606,7 +602,6 @@ public: address stub_end () const { return code_end() ; } address exception_begin () const { return header_begin() + _exception_offset ; } address deopt_handler_begin () const { return header_begin() + _deopt_handler_offset ; } - address deopt_mh_handler_begin() const { return header_begin() + _deopt_mh_handler_offset ; } address unwind_handler_begin () const { return _unwind_handler_offset != -1 ? (insts_end() - _unwind_handler_offset) : nullptr; } oop* oops_begin () const { return (oop*) data_begin(); } oop* oops_end () const { return (oop*) data_end(); } @@ -745,9 +740,6 @@ public: bool has_scoped_access() const { return _has_scoped_access; } void set_has_scoped_access(bool z) { _has_scoped_access = z; } - bool has_method_handle_invokes() const { return _has_method_handle_invokes; } - void set_has_method_handle_invokes(bool z) { _has_method_handle_invokes = z; } - bool has_wide_vectors() const { return _has_wide_vectors; } void set_has_wide_vectors(bool z) { _has_wide_vectors = z; } @@ -818,12 +810,9 @@ public: ExceptionCache* exception_cache_entry_for_exception(Handle exception); - // MethodHandle - bool is_method_handle_return(address return_pc); // Deopt // Return true is the PC is one would expect if the frame is being deopted. inline bool is_deopt_pc(address pc); - inline bool is_deopt_mh_entry(address pc); inline bool is_deopt_entry(address pc); // Accessor/mutator for the original pc of a frame before a frame was deopted. diff --git a/src/hotspot/share/code/nmethod.inline.hpp b/src/hotspot/share/code/nmethod.inline.hpp index 62c8eb723ea..44331db669c 100644 --- a/src/hotspot/share/code/nmethod.inline.hpp +++ b/src/hotspot/share/code/nmethod.inline.hpp @@ -31,16 +31,12 @@ #include "runtime/atomicAccess.hpp" #include "runtime/frame.hpp" -inline bool nmethod::is_deopt_pc(address pc) { return is_deopt_entry(pc) || is_deopt_mh_entry(pc); } +inline bool nmethod::is_deopt_pc(address pc) { return is_deopt_entry(pc); } inline bool nmethod::is_deopt_entry(address pc) { return pc == deopt_handler_begin(); } -inline bool nmethod::is_deopt_mh_entry(address pc) { - return pc == deopt_mh_handler_begin(); -} - // class ExceptionCache methods inline int ExceptionCache::count() { return AtomicAccess::load_acquire(&_count); } diff --git a/src/hotspot/share/code/pcDesc.hpp b/src/hotspot/share/code/pcDesc.hpp index 8048c3909c7..d8abe19ad35 100644 --- a/src/hotspot/share/code/pcDesc.hpp +++ b/src/hotspot/share/code/pcDesc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,11 +40,10 @@ class PcDesc { enum { PCDESC_reexecute = 1 << 0, - PCDESC_is_method_handle_invoke = 1 << 1, - PCDESC_return_oop = 1 << 2, - PCDESC_rethrow_exception = 1 << 3, - PCDESC_has_ea_local_in_scope = 1 << 4, - PCDESC_arg_escape = 1 << 5 + PCDESC_return_oop = 1 << 1, + PCDESC_rethrow_exception = 1 << 2, + PCDESC_has_ea_local_in_scope = 1 << 3, + PCDESC_arg_escape = 1 << 4 }; int _flags; @@ -85,9 +84,6 @@ class PcDesc { _flags == pd->_flags; } - bool is_method_handle_invoke() const { return (_flags & PCDESC_is_method_handle_invoke) != 0; } - void set_is_method_handle_invoke(bool z) { set_flag(PCDESC_is_method_handle_invoke, z); } - bool return_oop() const { return (_flags & PCDESC_return_oop) != 0; } void set_return_oop(bool z) { set_flag(PCDESC_return_oop, z); } diff --git a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp index 3a9fbc54bf9..ce617a4a514 100644 --- a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp +++ b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp @@ -1141,7 +1141,7 @@ int CodeInstaller::map_jvmci_bci(int bci) { return bci; } -void CodeInstaller::record_scope(jint pc_offset, HotSpotCompiledCodeStream* stream, u1 debug_info_flags, bool full_info, bool is_mh_invoke, bool return_oop, JVMCI_TRAPS) { +void CodeInstaller::record_scope(jint pc_offset, HotSpotCompiledCodeStream* stream, u1 debug_info_flags, bool full_info, bool return_oop, JVMCI_TRAPS) { if (full_info) { read_virtual_objects(stream, JVMCI_CHECK); } @@ -1184,7 +1184,7 @@ void CodeInstaller::record_scope(jint pc_offset, HotSpotCompiledCodeStream* stre // has_ea_local_in_scope and arg_escape should be added to JVMCI const bool has_ea_local_in_scope = false; const bool arg_escape = false; - _debug_recorder->describe_scope(pc_offset, method, nullptr, bci, reexecute, rethrow_exception, is_mh_invoke, return_oop, + _debug_recorder->describe_scope(pc_offset, method, nullptr, bci, reexecute, rethrow_exception, return_oop, has_ea_local_in_scope, arg_escape, locals_token, stack_token, monitors_token); } @@ -1242,14 +1242,8 @@ void CodeInstaller::site_Call(CodeBuffer& buffer, u1 tag, jint pc_offset, HotSpo _debug_recorder->add_safepoint(next_pc_offset, map); if (!method.is_null()) { - vmIntrinsics::ID iid = method->intrinsic_id(); - bool is_mh_invoke = false; - if (direct_call) { - is_mh_invoke = !method->is_static() && (iid == vmIntrinsics::_compiledLambdaForm || - (MethodHandles::is_signature_polymorphic(iid) && MethodHandles::is_signature_polymorphic_intrinsic(iid))); - } bool return_oop = method->is_returning_oop(); - record_scope(next_pc_offset, stream, flags, true, is_mh_invoke, return_oop, JVMCI_CHECK); + record_scope(next_pc_offset, stream, flags, true, return_oop, JVMCI_CHECK); } else { record_scope(next_pc_offset, stream, flags, true, JVMCI_CHECK); } @@ -1339,9 +1333,6 @@ void CodeInstaller::site_Mark(CodeBuffer& buffer, jint pc_offset, HotSpotCompile case DEOPT_HANDLER_ENTRY: _offsets.set_value(CodeOffsets::Deopt, pc_offset); break; - case DEOPT_MH_HANDLER_ENTRY: - _offsets.set_value(CodeOffsets::DeoptMH, pc_offset); - break; case FRAME_COMPLETE: _offsets.set_value(CodeOffsets::Frame_Complete, pc_offset); break; @@ -1369,6 +1360,7 @@ void CodeInstaller::site_Mark(CodeBuffer& buffer, jint pc_offset, HotSpotCompile case VERIFY_OOP_BITS: case VERIFY_OOP_MASK: case VERIFY_OOP_COUNT_ADDRESS: + case DEOPT_MH_HANDLER_ENTRY: break; default: diff --git a/src/hotspot/share/jvmci/jvmciCodeInstaller.hpp b/src/hotspot/share/jvmci/jvmciCodeInstaller.hpp index a8279e99dc2..bdebed2d9e8 100644 --- a/src/hotspot/share/jvmci/jvmciCodeInstaller.hpp +++ b/src/hotspot/share/jvmci/jvmciCodeInstaller.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -411,10 +411,10 @@ protected: void record_oop_patch(HotSpotCompiledCodeStream* stream, address dest, u1 read_tag, bool narrow, JVMCI_TRAPS); // full_info: if false, only BytecodePosition is in stream otherwise all DebugInfo is in stream - void record_scope(jint pc_offset, HotSpotCompiledCodeStream* stream, u1 debug_info_flags, bool full_info, bool is_mh_invoke, bool return_oop, JVMCI_TRAPS); + void record_scope(jint pc_offset, HotSpotCompiledCodeStream* stream, u1 debug_info_flags, bool full_info, bool return_oop, JVMCI_TRAPS); void record_scope(jint pc_offset, HotSpotCompiledCodeStream* stream, u1 debug_info_flags, bool full_info, JVMCI_TRAPS) { - record_scope(pc_offset, stream, debug_info_flags, full_info, false /* is_mh_invoke */, false /* return_oop */, JVMCIENV); + record_scope(pc_offset, stream, debug_info_flags, full_info, false /* return_oop */, JVMCIENV); } void record_object_value(ObjectValue* sv, HotSpotCompiledCodeStream* stream, JVMCI_TRAPS); diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index e75527235f0..a178ac66344 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -228,9 +228,6 @@ extern void vm_exit(int code); // unpack_with_exception entry instead. This makes life for the exception blob easier // because making that same check and diverting is painful from assembly language. JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* current, oopDesc* ex, address pc, nmethod*& nm)) - // Reset method handle flag. - current->set_is_method_handle_return(false); - Handle exception(current, ex); // The frame we rethrow the exception to might not have been processed by the GC yet. @@ -305,8 +302,6 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* c if (guard_pages_enabled) { address fast_continuation = nm->handler_for_exception_and_pc(exception, pc); if (fast_continuation != nullptr) { - // Set flag if return address is a method handle call site. - current->set_is_method_handle_return(nm->is_method_handle_return(pc)); return fast_continuation; } } @@ -343,9 +338,6 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* c } } - // Set flag if return address is a method handle call site. - current->set_is_method_handle_return(nm->is_method_handle_return(pc)); - if (log_is_enabled(Info, exceptions)) { ResourceMark rm; log_info(exceptions)("Thread " PTR_FORMAT " continuing at PC " PTR_FORMAT diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index b91de1c9b35..b4f033a4f9a 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -242,7 +242,6 @@ nonstatic_field(JavaThread, _stack_overflow_state._stack_overflow_limit, address) \ volatile_nonstatic_field(JavaThread, _exception_oop, oop) \ volatile_nonstatic_field(JavaThread, _exception_pc, address) \ - volatile_nonstatic_field(JavaThread, _is_method_handle_return, int) \ volatile_nonstatic_field(JavaThread, _doing_unsafe_access, bool) \ nonstatic_field(JavaThread, _osthread, OSThread*) \ nonstatic_field(JavaThread, _saved_exception_pc, address) \ diff --git a/src/hotspot/share/opto/callGenerator.cpp b/src/hotspot/share/opto/callGenerator.cpp index e09d8cabe2c..03225044f5e 100644 --- a/src/hotspot/share/opto/callGenerator.cpp +++ b/src/hotspot/share/opto/callGenerator.cpp @@ -169,10 +169,6 @@ JVMState* DirectCallGenerator::generate(JVMState* jvms) { } // Mark the call node as virtual, sort of: call->set_optimized_virtual(true); - if (method()->is_method_handle_intrinsic() || - method()->is_compiled_lambda_form()) { - call->set_method_handle_invoke(true); - } } kit.set_arguments_for_java_call(call); kit.set_edges_for_java_call(call, false, _separate_io_proj); diff --git a/src/hotspot/share/opto/callnode.hpp b/src/hotspot/share/opto/callnode.hpp index 093c47194ef..9029a009989 100644 --- a/src/hotspot/share/opto/callnode.hpp +++ b/src/hotspot/share/opto/callnode.hpp @@ -778,7 +778,6 @@ protected: ciMethod* _method; // Method being direct called bool _optimized_virtual; - bool _method_handle_invoke; bool _override_symbolic_info; // Override symbolic call site info from bytecode bool _arg_escape; // ArgEscape in parameter list public: @@ -786,7 +785,6 @@ public: : CallNode(tf, addr, TypePtr::BOTTOM), _method(method), _optimized_virtual(false), - _method_handle_invoke(false), _override_symbolic_info(false), _arg_escape(false) { @@ -798,8 +796,6 @@ public: void set_method(ciMethod *m) { _method = m; } void set_optimized_virtual(bool f) { _optimized_virtual = f; } bool is_optimized_virtual() const { return _optimized_virtual; } - void set_method_handle_invoke(bool f) { _method_handle_invoke = f; } - bool is_method_handle_invoke() const { return _method_handle_invoke; } void set_override_symbolic_info(bool f) { _override_symbolic_info = f; } bool override_symbolic_info() const { return _override_symbolic_info; } void set_arg_escape(bool f) { _arg_escape = f; } diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index f828dfb6928..47de5acc2f2 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -650,7 +650,6 @@ Compile::Compile(ciEnv* ci_env, ciMethod* target, int osr_bci, _igv_idx(0), _trace_opto_output(directive->TraceOptoOutputOption), #endif - _has_method_handle_invokes(false), _clinit_barrier_on_entry(false), _stress_seed(0), _comp_arena(mtCompiler, Arena::Tag::tag_comp), @@ -925,7 +924,6 @@ Compile::Compile(ciEnv* ci_env, _igv_idx(0), _trace_opto_output(directive->TraceOptoOutputOption), #endif - _has_method_handle_invokes(false), _clinit_barrier_on_entry(false), _stress_seed(0), _comp_arena(mtCompiler, Arena::Tag::tag_comp), diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index 1cfcdca9610..05c5f22dad9 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -354,8 +354,6 @@ class Compile : public Phase { bool _parsed_irreducible_loop; // True if ciTypeFlow detected irreducible loops during parsing #endif bool _has_irreducible_loop; // Found irreducible loops - // JSR 292 - bool _has_method_handle_invokes; // True if this method has MethodHandle invokes. bool _has_monitors; // Metadata transfered to nmethod to enable Continuations lock-detection fastpath bool _has_scoped_access; // For shared scope closure bool _clinit_barrier_on_entry; // True if clinit barrier is needed on nmethod entry @@ -666,10 +664,6 @@ public: bool has_irreducible_loop() const { return _has_irreducible_loop; } void set_has_irreducible_loop(bool z) { _has_irreducible_loop = z; } - // JSR 292 - bool has_method_handle_invokes() const { return _has_method_handle_invokes; } - void set_has_method_handle_invokes(bool z) { _has_method_handle_invokes = z; } - Ticks _latest_stage_start_counter; void begin_method(); diff --git a/src/hotspot/share/opto/lcm.cpp b/src/hotspot/share/opto/lcm.cpp index ca1863b685e..fd7644f8587 100644 --- a/src/hotspot/share/opto/lcm.cpp +++ b/src/hotspot/share/opto/lcm.cpp @@ -946,17 +946,6 @@ uint PhaseCFG::sched_call(Block* block, uint node_cnt, Node_List& worklist, Grow // references but there no way to handle oops differently than other // pointers as far as the kill mask goes. bool exclude_soe = op == Op_CallRuntime; - - // If the call is a MethodHandle invoke, we need to exclude the - // register which is used to save the SP value over MH invokes from - // the mask. Otherwise this register could be used for - // deoptimization information. - if (op == Op_CallStaticJava) { - MachCallStaticJavaNode* mcallstaticjava = (MachCallStaticJavaNode*) mcall; - if (mcallstaticjava->_method_handle_invoke) - proj->_rout.OR(Matcher::method_handle_invoke_SP_save_mask()); - } - add_call_kills(proj, regs, save_policy, exclude_soe); return node_cnt; diff --git a/src/hotspot/share/opto/machnode.cpp b/src/hotspot/share/opto/machnode.cpp index e5acad98c09..5da929e4748 100644 --- a/src/hotspot/share/opto/machnode.cpp +++ b/src/hotspot/share/opto/machnode.cpp @@ -772,8 +772,6 @@ bool MachCallJavaNode::cmp( const Node &n ) const { } #ifndef PRODUCT void MachCallJavaNode::dump_spec(outputStream *st) const { - if (_method_handle_invoke) - st->print("MethodHandle "); if (_method) { _method->print_short_name(st); st->print(" "); @@ -794,10 +792,7 @@ const RegMask &MachCallJavaNode::in_RegMask(uint idx) const { } // Values outside the domain represent debug info Matcher* m = Compile::current()->matcher(); - // If this call is a MethodHandle invoke we have to use a different - // debugmask which does not include the register we use to save the - // SP over MH invokes. - RegMask** debugmask = _method_handle_invoke ? m->idealreg2mhdebugmask : m->idealreg2debugmask; + RegMask** debugmask = m->idealreg2debugmask; return *debugmask[in(idx)->ideal_reg()]; } diff --git a/src/hotspot/share/opto/machnode.hpp b/src/hotspot/share/opto/machnode.hpp index 5490f717a25..43e9a35df34 100644 --- a/src/hotspot/share/opto/machnode.hpp +++ b/src/hotspot/share/opto/machnode.hpp @@ -960,7 +960,6 @@ public: ciMethod* _method; // Method being direct called bool _override_symbolic_info; // Override symbolic call site info from bytecode bool _optimized_virtual; // Tells if node is a static call or an optimized virtual - bool _method_handle_invoke; // Tells if the call has to preserve SP bool _arg_escape; // ArgEscape in parameter list MachCallJavaNode() : MachCallNode(), _override_symbolic_info(false) { init_class_id(Class_MachCallJava); diff --git a/src/hotspot/share/opto/matcher.cpp b/src/hotspot/share/opto/matcher.cpp index b43bc05c465..7d73487cf88 100644 --- a/src/hotspot/share/opto/matcher.cpp +++ b/src/hotspot/share/opto/matcher.cpp @@ -50,8 +50,6 @@ const RegMask *Matcher::idealreg2regmask[_last_machine_leaf]; RegMask Matcher::mreg2regmask[_last_Mach_Reg]; RegMask Matcher::caller_save_regmask; RegMask Matcher::caller_save_regmask_exclude_soe; -RegMask Matcher::mh_caller_save_regmask; -RegMask Matcher::mh_caller_save_regmask_exclude_soe; RegMask Matcher::STACK_ONLY_mask; RegMask Matcher::c_frame_ptr_mask; const uint Matcher::_begin_rematerialize = _BEGIN_REMATERIALIZE; @@ -114,21 +112,6 @@ Matcher::Matcher() idealreg2debugmask [Op_RegFlags] = nullptr; idealreg2debugmask [Op_RegVectMask] = nullptr; - idealreg2mhdebugmask[Op_RegI] = nullptr; - idealreg2mhdebugmask[Op_RegN] = nullptr; - idealreg2mhdebugmask[Op_RegL] = nullptr; - idealreg2mhdebugmask[Op_RegF] = nullptr; - idealreg2mhdebugmask[Op_RegD] = nullptr; - idealreg2mhdebugmask[Op_RegP] = nullptr; - idealreg2mhdebugmask[Op_VecA] = nullptr; - idealreg2mhdebugmask[Op_VecS] = nullptr; - idealreg2mhdebugmask[Op_VecD] = nullptr; - idealreg2mhdebugmask[Op_VecX] = nullptr; - idealreg2mhdebugmask[Op_VecY] = nullptr; - idealreg2mhdebugmask[Op_VecZ] = nullptr; - idealreg2mhdebugmask[Op_RegFlags] = nullptr; - idealreg2mhdebugmask[Op_RegVectMask] = nullptr; - DEBUG_ONLY(_mem_node = nullptr;) // Ideal memory node consumed by mach node } @@ -465,7 +448,7 @@ int Matcher::scalable_predicate_reg_slots() { return round_up_power_of_2(slots); } -#define NOF_STACK_MASKS (3*13) +#define NOF_STACK_MASKS (2*13) // Create the initial stack mask used by values spilling to the stack. // Disallow any debug info in outgoing argument areas by setting the @@ -480,51 +463,12 @@ void Matcher::init_first_stack_mask() { new (rms + i) RegMask(C->comp_arena()); } - idealreg2spillmask [Op_RegN] = &rms[0]; - idealreg2spillmask [Op_RegI] = &rms[1]; - idealreg2spillmask [Op_RegL] = &rms[2]; - idealreg2spillmask [Op_RegF] = &rms[3]; - idealreg2spillmask [Op_RegD] = &rms[4]; - idealreg2spillmask [Op_RegP] = &rms[5]; - - idealreg2debugmask [Op_RegN] = &rms[6]; - idealreg2debugmask [Op_RegI] = &rms[7]; - idealreg2debugmask [Op_RegL] = &rms[8]; - idealreg2debugmask [Op_RegF] = &rms[9]; - idealreg2debugmask [Op_RegD] = &rms[10]; - idealreg2debugmask [Op_RegP] = &rms[11]; - - idealreg2mhdebugmask[Op_RegN] = &rms[12]; - idealreg2mhdebugmask[Op_RegI] = &rms[13]; - idealreg2mhdebugmask[Op_RegL] = &rms[14]; - idealreg2mhdebugmask[Op_RegF] = &rms[15]; - idealreg2mhdebugmask[Op_RegD] = &rms[16]; - idealreg2mhdebugmask[Op_RegP] = &rms[17]; - - idealreg2spillmask [Op_VecA] = &rms[18]; - idealreg2spillmask [Op_VecS] = &rms[19]; - idealreg2spillmask [Op_VecD] = &rms[20]; - idealreg2spillmask [Op_VecX] = &rms[21]; - idealreg2spillmask [Op_VecY] = &rms[22]; - idealreg2spillmask [Op_VecZ] = &rms[23]; - - idealreg2debugmask [Op_VecA] = &rms[24]; - idealreg2debugmask [Op_VecS] = &rms[25]; - idealreg2debugmask [Op_VecD] = &rms[26]; - idealreg2debugmask [Op_VecX] = &rms[27]; - idealreg2debugmask [Op_VecY] = &rms[28]; - idealreg2debugmask [Op_VecZ] = &rms[29]; - - idealreg2mhdebugmask[Op_VecA] = &rms[30]; - idealreg2mhdebugmask[Op_VecS] = &rms[31]; - idealreg2mhdebugmask[Op_VecD] = &rms[32]; - idealreg2mhdebugmask[Op_VecX] = &rms[33]; - idealreg2mhdebugmask[Op_VecY] = &rms[34]; - idealreg2mhdebugmask[Op_VecZ] = &rms[35]; - - idealreg2spillmask [Op_RegVectMask] = &rms[36]; - idealreg2debugmask [Op_RegVectMask] = &rms[37]; - idealreg2mhdebugmask[Op_RegVectMask] = &rms[38]; + int index = 0; + for (int i = Op_RegN; i <= Op_RegVectMask; ++i) { + idealreg2spillmask[i] = &rms[index++]; + idealreg2debugmask[i] = &rms[index++]; + } + assert(index == NOF_STACK_MASKS, "wrong size"); // At first, start with the empty mask C->FIRST_STACK_mask().Clear(); @@ -710,26 +654,10 @@ void Matcher::init_first_stack_mask() { *idealreg2debugmask [Op_VecY] = *idealreg2spillmask[Op_VecY]; *idealreg2debugmask [Op_VecZ] = *idealreg2spillmask[Op_VecZ]; - *idealreg2mhdebugmask[Op_RegN] = *idealreg2spillmask[Op_RegN]; - *idealreg2mhdebugmask[Op_RegI] = *idealreg2spillmask[Op_RegI]; - *idealreg2mhdebugmask[Op_RegL] = *idealreg2spillmask[Op_RegL]; - *idealreg2mhdebugmask[Op_RegF] = *idealreg2spillmask[Op_RegF]; - *idealreg2mhdebugmask[Op_RegD] = *idealreg2spillmask[Op_RegD]; - *idealreg2mhdebugmask[Op_RegP] = *idealreg2spillmask[Op_RegP]; - *idealreg2mhdebugmask[Op_RegVectMask] = *idealreg2spillmask[Op_RegVectMask]; - - *idealreg2mhdebugmask[Op_VecA] = *idealreg2spillmask[Op_VecA]; - *idealreg2mhdebugmask[Op_VecS] = *idealreg2spillmask[Op_VecS]; - *idealreg2mhdebugmask[Op_VecD] = *idealreg2spillmask[Op_VecD]; - *idealreg2mhdebugmask[Op_VecX] = *idealreg2spillmask[Op_VecX]; - *idealreg2mhdebugmask[Op_VecY] = *idealreg2spillmask[Op_VecY]; - *idealreg2mhdebugmask[Op_VecZ] = *idealreg2spillmask[Op_VecZ]; - // Prevent stub compilations from attempting to reference // callee-saved (SOE) registers from debug info bool exclude_soe = !Compile::current()->is_method_compilation(); RegMask* caller_save_mask = exclude_soe ? &caller_save_regmask_exclude_soe : &caller_save_regmask; - RegMask* mh_caller_save_mask = exclude_soe ? &mh_caller_save_regmask_exclude_soe : &mh_caller_save_regmask; idealreg2debugmask[Op_RegN]->SUBTRACT(*caller_save_mask); idealreg2debugmask[Op_RegI]->SUBTRACT(*caller_save_mask); @@ -745,21 +673,6 @@ void Matcher::init_first_stack_mask() { idealreg2debugmask[Op_VecX]->SUBTRACT(*caller_save_mask); idealreg2debugmask[Op_VecY]->SUBTRACT(*caller_save_mask); idealreg2debugmask[Op_VecZ]->SUBTRACT(*caller_save_mask); - - idealreg2mhdebugmask[Op_RegN]->SUBTRACT(*mh_caller_save_mask); - idealreg2mhdebugmask[Op_RegI]->SUBTRACT(*mh_caller_save_mask); - idealreg2mhdebugmask[Op_RegL]->SUBTRACT(*mh_caller_save_mask); - idealreg2mhdebugmask[Op_RegF]->SUBTRACT(*mh_caller_save_mask); - idealreg2mhdebugmask[Op_RegD]->SUBTRACT(*mh_caller_save_mask); - idealreg2mhdebugmask[Op_RegP]->SUBTRACT(*mh_caller_save_mask); - idealreg2mhdebugmask[Op_RegVectMask]->SUBTRACT(*mh_caller_save_mask); - - idealreg2mhdebugmask[Op_VecA]->SUBTRACT(*mh_caller_save_mask); - idealreg2mhdebugmask[Op_VecS]->SUBTRACT(*mh_caller_save_mask); - idealreg2mhdebugmask[Op_VecD]->SUBTRACT(*mh_caller_save_mask); - idealreg2mhdebugmask[Op_VecX]->SUBTRACT(*mh_caller_save_mask); - idealreg2mhdebugmask[Op_VecY]->SUBTRACT(*mh_caller_save_mask); - idealreg2mhdebugmask[Op_VecZ]->SUBTRACT(*mh_caller_save_mask); } //---------------------------is_save_on_entry---------------------------------- @@ -984,23 +897,15 @@ void Matcher::init_spill_mask( Node *ret ) { if (_register_save_policy[i] == 'C' || _register_save_policy[i] == 'A') { caller_save_regmask.Insert(i); - mh_caller_save_regmask.Insert(i); } // Exclude save-on-entry registers from debug masks for stub compilations. if (_register_save_policy[i] == 'C' || _register_save_policy[i] == 'A' || _register_save_policy[i] == 'E') { caller_save_regmask_exclude_soe.Insert(i); - mh_caller_save_regmask_exclude_soe.Insert(i); } } - // Also exclude the register we use to save the SP for MethodHandle - // invokes to from the corresponding MH debug masks - const RegMask sp_save_mask = method_handle_invoke_SP_save_mask(); - mh_caller_save_regmask.OR(sp_save_mask); - mh_caller_save_regmask_exclude_soe.OR(sp_save_mask); - // Grab the Frame Pointer Node *fp = ret->in(TypeFunc::FramePtr); // Share frame pointer while making spill ops @@ -1272,7 +1177,6 @@ MachNode *Matcher::match_sfpt( SafePointNode *sfpt ) { CallNode *call; const TypeTuple *domain; ciMethod* method = nullptr; - bool is_method_handle_invoke = false; // for special kill effects if( sfpt->is_Call() ) { call = sfpt->as_Call(); domain = call->tf()->domain(); @@ -1298,13 +1202,8 @@ MachNode *Matcher::match_sfpt( SafePointNode *sfpt ) { method = call_java->method(); mcall_java->_method = method; mcall_java->_optimized_virtual = call_java->is_optimized_virtual(); - is_method_handle_invoke = call_java->is_method_handle_invoke(); - mcall_java->_method_handle_invoke = is_method_handle_invoke; mcall_java->_override_symbolic_info = call_java->override_symbolic_info(); mcall_java->_arg_escape = call_java->arg_escape(); - if (is_method_handle_invoke) { - C->set_has_method_handle_invokes(true); - } if( mcall_java->is_MachCallStaticJava() ) mcall_java->as_MachCallStaticJava()->_name = call_java->as_CallStaticJava()->_name; diff --git a/src/hotspot/share/opto/matcher.hpp b/src/hotspot/share/opto/matcher.hpp index f4b0a7db873..0b609b70ab5 100644 --- a/src/hotspot/share/opto/matcher.hpp +++ b/src/hotspot/share/opto/matcher.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -177,7 +177,6 @@ public: static const RegMask *idealreg2regmask[]; RegMask *idealreg2spillmask [_last_machine_leaf]; RegMask *idealreg2debugmask [_last_machine_leaf]; - RegMask *idealreg2mhdebugmask[_last_machine_leaf]; void init_spill_mask( Node *ret ); // Convert machine register number to register mask static uint mreg2regmask_max; @@ -185,8 +184,6 @@ public: static RegMask STACK_ONLY_mask; static RegMask caller_save_regmask; static RegMask caller_save_regmask_exclude_soe; - static RegMask mh_caller_save_regmask; - static RegMask mh_caller_save_regmask_exclude_soe; MachNode* mach_null() const { return _mach_null; } @@ -424,8 +421,6 @@ public: // a code which use multiply for division by constant. static bool use_asm_for_ldiv_by_con( jlong divisor ); - static const RegMask method_handle_invoke_SP_save_mask(); - // Java-Interpreter calling convention // (what you use when calling between compiled-Java and Interpreted-Java diff --git a/src/hotspot/share/opto/output.cpp b/src/hotspot/share/opto/output.cpp index 90d24b609a7..84c01c68e38 100644 --- a/src/hotspot/share/opto/output.cpp +++ b/src/hotspot/share/opto/output.cpp @@ -992,7 +992,6 @@ void PhaseOutput::Process_OopMap_Node(MachNode *mach, int current_offset) { MachCallNode *mcall; int safepoint_pc_offset = current_offset; - bool is_method_handle_invoke = false; bool return_oop = false; bool has_ea_local_in_scope = sfn->_has_ea_local_in_scope; bool arg_escape = false; @@ -1004,12 +1003,7 @@ void PhaseOutput::Process_OopMap_Node(MachNode *mach, int current_offset) { } else { mcall = mach->as_MachCall(); - // Is the call a MethodHandle call? if (mcall->is_MachCallJava()) { - if (mcall->as_MachCallJava()->_method_handle_invoke) { - assert(C->has_method_handle_invokes(), "must have been set during call generation"); - is_method_handle_invoke = true; - } arg_escape = mcall->as_MachCallJava()->_arg_escape; } @@ -1192,7 +1186,6 @@ void PhaseOutput::Process_OopMap_Node(MachNode *mach, int current_offset) { jvms->bci(), jvms->should_reexecute(), rethrow_exception, - is_method_handle_invoke, return_oop, has_ea_local_in_scope, arg_escape, @@ -1370,9 +1363,6 @@ CodeBuffer* PhaseOutput::init_buffer() { exception_handler_req + deopt_handler_req; // deopt handler - if (C->has_method_handle_invokes()) - total_req += deopt_handler_req; // deopt MH handler - CodeBuffer* cb = code_buffer(); cb->set_const_section_alignment(constant_table().alignment()); cb->initialize(total_req, _buf_sizes._reloc); @@ -1806,13 +1796,6 @@ void PhaseOutput::fill_buffer(C2_MacroAssembler* masm, uint* blk_starts) { } // Emit the deopt handler code. _code_offsets.set_value(CodeOffsets::Deopt, HandlerImpl::emit_deopt_handler(masm)); - - // Emit the MethodHandle deopt handler code (if required). - if (C->has_method_handle_invokes() && !C->failing()) { - // We can use the same code as for the normal deopt handler, we - // just need a different entry point address. - _code_offsets.set_value(CodeOffsets::DeoptMH, HandlerImpl::emit_deopt_handler(masm)); - } } // One last check for failed CodeBuffer::expand: diff --git a/src/hotspot/share/opto/runtime.cpp b/src/hotspot/share/opto/runtime.cpp index 0d148edda6e..072b1384921 100644 --- a/src/hotspot/share/opto/runtime.cpp +++ b/src/hotspot/share/opto/runtime.cpp @@ -1913,9 +1913,6 @@ JRT_ENTRY_NO_ASYNC(address, OptoRuntime::handle_exception_C_helper(JavaThread* c current->set_exception_pc(pc); current->set_exception_handler_pc(handler_address); - - // Check if the exception PC is a MethodHandle call site. - current->set_is_method_handle_return(nm->is_method_handle_return(pc)); } // Restore correct return pc. Was saved above. diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index a96c18a18aa..853c6554022 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -589,12 +589,7 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread // Verify we have the right vframeArray assert(cb->frame_size() >= 0, "Unexpected frame size"); intptr_t* unpack_sp = stub_frame.sp() + cb->frame_size(); - - // If the deopt call site is a MethodHandle invoke call site we have - // to adjust the unpack_sp. - nmethod* deoptee_nm = deoptee.cb()->as_nmethod_or_null(); - if (deoptee_nm != nullptr && deoptee_nm->is_method_handle_return(deoptee.pc())) - unpack_sp = deoptee.unextended_sp(); + assert(unpack_sp == deoptee.unextended_sp(), "must be"); #ifdef ASSERT assert(cb->is_deoptimization_stub() || diff --git a/src/hotspot/share/runtime/frame.cpp b/src/hotspot/share/runtime/frame.cpp index 75c6e388b0d..e578e614440 100644 --- a/src/hotspot/share/runtime/frame.cpp +++ b/src/hotspot/share/runtime/frame.cpp @@ -206,10 +206,7 @@ address frame::raw_pc() const { if (is_deoptimized_frame()) { nmethod* nm = cb()->as_nmethod_or_null(); assert(nm != nullptr, "only nmethod is expected here"); - if (nm->is_method_handle_return(pc())) - return nm->deopt_mh_handler_begin() - pc_return_offset; - else - return nm->deopt_handler_begin() - pc_return_offset; + return nm->deopt_handler_begin() - pc_return_offset; } else { return (pc() - pc_return_offset); } @@ -358,9 +355,7 @@ void frame::deoptimize(JavaThread* thread) { // If the call site is a MethodHandle call site use the MH deopt handler. nmethod* nm = _cb->as_nmethod(); - address deopt = nm->is_method_handle_return(pc()) ? - nm->deopt_mh_handler_begin() : - nm->deopt_handler_begin(); + address deopt = nm->deopt_handler_begin(); NativePostCallNop* inst = nativePostCallNop_at(pc()); diff --git a/src/hotspot/share/runtime/frame.inline.hpp b/src/hotspot/share/runtime/frame.inline.hpp index 449abddd443..cbf01dd5763 100644 --- a/src/hotspot/share/runtime/frame.inline.hpp +++ b/src/hotspot/share/runtime/frame.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,7 +76,10 @@ inline address frame::get_deopt_original_pc() const { nmethod* nm = _cb->as_nmethod_or_null(); if (nm != nullptr && nm->is_deopt_pc(_pc)) { - return nm->get_original_pc(this); + address original_pc = nm->get_original_pc(this); + assert(nm->insts_contains_inclusive(original_pc), + "original PC must be in the main code section of the compiled method (or must be immediately following it)"); + return original_pc; } return nullptr; } diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index f5cd43b1769..e5af8d7bedd 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -476,7 +476,6 @@ JavaThread::JavaThread(MemTag mem_tag) : _exception_oop(oop()), _exception_pc(nullptr), _exception_handler_pc(nullptr), - _is_method_handle_return(0), _jni_active_critical(0), _pending_jni_exception_check_fn(nullptr), diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp index 00bc5969196..89c3191669a 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -450,7 +450,6 @@ class JavaThread: public Thread { volatile oop _exception_oop; // Exception thrown in compiled code volatile address _exception_pc; // PC where exception happened volatile address _exception_handler_pc; // PC for handler of exception - volatile int _is_method_handle_return; // true (== 1) if the current exception PC is a MethodHandle call site. private: // support for JNI critical regions @@ -817,7 +816,6 @@ public: void set_exception_oop(oop o); void set_exception_pc(address a) { _exception_pc = a; } void set_exception_handler_pc(address a) { _exception_handler_pc = a; } - void set_is_method_handle_return(bool value) { _is_method_handle_return = value ? 1 : 0; } void clear_exception_oop_and_pc() { set_exception_oop(nullptr); @@ -866,7 +864,6 @@ public: static ByteSize exception_oop_offset() { return byte_offset_of(JavaThread, _exception_oop); } static ByteSize exception_pc_offset() { return byte_offset_of(JavaThread, _exception_pc); } static ByteSize exception_handler_pc_offset() { return byte_offset_of(JavaThread, _exception_handler_pc); } - static ByteSize is_method_handle_return_offset() { return byte_offset_of(JavaThread, _is_method_handle_return); } static ByteSize active_handles_offset() { return byte_offset_of(JavaThread, _active_handles); } diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index c3a6e0a4dc3..c81c975372c 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -525,9 +525,6 @@ address SharedRuntime::raw_exception_handler_for_return_address(JavaThread* curr assert(frame::verify_return_pc(return_address), "must be a return address: " INTPTR_FORMAT, p2i(return_address)); assert(current->frames_to_pop_failed_realloc() == 0 || Interpreter::contains(return_address), "missed frames to pop?"); - // Reset method handle flag. - current->set_is_method_handle_return(false); - #if INCLUDE_JVMCI // JVMCI's ExceptionHandlerStub expects the thread local exception PC to be clear // and other exception handler continuations do not read it @@ -542,8 +539,6 @@ address SharedRuntime::raw_exception_handler_for_return_address(JavaThread* curr CodeBlob* blob = CodeCache::find_blob(return_address); nmethod* nm = (blob != nullptr) ? blob->as_nmethod_or_null() : nullptr; if (nm != nullptr) { - // Set flag if return address is a method handle call site. - current->set_is_method_handle_return(nm->is_method_handle_return(return_address)); // native nmethods don't have exception handlers assert(!nm->is_native_method() || nm->method()->is_continuation_enter_intrinsic(), "no exception handler"); assert(nm->header_begin() != nm->exception_begin(), "no exception handler"); diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 5a3850feac8..dee0a5d4eb7 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -536,7 +536,6 @@ nonstatic_field(nmethod, _state, volatile signed char) \ nonstatic_field(nmethod, _exception_offset, int) \ nonstatic_field(nmethod, _deopt_handler_offset, int) \ - nonstatic_field(nmethod, _deopt_mh_handler_offset, int) \ nonstatic_field(nmethod, _orig_pc_offset, int) \ nonstatic_field(nmethod, _stub_offset, int) \ nonstatic_field(nmethod, _scopes_pcs_offset, int) \ @@ -608,7 +607,6 @@ volatile_nonstatic_field(JavaThread, _suspend_flags, uint32_t) \ volatile_nonstatic_field(JavaThread, _exception_oop, oop) \ volatile_nonstatic_field(JavaThread, _exception_pc, address) \ - volatile_nonstatic_field(JavaThread, _is_method_handle_return, int) \ nonstatic_field(JavaThread, _saved_exception_pc, address) \ volatile_nonstatic_field(JavaThread, _thread_state, JavaThreadState) \ nonstatic_field(JavaThread, _stack_base, address) \ @@ -1711,7 +1709,6 @@ /**********************/ \ \ declare_constant(PcDesc::PCDESC_reexecute) \ - declare_constant(PcDesc::PCDESC_is_method_handle_invoke) \ declare_constant(PcDesc::PCDESC_return_oop) \ \ /**********************/ \ diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java index a3228765e91..c8ba2e8b5af 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java @@ -48,7 +48,6 @@ public class NMethod extends CodeBlob { /** Offsets for different nmethod parts */ private static CIntegerField exceptionOffsetField; private static CIntegerField deoptHandlerOffsetField; - private static CIntegerField deoptMhHandlerOffsetField; private static CIntegerField origPCOffsetField; private static CIntegerField stubOffsetField; private static CIntField handlerTableOffsetField; @@ -86,7 +85,6 @@ public class NMethod extends CodeBlob { immutableDataSizeField = type.getCIntegerField("_immutable_data_size"); exceptionOffsetField = type.getCIntegerField("_exception_offset"); deoptHandlerOffsetField = type.getCIntegerField("_deopt_handler_offset"); - deoptMhHandlerOffsetField = type.getCIntegerField("_deopt_mh_handler_offset"); origPCOffsetField = type.getCIntegerField("_orig_pc_offset"); stubOffsetField = type.getCIntegerField("_stub_offset"); scopesPCsOffsetField = type.getCIntegerField("_scopes_pcs_offset"); @@ -125,7 +123,6 @@ public class NMethod extends CodeBlob { public Address instsEnd() { return headerBegin().addOffsetTo(getStubOffset()); } public Address exceptionBegin() { return headerBegin().addOffsetTo(getExceptionOffset()); } public Address deoptHandlerBegin() { return headerBegin().addOffsetTo(getDeoptHandlerOffset()); } - public Address deoptMhHandlerBegin() { return headerBegin().addOffsetTo(getDeoptMhHandlerOffset()); } public Address stubBegin() { return headerBegin().addOffsetTo(getStubOffset()); } public Address stubEnd() { return dataBegin(); } public Address oopsBegin() { return dataBegin(); } @@ -250,22 +247,10 @@ public class NMethod extends CodeBlob { return VMObjectFactory.newObject(NMethod.class, osrLinkField.getValue(addr)); } - // MethodHandle - public boolean isMethodHandleReturn(Address returnPc) { - // Hard to read a bit fields from Java and it's only there for performance - // so just go directly to the PCDesc - // if (!hasMethodHandleInvokes()) return false; - PCDesc pd = getPCDescAt(returnPc); - if (pd == null) - return false; - return pd.isMethodHandleInvoke(); - } - // Deopt // Return true is the PC is one would expect if the frame is being deopted. - public boolean isDeoptPc (Address pc) { return isDeoptEntry(pc) || isDeoptMhEntry(pc); } + public boolean isDeoptPc (Address pc) { return isDeoptEntry(pc); } public boolean isDeoptEntry (Address pc) { return pc == deoptHandlerBegin(); } - public boolean isDeoptMhEntry (Address pc) { return pc == deoptMhHandlerBegin(); } /** Tells whether frames described by this nmethod can be deoptimized. Note: native wrappers cannot be deoptimized. */ @@ -494,7 +479,6 @@ public class NMethod extends CodeBlob { private int getEntryBCI() { return (int) entryBCIField .getValue(addr); } private int getExceptionOffset() { return (int) exceptionOffsetField .getValue(addr); } private int getDeoptHandlerOffset() { return (int) deoptHandlerOffsetField .getValue(addr); } - private int getDeoptMhHandlerOffset() { return (int) deoptMhHandlerOffsetField.getValue(addr); } private int getStubOffset() { return (int) stubOffsetField .getValue(addr); } private int getScopesDataOffset() { return (int) scopesDataOffsetField .getValue(addr); } private int getScopesPCsOffset() { return (int) scopesPCsOffsetField .getValue(addr); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/PCDesc.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/PCDesc.java index 58f358c01aa..037c26b53f5 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/PCDesc.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/PCDesc.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,6 @@ public class PCDesc extends VMObject { private static CIntegerField objDecodeOffsetField; private static CIntegerField pcFlagsField; private static int reexecuteMask; - private static int isMethodHandleInvokeMask; private static int returnOopMask; static { @@ -61,7 +60,6 @@ public class PCDesc extends VMObject { pcFlagsField = type.getCIntegerField("_flags"); reexecuteMask = db.lookupIntConstant("PcDesc::PCDESC_reexecute"); - isMethodHandleInvokeMask = db.lookupIntConstant("PcDesc::PCDESC_is_method_handle_invoke"); returnOopMask = db.lookupIntConstant("PcDesc::PCDESC_return_oop"); } @@ -93,11 +91,6 @@ public class PCDesc extends VMObject { return (flags & reexecuteMask) != 0; } - public boolean isMethodHandleInvoke() { - int flags = (int)pcFlagsField.getValue(addr); - return (flags & isMethodHandleInvokeMask) != 0; - } - public void print(NMethod code) { printOn(System.out, code); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Frame.java index a8c17a9f59e..27efb631f79 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Frame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Frame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,6 +81,24 @@ public abstract class Frame implements Cloneable { return pcReturnOffset; } + protected void adjustForDeopt() { + if (pc != null) { + // Look for a deopt pc and if it is deopted convert to original pc + CodeBlob cb = VM.getVM().getCodeCache().findBlob(pc); + if (cb != null && cb.isJavaMethod()) { + NMethod nm = (NMethod) cb; + if (pc.equals(nm.deoptHandlerBegin())) { + if (Assert.ASSERTS_ENABLED) { + Assert.that(this.getUnextendedSP() != null, "null SP in Java frame"); + } + // adjust pc if frame is deoptimized. + pc = this.getUnextendedSP().getAddressAt(nm.origPCOffset()); + deoptimized = true; + } + } + } + } + private static synchronized void initialize(TypeDataBase db) { Type ConstMethodType = db.lookupType("ConstMethod"); // FIXME: not sure whether alignment here is correct or how to diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java index dca5f2efa3b..a5aa7ce4405 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2019, Red Hat Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -106,30 +106,11 @@ public class AARCH64Frame extends Frame { private AARCH64Frame() { } - private void adjustForDeopt() { - if ( pc != null) { - // Look for a deopt pc and if it is deopted convert to original pc - CodeBlob cb = VM.getVM().getCodeCache().findBlob(pc); - if (cb != null && cb.isJavaMethod()) { - NMethod nm = (NMethod) cb; - if (pc.equals(nm.deoptHandlerBegin())) { - if (Assert.ASSERTS_ENABLED) { - Assert.that(this.getUnextendedSP() != null, "null SP in Java frame"); - } - // adjust pc if frame is deoptimized. - pc = this.getUnextendedSP().getAddressAt(nm.origPCOffset()); - deoptimized = true; - } - } - } - } - public AARCH64Frame(Address raw_sp, Address raw_fp, Address pc) { this.raw_sp = raw_sp; this.raw_unextendedSP = raw_sp; this.raw_fp = raw_fp; this.pc = pc; - adjustUnextendedSP(); // Frame must be fully constructed before this call adjustForDeopt(); @@ -153,8 +134,6 @@ public class AARCH64Frame extends Frame { this.pc = savedPC; } - adjustUnextendedSP(); - // Frame must be fully constructed before this call adjustForDeopt(); @@ -169,7 +148,6 @@ public class AARCH64Frame extends Frame { this.raw_unextendedSP = raw_unextendedSp; this.raw_fp = raw_fp; this.pc = pc; - adjustUnextendedSP(); // Frame must be fully constructed before this call adjustForDeopt(); @@ -355,24 +333,6 @@ public class AARCH64Frame extends Frame { return fr; } - //------------------------------------------------------------------------------ - // frame::adjust_unextended_sp - private void adjustUnextendedSP() { - // Sites calling method handle intrinsics and lambda forms are - // treated as any other call site. Therefore, no special action is - // needed when we are returning to any of these call sites. - - CodeBlob cb = cb(); - NMethod senderNm = (cb == null) ? null : cb.asNMethodOrNull(); - if (senderNm != null) { - // If the sender PC is a deoptimization point, get the original PC. - if (senderNm.isDeoptEntry(getPC()) || - senderNm.isDeoptMhEntry(getPC())) { - // DEBUG_ONLY(verifyDeoptriginalPc(senderNm, raw_unextendedSp)); - } - } - } - private Frame senderForInterpreterFrame(AARCH64RegisterMap map) { if (DEBUG) { System.out.println("senderForInterpreterFrame"); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java index a47a632c286..f4ce5337e2f 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -85,24 +85,6 @@ public class PPC64Frame extends Frame { private PPC64Frame() { } - private void adjustForDeopt() { - if ( pc != null) { - // Look for a deopt pc and if it is deopted convert to original pc - CodeBlob cb = VM.getVM().getCodeCache().findBlob(pc); - if (cb != null && cb.isJavaMethod()) { - NMethod nm = (NMethod) cb; - if (pc.equals(nm.deoptHandlerBegin())) { - if (Assert.ASSERTS_ENABLED) { - Assert.that(this.getUnextendedSP() != null, "null SP in Java frame"); - } - // adjust pc if frame is deoptimized. - pc = this.getUnextendedSP().getAddressAt(nm.origPCOffset()); - deoptimized = true; - } - } - } - } - public PPC64Frame(Address raw_sp, Address raw_fp, Address pc) { this.raw_sp = raw_sp; this.raw_unextendedSP = raw_sp; @@ -116,7 +98,6 @@ public class PPC64Frame extends Frame { } else { this.pc = pc; } - adjustUnextendedSP(); // Frame must be fully constructed before this call adjustForDeopt(); @@ -136,7 +117,6 @@ public class PPC64Frame extends Frame { this.raw_fp = raw_fp; } this.pc = raw_sp.getAddressAt(2 * VM.getVM().getAddressSize()); - adjustUnextendedSP(); // Frame must be fully constructed before this call adjustForDeopt(); @@ -160,7 +140,6 @@ public class PPC64Frame extends Frame { } else { this.pc = pc; } - adjustUnextendedSP(); // Frame must be fully constructed before this call adjustForDeopt(); @@ -342,12 +321,6 @@ public class PPC64Frame extends Frame { return fr; } - //------------------------------------------------------------------------------ - // frame::adjust_unextended_sp - private void adjustUnextendedSP() { - // Nothing to do. senderForInterpreterFrame finds the correct unextendedSP. - } - private Frame senderForInterpreterFrame(PPC64RegisterMap map) { if (DEBUG) { System.out.println("senderForInterpreterFrame"); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64Frame.java index 948a3008016..e02e056f028 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64Frame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64Frame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2019, Red Hat Inc. * Copyright (c) 2021, 2023, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -101,30 +101,11 @@ public class RISCV64Frame extends Frame { private RISCV64Frame() { } - private void adjustForDeopt() { - if ( pc != null) { - // Look for a deopt pc and if it is deopted convert to original pc - CodeBlob cb = VM.getVM().getCodeCache().findBlob(pc); - if (cb != null && cb.isJavaMethod()) { - NMethod nm = (NMethod) cb; - if (pc.equals(nm.deoptHandlerBegin())) { - if (Assert.ASSERTS_ENABLED) { - Assert.that(this.getUnextendedSP() != null, "null SP in Java frame"); - } - // adjust pc if frame is deoptimized. - pc = this.getUnextendedSP().getAddressAt(nm.origPCOffset()); - deoptimized = true; - } - } - } - } - public RISCV64Frame(Address raw_sp, Address raw_fp, Address pc) { this.raw_sp = raw_sp; this.raw_unextendedSP = raw_sp; this.raw_fp = raw_fp; this.pc = pc; - adjustUnextendedSP(); // Frame must be fully constructed before this call adjustForDeopt(); @@ -148,8 +129,6 @@ public class RISCV64Frame extends Frame { this.pc = savedPC; } - adjustUnextendedSP(); - // Frame must be fully constructed before this call adjustForDeopt(); @@ -164,7 +143,6 @@ public class RISCV64Frame extends Frame { this.raw_unextendedSP = raw_unextendedSp; this.raw_fp = raw_fp; this.pc = pc; - adjustUnextendedSP(); // Frame must be fully constructed before this call adjustForDeopt(); @@ -347,24 +325,6 @@ public class RISCV64Frame extends Frame { return fr; } - //------------------------------------------------------------------------------ - // frame::adjust_unextended_sp - private void adjustUnextendedSP() { - // Sites calling method handle intrinsics and lambda forms are - // treated as any other call site. Therefore, no special action is - // needed when we are returning to any of these call sites. - - CodeBlob cb = cb(); - NMethod senderNm = (cb == null) ? null : cb.asNMethodOrNull(); - if (senderNm != null) { - // If the sender PC is a deoptimization point, get the original PC. - if (senderNm.isDeoptEntry(getPC()) || - senderNm.isDeoptMhEntry(getPC())) { - // DEBUG_ONLY(verifyDeoptriginalPc(senderNm, raw_unextendedSp)); - } - } - } - private Frame senderForInterpreterFrame(RISCV64RegisterMap map) { if (DEBUG) { System.out.println("senderForInterpreterFrame"); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java index 169ecea1565..3ee4f0a8158 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -102,24 +102,6 @@ public class X86Frame extends Frame { private X86Frame() { } - private void adjustForDeopt() { - if ( pc != null) { - // Look for a deopt pc and if it is deopted convert to original pc - CodeBlob cb = VM.getVM().getCodeCache().findBlob(pc); - if (cb != null && cb.isJavaMethod()) { - NMethod nm = (NMethod) cb; - if (pc.equals(nm.deoptHandlerBegin())) { - if (Assert.ASSERTS_ENABLED) { - Assert.that(this.getUnextendedSP() != null, "null SP in Java frame"); - } - // adjust pc if frame is deoptimized. - pc = this.getUnextendedSP().getAddressAt(nm.origPCOffset()); - deoptimized = true; - } - } - } - } - private void initFrame(Address raw_sp, Address raw_fp, Address pc, Address raw_unextendedSp, Address live_bcp) { this.raw_sp = raw_sp; this.raw_fp = raw_fp; @@ -134,11 +116,10 @@ public class X86Frame extends Frame { this.pc = pc; } this.live_bcp = live_bcp; - adjustUnextendedSP(); // Frame must be fully constructed before this call adjustForDeopt(); -} + } public X86Frame(Address raw_sp, Address raw_fp, Address pc) { @@ -352,24 +333,6 @@ public class X86Frame extends Frame { return fr; } - //------------------------------------------------------------------------------ - // frame::adjust_unextended_sp - private void adjustUnextendedSP() { - // On x86, sites calling method handle intrinsics and lambda forms are treated - // as any other call site. Therefore, no special action is needed when we are - // returning to any of these call sites. - - CodeBlob cb = cb(); - NMethod senderNm = (cb == null) ? null : cb.asNMethodOrNull(); - if (senderNm != null) { - // If the sender PC is a deoptimization point, get the original PC. - if (senderNm.isDeoptEntry(getPC()) || - senderNm.isDeoptMhEntry(getPC())) { - // DEBUG_ONLY(verifyDeoptriginalPc(senderNm, raw_unextendedSp)); - } - } - } - private Frame senderForInterpreterFrame(X86RegisterMap map) { if (DEBUG) { System.out.println("senderForInterpreterFrame"); From 854b384b120fa2af41adca3048070866fe3cafd4 Mon Sep 17 00:00:00 2001 From: Alex Menkov Date: Thu, 2 Oct 2025 23:39:37 +0000 Subject: [PATCH 005/160] 8304811: vmTestbase/vm/mlvm/indy/func/jvmti/stepBreakPopReturn/INDIFY_Test.java fails with JVMTI_ERROR_TYPE_MISMATCH Reviewed-by: lmesnik, dholmes, sspitsyn --- .../func/jvmti/stepBreakPopReturn/stepBreakPopReturn.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/vm/mlvm/indy/func/jvmti/stepBreakPopReturn/stepBreakPopReturn.cpp b/test/hotspot/jtreg/vmTestbase/vm/mlvm/indy/func/jvmti/stepBreakPopReturn/stepBreakPopReturn.cpp index 413450892a5..0f7d1826937 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/mlvm/indy/func/jvmti/stepBreakPopReturn/stepBreakPopReturn.cpp +++ b/test/hotspot/jtreg/vmTestbase/vm/mlvm/indy/func/jvmti/stepBreakPopReturn/stepBreakPopReturn.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -89,7 +89,7 @@ MethodEntry(jvmtiEnv *jvmti_env, gIsMethodEntryWorking = JNI_TRUE; if (!gIsBreakpointSet) - NSK_JVMTI_VERIFY(jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_SINGLE_STEP, nullptr)); + NSK_JVMTI_VERIFY(jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_SINGLE_STEP, thread)); } } @@ -116,7 +116,7 @@ SingleStep(jvmtiEnv *jvmti_env, free(locStr); } - NSK_JVMTI_VERIFY(gJvmtiEnv->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_SINGLE_STEP, nullptr)); + NSK_JVMTI_VERIFY(gJvmtiEnv->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_SINGLE_STEP, thread)); if (!gIsDebuggerCompatible) { if (!NSK_JVMTI_VERIFY(jvmti_env->SetBreakpoint(method, location))) From f62b9eca08694bbbe80d9e7d7b704db4f2423830 Mon Sep 17 00:00:00 2001 From: Ashutosh Mehra Date: Fri, 3 Oct 2025 02:43:14 +0000 Subject: [PATCH 006/160] 8364929: Assign unique id to each AdapterBlob stored in AOTCodeCache Reviewed-by: kvn, iklam --- src/hotspot/share/runtime/sharedRuntime.cpp | 35 ++++++++++++++------- src/hotspot/share/runtime/sharedRuntime.hpp | 14 ++++++--- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index c81c975372c..cf949fe1e7c 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -2515,6 +2515,7 @@ ArchivedAdapterTable AdapterHandlerLibrary::_aot_adapter_handler_table; #endif // INCLUDE_CDS static const int AdapterHandlerLibrary_size = 16*K; BufferBlob* AdapterHandlerLibrary::_buffer = nullptr; +volatile uint AdapterHandlerLibrary::_id_counter = 0; BufferBlob* AdapterHandlerLibrary::buffer_blob() { assert(_buffer != nullptr, "should be initialized"); @@ -2595,7 +2596,9 @@ void AdapterHandlerLibrary::initialize() { } AdapterHandlerEntry* AdapterHandlerLibrary::new_entry(AdapterFingerPrint* fingerprint) { - return AdapterHandlerEntry::allocate(fingerprint); + uint id = (uint)AtomicAccess::add((int*)&_id_counter, 1); + assert(id > 0, "we can never overflow because AOT cache cannot contain more than 2^32 methods"); + return AdapterHandlerEntry::allocate(id, fingerprint); } AdapterHandlerEntry* AdapterHandlerLibrary::get_simple_adapter(const methodHandle& method) { @@ -2749,8 +2752,8 @@ AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(const methodHandle& meth void AdapterHandlerLibrary::lookup_aot_cache(AdapterHandlerEntry* handler) { ResourceMark rm; - const char* name = AdapterHandlerLibrary::name(handler->fingerprint()); - const uint32_t id = AdapterHandlerLibrary::id(handler->fingerprint()); + const char* name = AdapterHandlerLibrary::name(handler); + const uint32_t id = AdapterHandlerLibrary::id(handler); CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::Adapter, id, name); if (blob != nullptr) { @@ -2845,8 +2848,8 @@ bool AdapterHandlerLibrary::generate_adapter_code(AdapterHandlerEntry* handler, handler->set_adapter_blob(adapter_blob); if (!is_transient && AOTCodeCache::is_dumping_adapter()) { // try to save generated code - const char* name = AdapterHandlerLibrary::name(handler->fingerprint()); - const uint32_t id = AdapterHandlerLibrary::id(handler->fingerprint()); + const char* name = AdapterHandlerLibrary::name(handler); + const uint32_t id = AdapterHandlerLibrary::id(handler); bool success = AOTCodeCache::store_code_blob(*adapter_blob, AOTCodeEntry::Adapter, id, name); assert(success || !AOTCodeCache::is_dumping_adapter(), "caching of adapter must be disabled"); } @@ -2986,11 +2989,22 @@ void AdapterHandlerEntry::link() { } void AdapterHandlerLibrary::link_aot_adapters() { + uint max_id = 0; assert(AOTCodeCache::is_using_adapter(), "AOT adapters code should be available"); - _aot_adapter_handler_table.iterate([](AdapterHandlerEntry* entry) { + /* It is possible that some adapters generated in assembly phase are not stored in the cache. + * That implies adapter ids of the adapters in the cache may not be contiguous. + * If the size of the _aot_adapter_handler_table is used to initialize _id_counter, then it may + * result in collision of adapter ids between AOT stored handlers and runtime generated handlers. + * To avoid such situation, initialize the _id_counter with the largest adapter id among the AOT stored handlers. + */ + _aot_adapter_handler_table.iterate([&](AdapterHandlerEntry* entry) { assert(!entry->is_linked(), "AdapterHandlerEntry is already linked!"); entry->link(); + max_id = MAX2(max_id, entry->id()); }); + // Set adapter id to the maximum id found in the AOTCache + assert(_id_counter == 0, "Did not expect new AdapterHandlerEntry to be created at this stage"); + _id_counter = max_id; } // This method is called during production run to lookup simple adapters @@ -3355,13 +3369,12 @@ bool AdapterHandlerLibrary::contains(const CodeBlob* b) { return found; } -const char* AdapterHandlerLibrary::name(AdapterFingerPrint* fingerprint) { - return fingerprint->as_basic_args_string(); +const char* AdapterHandlerLibrary::name(AdapterHandlerEntry* handler) { + return handler->fingerprint()->as_basic_args_string(); } -uint32_t AdapterHandlerLibrary::id(AdapterFingerPrint* fingerprint) { - unsigned int hash = fingerprint->compute_hash(); - return hash; +uint32_t AdapterHandlerLibrary::id(AdapterHandlerEntry* handler) { + return handler->id(); } void AdapterHandlerLibrary::print_handler_on(outputStream* st, const CodeBlob* b) { diff --git a/src/hotspot/share/runtime/sharedRuntime.hpp b/src/hotspot/share/runtime/sharedRuntime.hpp index 374985ad921..6544e380d99 100644 --- a/src/hotspot/share/runtime/sharedRuntime.hpp +++ b/src/hotspot/share/runtime/sharedRuntime.hpp @@ -686,6 +686,7 @@ class AdapterHandlerEntry : public MetaspaceObj { private: AdapterFingerPrint* _fingerprint; AdapterBlob* _adapter_blob; + uint _id; bool _linked; static const char *_entry_names[]; @@ -697,9 +698,10 @@ class AdapterHandlerEntry : public MetaspaceObj { int _saved_code_length; #endif - AdapterHandlerEntry(AdapterFingerPrint* fingerprint) : + AdapterHandlerEntry(int id, AdapterFingerPrint* fingerprint) : _fingerprint(fingerprint), _adapter_blob(nullptr), + _id(id), _linked(false) #ifdef ASSERT , _saved_code(nullptr), @@ -720,8 +722,8 @@ class AdapterHandlerEntry : public MetaspaceObj { } public: - static AdapterHandlerEntry* allocate(AdapterFingerPrint* fingerprint) { - return new(0) AdapterHandlerEntry(fingerprint); + static AdapterHandlerEntry* allocate(uint id, AdapterFingerPrint* fingerprint) { + return new(0) AdapterHandlerEntry(id, fingerprint); } static void deallocate(AdapterHandlerEntry *handler) { @@ -772,6 +774,7 @@ class AdapterHandlerEntry : public MetaspaceObj { AdapterBlob* adapter_blob() const { return _adapter_blob; } bool is_linked() const { return _linked; } + uint id() const { return _id; } AdapterFingerPrint* fingerprint() const { return _fingerprint; } #ifdef ASSERT @@ -798,6 +801,7 @@ class ArchivedAdapterTable; class AdapterHandlerLibrary: public AllStatic { friend class SharedRuntime; private: + static volatile uint _id_counter; // counter for generating unique adapter ids, range = [1,UINT_MAX] static BufferBlob* _buffer; // the temporary code buffer in CodeCache static AdapterHandlerEntry* _no_arg_handler; static AdapterHandlerEntry* _int_arg_handler; @@ -837,8 +841,8 @@ class AdapterHandlerLibrary: public AllStatic { static void print_handler(const CodeBlob* b) { print_handler_on(tty, b); } static void print_handler_on(outputStream* st, const CodeBlob* b); static bool contains(const CodeBlob* b); - static const char* name(AdapterFingerPrint* fingerprint); - static uint32_t id(AdapterFingerPrint* fingerprint); + static const char* name(AdapterHandlerEntry* handler); + static uint32_t id(AdapterHandlerEntry* handler); #ifndef PRODUCT static void print_statistics(); #endif // PRODUCT From 3790965df3e7cba3b9792b8719d1e2ead046da15 Mon Sep 17 00:00:00 2001 From: Joe Wang Date: Fri, 3 Oct 2025 03:50:01 +0000 Subject: [PATCH 007/160] 8336695: Update Commons BCEL to Version 6.10.0 Reviewed-by: lancea, naoto, iris --- .../sun/org/apache/bcel/internal/Const.java | 828 ++++++++++-------- .../apache/bcel/internal/ExceptionConst.java | 7 +- .../org/apache/bcel/internal/Repository.java | 6 +- .../bcel/internal/classfile/AccessFlags.java | 232 ++++- .../internal/classfile/AnnotationEntry.java | 15 +- .../bcel/internal/classfile/Annotations.java | 10 +- .../internal/classfile/ArrayElementValue.java | 4 +- .../bcel/internal/classfile/Attribute.java | 8 +- .../internal/classfile/BootstrapMethod.java | 15 +- .../internal/classfile/BootstrapMethods.java | 6 +- .../classfile/ClassFormatException.java | 10 +- .../bcel/internal/classfile/ClassParser.java | 12 +- .../apache/bcel/internal/classfile/Code.java | 45 +- .../internal/classfile/CodeException.java | 8 +- .../bcel/internal/classfile/Constant.java | 31 +- .../bcel/internal/classfile/ConstantCP.java | 12 +- .../internal/classfile/ConstantDouble.java | 6 +- .../internal/classfile/ConstantFloat.java | 6 +- .../internal/classfile/ConstantInteger.java | 6 +- .../bcel/internal/classfile/ConstantLong.java | 6 +- .../internal/classfile/ConstantObject.java | 7 +- .../bcel/internal/classfile/ConstantPool.java | 29 +- .../bcel/internal/classfile/ConstantUtf8.java | 23 +- .../internal/classfile/ConstantValue.java | 2 +- .../bcel/internal/classfile/Deprecated.java | 2 +- .../internal/classfile/DescendingVisitor.java | 41 +- .../bcel/internal/classfile/ElementValue.java | 7 +- .../bcel/internal/classfile/EmptyVisitor.java | 9 + .../internal/classfile/ExceptionTable.java | 11 +- .../apache/bcel/internal/classfile/Field.java | 38 +- .../internal/classfile/FieldOrMethod.java | 38 +- .../bcel/internal/classfile/InnerClass.java | 2 +- .../bcel/internal/classfile/InnerClasses.java | 8 +- .../InvalidMethodSignatureException.java | 53 ++ .../bcel/internal/classfile/JavaClass.java | 152 +++- .../bcel/internal/classfile/LineNumber.java | 4 +- .../internal/classfile/LineNumberTable.java | 23 +- .../classfile/LocalVariableTable.java | 10 +- .../classfile/LocalVariableTypeTable.java | 11 +- .../bcel/internal/classfile/Method.java | 49 +- .../internal/classfile/MethodParameter.java | 12 +- .../internal/classfile/MethodParameters.java | 8 +- .../bcel/internal/classfile/Module.java | 66 +- .../internal/classfile/ModuleExports.java | 49 +- .../internal/classfile/ModuleMainClass.java | 2 +- .../bcel/internal/classfile/ModuleOpens.java | 49 +- .../internal/classfile/ModulePackages.java | 11 +- .../internal/classfile/ModuleProvides.java | 45 +- .../internal/classfile/ModuleRequires.java | 39 +- .../bcel/internal/classfile/NestMembers.java | 11 +- .../apache/bcel/internal/classfile/Node.java | 2 +- .../bcel/internal/classfile/PMGClass.java | 2 +- .../classfile/ParameterAnnotationEntry.java | 18 +- .../classfile/ParameterAnnotations.java | 8 +- .../bcel/internal/classfile/Record.java | 153 ++++ .../classfile/RecordComponentInfo.java | 139 +++ .../RuntimeInvisibleAnnotations.java | 8 +- .../RuntimeInvisibleParameterAnnotations.java | 2 + .../classfile/RuntimeVisibleAnnotations.java | 8 +- .../RuntimeVisibleParameterAnnotations.java | 2 + .../bcel/internal/classfile/Signature.java | 10 +- .../classfile/SimpleElementValue.java | 20 +- .../bcel/internal/classfile/SourceFile.java | 2 +- .../bcel/internal/classfile/StackMap.java | 10 +- .../internal/classfile/StackMapEntry.java | 13 +- .../bcel/internal/classfile/StackMapType.java | 29 +- .../bcel/internal/classfile/Synthetic.java | 2 +- .../bcel/internal/classfile/Utility.java | 60 +- .../bcel/internal/classfile/Visitor.java | 32 + .../bcel/internal/classfile/package-info.java | 25 + .../bcel/internal/generic/ARRAYLENGTH.java | 6 +- .../apache/bcel/internal/generic/ATHROW.java | 7 +- .../internal/generic/AnnotationEntryGen.java | 22 +- .../generic/ArrayElementValueGen.java | 15 +- .../bcel/internal/generic/ArrayType.java | 10 +- .../bcel/internal/generic/BranchHandle.java | 2 +- .../bcel/internal/generic/CPInstruction.java | 6 +- .../generic/ClassElementValueGen.java | 8 +- .../bcel/internal/generic/ClassGen.java | 82 +- .../internal/generic/CodeExceptionGen.java | 10 +- .../internal/generic/ElementValuePairGen.java | 4 +- .../internal/generic/EnumElementValueGen.java | 26 +- .../internal/generic/ExceptionThrower.java | 2 +- .../bcel/internal/generic/FieldGen.java | 42 +- .../internal/generic/FieldGenOrMethodGen.java | 12 +- .../bcel/internal/generic/FieldOrMethod.java | 4 +- .../apache/bcel/internal/generic/ICONST.java | 1 - .../bcel/internal/generic/INVOKEDYNAMIC.java | 8 +- .../bcel/internal/generic/Instruction.java | 6 +- .../internal/generic/InstructionConst.java | 2 +- .../internal/generic/InstructionFactory.java | 28 +- .../internal/generic/InstructionHandle.java | 15 +- .../internal/generic/InstructionList.java | 69 +- .../internal/generic/InstructionTargeter.java | 9 +- .../apache/bcel/internal/generic/LCMP.java | 1 - .../org/apache/bcel/internal/generic/LDC.java | 9 +- .../bcel/internal/generic/LineNumberGen.java | 4 +- .../internal/generic/LocalVariableGen.java | 2 +- .../generic/LocalVariableInstruction.java | 6 +- .../bcel/internal/generic/MethodGen.java | 53 +- .../bcel/internal/generic/ObjectType.java | 6 +- .../org/apache/bcel/internal/generic/RET.java | 2 +- .../bcel/internal/generic/ReferenceType.java | 62 +- .../apache/bcel/internal/generic/SWITCH.java | 2 +- .../apache/bcel/internal/generic/Select.java | 14 +- .../generic/SimpleElementValueGen.java | 6 +- .../internal/generic/TargetLostException.java | 28 +- .../apache/bcel/internal/generic/Type.java | 70 +- .../internal/generic/TypedInstruction.java | 2 +- .../bcel/internal/generic/package-info.java | 26 + .../apache/bcel/internal/package-info.java | 26 + .../bcel/internal/util/BCELComparator.java | 23 +- .../bcel/internal/util/BCELFactory.java | 8 +- .../apache/bcel/internal/util/BCELifier.java | 91 +- .../apache/bcel/internal/util/Class2HTML.java | 10 +- .../apache/bcel/internal/util/ClassSet.java | 4 +- .../apache/bcel/internal/util/CodeHTML.java | 2 +- .../bcel/internal/util/InstructionFinder.java | 7 +- .../apache/bcel/internal/util/Repository.java | 6 +- .../bcel/internal/util/package-info.java | 32 + .../share/classes/jdk/xml/internal/Utils.java | 60 +- src/java.xml/share/legal/bcel.md | 2 +- 122 files changed, 2461 insertions(+), 1128 deletions(-) create mode 100644 src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/InvalidMethodSignatureException.java create mode 100644 src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Record.java create mode 100644 src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RecordComponentInfo.java create mode 100644 src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/package-info.java create mode 100644 src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/package-info.java create mode 100644 src/java.xml/share/classes/com/sun/org/apache/bcel/internal/package-info.java create mode 100644 src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/package-info.java diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/Const.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/Const.java index bca72ab3f95..c6b97db142e 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/Const.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/Const.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -26,12 +26,12 @@ import java.util.Collections; * Constants for the project, mostly defined in the JVM specification. * * @since 6.0 (intended to replace the Constants interface) - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public final class Const { /** - * Java class file format Magic number (0xCAFEBABE) + * Java class file format Magic number: {@value}. * * @see The ClassFile Structure * in The Java Virtual Machine Specification @@ -39,201 +39,201 @@ public final class Const { public static final int JVM_CLASSFILE_MAGIC = 0xCAFEBABE; /** - * Major version number of class files for Java 1.1. + * Major version number of class files for Java 1.1: {@value}. * * @see #MINOR_1_1 */ public static final short MAJOR_1_1 = 45; /** - * Minor version number of class files for Java 1.1. + * Minor version number of class files for Java 1.1: {@value}. * * @see #MAJOR_1_1 */ public static final short MINOR_1_1 = 3; /** - * Major version number of class files for Java 1.2. + * Major version number of class files for Java 1.2: {@value}. * * @see #MINOR_1_2 */ public static final short MAJOR_1_2 = 46; /** - * Minor version number of class files for Java 1.2. + * Minor version number of class files for Java 1.2: {@value}. * * @see #MAJOR_1_2 */ public static final short MINOR_1_2 = 0; /** - * Major version number of class files for Java 1.2. + * Major version number of class files for Java 1.2: {@value}. * * @see #MINOR_1_2 */ public static final short MAJOR_1_3 = 47; /** - * Minor version number of class files for Java 1.3. + * Minor version number of class files for Java 1.3: {@value}. * * @see #MAJOR_1_3 */ public static final short MINOR_1_3 = 0; /** - * Major version number of class files for Java 1.3. + * Major version number of class files for Java 1.3: {@value}. * * @see #MINOR_1_3 */ public static final short MAJOR_1_4 = 48; /** - * Minor version number of class files for Java 1.4. + * Minor version number of class files for Java 1.4: {@value}. * * @see #MAJOR_1_4 */ public static final short MINOR_1_4 = 0; /** - * Major version number of class files for Java 1.4. + * Major version number of class files for Java 1.4: {@value}. * * @see #MINOR_1_4 */ public static final short MAJOR_1_5 = 49; /** - * Minor version number of class files for Java 1.5. + * Minor version number of class files for Java 1.5: {@value}. * * @see #MAJOR_1_5 */ public static final short MINOR_1_5 = 0; /** - * Major version number of class files for Java 1.6. + * Major version number of class files for Java 1.6: {@value}. * * @see #MINOR_1_6 */ public static final short MAJOR_1_6 = 50; /** - * Minor version number of class files for Java 1.6. + * Minor version number of class files for Java 1.6: {@value}. * * @see #MAJOR_1_6 */ public static final short MINOR_1_6 = 0; /** - * Major version number of class files for Java 1.7. + * Major version number of class files for Java 1.7: {@value}. * * @see #MINOR_1_7 */ public static final short MAJOR_1_7 = 51; /** - * Minor version number of class files for Java 1.7. + * Minor version number of class files for Java 1.7: {@value}. * * @see #MAJOR_1_7 */ public static final short MINOR_1_7 = 0; /** - * Major version number of class files for Java 1.8. + * Major version number of class files for Java 1.8: {@value}. * * @see #MINOR_1_8 */ public static final short MAJOR_1_8 = 52; /** - * Minor version number of class files for Java 1.8. + * Minor version number of class files for Java 1.8: {@value}. * * @see #MAJOR_1_8 */ public static final short MINOR_1_8 = 0; /** - * Major version number of class files for Java 9. + * Major version number of class files for Java 9: {@value}. * * @see #MINOR_9 */ public static final short MAJOR_9 = 53; /** - * Minor version number of class files for Java 9. + * Minor version number of class files for Java 9: {@value}. * * @see #MAJOR_9 */ public static final short MINOR_9 = 0; /** - * @deprecated Use {@link #MAJOR_9} instead + * @deprecated Use {@link #MAJOR_9} ({@value}) instead. */ @Deprecated public static final short MAJOR_1_9 = MAJOR_9; /** - * @deprecated Use {@link #MINOR_9} instead + * @deprecated Use {@link #MINOR_9} ({@value}) instead. */ @Deprecated public static final short MINOR_1_9 = MINOR_9; /** - * Major version number of class files for Java 10. + * Major version number of class files for Java 10: {@value}. * * @see #MINOR_10 */ public static final short MAJOR_10 = 54; /** - * Minor version number of class files for Java 10. + * Minor version number of class files for Java 10: {@value}. * * @see #MAJOR_10 */ public static final short MINOR_10 = 0; /** - * Major version number of class files for Java 11. + * Major version number of class files for Java 11: {@value}. * * @see #MINOR_11 */ public static final short MAJOR_11 = 55; /** - * Minor version number of class files for Java 11. + * Minor version number of class files for Java 11: {@value}. * * @see #MAJOR_11 */ public static final short MINOR_11 = 0; /** - * Major version number of class files for Java 12. + * Major version number of class files for Java 12: {@value}. * * @see #MINOR_12 */ public static final short MAJOR_12 = 56; /** - * Minor version number of class files for Java 12. + * Minor version number of class files for Java 12: {@value}. * * @see #MAJOR_12 */ public static final short MINOR_12 = 0; /** - * Major version number of class files for Java 13. + * Major version number of class files for Java 13: {@value}. * * @see #MINOR_13 */ public static final short MAJOR_13 = 57; /** - * Minor version number of class files for Java 13. + * Minor version number of class files for Java 13: {@value}. * * @see #MAJOR_13 */ public static final short MINOR_13 = 0; /** - * Minor version number of class files for Java 14. + * Minor version number of class files for Java 14: {@value}. * * @see #MAJOR_14 * @since 6.4.0 @@ -241,7 +241,7 @@ public final class Const { public static final short MINOR_14 = 0; /** - * Minor version number of class files for Java 15. + * Minor version number of class files for Java 15: {@value}. * * @see #MAJOR_15 * @since 6.6.0 @@ -249,7 +249,7 @@ public final class Const { public static final short MINOR_15 = 0; /** - * Minor version number of class files for Java 16. + * Minor version number of class files for Java 16: {@value}. * * @see #MAJOR_16 * @since 6.6.0 @@ -257,7 +257,7 @@ public final class Const { public static final short MINOR_16 = 0; /** - * Minor version number of class files for Java 17. + * Minor version number of class files for Java 17: {@value}. * * @see #MAJOR_17 * @since 6.6.0 @@ -265,7 +265,7 @@ public final class Const { public static final short MINOR_17 = 0; /** - * Minor version number of class files for Java 18. + * Minor version number of class files for Java 18: {@value}. * * @see #MAJOR_18 * @since 6.6.0 @@ -273,7 +273,7 @@ public final class Const { public static final short MINOR_18 = 0; /** - * Minor version number of class files for Java 19. + * Minor version number of class files for Java 19: {@value}. * * @see #MAJOR_19 * @since 6.6.0 @@ -281,7 +281,47 @@ public final class Const { public static final short MINOR_19 = 0; /** - * Major version number of class files for Java 14. + * Minor version number of class files for Java 20: {@value}. + * + * @see #MAJOR_20 + * @since 6.8.0 + */ + public static final short MINOR_20 = 0; + + /** + * Minor version number of class files for Java 21: {@value}. + * + * @see #MAJOR_21 + * @since 6.8.0 + */ + public static final short MINOR_21 = 0; + + /** + * Minor version number of class files for Java 22: {@value}. + * + * @see #MAJOR_22 + * @since 6.10.0 + */ + public static final short MINOR_22 = 0; + + /** + * Minor version number of class files for Java 23: {@value}. + * + * @see #MAJOR_23 + * @since 6.10.0 + */ + public static final short MINOR_23 = 0; + + /** + * Minor version number of class files for Java 24: {@value}. + * + * @see #MAJOR_24 + * @since 6.10.0 + */ + public static final short MINOR_24 = 0; + + /** + * Major version number of class files for Java 14: {@value}. * * @see #MINOR_14 * @since 6.4.0 @@ -289,7 +329,7 @@ public final class Const { public static final short MAJOR_14 = 58; /** - * Major version number of class files for Java 15. + * Major version number of class files for Java 15: {@value}. * * @see #MINOR_15 * @since 6.6.0 @@ -297,7 +337,7 @@ public final class Const { public static final short MAJOR_15 = 59; /** - * Major version number of class files for Java 16. + * Major version number of class files for Java 16: {@value}. * * @see #MINOR_16 * @since 6.6.0 @@ -305,7 +345,7 @@ public final class Const { public static final short MAJOR_16 = 60; /** - * Major version number of class files for Java 17. + * Major version number of class files for Java 17: {@value}. * * @see #MINOR_17 * @since 6.6.0 @@ -313,7 +353,7 @@ public final class Const { public static final short MAJOR_17 = 61; /** - * Major version number of class files for Java 18. + * Major version number of class files for Java 18: {@value}. * * @see #MINOR_18 * @since 6.6.0 @@ -321,7 +361,7 @@ public final class Const { public static final short MAJOR_18 = 62; /** - * Major version number of class files for Java 19. + * Major version number of class files for Java 19: {@value}. * * @see #MINOR_19 * @since 6.6.0 @@ -329,31 +369,71 @@ public final class Const { public static final short MAJOR_19 = 63; /** - * Default major version number. Class file is for Java 1.1. + * Major version number of class files for Java 20: {@value}. + * + * @see #MINOR_20 + * @since 6.8.0 + */ + public static final short MAJOR_20 = 64; + + /** + * Major version number of class files for Java 21: {@value}. + * + * @see #MINOR_21 + * @since 6.8.0 + */ + public static final short MAJOR_21 = 65; + + /** + * Major version number of class files for Java 22: {@value}. + * + * @see #MINOR_22 + * @since 6.10.0 + */ + public static final short MAJOR_22 = 66; + + /** + * Major version number of class files for Java 23: {@value}. + * + * @see #MINOR_23 + * @since 6.10.0 + */ + public static final short MAJOR_23 = 67; + + /** + * Major version number of class files for Java 24: {@value}. + * + * @see #MINOR_24 + * @since 6.10.0 + */ + public static final short MAJOR_24 = 68; + + /** + * Default major version number. Class file is for Java 1.1: {@value}. * * @see #MAJOR_1_1 */ public static final short MAJOR = MAJOR_1_1; /** - * Default major version number. Class file is for Java 1.1. + * Default major version number. Class file is for Java 1.1: {@value}. * * @see #MAJOR_1_1 */ public static final short MINOR = MINOR_1_1; /** - * Maximum value for an unsigned short. + * Maximum value for an unsigned short: {@value}. */ public static final int MAX_SHORT = 65535; // 2^16 - 1 /** - * Maximum value for an unsigned byte. + * Maximum value for an unsigned byte: {@value}. */ public static final int MAX_BYTE = 255; // 2^8 - 1 /** - * One of the access flags for fields, methods, or classes. + * One of the access flags for fields, methods, or classes: {@value}. * * @see Flag definitions for * Classes in the Java Virtual Machine Specification (Java SE 9 Edition). @@ -367,140 +447,140 @@ public final class Const { public static final short ACC_PUBLIC = 0x0001; /** - * One of the access flags for fields, methods, or classes. + * One of the access flags for fields, methods, or classes: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_PRIVATE = 0x0002; /** - * One of the access flags for fields, methods, or classes. + * One of the access flags for fields, methods, or classes: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_PROTECTED = 0x0004; /** - * One of the access flags for fields, methods, or classes. + * One of the access flags for fields, methods, or classes: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_STATIC = 0x0008; /** - * One of the access flags for fields, methods, or classes. + * One of the access flags for fields, methods, or classes: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_FINAL = 0x0010; /** - * One of the access flags for the Module attribute. + * One of the access flags for the Module attribute: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_OPEN = 0x0020; /** - * One of the access flags for classes. + * One of the access flags for classes: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_SUPER = 0x0020; /** - * One of the access flags for methods. + * One of the access flags for methods: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_SYNCHRONIZED = 0x0020; /** - * One of the access flags for the Module attribute. + * One of the access flags for the Module attribute: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_TRANSITIVE = 0x0020; /** - * One of the access flags for methods. + * One of the access flags for methods: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_BRIDGE = 0x0040; /** - * One of the access flags for the Module attribute. + * One of the access flags for the Module attribute: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_STATIC_PHASE = 0x0040; /** - * One of the access flags for fields. + * One of the access flags for fields: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_VOLATILE = 0x0040; /** - * One of the access flags for fields. + * One of the access flags for fields: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_TRANSIENT = 0x0080; /** - * One of the access flags for methods. + * One of the access flags for methods: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_VARARGS = 0x0080; /** - * One of the access flags for methods. + * One of the access flags for methods: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_NATIVE = 0x0100; /** - * One of the access flags for classes. + * One of the access flags for classes: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_INTERFACE = 0x0200; /** - * One of the access flags for methods or classes. + * One of the access flags for methods or classes: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_ABSTRACT = 0x0400; /** - * One of the access flags for methods. + * One of the access flags for methods: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_STRICT = 0x0800; /** - * One of the access flags for fields, methods, classes, MethodParameter attribute, or Module attribute. + * One of the access flags for fields, methods, classes, MethodParameter attribute, or Module attribute: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_SYNTHETIC = 0x1000; /** - * One of the access flags for classes. + * One of the access flags for classes: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_ANNOTATION = 0x2000; /** - * One of the access flags for fields or classes. + * One of the access flags for fields or classes: {@value}. * * @see #ACC_PUBLIC */ @@ -508,21 +588,21 @@ public final class Const { // Applies to classes compiled by new compilers only /** - * One of the access flags for MethodParameter or Module attributes. + * One of the access flags for MethodParameter or Module attributes: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_MANDATED = (short) 0x8000; /** - * One of the access flags for classes. + * One of the access flags for classes: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_MODULE = (short) 0x8000; /** - * One of the access flags for fields, methods, or classes. + * One of the access flags for fields, methods, or classes: {@value}. * * @see #ACC_PUBLIC * @deprecated Use {@link #MAX_ACC_FLAG_I} @@ -531,7 +611,7 @@ public final class Const { public static final short MAX_ACC_FLAG = ACC_ENUM; /** - * One of the access flags for fields, methods, or classes. ACC_MODULE is negative as a short. + * One of the access flags for fields, methods, or classes. ACC_MODULE is negative as a short: {@value}. * * @see #ACC_PUBLIC * @since 6.4.0 @@ -553,7 +633,7 @@ public final class Const { public static final int ACCESS_NAMES_LENGTH = ACCESS_NAMES.length; /** - * Marks a constant pool entry as type UTF-8. + * Marks a constant pool entry as type UTF-8: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -566,7 +646,7 @@ public final class Const { */ /** - * Marks a constant pool entry as type Integer. + * Marks a constant pool entry as type Integer: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -574,7 +654,7 @@ public final class Const { public static final byte CONSTANT_Integer = 3; /** - * Marks a constant pool entry as type Float. + * Marks a constant pool entry as type Float: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -582,7 +662,7 @@ public final class Const { public static final byte CONSTANT_Float = 4; /** - * Marks a constant pool entry as type Long. + * Marks a constant pool entry as type Long: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -590,7 +670,7 @@ public final class Const { public static final byte CONSTANT_Long = 5; /** - * Marks a constant pool entry as type Double. + * Marks a constant pool entry as type Double: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -598,7 +678,7 @@ public final class Const { public static final byte CONSTANT_Double = 6; /** - * Marks a constant pool entry as a Class + * Marks a constant pool entry as a Class: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -606,7 +686,7 @@ public final class Const { public static final byte CONSTANT_Class = 7; /** - * Marks a constant pool entry as a Field Reference. + * Marks a constant pool entry as a Field Reference: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -614,7 +694,7 @@ public final class Const { public static final byte CONSTANT_Fieldref = 9; /** - * Marks a constant pool entry as type String + * Marks a constant pool entry as type String: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -622,7 +702,7 @@ public final class Const { public static final byte CONSTANT_String = 8; /** - * Marks a constant pool entry as a Method Reference. + * Marks a constant pool entry as a Method Reference: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -630,7 +710,7 @@ public final class Const { public static final byte CONSTANT_Methodref = 10; /** - * Marks a constant pool entry as an Interface Method Reference. + * Marks a constant pool entry as an Interface Method Reference: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -638,7 +718,7 @@ public final class Const { public static final byte CONSTANT_InterfaceMethodref = 11; /** - * Marks a constant pool entry as a name and type. + * Marks a constant pool entry as a name and type: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -646,7 +726,7 @@ public final class Const { public static final byte CONSTANT_NameAndType = 12; /** - * Marks a constant pool entry as a Method Handle. + * Marks a constant pool entry as a Method Handle: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -654,7 +734,7 @@ public final class Const { public static final byte CONSTANT_MethodHandle = 15; /** - * Marks a constant pool entry as a Method Type. + * Marks a constant pool entry as a Method Type: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -662,16 +742,16 @@ public final class Const { public static final byte CONSTANT_MethodType = 16; /** - * Marks a constant pool entry as dynamically computed. + * Marks a constant pool entry as dynamically computed: {@value}. * - * @see Change request for JEP - * 309 + * @see The Constant Pool in The + * Java Virtual Machine Specification * @since 6.3 */ public static final byte CONSTANT_Dynamic = 17; /** - * Marks a constant pool entry as an Invoke Dynamic + * Marks a constant pool entry as an Invoke Dynamic: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -679,7 +759,7 @@ public final class Const { public static final byte CONSTANT_InvokeDynamic = 18; /** - * Marks a constant pool entry as a Module Reference. + * Marks a constant pool entry as a Module Reference: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -688,7 +768,7 @@ public final class Const { public static final byte CONSTANT_Module = 19; /** - * Marks a constant pool entry as a Package Reference. + * Marks a constant pool entry as a Package Reference: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -705,23 +785,23 @@ public final class Const { /** * The name of the static initializer, also called "class initialization method" or "interface - * initialization method". This is "<clinit>". + * initialization method". This is {@value}. */ public static final String STATIC_INITIALIZER_NAME = ""; /** * The name of every constructor method in a class, also called "instance initialization method". This is - * "<init>". + * {@value}. */ public static final String CONSTRUCTOR_NAME = ""; /** - * The names of the interfaces implemented by arrays + * The names of the interfaces implemented by arrays. */ private static final String[] INTERFACES_IMPLEMENTED_BY_ARRAYS = {"java.lang.Cloneable", "java.io.Serializable"}; /** - * Maximum Constant Pool entries. One of the limitations of the Java Virtual Machine. + * Maximum Constant Pool entries: {@value}. One of the limitations of the Java Virtual Machine. * * @see The Java Virtual * Machine Specification, Java SE 8 Edition, page 330, chapter 4.11. @@ -729,21 +809,25 @@ public final class Const { public static final int MAX_CP_ENTRIES = 65535; /** - * Maximum code size (plus one; the code size must be LESS than this) One of the limitations of the Java Virtual - * Machine. Note vmspec2 page 152 ("Limitations") says: "The amount of code per non-native, non-abstract method is - * limited to 65536 bytes by the sizes of the indices in the exception_table of the Code attribute (4.7.3), in the - * LineNumberTable attribute (4.7.8), and in the LocalVariableTable attribute (4.7.9)." However this should be taken - * as an upper limit rather than the defined maximum. On page 134 (4.8.1 Static Constants) of the same spec, it says: - * "The value of the code_length item must be less than 65536." The entry in the Limitations section has been removed - * from later versions of the spec; it is not present in the Java SE 8 edition. + * Maximum code size (plus one; the code size must be LESS than this): {@value}. + *

+ * One of the limitations of the Java Virtual Machine. Note vmspec2 page 152 ("Limitations") says: + *

+ *
"The amount of code per non-native, non-abstract method is limited to 65536 bytes by the sizes of the indices in the exception_table of the Code
+     * attribute (4.7.3), in the LineNumberTable attribute (4.7.8), and in the LocalVariableTable attribute (4.7.9)." However this should be taken as an
+     * upper limit rather than the defined maximum. On page 134 (4.8.1 Static Constants) of the same spec, it says: "The value of the code_length item must be
+     * less than 65536."
+ *

+ * The entry in the Limitations section has been removed from later versions of the specification; it is not present in the Java SE 8 edition. + *

* - * @see The Java Virtual - * Machine Specification, Java SE 8 Edition, page 104, chapter 4.7. + * @see The Java Virtual Machine Specification, Java SE 8 + * Edition, page 104, chapter 4.7. */ public static final int MAX_CODE_SIZE = 65536; // bytes /** - * The maximum number of dimensions in an array ({@value}). One of the limitations of the Java Virtual Machine. + * The maximum number of dimensions in an array: {@value}. One of the limitations of the Java Virtual Machine. * * @see Field Descriptors in * The Java Virtual Machine Specification @@ -751,7 +835,7 @@ public final class Const { public static final int MAX_ARRAY_DIMENSIONS = 255; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -759,7 +843,7 @@ public final class Const { public static final short NOP = 0; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -767,7 +851,7 @@ public final class Const { public static final short ACONST_NULL = 1; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -775,7 +859,7 @@ public final class Const { public static final short ICONST_M1 = 2; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -783,7 +867,7 @@ public final class Const { public static final short ICONST_0 = 3; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -791,7 +875,7 @@ public final class Const { public static final short ICONST_1 = 4; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -799,7 +883,7 @@ public final class Const { public static final short ICONST_2 = 5; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -807,7 +891,7 @@ public final class Const { public static final short ICONST_3 = 6; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -815,7 +899,7 @@ public final class Const { public static final short ICONST_4 = 7; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -823,7 +907,7 @@ public final class Const { public static final short ICONST_5 = 8; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -831,7 +915,7 @@ public final class Const { public static final short LCONST_0 = 9; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -839,7 +923,7 @@ public final class Const { public static final short LCONST_1 = 10; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -847,7 +931,7 @@ public final class Const { public static final short FCONST_0 = 11; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -855,7 +939,7 @@ public final class Const { public static final short FCONST_1 = 12; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -863,7 +947,7 @@ public final class Const { public static final short FCONST_2 = 13; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -871,7 +955,7 @@ public final class Const { public static final short DCONST_0 = 14; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -879,7 +963,7 @@ public final class Const { public static final short DCONST_1 = 15; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -887,7 +971,7 @@ public final class Const { public static final short BIPUSH = 16; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -895,7 +979,7 @@ public final class Const { public static final short SIPUSH = 17; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -903,7 +987,7 @@ public final class Const { public static final short LDC = 18; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -911,7 +995,7 @@ public final class Const { public static final short LDC_W = 19; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -919,7 +1003,7 @@ public final class Const { public static final short LDC2_W = 20; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -927,7 +1011,7 @@ public final class Const { public static final short ILOAD = 21; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -935,7 +1019,7 @@ public final class Const { public static final short LLOAD = 22; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -943,7 +1027,7 @@ public final class Const { public static final short FLOAD = 23; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -951,7 +1035,7 @@ public final class Const { public static final short DLOAD = 24; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -959,7 +1043,7 @@ public final class Const { public static final short ALOAD = 25; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -967,7 +1051,7 @@ public final class Const { public static final short ILOAD_0 = 26; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -975,7 +1059,7 @@ public final class Const { public static final short ILOAD_1 = 27; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -983,7 +1067,7 @@ public final class Const { public static final short ILOAD_2 = 28; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -991,7 +1075,7 @@ public final class Const { public static final short ILOAD_3 = 29; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -999,7 +1083,7 @@ public final class Const { public static final short LLOAD_0 = 30; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1007,7 +1091,7 @@ public final class Const { public static final short LLOAD_1 = 31; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1015,7 +1099,7 @@ public final class Const { public static final short LLOAD_2 = 32; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1023,7 +1107,7 @@ public final class Const { public static final short LLOAD_3 = 33; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1031,7 +1115,7 @@ public final class Const { public static final short FLOAD_0 = 34; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1039,7 +1123,7 @@ public final class Const { public static final short FLOAD_1 = 35; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1047,7 +1131,7 @@ public final class Const { public static final short FLOAD_2 = 36; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1055,7 +1139,7 @@ public final class Const { public static final short FLOAD_3 = 37; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1063,7 +1147,7 @@ public final class Const { public static final short DLOAD_0 = 38; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1071,7 +1155,7 @@ public final class Const { public static final short DLOAD_1 = 39; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1079,7 +1163,7 @@ public final class Const { public static final short DLOAD_2 = 40; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1087,7 +1171,7 @@ public final class Const { public static final short DLOAD_3 = 41; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1095,7 +1179,7 @@ public final class Const { public static final short ALOAD_0 = 42; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1103,7 +1187,7 @@ public final class Const { public static final short ALOAD_1 = 43; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1111,7 +1195,7 @@ public final class Const { public static final short ALOAD_2 = 44; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1119,7 +1203,7 @@ public final class Const { public static final short ALOAD_3 = 45; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1127,7 +1211,7 @@ public final class Const { public static final short IALOAD = 46; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1135,7 +1219,7 @@ public final class Const { public static final short LALOAD = 47; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1143,7 +1227,7 @@ public final class Const { public static final short FALOAD = 48; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1151,7 +1235,7 @@ public final class Const { public static final short DALOAD = 49; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1159,7 +1243,7 @@ public final class Const { public static final short AALOAD = 50; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1167,7 +1251,7 @@ public final class Const { public static final short BALOAD = 51; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1175,7 +1259,7 @@ public final class Const { public static final short CALOAD = 52; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1183,7 +1267,7 @@ public final class Const { public static final short SALOAD = 53; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1191,7 +1275,7 @@ public final class Const { public static final short ISTORE = 54; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1199,7 +1283,7 @@ public final class Const { public static final short LSTORE = 55; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1207,7 +1291,7 @@ public final class Const { public static final short FSTORE = 56; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1215,7 +1299,7 @@ public final class Const { public static final short DSTORE = 57; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1223,7 +1307,7 @@ public final class Const { public static final short ASTORE = 58; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1231,7 +1315,7 @@ public final class Const { public static final short ISTORE_0 = 59; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1239,7 +1323,7 @@ public final class Const { public static final short ISTORE_1 = 60; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1247,7 +1331,7 @@ public final class Const { public static final short ISTORE_2 = 61; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1255,7 +1339,7 @@ public final class Const { public static final short ISTORE_3 = 62; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1263,7 +1347,7 @@ public final class Const { public static final short LSTORE_0 = 63; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1271,7 +1355,7 @@ public final class Const { public static final short LSTORE_1 = 64; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1279,7 +1363,7 @@ public final class Const { public static final short LSTORE_2 = 65; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1287,7 +1371,7 @@ public final class Const { public static final short LSTORE_3 = 66; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1295,7 +1379,7 @@ public final class Const { public static final short FSTORE_0 = 67; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1303,7 +1387,7 @@ public final class Const { public static final short FSTORE_1 = 68; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1311,7 +1395,7 @@ public final class Const { public static final short FSTORE_2 = 69; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1319,7 +1403,7 @@ public final class Const { public static final short FSTORE_3 = 70; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1327,7 +1411,7 @@ public final class Const { public static final short DSTORE_0 = 71; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1335,7 +1419,7 @@ public final class Const { public static final short DSTORE_1 = 72; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1343,7 +1427,7 @@ public final class Const { public static final short DSTORE_2 = 73; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1351,7 +1435,7 @@ public final class Const { public static final short DSTORE_3 = 74; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1359,7 +1443,7 @@ public final class Const { public static final short ASTORE_0 = 75; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1367,7 +1451,7 @@ public final class Const { public static final short ASTORE_1 = 76; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1375,7 +1459,7 @@ public final class Const { public static final short ASTORE_2 = 77; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1383,7 +1467,7 @@ public final class Const { public static final short ASTORE_3 = 78; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1391,7 +1475,7 @@ public final class Const { public static final short IASTORE = 79; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1399,7 +1483,7 @@ public final class Const { public static final short LASTORE = 80; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1407,7 +1491,7 @@ public final class Const { public static final short FASTORE = 81; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1415,7 +1499,7 @@ public final class Const { public static final short DASTORE = 82; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1423,7 +1507,7 @@ public final class Const { public static final short AASTORE = 83; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1431,7 +1515,7 @@ public final class Const { public static final short BASTORE = 84; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1439,7 +1523,7 @@ public final class Const { public static final short CASTORE = 85; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1447,7 +1531,7 @@ public final class Const { public static final short SASTORE = 86; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1455,7 +1539,7 @@ public final class Const { public static final short POP = 87; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1463,7 +1547,7 @@ public final class Const { public static final short POP2 = 88; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1471,7 +1555,7 @@ public final class Const { public static final short DUP = 89; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1479,7 +1563,7 @@ public final class Const { public static final short DUP_X1 = 90; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1487,7 +1571,7 @@ public final class Const { public static final short DUP_X2 = 91; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1495,7 +1579,7 @@ public final class Const { public static final short DUP2 = 92; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1503,7 +1587,7 @@ public final class Const { public static final short DUP2_X1 = 93; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1511,7 +1595,7 @@ public final class Const { public static final short DUP2_X2 = 94; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1519,7 +1603,7 @@ public final class Const { public static final short SWAP = 95; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1527,7 +1611,7 @@ public final class Const { public static final short IADD = 96; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1535,7 +1619,7 @@ public final class Const { public static final short LADD = 97; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1543,7 +1627,7 @@ public final class Const { public static final short FADD = 98; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1551,7 +1635,7 @@ public final class Const { public static final short DADD = 99; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1559,7 +1643,7 @@ public final class Const { public static final short ISUB = 100; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1567,7 +1651,7 @@ public final class Const { public static final short LSUB = 101; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1575,7 +1659,7 @@ public final class Const { public static final short FSUB = 102; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1583,7 +1667,7 @@ public final class Const { public static final short DSUB = 103; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1591,7 +1675,7 @@ public final class Const { public static final short IMUL = 104; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1599,7 +1683,7 @@ public final class Const { public static final short LMUL = 105; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1607,7 +1691,7 @@ public final class Const { public static final short FMUL = 106; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1615,7 +1699,7 @@ public final class Const { public static final short DMUL = 107; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1623,7 +1707,7 @@ public final class Const { public static final short IDIV = 108; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1631,7 +1715,7 @@ public final class Const { public static final short LDIV = 109; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1639,7 +1723,7 @@ public final class Const { public static final short FDIV = 110; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1647,7 +1731,7 @@ public final class Const { public static final short DDIV = 111; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1655,7 +1739,7 @@ public final class Const { public static final short IREM = 112; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1663,7 +1747,7 @@ public final class Const { public static final short LREM = 113; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1671,7 +1755,7 @@ public final class Const { public static final short FREM = 114; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1679,7 +1763,7 @@ public final class Const { public static final short DREM = 115; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1687,7 +1771,7 @@ public final class Const { public static final short INEG = 116; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1695,7 +1779,7 @@ public final class Const { public static final short LNEG = 117; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1703,7 +1787,7 @@ public final class Const { public static final short FNEG = 118; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1711,7 +1795,7 @@ public final class Const { public static final short DNEG = 119; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1719,7 +1803,7 @@ public final class Const { public static final short ISHL = 120; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1727,7 +1811,7 @@ public final class Const { public static final short LSHL = 121; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1735,7 +1819,7 @@ public final class Const { public static final short ISHR = 122; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1743,7 +1827,7 @@ public final class Const { public static final short LSHR = 123; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1751,7 +1835,7 @@ public final class Const { public static final short IUSHR = 124; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1759,7 +1843,7 @@ public final class Const { public static final short LUSHR = 125; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1767,7 +1851,7 @@ public final class Const { public static final short IAND = 126; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1775,7 +1859,7 @@ public final class Const { public static final short LAND = 127; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1783,7 +1867,7 @@ public final class Const { public static final short IOR = 128; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1791,7 +1875,7 @@ public final class Const { public static final short LOR = 129; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1799,7 +1883,7 @@ public final class Const { public static final short IXOR = 130; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1807,7 +1891,7 @@ public final class Const { public static final short LXOR = 131; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1815,7 +1899,7 @@ public final class Const { public static final short IINC = 132; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1823,7 +1907,7 @@ public final class Const { public static final short I2L = 133; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1831,7 +1915,7 @@ public final class Const { public static final short I2F = 134; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1839,7 +1923,7 @@ public final class Const { public static final short I2D = 135; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1847,7 +1931,7 @@ public final class Const { public static final short L2I = 136; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1855,7 +1939,7 @@ public final class Const { public static final short L2F = 137; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1863,7 +1947,7 @@ public final class Const { public static final short L2D = 138; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1871,7 +1955,7 @@ public final class Const { public static final short F2I = 139; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1879,7 +1963,7 @@ public final class Const { public static final short F2L = 140; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1887,7 +1971,7 @@ public final class Const { public static final short F2D = 141; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1895,7 +1979,7 @@ public final class Const { public static final short D2I = 142; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1903,7 +1987,7 @@ public final class Const { public static final short D2L = 143; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1911,7 +1995,7 @@ public final class Const { public static final short D2F = 144; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1919,7 +2003,7 @@ public final class Const { public static final short I2B = 145; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1927,7 +2011,7 @@ public final class Const { public static final short INT2BYTE = 145; // Old notation /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1935,7 +2019,7 @@ public final class Const { public static final short I2C = 146; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1943,7 +2027,7 @@ public final class Const { public static final short INT2CHAR = 146; // Old notation /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1951,7 +2035,7 @@ public final class Const { public static final short I2S = 147; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1959,7 +2043,7 @@ public final class Const { public static final short INT2SHORT = 147; // Old notation /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1967,7 +2051,7 @@ public final class Const { public static final short LCMP = 148; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1975,7 +2059,7 @@ public final class Const { public static final short FCMPL = 149; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1983,7 +2067,7 @@ public final class Const { public static final short FCMPG = 150; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1991,7 +2075,7 @@ public final class Const { public static final short DCMPL = 151; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1999,7 +2083,7 @@ public final class Const { public static final short DCMPG = 152; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2007,7 +2091,7 @@ public final class Const { public static final short IFEQ = 153; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2015,7 +2099,7 @@ public final class Const { public static final short IFNE = 154; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2023,7 +2107,7 @@ public final class Const { public static final short IFLT = 155; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2031,7 +2115,7 @@ public final class Const { public static final short IFGE = 156; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2039,7 +2123,7 @@ public final class Const { public static final short IFGT = 157; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2047,7 +2131,7 @@ public final class Const { public static final short IFLE = 158; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2055,7 +2139,7 @@ public final class Const { public static final short IF_ICMPEQ = 159; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2063,7 +2147,7 @@ public final class Const { public static final short IF_ICMPNE = 160; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2071,7 +2155,7 @@ public final class Const { public static final short IF_ICMPLT = 161; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2079,7 +2163,7 @@ public final class Const { public static final short IF_ICMPGE = 162; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2087,7 +2171,7 @@ public final class Const { public static final short IF_ICMPGT = 163; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2095,7 +2179,7 @@ public final class Const { public static final short IF_ICMPLE = 164; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2103,7 +2187,7 @@ public final class Const { public static final short IF_ACMPEQ = 165; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2111,7 +2195,7 @@ public final class Const { public static final short IF_ACMPNE = 166; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2119,7 +2203,7 @@ public final class Const { public static final short GOTO = 167; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -2127,7 +2211,7 @@ public final class Const { public static final short JSR = 168; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -2135,7 +2219,7 @@ public final class Const { public static final short RET = 169; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2143,7 +2227,7 @@ public final class Const { public static final short TABLESWITCH = 170; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2151,7 +2235,7 @@ public final class Const { public static final short LOOKUPSWITCH = 171; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2159,7 +2243,7 @@ public final class Const { public static final short IRETURN = 172; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2167,7 +2251,7 @@ public final class Const { public static final short LRETURN = 173; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2175,7 +2259,7 @@ public final class Const { public static final short FRETURN = 174; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2183,7 +2267,7 @@ public final class Const { public static final short DRETURN = 175; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2191,7 +2275,7 @@ public final class Const { public static final short ARETURN = 176; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2199,7 +2283,7 @@ public final class Const { public static final short RETURN = 177; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -2207,7 +2291,7 @@ public final class Const { public static final short GETSTATIC = 178; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -2215,7 +2299,7 @@ public final class Const { public static final short PUTSTATIC = 179; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -2223,7 +2307,7 @@ public final class Const { public static final short GETFIELD = 180; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -2231,7 +2315,7 @@ public final class Const { public static final short PUTFIELD = 181; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2239,7 +2323,7 @@ public final class Const { public static final short INVOKEVIRTUAL = 182; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2247,7 +2331,7 @@ public final class Const { public static final short INVOKESPECIAL = 183; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -2255,7 +2339,7 @@ public final class Const { public static final short INVOKENONVIRTUAL = 183; // Old name in JDK 1.0 /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2263,7 +2347,7 @@ public final class Const { public static final short INVOKESTATIC = 184; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2271,7 +2355,7 @@ public final class Const { public static final short INVOKEINTERFACE = 185; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2279,7 +2363,7 @@ public final class Const { public static final short INVOKEDYNAMIC = 186; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -2287,7 +2371,7 @@ public final class Const { public static final short NEW = 187; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -2295,7 +2379,7 @@ public final class Const { public static final short NEWARRAY = 188; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -2303,7 +2387,7 @@ public final class Const { public static final short ANEWARRAY = 189; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2311,7 +2395,7 @@ public final class Const { public static final short ARRAYLENGTH = 190; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2319,7 +2403,7 @@ public final class Const { public static final short ATHROW = 191; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -2327,7 +2411,7 @@ public final class Const { public static final short CHECKCAST = 192; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -2335,7 +2419,7 @@ public final class Const { public static final short INSTANCEOF = 193; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2343,7 +2427,7 @@ public final class Const { public static final short MONITORENTER = 194; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2351,7 +2435,7 @@ public final class Const { public static final short MONITOREXIT = 195; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2359,7 +2443,7 @@ public final class Const { public static final short WIDE = 196; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2367,7 +2451,7 @@ public final class Const { public static final short MULTIANEWARRAY = 197; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2375,7 +2459,7 @@ public final class Const { public static final short IFNULL = 198; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -2383,7 +2467,7 @@ public final class Const { public static final short IFNONNULL = 199; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2391,7 +2475,7 @@ public final class Const { public static final short GOTO_W = 200; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2399,7 +2483,7 @@ public final class Const { public static final short JSR_W = 201; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see Reserved opcodes in the Java * Virtual Machine Specification @@ -2407,7 +2491,7 @@ public final class Const { public static final short BREAKPOINT = 202; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2418,7 +2502,7 @@ public final class Const { public static final short LDC_QUICK = 203; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2429,7 +2513,7 @@ public final class Const { public static final short LDC_W_QUICK = 204; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2440,7 +2524,7 @@ public final class Const { public static final short LDC2_W_QUICK = 205; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2451,7 +2535,7 @@ public final class Const { public static final short GETFIELD_QUICK = 206; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2462,7 +2546,7 @@ public final class Const { public static final short PUTFIELD_QUICK = 207; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2473,7 +2557,7 @@ public final class Const { public static final short GETFIELD2_QUICK = 208; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2484,7 +2568,7 @@ public final class Const { public static final short PUTFIELD2_QUICK = 209; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2495,7 +2579,7 @@ public final class Const { public static final short GETSTATIC_QUICK = 210; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2506,7 +2590,7 @@ public final class Const { public static final short PUTSTATIC_QUICK = 211; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2517,7 +2601,7 @@ public final class Const { public static final short GETSTATIC2_QUICK = 212; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2528,7 +2612,7 @@ public final class Const { public static final short PUTSTATIC2_QUICK = 213; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2539,7 +2623,7 @@ public final class Const { public static final short INVOKEVIRTUAL_QUICK = 214; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2550,7 +2634,7 @@ public final class Const { public static final short INVOKENONVIRTUAL_QUICK = 215; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2561,7 +2645,7 @@ public final class Const { public static final short INVOKESUPER_QUICK = 216; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2572,7 +2656,7 @@ public final class Const { public static final short INVOKESTATIC_QUICK = 217; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2583,7 +2667,7 @@ public final class Const { public static final short INVOKEINTERFACE_QUICK = 218; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2594,7 +2678,7 @@ public final class Const { public static final short INVOKEVIRTUALOBJECT_QUICK = 219; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2605,7 +2689,7 @@ public final class Const { public static final short NEW_QUICK = 221; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2616,7 +2700,7 @@ public final class Const { public static final short ANEWARRAY_QUICK = 222; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2627,7 +2711,7 @@ public final class Const { public static final short MULTIANEWARRAY_QUICK = 223; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2638,7 +2722,7 @@ public final class Const { public static final short CHECKCAST_QUICK = 224; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2649,7 +2733,7 @@ public final class Const { public static final short INSTANCEOF_QUICK = 225; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2660,7 +2744,7 @@ public final class Const { public static final short INVOKEVIRTUAL_QUICK_W = 226; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2671,7 +2755,7 @@ public final class Const { public static final short GETFIELD_QUICK_W = 227; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2682,7 +2766,7 @@ public final class Const { public static final short PUTFIELD_QUICK_W = 228; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see Reserved opcodes in the Java * Virtual Machine Specification @@ -2690,7 +2774,7 @@ public final class Const { public static final short IMPDEP1 = 254; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see Reserved opcodes in the Java * Virtual Machine Specification @@ -2698,34 +2782,44 @@ public final class Const { public static final short IMPDEP2 = 255; /** - * BCEL virtual instruction for pushing an arbitrary data type onto the stack. Will be converted to the appropriate JVM + * BCEL virtual instruction for pushing an arbitrary data type onto the stack: {@value}. Will be converted to the appropriate JVM * opcode when the class is dumped. */ public static final short PUSH = 4711; /** - * BCEL virtual instruction for either LOOKUPSWITCH or TABLESWITCH. Will be converted to the appropriate JVM opcode when + * BCEL virtual instruction for either LOOKUPSWITCH or TABLESWITCH: {@value}. Will be converted to the appropriate JVM opcode when * the class is dumped. */ public static final short SWITCH = 4712; - /** Illegal opcode. */ + /** + * Illegal opcode: {@value}. + */ public static final short UNDEFINED = -1; - /** Illegal opcode. */ + /** + * Illegal opcode: {@value}. + */ public static final short UNPREDICTABLE = -2; - /** Illegal opcode. */ + /** + * Illegal opcode: {@value}. + */ public static final short RESERVED = -3; - /** Mnemonic for an illegal opcode. */ + /** + * Mnemonic for an illegal opcode: {@value}. + */ public static final String ILLEGAL_OPCODE = ""; - /** Mnemonic for an illegal type. */ + /** + * Mnemonic for an illegal type: {@value}. + */ public static final String ILLEGAL_TYPE = ""; /** - * Boolean data type. + * Boolean data type: {@value}. * * @see Static Constraints in * the Java Virtual Machine Specification @@ -2733,7 +2827,7 @@ public final class Const { public static final byte T_BOOLEAN = 4; /** - * Char data type. + * Char data type: {@value}. * * @see Static Constraints in * the Java Virtual Machine Specification @@ -2741,7 +2835,7 @@ public final class Const { public static final byte T_CHAR = 5; /** - * Float data type. + * Float data type: {@value}. * * @see Static Constraints in * the Java Virtual Machine Specification @@ -2749,7 +2843,7 @@ public final class Const { public static final byte T_FLOAT = 6; /** - * Double data type. + * Double data type: {@value}. * * @see Static Constraints in * the Java Virtual Machine Specification @@ -2757,7 +2851,7 @@ public final class Const { public static final byte T_DOUBLE = 7; /** - * Byte data type. + * Byte data type: {@value}. * * @see Static Constraints in * the Java Virtual Machine Specification @@ -2765,7 +2859,7 @@ public final class Const { public static final byte T_BYTE = 8; /** - * Short data type. + * Short data type: {@value}. * * @see Static Constraints in * the Java Virtual Machine Specification @@ -2773,7 +2867,7 @@ public final class Const { public static final byte T_SHORT = 9; /** - * Int data type. + * Int data type: {@value}. * * @see Static Constraints in * the Java Virtual Machine Specification @@ -2781,7 +2875,7 @@ public final class Const { public static final byte T_INT = 10; /** - * Long data type. + * Long data type: {@value}. * * @see Static Constraints in * the Java Virtual Machine Specification @@ -2827,7 +2921,7 @@ public final class Const { /** * The signature characters corresponding to primitive types, e.g., SHORT_TYPE_NAMES[T_INT] = "I" */ - private static final String[] SHORT_TYPE_NAMES = {ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, "Z", "C", "F", "D", "B", "S", "I", "J", "V", + public static final String[] SHORT_TYPE_NAMES = {ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, "Z", "C", "F", "D", "B", "S", "I", "J", "V", ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE}; /** @@ -3036,11 +3130,13 @@ public final class Const { public static final byte ATTR_MODULE_MAIN_CLASS = 24; public static final byte ATTR_NEST_HOST = 25; public static final byte ATTR_NEST_MEMBERS = 26; - public static final short KNOWN_ATTRIBUTES = 27; // count of attributes + public static final byte ATTR_RECORD = 27; + + public static final short KNOWN_ATTRIBUTES = 28; // count of attributes private static final String[] ATTRIBUTE_NAMES = {"SourceFile", "ConstantValue", "Code", "Exceptions", "LineNumberTable", "LocalVariableTable", "InnerClasses", "Synthetic", "Deprecated", "PMGClass", "Signature", "StackMap", "RuntimeVisibleAnnotations", "RuntimeInvisibleAnnotations", "RuntimeVisibleParameterAnnotations", "RuntimeInvisibleParameterAnnotations", "AnnotationDefault", "LocalVariableTypeTable", "EnclosingMethod", - "StackMapTable", "BootstrapMethods", "MethodParameters", "Module", "ModulePackages", "ModuleMainClass", "NestHost", "NestMembers"}; + "StackMapTable", "BootstrapMethods", "MethodParameters", "Module", "ModulePackages", "ModuleMainClass", "NestHost", "NestMembers", "Record"}; /** * Constants used in the StackMap attribute. */ @@ -3070,6 +3166,7 @@ public final class Const { public static final int SAME_FRAME_EXTENDED = 251; public static final int APPEND_FRAME = 252; public static final int FULL_FRAME = 255; + /** * Constants that define the maximum value of those constants which store ranges. */ @@ -3090,6 +3187,7 @@ public final class Const { public static final byte REF_invokeSpecial = 7; public static final byte REF_newInvokeSpecial = 8; public static final byte REF_invokeInterface = 9; + /** * The names of the reference_kinds of a CONSTANT_MethodHandle_info. */ @@ -3097,7 +3195,7 @@ public final class Const { "newInvokeSpecial", "invokeInterface"}; /** - * @param index + * @param index index into {@code ACCESS_NAMES}. * @return the ACCESS_NAMES entry at the given index * @since 6.0 */ @@ -3107,7 +3205,7 @@ public final class Const { /** * - * @param index + * @param index index into {@code ACCESS_NAMES}. * @return the attribute name * @since 6.0 */ @@ -3118,7 +3216,7 @@ public final class Const { /** * The primitive class names corresponding to the T_XX constants, e.g., CLASS_TYPE_NAMES[T_INT] = "java.lang.Integer" * - * @param index + * @param index index into {@code CLASS_TYPE_NAMES}. * @return the class name * @since 6.0 */ @@ -3128,7 +3226,7 @@ public final class Const { /** * - * @param index + * @param index index into {@code CONSTANT_NAMES}. * @return the CONSTANT_NAMES entry at the given index * @since 6.0 */ @@ -3140,7 +3238,7 @@ public final class Const { /** * - * @param index + * @param index index into {@code CONSUME_STACK}. * @return Number of words consumed on operand stack * @since 6.0 */ @@ -3157,7 +3255,7 @@ public final class Const { /** * - * @param index + * @param index index into {@code ITEM_NAMES}. * @return the item name * @since 6.0 */ @@ -3167,7 +3265,7 @@ public final class Const { /** * - * @param index + * @param index index into {@code METHODHANDLE_NAMES}. * @return the method handle name * @since 6.0 */ @@ -3177,7 +3275,7 @@ public final class Const { /** * - * @param index + * @param index index into {@code NO_OF_OPERANDS}. * @return Number of byte code operands * @since 6.0 */ diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/ExceptionConst.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/ExceptionConst.java index d45c5794b7b..89cf3f835da 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/ExceptionConst.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/ExceptionConst.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -26,7 +26,7 @@ import jdk.xml.internal.Utils; * Exception constants. * * @since 6.0 (intended to replace the InstructionConstant interface) - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public final class ExceptionConst { @@ -52,7 +52,6 @@ public final class ExceptionConst { * Super class of any linking exception (aka Linkage Error) */ public static final Class LINKING_EXCEPTION = LinkageError.class; - /** * Linking Exceptions */ @@ -67,10 +66,10 @@ public final class ExceptionConst { public static final Class NO_SUCH_METHOD_ERROR = NoSuchMethodError.class; public static final Class NO_CLASS_DEF_FOUND_ERROR = NoClassDefFoundError.class; public static final Class UNSATISFIED_LINK_ERROR = UnsatisfiedLinkError.class; + public static final Class VERIFY_ERROR = VerifyError.class; /* UnsupportedClassVersionError is new in JDK 1.2 */ // public static final Class UnsupportedClassVersionError = UnsupportedClassVersionError.class; - /** * Run-Time Exceptions */ diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/Repository.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/Repository.java index d36260cc23a..10f6a1a8ff4 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/Repository.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/Repository.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -30,7 +30,7 @@ import com.sun.org.apache.bcel.internal.util.SyntheticRepository; * @see com.sun.org.apache.bcel.internal.util.Repository * @see SyntheticRepository * - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public abstract class Repository { @@ -174,7 +174,7 @@ public abstract class Repository { } /** - * Lookups class somewhere found on your CLASSPATH, or wherever the repository instance looks for it. + * Lookups class somewhere found on your CLASSPATH, or whereever the repository instance looks for it. * * @return class object for given fully qualified class name * @throws ClassNotFoundException if the class could not be found or parsed correctly diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/AccessFlags.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/AccessFlags.java index 61ec9c4d690..f1d350894c9 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/AccessFlags.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/AccessFlags.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -25,27 +25,36 @@ import com.sun.org.apache.bcel.internal.Const; * Super class for all objects that have modifiers like private, final, ... I.e. * classes, fields, and methods. * - * @LastModified: Jan 2020 + * @LastModified: Sept 2025 */ public abstract class AccessFlags { /** - * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter + * Access flags. + * + * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter. */ @java.lang.Deprecated protected int access_flags; // TODO not used externally at present + /** + * Constructs a new instance. + */ public AccessFlags() { } /** - * @param a initial access flags + * Constructs a new instance. + * + * @param accessFlags initial access flags. */ - public AccessFlags(final int a) { - access_flags = a; + public AccessFlags(final int accessFlags) { + access_flags = accessFlags; } /** + * Gets access flags. + * * @return Access flags of the object aka. "modifiers". */ public final int getAccessFlags() { @@ -53,142 +62,303 @@ public abstract class AccessFlags { } /** - * @return Access flags of the object aka. "modifiers". + * Gets access flags. + * + * @return Access flags of the object also known as modifiers. */ public final int getModifiers() { return access_flags; } + /** + * Tests whether the abstract bit is on. + * + * @return whether the abstract bit is on. + */ public final boolean isAbstract() { - return (access_flags & Const.ACC_ABSTRACT) != 0; + return test(Const.ACC_ABSTRACT); } + /** + * Sets the abstract bit. + * + * @param flag The new value. + */ public final void isAbstract(final boolean flag) { setFlag(Const.ACC_ABSTRACT, flag); } + /** + * Tests whether the annotation bit is on. + * + * @return whether the annotation bit is on. + */ public final boolean isAnnotation() { - return (access_flags & Const.ACC_ANNOTATION) != 0; + return test(Const.ACC_ANNOTATION); } + /** + * Sets the annotation bit. + * + * @param flag The new value. + */ public final void isAnnotation(final boolean flag) { setFlag(Const.ACC_ANNOTATION, flag); } - + /** + * Tests whether the enum bit is on. + * + * @return whether the enum bit is on. + */ public final boolean isEnum() { - return (access_flags & Const.ACC_ENUM) != 0; + return test(Const.ACC_ENUM); } + /** + * Sets the enum bit. + * + * @param flag The new value. + */ public final void isEnum(final boolean flag) { setFlag(Const.ACC_ENUM, flag); } + /** + * Tests whether the final bit is on. + * + * @return whether the final bit is on. + */ public final boolean isFinal() { - return (access_flags & Const.ACC_FINAL) != 0; + return test(Const.ACC_FINAL); } + /** + * Sets the final bit. + * + * @param flag The new value. + */ public final void isFinal(final boolean flag) { setFlag(Const.ACC_FINAL, flag); } + /** + * Tests whether the interface bit is on. + * + * @return whether the interface bit is on. + */ public final boolean isInterface() { - return (access_flags & Const.ACC_INTERFACE) != 0; + return test(Const.ACC_INTERFACE); } + /** + * Sets the interface bit. + * + * @param flag The new value. + */ public final void isInterface(final boolean flag) { setFlag(Const.ACC_INTERFACE, flag); } + /** + * Tests whether the native bit is on. + * + * @return whether the native bit is on. + */ public final boolean isNative() { - return (access_flags & Const.ACC_NATIVE) != 0; + return test(Const.ACC_NATIVE); } + /** + * Sets the native bit. + * + * @param flag The new value. + */ public final void isNative(final boolean flag) { setFlag(Const.ACC_NATIVE, flag); } + /** + * Tests whether the private bit is on. + * + * @return whether the private bit is on. + */ public final boolean isPrivate() { - return (access_flags & Const.ACC_PRIVATE) != 0; + return test(Const.ACC_PRIVATE); } + /** + * Sets the private bit. + * + * @param flag The new value. + */ public final void isPrivate(final boolean flag) { setFlag(Const.ACC_PRIVATE, flag); } + /** + * Tests whether the protected bit is on. + * + * @return whether the protected bit is on. + */ public final boolean isProtected() { - return (access_flags & Const.ACC_PROTECTED) != 0; + return test(Const.ACC_PROTECTED); } + /** + * Sets the protected bit. + * + * @param flag The new value. + */ public final void isProtected(final boolean flag) { setFlag(Const.ACC_PROTECTED, flag); } + /** + * Tests whether the public bit is on. + * + * @return whether the public bit is on. + */ public final boolean isPublic() { - return (access_flags & Const.ACC_PUBLIC) != 0; + return test(Const.ACC_PUBLIC); } + /** + * Sets the public bit. + * + * @param flag The new value. + */ public final void isPublic(final boolean flag) { setFlag(Const.ACC_PUBLIC, flag); } + /** + * Tests whether the static bit is on. + * + * @return whether the static bit is on. + */ public final boolean isStatic() { - return (access_flags & Const.ACC_STATIC) != 0; + return test(Const.ACC_STATIC); } + /** + * Sets the static bit. + * + * @param flag The new value. + */ public final void isStatic(final boolean flag) { setFlag(Const.ACC_STATIC, flag); } + /** + * Tests whether the strict bit is on. + * + * @return whether the strict bit is on. + */ public final boolean isStrictfp() { - return (access_flags & Const.ACC_STRICT) != 0; + return test(Const.ACC_STRICT); } + /** + * Sets the strict bit. + * + * @param flag The new value. + */ public final void isStrictfp(final boolean flag) { setFlag(Const.ACC_STRICT, flag); } + /** + * Tests whether the synchronized bit is on. + * + * @return whether the synchronized bit is on. + */ public final boolean isSynchronized() { - return (access_flags & Const.ACC_SYNCHRONIZED) != 0; + return test(Const.ACC_SYNCHRONIZED); } + /** + * Sets the synchronized bit. + * + * @param flag The new value. + */ public final void isSynchronized(final boolean flag) { setFlag(Const.ACC_SYNCHRONIZED, flag); } + /** + * Tests whether the synthetic bit is on. + * + * @return whether the synthetic bit is on. + */ public final boolean isSynthetic() { - return (access_flags & Const.ACC_SYNTHETIC) != 0; + return test(Const.ACC_SYNTHETIC); } + /** + * Sets the synthetic bit. + * + * @param flag The new value. + */ public final void isSynthetic(final boolean flag) { setFlag(Const.ACC_SYNTHETIC, flag); } + /** + * Tests whether the transient bit is on. + * + * @return whether the varargs bit is on. + */ public final boolean isTransient() { - return (access_flags & Const.ACC_TRANSIENT) != 0; + return test(Const.ACC_TRANSIENT); } + /** + * Sets the varargs bit. + * + * @param flag The new value. + */ public final void isTransient(final boolean flag) { setFlag(Const.ACC_TRANSIENT, flag); } + /** + * Tests whether the varargs bit is on. + * + * @return whether the varargs bit is on. + */ public final boolean isVarArgs() { - return (access_flags & Const.ACC_VARARGS) != 0; + return test(Const.ACC_VARARGS); } + /** + * Sets the varargs bit. + * + * @param flag The new value. + */ public final void isVarArgs(final boolean flag) { setFlag(Const.ACC_VARARGS, flag); } + /** + * Tests whether the volatile bit is on. + * + * @return whether the volatile bit is on. + */ public final boolean isVolatile() { - return (access_flags & Const.ACC_VOLATILE) != 0; + return test(Const.ACC_VOLATILE); } + /** + * Sets the volatile bit. + * + * @param flag The new value. + */ public final void isVolatile(final boolean flag) { setFlag(Const.ACC_VOLATILE, flag); } /** - * Set access flags aka "modifiers". + * Sets access flags also known as modifiers. * * @param accessFlags Access flags of the object. */ @@ -207,11 +377,21 @@ public abstract class AccessFlags { } /** - * Set access flags aka "modifiers". + * Sets access flags aka "modifiers". * * @param accessFlags Access flags of the object. */ public final void setModifiers(final int accessFlags) { setAccessFlags(accessFlags); } + + /** + * Tests whether the bit is on. + * + * @param test the bit to test. + * @return whether the bit is on. + */ + private boolean test(final short test) { + return (access_flags & test) != 0; + } } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/AnnotationEntry.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/AnnotationEntry.java index 466e9bf3404..c9503332a6f 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/AnnotationEntry.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/AnnotationEntry.java @@ -1,6 +1,5 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -27,20 +26,22 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; +import jdk.xml.internal.Utils; /** * Represents one annotation in the annotation table * * @since 6.0 + * @LastModified: Sept 2025 */ public class AnnotationEntry implements Node { public static final AnnotationEntry[] EMPTY_ARRAY = {}; - public static AnnotationEntry[] createAnnotationEntries(final Attribute[] attrs) { + public static AnnotationEntry[] createAnnotationEntries(final Attribute[] attributes) { // Find attributes that contain annotation data - return Stream.of(attrs).filter(Annotations.class::isInstance).flatMap(e -> Stream.of(((Annotations) e).getAnnotationEntries())) - .toArray(AnnotationEntry[]::new); + return Utils.streamOfIfNonNull(attributes).filter(Annotations.class::isInstance).flatMap(e -> Stream.of(((Annotations) e).getAnnotationEntries())) + .toArray(AnnotationEntry[]::new); } /** @@ -55,7 +56,6 @@ public class AnnotationEntry implements Node { public static AnnotationEntry read(final DataInput input, final ConstantPool constantPool, final boolean isRuntimeVisible) throws IOException { final AnnotationEntry annotationEntry = new AnnotationEntry(input.readUnsignedShort(), constantPool, isRuntimeVisible); final int numElementValuePairs = input.readUnsignedShort(); - annotationEntry.elementValuePairs = new ArrayList<>(); for (int i = 0; i < numElementValuePairs; i++) { annotationEntry.elementValuePairs .add(new ElementValuePair(input.readUnsignedShort(), ElementValue.readElementValue(input, constantPool), constantPool)); @@ -69,12 +69,13 @@ public class AnnotationEntry implements Node { private final boolean isRuntimeVisible; - private List elementValuePairs; + private final List elementValuePairs; public AnnotationEntry(final int typeIndex, final ConstantPool constantPool, final boolean isRuntimeVisible) { this.typeIndex = typeIndex; this.constantPool = constantPool; this.isRuntimeVisible = isRuntimeVisible; + this.elementValuePairs = new ArrayList<>(); } /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Annotations.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Annotations.java index 52ac9d0dd98..6ff9b4a046f 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Annotations.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Annotations.java @@ -52,7 +52,7 @@ public abstract class Annotations extends Attribute implements Iterable The class File Format : * The BootstrapMethods Attribute * @since 6.0 + * @LastModified: Sept 2025 */ public class BootstrapMethod implements Cloneable { + static final BootstrapMethod[] EMPTY_ARRAY = {}; + /** Index of the CONSTANT_MethodHandle_info structure in the constant_pool table */ private int bootstrapMethodRef; @@ -54,7 +57,7 @@ public class BootstrapMethod implements Cloneable { } /** - * Construct object from input stream. + * Constructs object from input stream. * * @param input Input stream * @throws IOException if an I/O error occurs. @@ -78,7 +81,7 @@ public class BootstrapMethod implements Cloneable { */ public BootstrapMethod(final int bootstrapMethodRef, final int[] bootstrapArguments) { this.bootstrapMethodRef = bootstrapMethodRef; - this.bootstrapArguments = bootstrapArguments; + setBootstrapArguments(bootstrapArguments); } /** @@ -87,7 +90,7 @@ public class BootstrapMethod implements Cloneable { public BootstrapMethod copy() { try { return (BootstrapMethod) clone(); - } catch (final CloneNotSupportedException e) { + } catch (final CloneNotSupportedException ignore) { // TODO should this throw? } return null; @@ -132,7 +135,7 @@ public class BootstrapMethod implements Cloneable { * @param bootstrapArguments int[] indices into constant_pool of CONSTANT_[type]_info */ public void setBootstrapArguments(final int[] bootstrapArguments) { - this.bootstrapArguments = bootstrapArguments; + this.bootstrapArguments = Utils.createEmptyArrayIfNull(bootstrapArguments); } /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/BootstrapMethods.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/BootstrapMethods.java index 6f9930f1b16..ef2475e1856 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/BootstrapMethods.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/BootstrapMethods.java @@ -58,11 +58,11 @@ public class BootstrapMethods extends Attribute implements Iterable - * Note that the detail message associated with {@code cause} is not automatically incorporated in this runtime exception's detail message. * * @param message the detail message (which is saved for later retrieval by the {@link #getMessage()} method). - * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). (A {@code null} value is permitted, and indicates that - * the cause is nonexistent or unknown.) + * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). A {@code null} value is permitted, and indicates that + * the cause is nonexistent or unknown. * @since 6.0 */ public ClassFormatException(final String message, final Throwable cause) { @@ -63,8 +61,8 @@ public class ClassFormatException extends RuntimeException { * Constructs a new instance with the specified cause and a detail message of {@code (cause==null ? null : cause.toString())} (which typically contains the * class and detail message of {@code cause}). This constructor is useful for runtime exceptions that are little more than wrappers for other throwables. * - * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). (A {@code null} value is permitted, and indicates that the - * cause is nonexistent or unknown.) + * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). A {@code null} value is permitted, and indicates that the + * cause is nonexistent or unknown. * @since 6.7.0 */ public ClassFormatException(final Throwable cause) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ClassParser.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ClassParser.java index c9daaeabf9b..0dbda722ec4 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ClassParser.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ClassParser.java @@ -37,7 +37,7 @@ import com.sun.org.apache.bcel.internal.Const; * appropriate exception is propagated back to the caller. * * The structure and the names comply, except for a few conveniences, exactly with the - * JVM specification 1.0. See this paper for further details about + * JVM specification 1.0. See this paper for further details about * the structure of a bytecode file. */ public final class ClassParser { @@ -57,7 +57,7 @@ public final class ClassParser { private Field[] fields; // class fields, i.e., its variables private Method[] methods; // methods defined in the class private Attribute[] attributes; // attributes defined in the class - private final boolean isZip; // Loaded from zip file + private final boolean isZip; // Loaded from ZIP file /** * Parses class from the given stream. @@ -91,7 +91,7 @@ public final class ClassParser { /** * Parses class from given .class file in a ZIP-archive * - * @param zipFile zip file name + * @param zipFile ZIP file name * @param fileName file name */ public ClassParser(final String zipFile, final String fileName) { @@ -104,7 +104,7 @@ public final class ClassParser { /** * Parses the given Java class file and return an object that represents the contained data, i.e., constants, methods, * fields and commands. A ClassFormatException is raised, if the file is not a valid .class file. (This does - * not include verification of the byte code as it is performed by the java interpreter). + * not include verification of the byte code as it is performed by the Java interpreter). * * @return Class object representing the parsed class file * @throws IOException if an I/O error occurs. @@ -151,11 +151,11 @@ public final class ClassParser { // for (int i=0; i < u.length; i++) // System.err.println("WARNING: " + u[i]); // Everything should have been read now - // if(file.available() > 0) { + // if (file.available() > 0) { // int bytes = file.available(); // byte[] buf = new byte[bytes]; // file.read(buf); - // if(!(isZip && (buf.length == 1))) { + // if (!(isZip && (buf.length == 1))) { // System.err.println("WARNING: Trailing garbage at end of " + fileName); // System.err.println(bytes + " extra bytes: " + Utility.toHexString(buf)); // } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Code.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Code.java index 498a8c71b18..7573a5412e7 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Code.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Code.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -27,6 +27,7 @@ import java.util.Arrays; import com.sun.org.apache.bcel.internal.Const; import com.sun.org.apache.bcel.internal.util.Args; +import jdk.xml.internal.Utils; /** * This class represents a chunk of Java byte code contained in a method. It is instantiated by the @@ -59,7 +60,7 @@ import com.sun.org.apache.bcel.internal.util.Args; * @see CodeException * @see LineNumberTable * @see LocalVariableTable - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public final class Code extends Attribute { @@ -93,7 +94,7 @@ public final class Code extends Attribute { code = new byte[codeLength]; // Read byte code file.readFully(code); /* - * Read exception table that contains all regions where an exception handler is active, i.e., a try { ... } catch() + * Read exception table that contains all regions where an exception handler is active, i.e., a try { ... } catch () * block. */ final int exceptionTableLength = file.readUnsignedShort(); @@ -107,7 +108,7 @@ public final class Code extends Attribute { final int attributesCount = file.readUnsignedShort(); attributes = new Attribute[attributesCount]; for (int i = 0; i < attributesCount; i++) { - attributes[i] = Attribute.readAttribute(file, constantPool); + attributes[i] = readAttribute(file, constantPool); } /* * Adjust length, because of setAttributes in this(), s.b. length is incorrect, because it didn't take the internal @@ -131,8 +132,8 @@ public final class Code extends Attribute { super(Const.ATTR_CODE, nameIndex, length, constantPool); this.maxStack = Args.requireU2(maxStack, "maxStack"); this.maxLocals = Args.requireU2(maxLocals, "maxLocals"); - this.code = code != null ? code : Const.EMPTY_BYTE_ARRAY; - this.exceptionTable = exceptionTable != null ? exceptionTable : CodeException.EMPTY_CODE_EXCEPTION_ARRAY; + this.code = Utils.createEmptyArrayIfNull(code); + this.exceptionTable = Utils.createEmptyArrayIfNull(exceptionTable, CodeException[].class); Args.requireU2(this.exceptionTable.length, "exceptionTable.length"); this.attributes = attributes != null ? attributes : EMPTY_ARRAY; super.setLength(calculateLength()); // Adjust length @@ -263,6 +264,20 @@ public final class Code extends Attribute { return null; } + /** + * Gets the local variable type table attribute {@link LocalVariableTypeTable}. + * @return LocalVariableTypeTable of Code, if it has one, null otherwise. + * @since 6.10.0 + */ + public LocalVariableTypeTable getLocalVariableTypeTable() { + for (final Attribute attribute : attributes) { + if (attribute instanceof LocalVariableTypeTable) { + return (LocalVariableTypeTable) attribute; + } + } + return null; + } + /** * @return Number of local variables. */ @@ -277,6 +292,20 @@ public final class Code extends Attribute { return maxStack; } + /** + * Finds the attribute of {@link StackMap} instance. + * @return StackMap of Code, if it has one, else null. + * @since 6.8.0 + */ + public StackMap getStackMap() { + for (final Attribute attribute : attributes) { + if (attribute instanceof StackMap) { + return (StackMap) attribute; + } + } + return null; + } + /** * @param attributes the attributes to set for this Code */ @@ -289,7 +318,7 @@ public final class Code extends Attribute { * @param code byte code */ public void setCode(final byte[] code) { - this.code = code != null ? code : Const.EMPTY_BYTE_ARRAY; + this.code = Utils.createEmptyArrayIfNull(code); super.setLength(calculateLength()); // Adjust length } @@ -297,7 +326,7 @@ public final class Code extends Attribute { * @param exceptionTable exception table */ public void setExceptionTable(final CodeException[] exceptionTable) { - this.exceptionTable = exceptionTable != null ? exceptionTable : CodeException.EMPTY_CODE_EXCEPTION_ARRAY; + this.exceptionTable = exceptionTable != null ? exceptionTable : CodeException.EMPTY_ARRAY; super.setLength(calculateLength()); // Adjust length } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/CodeException.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/CodeException.java index ee224e6b348..b8bf109239e 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/CodeException.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/CodeException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -52,19 +52,19 @@ import com.sun.org.apache.bcel.internal.util.Args; * * * @see Code - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public final class CodeException implements Cloneable, Node { /** * Empty array. */ - static final CodeException[] EMPTY_CODE_EXCEPTION_ARRAY = {}; + static final CodeException[] EMPTY_ARRAY = {}; /** Range in the code the exception handler. */ private int startPc; - /** active. startPc is inclusive, endPc exclusive. */ + /** Active. startPc is inclusive, endPc exclusive. */ private int endPc; /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Constant.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Constant.java index 885e1b599eb..9b3d6f31e17 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Constant.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Constant.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -32,30 +32,29 @@ import com.sun.org.apache.bcel.internal.util.BCELComparator; * in the constant pool of a class file. The classes keep closely to * the JVM specification. * - * @LastModified: May 2021 + * @LastModified: Sept 2025 */ public abstract class Constant implements Cloneable, Node { - private static BCELComparator bcelComparator = new BCELComparator() { + static final Constant[] EMPTY_ARRAY = {}; + + private static BCELComparator bcelComparator = new BCELComparator() { @Override - public boolean equals(final Object o1, final Object o2) { - final Constant THIS = (Constant) o1; - final Constant THAT = (Constant) o2; - return Objects.equals(THIS.toString(), THAT.toString()); + public boolean equals(final Constant a, final Constant b) { + return a == b || a != null && b != null && Objects.equals(a.toString(), b.toString()); } @Override - public int hashCode(final Object o) { - final Constant THIS = (Constant) o; - return THIS.toString().hashCode(); + public int hashCode(final Constant o) { + return o != null ? Objects.hashCode(o.toString()) : 0; } }; /** - * @return Comparison strategy object + * @return Comparison strategy object. */ - public static BCELComparator getComparator() { + public static BCELComparator getComparator() { return bcelComparator; } @@ -113,7 +112,7 @@ public abstract class Constant implements Cloneable, Node { /** * @param comparator Comparison strategy object */ - public static void setComparator(final BCELComparator comparator) { + public static void setComparator(final BCELComparator comparator) { bcelComparator = comparator; } @@ -148,7 +147,7 @@ public abstract class Constant implements Cloneable, Node { try { return super.clone(); } catch (final CloneNotSupportedException e) { - throw new Error("Clone Not Supported"); // never happens + throw new UnsupportedOperationException("Clone Not Supported", e); // never happens } } @@ -174,7 +173,7 @@ public abstract class Constant implements Cloneable, Node { */ @Override public boolean equals(final Object obj) { - return bcelComparator.equals(this, obj); + return obj instanceof Constant && bcelComparator.equals(this, (Constant) obj); } /** @@ -185,7 +184,7 @@ public abstract class Constant implements Cloneable, Node { } /** - * Returns value as defined by given BCELComparator strategy. By default return the hashcode of the result of + * Returns value as defined by given BCELComparator strategy. By default return the hash code of the result of * toString(). * * @see Object#hashCode() diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantCP.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantCP.java index 71fd91b249a..51113a1aeaa 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantCP.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantCP.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -28,11 +28,11 @@ import com.sun.org.apache.bcel.internal.Const; /** * Abstract super class for Fieldref, Methodref, InterfaceMethodref and InvokeDynamic constants. * - * @see ConstantFieldref - * @see ConstantMethodref - * @see ConstantInterfaceMethodref - * @see ConstantInvokeDynamic - * @LastModified: Jun 2019 + * @see ConstantFieldref + * @see ConstantMethodref + * @see ConstantInterfaceMethodref + * @see ConstantInvokeDynamic + * @LastModified: Sept 2025 */ public abstract class ConstantCP extends Constant { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantDouble.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantDouble.java index ebb3d0af46a..14b43937c92 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantDouble.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantDouble.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -29,8 +29,8 @@ import com.sun.org.apache.bcel.internal.Const; /** * This class is derived from the abstract {@link Constant} and represents a reference to a Double object. * - * @see Constant - * @LastModified: Jun 2019 + * @see Constant + * @LastModified: Sept 2025 */ public final class ConstantDouble extends Constant implements ConstantObject { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantFloat.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantFloat.java index 9c30c9e4fdb..e86bbb94e66 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantFloat.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantFloat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -29,8 +29,8 @@ import com.sun.org.apache.bcel.internal.Const; /** * This class is derived from the abstract {@link Constant} and represents a reference to a float object. * - * @see Constant - * @LastModified: Jun 2019 + * @see Constant + * @LastModified: Sept 2025 */ public final class ConstantFloat extends Constant implements ConstantObject { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantInteger.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantInteger.java index cabd2e15b03..20c0717acb6 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantInteger.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantInteger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -29,8 +29,8 @@ import com.sun.org.apache.bcel.internal.Const; /** * This class is derived from the abstract {@link Constant} and represents a reference to an int object. * - * @see Constant - * @LastModified: Jun 2019 + * @see Constant + * @LastModified: Sept 2025 */ public final class ConstantInteger extends Constant implements ConstantObject { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantLong.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantLong.java index c1e683abadb..6936162c264 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantLong.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantLong.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -29,8 +29,8 @@ import com.sun.org.apache.bcel.internal.Const; /** * This class is derived from the abstract {@link Constant} and represents a reference to a long object. * - * @see Constant - * @LastModified: Jan 2020 + * @see Constant + * @LastModified: Sept 2025 */ public final class ConstantLong extends Constant implements ConstantObject { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantObject.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantObject.java index cb28f7dacb8..ab187b7e4f8 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantObject.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantObject.java @@ -29,7 +29,10 @@ package com.sun.org.apache.bcel.internal.classfile; public interface ConstantObject { /** - * @return object representing the constant, e.g., Long for ConstantLong + * Gets the object representing the constant, e.g., Long for ConstantLong. + * + * @param constantPool the constant. + * @return object representing the constant, e.g., Long for ConstantLong. */ - Object getConstantValue(ConstantPool cp); + Object getConstantValue(ConstantPool constantPool); } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantPool.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantPool.java index 5fb4ef1b080..ae1e3977c99 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantPool.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantPool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -35,7 +35,7 @@ import com.sun.org.apache.bcel.internal.Const; * * @see Constant * @see com.sun.org.apache.bcel.internal.generic.ConstantPoolGen - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public class ConstantPool implements Cloneable, Node, Iterable { @@ -73,7 +73,7 @@ public class ConstantPool implements Cloneable, Node, Iterable { * @param constantPool Array of constants */ public ConstantPool(final Constant[] constantPool) { - this.constantPool = constantPool; + setConstantPool(constantPool); } /** @@ -88,6 +88,7 @@ public class ConstantPool implements Cloneable, Node, Iterable { constantPool = new Constant[constantPoolCount]; /* * constantPool[0] is unused by the compiler and may be used freely by the implementation. + * constantPool[0] is currently unused by the implementation. */ for (int i = 1; i < constantPoolCount; i++) { constantPool[i] = Constant.readConstant(input); @@ -288,7 +289,7 @@ public class ConstantPool implements Cloneable, Node, Iterable { */ public T getConstant(final int index, final byte tag, final Class castTo) throws ClassFormatException { final T c = getConstant(index); - if (c.getTag() != tag) { + if (c == null || c.getTag() != tag) { throw new ClassFormatException("Expected class '" + Const.getConstantName(tag) + "' at index " + index + " and got " + c); } return c; @@ -313,15 +314,17 @@ public class ConstantPool implements Cloneable, Node, Iterable { throw new ClassFormatException("Invalid constant pool reference at index: " + index + ". Expected " + castTo + " but was " + constantPool[index].getClass()); } + if (index > 1) { + final Constant prev = constantPool[index - 1]; + if (prev != null && (prev.getTag() == Const.CONSTANT_Double || prev.getTag() == Const.CONSTANT_Long)) { + throw new ClassFormatException("Constant pool at index " + index + " is invalid. The index is unused due to the preceeding " + + Const.getConstantName(prev.getTag()) + "."); + } + } // Previous check ensures this won't throw a ClassCastException final T c = castTo.cast(constantPool[index]); - if (c == null - // the 0th element is always null - && index != 0) { - final Constant prev = constantPool[index - 1]; - if (prev == null || prev.getTag() != Const.CONSTANT_Double && prev.getTag() != Const.CONSTANT_Long) { - throw new ClassFormatException("Constant pool at index " + index + " is null."); - } + if (c == null) { + throw new ClassFormatException("Constant pool at index " + index + " is null."); } return c; } @@ -402,7 +405,7 @@ public class ConstantPool implements Cloneable, Node, Iterable { * @return Length of constant pool. */ public int getLength() { - return constantPool == null ? 0 : constantPool.length; + return constantPool.length; } @Override @@ -421,7 +424,7 @@ public class ConstantPool implements Cloneable, Node, Iterable { * @param constantPool */ public void setConstantPool(final Constant[] constantPool) { - this.constantPool = constantPool; + this.constantPool = constantPool != null ? constantPool : Constant.EMPTY_ARRAY; } /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantUtf8.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantUtf8.java index ec875554c1a..90e45c807e5 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantUtf8.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantUtf8.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -36,11 +36,11 @@ import com.sun.org.apache.bcel.internal.Const; * The following system properties govern caching this class performs. *

*
    - *
  • {@value #SYS_PROP_CACHE_MAX_ENTRIES} (since 6.4): The size of the cache, by default 0, meaning caching is + *
  • {@link #SYS_PROP_CACHE_MAX_ENTRIES} (since 6.4): The size of the cache, by default 0, meaning caching is * disabled.
  • - *
  • {@value #SYS_PROP_CACHE_MAX_ENTRY_SIZE} (since 6.0): The maximum size of the values to cache, by default 200, 0 + *
  • {@link #SYS_PROP_CACHE_MAX_ENTRY_SIZE} (since 6.0): The maximum size of the values to cache, by default 200, 0 * disables caching. Values larger than this are not cached.
  • - *
  • {@value #SYS_PROP_STATISTICS} (since 6.0): Prints statistics on the console when the JVM exits.
  • + *
  • {@link #SYS_PROP_STATISTICS} (since 6.0): Prints statistics on the console when the JVM exits.
  • *
*

* Here is a sample Maven invocation with caching disabled: @@ -58,11 +58,11 @@ import com.sun.org.apache.bcel.internal.Const; * * * @see Constant - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public final class ConstantUtf8 extends Constant { - private static class Cache { + private static final class Cache { private static final boolean BCEL_STATISTICS = false; private static final int MAX_ENTRIES = 20000; @@ -82,7 +82,7 @@ public final class ConstantUtf8 extends Constant { private static final int MAX_ENTRY_SIZE = 200; static boolean isEnabled() { - return Cache.MAX_ENTRIES > 0 && MAX_ENTRY_SIZE > 0; + return MAX_ENTRIES > 0 && MAX_ENTRY_SIZE > 0; } } @@ -117,6 +117,11 @@ public final class ConstantUtf8 extends Constant { hits = considered = skipped = created = 0; } + // Avoid Spotbugs complaint about Write to static field + private static void countCreated() { + created++; + } + /** * Gets a new or cached instance of the given value. *

@@ -203,7 +208,7 @@ public final class ConstantUtf8 extends Constant { ConstantUtf8(final DataInput dataInput) throws IOException { super(Const.CONSTANT_Utf8); value = dataInput.readUTF(); - created++; + countCreated(); } /** @@ -212,7 +217,7 @@ public final class ConstantUtf8 extends Constant { public ConstantUtf8(final String value) { super(Const.CONSTANT_Utf8); this.value = Objects.requireNonNull(value, "value"); - created++; + countCreated(); } /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantValue.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantValue.java index 311e9a33fa3..143c2a25544 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantValue.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantValue.java @@ -56,7 +56,7 @@ public final class ConstantValue extends Attribute { } /** - * Construct object from input stream. + * Constructs object from input stream. * * @param nameIndex Name index in constant pool * @param length Content length in bytes diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Deprecated.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Deprecated.java index 90841d96081..c561afe33c5 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Deprecated.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Deprecated.java @@ -59,7 +59,7 @@ public final class Deprecated extends Attribute { } /** - * Construct object from input stream. + * Constructs object from input stream. * * @param nameIndex Index in constant pool to CONSTANT_Utf8 * @param length Content length in bytes diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/DescendingVisitor.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/DescendingVisitor.java index 3c475891acd..934b608d6ac 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/DescendingVisitor.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/DescendingVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -22,12 +22,13 @@ package com.sun.org.apache.bcel.internal.classfile; import java.util.Objects; import java.util.Stack; import java.util.stream.Stream; +import jdk.xml.internal.Utils; /** - * Traverses a JavaClass with another Visitor object 'piggy-backed' that is - * applied to all components of a JavaClass object. I.e. this class supplies the - * traversal strategy, other classes can make use of it. + * Traverses a JavaClass with another Visitor object 'piggy-backed' that is applied to all components of a JavaClass + * object. I.e. this class supplies the traversal strategy, other classes can make use of it. * + * @LastModified: Sept 2025 */ public class DescendingVisitor implements Visitor { private final JavaClass clazz; @@ -46,7 +47,7 @@ public class DescendingVisitor implements Visitor { } private void accept(final E[] node) { - Stream.of(node).forEach(e -> e.accept(this)); + Utils.streamOfIfNonNull(node).forEach(e -> e.accept(this)); } /** @@ -507,6 +508,21 @@ public class DescendingVisitor implements Visitor { stack.pop(); } + @Override + public void visitRecord(final Record record) { + stack.push(record); + record.accept(visitor); + accept(record.getComponents()); + stack.pop(); + } + + @Override + public void visitRecordComponent(final RecordComponentInfo recordComponentInfo) { + stack.push(recordComponentInfo); + recordComponentInfo.accept(visitor); + stack.pop(); + } + @Override public void visitSignature(final Signature attribute) { stack.push(attribute); @@ -531,6 +547,20 @@ public class DescendingVisitor implements Visitor { @Override public void visitStackMapEntry(final StackMapEntry var) { + stack.push(var); + var.accept(visitor); + accept(var.getTypesOfLocals()); + accept(var.getTypesOfStackItems()); + stack.pop(); + } + + /** + * Visits a {@link StackMapType} object. + * @param var object to visit + * @since 6.8.0 + */ + @Override + public void visitStackMapType(final StackMapType var) { stack.push(var); var.accept(visitor); stack.pop(); @@ -549,4 +579,5 @@ public class DescendingVisitor implements Visitor { attribute.accept(visitor); stack.pop(); } + } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ElementValue.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ElementValue.java index 5c3d9b3172b..d87307c0e7d 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ElementValue.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ElementValue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -50,7 +50,7 @@ import com.sun.org.apache.bcel.internal.Const; *} * * @since 6.0 - * @LastModified: May 2021 + * @LastModified: Sept 2025 */ public abstract class ElementValue { @@ -67,6 +67,7 @@ public abstract class ElementValue { public static final byte PRIMITIVE_LONG = 'J'; public static final byte PRIMITIVE_SHORT = 'S'; public static final byte PRIMITIVE_BOOLEAN = 'Z'; + static final ElementValue[] EMPTY_ARRAY = {}; /** * Reads an {@code element_value} as an {@code ElementValue}. @@ -124,7 +125,7 @@ public abstract class ElementValue { final int numArrayVals = input.readUnsignedShort(); final ElementValue[] evalues = new ElementValue[numArrayVals]; for (int j = 0; j < numArrayVals; j++) { - evalues[j] = ElementValue.readElementValue(input, cpool, arrayNesting); + evalues[j] = readElementValue(input, cpool, arrayNesting); } return new ArrayElementValue(ARRAY, evalues, cpool); diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/EmptyVisitor.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/EmptyVisitor.java index 826ba41af70..db33c871656 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/EmptyVisitor.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/EmptyVisitor.java @@ -315,6 +315,15 @@ public class EmptyVisitor implements Visitor { public void visitStackMapEntry(final StackMapEntry obj) { } + /** + * Visits a {@link StackMapType} object. + * @param obj object to visit + * @since 6.8.0 + */ + @Override + public void visitStackMapType(final StackMapType obj) { + } + @Override public void visitSynthetic(final Synthetic obj) { } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ExceptionTable.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ExceptionTable.java index 90eaa3eb062..1b6004b3740 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ExceptionTable.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ExceptionTable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -27,6 +27,7 @@ import java.util.Arrays; import com.sun.org.apache.bcel.internal.Const; import com.sun.org.apache.bcel.internal.util.Args; +import jdk.xml.internal.Utils; /** * This class represents the table of exceptions that are thrown by a method. This attribute may be used once per @@ -43,7 +44,7 @@ import com.sun.org.apache.bcel.internal.util.Args; * } * * @see Code - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public final class ExceptionTable extends Attribute { @@ -60,7 +61,7 @@ public final class ExceptionTable extends Attribute { } /** - * Construct object from input stream. + * Constructs object from input stream. * * @param nameIndex Index in constant pool * @param length Content length in bytes @@ -85,7 +86,7 @@ public final class ExceptionTable extends Attribute { */ public ExceptionTable(final int nameIndex, final int length, final int[] exceptionIndexTable, final ConstantPool constantPool) { super(Const.ATTR_EXCEPTIONS, nameIndex, length, constantPool); - this.exceptionIndexTable = exceptionIndexTable != null ? exceptionIndexTable : Const.EMPTY_INT_ARRAY; + this.exceptionIndexTable = Utils.createEmptyArrayIfNull(exceptionIndexTable); Args.requireU2(this.exceptionIndexTable.length, "exceptionIndexTable.length"); } @@ -156,7 +157,7 @@ public final class ExceptionTable extends Attribute { * length. */ public void setExceptionIndexTable(final int[] exceptionIndexTable) { - this.exceptionIndexTable = exceptionIndexTable != null ? exceptionIndexTable : Const.EMPTY_INT_ARRAY; + this.exceptionIndexTable = Utils.createEmptyArrayIfNull(exceptionIndexTable); } /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Field.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Field.java index 7e6ccb2ecb5..8ffc796a0ea 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Field.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Field.java @@ -42,45 +42,37 @@ public final class Field extends FieldOrMethod { */ public static final Field[] EMPTY_ARRAY = {}; - private static BCELComparator bcelComparator = new BCELComparator() { + private static BCELComparator bcelComparator = new BCELComparator() { @Override - public boolean equals(final Object o1, final Object o2) { - final Field THIS = (Field) o1; - final Field THAT = (Field) o2; - return Objects.equals(THIS.getName(), THAT.getName()) && Objects.equals(THIS.getSignature(), THAT.getSignature()); + public boolean equals(final Field a, final Field b) { + return a == b || a != null && b != null && Objects.equals(a.getName(), b.getName()) && Objects.equals(a.getSignature(), b.getSignature()); } @Override - public int hashCode(final Object o) { - final Field THIS = (Field) o; - return THIS.getSignature().hashCode() ^ THIS.getName().hashCode(); + public int hashCode(final Field o) { + return o != null ? Objects.hash(o.getSignature(), o.getName()) : 0; } }; /** - * Empty array. + * @return Comparison strategy object. */ - static final Field[] EMPTY_FIELD_ARRAY = {}; - - /** - * @return Comparison strategy object - */ - public static BCELComparator getComparator() { + public static BCELComparator getComparator() { return bcelComparator; } /** - * @param comparator Comparison strategy object + * @param comparator Comparison strategy object. */ - public static void setComparator(final BCELComparator comparator) { + public static void setComparator(final BCELComparator comparator) { bcelComparator = comparator; } /** - * Construct object from file stream. + * Constructs object from file stream. * - * @param file Input stream + * @param file Input stream. */ Field(final DataInput file, final ConstantPool constantPool) throws IOException, ClassFormatException { super(file, constantPool); @@ -133,7 +125,7 @@ public final class Field extends FieldOrMethod { */ @Override public boolean equals(final Object obj) { - return bcelComparator.equals(this, obj); + return obj instanceof Field && bcelComparator.equals(this, (Field) obj); } /** @@ -149,14 +141,16 @@ public final class Field extends FieldOrMethod { } /** + * See https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.2.2 + * * @return type of field */ public Type getType() { - return Type.getReturnType(getSignature()); + return Type.getType(getSignature()); } /** - * Return value as defined by given BCELComparator strategy. By default return the hashcode of the field's name XOR + * Return value as defined by given BCELComparator strategy. By default return the hash code of the field's name XOR * signature. * * @see Object#hashCode() diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/FieldOrMethod.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/FieldOrMethod.java index 1daa6a62fd5..679d5a9eb7c 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/FieldOrMethod.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/FieldOrMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -28,7 +28,7 @@ import java.util.Arrays; /** * Abstract super class for fields and methods. * - * @LastModified: Jan 2020 + * @LastModified: Sept 2025 */ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, Node { @@ -72,7 +72,7 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No } /** - * Construct object from file stream. + * Constructs object from file stream. * * @param file Input stream * @throws IOException if an I/O error occurs. @@ -88,7 +88,7 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No } /** - * Construct object from file stream. + * Constructs object from file stream. * * @param file Input stream * @throws IOException if an I/O error occurs. @@ -137,7 +137,7 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No Arrays.setAll(c.attributes, i -> attributes[i].copy(constantPool)); return c; } catch (final CloneNotSupportedException e) { - throw new IllegalStateException(e); + throw new UnsupportedOperationException(e); } } @@ -152,10 +152,8 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No file.writeShort(name_index); file.writeShort(signature_index); file.writeShort(attributes_count); - if (attributes != null) { - for (final Attribute attribute : attributes) { - attribute.dump(file); - } + for (final Attribute attribute : attributes) { + attribute.dump(file); } } @@ -171,6 +169,22 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No return annotationEntries; } + /** + * Gets attribute for given tag. + * @return Attribute for given tag, null if not found. + * Refer to {@link com.sun.org.apache.bcel.internal.Const#ATTR_UNKNOWN} constants named ATTR_* for possible values. + * @since 6.10.0 + */ + @SuppressWarnings("unchecked") + public final T getAttribute(final byte tag) { + for (final Attribute attribute : getAttributes()) { + if (attribute.getTag() == tag) { + return (T) attribute; + } + } + return null; + } + /** * @return Collection of object attributes. */ @@ -221,7 +235,7 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No } /** - * @return String representation of object's type signature (java style) + * @return String representation of object's type signature (Java style) */ public final String getSignature() { return constant_pool.getConstantUtf8(signature_index).getBytes(); @@ -238,8 +252,8 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No * @param attributes Collection of object attributes. */ public final void setAttributes(final Attribute[] attributes) { - this.attributes = attributes; - this.attributes_count = attributes != null ? attributes.length : 0; // init deprecated field + this.attributes = attributes != null ? attributes : Attribute.EMPTY_ARRAY; + this.attributes_count = this.attributes.length; // init deprecated field } /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/InnerClass.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/InnerClass.java index d77582815b7..82900dcca10 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/InnerClass.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/InnerClass.java @@ -41,7 +41,7 @@ public final class InnerClass implements Cloneable, Node { private int innerAccessFlags; /** - * Construct object from file stream. + * Constructs object from file stream. * * @param file Input stream * @throws IOException if an I/O error occurs. diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/InnerClasses.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/InnerClasses.java index 2295ca5c625..b61be1effa0 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/InnerClasses.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/InnerClasses.java @@ -42,7 +42,7 @@ public final class InnerClasses extends Attribute implements IterableClassGen class. * * @see com.sun.org.apache.bcel.internal.generic.ClassGen - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparable { @@ -67,26 +68,23 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl public static final byte HEAP = 1; public static final byte FILE = 2; public static final byte ZIP = 3; - private static BCELComparator bcelComparator = new BCELComparator() { + private static BCELComparator bcelComparator = new BCELComparator() { @Override - public boolean equals(final Object o1, final Object o2) { - final JavaClass THIS = (JavaClass) o1; - final JavaClass THAT = (JavaClass) o2; - return Objects.equals(THIS.getClassName(), THAT.getClassName()); + public boolean equals(final JavaClass a, final JavaClass b) { + return a == b || a != null && b != null && Objects.equals(a.getClassName(), b.getClassName()); } @Override - public int hashCode(final Object o) { - final JavaClass THIS = (JavaClass) o; - return THIS.getClassName().hashCode(); + public int hashCode(final JavaClass o) { + return o != null ? Objects.hashCode(o.getClassName()) : 0; } }; /** - * @return Comparison strategy object + * @return Comparison strategy object. */ - public static BCELComparator getComparator() { + public static BCELComparator getComparator() { return bcelComparator; } @@ -100,9 +98,9 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl } /** - * @param comparator Comparison strategy object + * @param comparator Comparison strategy object. */ - public static void setComparator(final BCELComparator comparator) { + public static void setComparator(final BCELComparator comparator) { bcelComparator = comparator; } @@ -128,8 +126,10 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl private boolean isAnonymous; private boolean isNested; + private boolean isRecord; private boolean computedNestedTypeStatus; + private boolean computedRecord; /** * In cases where we go ahead and create something, use the default SyntheticRepository, because we don't know any @@ -177,17 +177,15 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl public JavaClass(final int classNameIndex, final int superclassNameIndex, final String fileName, final int major, final int minor, final int accessFlags, final ConstantPool constantPool, int[] interfaces, Field[] fields, Method[] methods, Attribute[] attributes, final byte source) { super(accessFlags); - if (interfaces == null) { - interfaces = Const.EMPTY_INT_ARRAY; - } + interfaces = Utils.createEmptyArrayIfNull(interfaces); if (attributes == null) { attributes = Attribute.EMPTY_ARRAY; } if (fields == null) { - fields = Field.EMPTY_FIELD_ARRAY; + fields = Field.EMPTY_ARRAY; } if (methods == null) { - methods = Method.EMPTY_METHOD_ARRAY; + methods = Method.EMPTY_ARRAY; } this.classNameIndex = classNameIndex; this.superclassNameIndex = superclassNameIndex; @@ -254,6 +252,19 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl return getClassName().compareTo(obj.getClassName()); } + private void computeIsRecord() { + if (computedRecord) { + return; + } + for (final Attribute attribute : this.attributes) { + if (attribute instanceof Record) { + isRecord = true; + break; + } + } + this.computedRecord = true; + } + private void computeNestedTypeStatus() { if (computedNestedTypeStatus) { return; @@ -384,11 +395,51 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl */ @Override public boolean equals(final Object obj) { - return bcelComparator.equals(this, obj); + return obj instanceof JavaClass && bcelComparator.equals(this, (JavaClass) obj); } /** - * Get all interfaces implemented by this JavaClass (transitively). + * Finds a visible field by name and type in this class and its super classes. + * @param fieldName the field name to find + * @param fieldType the field type to find + * @return field matching given name and type, null if field is not found or not accessible from this class. + * @throws ClassNotFoundException + * @since 6.8.0 + */ + public Field findField(final String fieldName, final Type fieldType) throws ClassNotFoundException { + for (final Field field : fields) { + if (field.getName().equals(fieldName)) { + final Type fType = Type.getType(field.getSignature()); + /* + * TODO: Check if assignment compatibility is sufficient. What does Sun do? + */ + if (fType.equals(fieldType)) { + return field; + } + } + } + + final JavaClass superclass = getSuperClass(); + if (superclass != null && !"java.lang.Object".equals(superclass.getClassName())) { + final Field f = superclass.findField(fieldName, fieldType); + if (f != null && (f.isPublic() || f.isProtected() || !f.isPrivate() && packageName.equals(superclass.getPackageName()))) { + return f; + } + } + final JavaClass[] implementedInterfaces = getInterfaces(); + if (implementedInterfaces != null) { + for (final JavaClass implementedInterface : implementedInterfaces) { + final Field f = implementedInterface.findField(fieldName, fieldType); + if (f != null) { + return f; + } + } + } + return null; + } + + /** + * Gets all interfaces implemented by this JavaClass (transitively). * * @throws ClassNotFoundException if any of the class's superclasses or interfaces can't be found. */ @@ -409,7 +460,7 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl queue.enqueue(iface); } } - return allInterfaces.toArray(JavaClass.EMPTY_ARRAY); + return allInterfaces.toArray(EMPTY_ARRAY); } /** @@ -424,6 +475,22 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl return annotations; } + /** + * Gets attribute for given tag. + * @return Attribute for given tag, null if not found. + * Refer to {@link com.sun.org.apache.bcel.internal.Const#ATTR_UNKNOWN} constants named ATTR_* for possible values. + * @since 6.10.0 + */ + @SuppressWarnings("unchecked") + public final T getAttribute(final byte tag) { + for (final Attribute attribute : getAttributes()) { + if (attribute.getTag() == tag) { + return (T) attribute; + } + } + return null; + } + /** * @return Attributes of the class. */ @@ -495,7 +562,7 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl } /** - * Get interfaces directly implemented by this JavaClass. + * Gets interfaces directly implemented by this JavaClass. * * @throws ClassNotFoundException if any of the class's interfaces can't be found. */ @@ -587,7 +654,7 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl } /** - * @return the superclass for this JavaClass object, or null if this is java.lang.Object + * @return the superclass for this JavaClass object, or null if this is {@link Object} * @throws ClassNotFoundException if the superclass can't be found */ public JavaClass getSuperClass() throws ClassNotFoundException { @@ -607,12 +674,12 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl for (clazz = clazz.getSuperClass(); clazz != null; clazz = clazz.getSuperClass()) { allSuperClasses.add(clazz); } - return allSuperClasses.toArray(JavaClass.EMPTY_ARRAY); + return allSuperClasses.toArray(EMPTY_ARRAY); } /** - * returns the super class name of this class. In the case that this class is java.lang.Object, it will return itself - * (java.lang.Object). This is probably incorrect but isn't fixed at this time to not break existing clients. + * returns the super class name of this class. In the case that this class is {@link Object}, it will return itself + * ({@link Object}). This is probably incorrect but isn't fixed at this time to not break existing clients. * * @return Superclass name. */ @@ -628,7 +695,7 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl } /** - * Return value as defined by given BCELComparator strategy. By default return the hashcode of the class name. + * Return value as defined by given BCELComparator strategy. By default return the hash code of the class name. * * @see Object#hashCode() */ @@ -645,7 +712,7 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl if (!inter.isInterface()) { throw new IllegalArgumentException(inter.getClassName() + " is no interface"); } - if (this.equals(inter)) { + if (equals(inter)) { return true; } final JavaClass[] superInterfaces = getAllInterfaces(); @@ -664,7 +731,7 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl * @throws ClassNotFoundException if superclasses or superinterfaces of this object can't be found */ public final boolean instanceOf(final JavaClass superclass) throws ClassNotFoundException { - if (this.equals(superclass)) { + if (equals(superclass)) { return true; } for (final JavaClass clazz : getSuperClasses()) { @@ -698,6 +765,17 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl return this.isNested; } + /** + * Tests whether this class was declared as a record + * + * @return true if a record attribute is present, false otherwise. + * @since 6.9.0 + */ + public boolean isRecord() { + computeIsRecord(); + return this.isRecord; + } + public final boolean isSuper() { return (super.getAccessFlags() & Const.ACC_SUPER) != 0; } @@ -706,7 +784,7 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl * @param attributes . */ public void setAttributes(final Attribute[] attributes) { - this.attributes = attributes; + this.attributes = attributes != null ? attributes : Attribute.EMPTY_ARRAY; } /** @@ -734,11 +812,11 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl * @param fields . */ public void setFields(final Field[] fields) { - this.fields = fields; + this.fields = fields != null ? fields : Field.EMPTY_ARRAY; } /** - * Set File name of class, aka SourceFile attribute value + * Sets File name of class, aka SourceFile attribute value */ public void setFileName(final String fileName) { this.fileName = fileName; @@ -748,14 +826,14 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl * @param interfaceNames . */ public void setInterfaceNames(final String[] interfaceNames) { - this.interfaceNames = interfaceNames; + this.interfaceNames = Utils.createEmptyArrayIfNull(interfaceNames, String[].class); } /** * @param interfaces . */ public void setInterfaces(final int[] interfaces) { - this.interfaces = interfaces; + this.interfaces = Utils.createEmptyArrayIfNull(interfaces); } /** @@ -769,7 +847,7 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl * @param methods . */ public void setMethods(final Method[] methods) { - this.methods = methods; + this.methods = methods != null ? methods : Method.EMPTY_ARRAY; } /** @@ -787,7 +865,7 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl } /** - * Set absolute path to file this class was read from. + * Sets absolute path to file this class was read from. */ public void setSourceFileName(final String sourceFileName) { this.sourceFileName = sourceFileName; diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/LineNumber.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/LineNumber.java index 4380d04bc06..dc41ad065f8 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/LineNumber.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/LineNumber.java @@ -40,11 +40,11 @@ public final class LineNumber implements Cloneable, Node { /** Program Counter (PC) corresponds to line */ private int startPc; - /** number in source file */ + /** Number in source file */ private int lineNumber; /** - * Construct object from file stream. + * Constructs object from file stream. * * @param file Input stream * @throws IOException if an I/O Exception occurs in readUnsignedShort diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/LineNumberTable.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/LineNumberTable.java index 6251fc514cc..96541f309bd 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/LineNumberTable.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/LineNumberTable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -36,7 +36,7 @@ import jdk.xml.internal.SecuritySupport; * * @see Code * @see LineNumber - * @LastModified: May 2021 + * @LastModified: Sept 2025 */ public final class LineNumberTable extends Attribute implements Iterable { @@ -44,7 +44,7 @@ public final class LineNumberTable extends Attribute implements Iterable + * Note that both objects use the same references (shallow copy). Use copy() for a physical copy. + *

*/ public LineNumberTable(final LineNumberTable c) { this(c.getNameIndex(), c.getLength(), c.getLineNumberTable(), c.getConstantPool()); @@ -190,7 +191,7 @@ public final class LineNumberTable extends Attribute implements Iterable { + private static final LocalVariable[] EMPTY_ARRAY = {}; + private LocalVariable[] localVariableTable; // variables /** - * Construct object from input stream. + * Constructs object from input stream. * * @param nameIndex Index in constant pool * @param length Content length in bytes @@ -68,7 +70,7 @@ public class LocalVariableTable extends Attribute implements Iterable { + private static final LocalVariable[] EMPTY_ARRAY = {}; + private LocalVariable[] localVariableTypeTable; // variables LocalVariableTypeTable(final int nameIdx, final int len, final DataInput input, final ConstantPool cpool) throws IOException { this(nameIdx, len, (LocalVariable[]) null, cpool); - final int localVariableTypeTableLength = input.readUnsignedShort(); localVariableTypeTable = new LocalVariable[localVariableTypeTableLength]; - for (int i = 0; i < localVariableTypeTableLength; i++) { localVariableTypeTable[i] = new LocalVariable(input, cpool); } @@ -97,7 +97,6 @@ public class LocalVariableTypeTable extends Attribute implements Iterable localVariableTypeTable[i].copy()); c.setConstantPool(constantPool); @@ -119,7 +118,6 @@ public class LocalVariableTypeTable extends Attribute implements Iterable bcelComparator = new BCELComparator() { @Override - public boolean equals(final Object o1, final Object o2) { - final Method THIS = (Method) o1; - final Method THAT = (Method) o2; - return Objects.equals(THIS.getName(), THAT.getName()) && Objects.equals(THIS.getSignature(), THAT.getSignature()); + public boolean equals(final Method a, final Method b) { + return a == b || a != null && b != null && Objects.equals(a.getName(), b.getName()) && Objects.equals(a.getSignature(), b.getSignature()); } @Override - public int hashCode(final Object o) { - final Method THIS = (Method) o; - return THIS.getSignature().hashCode() ^ THIS.getName().hashCode(); + public int hashCode(final Method o) { + return o != null ? Objects.hash(o.getSignature(), o.getName()) : 0; } }; /** - * Empty array. + * @return Comparison strategy object. */ - static final Method[] EMPTY_METHOD_ARRAY = {}; - - /** - * @return Comparison strategy object - */ - public static BCELComparator getComparator() { + public static BCELComparator getComparator() { return bcelComparator; } /** - * @param comparator Comparison strategy object + * @param comparator Comparison strategy object. */ - public static void setComparator(final BCELComparator comparator) { + public static void setComparator(final BCELComparator comparator) { bcelComparator = comparator; } - // annotations defined on the parameters of a method + /** Annotations defined on the parameters of a method. */ private ParameterAnnotationEntry[] parameterAnnotationEntries; /** @@ -85,7 +77,7 @@ public final class Method extends FieldOrMethod { } /** - * Construct object from file stream. + * Constructs object from file stream. * * @param file Input stream * @throws IOException if an I/O error occurs. @@ -142,7 +134,7 @@ public final class Method extends FieldOrMethod { */ @Override public boolean equals(final Object obj) { - return bcelComparator.equals(this, obj); + return obj instanceof Method && bcelComparator.equals(this, (Method) obj); } /** @@ -189,7 +181,7 @@ public final class Method extends FieldOrMethod { } /** - * @return LocalVariableTable of code attribute if any, i.e. the call is forwarded to the Code atribute. + * @return LocalVariableTable of code attribute if any, i.e. the call is forwarded to the Code attribute. */ public LocalVariableTable getLocalVariableTable() { final Code code = getCode(); @@ -199,6 +191,19 @@ public final class Method extends FieldOrMethod { return code.getLocalVariableTable(); } + /** + * Gets the local variable type table attribute {@link LocalVariableTypeTable}. + * @return LocalVariableTypeTable of code attribute if any, i.e. the call is forwarded to the Code attribute. + * @since 6.10.0 + */ + public LocalVariableTypeTable getLocalVariableTypeTable() { + final Code code = getCode(); + if (code == null) { + return null; + } + return code.getLocalVariableTypeTable(); + } + /** * @return Annotations on the parameters of a method * @since 6.0 @@ -218,7 +223,7 @@ public final class Method extends FieldOrMethod { } /** - * Return value as defined by given BCELComparator strategy. By default return the hashcode of the method's name XOR + * Return value as defined by given BCELComparator strategy. By default return the hash code of the method's name XOR * signature. * * @see Object#hashCode() diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/MethodParameter.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/MethodParameter.java index ffc1a20f80a..865e154d334 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/MethodParameter.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/MethodParameter.java @@ -29,6 +29,9 @@ import com.sun.org.apache.bcel.internal.Const; /** * Entry of the parameters table. + *

+ * Implements {@link Node} as of 6.7.0. + *

* * @see The class File Format : * The MethodParameters Attribute @@ -46,7 +49,7 @@ public class MethodParameter implements Cloneable, Node { } /** - * Construct object from input stream. + * Constructs an instance from a DataInput. * * @param input Input stream * @throws IOException if an I/O error occurs. @@ -75,7 +78,7 @@ public class MethodParameter implements Cloneable, Node { } /** - * Dump object to file stream on binary format. + * Dumps object to file stream on binary format. * * @param file Output file stream * @throws IOException if an I/O error occurs. @@ -94,7 +97,10 @@ public class MethodParameter implements Cloneable, Node { } /** - * Returns the name of the parameter. + * Gets the name of the parameter. + * + * @param constantPool The pool to query. + * @return Constant from the given pool. */ public String getParameterName(final ConstantPool constantPool) { if (nameIndex == 0) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/MethodParameters.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/MethodParameters.java index 5b5d1d77f6f..2f5bffd8d3c 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/MethodParameters.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/MethodParameters.java @@ -42,13 +42,12 @@ public class MethodParameters extends Attribute implements Iterable parameters[i].copy()); c.setConstantPool(constantPool); return c; @@ -96,6 +94,6 @@ public class MethodParameters extends Attribute implements IterableAttribute and represents the list of packages that are exported or opened by the * Module attribute. There may be at most one ModulePackages attribute in a ClassFile structure. * * @see Attribute - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public final class ModulePackages extends Attribute { private int[] packageIndexTable; /** - * Construct object from input stream. + * Constructs object from input stream. * * @param nameIndex Index in constant pool * @param length Content length in bytes @@ -65,7 +66,7 @@ public final class ModulePackages extends Attribute { */ public ModulePackages(final int nameIndex, final int length, final int[] packageIndexTable, final ConstantPool constantPool) { super(Const.ATTR_MODULE_PACKAGES, nameIndex, length, constantPool); - this.packageIndexTable = packageIndexTable != null ? packageIndexTable : Const.EMPTY_INT_ARRAY; + this.packageIndexTable = Utils.createEmptyArrayIfNull(packageIndexTable); Args.requireU2(this.packageIndexTable.length, "packageIndexTable.length"); } @@ -145,7 +146,7 @@ public final class ModulePackages extends Attribute { * @param packageIndexTable the list of package indexes Also redefines number_of_packages according to table length. */ public void setPackageIndexTable(final int[] packageIndexTable) { - this.packageIndexTable = packageIndexTable != null ? packageIndexTable : Const.EMPTY_INT_ARRAY; + this.packageIndexTable = Utils.createEmptyArrayIfNull(packageIndexTable); } /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModuleProvides.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModuleProvides.java index f6c6058dfbb..490e9cd5d44 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModuleProvides.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModuleProvides.java @@ -36,12 +36,20 @@ import com.sun.org.apache.bcel.internal.Const; */ public final class ModuleProvides implements Cloneable, Node { + private static String getImplementationClassNameAtIndex(final ConstantPool constantPool, final int index, final boolean compactClassName) { + final String className = constantPool.getConstantString(index, Const.CONSTANT_Class); + if (compactClassName) { + return Utility.compactClassName(className, false); + } + return className; + } private final int providesIndex; // points to CONSTANT_Class_info private final int providesWithCount; + private final int[] providesWithIndex; // points to CONSTANT_Class_info /** - * Construct object from file stream. + * Constructs object from file stream. * * @param file Input stream * @throws IOException if an I/O Exception occurs in readUnsignedShort @@ -66,8 +74,6 @@ public final class ModuleProvides implements Cloneable, Node { v.visitModuleProvides(this); } - // TODO add more getters and setters? - /** * @return deep copy of this object */ @@ -94,6 +100,31 @@ public final class ModuleProvides implements Cloneable, Node { } } + /** + * Gets the array of implementation class names for this ModuleProvides. + * @param constantPool Array of constants usually obtained from the ClassFile object + * @param compactClassName false for original constant pool value, true to replace '/' with '.' + * @return array of implementation class names + * @since 6.10.0 + */ + public String[] getImplementationClassNames(final ConstantPool constantPool, final boolean compactClassName) { + final String[] implementationClassNames = new String[providesWithCount]; + for (int i = 0; i < providesWithCount; i++) { + implementationClassNames[i] = getImplementationClassNameAtIndex(constantPool, providesWithIndex[i], compactClassName); + } + return implementationClassNames; + } + + /** + * Gets the interface name for this ModuleProvides. + * @param constantPool Array of constants usually obtained from the ClassFile object + * @return interface name + * @since 6.10.0 + */ + public String getInterfaceName(final ConstantPool constantPool) { + return constantPool.constantToString(providesIndex, Const.CONSTANT_Class); + } + /** * @return String representation */ @@ -107,12 +138,12 @@ public final class ModuleProvides implements Cloneable, Node { */ public String toString(final ConstantPool constantPool) { final StringBuilder buf = new StringBuilder(); - final String interfaceName = constantPool.constantToString(providesIndex, Const.CONSTANT_Class); - buf.append(Utility.compactClassName(interfaceName, false)); + final String interfaceName = getInterfaceName(constantPool); + buf.append(interfaceName); buf.append(", with(").append(providesWithCount).append("):\n"); for (final int index : providesWithIndex) { - final String className = constantPool.getConstantString(index, Const.CONSTANT_Class); - buf.append(" ").append(Utility.compactClassName(className, false)).append("\n"); + final String className = getImplementationClassNameAtIndex(constantPool, index, true); + buf.append(" ").append(className).append("\n"); } return buf.substring(0, buf.length() - 1); // remove the last newline } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModuleRequires.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModuleRequires.java index c9c26c20649..3149a18290b 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModuleRequires.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModuleRequires.java @@ -41,7 +41,7 @@ public final class ModuleRequires implements Cloneable, Node { private final int requiresVersionIndex; // either 0 or points to CONSTANT_Utf8_info /** - * Construct object from file stream. + * Constructs object from file stream. * * @param file Input stream * @throws IOException if an I/O Exception occurs in readUnsignedShort @@ -63,8 +63,6 @@ public final class ModuleRequires implements Cloneable, Node { v.visitModuleRequires(this); } - // TODO add more getters and setters? - /** * @return deep copy of this object */ @@ -89,6 +87,35 @@ public final class ModuleRequires implements Cloneable, Node { file.writeShort(requiresVersionIndex); } + /** + * Gets the module name from the constant pool. + * @param constantPool Array of constants usually obtained from the ClassFile object + * @return module name + * @since 6.10.0 + */ + public String getModuleName(final ConstantPool constantPool) { + return constantPool.constantToString(requiresIndex, Const.CONSTANT_Module); + } + + /** + * Gets the flags for this ModuleRequires. + * @return the requiresFlags + * @since 6.10.0 + */ + public int getRequiresFlags() { + return requiresFlags; + } + + /** + * Gets the required version from the constant pool. + * @param constantPool Array of constants usually obtained from the ClassFile object + * @return required version, "0" if version index is 0. + * @since 6.10.0 + */ + public String getVersion(final ConstantPool constantPool) { + return requiresVersionIndex == 0 ? "0" : constantPool.getConstantString(requiresVersionIndex, Const.CONSTANT_Utf8); + } + /** * @return String representation */ @@ -102,10 +129,10 @@ public final class ModuleRequires implements Cloneable, Node { */ public String toString(final ConstantPool constantPool) { final StringBuilder buf = new StringBuilder(); - final String moduleName = constantPool.constantToString(requiresIndex, Const.CONSTANT_Module); - buf.append(Utility.compactClassName(moduleName, false)); + final String moduleName = getModuleName(constantPool); + buf.append(moduleName); buf.append(", ").append(String.format("%04x", requiresFlags)); - final String version = requiresVersionIndex == 0 ? "0" : constantPool.getConstantString(requiresVersionIndex, Const.CONSTANT_Utf8); + final String version = getVersion(constantPool); buf.append(", ").append(version); return buf.toString(); } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/NestMembers.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/NestMembers.java index 05d982ca6e8..261f57d98a8 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/NestMembers.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/NestMembers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -27,6 +27,7 @@ import java.util.Arrays; import com.sun.org.apache.bcel.internal.Const; import com.sun.org.apache.bcel.internal.util.Args; +import jdk.xml.internal.Utils; /** * This class is derived from Attribute and records the classes and interfaces that are authorized to claim @@ -34,14 +35,14 @@ import com.sun.org.apache.bcel.internal.util.Args; * ClassFile structure. * * @see Attribute - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public final class NestMembers extends Attribute { private int[] classes; /** - * Construct object from input stream. + * Constructs object from input stream. * * @param nameIndex Index in constant pool * @param length Content length in bytes @@ -66,7 +67,7 @@ public final class NestMembers extends Attribute { */ public NestMembers(final int nameIndex, final int length, final int[] classes, final ConstantPool constantPool) { super(Const.ATTR_NEST_MEMBERS, nameIndex, length, constantPool); - this.classes = classes != null ? classes : Const.EMPTY_INT_ARRAY; + this.classes = Utils.createEmptyArrayIfNull(classes); Args.requireU2(this.classes.length, "classes.length"); } @@ -146,7 +147,7 @@ public final class NestMembers extends Attribute { * @param classes the list of class indexes Also redefines number_of_classes according to table length. */ public void setClasses(final int[] classes) { - this.classes = classes != null ? classes : Const.EMPTY_INT_ARRAY; + this.classes = Utils.createEmptyArrayIfNull(classes); } /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Node.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Node.java index c0395732d79..792ef31cb72 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Node.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Node.java @@ -26,5 +26,5 @@ package com.sun.org.apache.bcel.internal.classfile; */ public interface Node { - void accept(Visitor obj); + void accept(Visitor visitor); } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/PMGClass.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/PMGClass.java index 9b1dd4c7b41..b7b5e1f1d99 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/PMGClass.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/PMGClass.java @@ -38,7 +38,7 @@ public final class PMGClass extends Attribute { private int pmgIndex; /** - * Construct object from input stream. + * Constructs object from input stream. * * @param nameIndex Index in constant pool to CONSTANT_Utf8 * @param length Content length in bytes diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ParameterAnnotationEntry.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ParameterAnnotationEntry.java index a3070fa7e0c..6ebe60c8049 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ParameterAnnotationEntry.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ParameterAnnotationEntry.java @@ -37,22 +37,28 @@ public class ParameterAnnotationEntry implements Node { static final ParameterAnnotationEntry[] EMPTY_ARRAY = {}; - public static ParameterAnnotationEntry[] createParameterAnnotationEntries(final Attribute[] attrs) { + public static ParameterAnnotationEntry[] createParameterAnnotationEntries(final Attribute[] attributes) { + if (attributes == null) { + return EMPTY_ARRAY; + } // Find attributes that contain parameter annotation data - final List accumulatedAnnotations = new ArrayList<>(attrs.length); - for (final Attribute attribute : attrs) { + final List accumulatedAnnotations = new ArrayList<>(attributes.length); + for (final Attribute attribute : attributes) { if (attribute instanceof ParameterAnnotations) { final ParameterAnnotations runtimeAnnotations = (ParameterAnnotations) attribute; - Collections.addAll(accumulatedAnnotations, runtimeAnnotations.getParameterAnnotationEntries()); + final ParameterAnnotationEntry[] parameterAnnotationEntries = runtimeAnnotations.getParameterAnnotationEntries(); + if (parameterAnnotationEntries != null) { + Collections.addAll(accumulatedAnnotations, parameterAnnotationEntries); + } } } - return accumulatedAnnotations.toArray(ParameterAnnotationEntry.EMPTY_ARRAY); + return accumulatedAnnotations.toArray(EMPTY_ARRAY); } private final AnnotationEntry[] annotationTable; /** - * Construct object from input stream. + * Constructs object from input stream. * * @param input Input stream * @throws IOException if an I/O error occurs. diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ParameterAnnotations.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ParameterAnnotations.java index 4817793120f..1e056b5d4f8 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ParameterAnnotations.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ParameterAnnotations.java @@ -34,10 +34,14 @@ import java.util.stream.Stream; */ public abstract class ParameterAnnotations extends Attribute implements Iterable { + private static final ParameterAnnotationEntry[] EMPTY_ARRAY = {}; + /** Table of parameter annotations */ private ParameterAnnotationEntry[] parameterAnnotationTable; /** + * Constructs a new instance. + * * @param parameterAnnotationType the subclass type of the parameter annotation * @param nameIndex Index pointing to the name Code * @param length Content length in bytes @@ -55,6 +59,8 @@ public abstract class ParameterAnnotations extends Attribute implements Iterable } /** + * Constructs a new instance. + * * @param parameterAnnotationType the subclass type of the parameter annotation * @param nameIndex Index pointing to the name Code * @param length Content length in bytes @@ -120,6 +126,6 @@ public abstract class ParameterAnnotations extends Attribute implements Iterable * @param parameterAnnotationTable the entries to set in this parameter annotation */ public final void setParameterAnnotationTable(final ParameterAnnotationEntry[] parameterAnnotationTable) { - this.parameterAnnotationTable = parameterAnnotationTable; + this.parameterAnnotationTable = parameterAnnotationTable != null ? parameterAnnotationTable : EMPTY_ARRAY; } } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Record.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Record.java new file mode 100644 index 00000000000..f59cfa37ca4 --- /dev/null +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Record.java @@ -0,0 +1,153 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.sun.org.apache.bcel.internal.classfile; + +import java.io.DataInput; +import java.io.DataOutputStream; +import java.io.IOException; + +import com.sun.org.apache.bcel.internal.Const; +import com.sun.org.apache.bcel.internal.util.Args; + +/** + * Extends {@link Attribute} and records the classes and + * interfaces that are authorized to claim membership in the nest hosted by the + * current class or interface. There may be at most one Record attribute in a + * ClassFile structure. + * + * @see Attribute + * @since 6.9.0 + */ +public final class Record extends Attribute { + + private static final RecordComponentInfo[] EMPTY_RCI_ARRAY = {}; + + private static RecordComponentInfo[] readComponents(final DataInput input, final ConstantPool constantPool) + throws IOException { + final int classCount = input.readUnsignedShort(); + final RecordComponentInfo[] components = new RecordComponentInfo[classCount]; + for (int i = 0; i < classCount; i++) { + components[i] = new RecordComponentInfo(input, constantPool); + } + return components; + } + + private RecordComponentInfo[] components; + + /** + * Constructs object from input stream. + * + * @param nameIndex Index in constant pool + * @param length Content length in bytes + * @param input Input stream + * @param constantPool Array of constants + * @throws IOException if an I/O error occurs. + */ + Record(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) + throws IOException { + this(nameIndex, length, readComponents(input, constantPool), constantPool); + } + + /** + * Constructs a new instance using components. + * + * @param nameIndex Index in constant pool + * @param length Content length in bytes + * @param classes Array of Record Component Info elements + * @param constantPool Array of constants + */ + public Record(final int nameIndex, final int length, final RecordComponentInfo[] classes, + final ConstantPool constantPool) { + super(Const.ATTR_RECORD, nameIndex, length, constantPool); + this.components = classes != null ? classes : EMPTY_RCI_ARRAY; + Args.requireU2(this.components.length, "attributes.length"); + } + + /** + * Called by objects that are traversing the nodes of the tree implicitly + * defined by the contents of a Java class. For example, the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + @Override + public void accept(final Visitor v) { + v.visitRecord(this); + } + + /** + * Copies this instance and its components. + * + * @return a deep copy of this instance and its components. + */ + @Override + public Attribute copy(final ConstantPool constantPool) { + final Record c = (Record) clone(); + if (components.length > 0) { + c.components = components.clone(); + } + c.setConstantPool(constantPool); + return c; + } + + /** + * Dumps this instance into a file stream in binary format. + * + * @param file output stream. + * @throws IOException if an I/O error occurs. + */ + @Override + public void dump(final DataOutputStream file) throws IOException { + super.dump(file); + file.writeShort(components.length); + for (final RecordComponentInfo component : components) { + component.dump(file); + } + } + + /** + * Gets all the record components. + * + * @return array of Record Component Info elements. + */ + public RecordComponentInfo[] getComponents() { + return components; + } + + /** + * Converts this instance to a String suitable for debugging. + * + * @return String a String suitable for debugging. + */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder(); + buf.append("Record("); + buf.append(components.length); + buf.append("):\n"); + for (final RecordComponentInfo component : components) { + buf.append(" ").append(component.toString()).append("\n"); + } + return buf.substring(0, buf.length() - 1); // remove the last newline + } + +} diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RecordComponentInfo.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RecordComponentInfo.java new file mode 100644 index 00000000000..3679647d409 --- /dev/null +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RecordComponentInfo.java @@ -0,0 +1,139 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.sun.org.apache.bcel.internal.classfile; + +import java.io.DataInput; +import java.io.DataOutputStream; +import java.io.IOException; + +import com.sun.org.apache.bcel.internal.Const; + +/** + * Record component info from a record. Instances from this class maps + * every component from a given record. + * + * @see + * The Java Virtual Machine Specification, Java SE 14 Edition, Records (preview) + * @since 6.9.0 + */ +public class RecordComponentInfo implements Node { + + private final int index; + private final int descriptorIndex; + private final Attribute[] attributes; + private final ConstantPool constantPool; + + /** + * Constructs a new instance from an input stream. + * + * @param input Input stream + * @param constantPool Array of constants + * @throws IOException if an I/O error occurs. + */ + public RecordComponentInfo(final DataInput input, final ConstantPool constantPool) throws IOException { + this.index = input.readUnsignedShort(); + this.descriptorIndex = input.readUnsignedShort(); + final int attributesCount = input.readUnsignedShort(); + this.attributes = new Attribute[attributesCount]; + for (int j = 0; j < attributesCount; j++) { + attributes[j] = Attribute.readAttribute(input, constantPool); + } + this.constantPool = constantPool; + } + + @Override + public void accept(final Visitor v) { + v.visitRecordComponent(this); + } + + /** + * Dumps contents into a file stream in binary format. + * + * @param file Output file stream + * @throws IOException if an I/O error occurs. + */ + public void dump(final DataOutputStream file) throws IOException { + file.writeShort(index); + file.writeShort(descriptorIndex); + file.writeShort(attributes.length); + for (final Attribute attribute : attributes) { + attribute.dump(file); + } + } + + /** + * Gets all attributes. + * + * @return all attributes. + */ + public Attribute[] getAttributes() { + return attributes; + } + + /** + * Gets the constant pool. + * + * @return Constant pool. + */ + public ConstantPool getConstantPool() { + return constantPool; + } + + /** + * Gets the description index. + * + * @return index in constant pool of this record component descriptor. + */ + public int getDescriptorIndex() { + return descriptorIndex; + } + + /** + * Gets the name index. + * + * @return index in constant pool of this record component name. + */ + public int getIndex() { + return index; + } + + /** + * Converts this instance to a String suitable for debugging. + * + * @return a String suitable for debugging. + */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder(); + buf.append("RecordComponentInfo("); + buf.append(constantPool.getConstantString(index, Const.CONSTANT_Utf8)); + buf.append(","); + buf.append(constantPool.getConstantString(descriptorIndex, Const.CONSTANT_Utf8)); + buf.append(","); + buf.append(attributes.length); + buf.append("):\n"); + for (final Attribute attribute : attributes) { + buf.append(" ").append(attribute.toString()).append("\n"); + } + return buf.substring(0, buf.length() - 1); // remove the last newline + } + +} diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeInvisibleAnnotations.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeInvisibleAnnotations.java index 7afb8719559..7a7c539f15a 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeInvisibleAnnotations.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeInvisibleAnnotations.java @@ -28,13 +28,15 @@ import java.io.IOException; import com.sun.org.apache.bcel.internal.Const; /** - * represents an annotation that is represented in the class file but is not provided to the JVM. + * An annotation that is represented in the class file but is not provided to the JVM. * * @since 6.0 */ public class RuntimeInvisibleAnnotations extends Annotations { /** + * Constructs a new instance. + * * @param nameIndex Index pointing to the name Code * @param length Content length in bytes * @param input Input stream @@ -46,7 +48,9 @@ public class RuntimeInvisibleAnnotations extends Annotations { } /** - * @return deep copy of this attribute + * Creates a deep copy of this attribute. + * + * @return deep copy of this attribute. */ @Override public Attribute copy(final ConstantPool constantPool) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeInvisibleParameterAnnotations.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeInvisibleParameterAnnotations.java index e4c3276f968..3d50ce16d40 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeInvisibleParameterAnnotations.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeInvisibleParameterAnnotations.java @@ -34,6 +34,8 @@ import com.sun.org.apache.bcel.internal.Const; public class RuntimeInvisibleParameterAnnotations extends ParameterAnnotations { /** + * Constructs a new instance. + * * @param nameIndex Index pointing to the name Code * @param length Content length in bytes * @param input Input stream diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeVisibleAnnotations.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeVisibleAnnotations.java index c91c77387b9..4bf8e6f7197 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeVisibleAnnotations.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeVisibleAnnotations.java @@ -28,13 +28,15 @@ import java.io.IOException; import com.sun.org.apache.bcel.internal.Const; /** - * represents an annotation that is represented in the class file and is provided to the JVM. + * An annotation that is represented in the class file and is provided to the JVM. * * @since 6.0 */ public class RuntimeVisibleAnnotations extends Annotations { /** + * Constructs a new instance. + * * @param nameIndex Index pointing to the name Code * @param length Content length in bytes * @param input Input stream @@ -46,7 +48,9 @@ public class RuntimeVisibleAnnotations extends Annotations { } /** - * @return deep copy of this attribute + * Creates a deep copy of this attribute. + * + * @return deep copy of this attribute. */ @Override public Attribute copy(final ConstantPool constantPool) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeVisibleParameterAnnotations.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeVisibleParameterAnnotations.java index 7e5d7eaaca3..ab5355235f6 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeVisibleParameterAnnotations.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeVisibleParameterAnnotations.java @@ -34,6 +34,8 @@ import com.sun.org.apache.bcel.internal.Const; public class RuntimeVisibleParameterAnnotations extends ParameterAnnotations { /** + * Constructs a new instance. + * * @param nameIndex Index pointing to the name Code * @param length Content length in bytes * @param input Input stream diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Signature.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Signature.java index 4f5d3a341b3..2161bbcb6ec 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Signature.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Signature.java @@ -110,7 +110,7 @@ public final class Signature extends Attribute { if ((ch = in.read()) == -1) { throw new IllegalArgumentException("Illegal signature: " + in.getData() + " no ident, reaching EOF"); } - // System.out.println("return from ident:" + (char)ch); + // System.out.println("return from ident:" + (char) ch); if (!identStart(ch)) { final StringBuilder buf2 = new StringBuilder(); int count = 1; @@ -128,7 +128,7 @@ public final class Signature extends Attribute { buf.append(buf2); ch = in.read(); in.unread(); - // System.out.println("so far:" + buf2 + ":next:" +(char)ch); + // System.out.println("so far:" + buf2 + ":next:" +(char) ch); } else { for (int i = 0; i < count; i++) { in.unread(); @@ -141,10 +141,10 @@ public final class Signature extends Attribute { do { buf2.append((char) ch); ch = in.read(); - // System.out.println("within ident:"+ (char)ch); + // System.out.println("within ident:"+ (char) ch); } while (ch != -1 && (Character.isJavaIdentifierPart((char) ch) || ch == '/')); buf.append(Utility.pathToPackage(buf2.toString())); - // System.out.println("regular return ident:"+ (char)ch + ":" + buf2); + // System.out.println("regular return ident:"+ (char) ch + ":" + buf2); if (ch != -1) { in.unread(); } @@ -160,7 +160,7 @@ public final class Signature extends Attribute { private int signatureIndex; /** - * Construct object from file stream. + * Constructs object from file stream. * * @param nameIndex Index in constant pool to CONSTANT_Utf8 * @param length Content length in bytes diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/SimpleElementValue.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/SimpleElementValue.java index 5e4e98d94df..e3e1cf40031 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/SimpleElementValue.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/SimpleElementValue.java @@ -54,7 +54,7 @@ public class SimpleElementValue extends ElementValue { dos.writeShort(getIndex()); break; default: - throw new ClassFormatException("SimpleElementValue doesnt know how to write out type " + type); + throw new ClassFormatException("SimpleElementValue doesn't know how to write out type " + type); } } @@ -67,7 +67,7 @@ public class SimpleElementValue extends ElementValue { public boolean getValueBoolean() { if (super.getType() != PRIMITIVE_BOOLEAN) { - throw new IllegalStateException("Dont call getValueBoolean() on a non BOOLEAN ElementValue"); + throw new IllegalStateException("Don't call getValueBoolean() on a non BOOLEAN ElementValue"); } final ConstantInteger bo = (ConstantInteger) super.getConstantPool().getConstant(getIndex()); return bo.getBytes() != 0; @@ -75,21 +75,21 @@ public class SimpleElementValue extends ElementValue { public byte getValueByte() { if (super.getType() != PRIMITIVE_BYTE) { - throw new IllegalStateException("Dont call getValueByte() on a non BYTE ElementValue"); + throw new IllegalStateException("Don't call getValueByte() on a non BYTE ElementValue"); } return (byte) super.getConstantPool().getConstantInteger(getIndex()).getBytes(); } public char getValueChar() { if (super.getType() != PRIMITIVE_CHAR) { - throw new IllegalStateException("Dont call getValueChar() on a non CHAR ElementValue"); + throw new IllegalStateException("Don't call getValueChar() on a non CHAR ElementValue"); } return (char) super.getConstantPool().getConstantInteger(getIndex()).getBytes(); } public double getValueDouble() { if (super.getType() != PRIMITIVE_DOUBLE) { - throw new IllegalStateException("Dont call getValueDouble() on a non DOUBLE ElementValue"); + throw new IllegalStateException("Don't call getValueDouble() on a non DOUBLE ElementValue"); } final ConstantDouble d = (ConstantDouble) super.getConstantPool().getConstant(getIndex()); return d.getBytes(); @@ -97,7 +97,7 @@ public class SimpleElementValue extends ElementValue { public float getValueFloat() { if (super.getType() != PRIMITIVE_FLOAT) { - throw new IllegalStateException("Dont call getValueFloat() on a non FLOAT ElementValue"); + throw new IllegalStateException("Don't call getValueFloat() on a non FLOAT ElementValue"); } final ConstantFloat f = (ConstantFloat) super.getConstantPool().getConstant(getIndex()); return f.getBytes(); @@ -105,14 +105,14 @@ public class SimpleElementValue extends ElementValue { public int getValueInt() { if (super.getType() != PRIMITIVE_INT) { - throw new IllegalStateException("Dont call getValueInt() on a non INT ElementValue"); + throw new IllegalStateException("Don't call getValueInt() on a non INT ElementValue"); } return super.getConstantPool().getConstantInteger(getIndex()).getBytes(); } public long getValueLong() { if (super.getType() != PRIMITIVE_LONG) { - throw new IllegalStateException("Dont call getValueLong() on a non LONG ElementValue"); + throw new IllegalStateException("Don't call getValueLong() on a non LONG ElementValue"); } final ConstantLong j = (ConstantLong) super.getConstantPool().getConstant(getIndex()); return j.getBytes(); @@ -120,7 +120,7 @@ public class SimpleElementValue extends ElementValue { public short getValueShort() { if (super.getType() != PRIMITIVE_SHORT) { - throw new IllegalStateException("Dont call getValueShort() on a non SHORT ElementValue"); + throw new IllegalStateException("Don't call getValueShort() on a non SHORT ElementValue"); } final ConstantInteger s = (ConstantInteger) super.getConstantPool().getConstant(getIndex()); return (short) s.getBytes(); @@ -128,7 +128,7 @@ public class SimpleElementValue extends ElementValue { public String getValueString() { if (super.getType() != STRING) { - throw new IllegalStateException("Dont call getValueString() on a non STRING ElementValue"); + throw new IllegalStateException("Don't call getValueString() on a non STRING ElementValue"); } return super.getConstantPool().getConstantUtf8(getIndex()).getBytes(); } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/SourceFile.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/SourceFile.java index e9ceed21957..bfa9cbf8fcb 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/SourceFile.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/SourceFile.java @@ -40,7 +40,7 @@ public final class SourceFile extends Attribute { private int sourceFileIndex; /** - * Construct object from input stream. + * Constructs object from input stream. * * @param nameIndex Index in constant pool to CONSTANT_Utf8 * @param length Content length in bytes diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/StackMap.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/StackMap.java index 1f8ce5ea410..317638e6b2d 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/StackMap.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/StackMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -30,8 +30,8 @@ import com.sun.org.apache.bcel.internal.util.Args; /** * This class represents a stack map attribute used for preverification of Java classes for the - * Java 2 Micro Edition (J2ME). This attribute is used by the - * KVM and contained within the Code attribute of a method. See CLDC + * Java 2 Micro Edition (J2ME). This attribute is used by the + * KVM and contained within the Code attribute of a method. See CLDC * specification 5.3.1.2 * *
@@ -46,14 +46,14 @@ import com.sun.org.apache.bcel.internal.util.Args;
  * @see Code
  * @see StackMapEntry
  * @see StackMapType
- * @LastModified: Oct 2020
+ * @LastModified: Sept 2025
  */
 public final class StackMap extends Attribute {
 
     private StackMapEntry[] table; // Table of stack map entries
 
     /**
-     * Construct object from input stream.
+     * Constructs object from input stream.
      *
      * @param nameIndex Index of name
      * @param length Content length in bytes
diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/StackMapEntry.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/StackMapEntry.java
index 110e30392ab..015083dd066 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/StackMapEntry.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/StackMapEntry.java
@@ -59,7 +59,7 @@ public final class StackMapEntry implements Node, Cloneable {
     private ConstantPool constantPool;
 
     /**
-     * Construct object from input stream.
+     * Constructs object from input stream.
      *
      * @param dataInput Input stream
      * @throws IOException if an I/O error occurs.
@@ -75,9 +75,7 @@ public final class StackMapEntry implements Node, Cloneable {
         } else if (frameType == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
             byteCodeOffset = dataInput.readUnsignedShort();
             typesOfStackItems = new StackMapType[] { new StackMapType(dataInput, constantPool) };
-        } else if (frameType >= Const.CHOP_FRAME && frameType <= Const.CHOP_FRAME_MAX) {
-            byteCodeOffset = dataInput.readUnsignedShort();
-        } else if (frameType == Const.SAME_FRAME_EXTENDED) {
+        } else if (frameType >= Const.CHOP_FRAME && frameType <= Const.CHOP_FRAME_MAX || frameType == Const.SAME_FRAME_EXTENDED) {
             byteCodeOffset = dataInput.readUnsignedShort();
         } else if (frameType >= Const.APPEND_FRAME && frameType <= Const.APPEND_FRAME_MAX) {
             byteCodeOffset = dataInput.readUnsignedShort();
@@ -167,7 +165,7 @@ public final class StackMapEntry implements Node, Cloneable {
         try {
             e = (StackMapEntry) clone();
         } catch (final CloneNotSupportedException ex) {
-            throw new Error("Clone Not Supported");
+            throw new UnsupportedOperationException("Clone Not Supported", ex);
         }
 
         e.typesOfLocals = new StackMapType[typesOfLocals.length];
@@ -190,9 +188,7 @@ public final class StackMapEntry implements Node, Cloneable {
         } else if (frameType == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
             file.writeShort(byteCodeOffset);
             typesOfStackItems[0].dump(file);
-        } else if (frameType >= Const.CHOP_FRAME && frameType <= Const.CHOP_FRAME_MAX) {
-            file.writeShort(byteCodeOffset);
-        } else if (frameType == Const.SAME_FRAME_EXTENDED) {
+        } else if (frameType >= Const.CHOP_FRAME && frameType <= Const.CHOP_FRAME_MAX || frameType == Const.SAME_FRAME_EXTENDED) {
             file.writeShort(byteCodeOffset);
         } else if (frameType >= Const.APPEND_FRAME && frameType <= Const.APPEND_FRAME_MAX) {
             file.writeShort(byteCodeOffset);
@@ -232,7 +228,6 @@ public final class StackMapEntry implements Node, Cloneable {
 
     /**
      * Calculate stack map entry size
-     *
      */
     int getMapEntrySize() {
         if (frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX) {
diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/StackMapType.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/StackMapType.java
index 4575b31dfce..b93066d53b7 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/StackMapType.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/StackMapType.java
@@ -34,9 +34,9 @@ import com.sun.org.apache.bcel.internal.Const;
  * @see StackMap
  * @see Const
  */
-public final class StackMapType implements Cloneable {
+public final class StackMapType implements Node, Cloneable {
 
-    public static final StackMapType[] EMPTY_ARRAY = {}; // must be public because BCELifier code generator writes calls to it
+    public static final StackMapType[] EMPTY_ARRAY = {}; // BCELifier code generator writes calls to constructor translating null to EMPTY_ARRAY
 
     private byte type;
     private int index = -1; // Index to CONSTANT_Class or offset
@@ -53,7 +53,7 @@ public final class StackMapType implements Cloneable {
     }
 
     /**
-     * Construct object from file stream.
+     * Constructs object from file stream.
      *
      * @param file Input stream
      * @throws IOException if an I/O error occurs.
@@ -66,6 +66,18 @@ public final class StackMapType implements Cloneable {
         this.constantPool = constantPool;
     }
 
+    /**
+     * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
+     * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
+     *
+     * @param v Visitor object
+     * @since 6.8.0
+     */
+    @Override
+    public void accept(final Visitor v) {
+        v.visitStackMapType(this);
+    }
+
     private byte checkType(final byte type) {
         if (type < Const.ITEM_Bogus || type > Const.ITEM_NewObject) {
             throw new ClassFormatException("Illegal type for StackMapType: " + type);
@@ -98,6 +110,15 @@ public final class StackMapType implements Cloneable {
         }
     }
 
+    /**
+     * Gets the class name of this StackMapType from the constant pool at index position.
+     * @return the fully qualified name of the class for this StackMapType.
+     * @since 6.8.0
+     */
+    public String getClassName() {
+        return constantPool.constantToString(index, Const.CONSTANT_Class);
+    }
+
     /**
      * @return Constant pool used by this object.
      */
@@ -129,7 +150,7 @@ public final class StackMapType implements Cloneable {
             if (index < 0) {
                 return ", class=";
             }
-            return ", class=" + constantPool.constantToString(index, Const.CONSTANT_Class);
+            return ", class=" + getClassName();
         }
         if (type == Const.ITEM_NewObject) {
             return ", offset=" + index;
diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Synthetic.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Synthetic.java
index 3683fd6437e..c7fef8fcebc 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Synthetic.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Synthetic.java
@@ -52,7 +52,7 @@ public final class Synthetic extends Attribute {
     }
 
     /**
-     * Construct object from input stream.
+     * Constructs object from input stream.
      *
      * @param nameIndex Index in constant pool to CONSTANT_Utf8
      * @param length Content length in bytes
diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Utility.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Utility.java
index 12dbbe4828a..6967dcefd94 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Utility.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Utility.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -43,7 +43,7 @@ import com.sun.org.apache.bcel.internal.util.ByteSequence;
 /**
  * Utility functions that do not really belong to any class in particular.
  *
- * @LastModified: Feb 2023
+ * @LastModified: Sept 2025
  */
 // @since 6.0 methods are no longer final
 public abstract class Utility {
@@ -51,7 +51,7 @@ public abstract class Utility {
     /**
      * Decode characters into bytes. Used by decode()
      */
-    private static class JavaReader extends FilterReader {
+    private static final class JavaReader extends FilterReader {
 
         public JavaReader(final Reader in) {
             super(in);
@@ -88,10 +88,10 @@ public abstract class Utility {
     }
 
     /**
-     * Encode bytes into valid java identifier characters. Used by
+     * Encode bytes into valid Java identifier characters. Used by
      * encode()
      */
-    private static class JavaWriter extends FilterWriter {
+    private static final class JavaWriter extends FilterWriter {
 
         public JavaWriter(final Writer out) {
             super(out);
@@ -437,7 +437,9 @@ public abstract class Utility {
         case Const.NEW:
         case Const.CHECKCAST:
             buf.append("\t");
-            //$FALL-THROUGH$
+            index = bytes.readUnsignedShort();
+            buf.append("\t<").append(constantPool.constantToString(index, Const.CONSTANT_Class)).append(">").append(verbose ? " (" + index + ")" : "");
+            break;
         case Const.INSTANCEOF:
             index = bytes.readUnsignedShort();
             buf.append("\t<").append(constantPool.constantToString(index, Const.CONSTANT_Class)).append(">").append(verbose ? " (" + index + ")" : "");
@@ -864,7 +866,7 @@ public abstract class Utility {
             // Skip any type arguments to read argument declarations between '(' and ')'
             index = signature.indexOf('(') + 1;
             if (index <= 0) {
-                throw new ClassFormatException("Invalid method signature: " + signature);
+                throw new InvalidMethodSignatureException(signature);
             }
             while (signature.charAt(index) != ')') {
                 vec.add(typeSignatureToString(signature.substring(index), chopit));
@@ -872,7 +874,7 @@ public abstract class Utility {
                 index += unwrap(CONSUMER_CHARS); // update position
             }
         } catch (final StringIndexOutOfBoundsException e) { // Should never occur
-            throw new ClassFormatException("Invalid method signature: " + signature, e);
+            throw new InvalidMethodSignatureException(signature, e);
         }
         return vec.toArray(Const.EMPTY_STRING_ARRAY);
     }
@@ -903,11 +905,11 @@ public abstract class Utility {
             // Read return type after ')'
             index = signature.lastIndexOf(')') + 1;
             if (index <= 0) {
-                throw new ClassFormatException("Invalid method signature: " + signature);
+                throw new InvalidMethodSignatureException(signature);
             }
             type = typeSignatureToString(signature.substring(index), chopit);
         } catch (final StringIndexOutOfBoundsException e) { // Should never occur
-            throw new ClassFormatException("Invalid method signature: " + signature, e);
+            throw new InvalidMethodSignatureException(signature, e);
         }
         return type;
     }
@@ -959,7 +961,7 @@ public abstract class Utility {
             // Skip any type arguments to read argument declarations between '(' and ')'
             index = signature.indexOf('(') + 1;
             if (index <= 0) {
-                throw new ClassFormatException("Invalid method signature: " + signature);
+                throw new InvalidMethodSignatureException(signature);
             }
             while (signature.charAt(index) != ')') {
                 final String paramType = typeSignatureToString(signature.substring(index), chopit);
@@ -985,7 +987,7 @@ public abstract class Utility {
             // Read return type after ')'
             type = typeSignatureToString(signature.substring(index), chopit);
         } catch (final StringIndexOutOfBoundsException e) { // Should never occur
-            throw new ClassFormatException("Invalid method signature: " + signature, e);
+            throw new InvalidMethodSignatureException(signature, e);
         }
         // ignore any throws information in the signature
         if (buf.length() > 1) {
@@ -1172,7 +1174,7 @@ public abstract class Utility {
             type = typeParams + typeSignaturesToString(signature.substring(index), chopit, ')');
             index += unwrap(CONSUMER_CHARS); // update position
             // add return type
-            type = type + typeSignatureToString(signature.substring(index), chopit);
+            type += typeSignatureToString(signature.substring(index), chopit);
             index += unwrap(CONSUMER_CHARS); // update position
             // ignore any throws information in the signature
             return type;
@@ -1237,12 +1239,12 @@ public abstract class Utility {
         int index;
         try {
             if (signature.charAt(0) != '(') {
-                throw new ClassFormatException("Invalid method signature: " + signature);
+                throw new InvalidMethodSignatureException(signature);
             }
             index = signature.lastIndexOf(')') + 1;
             return typeOfSignature(signature.substring(index));
         } catch (final StringIndexOutOfBoundsException e) {
-            throw new ClassFormatException("Invalid method signature: " + signature, e);
+            throw new InvalidMethodSignatureException(signature, e);
         }
     }
 
@@ -1286,10 +1288,10 @@ public abstract class Utility {
             case '*':
                 return typeOfSignature(signature.substring(1));
             default:
-                throw new ClassFormatException("Invalid method signature: " + signature);
+                throw new InvalidMethodSignatureException(signature);
             }
         } catch (final StringIndexOutOfBoundsException e) {
-            throw new ClassFormatException("Invalid method signature: " + signature, e);
+            throw new InvalidMethodSignatureException(signature, e);
         }
     }
 
@@ -1469,8 +1471,8 @@ public abstract class Utility {
                 } else {
                     type.append(typeSignatureToString(signature.substring(consumedChars), chopit));
                     // update our consumed count by the number of characters the for type argument
-                    consumedChars = unwrap(Utility.CONSUMER_CHARS) + consumedChars;
-                    wrap(Utility.CONSUMER_CHARS, consumedChars);
+                    consumedChars = unwrap(CONSUMER_CHARS) + consumedChars;
+                    wrap(CONSUMER_CHARS, consumedChars);
                 }
 
                 // are there more TypeArguments?
@@ -1490,8 +1492,8 @@ public abstract class Utility {
                     } else {
                         type.append(typeSignatureToString(signature.substring(consumedChars), chopit));
                         // update our consumed count by the number of characters the for type argument
-                        consumedChars = unwrap(Utility.CONSUMER_CHARS) + consumedChars;
-                        wrap(Utility.CONSUMER_CHARS, consumedChars);
+                        consumedChars = unwrap(CONSUMER_CHARS) + consumedChars;
+                        wrap(CONSUMER_CHARS, consumedChars);
                     }
                 }
 
@@ -1508,14 +1510,14 @@ public abstract class Utility {
                     // update our consumed count by the number of characters the for type argument
                     // note that this count includes the "L" we added, but that is ok
                     // as it accounts for the "." we didn't consume
-                    consumedChars = unwrap(Utility.CONSUMER_CHARS) + consumedChars;
-                    wrap(Utility.CONSUMER_CHARS, consumedChars);
+                    consumedChars = unwrap(CONSUMER_CHARS) + consumedChars;
+                    wrap(CONSUMER_CHARS, consumedChars);
                     return type.toString();
                 }
                 if (signature.charAt(consumedChars) != ';') {
                     throw new ClassFormatException("Invalid signature: " + signature);
                 }
-                wrap(Utility.CONSUMER_CHARS, consumedChars + 1); // remove final ";"
+                wrap(CONSUMER_CHARS, consumedChars + 1); // remove final ";"
                 return type.toString();
             }
             case 'S':
@@ -1536,9 +1538,9 @@ public abstract class Utility {
                 // The rest of the string denotes a ''
                 type = typeSignatureToString(signature.substring(n), chopit);
                 // corrected concurrent private static field acess
-                // Utility.consumed_chars += consumed_chars; is replaced by:
-                final int temp = unwrap(Utility.CONSUMER_CHARS) + consumedChars;
-                wrap(Utility.CONSUMER_CHARS, temp);
+                // consumed_chars += consumed_chars; is replaced by:
+                final int temp = unwrap(CONSUMER_CHARS) + consumedChars;
+                wrap(CONSUMER_CHARS, temp);
                 return type + brackets.toString();
             }
             case 'V':
@@ -1552,11 +1554,11 @@ public abstract class Utility {
     }
 
     private static int unwrap(final ThreadLocal tl) {
-        return tl.get();
+        return tl.get().intValue();
     }
 
     private static void wrap(final ThreadLocal tl, final int value) {
-        tl.set(value);
+        tl.set(Integer.valueOf(value));
     }
 
 }
diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Visitor.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Visitor.java
index 74cb8400d3e..1f6fe9c96ee 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Visitor.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Visitor.java
@@ -217,11 +217,32 @@ public interface Visitor {
      */
     void visitParameterAnnotation(ParameterAnnotations obj);
 
+
     /**
      * @since 6.0
      */
     void visitParameterAnnotationEntry(ParameterAnnotationEntry obj);
 
+    /**
+     * Visits a {@link Record} object.
+     *
+     * @param obj Record to visit
+     * @since 6.9.0
+     */
+    default void visitRecord(final Record obj) {
+        // empty
+    }
+
+    /**
+     * Visits a {@link RecordComponentInfo} object.
+     *
+     * @param record component to visit
+     * @since 6.9.0
+     */
+    default void visitRecordComponent(final RecordComponentInfo record) {
+     // noop
+    }
+
     void visitSignature(Signature obj);
 
     void visitSourceFile(SourceFile obj);
@@ -230,7 +251,18 @@ public interface Visitor {
 
     void visitStackMapEntry(StackMapEntry obj);
 
+    /**
+     * Visits a {@link StackMapType} object.
+     *
+     * @param obj object to visit
+     * @since 6.8.0
+     */
+    default void visitStackMapType(final StackMapType obj) {
+      // empty
+    }
+
     void visitSynthetic(Synthetic obj);
 
     void visitUnknown(Unknown obj);
+
 }
diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/package-info.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/package-info.java
new file mode 100644
index 00000000000..4e8d383bcab
--- /dev/null
+++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/package-info.java
@@ -0,0 +1,25 @@
+/*
+ * reserved comment block
+ * DO NOT REMOVE OR ALTER!
+ */
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * Classes that describe the structure of a Java class file and a class file parser.
+ */
+package com.sun.org.apache.bcel.internal.classfile;
diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ARRAYLENGTH.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ARRAYLENGTH.java
index 2d7188e9174..db756700085 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ARRAYLENGTH.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ARRAYLENGTH.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -28,12 +28,12 @@ import com.sun.org.apache.bcel.internal.ExceptionConst;
  * 
  * Stack: ..., arrayref -> ..., length
  * 
- * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public class ARRAYLENGTH extends Instruction implements ExceptionThrower, StackProducer, StackConsumer /* since 6.0 */ { /** - * Get length of array + * Gets length of array */ public ARRAYLENGTH() { super(com.sun.org.apache.bcel.internal.Const.ARRAYLENGTH, (short) 1); diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ATHROW.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ATHROW.java index bb2e953f850..07171fefde1 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ATHROW.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ATHROW.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -28,8 +28,10 @@ import com.sun.org.apache.bcel.internal.ExceptionConst; *
  * Stack: ..., objectref -> objectref
  * 
+ * + * @LastModified: Sept 2025 */ -public class ATHROW extends Instruction implements UnconditionalBranch, ExceptionThrower { +public class ATHROW extends Instruction implements UnconditionalBranch, ExceptionThrower, StackConsumer { /** * Throw exception @@ -48,6 +50,7 @@ public class ATHROW extends Instruction implements UnconditionalBranch, Exceptio public void accept(final Visitor v) { v.visitUnconditionalBranch(this); v.visitExceptionThrower(this); + v.visitStackConsumer(this); v.visitATHROW(this); } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/AnnotationEntryGen.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/AnnotationEntryGen.java index ea01a837175..0fad6ea7389 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/AnnotationEntryGen.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/AnnotationEntryGen.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -28,6 +28,7 @@ import java.io.DataOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; import com.sun.org.apache.bcel.internal.classfile.AnnotationEntry; import com.sun.org.apache.bcel.internal.classfile.Attribute; @@ -37,10 +38,11 @@ import com.sun.org.apache.bcel.internal.classfile.RuntimeInvisibleAnnotations; import com.sun.org.apache.bcel.internal.classfile.RuntimeInvisibleParameterAnnotations; import com.sun.org.apache.bcel.internal.classfile.RuntimeVisibleAnnotations; import com.sun.org.apache.bcel.internal.classfile.RuntimeVisibleParameterAnnotations; +import jdk.xml.internal.Utils; /** * @since 6.0 - * @LastModified: Jan 2020 + * @LastModified: Sept 2025 */ public class AnnotationEntryGen { @@ -53,7 +55,7 @@ public class AnnotationEntryGen { * @param annotationEntryGens An array of AnnotationGen objects */ static Attribute[] getAnnotationAttributes(final ConstantPoolGen cp, final AnnotationEntryGen[] annotationEntryGens) { - if (annotationEntryGens.length == 0) { + if (annotationEntryGens == null && annotationEntryGens.length == 0) { return Attribute.EMPTY_ARRAY; } @@ -255,11 +257,7 @@ public class AnnotationEntryGen { } private List copyValues(final ElementValuePair[] in, final ConstantPoolGen cpool, final boolean copyPoolEntries) { - final List out = new ArrayList<>(); - for (final ElementValuePair nvp : in) { - out.add(new ElementValuePairGen(nvp, cpool, copyPoolEntries)); - } - return out; + return Utils.streamOfIfNonNull(in).map(nvp -> new ElementValuePairGen(nvp, cpool, copyPoolEntries)).collect(Collectors.toList()); } public void dump(final DataOutputStream dos) throws IOException { @@ -286,18 +284,20 @@ public class AnnotationEntryGen { } public final String getTypeName() { - return getTypeSignature();// BCELBUG: Should I use this instead? + return getTypeSignature(); // BCELBUG: Should I use this instead? // Utility.signatureToString(getTypeSignature()); } public final String getTypeSignature() { - // ConstantClass c = (ConstantClass)cpool.getConstant(typeIndex); + // ConstantClass c = (ConstantClass) cpool.getConstant(typeIndex); final ConstantUtf8 utf8 = (ConstantUtf8) cpool.getConstant(typeIndex/* c.getNameIndex() */); return utf8.getBytes(); } /** - * Returns list of ElementNameValuePair objects + * Returns list of ElementNameValuePair objects. + * + * @return list of ElementNameValuePair objects. */ public List getValues() { return evs; diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ArrayElementValueGen.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ArrayElementValueGen.java index 71374877efe..59b774a9afc 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ArrayElementValueGen.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ArrayElementValueGen.java @@ -1,6 +1,5 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -25,12 +24,15 @@ import java.io.DataOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; import com.sun.org.apache.bcel.internal.classfile.ArrayElementValue; import com.sun.org.apache.bcel.internal.classfile.ElementValue; +import jdk.xml.internal.Utils; /** * @since 6.0 + * @LastModified: Sept 2025 */ public class ArrayElementValueGen extends ElementValueGen { // J5TODO: Should we make this an array or a list? A list would be easier to @@ -46,7 +48,7 @@ public class ArrayElementValueGen extends ElementValueGen { evalues = new ArrayList<>(); final ElementValue[] in = value.getElementValuesArray(); for (final ElementValue element : in) { - evalues.add(ElementValueGen.copy(element, cpool, copyPoolEntries)); + evalues.add(copy(element, cpool, copyPoolEntries)); } } @@ -55,15 +57,12 @@ public class ArrayElementValueGen extends ElementValueGen { evalues = new ArrayList<>(); } - public ArrayElementValueGen(final int type, final ElementValue[] datums, final ConstantPoolGen cpool) { + public ArrayElementValueGen(final int type, final ElementValue[] elementValues, final ConstantPoolGen cpool) { super(type, cpool); if (type != ARRAY) { throw new IllegalArgumentException("Only element values of type array can be built with this ctor - type specified: " + type); } - this.evalues = new ArrayList<>(); - for (final ElementValue datum : datums) { - evalues.add(ElementValueGen.copy(datum, cpool, true)); - } + this.evalues = Utils.streamOfIfNonNull(elementValues).map(e -> copy(e, cpool, true)).collect(Collectors.toList()); } public void addElement(final ElementValueGen gen) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ArrayType.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ArrayType.java index 138999ebe90..78a676e875e 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ArrayType.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ArrayType.java @@ -1,6 +1,5 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -24,6 +23,8 @@ import com.sun.org.apache.bcel.internal.Const; /** * Denotes array type, such as int[][] + * + * @LastModified: Sept 2025 */ public final class ArrayType extends ReferenceType { @@ -43,7 +44,7 @@ public final class ArrayType extends ReferenceType { /** * Convenience constructor for reference array type, e.g. Object[] * - * @param className complete name of class (java.lang.String, e.g.) + * @param className complete name of class ({@link String}, for example) * @param dimensions array dimensions */ public ArrayType(final String className, final int dimensions) { @@ -56,6 +57,7 @@ public final class ArrayType extends ReferenceType { * @param type type of array (may be an array itself) * @param dimensions array dimensions */ + @SuppressWarnings("deprecation") //signature public ArrayType(final Type type, final int dimensions) { super(Const.T_ARRAY, ""); if (dimensions < 1 || dimensions > Const.MAX_BYTE) { @@ -79,7 +81,7 @@ public final class ArrayType extends ReferenceType { buf.append('['); } buf.append(basicType.getSignature()); - super.setSignature(buf.toString()); + this.signature = buf.toString(); } /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/BranchHandle.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/BranchHandle.java index 91ab9ac5463..f489f9a7658 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/BranchHandle.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/BranchHandle.java @@ -63,7 +63,7 @@ public final class BranchHandle extends InstructionHandle { } /** - * Set new contents. Old instruction is disposed and may not be used anymore. + * Sets new contents. Old instruction is disposed and may not be used anymore. */ @Override // This is only done in order to apply the additional type check; could be merged with super impl. public void setInstruction(final Instruction i) { // TODO could be package-protected? diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/CPInstruction.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/CPInstruction.java index 1dfd244141a..ff45e5cde93 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/CPInstruction.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/CPInstruction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -35,7 +35,7 @@ import com.sun.org.apache.bcel.internal.util.ByteSequence; * @see LDC * @see INVOKEVIRTUAL * - * @LastModified: Jan 2020 + * @LastModified: Sept 2025 */ public abstract class CPInstruction extends Instruction implements TypedInstruction, IndexedInstruction { @@ -104,7 +104,7 @@ public abstract class CPInstruction extends Instruction implements TypedInstruct } /** - * Set the index to constant pool. + * Sets the index to constant pool. * * @param index in constant pool. */ diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ClassElementValueGen.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ClassElementValueGen.java index 1c1c032dbd5..8e024eebaa4 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ClassElementValueGen.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ClassElementValueGen.java @@ -48,12 +48,12 @@ public class ClassElementValueGen extends ElementValueGen { } protected ClassElementValueGen(final int typeIdx, final ConstantPoolGen cpool) { - super(ElementValueGen.CLASS, cpool); + super(CLASS, cpool); this.idx = typeIdx; } public ClassElementValueGen(final ObjectType t, final ConstantPoolGen cpool) { - super(ElementValueGen.CLASS, cpool); + super(CLASS, cpool); // this.idx = cpool.addClass(t); idx = cpool.addUtf8(t.getSignature()); } @@ -67,9 +67,9 @@ public class ClassElementValueGen extends ElementValueGen { public String getClassString() { final ConstantUtf8 cu8 = (ConstantUtf8) getConstantPool().getConstant(idx); return cu8.getBytes(); - // ConstantClass c = (ConstantClass)getConstantPool().getConstant(idx); + // ConstantClass c = (ConstantClass) getConstantPool().getConstant(idx); // ConstantUtf8 utf8 = - // (ConstantUtf8)getConstantPool().getConstant(c.getNameIndex()); + // (ConstantUtf8) getConstantPool().getConstant(c.getNameIndex()); // return utf8.getBytes(); } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ClassGen.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ClassGen.java index acaf4519567..debf930fe90 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ClassGen.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ClassGen.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -40,40 +40,37 @@ import com.sun.org.apache.bcel.internal.classfile.Utility; import com.sun.org.apache.bcel.internal.util.BCELComparator; /** - * Template class for building up a java class. May be initialized with an existing java class (file). + * Template class for building up a java class. May be initialized with an existing Java class (file). * * @see JavaClass - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public class ClassGen extends AccessFlags implements Cloneable { - private static BCELComparator bcelComparator = new BCELComparator() { + private static BCELComparator bcelComparator = new BCELComparator() { @Override - public boolean equals(final Object o1, final Object o2) { - final ClassGen THIS = (ClassGen) o1; - final ClassGen THAT = (ClassGen) o2; - return Objects.equals(THIS.getClassName(), THAT.getClassName()); + public boolean equals(final ClassGen a, final ClassGen b) { + return a == b || a != null && b != null && Objects.equals(a.getClassName(), b.getClassName()); } @Override - public int hashCode(final Object o) { - final ClassGen THIS = (ClassGen) o; - return THIS.getClassName().hashCode(); + public int hashCode(final ClassGen o) { + return o != null ? Objects.hashCode(o.getClassName()) : 0; } }; /** * @return Comparison strategy object */ - public static BCELComparator getComparator() { + public static BCELComparator getComparator() { return bcelComparator; } /** * @param comparator Comparison strategy object */ - public static void setComparator(final BCELComparator comparator) { + public static void setComparator(final BCELComparator comparator) { bcelComparator = comparator; } @@ -101,7 +98,7 @@ public class ClassGen extends AccessFlags implements Cloneable { private List observers; /** - * Initialize with existing class. + * Constructs a new instance from an existing class. * * @param clazz JavaClass object (e.g. read from file) */ @@ -118,15 +115,26 @@ public class ClassGen extends AccessFlags implements Cloneable { final Attribute[] attributes = clazz.getAttributes(); // J5TODO: Could make unpacking lazy, done on first reference final AnnotationEntryGen[] annotations = unpackAnnotations(attributes); - Collections.addAll(interfaceList, clazz.getInterfaceNames()); - for (final Attribute attribute : attributes) { - if (!(attribute instanceof Annotations)) { - addAttribute(attribute); + final String[] interfaceNames = clazz.getInterfaceNames(); + if (interfaceNames != null) { + Collections.addAll(interfaceList, interfaceNames); + } + if (attributes != null) { + for (final Attribute attribute : attributes) { + if (!(attribute instanceof Annotations)) { + addAttribute(attribute); + } } } Collections.addAll(annotationList, annotations); - Collections.addAll(methodList, clazz.getMethods()); - Collections.addAll(fieldList, clazz.getFields()); + final Method[] methods = clazz.getMethods(); + if (methods != null) { + Collections.addAll(methodList, methods); + } + final Field[] fields = clazz.getFields(); + if (fields != null) { + Collections.addAll(fieldList, fields); + } } /** @@ -242,7 +250,7 @@ public class ClassGen extends AccessFlags implements Cloneable { try { return super.clone(); } catch (final CloneNotSupportedException e) { - throw new Error("Clone Not Supported"); // never happens + throw new UnsupportedOperationException("Clone Not Supported", e); // never happens } } @@ -282,7 +290,7 @@ public class ClassGen extends AccessFlags implements Cloneable { */ @Override public boolean equals(final Object obj) { - return bcelComparator.equals(this, obj); + return obj instanceof ClassGen && bcelComparator.equals(this, (ClassGen) obj); } // J5TODO: Should we make calling unpackAnnotations() lazy and put it in here? @@ -379,7 +387,7 @@ public class ClassGen extends AccessFlags implements Cloneable { } /** - * Return value as defined by given BCELComparator strategy. By default return the hashcode of the class name. + * Return value as defined by given BCELComparator strategy. By default return the hash code of the class name. * * @see Object#hashCode() */ @@ -478,7 +486,7 @@ public class ClassGen extends AccessFlags implements Cloneable { } /** - * Set major version number of class file, default value is 45 (JDK 1.1) + * Sets major version number of class file, default value is 45 (JDK 1.1) * * @param major major version number */ @@ -492,11 +500,13 @@ public class ClassGen extends AccessFlags implements Cloneable { public void setMethods(final Method[] methods) { methodList.clear(); - Collections.addAll(methodList, methods); + if (methods != null) { + Collections.addAll(methodList, methods); + } } /** - * Set minor version number of class file, default value is 3 (JDK 1.1) + * Sets minor version number of class file, default value is 3 (JDK 1.1) * * @param minor minor version number */ @@ -515,17 +525,19 @@ public class ClassGen extends AccessFlags implements Cloneable { } /** - * Look for attributes representing annotations and unpack them. + * Unpacks attributes representing annotations. */ - private AnnotationEntryGen[] unpackAnnotations(final Attribute[] attrs) { + private AnnotationEntryGen[] unpackAnnotations(final Attribute[] attributes) { final List annotationGenObjs = new ArrayList<>(); - for (final Attribute attr : attrs) { - if (attr instanceof RuntimeVisibleAnnotations) { - final RuntimeVisibleAnnotations rva = (RuntimeVisibleAnnotations) attr; - rva.forEach(a -> annotationGenObjs.add(new AnnotationEntryGen(a, getConstantPool(), false))); - } else if (attr instanceof RuntimeInvisibleAnnotations) { - final RuntimeInvisibleAnnotations ria = (RuntimeInvisibleAnnotations) attr; - ria.forEach(a -> annotationGenObjs.add(new AnnotationEntryGen(a, getConstantPool(), false))); + if (attributes != null) { + for (final Attribute attr : attributes) { + if (attr instanceof RuntimeVisibleAnnotations) { + final RuntimeVisibleAnnotations rva = (RuntimeVisibleAnnotations) attr; + rva.forEach(a -> annotationGenObjs.add(new AnnotationEntryGen(a, getConstantPool(), false))); + } else if (attr instanceof RuntimeInvisibleAnnotations) { + final RuntimeInvisibleAnnotations ria = (RuntimeInvisibleAnnotations) attr; + ria.forEach(a -> annotationGenObjs.add(new AnnotationEntryGen(a, getConstantPool(), false))); + } } } return annotationGenObjs.toArray(AnnotationEntryGen.EMPTY_ARRAY); diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/CodeExceptionGen.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/CodeExceptionGen.java index fa660954d15..2518131ccee 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/CodeExceptionGen.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/CodeExceptionGen.java @@ -63,7 +63,7 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable { try { return super.clone(); } catch (final CloneNotSupportedException e) { - throw new Error("Clone Not Supported"); // never happens + throw new UnsupportedOperationException("Clone Not Supported", e); // never happens } } @@ -81,7 +81,7 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable { } /** - * Get CodeException object.
+ * Gets CodeException object.
* * This relies on that the instruction list has already been dumped to byte code or that the 'setPositions' methods * has been called for the instruction list. @@ -120,7 +120,7 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable { } /* - * Set end of handler + * Sets end of handler * * @param endPc End of handled region (inclusive) */ @@ -130,7 +130,7 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable { } /* - * Set handler code + * Sets handler code * * @param handlerPc Start of handler */ @@ -140,7 +140,7 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable { } /* - * Set start of handler + * Sets start of handler * * @param startPc Start of handled region (inclusive) */ diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ElementValuePairGen.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ElementValuePairGen.java index bdc9c517a86..878f392b6b7 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ElementValuePairGen.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ElementValuePairGen.java @@ -44,7 +44,7 @@ public class ElementValuePairGen { // Could assert nvp.getNameString() points to the same thing as // constantPoolGen.getConstant(nvp.getNameIndex()) // if - // (!nvp.getNameString().equals(((ConstantUtf8)constantPoolGen.getConstant(nvp.getNameIndex())).getBytes())) + // (!nvp.getNameString().equals(((ConstantUtf8) constantPoolGen.getConstant(nvp.getNameIndex())).getBytes())) // { // throw new IllegalArgumentException("envp buggered"); // } @@ -86,7 +86,7 @@ public class ElementValuePairGen { } public final String getNameString() { - // ConstantString cu8 = (ConstantString)constantPoolGen.getConstant(nameIdx); + // ConstantString cu8 = (ConstantString) constantPoolGen.getConstant(nameIdx); return ((ConstantUtf8) constantPoolGen.getConstant(nameIdx)).getBytes(); } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/EnumElementValueGen.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/EnumElementValueGen.java index 95ac794f2d7..95c00ed3813 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/EnumElementValueGen.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/EnumElementValueGen.java @@ -40,10 +40,8 @@ public class EnumElementValueGen extends ElementValueGen { public EnumElementValueGen(final EnumElementValue value, final ConstantPoolGen cpool, final boolean copyPoolEntries) { super(ENUM_CONSTANT, cpool); if (copyPoolEntries) { - typeIdx = cpool.addUtf8(value.getEnumTypeString());// was - // addClass(value.getEnumTypeString()); - valueIdx = cpool.addUtf8(value.getEnumValueString()); // was - // addString(value.getEnumValueString()); + typeIdx = cpool.addUtf8(value.getEnumTypeString()); // was addClass(value.getEnumTypeString()); + valueIdx = cpool.addUtf8(value.getEnumValueString()); // was addString(value.getEnumValueString()); } else { typeIdx = value.getTypeIndex(); valueIdx = value.getValueIndex(); @@ -55,7 +53,7 @@ public class EnumElementValueGen extends ElementValueGen { * This ctor is used for deserialization */ protected EnumElementValueGen(final int typeIdx, final int valueIdx, final ConstantPoolGen cpool) { - super(ElementValueGen.ENUM_CONSTANT, cpool); + super(ENUM_CONSTANT, cpool); if (super.getElementValueType() != ENUM_CONSTANT) { throw new IllegalArgumentException("Only element values of type enum can be built with this ctor - type specified: " + super.getElementValueType()); } @@ -64,9 +62,9 @@ public class EnumElementValueGen extends ElementValueGen { } public EnumElementValueGen(final ObjectType t, final String value, final ConstantPoolGen cpool) { - super(ElementValueGen.ENUM_CONSTANT, cpool); - typeIdx = cpool.addUtf8(t.getSignature());// was addClass(t); - valueIdx = cpool.addUtf8(value);// was addString(value); + super(ENUM_CONSTANT, cpool); + typeIdx = cpool.addUtf8(t.getSignature()); // was addClass(t); + valueIdx = cpool.addUtf8(value); // was addString(value); } @Override @@ -90,9 +88,9 @@ public class EnumElementValueGen extends ElementValueGen { public String getEnumTypeString() { // Constant cc = getConstantPool().getConstant(typeIdx); // ConstantClass cu8 = - // (ConstantClass)getConstantPool().getConstant(typeIdx); + // (ConstantClass) getConstantPool().getConstant(typeIdx); // return - // ((ConstantUtf8)getConstantPool().getConstant(cu8.getNameIndex())).getBytes(); + // ((ConstantUtf8) getConstantPool().getConstant(cu8.getNameIndex())).getBytes(); return ((ConstantUtf8) getConstantPool().getConstant(typeIdx)).getBytes(); // return Utility.signatureToString(cu8.getBytes()); } @@ -100,9 +98,9 @@ public class EnumElementValueGen extends ElementValueGen { public String getEnumValueString() { return ((ConstantUtf8) getConstantPool().getConstant(valueIdx)).getBytes(); // ConstantString cu8 = - // (ConstantString)getConstantPool().getConstant(valueIdx); + // (ConstantString) getConstantPool().getConstant(valueIdx); // return - // ((ConstantUtf8)getConstantPool().getConstant(cu8.getStringIndex())).getBytes(); + // ((ConstantUtf8) getConstantPool().getConstant(cu8.getStringIndex())).getBytes(); } public int getTypeIndex() { @@ -118,8 +116,8 @@ public class EnumElementValueGen extends ElementValueGen { final ConstantUtf8 cu8 = (ConstantUtf8) getConstantPool().getConstant(valueIdx); return cu8.getBytes(); // ConstantString cu8 = - // (ConstantString)getConstantPool().getConstant(valueIdx); + // (ConstantString) getConstantPool().getConstant(valueIdx); // return - // ((ConstantUtf8)getConstantPool().getConstant(cu8.getStringIndex())).getBytes(); + // ((ConstantUtf8) getConstantPool().getConstant(cu8.getStringIndex())).getBytes(); } } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ExceptionThrower.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ExceptionThrower.java index 86a0cad256c..2a488c85ede 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ExceptionThrower.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ExceptionThrower.java @@ -23,7 +23,7 @@ package com.sun.org.apache.bcel.internal.generic; /** * Denote an instruction that may throw a run-time or a linking exception (or both) during execution. This is not quite - * the truth as such; because all instructions may throw an java.lang.VirtualMachineError. These exceptions are omitted. + * the truth as such; because all instructions may throw a {@link VirtualMachineError}. These exceptions are omitted. * * The Lava Language Specification specifies exactly which RUN-TIME and which LINKING exceptions each * instruction may throw which is reflected by the implementers. Due to the structure of the JVM specification, it may diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/FieldGen.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/FieldGen.java index 9d1f4d41d93..30786370d29 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/FieldGen.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/FieldGen.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -40,37 +40,34 @@ import com.sun.org.apache.bcel.internal.util.BCELComparator; * to a field (which must of course be compatible with to the declared type). * * @see Field - * @LastModified: May 2021 + * @LastModified: Sept 2025 */ public class FieldGen extends FieldGenOrMethodGen { - private static BCELComparator bcelComparator = new BCELComparator() { + private static BCELComparator bcelComparator = new BCELComparator() { @Override - public boolean equals(final Object o1, final Object o2) { - final FieldGen THIS = (FieldGen) o1; - final FieldGen THAT = (FieldGen) o2; - return Objects.equals(THIS.getName(), THAT.getName()) && Objects.equals(THIS.getSignature(), THAT.getSignature()); + public boolean equals(final FieldGen a, final FieldGen b) { + return a == b || a != null && b != null && Objects.equals(a.getName(), b.getName()) && Objects.equals(a.getSignature(), b.getSignature()); } @Override - public int hashCode(final Object o) { - final FieldGen THIS = (FieldGen) o; - return THIS.getSignature().hashCode() ^ THIS.getName().hashCode(); + public int hashCode(final FieldGen o) { + return o != null ? Objects.hash(o.getSignature(), o.getName()) : 0; } }; /** - * @return Comparison strategy object + * @return Comparison strategy object. */ - public static BCELComparator getComparator() { + public static BCELComparator getComparator() { return bcelComparator; } /** - * @param comparator Comparison strategy object + * @param comparator Comparison strategy object. */ - public static void setComparator(final BCELComparator comparator) { + public static void setComparator(final BCELComparator comparator) { bcelComparator = comparator; } @@ -81,8 +78,8 @@ public class FieldGen extends FieldGenOrMethodGen { /** * Instantiate from existing field. * - * @param field Field object - * @param cp constant pool (must contain the same entries as the field's constant pool) + * @param field Field object. + * @param cp constant pool (must contain the same entries as the field's constant pool). */ public FieldGen(final Field field, final ConstantPoolGen cp) { this(field.getAccessFlags(), Type.getType(field.getSignature()), field.getName(), cp); @@ -187,11 +184,11 @@ public class FieldGen extends FieldGenOrMethodGen { */ @Override public boolean equals(final Object obj) { - return bcelComparator.equals(this, obj); + return obj instanceof FieldGen && bcelComparator.equals(this, (FieldGen) obj); } /** - * Get field object after having set up all necessary values. + * Gets field object after having set up all necessary values. */ public Field getField() { final String signature = getSignature(); @@ -207,10 +204,7 @@ public class FieldGen extends FieldGenOrMethodGen { } public String getInitValue() { - if (value != null) { - return value.toString(); - } - return null; + return Objects.toString(value, null); } @Override @@ -219,7 +213,7 @@ public class FieldGen extends FieldGenOrMethodGen { } /** - * Return value as defined by given BCELComparator strategy. By default return the hashcode of the field's name XOR + * Return value as defined by given BCELComparator strategy. By default return the hash code of the field's name XOR * signature. * * @see Object#hashCode() @@ -295,7 +289,7 @@ public class FieldGen extends FieldGenOrMethodGen { } /** - * Set (optional) initial value of field, otherwise it will be set to null/0/false by the JVM automatically. + * Sets (optional) initial value of field, otherwise it will be set to null/0/false by the JVM automatically. */ public void setInitValue(final String str) { checkType(ObjectType.getInstance("java.lang.String")); diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/FieldGenOrMethodGen.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/FieldGenOrMethodGen.java index 6555392e9d4..bc1fbc8627e 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/FieldGenOrMethodGen.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/FieldGenOrMethodGen.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -30,7 +30,7 @@ import com.sun.org.apache.bcel.internal.classfile.Attribute; /** * Super class for FieldGen and MethodGen objects, since they have some methods in common! * - * @LastModified: May 2021 + * @LastModified: Sept 2025 */ public abstract class FieldGenOrMethodGen extends AccessFlags implements NamedAndTyped, Cloneable { @@ -67,8 +67,10 @@ public abstract class FieldGenOrMethodGen extends AccessFlags implements NamedAn super(accessFlags); } - protected void addAll(final Attribute[] attrs) { - Collections.addAll(attributeList, attrs); + protected void addAll(final Attribute[] attributes) { + if (attributes != null) { + Collections.addAll(attributeList, attributes); + } } /** @@ -93,7 +95,7 @@ public abstract class FieldGenOrMethodGen extends AccessFlags implements NamedAn try { return super.clone(); } catch (final CloneNotSupportedException e) { - throw new Error("Clone Not Supported"); // never happens + throw new UnsupportedOperationException("Clone Not Supported", e); // never happens } } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/FieldOrMethod.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/FieldOrMethod.java index 1c646f48292..87ba4cb913e 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/FieldOrMethod.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/FieldOrMethod.java @@ -53,7 +53,6 @@ public abstract class FieldOrMethod extends CPInstruction implements LoadClass { * generated by Java 1.5, this answer is sometimes wrong (e.g., if the "clone()" method is called on an * array). A better idea is to use the {@link #getReferenceType(ConstantPoolGen)} method, which correctly * distinguishes between class types and array types. - * */ @Deprecated public String getClassName(final ConstantPoolGen cpg) { @@ -89,6 +88,9 @@ public abstract class FieldOrMethod extends CPInstruction implements LoadClass { if (rt instanceof ObjectType) { return (ObjectType) rt; } + if (rt instanceof ArrayType) { + return Type.OBJECT; + } throw new ClassGenException(rt.getClass().getCanonicalName() + " " + rt.getSignature() + " does not represent an ObjectType"); } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ICONST.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ICONST.java index 5effd7edcd9..b3eb14a9ddf 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ICONST.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ICONST.java @@ -25,7 +25,6 @@ package com.sun.org.apache.bcel.internal.generic; *
  * Stack: ... -> ...,
  * 
- * */ public class ICONST extends Instruction implements ConstantPushInstruction { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/INVOKEDYNAMIC.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/INVOKEDYNAMIC.java index 2865a158de2..998d072e067 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/INVOKEDYNAMIC.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/INVOKEDYNAMIC.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -37,7 +37,7 @@ import com.sun.org.apache.bcel.internal.util.ByteSequence; * @see The * invokedynamic instruction in The Java Virtual Machine Specification * @since 6.0 - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public class INVOKEDYNAMIC extends InvokeInstruction { @@ -104,11 +104,11 @@ public class INVOKEDYNAMIC extends InvokeInstruction { } /** - * Since InvokeDynamic doesn't refer to a reference type, just return java.lang.Object, as that is the only type we can + * Since InvokeDynamic doesn't refer to a reference type, just return {@link Object}, as that is the only type we can * say for sure the reference will be. * * @param cpg the ConstantPoolGen used to create the instruction - * @return an ObjectType for java.lang.Object + * @return an ObjectType for {@link Object} * @since 6.1 */ @Override diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/Instruction.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/Instruction.java index 16c8e2444b4..a7124409f12 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/Instruction.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/Instruction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -29,7 +29,7 @@ import com.sun.org.apache.bcel.internal.util.ByteSequence; /** * Abstract super class for all Java byte codes. * - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public abstract class Instruction implements Cloneable { @@ -461,7 +461,7 @@ public abstract class Instruction implements Cloneable { public Instruction copy() { Instruction i = null; // "Constant" instruction, no need to duplicate - if (InstructionConst.getInstruction(this.getOpcode()) != null) { + if (InstructionConst.getInstruction(getOpcode()) != null) { i = this; } else { try { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionConst.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionConst.java index 439268e35eb..7b95bfc99b1 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionConst.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionConst.java @@ -170,7 +170,7 @@ public final class InstructionConst { public static final LocalVariableInstruction ISTORE_2 = new ISTORE(2); /** - * Get object via its opcode, for immutable instructions like branch instructions entries are set to null. + * Gets object via its opcode, for immutable instructions like branch instructions entries are set to null. */ static final Instruction[] INSTRUCTIONS = new Instruction[256]; diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionFactory.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionFactory.java index 5e9220354c3..3c4b3e9f9da 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionFactory.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -30,11 +30,11 @@ import com.sun.org.apache.bcel.internal.Const; * * @see Const * @see InstructionConst - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public class InstructionFactory { - private static class MethodObject { + private static final class MethodObject { final Type[] argTypes; final Type resultType; @@ -53,10 +53,12 @@ public class InstructionFactory { private static final String FQCN_STRING_BUFFER = "java.lang.StringBuffer"; - // N.N. These must agree with the order of Constants.T_CHAR through T_LONG - private static final String[] shortNames = {"C", "F", "D", "B", "S", "I", "L"}; + /** + * These must agree with the order of Constants.T_CHAR through T_LONG. + */ + private static final String[] SHORT_NAMES = {"C", "F", "D", "B", "S", "I", "L"}; - private static final MethodObject[] appendMethodObjects = { + private static final MethodObject[] APPEND_METHOD_OBJECTS = { new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.STRING }), new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.OBJECT }), null, null, // indices 2, 3 new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.BOOLEAN }), @@ -484,7 +486,7 @@ public class InstructionFactory { public Instruction createAppend(final Type type) { final byte t = type.getType(); if (isString(type)) { - return createInvoke(appendMethodObjects[0], Const.INVOKEVIRTUAL); + return createInvoke(APPEND_METHOD_OBJECTS[0], Const.INVOKEVIRTUAL); } switch (t) { case Const.T_BOOLEAN: @@ -495,10 +497,10 @@ public class InstructionFactory { case Const.T_SHORT: case Const.T_INT: case Const.T_LONG: - return createInvoke(appendMethodObjects[t], Const.INVOKEVIRTUAL); + return createInvoke(APPEND_METHOD_OBJECTS[t], Const.INVOKEVIRTUAL); case Const.T_ARRAY: case Const.T_OBJECT: - return createInvoke(appendMethodObjects[1], Const.INVOKEVIRTUAL); + return createInvoke(APPEND_METHOD_OBJECTS[1], Const.INVOKEVIRTUAL); default: throw new IllegalArgumentException("No append for this type? " + type); } @@ -515,7 +517,7 @@ public class InstructionFactory { if (dest == Const.T_LONG && (src == Const.T_CHAR || src == Const.T_BYTE || src == Const.T_SHORT)) { src = Const.T_INT; } - final String name = "com.sun.org.apache.bcel.internal.generic." + shortNames[src - Const.T_CHAR] + "2" + shortNames[dest - Const.T_CHAR]; + final String name = "com.sun.org.apache.bcel.internal.generic." + SHORT_NAMES[src - Const.T_CHAR] + "2" + SHORT_NAMES[dest - Const.T_CHAR]; Instruction i = null; try { i = (Instruction) Class.forName(name).getDeclaredConstructor().newInstance();; @@ -642,8 +644,10 @@ public class InstructionFactory { int index; int nargs = 0; final String signature = Type.getMethodSignature(retType, argTypes); - for (final Type argType : argTypes) { - nargs += argType.getSize(); + if (argTypes != null) { + for (final Type argType : argTypes) { + nargs += argType.getSize(); + } } if (useInterface) { index = cp.addInterfaceMethodref(className, name, signature); diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionHandle.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionHandle.java index 5e962354d16..2c94b770265 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionHandle.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionHandle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -38,7 +38,7 @@ import com.sun.org.apache.bcel.internal.classfile.Utility; * @see Instruction * @see BranchHandle * @see InstructionList - * @LastModified: May 2021 + * @LastModified: Sept 2025 */ public class InstructionHandle { @@ -118,7 +118,7 @@ public class InstructionHandle { if (targeters == null) { targeters = new HashSet<>(); } - // if(!targeters.contains(t)) + // if (!targeters.contains(t)) targeters.add(t); } @@ -135,15 +135,12 @@ public class InstructionHandle { } /** - * Get attribute of an instruction handle. + * Gets attribute of an instruction handle. * * @param key the key object to store/retrieve the attribute */ public Object getAttribute(final Object key) { - if (attributes != null) { - return attributes.get(key); - } - return null; + return attributes != null ? attributes.get(key) : null; } /** @@ -247,7 +244,7 @@ public class InstructionHandle { } /** - * Set the position, i.e., the byte code offset of the contained instruction. + * Sets the position, i.e., the byte code offset of the contained instruction. */ void setPosition(final int pos) { i_position = pos; diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionList.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionList.java index 7ffc3a8228e..579efc9fe3b 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionList.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionList.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -33,6 +33,7 @@ import java.util.NoSuchElementException; import com.sun.org.apache.bcel.internal.Const; import com.sun.org.apache.bcel.internal.classfile.Constant; import com.sun.org.apache.bcel.internal.util.ByteSequence; +import jdk.xml.internal.Utils; /** * This class is a container for a list of Instruction objects. Instructions can be @@ -46,7 +47,7 @@ import com.sun.org.apache.bcel.internal.util.ByteSequence; * @see Instruction * @see InstructionHandle * @see BranchHandle - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public class InstructionList implements Iterable { @@ -60,23 +61,25 @@ public class InstructionList implements Iterable { * @return target position's instruction handle if available */ public static InstructionHandle findHandle(final InstructionHandle[] ihs, final int[] pos, final int count, final int target) { - int l = 0; - int r = count - 1; - /* - * Do a binary search since the pos array is orderd. - */ - do { - final int i = l + r >>> 1; - final int j = pos[i]; - if (j == target) { - return ihs[i]; - } - if (target < j) { - r = i - 1; - } else { - l = i + 1; - } - } while (l <= r); + if (ihs != null && pos != null) { + int l = 0; + int r = count - 1; + /* + * Do a binary search since the pos array is orderd. + */ + do { + final int i = l + r >>> 1; + final int j = pos[i]; + if (j == target) { + return ihs[i]; + } + if (target < j) { + r = i - 1; + } else { + l = i + 1; + } + } while (l <= r); + } return null; } @@ -513,7 +516,7 @@ public class InstructionList implements Iterable { } /** - * Get instruction handle for instruction at byte code position pos. This only works properly, if the list is freshly + * Gets instruction handle for instruction at byte code position pos. This only works properly, if the list is freshly * initialized from a byte array or setPositions() has been called before this method. * * @param pos byte code position to search for @@ -605,7 +608,7 @@ public class InstructionList implements Iterable { } /** - * Get positions (offsets) of all instructions in the list. This relies on that the list has been freshly created from + * Gets positions (offsets) of all instructions in the list. This relies on that the list has been freshly created from * an byte code array, or that setPositions() has been called. Otherwise this may be inaccurate. * * @return array containing all instruction's offset in byte code @@ -959,7 +962,7 @@ public class InstructionList implements Iterable { * @see MethodGen */ public void redirectExceptionHandlers(final CodeExceptionGen[] exceptions, final InstructionHandle oldTarget, final InstructionHandle newTarget) { - for (final CodeExceptionGen exception : exceptions) { + Utils.streamOfIfNonNull(exceptions).forEach(exception -> { if (exception.getStartPC() == oldTarget) { exception.setStartPC(newTarget); } @@ -969,7 +972,7 @@ public class InstructionList implements Iterable { if (exception.getHandlerPC() == oldTarget) { exception.setHandlerPC(newTarget); } - } + }); } /** @@ -981,16 +984,14 @@ public class InstructionList implements Iterable { * @see MethodGen */ public void redirectLocalVariables(final LocalVariableGen[] lg, final InstructionHandle oldTarget, final InstructionHandle newTarget) { - for (final LocalVariableGen element : lg) { - final InstructionHandle start = element.getStart(); - final InstructionHandle end = element.getEnd(); - if (start == oldTarget) { + Utils.streamOfIfNonNull(lg).forEach(element -> { + if (element.getStart() == oldTarget) { element.setStart(newTarget); } - if (end == oldTarget) { + if (element.getEnd() == oldTarget) { element.setEnd(newTarget); } - } + }); } /** @@ -1120,7 +1121,7 @@ public class InstructionList implements Iterable { ih.setPosition(index); pos[count++] = index; /* - * Get an estimate about how many additional bytes may be added, because BranchInstructions may have variable length + * Gets an estimate about how many additional bytes may be added, because BranchInstructions may have variable length * depending on the target offset (short vs. int) or alignment issues (TABLESWITCH and LOOKUPSWITCH). */ switch (i.getOpcode()) { @@ -1132,11 +1133,14 @@ public class InstructionList implements Iterable { case Const.LOOKUPSWITCH: maxAdditionalBytes += 3; break; + default: + // TODO should this be an error? + break; } index += i.getLength(); } /* - * Pass 2: Expand the variable-length (Branch)Instructions depending on the target offset (short or int) and ensure that + * Pass 2: Expand the variable-length (Branch) Instructions depending on the target offset (short or int) and ensure that * branch targets are within this list. */ for (InstructionHandle ih = start; ih != null; ih = ih.getNext()) { @@ -1152,8 +1156,7 @@ public class InstructionList implements Iterable { pos[count++] = index; index += i.getLength(); } - bytePositions = new int[count]; // Trim to proper size - System.arraycopy(pos, 0, bytePositions, 0, count); + bytePositions = Arrays.copyOfRange(pos, 0, count); // Trim to proper size } /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionTargeter.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionTargeter.java index 5146408ef49..0681476b5ee 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionTargeter.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionTargeter.java @@ -22,7 +22,7 @@ package com.sun.org.apache.bcel.internal.generic; /** - * Denote that a class targets InstructionHandles within an InstructionList. Namely the following implementers: + * Denotes that a class targets InstructionHandles within an InstructionList. * * @see BranchHandle * @see LocalVariableGen @@ -33,9 +33,12 @@ public interface InstructionTargeter { // static final InstructionTargeter[] EMPTY_ARRAY = new InstructionTargeter[0]; /** - * Checks whether this targeter targets the specified instruction handle. + * Tests whether this targeter targets the specified instruction handle. + * + * @param instructionHandle the instruction handle to test. + * @return whether this targeter targets the specified instruction handle. */ - boolean containsTarget(InstructionHandle ih); + boolean containsTarget(InstructionHandle instructionHandle); /** * Replaces the target of this targeter from this old handle to the new handle. diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LCMP.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LCMP.java index c517b492f0a..188ac95f6ef 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LCMP.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LCMP.java @@ -27,7 +27,6 @@ package com.sun.org.apache.bcel.internal.generic; *
  * Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 -> ..., result <= -1, 0, 1>
  * 
- * */ public class LCMP extends Instruction implements TypedInstruction, StackProducer, StackConsumer { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LDC.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LDC.java index d95bade23bd..13ca0a84cfa 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LDC.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LDC.java @@ -94,6 +94,8 @@ public class LDC extends CPInstruction implements PushInstruction, ExceptionThro return Type.INT; case com.sun.org.apache.bcel.internal.Const.CONSTANT_Class: return Type.CLASS; + case com.sun.org.apache.bcel.internal.Const.CONSTANT_Dynamic: + return Type.OBJECT; default: // Never reached throw new IllegalArgumentException("Unknown or invalid constant type at " + super.getIndex()); } @@ -113,7 +115,10 @@ public class LDC extends CPInstruction implements PushInstruction, ExceptionThro case com.sun.org.apache.bcel.internal.Const.CONSTANT_Class: final int nameIndex = ((com.sun.org.apache.bcel.internal.classfile.ConstantClass) c).getNameIndex(); c = cpg.getConstantPool().getConstant(nameIndex); - return Type.getType(((com.sun.org.apache.bcel.internal.classfile.ConstantUtf8) c).getBytes()); + return Type.getType(Type.internalTypeNameToSignature(((com.sun.org.apache.bcel.internal.classfile.ConstantUtf8) c).getBytes())); + case com.sun.org.apache.bcel.internal.Const.CONSTANT_Dynamic: + // Really not sure what to return here, maybe a BootstrapMethod instance but how do we get it? + return c; default: // Never reached throw new IllegalArgumentException("Unknown or invalid constant type at " + super.getIndex()); } @@ -129,7 +134,7 @@ public class LDC extends CPInstruction implements PushInstruction, ExceptionThro } /** - * Set the index to constant pool and adjust size. + * Sets the index to constant pool and adjust size. */ @Override public final void setIndex(final int index) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LineNumberGen.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LineNumberGen.java index 3773c21e7b3..68bb2abf513 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LineNumberGen.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LineNumberGen.java @@ -54,7 +54,7 @@ public class LineNumberGen implements InstructionTargeter, Cloneable { try { return super.clone(); } catch (final CloneNotSupportedException e) { - throw new Error("Clone Not Supported"); // never happens + throw new UnsupportedOperationException("Clone Not Supported", e); // never happens } } @@ -71,7 +71,7 @@ public class LineNumberGen implements InstructionTargeter, Cloneable { } /** - * Get LineNumber attribute. + * Gets LineNumber attribute. * * This relies on that the instruction list has already been dumped to byte code or that the 'setPositions' methods * has been called for the instruction list. diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LocalVariableGen.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LocalVariableGen.java index 830564d42c9..71cfa0cf1c2 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LocalVariableGen.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LocalVariableGen.java @@ -85,7 +85,7 @@ public class LocalVariableGen implements InstructionTargeter, NamedAndTyped, Clo try { return super.clone(); } catch (final CloneNotSupportedException e) { - throw new Error("Clone Not Supported"); // never happens + throw new UnsupportedOperationException("Clone Not Supported", e); // never happens } } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LocalVariableInstruction.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LocalVariableInstruction.java index 67184c0b9f1..f952a65880b 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LocalVariableInstruction.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LocalVariableInstruction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -28,7 +28,7 @@ import com.sun.org.apache.bcel.internal.util.ByteSequence; /** * Abstract super class for instructions dealing with local variables. * - * @LastModified: May 2021 + * @LastModified: Sept 2025 */ public abstract class LocalVariableInstruction extends Instruction implements TypedInstruction, IndexedInstruction { @@ -162,7 +162,7 @@ public abstract class LocalVariableInstruction extends Instruction implements Ty } /** - * Set the local variable index. also updates opcode and length TODO Why? + * Sets the local variable index. also updates opcode and length TODO Why? * * @see #setIndexOnly(int) */ diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/MethodGen.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/MethodGen.java index f6e8333be79..be09b0a5159 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/MethodGen.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/MethodGen.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -27,6 +27,7 @@ import java.util.HashMap; import java.util.List; import java.util.Objects; import java.util.Stack; +import java.util.stream.Collectors; import com.sun.org.apache.bcel.internal.Const; import com.sun.org.apache.bcel.internal.classfile.AnnotationEntry; @@ -46,6 +47,7 @@ import com.sun.org.apache.bcel.internal.classfile.ParameterAnnotations; import com.sun.org.apache.bcel.internal.classfile.RuntimeVisibleParameterAnnotations; import com.sun.org.apache.bcel.internal.classfile.Utility; import com.sun.org.apache.bcel.internal.util.BCELComparator; +import jdk.xml.internal.Utils; /** * Template class for building up a method. This is done by defining exception handlers, adding thrown exceptions, local @@ -57,7 +59,7 @@ import com.sun.org.apache.bcel.internal.util.BCELComparator; * * @see InstructionList * @see Method - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public class MethodGen extends FieldGenOrMethodGen { @@ -102,19 +104,16 @@ public class MethodGen extends FieldGenOrMethodGen { } } - private static BCELComparator bcelComparator = new BCELComparator() { + private static BCELComparator bcelComparator = new BCELComparator() { @Override - public boolean equals(final Object o1, final Object o2) { - final FieldGenOrMethodGen THIS = (FieldGenOrMethodGen) o1; - final FieldGenOrMethodGen THAT = (FieldGenOrMethodGen) o2; - return Objects.equals(THIS.getName(), THAT.getName()) && Objects.equals(THIS.getSignature(), THAT.getSignature()); + public boolean equals(final FieldGenOrMethodGen a, final FieldGenOrMethodGen b) { + return a == b || a != null && b != null && Objects.equals(a.getName(), b.getName()) && Objects.equals(a.getSignature(), b.getSignature()); } @Override - public int hashCode(final Object o) { - final FieldGenOrMethodGen THIS = (FieldGenOrMethodGen) o; - return THIS.getSignature().hashCode() ^ THIS.getName().hashCode(); + public int hashCode(final FieldGenOrMethodGen o) { + return o != null ? Objects.hash(o.getSignature(), o.getName()) : 0; } }; @@ -127,9 +126,9 @@ public class MethodGen extends FieldGenOrMethodGen { } /** - * @return Comparison strategy object + * @return Comparison strategy object. */ - public static BCELComparator getComparator() { + public static BCELComparator getComparator() { return bcelComparator; } @@ -206,9 +205,9 @@ public class MethodGen extends FieldGenOrMethodGen { } /** - * @param comparator Comparison strategy object + * @param comparator Comparison strategy object. */ - public static void setComparator(final BCELComparator comparator) { + public static void setComparator(final BCELComparator comparator) { bcelComparator = comparator; } @@ -636,7 +635,7 @@ public class MethodGen extends FieldGenOrMethodGen { */ @Override public boolean equals(final Object obj) { - return bcelComparator.equals(this, obj); + return obj instanceof FieldGenOrMethodGen && bcelComparator.equals(this, (FieldGenOrMethodGen) obj); } // J5TODO: Should paramAnnotations be an array of arrays? Rather than an array of lists, this @@ -790,7 +789,7 @@ public class MethodGen extends FieldGenOrMethodGen { } /** - * Get method object. Never forget to call setMaxStack() or setMaxStack(max), respectively, before calling this method + * Gets method object. Never forget to call setMaxStack() or setMaxStack(max), respectively, before calling this method * (the same applies for max locals). * * @return method object @@ -888,7 +887,7 @@ public class MethodGen extends FieldGenOrMethodGen { } /** - * Return value as defined by given BCELComparator strategy. By default return the hashcode of the method's name XOR + * Return value as defined by given BCELComparator strategy. By default return the hash code of the method's name XOR * signature. * * @see Object#hashCode() @@ -899,11 +898,7 @@ public class MethodGen extends FieldGenOrMethodGen { } private List makeMutableVersion(final AnnotationEntry[] mutableArray) { - final List result = new ArrayList<>(); - for (final AnnotationEntry element : mutableArray) { - result.add(new AnnotationEntryGen(element, getConstantPool(), false)); - } - return result; + return Utils.streamOfIfNonNull(mutableArray).map(ae -> new AnnotationEntryGen(ae, getConstantPool(), false)).collect(Collectors.toList()); } /** @@ -1027,10 +1022,8 @@ public class MethodGen extends FieldGenOrMethodGen { * * @since 6.5.0 */ - public void removeRuntimeAttributes(final Attribute[] attrs) { - for (final Attribute attr : attrs) { - removeAttribute(attr); - } + public void removeRuntimeAttributes(final Attribute[] attributes) { + Utils.streamOfIfNonNull(attributes).forEach(this::removeAttribute); } public void setArgumentName(final int i, final String name) { @@ -1038,7 +1031,7 @@ public class MethodGen extends FieldGenOrMethodGen { } public void setArgumentNames(final String[] argNames) { - this.argNames = argNames; + this.argNames = Utils.createEmptyArrayIfNull(argNames, String[].class); } public void setArgumentType(final int i, final Type type) { @@ -1046,7 +1039,7 @@ public class MethodGen extends FieldGenOrMethodGen { } public void setArgumentTypes(final Type[] argTypes) { - this.argTypes = argTypes; + this.argTypes = argTypes != null ? argTypes : Type.NO_ARGS; } public void setClassName(final String className) { // TODO could be package-protected? @@ -1084,7 +1077,7 @@ public class MethodGen extends FieldGenOrMethodGen { } /** - * Set maximum number of local variables. + * Sets maximum number of local variables. */ public void setMaxLocals(final int m) { maxLocals = m; @@ -1102,7 +1095,7 @@ public class MethodGen extends FieldGenOrMethodGen { } /** - * Set maximum stack size for this method. + * Sets maximum stack size for this method. */ public void setMaxStack(final int m) { // TODO could be package-protected? maxStack = m; diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ObjectType.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ObjectType.java index 46378a1b71e..622a3cdd961 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ObjectType.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ObjectType.java @@ -27,7 +27,7 @@ import com.sun.org.apache.bcel.internal.classfile.JavaClass; import com.sun.org.apache.bcel.internal.classfile.Utility; /** - * Denotes reference such as java.lang.String. + * Denotes reference such as {@link String}. */ public class ObjectType extends ReferenceType { @@ -47,7 +47,7 @@ public class ObjectType extends ReferenceType { /** * Constructs a new instance. * - * @param className fully qualified class name, e.g. java.lang.String + * @param className fully qualified class name, e.g. {@link String} */ public ObjectType(final String className) { super(Const.T_REFERENCE, "L" + Utility.packageToPath(className) + ";"); @@ -151,7 +151,7 @@ public class ObjectType extends ReferenceType { * @throws ClassNotFoundException if any of this class's superclasses can't be found */ public boolean subclassOf(final ObjectType superclass) throws ClassNotFoundException { - if (this.referencesInterfaceExact() || superclass.referencesInterfaceExact()) { + if (referencesInterfaceExact() || superclass.referencesInterfaceExact()) { return false; } return Repository.instanceOf(this.className, superclass.className); diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/RET.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/RET.java index a7cacc7c165..99a1efbed16 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/RET.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/RET.java @@ -110,7 +110,7 @@ public class RET extends Instruction implements IndexedInstruction, TypedInstruc } /** - * Set index of local variable containg the return address + * Sets index of local variable containg the return address */ @Override public final void setIndex(final int n) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ReferenceType.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ReferenceType.java index fe75792e213..9b94a1dcf2d 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ReferenceType.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ReferenceType.java @@ -42,10 +42,10 @@ public abstract class ReferenceType extends Type { /** * This commutative operation returns the first common superclass (narrowest ReferenceType referencing a class, not an - * interface). If one of the types is a superclass of the other, the former is returned. If "this" is Type.NULL, then t - * is returned. If t is Type.NULL, then "this" is returned. If "this" equals t ['this.equals(t)'] "this" is returned. If - * "this" or t is an ArrayType, then Type.OBJECT is returned. If "this" or t is a ReferenceType referencing an - * interface, then Type.OBJECT is returned. If not all of the two classes' superclasses cannot be found, "null" is + * interface). If one of the types is a superclass of the other, the former is returned. If "this" is NULL, then t + * is returned. If t is NULL, then "this" is returned. If "this" equals t ['this.equals(t)'] "this" is returned. If + * "this" or t is an ArrayType, then {@link #OBJECT} is returned. If "this" or t is a ReferenceType referencing an + * interface, then {@link #OBJECT} is returned. If not all of the two classes' superclasses cannot be found, "null" is * returned. See the JVM specification edition 2, "4.9.2 The Bytecode Verifier". * * @deprecated use getFirstCommonSuperclass(ReferenceType t) which has slightly changed semantics. @@ -53,46 +53,46 @@ public abstract class ReferenceType extends Type { */ @Deprecated public ReferenceType firstCommonSuperclass(final ReferenceType t) throws ClassNotFoundException { - if (this.equals(Type.NULL)) { + if (equals(NULL)) { return t; } - if (t.equals(Type.NULL) || this.equals(t)) { + if (t.equals(NULL) || equals(t)) { return this; /* - * TODO: Above sounds a little arbitrary. On the other hand, there is no object referenced by Type.NULL so we can also - * say all the objects referenced by Type.NULL were derived from java.lang.Object. However, the Java Language's - * "instanceof" operator proves us wrong: "null" is not referring to an instance of java.lang.Object :) + * TODO: Above sounds a little arbitrary. On the other hand, there is no object referenced by {@link #NULL} so we can also + * say all the objects referenced by {@link #NULL} were derived from {@link Object}. However, the Java Language's + * "instanceof" operator proves us wrong: "null" is not referring to an instance of {@link Object} :) */ } if (this instanceof ArrayType || t instanceof ArrayType) { - return Type.OBJECT; - // TODO: Is there a proof of OBJECT being the direct ancestor of every ArrayType? + return OBJECT; + // TODO: Is there a proof of {@link #OBJECT} being the direct ancestor of every ArrayType? } return getFirstCommonSuperclassInternal(t); } /** * This commutative operation returns the first common superclass (narrowest ReferenceType referencing a class, not an - * interface). If one of the types is a superclass of the other, the former is returned. If "this" is Type.NULL, then t - * is returned. If t is Type.NULL, then "this" is returned. If "this" equals t ['this.equals(t)'] "this" is returned. If - * "this" or t is an ArrayType, then Type.OBJECT is returned; unless their dimensions match. Then an ArrayType of the + * interface). If one of the types is a superclass of the other, the former is returned. If "this" is NULL, then t + * is returned. If t is NULL, then "this" is returned. If "this" equals t ['this.equals(t)'] "this" is returned. If + * "this" or t is an ArrayType, then {@link #OBJECT} is returned; unless their dimensions match. Then an ArrayType of the * same number of dimensions is returned, with its basic type being the first common super class of the basic types of - * "this" and t. If "this" or t is a ReferenceType referencing an interface, then Type.OBJECT is returned. If not all of + * "this" and t. If "this" or t is a ReferenceType referencing an interface, then {@link #OBJECT} is returned. If not all of * the two classes' superclasses cannot be found, "null" is returned. See the JVM specification edition 2, "4.9.2 The * Bytecode Verifier". * * @throws ClassNotFoundException on failure to find superclasses of this type, or the type passed as a parameter */ public ReferenceType getFirstCommonSuperclass(final ReferenceType t) throws ClassNotFoundException { - if (this.equals(Type.NULL)) { + if (equals(NULL)) { return t; } - if (t.equals(Type.NULL) || this.equals(t)) { + if (t.equals(NULL) || equals(t)) { return this; /* - * TODO: Above sounds a little arbitrary. On the other hand, there is no object referenced by Type.NULL so we can also - * say all the objects referenced by Type.NULL were derived from java.lang.Object. However, the Java Language's - * "instanceof" operator proves us wrong: "null" is not referring to an instance of java.lang.Object :) + * TODO: Above sounds a little arbitrary. On the other hand, there is no object referenced by {@link #NULL} so we can also + * say all the objects referenced by {@link #NULL} were derived from {@link Object}. However, the Java Language's + * "instanceof" operator proves us wrong: "null" is not referring to an instance of {@link Object} :) */ } /* This code is from a bug report by Konstantin Shagin */ @@ -106,8 +106,8 @@ public abstract class ReferenceType extends Type { } } if (this instanceof ArrayType || t instanceof ArrayType) { - return Type.OBJECT; - // TODO: Is there a proof of OBJECT being the direct ancestor of every ArrayType? + return OBJECT; + // TODO: Is there a proof of {@link #OBJECT} being the direct ancestor of every ArrayType? } return getFirstCommonSuperclassInternal(t); } @@ -115,7 +115,7 @@ public abstract class ReferenceType extends Type { private ReferenceType getFirstCommonSuperclassInternal(final ReferenceType t) throws ClassNotFoundException { if (this instanceof ObjectType && ((ObjectType) this).referencesInterfaceExact() || t instanceof ObjectType && ((ObjectType) t).referencesInterfaceExact()) { - return Type.OBJECT; + return OBJECT; // TODO: The above line is correct comparing to the vmspec2. But one could // make class file verification a bit stronger here by using the notion of // superinterfaces or even castability or assignment compatibility. @@ -142,7 +142,7 @@ public abstract class ReferenceType extends Type { } } } - // Huh? Did you ask for Type.OBJECT's superclass?? + // Huh? Did you ask for OBJECT's superclass?? return null; } @@ -158,7 +158,7 @@ public abstract class ReferenceType extends Type { return false; } final ReferenceType T = (ReferenceType) t; - if (this.equals(Type.NULL)) { + if (equals(NULL)) { return true; // This is not explicitly stated, but clear. Isn't it? } /* @@ -169,7 +169,7 @@ public abstract class ReferenceType extends Type { * If T is a class type, then this must be the same class as T, or this must be a subclass of T; */ if (T instanceof ObjectType && ((ObjectType) T).referencesClassExact() - && (this.equals(T) || Repository.instanceOf(((ObjectType) this).getClassName(), ((ObjectType) T).getClassName()))) { + && (equals(T) || Repository.instanceOf(((ObjectType) this).getClassName(), ((ObjectType) T).getClassName()))) { return true; } /* @@ -187,14 +187,14 @@ public abstract class ReferenceType extends Type { /* * If T is a class type, then T must be Object (2.4.7). */ - if (T instanceof ObjectType && ((ObjectType) T).referencesClassExact() && T.equals(Type.OBJECT)) { + if (T instanceof ObjectType && ((ObjectType) T).referencesClassExact() && T.equals(OBJECT)) { return true; } /* * If T is an interface type, then T must be the same interface as this or a superinterface of this (2.13.2). */ if (T instanceof ObjectType && ((ObjectType) T).referencesInterfaceExact() - && (this.equals(T) || Repository.implementationOf(((ObjectType) this).getClassName(), ((ObjectType) T).getClassName()))) { + && (equals(T) || Repository.implementationOf(((ObjectType) this).getClassName(), ((ObjectType) T).getClassName()))) { return true; } } @@ -205,7 +205,7 @@ public abstract class ReferenceType extends Type { /* * If T is a class type, then T must be Object (2.4.7). */ - if (T instanceof ObjectType && ((ObjectType) T).referencesClassExact() && T.equals(Type.OBJECT)) { + if (T instanceof ObjectType && ((ObjectType) T).referencesClassExact() && T.equals(OBJECT)) { return true; } /* @@ -246,14 +246,14 @@ public abstract class ReferenceType extends Type { /** * Return true iff this type is castable to another type t as defined in the JVM specification. The case where this is - * Type.NULL is not defined (see the CHECKCAST definition in the JVM specification). However, because e.g. CHECKCAST + * {@link #NULL} is not defined (see the CHECKCAST definition in the JVM specification). However, because e.g. CHECKCAST * doesn't throw a ClassCastException when casting a null reference to any Object, true is returned in this case. * * @throws ClassNotFoundException if any classes or interfaces required to determine assignment compatibility can't be * found */ public boolean isCastableTo(final Type t) throws ClassNotFoundException { - if (this.equals(Type.NULL)) { + if (equals(NULL)) { return t instanceof ReferenceType; // If this is ever changed in isAssignmentCompatible() } return isAssignmentCompatibleWith(t); diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/SWITCH.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/SWITCH.java index aed1626ec0d..f929176c174 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/SWITCH.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/SWITCH.java @@ -95,7 +95,7 @@ public final class SWITCH implements CompoundInstruction { * @param maxGap maximum gap that may between case branches */ public SWITCH(final int[] match, final InstructionHandle[] targets, final InstructionHandle target, final int maxGap) { - int[] matchClone = match.clone(); + final int[] matchClone = match.clone(); final InstructionHandle[] targetsClone = targets.clone(); final int matchLength = match.length; if (matchLength < 2) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/Select.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/Select.java index a90e795e99f..a3086ac1664 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/Select.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/Select.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -33,7 +33,7 @@ import com.sun.org.apache.bcel.internal.util.ByteSequence; * @see LOOKUPSWITCH * @see TABLESWITCH * @see InstructionList - * @LastModified: May 2021 + * @LastModified: Sept 2025 */ public abstract class Select extends BranchInstruction implements VariableLengthInstruction, StackConsumer /* @since 6.0 */, StackProducer { @@ -87,7 +87,7 @@ public abstract class Select extends BranchInstruction implements VariableLength * @param defaultTarget default instruction target */ Select(final short opcode, final int[] match, final InstructionHandle[] targets, final InstructionHandle defaultTarget) { - // don't set default target before instuction is built + // don't set default target before instruction is built super(opcode, null); this.match = match; this.targets = targets; @@ -288,7 +288,7 @@ public abstract class Select extends BranchInstruction implements VariableLength } /** - * Set branch target for 'i'th case + * Sets branch target for 'i'th case */ public void setTarget(final int i, final InstructionHandle target) { // TODO could be package-protected? notifyTarget(targets[i], target, this); @@ -314,7 +314,11 @@ public abstract class Select extends BranchInstruction implements VariableLength for (int i = 0; i < match_length; i++) { String s = "null"; if (targets[i] != null) { - s = targets[i].getInstruction().toString(); + if (targets[i].getInstruction() == this) { + s = ""; + } else { + s = targets[i].getInstruction().toString(); + } } buf.append("(").append(match[i]).append(", ").append(s).append(" = {").append(indices[i]).append("})"); } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/SimpleElementValueGen.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/SimpleElementValueGen.java index a4de20315d7..363b3237632 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/SimpleElementValueGen.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/SimpleElementValueGen.java @@ -166,7 +166,7 @@ public class SimpleElementValueGen extends ElementValueGen { dos.writeShort(idx); break; default: - throw new IllegalStateException("SimpleElementValueGen doesnt know how to write out type " + super.getElementValueType()); + throw new IllegalStateException("SimpleElementValueGen doesn't know how to write out type " + super.getElementValueType()); } } @@ -184,7 +184,7 @@ public class SimpleElementValueGen extends ElementValueGen { public int getValueInt() { if (super.getElementValueType() != PRIMITIVE_INT) { - throw new IllegalStateException("Dont call getValueString() on a non STRING ElementValue"); + throw new IllegalStateException("Don't call getValueString() on a non STRING ElementValue"); } final ConstantInteger c = (ConstantInteger) getConstantPool().getConstant(idx); return c.getBytes(); @@ -192,7 +192,7 @@ public class SimpleElementValueGen extends ElementValueGen { public String getValueString() { if (super.getElementValueType() != STRING) { - throw new IllegalStateException("Dont call getValueString() on a non STRING ElementValue"); + throw new IllegalStateException("Don't call getValueString() on a non STRING ElementValue"); } final ConstantUtf8 c = (ConstantUtf8) getConstantPool().getConstant(idx); return c.getBytes(); diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/TargetLostException.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/TargetLostException.java index 40ed6ff4c38..038bbe63148 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/TargetLostException.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/TargetLostException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -21,32 +21,32 @@ package com.sun.org.apache.bcel.internal.generic; /** - * Thrown by InstructionList.remove() when one or multiple disposed instructions are still being referenced by an - * InstructionTargeter object. I.e. the InstructionTargeter has to be notified that (one of) the InstructionHandle it is - * referencing is being removed from the InstructionList and thus not valid anymore. + * Thrown by {@link InstructionList} when one or multiple disposed instructions are still being referenced by an {@link InstructionTargeter} object. I.e. the + * {@link InstructionTargeter} has to be notified that (one of) the {@link InstructionHandle} it is referencing is being removed from the + * {@link InstructionList} and thus not valid anymore. * *

- * Making this an exception instead of a return value forces the user to handle these case explicitly in a try { ... } - * catch. The following code illustrates how this may be done: + * Making this an exception instead of a return value forces the user to handle these case explicitly in a try { ... } catch. The following code illustrates how + * this may be done: *

* - *
+ * 
  *     ...
  *     try {
  *         il.delete(start_ih, end_ih);
- *     } catch(TargetLostException e) {
+ *     } catch (TargetLostException e) {
  *         for (InstructionHandle target : e.getTargets()) {
  *             for (InstructionTargeter targeter : target.getTargeters()) {
  *                 targeter.updateTarget(target, new_target);
  *             }
  *         }
  *     }
- * 
+ *
* * @see InstructionHandle * @see InstructionList * @see InstructionTargeter - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public final class TargetLostException extends Exception { @@ -54,12 +54,14 @@ public final class TargetLostException extends Exception { @SuppressWarnings("serial") // Array component type is not Serializable private final InstructionHandle[] targets; - TargetLostException(final InstructionHandle[] t, final String mesg) { - super(mesg); - targets = t; + TargetLostException(final InstructionHandle[] targets, final String message) { + super(message); + this.targets = targets; } /** + * Gets the list of instructions still being targeted. + * * @return list of instructions still being targeted. */ public InstructionHandle[] getTargets() { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/Type.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/Type.java index ea20710af2e..b58645b402e 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/Type.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/Type.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -26,12 +26,14 @@ import java.util.Objects; import com.sun.org.apache.bcel.internal.Const; import com.sun.org.apache.bcel.internal.classfile.ClassFormatException; +import com.sun.org.apache.bcel.internal.classfile.InvalidMethodSignatureException; import com.sun.org.apache.bcel.internal.classfile.Utility; +import jdk.xml.internal.Utils; /** - * Abstract super class for all possible java types, namely basic types such as int, object types like String and array + * Abstract super class for all possible Java types, namely basic types such as int, object types like String and array * types, e.g. int[] - * @LastModified: May 2021 + * @LastModified: Sept 2025 */ public abstract class Type { @@ -88,15 +90,15 @@ public abstract class Type { // Skip any type arguments to read argument declarations between '(' and ')' index = signature.indexOf('(') + 1; if (index <= 0) { - throw new ClassFormatException("Invalid method signature: " + signature); + throw new InvalidMethodSignatureException(signature); } while (signature.charAt(index) != ')') { vec.add(getType(signature.substring(index))); - // corrected concurrent private static field acess + // corrected concurrent private static field access index += unwrap(CONSUMED_CHARS); // update position } } catch (final StringIndexOutOfBoundsException e) { // Should never occur - throw new ClassFormatException("Invalid method signature: " + signature, e); + throw new InvalidMethodSignatureException(signature, e); } final Type[] types = new Type[vec.size()]; vec.toArray(types); @@ -110,7 +112,7 @@ public abstract class Type { // Skip any type arguments to read argument declarations between '(' and ')' index = signature.indexOf('(') + 1; if (index <= 0) { - throw new ClassFormatException("Invalid method signature: " + signature); + throw new InvalidMethodSignatureException(signature); } while (signature.charAt(index) != ')') { final int coded = getTypeSize(signature.substring(index)); @@ -118,7 +120,7 @@ public abstract class Type { index += consumed(coded); } } catch (final StringIndexOutOfBoundsException e) { // Should never occur - throw new ClassFormatException("Invalid method signature: " + signature, e); + throw new InvalidMethodSignatureException(signature, e); } return res; } @@ -154,13 +156,13 @@ public abstract class Type { final int index = signature.lastIndexOf(')') + 1; return getType(signature.substring(index)); } catch (final StringIndexOutOfBoundsException e) { // Should never occur - throw new ClassFormatException("Invalid method signature: " + signature, e); + throw new InvalidMethodSignatureException(signature, e); } } static int getReturnTypeSize(final String signature) { final int index = signature.lastIndexOf(')') + 1; - return Type.size(getTypeSize(signature.substring(index))); + return size(getTypeSize(signature.substring(index))); } public static String getSignature(final java.lang.reflect.Method meth) { @@ -175,7 +177,7 @@ public abstract class Type { } /** - * Convert runtime java.lang.Class to BCEL Type object. + * Convert runtime {@link Class} to BCEL Type object. * * @param cls Java class * @return corresponding Type object @@ -183,7 +185,7 @@ public abstract class Type { public static Type getType(final Class cls) { Objects.requireNonNull(cls, "cls"); /* - * That's an amzingly easy case, because getName() returns the signature. That's what we would have liked anyway. + * That's an amazingly easy case, because getName() returns the signature. That's what we would have liked anyway. */ if (cls.isArray()) { return getType(cls.getName()); @@ -230,7 +232,7 @@ public abstract class Type { public static Type getType(final String signature) throws StringIndexOutOfBoundsException { final byte type = Utility.typeOfSignature(signature); if (type <= Const.T_VOID) { - // corrected concurrent private static field acess + // corrected concurrent private static field access wrap(CONSUMED_CHARS, 1); return BasicType.getType(type); } @@ -246,7 +248,7 @@ public abstract class Type { } while (signature.charAt(dim) == '['); // Recurse, but just once, if the signature is ok final Type t = getType(signature.substring(dim)); - // corrected concurrent private static field acess + // corrected concurrent private static field access // consumed_chars += dim; // update counter - is replaced by final int temp = unwrap(CONSUMED_CHARS) + dim; wrap(CONSUMED_CHARS, temp); @@ -254,7 +256,7 @@ public abstract class Type { } /** - * Convert runtime java.lang.Class[] to BCEL Type objects. + * Convert runtime {@code java.lang.Class[]} to BCEL Type objects. * * @param classes an array of runtime class objects * @return array of corresponding Type objects @@ -286,6 +288,24 @@ public abstract class Type { return encode(1, index + 1); } + static String internalTypeNameToSignature(final String internalTypeName) { + if (Utils.isEmpty(internalTypeName) || Arrays.asList(Const.SHORT_TYPE_NAMES).contains(internalTypeName)) { + return internalTypeName; + } + switch (internalTypeName.charAt(0)) { + case '[': + return internalTypeName; + case 'L': + case 'T': + if (internalTypeName.charAt(internalTypeName.length() - 1) == ';') { + return internalTypeName; + } + return 'L' + internalTypeName + ';'; + default: + return 'L' + internalTypeName + ';'; + } + } + static int size(final int coded) { return coded & 3; } @@ -361,7 +381,7 @@ public abstract class Type { } /** - * @return hashcode of Type + * @return hash code of Type */ @Override public int hashCode() { @@ -369,31 +389,23 @@ public abstract class Type { } /** - * boolean, short and char variable are considered as int in the stack or local variable area. Returns {@link Type#INT} - * for {@link Type#BOOLEAN}, {@link Type#SHORT} or {@link Type#CHAR}, otherwise returns the given type. + * boolean, short and char variable are considered as int in the stack or local variable area. Returns {@link #INT} + * for {@link #BOOLEAN}, {@link #SHORT} or {@link #CHAR}, otherwise returns the given type. * * @since 6.0 */ public Type normalizeForStackOrLocal() { - if (this == Type.BOOLEAN || this == Type.BYTE || this == Type.SHORT || this == Type.CHAR) { - return Type.INT; + if (this == BOOLEAN || this == BYTE || this == SHORT || this == CHAR) { + return INT; } return this; } - /* - * Currently only used by the ArrayType constructor. The signature has a complicated dependency on other parameter so - * it's tricky to do it in a call to the super ctor. - */ - void setSignature(final String signature) { - this.signature = signature; - } - /** * @return Type string, e.g. 'int[]' */ @Override public String toString() { - return this.equals(Type.NULL) || type >= Const.T_UNKNOWN ? signature : Utility.signatureToString(signature, false); + return equals(NULL) || type >= Const.T_UNKNOWN ? signature : Utility.signatureToString(signature, false); } } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/TypedInstruction.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/TypedInstruction.java index 5a22942a6a7..27b952f3996 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/TypedInstruction.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/TypedInstruction.java @@ -22,7 +22,7 @@ package com.sun.org.apache.bcel.internal.generic; /** - * Get the type associated with an instruction, int for ILOAD, or the type of the field of a PUTFIELD instruction, e.g.. + * Gets the type associated with an instruction, int for ILOAD, or the type of the field of a PUTFIELD instruction, e.g.. */ public interface TypedInstruction { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/package-info.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/package-info.java new file mode 100644 index 00000000000..63d4dc876ce --- /dev/null +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/package-info.java @@ -0,0 +1,26 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Generic part of the Apache Byte Code Engineering Library (BCEL), classes to dynamically modify class objects + * and byte code instructions. + */ +package com.sun.org.apache.bcel.internal.generic; diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/package-info.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/package-info.java new file mode 100644 index 00000000000..581037d7981 --- /dev/null +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/package-info.java @@ -0,0 +1,26 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Basic classes for the Apache Byte Code Engineering Library (BCEL) and constants defined by the + * JVM specification. + */ +package com.sun.org.apache.bcel.internal; diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/BCELComparator.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/BCELComparator.java index 2e663bfdaa1..fb32dc35e0b 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/BCELComparator.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/BCELComparator.java @@ -22,26 +22,27 @@ package com.sun.org.apache.bcel.internal.util; /** - * Used for BCEL comparison strategy + * Used for BCEL comparison strategy. * + * @param What type we are comparing. * @since 5.2 */ -public interface BCELComparator { +public interface BCELComparator { /** - * Compare two objects and return what THIS.equals(THAT) should return + * Compares two objects and return what a.equals(b) should return. * - * @param THIS - * @param THAT - * @return true if and only if THIS equals THAT + * @param a an object. + * @param b an object to be compared with {@code a} for equality. + * @return {@code true} if the arguments are equal to each other and {@code false} otherwise. */ - boolean equals(Object THIS, Object THAT); + boolean equals(T a, T b); /** - * Return hashcode for THIS.hashCode() + * Gets the hash code for o.hashCode() * - * @param THIS - * @return hashcode for THIS.hashCode() + * @param o + * @return hash code for o.hashCode() */ - int hashCode(Object THIS); + int hashCode(T o); } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/BCELFactory.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/BCELFactory.java index c931fb1e422..93f22e7d0ad 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/BCELFactory.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/BCELFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -63,9 +63,9 @@ import com.sun.org.apache.bcel.internal.generic.Type; * Factory creates il.append() statements, and sets instruction targets. A helper class for BCELifier. * * @see BCELifier - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ -class BCELFactory extends EmptyVisitor { +final class BCELFactory extends EmptyVisitor { private static final String CONSTANT_PREFIX = Const.class.getSimpleName() + "."; private final MethodGen methodGen; @@ -88,7 +88,7 @@ class BCELFactory extends EmptyVisitor { if (value instanceof String) { embed = '"' + Utility.convertString(embed) + '"'; } else if (value instanceof Character) { - embed = "(char)0x" + Integer.toHexString(((Character) value).charValue()); + embed = "(char) 0x" + Integer.toHexString(((Character) value).charValue()); } else if (value instanceof Float) { final Float f = (Float) value; if (Float.isNaN(f)) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/BCELifier.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/BCELifier.java index 151083ea71b..0eb9bfb4ee1 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/BCELifier.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/BCELifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -30,11 +30,15 @@ import java.util.Locale; import com.sun.org.apache.bcel.internal.Const; import com.sun.org.apache.bcel.internal.Repository; import com.sun.org.apache.bcel.internal.classfile.ClassParser; +import com.sun.org.apache.bcel.internal.classfile.Code; import com.sun.org.apache.bcel.internal.classfile.ConstantValue; import com.sun.org.apache.bcel.internal.classfile.ExceptionTable; import com.sun.org.apache.bcel.internal.classfile.Field; import com.sun.org.apache.bcel.internal.classfile.JavaClass; import com.sun.org.apache.bcel.internal.classfile.Method; +import com.sun.org.apache.bcel.internal.classfile.StackMap; +import com.sun.org.apache.bcel.internal.classfile.StackMapEntry; +import com.sun.org.apache.bcel.internal.classfile.StackMapType; import com.sun.org.apache.bcel.internal.classfile.Utility; import com.sun.org.apache.bcel.internal.generic.ArrayType; import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; @@ -46,7 +50,7 @@ import com.sun.org.apache.bcel.internal.generic.Type; * This gives new users of BCEL a useful example showing how things are done with BCEL. It does not cover all features * of BCEL, but tries to mimic hand-written code as close as possible. * - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public class BCELifier extends com.sun.org.apache.bcel.internal.classfile.EmptyVisitor { @@ -74,7 +78,7 @@ public class BCELifier extends com.sun.org.apache.bcel.internal.classfile.EmptyV /** * Default main method */ - public static void _main(final String[] argv) throws Exception { + public static void main(final String[] argv) throws Exception { if (argv.length != 1) { System.out.println("Usage: BCELifier className"); System.out.println("\tThe class must exist on the classpath"); @@ -311,6 +315,13 @@ public class BCELifier extends com.sun.org.apache.bcel.internal.classfile.EmptyV printWriter.println("\");"); } } + final Code code = method.getCode(); + if (code != null) { + final StackMap stackMap = code.getStackMap(); + if (stackMap != null) { + stackMap.accept(this); + } + } printWriter.println(); final BCELFactory factory = new BCELFactory(mg, printWriter); factory.start(); @@ -319,4 +330,78 @@ public class BCELifier extends com.sun.org.apache.bcel.internal.classfile.EmptyV printWriter.println(" _cg.addMethod(method.getMethod());"); printWriter.println(" il.dispose();"); } + + @Override + public void visitStackMap(final StackMap stackMap) { + super.visitStackMap(stackMap); + printWriter.print(" method.addCodeAttribute("); + printWriter.print("new StackMap(_cp.addUtf8(\""); + printWriter.print(stackMap.getName()); + printWriter.print("\"), "); + printWriter.print(stackMap.getLength()); + printWriter.print(", "); + printWriter.print("new StackMapEntry[] {"); + final StackMapEntry[] table = stackMap.getStackMap(); + for (int i = 0; i < table.length; i++) { + table[i].accept(this); + if (i < table.length - 1) { + printWriter.print(", "); + } else { + printWriter.print(" }"); + } + } + printWriter.print(", _cp.getConstantPool())"); + printWriter.println(");"); + } + + @Override + public void visitStackMapEntry(final StackMapEntry stackMapEntry) { + super.visitStackMapEntry(stackMapEntry); + printWriter.print("new StackMapEntry("); + printWriter.print(stackMapEntry.getFrameType()); + printWriter.print(", "); + printWriter.print(stackMapEntry.getByteCodeOffset()); + printWriter.print(", "); + visitStackMapTypeArray(stackMapEntry.getTypesOfLocals()); + printWriter.print(", "); + visitStackMapTypeArray(stackMapEntry.getTypesOfStackItems()); + printWriter.print(", _cp.getConstantPool())"); + } + + /** + * Visits a {@link StackMapType} object. + * @param stackMapType object to visit + * @since 6.7.1 + */ + @Override + public void visitStackMapType(final StackMapType stackMapType) { + super.visitStackMapType(stackMapType); + printWriter.print("new StackMapType((byte)"); + printWriter.print(stackMapType.getType()); + printWriter.print(", "); + if (stackMapType.hasIndex()) { + printWriter.print("_cp.addClass(\""); + printWriter.print(stackMapType.getClassName()); + printWriter.print("\")"); + } else { + printWriter.print("-1"); + } + printWriter.print(", _cp.getConstantPool())"); + } + + private void visitStackMapTypeArray(final StackMapType[] types) { + if (types == null || types.length == 0) { + printWriter.print("null"); // null translates to StackMapType.EMPTY_ARRAY + } else { + printWriter.print("new StackMapType[] {"); + for (int i = 0; i < types.length; i++) { + types[i].accept(this); + if (i < types.length - 1) { + printWriter.print(", "); + } else { + printWriter.print(" }"); + } + } + } + } } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/Class2HTML.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/Class2HTML.java index f644c698b72..10d31974d47 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/Class2HTML.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/Class2HTML.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -53,7 +53,7 @@ import com.sun.org.apache.bcel.internal.classfile.Utility; * All subfiles reference each other appropriately, e.g. clicking on a method in the Method's frame will jump to the * appropriate method in the Code frame. * - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public class Class2HTML { @@ -73,7 +73,7 @@ public class Class2HTML { basicTypes.add("float"); } - public static void _main(final String[] argv) throws IOException { + public static void main(final String[] argv) throws IOException { final String[] fileName = new String[argv.length]; int files = 0; ClassParser parser = null; @@ -89,7 +89,7 @@ public class Class2HTML { if (argv[i].equals("-d")) { // Specify target directory, default '.' dir = argv[++i]; if (!dir.endsWith("" + sep)) { - dir = dir + sep; + dir += sep; } final File store = new File(dir); if (!store.isDirectory()) { @@ -115,7 +115,7 @@ public class Class2HTML { if (zipFile == null) { parser = new ClassParser(fileName[i]); // Create parser object from file } else { - parser = new ClassParser(zipFile, fileName[i]); // Create parser object from zip file + parser = new ClassParser(zipFile, fileName[i]); // Create parser object from ZIP file } javaClass = parser.parse(); new Class2HTML(javaClass, dir); diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/ClassSet.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/ClassSet.java index 178ccc786b1..e95e8fbd0a0 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/ClassSet.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/ClassSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -30,7 +30,7 @@ import com.sun.org.apache.bcel.internal.classfile.JavaClass; * Utility class implementing a (type-safe) set of JavaClass objects. Since JavaClass has no equals() method, the name of the class is used for comparison. * * @see ClassStack - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public class ClassSet { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/CodeHTML.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/CodeHTML.java index 723fc07509b..1935d724b3b 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/CodeHTML.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/CodeHTML.java @@ -542,7 +542,7 @@ final class CodeHTML { final String str = codeToHTML(stream, methodNumber); String anchor = ""; /* - * Set an anchor mark if this line is targetted by a goto, jsr, etc. Defining an anchor for every line is very + * Sets an anchor mark if this line is targetted by a goto, jsr, etc. Defining an anchor for every line is very * inefficient! */ if (gotoSet.get(offset)) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/InstructionFinder.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/InstructionFinder.java index 5b045bf08cc..510fe4a03a6 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/InstructionFinder.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/InstructionFinder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -63,14 +63,13 @@ import com.sun.org.apache.bcel.internal.generic.InstructionList; * * @see com.sun.org.apache.bcel.internal.generic.Instruction * @see InstructionList - * @LastModified: May 2021 + * @LastModified: Sept 2025 */ public class InstructionFinder { /** * Code patterns found may be checked using an additional user-defined constraint object whether they really match the * needed criterion. I.e., check constraints that can not expressed with regular expressions. - * */ public interface CodeConstraint { @@ -374,7 +373,7 @@ public class InstructionFinder { // } // private static final String pattern2string( String pattern, boolean make_string ) { -// StringBuffer buf = new StringBuffer(); +// StringBuilder buf = new StringBuilder(); // for (int i = 0; i < pattern.length(); i++) { // char ch = pattern.charAt(i); // if (ch >= OFFSET) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/Repository.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/Repository.java index 8d1ddf493cd..c44e36d0a81 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/Repository.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/Repository.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -25,8 +25,8 @@ import com.sun.org.apache.bcel.internal.classfile.JavaClass; * Abstract definition of a class repository. Instances may be used to load classes from different sources and may be * used in the Repository.setRepository method. * - * @see org.apache.bcel.Repository - * @LastModified: Feb 2023 + * @see com.sun.org.apache.bcel.internal.Repository + * @LastModified: Sept 2025 */ public interface Repository { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/package-info.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/package-info.java new file mode 100644 index 00000000000..2bd92f155bc --- /dev/null +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/package-info.java @@ -0,0 +1,32 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Utility classes for the Apache Byte Code Engineering Library (BCEL), namely: + *
    + *
  • Collection classes for JavaClass objects
  • + *
  • A converter for class files to HTML
  • + *
  • A tool to find instructions patterns via regular expressions
  • + *
  • A class to find classes as defined in the CLASSPATH
  • + *
  • A class loader that allows to create classes at run time
  • + *
+ */ +package com.sun.org.apache.bcel.internal.util; diff --git a/src/java.xml/share/classes/jdk/xml/internal/Utils.java b/src/java.xml/share/classes/jdk/xml/internal/Utils.java index f55ab95a58f..96d9b1b9521 100644 --- a/src/java.xml/share/classes/jdk/xml/internal/Utils.java +++ b/src/java.xml/share/classes/jdk/xml/internal/Utils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,11 @@ package jdk.xml.internal; +import java.lang.reflect.Array; import java.util.Arrays; +import java.util.Objects; import java.util.function.Supplier; +import java.util.stream.Stream; /** * General utility. Use JdkXmlUtils for XML processing related functions. @@ -76,4 +79,59 @@ public class Utils { System.arraycopy(items, 0, result, original.length, items.length); return result; } + + /** + * Returns the original array, or an empty array if it is {@code null}. + * @param array the specified array + * @return the original array, or an empty array if it is {@code null} + */ + public static byte[] createEmptyArrayIfNull(byte[] array) { + return (array != null) ? array : new byte[0]; + } + + /** + * Returns the original array, or an empty array if it is {@code null}. + * @param array the specified array + * @return the original array, or an empty array if it is {@code null} + */ + public static int[] createEmptyArrayIfNull(int[] array) { + return (array != null) ? array : new int[0]; + } + + /** + * Returns the original array, or an empty array if it is {@code null}. + * @param the class type + * @param array the specified array + * @param type the type of the array + * @return the original array, or an empty array if it is {@code null} + */ + public static T[] createEmptyArrayIfNull(final T[] array, final Class type) { + Objects.requireNonNull(type, "The type argument should not be null."); + + return (array != null) ? array : type.cast(Array.newInstance(type.getComponentType(), 0)); + } + + /** + * Returns the new stream created by {@code Stream.of(values)} or an empty + * sequential stream created by {@code Stream.empty()} if values is null. + * + * @param the type of stream elements + * @param values the elements of the new stream + * @return the new stream created by {@code Stream.of(values)} or an empty + * sequential stream created by {@code Stream.empty()} if values is null. + */ + @SafeVarargs + @SuppressWarnings("varargs") // Creating a stream from an array is safe + public static Stream streamOfIfNonNull(final T... values) { + return values == null ? Stream.empty() : Stream.of(values); + } + + /** + * Checks if a CharSequence is empty ("") or null. + * @param cs the CharSequence to check, may be null + * @return {@code true} if the CharSequence is empty or null + */ + public static boolean isEmpty(final CharSequence cs) { + return cs == null || cs.length() == 0; + } } diff --git a/src/java.xml/share/legal/bcel.md b/src/java.xml/share/legal/bcel.md index 2c673d6b1af..b64fc3640d4 100644 --- a/src/java.xml/share/legal/bcel.md +++ b/src/java.xml/share/legal/bcel.md @@ -1,4 +1,4 @@ -## Apache Commons Byte Code Engineering Library (BCEL) Version 6.7.0 +## Apache Commons Byte Code Engineering Library (BCEL) Version 6.10.0 ### Apache Commons BCEL Notice

From ebb6fd7d7865fd20ff2f90b4ef72c5ef6a3e5dea Mon Sep 17 00:00:00 2001
From: Mikhail Yankelevich 
Date: Fri, 3 Oct 2025 07:37:17 +0000
Subject: [PATCH 008/160] 8360562: sun/security/tools/keytool/i18n.java add an
 ability to add comment for failures

Reviewed-by: rhalade
---
 test/jdk/sun/security/tools/keytool/i18n.java | 46 ++++++++++++++++++-
 1 file changed, 44 insertions(+), 2 deletions(-)

diff --git a/test/jdk/sun/security/tools/keytool/i18n.java b/test/jdk/sun/security/tools/keytool/i18n.java
index 6eac0239eee..ab9da8b1d3e 100644
--- a/test/jdk/sun/security/tools/keytool/i18n.java
+++ b/test/jdk/sun/security/tools/keytool/i18n.java
@@ -63,11 +63,21 @@
 
 import jdk.test.lib.UIBuilder;
 
-import javax.swing.*;
+import javax.swing.JDialog;
+import javax.swing.SwingUtilities;
+import javax.swing.JTextArea;
+import javax.swing.JButton;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JFrame;
+import java.awt.FlowLayout;
+import java.awt.BorderLayout;
 import java.io.ByteArrayOutputStream;
 import java.io.PrintStream;
 import java.util.Locale;
 
+import static javax.swing.BorderFactory.createEmptyBorder;
+
 public class i18n {
     private static final String[][] TABLE = new String[][]{
             {"-help", "All the output in this test should be in ${LANG}. "
@@ -234,11 +244,12 @@ public class i18n {
                     "Output in ${LANG}. Check keytool error: java.lang"
                             + ".IllegalArgumentException: if -protected is "
                             + "specified, then -storepass, -keypass, and -new "
-                            + "must not be specified."},
+                            + "must not be specified."}
     };
     private static String TEST_SRC = System.getProperty("test.src");
     private static int TIMEOUT_MS = 120000;
     private volatile boolean failed = false;
+    private volatile String failureReason = "";
     private volatile boolean aborted = false;
     private Thread currentThread = null;
 
@@ -330,6 +341,7 @@ public class i18n {
 
             if (failed) {
                 System.out.println(command + ": TEST FAILED");
+                System.out.println("REASON: " + failureReason);
                 System.out.println(message);
             } else {
                 System.out.println(command + ": TEST PASSED");
@@ -348,6 +360,7 @@ public class i18n {
 
     public void fail() {
         failed = true;
+        failureReason = requestFailDescription();
         currentThread.interrupt();
     }
 
@@ -355,4 +368,33 @@ public class i18n {
         aborted = true;
         currentThread.interrupt();
     }
+
+    /**
+     * Opens a prompt to enter a failure reason to be filled by the tester
+     */
+     public static String requestFailDescription() {
+
+        final JDialog dialogWindow = new JDialog(new JFrame(), "Failure Description", true);
+        final JTextArea reasonTextArea = new JTextArea(5, 20);
+
+        final JButton okButton = new JButton("OK");
+        okButton.addActionListener(_ -> dialogWindow.setVisible(false));
+
+        final JPanel okayBtnPanel = new JPanel(
+                new FlowLayout(FlowLayout.CENTER, 4, 0));
+        okayBtnPanel.setBorder(createEmptyBorder(4, 0, 0, 0));
+        okayBtnPanel.add(okButton);
+
+        final JPanel mainPanel = new JPanel(new BorderLayout());
+        mainPanel.add(new JScrollPane(reasonTextArea), BorderLayout.CENTER);
+        mainPanel.add(okayBtnPanel, BorderLayout.SOUTH);
+
+        dialogWindow.add(mainPanel);
+        dialogWindow.pack();
+        dialogWindow.setVisible(true);
+
+        dialogWindow.dispose();
+
+        return reasonTextArea.getText();
+    }
 }

From 2e783963d21c8edd88e79226ca473cfe0e41335b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mar=C3=ADa=20Arias=20de=20Reyna=20Dom=C3=ADnguez?=
 
Date: Fri, 3 Oct 2025 07:57:24 +0000
Subject: [PATCH 009/160] 8369037: Identify owning method for MethodData and
 MethodCounters in AOT map output

Reviewed-by: iklam, asmehra, adinn, macarte
---
 src/hotspot/share/cds/aotMapLogger.cpp | 20 ++++++++++++++++++++
 src/hotspot/share/cds/aotMapLogger.hpp |  4 ++++
 2 files changed, 24 insertions(+)

diff --git a/src/hotspot/share/cds/aotMapLogger.cpp b/src/hotspot/share/cds/aotMapLogger.cpp
index a15d7f670d4..ded3f05a9b8 100644
--- a/src/hotspot/share/cds/aotMapLogger.cpp
+++ b/src/hotspot/share/cds/aotMapLogger.cpp
@@ -33,6 +33,8 @@
 #include "memory/metaspaceClosure.hpp"
 #include "memory/resourceArea.hpp"
 #include "oops/method.hpp"
+#include "oops/methodCounters.hpp"
+#include "oops/methodData.hpp"
 #include "oops/oop.inline.hpp"
 #include "runtime/fieldDescriptor.inline.hpp"
 #include "runtime/globals_extension.hpp"
@@ -348,6 +350,12 @@ void AOTMapLogger::log_metaspace_objects_impl(address region_base, address regio
     case MetaspaceObj::MethodType:
       log_method((Method*)src, requested_addr, type_name, bytes, current);
       break;
+    case MetaspaceObj::MethodCountersType:
+      log_method_counters((MethodCounters*)src, requested_addr, type_name, bytes, current);
+      break;
+    case MetaspaceObj::MethodDataType:
+      log_method_data((MethodData*)src, requested_addr, type_name, bytes, current);
+      break;
     case MetaspaceObj::SymbolType:
       log_symbol((Symbol*)src, requested_addr, type_name, bytes, current);
       break;
@@ -389,6 +397,18 @@ void AOTMapLogger::log_const_method(ConstMethod* cm, address requested_addr, con
   log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes,  cm->method()->external_name());
 }
 
+void AOTMapLogger::log_method_counters(MethodCounters* mc, address requested_addr, const char* type_name,
+                                      int bytes, Thread* current) {
+  ResourceMark rm(current);
+  log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes,  mc->method()->external_name());
+}
+
+void AOTMapLogger::log_method_data(MethodData* md, address requested_addr, const char* type_name,
+                                   int bytes, Thread* current) {
+  ResourceMark rm(current);
+  log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes,  md->method()->external_name());
+}
+
 void AOTMapLogger::log_klass(Klass* k, address requested_addr, const char* type_name,
                              int bytes, Thread* current) {
   ResourceMark rm(current);
diff --git a/src/hotspot/share/cds/aotMapLogger.hpp b/src/hotspot/share/cds/aotMapLogger.hpp
index 9cd67fb7ff6..f2ca4c407e3 100644
--- a/src/hotspot/share/cds/aotMapLogger.hpp
+++ b/src/hotspot/share/cds/aotMapLogger.hpp
@@ -98,6 +98,10 @@ class AOTMapLogger : AllStatic {
   static void log_constant_pool_cache(ConstantPoolCache* cpc, address requested_addr,
                                       const char* type_name, int bytes, Thread* current);
   static void log_const_method(ConstMethod* cm, address requested_addr, const char* type_name, int bytes, Thread* current);
+  static void log_method_counters(MethodCounters* mc, address requested_addr, const char* type_name, int bytes,
+  Thread* current);
+  static void log_method_data(MethodData* md, address requested_addr, const char* type_name, int bytes,
+  Thread* current);
   static void log_klass(Klass* k, address requested_addr, const char* type_name, int bytes, Thread* current);
   static void log_method(Method* m, address requested_addr, const char* type_name, int bytes, Thread* current);
   static void log_symbol(Symbol* s, address requested_addr, const char* type_name, int bytes, Thread* current);

From 134b63f0e8c4093f7ad0a528d6996898ab881d5c Mon Sep 17 00:00:00 2001
From: Yuri Gaevsky 
Date: Fri, 3 Oct 2025 09:44:56 +0000
Subject: [PATCH 010/160] 8322174: RISC-V: C2 VectorizedHashCode RVV Version

Reviewed-by: fyang, rehn
---
 .../cpu/riscv/c2_MacroAssembler_riscv.cpp     | 147 ++++++++++++++++--
 .../cpu/riscv/c2_MacroAssembler_riscv.hpp     |   8 +-
 src/hotspot/cpu/riscv/riscv.ad                |   1 +
 src/hotspot/cpu/riscv/riscv_v.ad              |  22 +++
 .../cpu/riscv/stubDeclarations_riscv.hpp      |   3 +
 src/hotspot/cpu/riscv/stubGenerator_riscv.cpp |  22 +++
 6 files changed, 185 insertions(+), 18 deletions(-)

diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp
index 1bdb7bc2f7c..154b62db47f 100644
--- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp
+++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp
@@ -1687,6 +1687,7 @@ void C2_MacroAssembler::arrays_hashcode(Register ary, Register cnt, Register res
                                         Register tmp4, Register tmp5, Register tmp6,
                                         BasicType eltype)
 {
+  assert(!UseRVV, "sanity");
   assert_different_registers(ary, cnt, result, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, t0, t1);
 
   const int elsize = arrays_hashcode_elsize(eltype);
@@ -1759,29 +1760,143 @@ void C2_MacroAssembler::arrays_hashcode(Register ary, Register cnt, Register res
   BLOCK_COMMENT("} // arrays_hashcode");
 }
 
+void C2_MacroAssembler::arrays_hashcode_v(Register ary, Register cnt, Register result,
+                                          Register tmp1, Register tmp2, Register tmp3,
+                                          BasicType eltype)
+{
+  assert(UseRVV, "sanity");
+  assert(StubRoutines::riscv::arrays_hashcode_powers_of_31() != nullptr, "sanity");
+  assert_different_registers(ary, cnt, result, tmp1, tmp2, tmp3, t0, t1);
+
+  // The MaxVectorSize should have been set by detecting RVV max vector register
+  // size when check UseRVV (i.e. MaxVectorSize == VM_Version::_initial_vector_length).
+  // Let's use T_INT as all hashCode calculations eventually deal with ints.
+  const int lmul = 2;
+  const int stride = MaxVectorSize / sizeof(jint) * lmul;
+
+  const int elsize_bytes = arrays_hashcode_elsize(eltype);
+  const int elsize_shift = exact_log2(elsize_bytes);
+
+  switch (eltype) {
+    case T_BOOLEAN: BLOCK_COMMENT("arrays_hashcode_v(unsigned byte) {"); break;
+    case T_CHAR:    BLOCK_COMMENT("arrays_hashcode_v(char) {");          break;
+    case T_BYTE:    BLOCK_COMMENT("arrays_hashcode_v(byte) {");          break;
+    case T_SHORT:   BLOCK_COMMENT("arrays_hashcode_v(short) {");         break;
+    case T_INT:     BLOCK_COMMENT("arrays_hashcode_v(int) {");           break;
+    default:
+      ShouldNotReachHere();
+  }
+
+  const Register pow31_highest = tmp1;
+  const Register ary_end       = tmp2;
+  const Register consumed      = tmp3;
+
+  const VectorRegister v_sum    = v2;
+  const VectorRegister v_src    = v4;
+  const VectorRegister v_coeffs = v6;
+  const VectorRegister v_tmp    = v8;
+
+  const address adr_pows31 = StubRoutines::riscv::arrays_hashcode_powers_of_31()
+                           + sizeof(jint);
+  Label VEC_LOOP, DONE, SCALAR_TAIL, SCALAR_TAIL_LOOP;
+
+  // NB: at this point (a) 'result' already has some value,
+  // (b) 'cnt' is not 0 or 1, see java code for details.
+
+  andi(t0, cnt, ~(stride - 1));
+  beqz(t0, SCALAR_TAIL);
+
+  la(t1, ExternalAddress(adr_pows31));
+  lw(pow31_highest, Address(t1, -1 * sizeof(jint)));
+
+  vsetvli(consumed, cnt, Assembler::e32, Assembler::m2);
+  vle32_v(v_coeffs, t1); // 31^^(stride - 1) ... 31^^0
+  vmv_v_x(v_sum, x0);
+
+  bind(VEC_LOOP);
+  arrays_hashcode_elload_v(v_src, v_tmp, ary, eltype);
+  vmul_vv(v_src, v_src, v_coeffs);
+  vmadd_vx(v_sum, pow31_highest, v_src);
+  mulw(result, result, pow31_highest);
+  shadd(ary, consumed, ary, t0, elsize_shift);
+  subw(cnt, cnt, consumed);
+  andi(t1, cnt, ~(stride - 1));
+  bnez(t1, VEC_LOOP);
+
+  vmv_s_x(v_tmp, x0);
+  vredsum_vs(v_sum, v_sum, v_tmp);
+  vmv_x_s(t0, v_sum);
+  addw(result, result, t0);
+  beqz(cnt, DONE);
+
+  bind(SCALAR_TAIL);
+  shadd(ary_end, cnt, ary, t0, elsize_shift);
+
+  bind(SCALAR_TAIL_LOOP);
+  arrays_hashcode_elload(t0, Address(ary), eltype);
+  slli(t1, result, 5);      // optimize 31 * result
+  subw(result, t1, result); // with result<<5 - result
+  addw(result, result, t0);
+  addi(ary, ary, elsize_bytes);
+  bne(ary, ary_end, SCALAR_TAIL_LOOP);
+
+  bind(DONE);
+  BLOCK_COMMENT("} // arrays_hashcode_v");
+}
+
 int C2_MacroAssembler::arrays_hashcode_elsize(BasicType eltype) {
   switch (eltype) {
-  case T_BOOLEAN: return sizeof(jboolean);
-  case T_BYTE:    return sizeof(jbyte);
-  case T_SHORT:   return sizeof(jshort);
-  case T_CHAR:    return sizeof(jchar);
-  case T_INT:     return sizeof(jint);
-  default:
-    ShouldNotReachHere();
-    return -1;
+    case T_BOOLEAN: return sizeof(jboolean);
+    case T_BYTE:    return sizeof(jbyte);
+    case T_SHORT:   return sizeof(jshort);
+    case T_CHAR:    return sizeof(jchar);
+    case T_INT:     return sizeof(jint);
+    default:
+      ShouldNotReachHere();
+      return -1;
   }
 }
 
 void C2_MacroAssembler::arrays_hashcode_elload(Register dst, Address src, BasicType eltype) {
   switch (eltype) {
-  // T_BOOLEAN used as surrogate for unsigned byte
-  case T_BOOLEAN: lbu(dst, src);   break;
-  case T_BYTE:     lb(dst, src);   break;
-  case T_SHORT:    lh(dst, src);   break;
-  case T_CHAR:    lhu(dst, src);   break;
-  case T_INT:      lw(dst, src);   break;
-  default:
-    ShouldNotReachHere();
+    // T_BOOLEAN used as surrogate for unsigned byte
+    case T_BOOLEAN: lbu(dst, src);   break;
+    case T_BYTE:     lb(dst, src);   break;
+    case T_SHORT:    lh(dst, src);   break;
+    case T_CHAR:    lhu(dst, src);   break;
+    case T_INT:      lw(dst, src);   break;
+    default:
+      ShouldNotReachHere();
+  }
+}
+
+void C2_MacroAssembler::arrays_hashcode_elload_v(VectorRegister vdst,
+                                                 VectorRegister vtmp,
+                                                 Register src,
+                                                 BasicType eltype) {
+  assert_different_registers(vdst, vtmp);
+  switch (eltype) {
+    case T_BOOLEAN:
+      vle8_v(vtmp, src);
+      vzext_vf4(vdst, vtmp);
+      break;
+    case T_BYTE:
+      vle8_v(vtmp, src);
+      vsext_vf4(vdst, vtmp);
+      break;
+    case T_CHAR:
+      vle16_v(vtmp, src);
+      vzext_vf2(vdst, vtmp);
+      break;
+    case T_SHORT:
+      vle16_v(vtmp, src);
+      vsext_vf2(vdst, vtmp);
+      break;
+    case T_INT:
+      vle32_v(vdst, src);
+      break;
+    default:
+      ShouldNotReachHere();
   }
 }
 
diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp
index 309ef8d9d5e..2d5339dc153 100644
--- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp
+++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp
@@ -92,11 +92,15 @@
                        Register tmp3, Register tmp4,
                        Register tmp5, Register tmp6,
                        BasicType eltype);
-
-  // helper function for arrays_hashcode
   int arrays_hashcode_elsize(BasicType eltype);
   void arrays_hashcode_elload(Register dst, Address src, BasicType eltype);
 
+  void arrays_hashcode_v(Register ary, Register cnt, Register result,
+                         Register tmp1, Register tmp2, Register tmp3,
+                         BasicType eltype);
+  void arrays_hashcode_elload_v(VectorRegister vdst, VectorRegister vtmp,
+                                Register src, BasicType eltype);
+
   void string_equals(Register r1, Register r2,
                      Register result, Register cnt1);
 
diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad
index 1f14c499c34..009acd628a0 100644
--- a/src/hotspot/cpu/riscv/riscv.ad
+++ b/src/hotspot/cpu/riscv/riscv.ad
@@ -10991,6 +10991,7 @@ instruct arrays_hashcode(iRegP_R11 ary, iRegI_R12 cnt, iRegI_R10 result, immI ba
                          iRegLNoSp tmp3, iRegLNoSp tmp4,
                          iRegLNoSp tmp5, iRegLNoSp tmp6, rFlagsReg cr)
 %{
+  predicate(!UseRVV);
   match(Set result (VectorizedHashCode (Binary ary cnt) (Binary result basic_type)));
   effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, TEMP tmp6,
          USE_KILL ary, USE_KILL cnt, USE basic_type, KILL cr);
diff --git a/src/hotspot/cpu/riscv/riscv_v.ad b/src/hotspot/cpu/riscv/riscv_v.ad
index f2845ee2a6c..fe323474d60 100644
--- a/src/hotspot/cpu/riscv/riscv_v.ad
+++ b/src/hotspot/cpu/riscv/riscv_v.ad
@@ -4080,6 +4080,28 @@ instruct varray_equalsC(iRegP_R11 ary1, iRegP_R12 ary2, iRegI_R10 result,
   ins_pipe(pipe_class_memory);
 %}
 
+// fast ArraysSupport.vectorizedHashCode
+instruct varrays_hashcode(iRegP_R11 ary, iRegI_R12 cnt, iRegI_R10 result, immI basic_type,
+                          vReg_V2 v2, vReg_V3 v3, vReg_V4 v4, vReg_V5 v5,
+                          vReg_V6 v6, vReg_V7 v7, vReg_V8 v8, vReg_V9 v9,
+                          iRegLNoSp tmp1, iRegLNoSp tmp2, iRegLNoSp tmp3,
+                          rFlagsReg cr)
+%{
+  predicate(UseRVV);
+  match(Set result (VectorizedHashCode (Binary ary cnt) (Binary result basic_type)));
+  effect(USE_KILL ary, USE_KILL cnt, USE basic_type,
+         TEMP v2, TEMP v3, TEMP v4, TEMP v5, TEMP v6, TEMP v7, TEMP v8, TEMP v9,
+         TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+
+  format %{ "Array HashCode array[] $ary,$cnt,$result,$basic_type -> $result   // KILL all" %}
+  ins_encode %{
+    __ arrays_hashcode_v($ary$$Register, $cnt$$Register, $result$$Register,
+                         $tmp1$$Register, $tmp2$$Register, $tmp3$$Register,
+                         (BasicType)$basic_type$$constant);
+  %}
+  ins_pipe(pipe_class_memory);
+%}
+
 instruct vstring_compareU_128b(iRegP_R11 str1, iRegI_R12 cnt1, iRegP_R13 str2, iRegI_R14 cnt2,
                           iRegI_R10 result, vReg_V4 v4, vReg_V5 v5, vReg_V6 v6, vReg_V7 v7,
                           vReg_V8 v8, vReg_V9 v9, vReg_V10 v10, vReg_V11 v11,
diff --git a/src/hotspot/cpu/riscv/stubDeclarations_riscv.hpp b/src/hotspot/cpu/riscv/stubDeclarations_riscv.hpp
index fe7f52884fa..f977d759d20 100644
--- a/src/hotspot/cpu/riscv/stubDeclarations_riscv.hpp
+++ b/src/hotspot/cpu/riscv/stubDeclarations_riscv.hpp
@@ -73,6 +73,9 @@
   do_stub(compiler, string_indexof_linear_ul)                           \
   do_arch_entry(riscv, compiler, string_indexof_linear_ul,              \
                 string_indexof_linear_ul, string_indexof_linear_ul)     \
+  do_stub(compiler, arrays_hashcode_powers_of_31)                       \
+  do_arch_entry(riscv, compiler, arrays_hashcode_powers_of_31,          \
+            arrays_hashcode_powers_of_31, arrays_hashcode_powers_of_31) \
 
 
 #define STUBGEN_FINAL_BLOBS_ARCH_DO(do_stub,                            \
diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp
index 88961ccd5a4..ec268d9bb65 100644
--- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp
+++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp
@@ -6624,6 +6624,24 @@ static const int64_t right_3_bits = right_n_bits(3);
     return start;
   }
 
+  address generate_arrays_hashcode_powers_of_31() {
+    assert(UseRVV, "sanity");
+    const int lmul = 2;
+    const int stride = MaxVectorSize / sizeof(jint) * lmul;
+    __ align(CodeEntryAlignment);
+    StubCodeMark mark(this, "StubRoutines", "arrays_hashcode_powers_of_31");
+    address start = __ pc();
+    for (int i = stride; i >= 0; i--) {
+        jint power_of_31 = 1;
+        for (int j = i; j > 0; j--) {
+          power_of_31 = java_multiply(power_of_31, 31);
+        }
+        __ emit_int32(power_of_31);
+    }
+
+    return start;
+  }
+
 #endif // COMPILER2
 
   /**
@@ -6818,6 +6836,10 @@ static const int64_t right_3_bits = right_n_bits(3);
       StubRoutines::_bigIntegerRightShiftWorker = generate_bigIntegerRightShift();
     }
 
+    if (UseVectorizedHashCodeIntrinsic && UseRVV) {
+      StubRoutines::riscv::_arrays_hashcode_powers_of_31 = generate_arrays_hashcode_powers_of_31();
+    }
+
     if (UseSHA256Intrinsics) {
       Sha2Generator sha2(_masm, this);
       StubRoutines::_sha256_implCompress   = sha2.generate_sha256_implCompress(StubId::stubgen_sha256_implCompress_id);

From 72319167543a28295276f11178c17bef6680c32f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Beno=C3=AEt=20Maillard?= 
Date: Fri, 3 Oct 2025 10:40:50 +0000
Subject: [PATCH 011/160] 8364757: Missing Store nodes caused by bad wiring in
 PhaseIdealLoop::insert_post_loop

Reviewed-by: mhaessig, roland
---
 src/hotspot/share/opto/loopTransform.cpp      |  44 ++++++
 src/hotspot/share/opto/loopnode.hpp           |   3 +
 .../MissingStoreAfterOuterStripMinedLoop.java | 136 ++++++++++++++++++
 3 files changed, 183 insertions(+)
 create mode 100644 test/hotspot/jtreg/compiler/loopstripmining/MissingStoreAfterOuterStripMinedLoop.java

diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp
index 5f5e0520e7e..f92833e9e1c 100644
--- a/src/hotspot/share/opto/loopTransform.cpp
+++ b/src/hotspot/share/opto/loopTransform.cpp
@@ -1668,6 +1668,30 @@ void PhaseIdealLoop::insert_vector_post_loop(IdealLoopTree *loop, Node_List &old
   loop->record_for_igvn();
 }
 
+Node* PhaseIdealLoop::find_last_store_in_outer_loop(Node* store, const IdealLoopTree* outer_loop) {
+  assert(store != nullptr && store->is_Store(), "starting point should be a store node");
+  // Follow the memory uses until we get out of the loop.
+  // Store nodes in the outer loop body were moved by PhaseIdealLoop::try_move_store_after_loop.
+  // Because of the conditions in try_move_store_after_loop (no other usage in the loop body
+  // except for the phi node associated with the loop head), we have the guarantee of a
+  // linear memory subgraph within the outer loop body.
+  Node* last = store;
+  Node* unique_next = store;
+  do {
+    last = unique_next;
+    for (DUIterator_Fast imax, l = last->fast_outs(imax); l < imax; l++) {
+      Node* use = last->fast_out(l);
+      if (use->is_Store() && use->in(MemNode::Memory) == last) {
+        if (is_member(outer_loop, get_ctrl(use))) {
+          assert(unique_next == last, "memory node should only have one usage in the loop body");
+          unique_next = use;
+        }
+      }
+    }
+  } while (last != unique_next);
+  return last;
+}
+
 //------------------------------insert_post_loop-------------------------------
 // Insert post loops.  Add a post loop to the given loop passed.
 Node *PhaseIdealLoop::insert_post_loop(IdealLoopTree* loop, Node_List& old_new,
@@ -1758,6 +1782,26 @@ Node *PhaseIdealLoop::insert_post_loop(IdealLoopTree* loop, Node_List& old_new,
       cur_phi->set_req(LoopNode::EntryControl, fallnew);
     }
   }
+  // Store nodes that were moved to the outer loop by PhaseIdealLoop::try_move_store_after_loop
+  // do not have an associated Phi node. Such nodes are attached to the false projection of the CountedLoopEnd node,
+  // right after the execution of the inner CountedLoop.
+  // We have to make sure that such stores in the post loop have the right memory inputs from the main loop
+  // The moved store node is always attached right after the inner loop exit, and just before the safepoint
+  const Node* if_false = main_end->proj_out(false);
+  for (DUIterator j = if_false->outs(); if_false->has_out(j); j++) {
+    Node* store = if_false->out(j);
+    if (store->is_Store()) {
+      // We only make changes if the memory input of the store is outside the outer loop body,
+      // as this is when we would normally expect a Phi as input. If the memory input
+      // is in the loop body as well, then we can safely assume it is still correct as the entire
+      // body was cloned as a unit
+      if (!is_member(outer_loop, get_ctrl(store->in(MemNode::Memory)))) {
+        Node* mem_out = find_last_store_in_outer_loop(store, outer_loop);
+        Node* store_new = old_new[store->_idx];
+        store_new->set_req(MemNode::Memory, mem_out);
+      }
+    }
+  }
 
   DEBUG_ONLY(ensure_zero_trip_guard_proj(post_head->in(LoopNode::EntryControl), false);)
   initialize_assertion_predicates_for_post_loop(main_head, post_head, first_node_index_in_cloned_loop_body);
diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp
index bdccffa18b2..2645df86d96 100644
--- a/src/hotspot/share/opto/loopnode.hpp
+++ b/src/hotspot/share/opto/loopnode.hpp
@@ -1380,6 +1380,9 @@ public:
   // during RCE, unrolling and aligning loops.
   void insert_pre_post_loops( IdealLoopTree *loop, Node_List &old_new, bool peel_only );
 
+  // Find the last store in the body of an OuterStripMinedLoop when following memory uses
+  Node *find_last_store_in_outer_loop(Node* store, const IdealLoopTree* outer_loop);
+
   // Add post loop after the given loop.
   Node *insert_post_loop(IdealLoopTree* loop, Node_List& old_new,
                          CountedLoopNode* main_head, CountedLoopEndNode* main_end,
diff --git a/test/hotspot/jtreg/compiler/loopstripmining/MissingStoreAfterOuterStripMinedLoop.java b/test/hotspot/jtreg/compiler/loopstripmining/MissingStoreAfterOuterStripMinedLoop.java
new file mode 100644
index 00000000000..8fa6cae12e6
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/loopstripmining/MissingStoreAfterOuterStripMinedLoop.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8364757
+ * @summary Moving Store nodes from the main CountedLoop to the OuterStripMinedLoop causes
+ *          subsequent Store nodes to be eventually removed because of missing Phi nodes,
+ *          leading to wrong results.
+ *
+ * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation
+ *      -Xcomp -XX:-UseLoopPredicate -XX:-UseAutoVectorizationPredicate
+ *      -XX:CompileCommand=compileonly,compiler.loopstripmining.MissingStoreAfterOuterStripMinedLoop::test*
+ *      compiler.loopstripmining.MissingStoreAfterOuterStripMinedLoop
+ * @run main compiler.loopstripmining.MissingStoreAfterOuterStripMinedLoop
+ *
+ */
+
+package compiler.loopstripmining;
+
+public class MissingStoreAfterOuterStripMinedLoop {
+    public static int x = 0;
+    public static int y = 0;
+
+    static class A {
+        int field;
+    }
+
+    // The store node in the loop body is moved to the OuterStripLoop.
+    // When making the post loop the new store node
+    // should have the moved store node as memory input, and not the
+    // initial x = 0 store.
+    //
+    // store (x = 0)
+    //  |
+    // store (x += 1, exit of CountedLoop main)
+    //  | <-- additional rewiring due to absence of phi node
+    // store (x += 1, exit of CountedLoop post)
+    //  |
+    // store (x = 0)
+    static public void test1() {
+        x = 0;
+        for (int i = 0; i < 20000; i++) {
+            x += i;
+        }
+        x = 0;
+    }
+
+    // Two independent stores
+    // They should be wired independently in the post loop, no aliasing
+    static public void test2() {
+        x = 0;
+        y = 0;
+        for (int i = 0; i < 20000; i++) {
+            x += i;
+            y += i;
+        }
+        x = 0;
+        y = 0;
+    }
+
+    // Chain of stores with potential aliasing.
+    // The entire chain is moved to the OuterStripLoop, between the
+    // inner loop exit and the safepoint.
+    // The chain should be preserved when cloning the main loop body
+    // to create the post loop. Only the first store of the post loop
+    // should be rewired to have the last store of the main loop
+    // as memory input.
+    //
+    // ...
+    //  |
+    // store (a1.field = v, exit of CountedLoop main)
+    //  |
+    // store (a2.field = v, exit of CountedLoop main)
+    //  |
+    // store (a3.field = v, exit of CountedLoop main)
+    //  | <-- only additional rewiring needed
+    // store (a1.field = v, exit of CountedLoop post)
+    //  |
+    // store (a2.field = v, exit of CountedLoop post)
+    //  |
+    // store (a3.field = v, exit of CountedLoop post)
+    static public void test3(A a1, A a2, A a3) {
+        a1.field = 0;
+        a2.field = 0;
+        a3.field = 0;
+        int v = 0;
+        for (int i = 0; i < 20000; i++) {
+            v++;
+            a1.field = v;
+            a2.field = v;
+            a3.field = v;
+        }
+    }
+
+    public static void main(String[] strArr) {
+        A a1 = new A();
+        A a2 = new A();
+        A a3 = new A();
+
+        test1();
+        if (x != 0) {
+            throw new RuntimeException("unexpected value: " + x);
+        }
+
+        test2();
+        if (x != 0 || y != 0) {
+            throw new RuntimeException("unexpected value: " + x + " " + y);
+        }
+
+        test3(a1, a2, a3);
+        if (a1.field != 20000 || a2.field != 20000 || a3.field != 20000) {
+            throw new RuntimeException("unexpected value: " + a1.field + " " + a2.field + " " + a3.field);
+        }
+    }
+}
\ No newline at end of file

From f81c7c592bbc9f5575ed41e41d12f54cbfc5e4aa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= 
Date: Fri, 3 Oct 2025 15:53:37 +0000
Subject: [PATCH 012/160] 8276966: Improve diagnostic output for the
 mismatching parts of a hybrid snippet

Reviewed-by: prappo
---
 .../formats/html/taglets/SnippetTaglet.java    |  1 +
 .../doclet/testSnippetTag/TestSnippetTag.java  | 18 ++++++++++++++----
 2 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java
index 32bcab0eef5..d16c47dd59f 100644
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java
@@ -462,6 +462,7 @@ public class SnippetTaglet extends BaseTaglet {
                %s
                ----------------- external -----------------
                %s
+               --------------------------------------------
                """.formatted(inline, external);
     }
 
diff --git a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java
index 413de03d23b..26030629738 100644
--- a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java
+++ b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8266666 8275788 8276964 8299080
+ * @bug 8266666 8275788 8276964 8299080 8276966
  * @summary Implementation for snippets
  * @library /tools/lib ../../lib
  * @modules jdk.compiler/com.sun.tools.javac.api
@@ -2166,6 +2166,7 @@ public class TestSnippetTag extends SnippetTester {
                         Hello, Snippet!
                         ----------------- external -----------------
                         Hello, Snippet!...more
+                        --------------------------------------------
                         
"""); @@ -2207,8 +2208,16 @@ public class TestSnippetTag extends SnippetTester { "pkg"); checkExit(Exit.ERROR); checkOutput(Output.OUT, true, - """ - A.java:4: error: contents mismatch"""); + """ + A.java:4: error: contents mismatch""", + """ + ----------------- inline ------------------- + Hello, Snippet! ...more + \s\s + ----------------- external ----------------- + Hello, Snippet! + \s\s + --------------------------------------------"""); checkOutput("pkg/A.html", true, """
invalid @snippet @@ -2219,6 +2228,7 @@ public class TestSnippetTag extends SnippetTester { ----------------- external ----------------- Hello, Snippet! + --------------------------------------------
"""); From 23a65644ae63b271ca99c55a2a60a192c4e4dfb8 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Fri, 3 Oct 2025 16:25:55 +0000 Subject: [PATCH 013/160] 8368981: Case Fold Locale Legacy Tags On Demand Reviewed-by: rriggs, naoto --- .../classes/sun/util/locale/LanguageTag.java | 158 ++++++++---------- .../util/Locale/CaseFoldLanguageTagTest.java | 68 ++++++-- 2 files changed, 118 insertions(+), 108 deletions(-) diff --git a/src/java.base/share/classes/sun/util/locale/LanguageTag.java b/src/java.base/share/classes/sun/util/locale/LanguageTag.java index 6036c1dd04f..0b2fee7f2cd 100644 --- a/src/java.base/share/classes/sun/util/locale/LanguageTag.java +++ b/src/java.base/share/classes/sun/util/locale/LanguageTag.java @@ -34,17 +34,21 @@ package sun.util.locale; import java.text.ParsePosition; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.IllformedLocaleException; import java.util.List; import java.util.Locale; -import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.StringJoiner; // List fields are unmodifiable -public record LanguageTag(String language, String script, String region, String privateuse, - List extlangs, List variants, List extensions) { +public record LanguageTag(String language, + String script, + String region, + String privateuse, + List extlangs, + List variants, + List extensions) { public static final String SEP = "-"; public static final String PRIVATEUSE = "x"; @@ -53,78 +57,6 @@ public record LanguageTag(String language, String script, String region, String private static final String EMPTY_SUBTAG = ""; private static final List EMPTY_SUBTAGS = List.of(); - // Map contains legacy language tags and its preferred mappings from - // http://www.ietf.org/rfc/rfc5646.txt - // Keys are lower-case strings. - private static final Map LEGACY; - - static { - // grandfathered = irregular ; non-redundant tags registered - // / regular ; during the RFC 3066 era - // - // irregular = "en-GB-oed" ; irregular tags do not match - // / "i-ami" ; the 'langtag' production and - // / "i-bnn" ; would not otherwise be - // / "i-default" ; considered 'well-formed' - // / "i-enochian" ; These tags are all valid, - // / "i-hak" ; but most are deprecated - // / "i-klingon" ; in favor of more modern - // / "i-lux" ; subtags or subtag - // / "i-mingo" ; combination - // / "i-navajo" - // / "i-pwn" - // / "i-tao" - // / "i-tay" - // / "i-tsu" - // / "sgn-BE-FR" - // / "sgn-BE-NL" - // / "sgn-CH-DE" - // - // regular = "art-lojban" ; these tags match the 'langtag' - // / "cel-gaulish" ; production, but their subtags - // / "no-bok" ; are not extended language - // / "no-nyn" ; or variant subtags: their meaning - // / "zh-guoyu" ; is defined by their registration - // / "zh-hakka" ; and all of these are deprecated - // / "zh-min" ; in favor of a more modern - // / "zh-min-nan" ; subtag or sequence of subtags - // / "zh-xiang" - - final String[][] entries = { - //{"tag", "preferred"}, - {"art-lojban", "jbo"}, - {"cel-gaulish", "xtg-x-cel-gaulish"}, // fallback - {"en-GB-oed", "en-GB-x-oed"}, // fallback - {"i-ami", "ami"}, - {"i-bnn", "bnn"}, - {"i-default", "en-x-i-default"}, // fallback - {"i-enochian", "und-x-i-enochian"}, // fallback - {"i-hak", "hak"}, - {"i-klingon", "tlh"}, - {"i-lux", "lb"}, - {"i-mingo", "see-x-i-mingo"}, // fallback - {"i-navajo", "nv"}, - {"i-pwn", "pwn"}, - {"i-tao", "tao"}, - {"i-tay", "tay"}, - {"i-tsu", "tsu"}, - {"no-bok", "nb"}, - {"no-nyn", "nn"}, - {"sgn-BE-FR", "sfb"}, - {"sgn-BE-NL", "vgt"}, - {"sgn-CH-DE", "sgg"}, - {"zh-guoyu", "cmn"}, - {"zh-hakka", "hak"}, - {"zh-min", "nan-x-zh-min"}, // fallback - {"zh-min-nan", "nan"}, - {"zh-xiang", "hsn"}, - }; - LEGACY = HashMap.newHashMap(entries.length); - for (String[] e : entries) { - LEGACY.put(LocaleUtils.toLowerString(e[0]), e); - } - } - /* * BNF in RFC5646 * @@ -175,14 +107,10 @@ public record LanguageTag(String language, String script, String region, String StringTokenIterator itr; var errorMsg = new StringBuilder(); - // Check if the tag is a legacy language tag - String[] gfmap = LEGACY.get(LocaleUtils.toLowerString(languageTag)); - if (gfmap != null) { - // use preferred mapping - itr = new StringTokenIterator(gfmap[1], SEP); - } else { - itr = new StringTokenIterator(languageTag, SEP); - } + // Check if the tag is a legacy tag + var pref = legacyToPreferred(LocaleUtils.toLowerString(languageTag)); + // If legacy use preferred mapping, otherwise use the tag as is + itr = new StringTokenIterator(Objects.requireNonNullElse(pref, languageTag), SEP); String language = parseLanguage(itr, pp); List extlangs; @@ -400,15 +328,24 @@ public record LanguageTag(String language, String script, String region, String public static String caseFoldTag(String tag) { parse(tag, new ParsePosition(0), false); + StringBuilder bldr = new StringBuilder(tag.length()); + String[] subtags = tag.split(SEP); // Legacy tags - String potentialLegacy = tag.toLowerCase(Locale.ROOT); - if (LEGACY.containsKey(potentialLegacy)) { - return LEGACY.get(potentialLegacy)[0]; + if (legacyToPreferred(tag.toLowerCase(Locale.ROOT)) != null) { + // Fold the legacy tag + for (int i = 0; i < subtags.length ; i++) { + // 2 ALPHA Region subtag(s) are upper, all other subtags are lower + if (i > 0 && subtags[i].length() == 2) { + bldr.append(LocaleUtils.toUpperString(subtags[i])).append(SEP); + } else { + bldr.append(LocaleUtils.toLowerString(subtags[i])).append(SEP); + } + } + bldr.setLength(bldr.length() - 1); // Remove trailing '-' + return bldr.toString(); } // Non-legacy tags - StringBuilder bldr = new StringBuilder(tag.length()); - String[] subtags = tag.split("-"); boolean privateFound = false; boolean singletonFound = false; boolean privUseVarFound = false; @@ -435,7 +372,7 @@ public record LanguageTag(String language, String script, String region, String bldr.append(subtag.toLowerCase(Locale.ROOT)); } if (i != subtags.length-1) { - bldr.append("-"); + bldr.append(SEP); } } return bldr.substring(0); @@ -567,6 +504,47 @@ public record LanguageTag(String language, String script, String region, String return new LanguageTag(language, script, region, privateuse, EMPTY_SUBTAGS, variants, extensions); } + /* + * Converts a legacy tag to its preferred mapping if it exists, otherwise null. + * The keys are mapped and stored as lower case. (Folded on demand). + * See http://www.ietf.org/rfc/rfc5646.txt Section 2.1 and 2.2.8 for the + * full syntax and case accurate legacy tags. + */ + private static String legacyToPreferred(String tag) { + if (tag.length() < 5) { + return null; + } + return switch (tag) { + case "art-lojban" -> "jbo"; + case "cel-gaulish" -> "xtg-x-cel-gaulish"; // fallback + case "en-gb-oed" -> "en-GB-x-oed"; // fallback + case "i-ami" -> "ami"; + case "i-bnn" -> "bnn"; + case "i-default" -> "en-x-i-default"; // fallback + case "i-enochian" -> "und-x-i-enochian"; // fallback + case "i-hak", + "zh-hakka" -> "hak"; + case "i-klingon" -> "tlh"; + case "i-lux" -> "lb"; + case "i-mingo" -> "see-x-i-mingo"; // fallback + case "i-navajo" -> "nv"; + case "i-pwn" -> "pwn"; + case "i-tao" -> "tao"; + case "i-tay" -> "tay"; + case "i-tsu" -> "tsu"; + case "no-bok" -> "nb"; + case "no-nyn" -> "nn"; + case "sgn-be-fr" -> "sfb"; + case "sgn-be-nl" -> "vgt"; + case "sgn-ch-de" -> "sgg"; + case "zh-guoyu" -> "cmn"; + case "zh-min" -> "nan-x-zh-min"; // fallback + case "zh-min-nan" -> "nan"; + case "zh-xiang" -> "hsn"; + default -> null; + }; + } + // // Language subtag syntax checking methods // diff --git a/test/jdk/java/util/Locale/CaseFoldLanguageTagTest.java b/test/jdk/java/util/Locale/CaseFoldLanguageTagTest.java index fdee5075229..f3babb7e4c2 100644 --- a/test/jdk/java/util/Locale/CaseFoldLanguageTagTest.java +++ b/test/jdk/java/util/Locale/CaseFoldLanguageTagTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,12 +23,11 @@ /* * @test - * @bug 8159337 + * @bug 8159337 8368981 * @summary Test Locale.caseFoldLanguageTag(String languageTag) * @run junit CaseFoldLanguageTagTest */ -import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -54,24 +53,67 @@ public class CaseFoldLanguageTagTest { @ParameterizedTest @MethodSource("wellFormedTags") - public void wellFormedTags(String tag, String foldedTag) { + void wellFormedTagsTest(String tag, String foldedTag) { assertEquals(foldedTag, Locale.caseFoldLanguageTag(tag), String.format("Folded %s", tag)); } + @ParameterizedTest + @MethodSource("legacyTags") + void legacyTagsTest(String tag) { + var lowerTag = tag.toLowerCase(Locale.ROOT); + var upperTag = tag.toUpperCase(Locale.ROOT); + assertEquals(tag, Locale.caseFoldLanguageTag(lowerTag), + String.format("Folded %s", lowerTag)); + assertEquals(tag, Locale.caseFoldLanguageTag(upperTag), + String.format("Folded %s", upperTag)); + } + @ParameterizedTest @MethodSource("illFormedTags") - public void illFormedTags(String tag) { + void illFormedTagsTest(String tag) { assertThrows(IllformedLocaleException.class, () -> Locale.caseFoldLanguageTag(tag)); } @Test - public void throwNPE() { + void throwNPETest() { assertThrows(NullPointerException.class, () -> Locale.caseFoldLanguageTag(null)); } - private static Stream wellFormedTags() { + // Well-formed legacy tags in expected case + static Stream legacyTags() { + return Stream.of( + "art-lojban", + "cel-gaulish", + "en-GB-oed", + "i-ami", + "i-bnn", + "i-default", + "i-enochian", + "i-hak", + "i-klingon", + "i-lux", + "i-mingo", + "i-navajo", + "i-pwn", + "i-tao", + "i-tay", + "i-tsu", + "no-bok", + "no-nyn", + "sgn-BE-FR", + "sgn-BE-NL", + "sgn-CH-DE", + "zh-guoyu", + "zh-hakka", + "zh-min", + "zh-min-nan", + "zh-xiang" + ); + } + + static Stream wellFormedTags() { return Stream.of( // langtag tests // language @@ -124,16 +166,6 @@ public class CaseFoldLanguageTagTest { Arguments.of("X-A-ABC", "x-a-abc"), // private w/ extended (incl. 1) Arguments.of("X-A-AB-Abcd", "x-a-ab-abcd"), // private w/ extended (incl. 1, 2, 4) - // Legacy tests - // irregular - Arguments.of("I-AMI", "i-ami"), - Arguments.of("EN-gb-OED", "en-GB-oed"), - Arguments.of("SGN-be-fr", "sgn-BE-FR"), - // regular - Arguments.of("NO-BOK", "no-bok"), - Arguments.of("CEL-GAULISH", "cel-gaulish"), - Arguments.of("ZH-MIN-NAN", "zh-min-nan"), - // Special JDK Cases (Variant and x-lvariant) Arguments.of("de-POSIX-x-URP-lvariant-Abc-Def", "de-POSIX-x-urp-lvariant-Abc-Def"), Arguments.of("JA-JPAN-JP-U-CA-JAPANESE-x-RANDOM-lvariant-JP", @@ -150,7 +182,7 @@ public class CaseFoldLanguageTagTest { ); } - private static Stream illFormedTags() { + static Stream illFormedTags() { return Stream.of( // Starts with non-language Arguments.of("xabadadoo-me"), From aee73d3568fbcb2fe7293f92154e6677c080d20c Mon Sep 17 00:00:00 2001 From: Harshitha Onkar Date: Fri, 3 Oct 2025 17:32:51 +0000 Subject: [PATCH 014/160] 8365424: [macos26] java/awt/Frame/DisposeTest.java fails on macOS 26 Reviewed-by: serb, azvegint --- test/jdk/java/awt/Frame/DisposeTest.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/jdk/java/awt/Frame/DisposeTest.java b/test/jdk/java/awt/Frame/DisposeTest.java index 08c0def638e..ea1b2428f5c 100644 --- a/test/jdk/java/awt/Frame/DisposeTest.java +++ b/test/jdk/java/awt/Frame/DisposeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,6 +44,7 @@ import java.io.IOException; public class DisposeTest { private static Frame backgroundFrame; private static Frame testedFrame; + private static final int PIXEL_OFFSET = 4; private static final Rectangle backgroundFrameBounds = new Rectangle(100, 100, 200, 200); @@ -74,8 +75,8 @@ public class DisposeTest { BufferedImage bi = robot.createScreenCapture(backgroundFrameBounds); int redPix = Color.RED.getRGB(); - for (int x = 0; x < bi.getWidth(); x++) { - for (int y = 0; y < bi.getHeight(); y++) { + for (int x = PIXEL_OFFSET; x < bi.getWidth() - PIXEL_OFFSET; x++) { + for (int y = PIXEL_OFFSET; y < bi.getHeight() - PIXEL_OFFSET; y++) { if (bi.getRGB(x, y) != redPix) { try { ImageIO.write(bi, "png", From 0935b76c6bd1fbfa0a431eedb54c51f6fe4d194e Mon Sep 17 00:00:00 2001 From: Mikael Vidstedt Date: Fri, 3 Oct 2025 17:40:37 +0000 Subject: [PATCH 015/160] 8369080: Use uname -m for devkit cpu detection Reviewed-by: iris, erikj --- make/devkit/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/make/devkit/Makefile b/make/devkit/Makefile index d2167bf33fa..ffa23508a13 100644 --- a/make/devkit/Makefile +++ b/make/devkit/Makefile @@ -1,5 +1,5 @@ # -# Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -58,7 +58,7 @@ COMMA := , os := $(shell uname -o) -cpu := $(shell uname -p) +cpu := $(shell uname -m) # Figure out what platform this is building on. me := $(cpu)-$(if $(findstring Linux,$(os)),linux-gnu) From 0e98ec36623d5d83172209058574a97bab1d6038 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Fri, 3 Oct 2025 17:49:59 +0000 Subject: [PATCH 016/160] 8367384: The ICC_Profile class may throw exceptions during serialization Reviewed-by: honkar, prr --- .../classes/java/awt/color/ICC_Profile.java | 41 +++----- .../SerializationSpecTest.java | 99 ++++++++++++++++++ .../SerializationSpecTest/empty.ser | Bin 0 -> 130 bytes .../SerializationSpecTest/invalid.ser | Bin 0 -> 141 bytes .../SerializationSpecTest/invalid_invalid.ser | Bin 0 -> 142 bytes .../SerializationSpecTest/invalid_null.ser | Bin 0 -> 142 bytes .../SerializationSpecTest/invalid_valid.ser | Bin 0 -> 7040 bytes .../invalid_wrongType.ser | Bin 0 -> 218 bytes .../SerializationSpecTest/null.ser | Bin 0 -> 131 bytes .../SerializationSpecTest/null_invalid.ser | Bin 0 -> 7030 bytes .../SerializationSpecTest/null_null.ser | Bin 0 -> 132 bytes .../SerializationSpecTest/null_valid.ser | Bin 0 -> 7030 bytes .../SerializationSpecTest/null_wrongType.ser | Bin 0 -> 208 bytes .../SerializationSpecTest/valid.ser | Bin 0 -> 140 bytes .../SerializationSpecTest/valid_invalid.ser | Bin 0 -> 141 bytes .../SerializationSpecTest/valid_null.ser | Bin 0 -> 141 bytes .../SerializationSpecTest/valid_valid.ser | Bin 0 -> 7039 bytes .../SerializationSpecTest/valid_wrongType.ser | Bin 0 -> 217 bytes .../SerializationSpecTest/wrongType.ser | Bin 0 -> 207 bytes .../wrongType_invalid.ser | Bin 0 -> 7106 bytes .../SerializationSpecTest/wrongType_null.ser | Bin 0 -> 208 bytes .../SerializationSpecTest/wrongType_valid.ser | Bin 0 -> 208 bytes .../wrongType_wrongType.ser | Bin 0 -> 217 bytes .../StandardProfilesRoundTrip.java | 73 +++++++++++++ .../ValidateICCHeaderData.java | 10 +- 25 files changed, 191 insertions(+), 32 deletions(-) create mode 100644 test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/SerializationSpecTest.java create mode 100644 test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/empty.ser create mode 100644 test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/invalid.ser create mode 100644 test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/invalid_invalid.ser create mode 100644 test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/invalid_null.ser create mode 100644 test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/invalid_valid.ser create mode 100644 test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/invalid_wrongType.ser create mode 100644 test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/null.ser create mode 100644 test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/null_invalid.ser create mode 100644 test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/null_null.ser create mode 100644 test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/null_valid.ser create mode 100644 test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/null_wrongType.ser create mode 100644 test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/valid.ser create mode 100644 test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/valid_invalid.ser create mode 100644 test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/valid_null.ser create mode 100644 test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/valid_valid.ser create mode 100644 test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/valid_wrongType.ser create mode 100644 test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/wrongType.ser create mode 100644 test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/wrongType_invalid.ser create mode 100644 test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/wrongType_null.ser create mode 100644 test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/wrongType_valid.ser create mode 100644 test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/wrongType_wrongType.ser create mode 100644 test/jdk/java/awt/color/ICC_Profile/Serialization/StandardProfilesRoundTrip.java diff --git a/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java b/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java index 8bf09195627..0c2902ba74a 100644 --- a/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java +++ b/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java @@ -41,6 +41,7 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamException; @@ -1549,33 +1550,19 @@ public sealed class ICC_Profile implements Serializable private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); - - String csName = (String) s.readObject(); - byte[] data = (byte[]) s.readObject(); - - int cspace = 0; // ColorSpace.CS_* constant if known - boolean isKnownPredefinedCS = false; - if (csName != null) { - isKnownPredefinedCS = true; - if (csName.equals("CS_sRGB")) { - cspace = ColorSpace.CS_sRGB; - } else if (csName.equals("CS_CIEXYZ")) { - cspace = ColorSpace.CS_CIEXYZ; - } else if (csName.equals("CS_PYCC")) { - cspace = ColorSpace.CS_PYCC; - } else if (csName.equals("CS_GRAY")) { - cspace = ColorSpace.CS_GRAY; - } else if (csName.equals("CS_LINEAR_RGB")) { - cspace = ColorSpace.CS_LINEAR_RGB; - } else { - isKnownPredefinedCS = false; - } - } - - if (isKnownPredefinedCS) { - resolvedDeserializedProfile = getInstance(cspace); - } else { - resolvedDeserializedProfile = getInstance(data); + try { + String csName = (String) s.readObject(); + byte[] data = (byte[]) s.readObject(); + resolvedDeserializedProfile = switch (csName) { + case "CS_sRGB" -> getInstance(ColorSpace.CS_sRGB); + case "CS_CIEXYZ" -> getInstance(ColorSpace.CS_CIEXYZ); + case "CS_PYCC" -> getInstance(ColorSpace.CS_PYCC); + case "CS_GRAY" -> getInstance(ColorSpace.CS_GRAY); + case "CS_LINEAR_RGB" -> getInstance(ColorSpace.CS_LINEAR_RGB); + case null, default -> getInstance(data); + }; + } catch (ClassCastException | IllegalArgumentException e) { + throw new InvalidObjectException("Invalid ICC Profile Data", e); } } diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/SerializationSpecTest.java b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/SerializationSpecTest.java new file mode 100644 index 00000000000..aa50d814264 --- /dev/null +++ b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/SerializationSpecTest.java @@ -0,0 +1,99 @@ +/* + * 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. + */ + +import java.io.File; +import java.io.FileInputStream; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; +import java.io.OptionalDataException; + +/** + * @test + * @bug 8367384 + * @summary Verify ICC_Profile serialization per spec, all name/data cases + */ +public final class SerializationSpecTest { + + public static void main(String[] args) throws Exception { + // Serialization form for ICC_Profile includes version, profile name, + // and profile data. If the name is invalid or does not match a standard + // profile, the data is used. An exception is thrown only if both the + // name and the data are invalid, or if one of them is missing or is of + // the wrong type. + + // Naming conventions used in test file names: + // null : null reference + // valid : valid standard profile name or valid profile data (byte[]) + // invalid : unrecognized name or data with incorrect ICC header + // wrongType: incorrect type, e.g., int[] instead of String or byte[] + + // No name or data + test("empty", OptionalDataException.class); + + // Cases where only the profile name is present (no profile data) + test("null", OptionalDataException.class); + test("valid", OptionalDataException.class); + test("invalid", OptionalDataException.class); + test("wrongType", InvalidObjectException.class); + + // The test files are named as _.ser + test("null_null", InvalidObjectException.class); + test("null_valid", null); // valid data is enough if name is null + test("null_invalid", InvalidObjectException.class); + test("null_wrongType", InvalidObjectException.class); + + test("invalid_null", InvalidObjectException.class); + test("invalid_valid", null); // valid data is enough if name is invalid + test("invalid_invalid", InvalidObjectException.class); + test("invalid_wrongType", InvalidObjectException.class); + + test("wrongType_null", InvalidObjectException.class); + test("wrongType_valid", InvalidObjectException.class); + test("wrongType_invalid", InvalidObjectException.class); + test("wrongType_wrongType", InvalidObjectException.class); + + test("valid_null", null); // the valid name is enough + test("valid_valid", null); // the valid name is enough + test("valid_invalid", null); // the valid name is enough + test("valid_wrongType", InvalidObjectException.class); + } + + private static void test(String test, Class expected) { + String fileName = test + ".ser"; + File file = new File(System.getProperty("test.src", "."), fileName); + Class actual = null; + try (var fis = new FileInputStream(file); + var ois = new ObjectInputStream(fis)) + { + ois.readObject(); + } catch (Exception e) { + actual = e.getClass(); + } + if (actual != expected) { + System.err.println("Test: " + test); + System.err.println("Expected: " + expected); + System.err.println("Actual: " + actual); + throw new RuntimeException("Test failed"); + } + } +} diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/empty.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/empty.ser new file mode 100644 index 0000000000000000000000000000000000000000..3fd70024d656af1d2f6370bdc63c5c863c32c8e6 GIT binary patch literal 130 zcmZ4UmVvdnh(R_hu`E$9vAjetIX@@ANYB&RIX<8$KP@vSHOSqmj6-netmDhsm>3u; ziWsDDt34S$WyATC@12+#7(E%}Gn12{W(21eWhUliR;8x6B$gzGr4|)u=I2!uFfcGM GRsaCnJ}zni literal 0 HcmV?d00001 diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/invalid.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/invalid.ser new file mode 100644 index 0000000000000000000000000000000000000000..dfe071e69dc6bfc8f50eea4dc91759c21baf0133 GIT binary patch literal 141 zcmZ4UmVvdnh(R_hu`E$9vAjetIX@@ANYB&RIX<8$KP@vSHOSqmj6-netmDhsm>3u; ziWsDDt34S$WyATC@12+#7(E%}Gn12{W(21eWhUliR;8x6B$gzGr4|)u=I2!uFfcGM RmN0NQ2gip8`TMz7008G^F=zk) literal 0 HcmV?d00001 diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/invalid_invalid.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/invalid_invalid.ser new file mode 100644 index 0000000000000000000000000000000000000000..60fb02f77836caff458594904ffba51da4445be9 GIT binary patch literal 142 zcmZ4UmVvdnh(R_hu`E$9vAjetIX@@ANYB&RIX<8$KP@vSHOSqmj6-netmDhsm>3u; ziWsDDt34S$WyATC@12+#7(E%}Gn12{W(21eWhUliR;8x6B$gzGr4|)u=I2!uFfcGM SmN0NQ2gip8`TMySQ~&@OMKRa_ literal 0 HcmV?d00001 diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/invalid_null.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/invalid_null.ser new file mode 100644 index 0000000000000000000000000000000000000000..60fb02f77836caff458594904ffba51da4445be9 GIT binary patch literal 142 zcmZ4UmVvdnh(R_hu`E$9vAjetIX@@ANYB&RIX<8$KP@vSHOSqmj6-netmDhsm>3u; ziWsDDt34S$WyATC@12+#7(E%}Gn12{W(21eWhUliR;8x6B$gzGr4|)u=I2!uFfcGM SmN0NQ2gip8`TMySQ~&@OMKRa_ literal 0 HcmV?d00001 diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/invalid_valid.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/invalid_valid.ser new file mode 100644 index 0000000000000000000000000000000000000000..e01b5766f62f3b75de13f54d014c55168a7d2dd6 GIT binary patch literal 7040 zcmeHMXHXQ`8ok{;IS^)G$T@>V2?I#ZNpcj0VTLe-0fs1MWpM>p5D`g=AcBMiSC_bo ziYTIpf&vC~2U%3qRb0h{%A3JgwQpa&_iyX{dDB(h_w?znzVEx;x2jK_+x9y^XK;Z+ zA|sn&z{troV5TOgat%D3oTB`=sd4P&*Z?=jY@B#+)ld@#1|XLUWdD2YaA?`d8^f<0 z5de7rB{q}!&m4iVTs9+_ofpe;W@Iu#V!0XYR8DRh007DaIH$m<&;Z}HZdqIauXAjB zBlQ7;3*rfi@groX1!podB?C4BAcd335I-Xj z#0tj09`7arBw%jo|L5m_jsCYgA}fW%;x~)q^NFn34CYGX03@(dSOT8kBS^@}Ov?lS zcIIOVF26xO4in&*Z#Y?i20g2mmo{!6cN~oXl7*hmowaLjIkXf2k#sA$Z|2S?uIYeKzOsEW*$Azp5ixFW*{! zW3#djAX>$rTq^$?&|d<8l>Eu59|k~l7XV%Te{wO$0q8CPK>8swi<|u|A4)Kw0Re~t z2_OR$ff~>T`oIKO0Bc|mT!1I=1wkMjYyeD<08#)K|5FN6GTp({K01Ahq zp?HV`WkH*vT~HBJ3ROXMP&4!s)C*mJhM_U&E;IwpLw`V@U<4+?60icS2^+$6*a7x} zgW&aWJe&^a!TIn$xB{+++u$zv0(=dgfO+t9co6{z5uqU}h(1C`oDg3m0*OPo$X28f zDM#v&cBBs(LT({EK1ASwSfAH zCZpxidT1-O2RaNLkIq3Cpv%#X=uY${^aOei{SJe{&@fsU3yeD^9FvIIgxQNZjOoCf z$BbcSF^gC%RtBqwwZZyg8Q4s00k#s`hCPQJ$If9t;D|USoC(eq7lGs8cH+u$Ex3N% zIPM8<2``4%z+2&c@htpCd@;TO--o|}pTjQ^#0gpi8$u8vk+6eML1-sjB1{wB5Q#)p zq9xIv$R=(lRuE4TuMlU5A4wFFF3E`$Ny;MaBQ=rElkSqwuw}Wbcu|MycETYYKS_BZV=5AEf+m4dPDSu7+y?M%t?$PwpFZJ ztXFJGY*CylZY=IAo+7?iyhVIi{3!)X(WJOgSd@IqG0H{CEES=uQJttv>Mm*n^%8YX z0wbX%;USSIQ6%xB#HhrABt_CxGDI?0vRd-2B#(yBG-)2RWLh!p6m63BNlHP=K`K^i zk5s$VxYT=TIca<8Sm{FP4(SQ$Pcq6fE;30n`(?Ui9>}6(b!Gi!b7YUmUXpzwCn0Ao z$CN9SJ0*8d9+uaY50Kv^e@uQveo;YD!A&7ep;F6x;mvV(H6a)t7s@`8%Iin~gdN}bB6%95&bnxUGzHM=#RYDsH(Xys|OYE5gCwe7Uiwd=KS z>tJ-~I!QW*b#Cgyx@Niwy4AWj^k6-6J+|Iqy|Gp3RhFwbtLj%x>67#w^t1I_^=Axd z2Hplc4Z00p8mb#c816S5GW=>}W|VByV07P@V(e+W)40$04-;Jzrb)HQ?bYPfuB*4L z?pgiXRL?Zl^oZ#lGpd=7*>1A|voGcr=3Mi3^LYz(i)f1)iz&JU-H*PPe#H`P>1esl z@{Hw2D|4$%t5a65to5yvtXr&~uF+Z(yQX2ytc|J-!=}!LXRB-*ZF|&~XQyJvu&cLw zWUpq=vTwA1;-KS@=+Nfy($UC~>)7e|-pR^oi_>{$#M#Zc(0SB_;u7pq;pAYQg>2ttm zdacG<&f0EY;OpUg!1sZlmS4KxFa8*RKmTg~#{tFxn*)Xdsew^}ErIWX9D|C3?gwiJ zX9W+0h=xRlG>5zobq*~J<%JoBZ3(*;E*s7c?}@-hghVt(EUt4|cW~WYq*-J^C-f%WbG>Q>*IvO1v8r>58nc>T*XDr5e#MHzrFrAo(n9o`EtTNVotW9ib z?2|Z~xYD?%@iy@X;^!0W63P=^u$|ad?AM9ziM5IElYEn!l9rQ0lRHvyDbXpt9116i zGnlHFnwvV7rk7Tb#!I(KKbXG2_2M>WKpE>ZdNL*WKjx7v?X2&zX0mOwtFu4kgyfvg z70>15j%?K3xM$;&JlDMAn^2pWn+7(kY~HbXW{bm?x~1ZwE1f;ybD*nCxva44 z?ZK#n!{w&swTB3YvJUYoyeoPt)hkOXKUXDGO;kHpchtz&?5TNwn00vki2afFT7}x8 z+D}K>NAJ|R)pgZt)|Vf{9LqlTxFMur=s5j&bE9lyQR9~;P807$z=^?Ti{|DQ`Ih2V zxHYSFzAdut=8w)l_O$D_*LBc3icW%)Stp{{qf=;rl=_l)&=_73z}_jUea@JrJfl{3|6CC?W36Z-S}m(S&$TRfk3{>6p(3$p`J z1NSe6UA#T$KR9~H>(Z6Wu9q(kISiefr+9Z*cb?u&zWe%K_PwS1 z+o#dfg%89Yls}YzSpTceuN^#d-q{)FnUP02r{^qlF&*q+|JzsiJ@Vof$H7~Va{`|`R)yP8F!rW`_>*YW8zL9y;^w#w4z@p#c z!*?m~mfjbBkoj=pBmLvhr_fJNmU2F0KUaLw`O^2*>+AG#%JQ;M3kbD3u; ziWsDDt34S$WyATC@12+#7(E%}Gn12{W(21eWhUliR;8x6B$gzGr4|)u=I2!uFfcGM zmN0NQ2gip8`TMy8-604zJ0~$OUC%SGBsD#?Na)dmCEpv{Eto(?vX&+0l%@jRAb?Qk bSDKrYTGX~?sx0@E2i+hi7I;o$x>NxG?Kn+0 literal 0 HcmV?d00001 diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/null.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/null.ser new file mode 100644 index 0000000000000000000000000000000000000000..1fc2022f8683b572573642900988316676339a5c GIT binary patch literal 131 zcmZ4UmVvdnh(R_hu`E$9vAjetIX@@ANYB&RIX<8$KP@vSHOSqmj6-netmDhsm>3u; ziWsDDt34S$WyATC@12+#7(E%}Gn12{W(21eWhUliR;8x6B$gzGr4|)u=I2!uFfcGM H7E}NL2_G)n literal 0 HcmV?d00001 diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/null_invalid.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/null_invalid.ser new file mode 100644 index 0000000000000000000000000000000000000000..b2847de4f46feabb8c141b730916d33e04d3dac5 GIT binary patch literal 7030 zcmeHMXHXQ`8ok{;IS^)G$T@>V2?L1aEP`YZg<*y;gaL*qU_usGa1{{|0Yy+j!h)+y zTqB~0A_@u^&>dtEP*!mjQBim^`l@_YulC>8`}3x&y6>rTzxuxKcHgQ#b#C*Y0G-MO z3UQ1Kh5;ip&48Jdki<1`cXSN*;U-116QX=w9Wrp@T@`)x7#M&oE|C5E*#4l>Gk5x5 zJ0JjZ2TE)v^WQoAqPT2E0y{g3<-|y11V(XF*-4zNWB>q^oX!RCMu+CNQXeolf1aQO zpO+mM+zHIYRM-fBL{1u)--dEq z^6y*{{~OR>0e}>L=hTk^Ai4{H_KV-S$Ws7x6aygrl$p-W_?8bP7|?(KM1cg50g6Bk zXajv<0xWCWr-zfD1A~F4zeQKoKYghd>3W1}8xSXaQ$I2RIL| zfa~BExC=(WW55Gb;3b#`@4*rTL0E_kQ6U*f3DSV{AQOlVt%aPSb&xL<0!2VE5C=+! za-m&N5mW+IKs8VU^b6DlU4ihjH z0%ybd@IJU4u7#W7cK8Z>3m$=a@Jo0B0SFPHAu5PILPs1CZzL3nM!3i}q!1}XYLOPC z8|g#tAv|Ob`G~@xs3>KWKFS*9h6+G2Q7NcxsJ*BP)M->Zsuy(+HG!H(Eu+b3d9)td z3hj;#M#rEt(FN!-bRD`4eGNT=obO--6$dKZ)Kxwutc_tREo5V42!%H#fxf)+KX-$%@!>aJtulcbWRK}rYYtq#t_>kRw>pcHYT

(VCi1a5JWf^Cgc$ot-9Wqa3QL?(S8)P$OkI7z>os*N0vzBAZ70R8J zdn6Cb>&pAe=g6OsACO;AP*iYLNLDzaa8+SWk)~*;7^hgOcu{dyiK?_#iLF$sbV=!j zvZS)Ta)NTXaJv4B8eJ_~tyHZ?ZC+hT-Ag@J zy-EF%23~`%5vy@nqfcW|Q%f^QbGK%P=8TrKmb+HAR+HAaHd)(NJ4L%z`@RlFhprQ^ zb5!T9F05;&8>?HXdq)q}GuLD59n~9Jg-(EjMze#_>fM&4HAkUz~ z;FY1eVW{B&!#=}hBQv7}qmxFDjVZ<+#(Bow#($aUnlMc&P42HIuXb6zeRb#RH>P@~ zQKrXCADB_iyv%l+^_YDzw=n0Lx0ugbs9Qu>R9TGCCFnl%z4RNFXiEpn?Uv^)KU$ev zrCFV|dTp(59dF%eJ+nq@P1Kr`YbI?}Z5TE+HoUdUYa`YkU(2&qv1QoS+CH;Wvt!xS z*-hK)*vHv7+rM%!a^O0&IV?I_Ic{~l?1VVEIu$w%I#ZkjoGYB4x~RIuxHP%UyPCP? zxL$TcyLq}Da2s=1aA&$VxX*i7cx?6P^(1-vc~*EnTc^8@yRO>{_VVyL=rz7xV?Aem zhd1zc_de+T#7D~~#pkyTm<>J~DmOg$HTKQ*?enAhh5I%7z4v$U-|zo8Ksz8kpeIl? zFf6bka52a!s3eFNY#6*X_*RH)2s@-R6dM{CS{J&o(Rt&cjZcbuM)`&14phndrptCG7jcVesk)|ze5w#aQg+ts$`Z=c%Xy5sat!p``exATnh zO7hf~zXCHr1 z<66^Rt65ui0&^nc#PgGZC;Lv(Pc_uZ))m!#spr)5PWztjZLnx)Xq0c<-vl?MH_bMO zHQ)W&>F3TC{g#?mT5Hi6a3=lCi(evs89nQHw&xuET+6Q-zgD$T+X~yE_ATx69kCs} z&XCTbE|0FBZtL#0-wb}MKd*AW@`B`r{TB%r^DnMk%D%L4Ir;M3m6$7&J>fl%uLfVe z-@BoA@S5kf8`oW~U+uH+yL7|m#`%7${;r$!n;o~zZ?zAY4Yb`hyWKWuKG=T8;!fvX z%e&n}Ylbck+YVp3=XCG-efRsfM%IrEjRuT97z-QYJzzbUd6@9<&7+J*OOJPqqsI%M zh&?HLD*v?hcb(r`dFH$e6HXHY&-|V}o@7qG{3G>`&r|u&$3u; ziWsDDt34S$WyATC@12+#7(E%}Gn12{W(21eWhUliR;8x6B$gzGr4|)u=I2!uFfcGM I78Fzf061YUN&o-= literal 0 HcmV?d00001 diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/null_valid.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/null_valid.ser new file mode 100644 index 0000000000000000000000000000000000000000..b32c838c80ad94b311dcd5af73d74c1ad0ec9dd6 GIT binary patch literal 7030 zcmeHMXHXQ`8ok{;IS^)G2$FLU1SAX~IVZ_cRE8PC5C$BgU_=&IUxKzEQuMOnpFL`CJz=&RbduipE&_5Qr+s_uLG^jF{a-R@h}r_OEt9iUUV zKt7I<&d_IMr0O%15|X(3ZVnEceYi={?1U&k7yERacu(bEBL)T_lM7`3d+bnf>8YDT zuj~;3xdBBslljja{!v^uBY~Y2#d2h%GJ>MGDeNRpW-1Yfc!PcG8>#mgTmVl{ zg3rrN3C;v&VhU^kKq4oV%Wp#|Bs5G3I{`>Q4p0CV&=|~=WG{c`0Dc}Ih!u=~J>E?K zNWk3I`_Iq+8vSo~L{=h)#cvVE=i^vWDNH_2<>OdZB1^#Ydjzo=smXi}cI0CTF26xO z4iVtUZ#Y4KW4_^CUtM*xUv z2_~V$=A=e(IgAADujJo(`IlNEDS{UsnZ`~?)njx1&LaF=|EoHJ_42LtH&$QQ0YoeR zlS|@%1Nut;`$D02G5mpc2%8de8*gz-iD0&Vq~J z3b+n#fpPEv@W3p10T#eJuna*E79vAbNCr}b)FEBS2%9P$DlLNdFV291G)o!89k1kMZd#fFf@!N#th?%3B|-=vN462Bbau~1SgMz1V%zr!c8Jh zqCnzDi4lnfNs6SgWRPU0WR>JONgfTMY0%tg3A7^GY1#zsqm;aqom7<6KB+dTF{vf# zRnoT7QPTO+?b74YA7zweoMhr<4#;%LJd{Pr>d5-aX2>3uy(~MwN@A7eD(0&ERi{_o zmxJYWlAl+gDcCB+DU>SoDaC@m<aul@=#H*NuQp%JSzWh!Qjer(ryfl^BqT=C{BS+l}?YGRh(m-TbvhMOkA>E zF1VsyJzNjCPP)mvG2NQn7TnF;x4RE`kUac7Dm@;1>UeTJd%a*Ucdvt9Q|r~&bJllx z18+C)gWeB)G<~-C{Nju8_3^Fped1^6x6N@9ZDPw}=h+VIO7`nG*SMOvrFif7#`u+l;Dq)>Tw+9G4~N2u=L{q%BxNRz zChI2WCG)meY&o=Lf$PC-NP$u|rgW!D@PEw1Xr&p!F&j`vmlPR9b$sFFQ zvvuFrr&-QfC$dr5%y>^ixduseSDjU0oV zlAO1Dg7@_1%IEINo%zn?yOunWJZ|3PUdz2T-=n@~e?PKs?Y@eAU-DV`*9r^@$_hRe zG7GQ$VE9A%4=ekl_m32r79B0d6myCv4%i$xSt4GNRWftX>tJW8QfYqa+e4cV4V4*} z)f^@qPCLvi_bl(OP^&1e_*5BNIbLO7)m|-Ey{~%d2~7O*t8J&X7n}m8(oQ}9DdMMz(;lb$&(P1b{jC0TbqBR0zZ2@*+PTmb+r{e+ z?H=uM@9FQg?CtnP|Ch$I%4e(2NuDd}BlP9=t(?y~zjz_}!u-XUi!=S3`yX5ixpZg1 zcVOhQ$K|V6oUdFOv>QBs)#~cmA&a4&YxHYf*G;c?4x0>j+%UP(F=9H>dDHA>_bu~V zy`$?!`^Id>F5Y&$edUhZo$KT4$44guC+<#$Px9`v?moMhaPRf~^!v*Xc1@wD@*j#l zEPEvPsP0$oU)y=6ymQlz)5DMbA3vC3&b;_7<+o3>xlhPX%AP7dZF*+(?ChNL+^y#u zp3lBWez82C_q+J-)i1SP{`|`J)$l^d!t87A>yslKG5F)t<&00*PvxJrKlgs|_%gMUxUwSD0zxey)B-{+Ak+dvEg;kaLM3u; ziWsDDt34S$WyATC@12+#7(E%}Gn12{W(21eWhUliR;8x6B$gzGr4|)u=I2!uFfcGM z765G*1e=(Xn3t~SnOBmUo?0aIXu*>2jqMgpAcI)T5_3vZfi?>u)cKX>CZ!g&t(hvz RJ>@|+$YBMZ)0i$*002rXN~r(< literal 0 HcmV?d00001 diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/valid.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/valid.ser new file mode 100644 index 0000000000000000000000000000000000000000..a6512d244cf246a938ee37fe376ee7c92bd57160 GIT binary patch literal 140 zcmZ4UmVvdnh(R_hu`E$9vAjetIX@@ANYB&RIX<8$KP@vSHOSqmj6-netmDhsm>3u; ziWsDDt34S$WyATC@12+#7(E%}Gn12{W(21eWhUliR;8x6B$gzGr4|)u=I2!uFfcGM PmN2k82ger!ZK(hNwt_Jz literal 0 HcmV?d00001 diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/valid_invalid.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/valid_invalid.ser new file mode 100644 index 0000000000000000000000000000000000000000..dbe11f2c6d651974009b5c4d96db2f45923a47dc GIT binary patch literal 141 zcmZ4UmVvdnh(R_hu`E$9vAjetIX@@ANYB&RIX<8$KP@vSHOSqmj6-netmDhsm>3u; ziWsDDt34S$WyATC@12+#7(E%}Gn12{W(21eWhUliR;8x6B$gzGr4|)u=I2!uFfcGM QmN2k82ger!Z7HY#0O%4im;e9( literal 0 HcmV?d00001 diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/valid_null.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/valid_null.ser new file mode 100644 index 0000000000000000000000000000000000000000..dbe11f2c6d651974009b5c4d96db2f45923a47dc GIT binary patch literal 141 zcmZ4UmVvdnh(R_hu`E$9vAjetIX@@ANYB&RIX<8$KP@vSHOSqmj6-netmDhsm>3u; ziWsDDt34S$WyATC@12+#7(E%}Gn12{W(21eWhUliR;8x6B$gzGr4|)u=I2!uFfcGM QmN2k82ger!Z7HY#0O%4im;e9( literal 0 HcmV?d00001 diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/valid_valid.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/valid_valid.ser new file mode 100644 index 0000000000000000000000000000000000000000..fbe90d0eb6ea8059d4cde7ff1b8e31d7531919b7 GIT binary patch literal 7039 zcmeHMXHXQ`8ok{;IS^)G$T@>V2?I#ZNpcj0VTLe-0fs1;WpM>p5D`g=AcBMiSC_bo ziUBd8pnw70K^75p6<0B#@@DW=?b}!H{o8tf-gH&>J^l5m@B41uTh*t|ZT}shGq^w@ zk&(?XVB};PFjJFLxdt9iPEmf`)Hrr>Y=E0%Hcq^+dZ-x#1CYxFvj3es99n+j=I|>= z1VA1@iOppGGe=-7m(56K=f$#|8JUcbSZ)S8m6MwW0Dv+9)+sP5gI^_!3*dE*?Qf($ zU~oY^K`lN(c1mz3GgC5PBLGr3nOr_oIV?Ov89M<;Kps#47SI^Xj5MD>*C2jEAm9qd zzh3Vq03?Xq*8k7n|H}TiHzF&A!{YafY*0sC#VlP4-G@3&^>4xnuq>?KEVh~f+b)DSQ9pc>97Or1qZ?F z;dnS5&Vvi!y>KPm0Jp>4@Ok(eJPz~V=kOu|5F$cDR1kfHjyNH{NCXmxaFH!Y5mJFP zARS0QGKAblc*qOnBMO6}qLfkkC~K5EDj3B?rK7f>_Moa!$5Gv=i>TYEY19JhE1Ha! zN9&=j&>rY8bUZo-U5KtgH=(=Gm(b(rS@b&$21CPWVJtB2m~c!YCLgm0a|qLkIfog= z%wQI=SgZ_I4{L+<#WJv&*g|X-wjFyGJBFRbe!vlNN;ngoD=q@Z!R^3R;97A5xG~%u zZV4}j*T7rheeo>(Mtljr5#Nu$iJ!$U5yS~v1RFvSA(611P)X<@Tp~;n-VljIRiY)) zpU5U|BUTbm5U&uYi62Q6k}k=K6iLb=?Iksn&XMks-jK;;O|m^Xf}Ba-OKu@wAU`61 z5TS|~hA+|-VMyyY4 zQfyJ2DsC+9E1n|0N4!;hSo|pkOVOmbP*{`#%2CP%$_y2us!^S&OzKW*BlQw>RstiT zCE+2FC{Zl&qr`~Bf+R)KR5C;|SF%R(j3keS&@^ctv}9Td?Idl2_DM=X%0VhtYPVE} z)R@$JX*p?o=~(F^=}zf!=}$7sGA=SnGW%qDWFE?*WOZfzWpiW?%U+UwAtxbcEyt8A zk~=APUmlj%l@E~5mp>|hU4BtPQNc|iO`%HRg2D?$nxeg8qGGw?fa1IoRmoO~tyHdb zR_U3tq_Tr@vT~*JMdbw*c@=k+ER}kd5tSuXE!AMv9jcwG57h{2bhS9Oa}tz6Lf2IZ|cE%=6Y{E>K4%!wHA|f3A!JB5B-WI+S1W-tL16S zk5=YZnN}yQURmo~Ct0^zKV74>CU#BZni(5a8-`824bN8DHrn=xEzeHHj$zke_t;*| zo@L);Kj)z1km%6v@Y2!9k?Yvy_}-OGKS`=p102h*d)W5LtHbF=3~FOpZFSGCt;Z(VP$cfSwpf*gZNf*u5G2WJHj zhKPnlhO~sd4|NVL3+06whHVbJ7A_mk4)2Y?MubE(MJ%p!S$AOFY@}IaVdTVmt@XL< zhd0P>NZxQJN;HZQbt)Pi9U9#l{h8s*XkaYHc*NAkEHIsz2bs@V_N;Q&e5_4uS?pY# zO;FW64(YWC|y_r$uy_es7<%}LA2p~;;oxRmIWJ`RPG#JQNN zn3|h9nx>aln8r)DNX4hnY$O*|gl`Edh z$-TZ&cjNAjb9t_L$MRA6%>2PkDx0=%n%?ZNxqb_@C1%UuR<*4KTW7bqZ9Bf5usvz} zjU7fi%67cn8M?E-K%rn;!OVAV-?bHr6mknEcUkYM`yTZ@`}>jIt9MuJ{#wK;x>{^h zTv7aa4|C7eAB=yf{9$=-+}@EA^OD1*m{LyZ#6G)y$IHaa^2%oR`|R&7S1vCqe|sS6 zz;K0WMcqNd!K{P4O7F_vD)p+;s?XI4)#EjeHJ!EcwYzKIA7ULEJ8XZrqfVi&xbD*t z_K~~wZuQ*_nhh04F-NnHK4}bT96Cln*3u-~RNVBXnbXWW9&r3(i$zOIt9)xo8{C%F zHs2oEe(Oi)AA39WJL)@Woy8}>iL4XPev1BS;-uHf!Bg~89Y1UQT-!zMD(Z&1H+C=d zB=qol!+S^jJo^Uwt^2!vG5DqVw94t4Gm>XY1_%QM1IuUg&MuxyJNM#z{P~%|sKEyp z!Y0ztkzN_@BJ=e^ybze8T-gU$5M%Re>NcT;P zo4vOzZ}pF^866n28#{m7`S#^I9(S&duN@zq2%fk*89B+j%ewpYUh=)y_p|RWJ=ivd zo+^4M_ORlS{G*0nb$;#Sne)y}J5OJK9QgRb40GoBZyCRRo-KGneo`@~G}rRfeW_61hXZun{d5h#MAlK=$e1K@oFfU0T$G~@W^ I3z51108jusz5oCK literal 0 HcmV?d00001 diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/valid_wrongType.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/valid_wrongType.ser new file mode 100644 index 0000000000000000000000000000000000000000..3538676276fd1b9cb42cfdd37378f05967885d59 GIT binary patch literal 217 zcmZ4UmVvdnh(R_hu`E$9vAjetIX@@ANYB&RIX<8$KP@vSHOSqmj6-netmDhsm>3u; ziWsDDt34S$WyATC@12+#7(E%}Gn12{W(21eWhUliR;8x6B$gzGr4|)u=I2!uFfcGM zmN2k82ger!Z2>w%5Nvc#VqUtQXI@EadTNo-qXkR8H?~_aflOpAOUx-v1v)_hq0X-~ ZHz~EKZOv3!?kNwtK`t!toW^vi0syHLO!oi) literal 0 HcmV?d00001 diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/wrongType.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/wrongType.ser new file mode 100644 index 0000000000000000000000000000000000000000..3469f871ef6042f9d8d244c3ec9388cc3063423a GIT binary patch literal 207 zcmZ4UmVvdnh(R_hu`E$9vAjetIX@@ANYB&RIX<8$KP@vSHOSqmj6-netmDhsm>3u; ziWsDDt34S$WyATC@12+#7(E%}Gn12{W(21eWhUliR;8x6B$gzGr4|)u=I2!uFfcGM z0xcH=8<>-rm#*iTSCX2ZS|s#n!IJNd?G{WRb6Cp~b4pWz77HNM`IY7-r53fVnJUXY QM2_;L?iH?cY!43iv&;V3`1#}iWGb1S6H$u`Akj6^K z@7I?v0K6Lnkd(P=@!#{`BmV{wIcWlpWVtxWd>3w@0`J20OU6T(0cwmmv9(>w(S6@JYkE3+28V^qyridfILtH zsz3|q0~25YY=I+i0q(#D1b|==0b;;Pzy`@64G2LF$Oi?W7?gtTU>B$X`$0Wu0L|be zXai@#C2$qo0C&Iucm%{?47>o-;2oHQAP5VQAsVC#X+wsPIb;hlpv906v;+!+VxV{^ z2@*geC?DDcl|toE4RjD{fPR6_K$oB%s1JGojX;yoU(iPwfl06;tO*;zRxkthfCJ$O zcmH zB6UbJ(t&g%cM&l%g?vC^P&AYd$^zwr@<%O0u~Dm0>rrK>8q_gVE2;~17d3*KMtwn( z(HdxTv@@ECjz%Y;bI`@;O7s!*Y4jEJ0D27l4uiqaF~%52j6Ws@lY&``DZ}i=v|uh` z`Y@xI87vm7iZ#c&VuP_PY!5NM5L{xqoj+Z2c$P-GTDgiPL3sKk++f?$d}1a z$nWK7a+Y#TIgZ>0xmvkaxqi8q@_2bec@O!O@_F)=@~7l)%TFob6^s1gE zC=4mgP-qkzN-!mjQbsvW>7h(eu~Z|f50yhLq8_4NrjF7Onm)~o#-?qe)zhxf#uPD% z#)?eE6va}-pA~x*r-xk|N4=aj^BglTw#(RkQ|Y~p6J+N93po+-wZ zVVY{X*Yu7VY-VqkY*uS_+Z;A`Fz1=?HSb%1Uf{Gqu%K?ikOj%Y!y?sLYoeoziiEH*|xQ|_ZE^D`YznCuzlfc zJ99g(-9Eef_B8t-`_1;9_MaUb9fS_e4wH@sj`5Cr9ETW+j1Wc{hU%k`kEc(Kmn_{9eni`{hHSZ;N0Pu=z1 zIqpZ?$309vQaqYGUV2)43O!GI&U!g}t@FC*jd=Tcmw5O3P<@v9)c8E{)$>jAZS(*ceF>jJt0NrB;kHGxl;m@N@5=?H>@0)lo14KFoZ zDp=YU41$@#JA)sG7>BG5`7IO^8WLI?`Yg;QEI+I}oEE++{CN1g2+xRZ5s#LcEE6s3 zjFgXzi)@ITjq;8vj}k{)MX!s#5u+Bvi)oL=#zw{-iJe*QvwYX`u{is<;<&*T#w&7H z^sH1{$zOSHmHaB!s#Edk_^9~f@t;`1tUA_A0yAMx!Zh29y_@}lzT4exb|f6D%p+0@|Fqp4r{QT&!PTv~kE839$0D(Fhr zO3zL2%P`L<&JeG5UcGDev@lS3BooS9k=dT5DETqp6q$&A5RGIn&aTaVpA(sLDwmQg z$i2D7Y|WN6<9WV$hu5Okve$Oz>*g2akF4`pcW^zlK4E?52K^018^$*JZ9G;$C`c{1 zRcKvUUifxX)TWLi&7zG(qd)ll&{!;2EG!<{?6P_PkEkDcKlW}}xTSi_ml96N^-}B7 z%F<6|?6T`W+5A-X)7PzuTYI-TY}>aTvt6)#aEIHDW95|cyz~ zfOp{jLBE5obw+iShcJh-4?U}otnWU|INWeV?MUg7&qoDE#mB;qbu~CPG#uABzO4~% z6g5sZ#Wmge+56}AW{c*7E%cVs6X1mC#PeU`e;GU(c(U^p<5csnhQIDPO*>uE3bn3j zoo-8R6Sv2-_niqi)7jzDar!sQ-;SQuJzIND>D;#Sg!4t`zh20@Fmo~E;?$+2OQW5u zIv-t*zI?AMw5#_@;FW7veXm~b_UOKF&Gp*Z9_OAj*BRH_ZaCa%y=i~*^ey{ar+XcG zTW>qwZolJnr=xFC-}!#G{!4eg?_Ryfymw<@=|JD$vcda9aYN$!ocj|G_zzw`%zilc zXyY(?xa6_I?F)c*BJ4 z#Mw#T$ve-NKOcLM@nUYO_)p58dtREn{PmUltDDo&(_^oNufP6P_D1#1(YJPQJ7+>> zp1ezYH#b}IUiJO44~!4pAEQ2w&*gl=eyaLx`nlsv;FsaAXd;ys+AoB%ezJSaZkof{KU*P}P7nnc0k*EPgst67Z0T8hkfF-v8sICFP LC{c305SRNe4T)CE literal 0 HcmV?d00001 diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/wrongType_null.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/wrongType_null.ser new file mode 100644 index 0000000000000000000000000000000000000000..2c1536cc09423dfa9117647e3d5206ba5763c15b GIT binary patch literal 208 zcmZ4UmVvdnh(R_hu`E$9vAjetIX@@ANYB&RIX<8$KP@vSHOSqmj6-netmDhsm>3u; ziWsDDt34S$WyATC@12+#7(E%}Gn12{W(21eWhUliR;8x6B$gzGr4|)u=I2!uFfcGM z0xcH=8<>-rm#*iTSCX2ZS|s#n!IJNd?G{WRb6Cp~b4pWz77HNM`IY7-r53fVnJUXY R3u; ziWsDDt34S$WyATC@12+#7(E%}Gn12{W(21eWhUliR;8x6B$gzGr4|)u=I2!uFfcGM z0xcH=8<>-rm#*iTSCX2ZS|s#n!IJNd?G{WRb6Cp~b4pWz77HNM`IY7-r53fVnJUXY R3u; ziWsDDt34S$WyATC@12+#7(E%}Gn12{W(21eWhUliR;8x6B$gzGr4|)u=I2!uFfcGM z0xcH=8<>-rm#*iTSCX2ZS|s#n!IJNd?G{WRb6Cp~b4pWz77HNM`IY7-r53fVnJUXY X Date: Fri, 3 Oct 2025 18:45:34 +0000 Subject: [PATCH 017/160] 8356202: Cleanup Source code in String Implementation Classes Reviewed-by: jpai, rgiulietti, liach --- .../share/classes/java/lang/StringLatin1.java | 124 +++++--------- .../share/classes/java/lang/StringUTF16.java | 161 +++++++++--------- 2 files changed, 127 insertions(+), 158 deletions(-) diff --git a/src/java.base/share/classes/java/lang/StringLatin1.java b/src/java.base/share/classes/java/lang/StringLatin1.java index da3acbe5f0a..61c62d049bc 100644 --- a/src/java.base/share/classes/java/lang/StringLatin1.java +++ b/src/java.base/share/classes/java/lang/StringLatin1.java @@ -41,61 +41,49 @@ import static java.lang.String.checkIndex; import static java.lang.String.checkOffset; final class StringLatin1 { - public static char charAt(byte[] value, int index) { + static char charAt(byte[] value, int index) { checkIndex(index, value.length); return (char)(value[index] & 0xff); } - public static boolean canEncode(char cp) { + static boolean canEncode(char cp) { return cp <= 0xff; } - public static boolean canEncode(int cp) { + static boolean canEncode(int cp) { return cp >=0 && cp <= 0xff; } - public static byte coderFromChar(char cp) { + static byte coderFromChar(char cp) { return (byte)((0xff - cp) >>> (Integer.SIZE - 1)); } - public static int length(byte[] value) { + static int length(byte[] value) { return value.length; } - public static int codePointAt(byte[] value, int index, int end) { - return value[index] & 0xff; - } - - public static int codePointBefore(byte[] value, int index) { - return value[index - 1] & 0xff; - } - - public static int codePointCount(byte[] value, int beginIndex, int endIndex) { - return endIndex - beginIndex; - } - - public static char[] toChars(byte[] value) { + static char[] toChars(byte[] value) { char[] dst = new char[value.length]; inflate(value, 0, dst, 0, value.length); return dst; } - public static byte[] inflate(byte[] value, int off, int len) { + static byte[] inflate(byte[] value, int off, int len) { byte[] ret = StringUTF16.newBytesFor(len); inflate(value, off, ret, 0, len); return ret; } - public static void getChars(byte[] value, int srcBegin, int srcEnd, char[] dst, int dstBegin) { + static void getChars(byte[] value, int srcBegin, int srcEnd, char[] dst, int dstBegin) { inflate(value, srcBegin, dst, dstBegin, srcEnd - srcBegin); } - public static void getBytes(byte[] value, int srcBegin, int srcEnd, byte[] dst, int dstBegin) { + static void getBytes(byte[] value, int srcBegin, int srcEnd, byte[] dst, int dstBegin) { System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin); } @IntrinsicCandidate - public static boolean equals(byte[] value, byte[] other) { + static boolean equals(byte[] value, byte[] other) { if (value.length == other.length) { for (int i = 0; i < value.length; i++) { if (value[i] != other[i]) { @@ -108,20 +96,20 @@ final class StringLatin1 { } @IntrinsicCandidate - public static int compareTo(byte[] value, byte[] other) { + static int compareTo(byte[] value, byte[] other) { int len1 = value.length; int len2 = other.length; return compareTo(value, other, len1, len2); } - public static int compareTo(byte[] value, byte[] other, int len1, int len2) { + static int compareTo(byte[] value, byte[] other, int len1, int len2) { int lim = Math.min(len1, len2); int k = ArraysSupport.mismatch(value, other, lim); return (k < 0) ? len1 - len2 : getChar(value, k) - getChar(other, k); } @IntrinsicCandidate - public static int compareToUTF16(byte[] value, byte[] other) { + static int compareToUTF16(byte[] value, byte[] other) { int len1 = length(value); int len2 = StringUTF16.length(other); return compareToUTF16Values(value, other, len1, len2); @@ -130,7 +118,7 @@ final class StringLatin1 { /* * Checks the boundary and then compares the byte arrays. */ - public static int compareToUTF16(byte[] value, byte[] other, int len1, int len2) { + static int compareToUTF16(byte[] value, byte[] other, int len1, int len2) { checkOffset(len1, length(value)); checkOffset(len2, StringUTF16.length(other)); @@ -149,7 +137,7 @@ final class StringLatin1 { return len1 - len2; } - public static int compareToCI(byte[] value, byte[] other) { + static int compareToCI(byte[] value, byte[] other) { int len1 = value.length; int len2 = other.length; int lim = Math.min(len1, len2); @@ -169,7 +157,7 @@ final class StringLatin1 { return len1 - len2; } - public static int compareToCI_UTF16(byte[] value, byte[] other) { + static int compareToCI_UTF16(byte[] value, byte[] other) { int len1 = length(value); int len2 = StringUTF16.length(other); int lim = Math.min(len1, len2); @@ -191,12 +179,12 @@ final class StringLatin1 { return len1 - len2; } - public static int hashCode(byte[] value) { + static int hashCode(byte[] value) { return ArraysSupport.hashCodeOfUnsigned(value, 0, value.length, 0); } // Caller must ensure that from- and toIndex are within bounds - public static int indexOf(byte[] value, int ch, int fromIndex, int toIndex) { + static int indexOf(byte[] value, int ch, int fromIndex, int toIndex) { if (!canEncode(ch)) { return -1; } @@ -215,7 +203,7 @@ final class StringLatin1 { } @IntrinsicCandidate - public static int indexOf(byte[] value, byte[] str) { + static int indexOf(byte[] value, byte[] str) { if (str.length == 0) { return 0; } @@ -226,7 +214,7 @@ final class StringLatin1 { } @IntrinsicCandidate - public static int indexOf(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) { + static int indexOf(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) { byte first = str[0]; int max = (valueCount - strCount); for (int i = fromIndex; i <= max; i++) { @@ -248,8 +236,8 @@ final class StringLatin1 { return -1; } - public static int lastIndexOf(byte[] src, int srcCount, - byte[] tgt, int tgtCount, int fromIndex) { + static int lastIndexOf(byte[] src, int srcCount, + byte[] tgt, int tgtCount, int fromIndex) { int min = tgtCount - 1; int i = min + fromIndex; int strLastIndex = tgtCount - 1; @@ -276,7 +264,7 @@ final class StringLatin1 { } } - public static int lastIndexOf(final byte[] value, int ch, int fromIndex) { + static int lastIndexOf(final byte[] value, int ch, int fromIndex) { if (!canEncode(ch)) { return -1; } @@ -289,7 +277,7 @@ final class StringLatin1 { return -1; } - public static String replace(byte[] value, char oldChar, char newChar) { + static String replace(byte[] value, char oldChar, char newChar) { if (canEncode(oldChar)) { int len = value.length; int i = -1; @@ -326,8 +314,8 @@ final class StringLatin1 { return null; // for string to return this; } - public static String replace(byte[] value, int valLen, byte[] targ, - int targLen, byte[] repl, int replLen) + static String replace(byte[] value, int valLen, byte[] targ, + int targLen, byte[] repl, int replLen) { assert targLen > 0; int i, j, p = 0; @@ -377,8 +365,8 @@ final class StringLatin1 { } // case insensitive - public static boolean regionMatchesCI(byte[] value, int toffset, - byte[] other, int ooffset, int len) { + static boolean regionMatchesCI(byte[] value, int toffset, + byte[] other, int ooffset, int len) { int last = toffset + len; while (toffset < last) { byte b1 = value[toffset++]; @@ -391,8 +379,8 @@ final class StringLatin1 { return true; } - public static boolean regionMatchesCI_UTF16(byte[] value, int toffset, - byte[] other, int ooffset, int len) { + static boolean regionMatchesCI_UTF16(byte[] value, int toffset, + byte[] other, int ooffset, int len) { int last = toffset + len; while (toffset < last) { char c1 = (char)(value[toffset++] & 0xff); @@ -413,7 +401,7 @@ final class StringLatin1 { return true; } - public static String toLowerCase(String str, byte[] value, Locale locale) { + static String toLowerCase(String str, byte[] value, Locale locale) { if (locale == null) { throw new NullPointerException(); } @@ -480,7 +468,7 @@ final class StringLatin1 { return StringUTF16.newString(result, 0, resultOffset); } - public static String toUpperCase(String str, byte[] value, Locale locale) { + static String toUpperCase(String str, byte[] value, Locale locale) { if (locale == null) { throw new NullPointerException(); } @@ -560,7 +548,7 @@ final class StringLatin1 { return StringUTF16.newString(result, 0, resultOffset); } - public static String trim(byte[] value) { + static String trim(byte[] value) { int len = value.length; int st = 0; while ((st < len) && ((value[st] & 0xff) <= ' ')) { @@ -573,7 +561,7 @@ final class StringLatin1 { newString(value, st, len - st) : null; } - public static int indexOfNonWhitespace(byte[] value) { + static int indexOfNonWhitespace(byte[] value) { int length = value.length; int left = 0; while (left < length) { @@ -586,9 +574,8 @@ final class StringLatin1 { return left; } - public static int lastIndexOfNonWhitespace(byte[] value) { - int length = value.length; - int right = length; + static int lastIndexOfNonWhitespace(byte[] value) { + int right = value.length; while (0 < right) { char ch = getChar(value, right - 1); if (ch != ' ' && ch != '\t' && !CharacterDataLatin1.instance.isWhitespace(ch)) { @@ -599,7 +586,7 @@ final class StringLatin1 { return right; } - public static String strip(byte[] value) { + static String strip(byte[] value) { int left = indexOfNonWhitespace(value); if (left == value.length) { return ""; @@ -609,12 +596,12 @@ final class StringLatin1 { return ifChanged ? newString(value, left, right - left) : null; } - public static String stripLeading(byte[] value) { + static String stripLeading(byte[] value) { int left = indexOfNonWhitespace(value); return (left != 0) ? newString(value, left, value.length - left) : null; } - public static String stripTrailing(byte[] value) { + static String stripTrailing(byte[] value) { int right = lastIndexOfNonWhitespace(value); return (right != value.length) ? newString(value, 0, right) : null; } @@ -713,14 +700,14 @@ final class StringLatin1 { return StreamSupport.stream(LinesSpliterator.spliterator(value), false); } - public static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4) { + static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4) { value[i] = (byte)c1; value[i + 1] = (byte)c2; value[i + 2] = (byte)c3; value[i + 3] = (byte)c4; } - public static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4, char c5) { + static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4, char c5) { value[i] = (byte)c1; value[i + 1] = (byte)c2; value[i + 2] = (byte)c3; @@ -728,32 +715,15 @@ final class StringLatin1 { value[i + 4] = (byte)c5; } - public static void putChar(byte[] val, int index, int c) { - //assert (canEncode(c)); - val[index] = (byte)(c); - } - - public static char getChar(byte[] val, int index) { + static char getChar(byte[] val, int index) { return (char)(val[index] & 0xff); } - public static byte[] toBytes(int[] val, int off, int len) { - byte[] ret = new byte[len]; - for (int i = 0; i < len; i++) { - int cp = val[off++]; - if (!canEncode(cp)) { - return null; - } - ret[i] = (byte)cp; - } - return ret; - } - - public static byte[] toBytes(char c) { + static byte[] toBytes(char c) { return new byte[] { (byte)c }; } - public static String newString(byte[] val, int index, int len) { + static String newString(byte[] val, int index, int len) { if (len == 0) { return ""; } @@ -763,7 +733,7 @@ final class StringLatin1 { // inflatedCopy byte[] -> char[] @IntrinsicCandidate - public static void inflate(byte[] src, int srcOff, char[] dst, int dstOff, int len) { + static void inflate(byte[] src, int srcOff, char[] dst, int dstOff, int len) { for (int i = 0; i < len; i++) { dst[dstOff++] = (char)(src[srcOff++] & 0xff); } @@ -771,7 +741,7 @@ final class StringLatin1 { // inflatedCopy byte[] -> byte[] @IntrinsicCandidate - public static void inflate(byte[] src, int srcOff, byte[] dst, int dstOff, int len) { + static void inflate(byte[] src, int srcOff, byte[] dst, int dstOff, int len) { StringUTF16.inflate(src, srcOff, dst, dstOff, len); } @@ -824,7 +794,7 @@ final class StringLatin1 { } @Override - public long estimateSize() { return (long)(fence - index); } + public long estimateSize() { return fence - index; } @Override public int characteristics() { diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java index 08b4072fc35..4e31c9728e9 100644 --- a/src/java.base/share/classes/java/lang/StringUTF16.java +++ b/src/java.base/share/classes/java/lang/StringUTF16.java @@ -54,13 +54,13 @@ final class StringUTF16 { // Return a new byte array for a UTF16-coded string for len chars // Throw an exception if out of range - public static byte[] newBytesFor(int len) { + static byte[] newBytesFor(int len) { return new byte[newBytesLength(len)]; } // Check the size of a UTF16-coded string // Throw an exception if out of range - public static int newBytesLength(int len) { + static int newBytesLength(int len) { if (len < 0) { throw new NegativeArraySizeException(); } @@ -89,7 +89,7 @@ final class StringUTF16 { ((val[index] & 0xff) << LO_BYTE_SHIFT)); } - public static int length(byte[] value) { + static int length(byte[] value) { return value.length >> 1; } @@ -111,7 +111,7 @@ final class StringUTF16 { return c1; } - public static int codePointAt(byte[] value, int index, int end) { + static int codePointAt(byte[] value, int index, int end) { return codePointAt(value, index, end, false /* unchecked */); } @@ -134,7 +134,7 @@ final class StringUTF16 { return c2; } - public static int codePointBefore(byte[] value, int index) { + static int codePointBefore(byte[] value, int index) { return codePointBefore(value, index, false /* unchecked */); } @@ -155,11 +155,11 @@ final class StringUTF16 { return count; } - public static int codePointCount(byte[] value, int beginIndex, int endIndex) { + static int codePointCount(byte[] value, int beginIndex, int endIndex) { return codePointCount(value, beginIndex, endIndex, false /* unchecked */); } - public static char[] toChars(byte[] value) { + static char[] toChars(byte[] value) { char[] dst = new char[value.length >> 1]; getChars(value, 0, dst.length, dst, 0); return dst; @@ -173,7 +173,7 @@ final class StringUTF16 { * @param len a length */ @IntrinsicCandidate - public static byte[] toBytes(char[] value, int off, int len) { + static byte[] toBytes(char[] value, int off, int len) { byte[] val = newBytesFor(len); for (int i = 0; i < len; i++) { putChar(val, i, value[off]); @@ -218,7 +218,7 @@ final class StringUTF16 { * @param count count of chars to be compressed, {@code count} > 0 */ @ForceInline - public static byte[] compress(final char[] val, final int off, final int count) { + static byte[] compress(final char[] val, final int off, final int count) { byte[] latin1 = new byte[count]; int ndx = compress(val, off, latin1, 0, count); if (ndx != count) { @@ -245,7 +245,7 @@ final class StringUTF16 { * @param off starting offset * @param count count of chars to be compressed, {@code count} > 0 */ - public static byte[] compress(final byte[] val, final int off, final int count) { + static byte[] compress(final byte[] val, final int off, final int count) { byte[] latin1 = new byte[count]; int ndx = compress(val, off, latin1, 0, count); if (ndx != count) {// Switch to UTF16 @@ -279,7 +279,7 @@ final class StringUTF16 { * @param off starting offset * @param count length of code points to be compressed, length > 0 */ - public static byte[] compress(final int[] val, int off, final int count) { + static byte[] compress(final int[] val, int off, final int count) { // Optimistically copy all latin1 code points to the destination byte[] latin1 = new byte[count]; final int end = off + count; @@ -389,7 +389,7 @@ final class StringUTF16 { // compressedCopy char[] -> byte[] @IntrinsicCandidate - public static int compress(char[] src, int srcOff, byte[] dst, int dstOff, int len) { + static int compress(char[] src, int srcOff, byte[] dst, int dstOff, int len) { for (int i = 0; i < len; i++) { char c = src[srcOff]; if (c > 0xff) { @@ -404,7 +404,7 @@ final class StringUTF16 { // compressedCopy byte[] -> byte[] @IntrinsicCandidate - public static int compress(byte[] src, int srcOff, byte[] dst, int dstOff, int len) { + static int compress(byte[] src, int srcOff, byte[] dst, int dstOff, int len) { // We need a range check here because 'getChar' has no checks checkBoundsOffCount(srcOff, len, src); for (int i = 0; i < len; i++) { @@ -420,7 +420,7 @@ final class StringUTF16 { } // Create the UTF16 buffer for !COMPACT_STRINGS - public static byte[] toBytes(int[] val, int index, int len) { + static byte[] toBytes(int[] val, int index, int len) { final int end = index + len; int n = computeCodePointSize(val, index, end); @@ -428,7 +428,7 @@ final class StringUTF16 { return extractCodepoints(val, index, end, buf, 0); } - public static byte[] toBytes(char c) { + static byte[] toBytes(char c) { byte[] result = new byte[2]; putChar(result, 0, c); return result; @@ -442,7 +442,7 @@ final class StringUTF16 { } @IntrinsicCandidate - public static void getChars(byte[] value, int srcBegin, int srcEnd, char[] dst, int dstBegin) { + static void getChars(byte[] value, int srcBegin, int srcEnd, char[] dst, int dstBegin) { // We need a range check here because 'getChar' has no checks if (srcBegin < srcEnd) { checkBoundsOffCount(srcBegin, srcEnd - srcBegin, value); @@ -453,7 +453,7 @@ final class StringUTF16 { } /* @see java.lang.String.getBytes(int, int, byte[], int) */ - public static void getBytes(byte[] value, int srcBegin, int srcEnd, byte[] dst, int dstBegin) { + static void getBytes(byte[] value, int srcBegin, int srcEnd, byte[] dst, int dstBegin) { srcBegin <<= 1; srcEnd <<= 1; for (int i = srcBegin + (1 >> LO_BYTE_SHIFT); i < srcEnd; i += 2) { @@ -462,7 +462,7 @@ final class StringUTF16 { } @IntrinsicCandidate - public static int compareTo(byte[] value, byte[] other) { + static int compareTo(byte[] value, byte[] other) { int len1 = length(value); int len2 = length(other); return compareValues(value, other, len1, len2); @@ -471,7 +471,7 @@ final class StringUTF16 { /* * Checks the boundary and then compares the byte arrays. */ - public static int compareTo(byte[] value, byte[] other, int len1, int len2) { + static int compareTo(byte[] value, byte[] other, int len1, int len2) { checkOffset(len1, value); checkOffset(len2, other); @@ -491,15 +491,15 @@ final class StringUTF16 { } @IntrinsicCandidate - public static int compareToLatin1(byte[] value, byte[] other) { + static int compareToLatin1(byte[] value, byte[] other) { return -StringLatin1.compareToUTF16(other, value); } - public static int compareToLatin1(byte[] value, byte[] other, int len1, int len2) { + static int compareToLatin1(byte[] value, byte[] other, int len1, int len2) { return -StringLatin1.compareToUTF16(other, value, len2, len1); } - public static int compareToCI(byte[] value, byte[] other) { + static int compareToCI(byte[] value, byte[] other) { return compareToCIImpl(value, 0, length(value), other, 0, length(other)); } @@ -512,8 +512,8 @@ final class StringUTF16 { assert olast <= length(other); for (int k1 = toffset, k2 = ooffset; k1 < tlast && k2 < olast; k1++, k2++) { - int cp1 = (int)getChar(value, k1); - int cp2 = (int)getChar(other, k2); + int cp1 = getChar(value, k1); + int cp2 = getChar(other, k2); if (cp1 == cp2 || compareCodePointCI(cp1, cp2) == 0) { continue; @@ -588,16 +588,16 @@ final class StringUTF16 { return cp; } - public static int compareToCI_Latin1(byte[] value, byte[] other) { + static int compareToCI_Latin1(byte[] value, byte[] other) { return -StringLatin1.compareToCI_UTF16(other, value); } - public static int hashCode(byte[] value) { + static int hashCode(byte[] value) { return ArraysSupport.hashCodeOfUTF16(value, 0, value.length >> 1, 0); } // Caller must ensure that from- and toIndex are within bounds - public static int indexOf(byte[] value, int ch, int fromIndex, int toIndex) { + static int indexOf(byte[] value, int ch, int fromIndex, int toIndex) { if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) { // handle most cases here (ch is a BMP code point or a // negative value (invalid code point)) @@ -608,7 +608,7 @@ final class StringUTF16 { } @IntrinsicCandidate - public static int indexOf(byte[] value, byte[] str) { + static int indexOf(byte[] value, byte[] str) { if (str.length == 0) { return 0; } @@ -619,7 +619,7 @@ final class StringUTF16 { } @IntrinsicCandidate - public static int indexOf(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) { + static int indexOf(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) { checkBoundsBeginEnd(fromIndex, valueCount, value); checkBoundsBeginEnd(0, strCount, str); return indexOfUnsafe(value, valueCount, str, strCount, fromIndex); @@ -657,7 +657,7 @@ final class StringUTF16 { * Handles indexOf Latin1 substring in UTF16 string. */ @IntrinsicCandidate - public static int indexOfLatin1(byte[] value, byte[] str) { + static int indexOfLatin1(byte[] value, byte[] str) { if (str.length == 0) { return 0; } @@ -668,13 +668,13 @@ final class StringUTF16 { } @IntrinsicCandidate - public static int indexOfLatin1(byte[] src, int srcCount, byte[] tgt, int tgtCount, int fromIndex) { + static int indexOfLatin1(byte[] src, int srcCount, byte[] tgt, int tgtCount, int fromIndex) { checkBoundsBeginEnd(fromIndex, srcCount, src); String.checkBoundsBeginEnd(0, tgtCount, tgt.length); return indexOfLatin1Unsafe(src, srcCount, tgt, tgtCount, fromIndex); } - public static int indexOfLatin1Unsafe(byte[] src, int srcCount, byte[] tgt, int tgtCount, int fromIndex) { + static int indexOfLatin1Unsafe(byte[] src, int srcCount, byte[] tgt, int tgtCount, int fromIndex) { assert fromIndex >= 0; assert tgtCount > 0; assert tgtCount <= tgt.length; @@ -730,8 +730,8 @@ final class StringUTF16 { } // srcCoder == UTF16 && tgtCoder == UTF16 - public static int lastIndexOf(byte[] src, int srcCount, - byte[] tgt, int tgtCount, int fromIndex) { + static int lastIndexOf(byte[] src, int srcCount, + byte[] tgt, int tgtCount, int fromIndex) { assert fromIndex >= 0; assert tgtCount > 0; assert tgtCount <= length(tgt); @@ -765,7 +765,7 @@ final class StringUTF16 { } } - public static int lastIndexOf(byte[] value, int ch, int fromIndex) { + static int lastIndexOf(byte[] value, int ch, int fromIndex) { if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) { // handle most cases here (ch is a BMP code point or a // negative value (invalid code point)) @@ -798,7 +798,7 @@ final class StringUTF16 { return -1; } - public static String replace(byte[] value, char oldChar, char newChar) { + static String replace(byte[] value, char oldChar, char newChar) { int len = value.length >> 1; int i = -1; while (++i < len) { @@ -829,9 +829,9 @@ final class StringUTF16 { return null; } - public static String replace(byte[] value, int valLen, boolean valLat1, - byte[] targ, int targLen, boolean targLat1, - byte[] repl, int replLen, boolean replLat1) + static String replace(byte[] value, int valLen, boolean valLat1, + byte[] targ, int targLen, boolean targLat1, + byte[] repl, int replLen, boolean replLat1) { assert targLen > 0; assert !valLat1 || !targLat1 || !replLat1; @@ -944,18 +944,18 @@ final class StringUTF16 { return new String(result, UTF16); } - public static boolean regionMatchesCI(byte[] value, int toffset, - byte[] other, int ooffset, int len) { + static boolean regionMatchesCI(byte[] value, int toffset, + byte[] other, int ooffset, int len) { return compareToCIImpl(value, toffset, len, other, ooffset, len) == 0; } - public static boolean regionMatchesCI_Latin1(byte[] value, int toffset, - byte[] other, int ooffset, - int len) { + static boolean regionMatchesCI_Latin1(byte[] value, int toffset, + byte[] other, int ooffset, + int len) { return StringLatin1.regionMatchesCI_UTF16(other, ooffset, value, toffset, len); } - public static String toLowerCase(String str, byte[] value, Locale locale) { + static String toLowerCase(String str, byte[] value, Locale locale) { if (locale == null) { throw new NullPointerException(); } @@ -965,7 +965,7 @@ final class StringUTF16 { // Now check if there are any characters that need to be changed, or are surrogate for (first = 0 ; first < len; first++) { - int cp = (int)getChar(value, first); + int cp = getChar(value, first); if (Character.isSurrogate((char)cp)) { hasSurr = true; break; @@ -988,7 +988,7 @@ final class StringUTF16 { } int bits = 0; for (int i = first; i < len; i++) { - int cp = (int)getChar(value, i); + int cp = getChar(value, i); if (cp == '\u03A3' || // GREEK CAPITAL LETTER SIGMA Character.isSurrogate((char)cp)) { return toLowerCaseEx(str, value, result, i, locale, false); @@ -1003,7 +1003,7 @@ final class StringUTF16 { bits |= cp; putChar(result, i, cp); } - if (bits < 0 || bits > 0xff) { + if (bits > 0xff) { return new String(result, UTF16); } else { return newString(result, 0, len); @@ -1059,7 +1059,7 @@ final class StringUTF16 { return newString(result, 0, resultOffset); } - public static String toUpperCase(String str, byte[] value, Locale locale) { + static String toUpperCase(String str, byte[] value, Locale locale) { if (locale == null) { throw new NullPointerException(); } @@ -1069,7 +1069,7 @@ final class StringUTF16 { // Now check if there are any characters that need to be changed, or are surrogate for (first = 0 ; first < len; first++) { - int cp = (int)getChar(value, first); + int cp = getChar(value, first); if (Character.isSurrogate((char)cp)) { hasSurr = true; break; @@ -1093,7 +1093,7 @@ final class StringUTF16 { } int bits = 0; for (int i = first; i < len; i++) { - int cp = (int)getChar(value, i); + int cp = getChar(value, i); if (Character.isSurrogate((char)cp)) { return toUpperCaseEx(str, value, result, i, locale, false); } @@ -1104,7 +1104,7 @@ final class StringUTF16 { bits |= cp; putChar(result, i, cp); } - if (bits < 0 || bits > 0xff) { + if (bits > 0xff) { return new String(result, UTF16); } else { return newString(result, 0, len); @@ -1164,7 +1164,7 @@ final class StringUTF16 { return newString(result, 0, resultOffset); } - public static String trim(byte[] value) { + static String trim(byte[] value) { int length = value.length >> 1; int len = length; int st = 0; @@ -1179,7 +1179,7 @@ final class StringUTF16 { null; } - public static int indexOfNonWhitespace(byte[] value) { + static int indexOfNonWhitespace(byte[] value) { int length = value.length >> 1; int left = 0; while (left < length) { @@ -1192,9 +1192,8 @@ final class StringUTF16 { return left; } - public static int lastIndexOfNonWhitespace(byte[] value) { - int length = value.length >>> 1; - int right = length; + static int lastIndexOfNonWhitespace(byte[] value) { + int right = value.length >>> 1; while (0 < right) { int codepoint = codePointBefore(value, right); if (codepoint != ' ' && codepoint != '\t' && !Character.isWhitespace(codepoint)) { @@ -1205,7 +1204,7 @@ final class StringUTF16 { return right; } - public static String strip(byte[] value) { + static String strip(byte[] value) { int length = value.length >>> 1; int left = indexOfNonWhitespace(value); if (left == length) { @@ -1216,13 +1215,13 @@ final class StringUTF16 { return ifChanged ? newString(value, left, right - left) : null; } - public static String stripLeading(byte[] value) { + static String stripLeading(byte[] value) { int length = value.length >>> 1; int left = indexOfNonWhitespace(value); return (left != 0) ? newString(value, left, length - left) : null; } - public static String stripTrailing(byte[] value) { + static String stripTrailing(byte[] value) { int length = value.length >>> 1; int right = lastIndexOfNonWhitespace(value); return (right != length) ? newString(value, 0, right) : null; @@ -1322,7 +1321,7 @@ final class StringUTF16 { return StreamSupport.stream(LinesSpliterator.spliterator(value), false); } - public static String newString(byte[] val, int index, int len) { + static String newString(byte[] val, int index, int len) { if (len == 0) { return ""; } @@ -1388,7 +1387,7 @@ final class StringUTF16 { } @Override - public long estimateSize() { return (long)(fence - index); } + public long estimateSize() { return fence - index; } @Override public int characteristics() { @@ -1473,7 +1472,7 @@ final class StringUTF16 { } @Override - public long estimateSize() { return (long)(fence - index); } + public long estimateSize() { return fence - index; } @Override public int characteristics() { @@ -1483,12 +1482,12 @@ final class StringUTF16 { //////////////////////////////////////////////////////////////// - public static void putCharSB(byte[] val, int index, int c) { + static void putCharSB(byte[] val, int index, int c) { checkIndex(index, val); putChar(val, index, c); } - public static void putCharsSB(byte[] val, int index, char[] ca, int off, int end) { + static void putCharsSB(byte[] val, int index, char[] ca, int off, int end) { checkBoundsBeginEnd(index, index + end - off, val); String.checkBoundsBeginEnd(off, end, ca.length); Unsafe.getUnsafe().copyMemory( @@ -1499,26 +1498,26 @@ final class StringUTF16 { (long) (end - off) << 1); } - public static void putCharsSB(byte[] val, int index, CharSequence s, int off, int end) { + static void putCharsSB(byte[] val, int index, CharSequence s, int off, int end) { checkBoundsBeginEnd(index, index + end - off, val); for (int i = off; i < end; i++) { putChar(val, index++, s.charAt(i)); } } - public static int codePointAtSB(byte[] val, int index, int end) { + static int codePointAtSB(byte[] val, int index, int end) { return codePointAt(val, index, end, true /* checked */); } - public static int codePointBeforeSB(byte[] val, int index) { + static int codePointBeforeSB(byte[] val, int index) { return codePointBefore(val, index, true /* checked */); } - public static int codePointCountSB(byte[] val, int beginIndex, int endIndex) { + static int codePointCountSB(byte[] val, int beginIndex, int endIndex) { return codePointCount(val, beginIndex, endIndex, true /* checked */); } - public static boolean contentEquals(byte[] v1, byte[] v2, int len) { + static boolean contentEquals(byte[] v1, byte[] v2, int len) { checkBoundsOffCount(0, len, v2); for (int i = 0; i < len; i++) { if ((char)(v1[i] & 0xff) != getChar(v2, i)) { @@ -1528,7 +1527,7 @@ final class StringUTF16 { return true; } - public static boolean contentEquals(byte[] value, CharSequence cs, int len) { + static boolean contentEquals(byte[] value, CharSequence cs, int len) { checkOffset(len, value); for (int i = 0; i < len; i++) { if (getChar(value, i) != cs.charAt(i)) { @@ -1538,7 +1537,7 @@ final class StringUTF16 { return true; } - public static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4) { + static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4) { int end = i + 4; checkBoundsBeginEnd(i, end, value); putChar(value, i, c1); @@ -1547,7 +1546,7 @@ final class StringUTF16 { putChar(value, i + 3, c4); } - public static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4, char c5) { + static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4, char c5) { int end = i + 5; checkBoundsBeginEnd(i, end, value); putChar(value, i, c1); @@ -1557,12 +1556,12 @@ final class StringUTF16 { putChar(value, i + 4, c5); } - public static char charAt(byte[] value, int index) { + static char charAt(byte[] value, int index) { checkIndex(index, value); return getChar(value, index); } - public static void reverse(byte[] val, int count) { + static void reverse(byte[] val, int count) { checkOffset(count, val); int n = count - 1; boolean hasSurrogates = false; @@ -1597,7 +1596,7 @@ final class StringUTF16 { } // inflatedCopy byte[] -> byte[] - public static void inflate(byte[] src, int srcOff, byte[] dst, int dstOff, int len) { + static void inflate(byte[] src, int srcOff, byte[] dst, int dstOff, int len) { // We need a range check here because 'putChar' has no checks checkBoundsOffCount(dstOff, len, dst); for (int i = 0; i < len; i++) { @@ -1606,7 +1605,7 @@ final class StringUTF16 { } // srcCoder == UTF16 && tgtCoder == LATIN1 - public static int lastIndexOfLatin1(byte[] src, int srcCount, + static int lastIndexOfLatin1(byte[] src, int srcCount, byte[] tgt, int tgtCount, int fromIndex) { assert fromIndex >= 0; assert tgtCount > 0; @@ -1659,19 +1658,19 @@ final class StringUTF16 { static final int MAX_LENGTH = Integer.MAX_VALUE >> 1; - public static void checkIndex(int off, byte[] val) { + static void checkIndex(int off, byte[] val) { String.checkIndex(off, length(val)); } - public static void checkOffset(int off, byte[] val) { + static void checkOffset(int off, byte[] val) { String.checkOffset(off, length(val)); } - public static void checkBoundsBeginEnd(int begin, int end, byte[] val) { + static void checkBoundsBeginEnd(int begin, int end, byte[] val) { String.checkBoundsBeginEnd(begin, end, length(val)); } - public static void checkBoundsOffCount(int offset, int count, byte[] val) { + static void checkBoundsOffCount(int offset, int count, byte[] val) { String.checkBoundsOffCount(offset, count, length(val)); } From 837f634bf29fd877dd62a2e0f7d7a1bd383372d3 Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Fri, 3 Oct 2025 21:11:33 +0000 Subject: [PATCH 018/160] 8369128: ProblemList jdk/jfr/event/profiling/TestCPUTimeSampleQueueAutoSizes.java in Xcomp configs 8369132: Disable vmTestbase/gc/vector/CircularListLow and LinearListLow with SerialGC 8369133: Disable gc/g1/TestShrinkAuxiliaryDataRunner.java with UseLargePages option Reviewed-by: ayang, dholmes --- test/hotspot/jtreg/gc/g1/TestShrinkAuxiliaryDataRunner.java | 1 + .../vmTestbase/gc/vector/CircularListLow/TestDescription.java | 1 + .../vmTestbase/gc/vector/LinearListLow/TestDescription.java | 1 + test/jdk/ProblemList-Xcomp.txt | 1 + 4 files changed, 4 insertions(+) diff --git a/test/hotspot/jtreg/gc/g1/TestShrinkAuxiliaryDataRunner.java b/test/hotspot/jtreg/gc/g1/TestShrinkAuxiliaryDataRunner.java index 309ba722787..d478f811490 100644 --- a/test/hotspot/jtreg/gc/g1/TestShrinkAuxiliaryDataRunner.java +++ b/test/hotspot/jtreg/gc/g1/TestShrinkAuxiliaryDataRunner.java @@ -29,6 +29,7 @@ package gc.g1; * @bug 8038423 8061715 * @summary Checks that decommitment occurs for JVM with different ObjectAlignmentInBytes values * @requires vm.gc.G1 + * @requires !vm.opt.final.UseLargePages * @library /test/lib * @library / * @modules java.base/jdk.internal.misc diff --git a/test/hotspot/jtreg/vmTestbase/gc/vector/CircularListLow/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/vector/CircularListLow/TestDescription.java index 68fe6779e99..252e3a2d40f 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/vector/CircularListLow/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/vector/CircularListLow/TestDescription.java @@ -31,5 +31,6 @@ * * @library /vmTestbase * /test/lib + * @requires vm.gc != "Serial" * @run main/othervm/timeout=480 gc.vector.SimpleGC.SimpleGC -ms low -gp circularList(low) */ diff --git a/test/hotspot/jtreg/vmTestbase/gc/vector/LinearListLow/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/vector/LinearListLow/TestDescription.java index 8ae86af035d..bd094045abf 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/vector/LinearListLow/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/vector/LinearListLow/TestDescription.java @@ -31,5 +31,6 @@ * * @library /vmTestbase * /test/lib + * @requires vm.gc != "Serial" * @run main/othervm gc.vector.SimpleGC.SimpleGC -ms low -gp linearList(low) */ diff --git a/test/jdk/ProblemList-Xcomp.txt b/test/jdk/ProblemList-Xcomp.txt index 5ed171a1fea..8e37e6e15d0 100644 --- a/test/jdk/ProblemList-Xcomp.txt +++ b/test/jdk/ProblemList-Xcomp.txt @@ -29,3 +29,4 @@ java/lang/invoke/MethodHandles/CatchExceptionTest.java 8146623 generic-all java/lang/reflect/callerCache/ReflectionCallerCacheTest.java 8332028 generic-all +jdk/jfr/event/profiling/TestCPUTimeSampleQueueAutoSizes.java 8367302 linux-all From e6868c624851d5c6bd182e45ba908cb06b731e8c Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Fri, 3 Oct 2025 22:17:01 +0000 Subject: [PATCH 019/160] 8369138: New test compiler/loopstripmining/MissingStoreAfterOuterStripMinedLoop.java fails Reviewed-by: kvn --- .../MissingStoreAfterOuterStripMinedLoop.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/compiler/loopstripmining/MissingStoreAfterOuterStripMinedLoop.java b/test/hotspot/jtreg/compiler/loopstripmining/MissingStoreAfterOuterStripMinedLoop.java index 8fa6cae12e6..24e3c4a5d30 100644 --- a/test/hotspot/jtreg/compiler/loopstripmining/MissingStoreAfterOuterStripMinedLoop.java +++ b/test/hotspot/jtreg/compiler/loopstripmining/MissingStoreAfterOuterStripMinedLoop.java @@ -29,7 +29,8 @@ * leading to wrong results. * * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation - * -Xcomp -XX:-UseLoopPredicate -XX:-UseAutoVectorizationPredicate + * -Xcomp -XX:-UseLoopPredicate + * -XX:+UnlockDiagnosticVMOptions -XX:-UseAutoVectorizationPredicate * -XX:CompileCommand=compileonly,compiler.loopstripmining.MissingStoreAfterOuterStripMinedLoop::test* * compiler.loopstripmining.MissingStoreAfterOuterStripMinedLoop * @run main compiler.loopstripmining.MissingStoreAfterOuterStripMinedLoop @@ -133,4 +134,4 @@ public class MissingStoreAfterOuterStripMinedLoop { throw new RuntimeException("unexpected value: " + a1.field + " " + a2.field + " " + a3.field); } } -} \ No newline at end of file +} From c3fbbfabcc9a9535a3b422c1c9afaa8e092a5da0 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Fri, 3 Oct 2025 23:16:41 +0000 Subject: [PATCH 020/160] 8369027: Apply java.io.Serial annotations in java.scripting Reviewed-by: rriggs --- .../share/classes/javax/script/ScriptException.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/java.scripting/share/classes/javax/script/ScriptException.java b/src/java.scripting/share/classes/javax/script/ScriptException.java index 1037ccde27f..48fb3221914 100644 --- a/src/java.scripting/share/classes/javax/script/ScriptException.java +++ b/src/java.scripting/share/classes/javax/script/ScriptException.java @@ -25,6 +25,8 @@ package javax.script; +import java.io.Serial; + /** * The generic Exception class for the Scripting APIs. Checked * exception types thrown by underlying scripting implementations must be wrapped in instances of @@ -36,6 +38,7 @@ package javax.script; */ public class ScriptException extends Exception { + @Serial private static final long serialVersionUID = 8265071037049225001L; /** @serial */ From 76dba201fa1a525780677e4d3dee8e9ffafd1cd7 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Sat, 4 Oct 2025 08:09:09 +0000 Subject: [PATCH 021/160] 8368821: Test java/net/httpclient/http3/GetHTTP3Test.java intermittently fails with java.io.IOException: QUIC endpoint closed Reviewed-by: dfuchs --- test/jdk/java/net/httpclient/http3/GetHTTP3Test.java | 12 ++++++------ .../jdk/java/net/httpclient/http3/PostHTTP3Test.java | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/test/jdk/java/net/httpclient/http3/GetHTTP3Test.java b/test/jdk/java/net/httpclient/http3/GetHTTP3Test.java index a67710c485f..14842d401fd 100644 --- a/test/jdk/java/net/httpclient/http3/GetHTTP3Test.java +++ b/test/jdk/java/net/httpclient/http3/GetHTTP3Test.java @@ -33,7 +33,6 @@ import java.net.http.HttpOption.Http3DiscoveryMode; import java.net.http.HttpResponse; import java.net.http.HttpResponse.BodyHandlers; import java.nio.charset.StandardCharsets; -import java.time.Duration; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -47,6 +46,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicLong; import javax.net.ssl.SSLContext; +import jdk.test.lib.Utils; import jdk.test.lib.net.SimpleSSLContext; import jdk.httpclient.test.lib.common.HttpServerAdapters; import jdk.httpclient.test.lib.http2.Http2TestServer; @@ -74,8 +74,9 @@ import static java.lang.System.out; * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext * jdk.httpclient.test.lib.common.HttpServerAdapters + * jdk.test.lib.Utils * @compile ../ReferenceTracker.java - * @run testng/othervm/timeout=60 -Djdk.internal.httpclient.debug=true + * @run testng/othervm -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=requests,responses,errors * GetHTTP3Test * @summary Basic HTTP/3 GET test @@ -216,7 +217,6 @@ public class GetHTTP3Test implements HttpServerAdapters { .proxy(HttpClient.Builder.NO_PROXY) .executor(executor) .sslContext(sslContext) - .connectTimeout(Duration.ofSeconds(10)) .build(); return TRACKER.track(client); } @@ -348,7 +348,7 @@ public class GetHTTP3Test implements HttpServerAdapters { var tracker = TRACKER.getTracker(client); client = null; System.gc(); - AssertionError error = TRACKER.check(tracker, 1000); + AssertionError error = TRACKER.check(tracker, Utils.adjustTimeout(1000)); if (error != null) throw error; } System.out.println("test: DONE"); @@ -394,7 +394,7 @@ public class GetHTTP3Test implements HttpServerAdapters { var tracker = TRACKER.getTracker(client); client = null; System.gc(); - AssertionError error = TRACKER.check(tracker, 1000); + AssertionError error = TRACKER.check(tracker, Utils.adjustTimeout(1000)); if (error != null) throw error; } @@ -423,7 +423,7 @@ public class GetHTTP3Test implements HttpServerAdapters { sharedClient == null ? null : sharedClient.toString(); sharedClient = null; Thread.sleep(100); - AssertionError fail = TRACKER.check(500); + AssertionError fail = TRACKER.check(Utils.adjustTimeout(1000)); try { h3TestServer.stop(); } finally { diff --git a/test/jdk/java/net/httpclient/http3/PostHTTP3Test.java b/test/jdk/java/net/httpclient/http3/PostHTTP3Test.java index 0e7a57ca699..8bb6515d4ff 100644 --- a/test/jdk/java/net/httpclient/http3/PostHTTP3Test.java +++ b/test/jdk/java/net/httpclient/http3/PostHTTP3Test.java @@ -38,7 +38,6 @@ import java.net.http.HttpOption.Http3DiscoveryMode; import java.net.http.HttpResponse; import java.net.http.HttpResponse.BodyHandlers; import java.nio.charset.StandardCharsets; -import java.time.Duration; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -53,6 +52,7 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.stream.Stream; import javax.net.ssl.SSLContext; +import jdk.test.lib.Utils; import jdk.test.lib.net.SimpleSSLContext; import jdk.httpclient.test.lib.common.HttpServerAdapters; import jdk.httpclient.test.lib.http2.Http2TestServer; @@ -79,6 +79,7 @@ import static java.lang.System.out; * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext * jdk.httpclient.test.lib.common.HttpServerAdapters + * jdk.test.lib.Utils * @compile ../ReferenceTracker.java * @run testng/othervm -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=requests,responses,errors @@ -221,7 +222,6 @@ public class PostHTTP3Test implements HttpServerAdapters { .proxy(HttpClient.Builder.NO_PROXY) .executor(executor) .sslContext(sslContext) - .connectTimeout(Duration.ofSeconds(10)) .build(); return TRACKER.track(client); } @@ -375,7 +375,7 @@ public class PostHTTP3Test implements HttpServerAdapters { var tracker = TRACKER.getTracker(client); client = null; System.gc(); - AssertionError error = TRACKER.check(tracker, 1000); + AssertionError error = TRACKER.check(tracker, Utils.adjustTimeout(1000)); if (error != null) throw error; } System.out.println("test: DONE"); @@ -437,7 +437,7 @@ public class PostHTTP3Test implements HttpServerAdapters { var tracker = TRACKER.getTracker(client); client = null; System.gc(); - AssertionError error = TRACKER.check(tracker, 1000); + AssertionError error = TRACKER.check(tracker, Utils.adjustTimeout(1000)); if (error != null) throw error; } @@ -466,7 +466,7 @@ public class PostHTTP3Test implements HttpServerAdapters { sharedClient == null ? null : sharedClient.toString(); sharedClient = null; Thread.sleep(100); - AssertionError fail = TRACKER.check(500); + AssertionError fail = TRACKER.check(Utils.adjustTimeout(1000)); try { h3TestServer.stop(); } finally { From f740cd2aad43a008da1ed1ff15ebe2c790f893a0 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Sat, 4 Oct 2025 21:17:26 +0000 Subject: [PATCH 022/160] 8316694: Implement relocation of nmethod within CodeCache Reviewed-by: kvn, eosterlund, never, eastigeevich, bulasevich --- src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp | 1 - src/hotspot/share/code/codeBehaviours.cpp | 11 +- src/hotspot/share/code/codeBehaviours.hpp | 12 +- src/hotspot/share/code/codeCache.hpp | 2 +- src/hotspot/share/code/compiledIC.cpp | 4 +- src/hotspot/share/code/compiledIC.hpp | 2 +- src/hotspot/share/code/nmethod.cpp | 311 +++++++++++++++++- src/hotspot/share/code/nmethod.hpp | 24 +- src/hotspot/share/code/relocInfo.cpp | 3 +- src/hotspot/share/compiler/oopMap.cpp | 6 + src/hotspot/share/compiler/oopMap.hpp | 2 + .../share/gc/shenandoah/shenandoahUnload.cpp | 2 +- src/hotspot/share/gc/z/zUnload.cpp | 2 +- src/hotspot/share/jvmci/jvmciRuntime.hpp | 5 + src/hotspot/share/prims/whitebox.cpp | 58 +++- src/hotspot/share/runtime/globals.hpp | 3 + .../classes/sun/jvm/hotspot/code/NMethod.java | 43 +-- .../whitebox/CompilerWhiteBoxTest.java | 56 +++- .../whitebox/DeoptimizeRelocatedNMethod.java | 157 +++++++++ .../compiler/whitebox/RelocateNMethod.java | 146 ++++++++ .../RelocateNMethodMultiplePaths.java | 261 +++++++++++++++ .../whitebox/StressNMethodRelocation.java | 239 ++++++++++++++ .../NMethodRelocationTest.java | 178 ++++++++++ .../libNMethodRelocationTest.cpp | 114 +++++++ test/lib/jdk/test/whitebox/WhiteBox.java | 6 + test/lib/jdk/test/whitebox/code/CodeBlob.java | 7 +- 26 files changed, 1591 insertions(+), 64 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java create mode 100644 test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java create mode 100644 test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java create mode 100644 test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java create mode 100644 test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java create mode 100644 test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/libNMethodRelocationTest.cpp diff --git a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp index f5d7d9e4387..94694b58d2f 100644 --- a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp @@ -90,7 +90,6 @@ void Relocation::pd_set_call_destination(address x) { void trampoline_stub_Relocation::pd_fix_owner_after_move() { NativeCall* call = nativeCall_at(owner()); - assert(call->raw_destination() == owner(), "destination should be empty"); address trampoline = addr(); address dest = nativeCallTrampolineStub_at(trampoline)->destination(); if (!Assembler::reachable_from_branch_at(owner(), dest)) { diff --git a/src/hotspot/share/code/codeBehaviours.cpp b/src/hotspot/share/code/codeBehaviours.cpp index 1f9eb0e2914..bc5a81c95b3 100644 --- a/src/hotspot/share/code/codeBehaviours.cpp +++ b/src/hotspot/share/code/codeBehaviours.cpp @@ -23,23 +23,24 @@ */ #include "code/codeBehaviours.hpp" +#include "code/nmethod.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/safepoint.hpp" CompiledICProtectionBehaviour* CompiledICProtectionBehaviour::_current = nullptr; -bool DefaultICProtectionBehaviour::lock(nmethod* method) { - if (is_safe(method)) { +bool DefaultICProtectionBehaviour::lock(nmethod* nm) { + if (is_safe(nm)) { return false; } CompiledIC_lock->lock_without_safepoint_check(); return true; } -void DefaultICProtectionBehaviour::unlock(nmethod* method) { +void DefaultICProtectionBehaviour::unlock(nmethod* nm) { CompiledIC_lock->unlock(); } -bool DefaultICProtectionBehaviour::is_safe(nmethod* method) { - return SafepointSynchronize::is_at_safepoint() || CompiledIC_lock->owned_by_self(); +bool DefaultICProtectionBehaviour::is_safe(nmethod* nm) { + return SafepointSynchronize::is_at_safepoint() || CompiledIC_lock->owned_by_self() || (NMethodState_lock->owned_by_self() && nm->is_not_installed()); } diff --git a/src/hotspot/share/code/codeBehaviours.hpp b/src/hotspot/share/code/codeBehaviours.hpp index 0350f5752f6..96a38fffc30 100644 --- a/src/hotspot/share/code/codeBehaviours.hpp +++ b/src/hotspot/share/code/codeBehaviours.hpp @@ -33,18 +33,18 @@ class CompiledICProtectionBehaviour { static CompiledICProtectionBehaviour* _current; public: - virtual bool lock(nmethod* method) = 0; - virtual void unlock(nmethod* method) = 0; - virtual bool is_safe(nmethod* method) = 0; + virtual bool lock(nmethod* nm) = 0; + virtual void unlock(nmethod* nm) = 0; + virtual bool is_safe(nmethod* nm) = 0; static CompiledICProtectionBehaviour* current() { return _current; } static void set_current(CompiledICProtectionBehaviour* current) { _current = current; } }; class DefaultICProtectionBehaviour: public CompiledICProtectionBehaviour, public CHeapObj { - virtual bool lock(nmethod* method); - virtual void unlock(nmethod* method); - virtual bool is_safe(nmethod* method); + virtual bool lock(nmethod* nm); + virtual void unlock(nmethod* nm); + virtual bool is_safe(nmethod* nm); }; #endif // SHARE_CODE_CODEBEHAVIOURS_HPP diff --git a/src/hotspot/share/code/codeCache.hpp b/src/hotspot/share/code/codeCache.hpp index 3e446ab8430..dc9e5d7dc20 100644 --- a/src/hotspot/share/code/codeCache.hpp +++ b/src/hotspot/share/code/codeCache.hpp @@ -259,7 +259,7 @@ class CodeCache : AllStatic { static bool heap_available(CodeBlobType code_blob_type); // Returns the CodeBlobType for the given nmethod - static CodeBlobType get_code_blob_type(nmethod* nm) { + static CodeBlobType get_code_blob_type(const nmethod* nm) { return get_code_heap(nm)->code_blob_type(); } diff --git a/src/hotspot/share/code/compiledIC.cpp b/src/hotspot/share/code/compiledIC.cpp index 03d9adc8e24..5f5c9711441 100644 --- a/src/hotspot/share/code/compiledIC.cpp +++ b/src/hotspot/share/code/compiledIC.cpp @@ -55,8 +55,8 @@ CompiledICLocker::~CompiledICLocker() { } } -bool CompiledICLocker::is_safe(nmethod* method) { - return CompiledICProtectionBehaviour::current()->is_safe(method); +bool CompiledICLocker::is_safe(nmethod* nm) { + return CompiledICProtectionBehaviour::current()->is_safe(nm); } bool CompiledICLocker::is_safe(address code) { diff --git a/src/hotspot/share/code/compiledIC.hpp b/src/hotspot/share/code/compiledIC.hpp index 624c1b428de..db8a0860b39 100644 --- a/src/hotspot/share/code/compiledIC.hpp +++ b/src/hotspot/share/code/compiledIC.hpp @@ -50,7 +50,7 @@ class CompiledICLocker: public StackObj { public: CompiledICLocker(nmethod* method); ~CompiledICLocker(); - static bool is_safe(nmethod* method); + static bool is_safe(nmethod* nm); static bool is_safe(address code); }; diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 1540fa0333a..7274b627f3e 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -754,7 +754,7 @@ Method* nmethod::attached_method_before_pc(address pc) { } void nmethod::clear_inline_caches() { - assert(SafepointSynchronize::is_at_safepoint(), "clearing of IC's only allowed at safepoint"); + assert(SafepointSynchronize::is_at_safepoint() || (NMethodState_lock->owned_by_self() && is_not_installed()), "clearing of IC's only allowed at safepoint or when not installed"); RelocIterator iter(this); while (iter.next()) { iter.reloc()->clear_inline_cache(); @@ -1146,7 +1146,8 @@ nmethod* nmethod::new_nmethod(const methodHandle& method, #if INCLUDE_JVMCI + align_up(speculations_len , oopSize) #endif - + align_up(debug_info->data_size() , oopSize); + + align_up(debug_info->data_size() , oopSize) + + align_up(ImmutableDataReferencesCounterSize, oopSize); // First, allocate space for immutable data in C heap. address immutable_data = nullptr; @@ -1371,10 +1372,266 @@ nmethod::nmethod( } } + +nmethod::nmethod(const nmethod &nm) : CodeBlob(nm._name, nm._kind, nm._size, nm._header_size) +{ + + if (nm._oop_maps != nullptr) { + _oop_maps = nm._oop_maps->clone(); + } else { + _oop_maps = nullptr; + } + + _size = nm._size; + _relocation_size = nm._relocation_size; + _content_offset = nm._content_offset; + _code_offset = nm._code_offset; + _data_offset = nm._data_offset; + _frame_size = nm._frame_size; + + S390_ONLY( _ctable_offset = nm._ctable_offset; ) + + _header_size = nm._header_size; + _frame_complete_offset = nm._frame_complete_offset; + + _kind = nm._kind; + + _caller_must_gc_arguments = nm._caller_must_gc_arguments; + +#ifndef PRODUCT + _asm_remarks.share(nm._asm_remarks); + _dbg_strings.share(nm._dbg_strings); +#endif + + // Allocate memory and copy mutable data to C heap + _mutable_data_size = nm._mutable_data_size; + if (_mutable_data_size > 0) { + _mutable_data = (address)os::malloc(_mutable_data_size, mtCode); + if (_mutable_data == nullptr) { + vm_exit_out_of_memory(_mutable_data_size, OOM_MALLOC_ERROR, "nmethod: no space for mutable data"); + } + memcpy(mutable_data_begin(), nm.mutable_data_begin(), nm.mutable_data_size()); + } else { + _mutable_data = nullptr; + } + + _deoptimization_generation = 0; + _gc_epoch = CodeCache::gc_epoch(); + _method = nm._method; + _osr_link = nullptr; + + // Increment number of references to immutable data to share it between nmethods + _immutable_data_size = nm._immutable_data_size; + if (_immutable_data_size > 0) { + _immutable_data = nm._immutable_data; + set_immutable_data_references_counter(get_immutable_data_references_counter() + 1); + } else { + _immutable_data = blob_end(); + } + + _exception_cache = nullptr; + _gc_data = nullptr; + _oops_do_mark_nmethods = nullptr; + _oops_do_mark_link = nullptr; + _compiled_ic_data = nullptr; + + if (nm._osr_entry_point != nullptr) { + _osr_entry_point = (nm._osr_entry_point - (address) &nm) + (address) this; + } else { + _osr_entry_point = nullptr; + } + + _entry_offset = nm._entry_offset; + _verified_entry_offset = nm._verified_entry_offset; + _entry_bci = nm._entry_bci; + + _skipped_instructions_size = nm._skipped_instructions_size; + _stub_offset = nm._stub_offset; + _exception_offset = nm._exception_offset; + _deopt_handler_offset = nm._deopt_handler_offset; + _unwind_handler_offset = nm._unwind_handler_offset; + _num_stack_arg_slots = nm._num_stack_arg_slots; + _oops_size = nm._oops_size; +#if INCLUDE_JVMCI + _metadata_size = nm._metadata_size; +#endif + _nul_chk_table_offset = nm._nul_chk_table_offset; + _handler_table_offset = nm._handler_table_offset; + _scopes_pcs_offset = nm._scopes_pcs_offset; + _scopes_data_offset = nm._scopes_data_offset; +#if INCLUDE_JVMCI + _speculations_offset = nm._speculations_offset; +#endif + + _orig_pc_offset = nm._orig_pc_offset; + _compile_id = nm._compile_id; + _comp_level = nm._comp_level; + _compiler_type = nm._compiler_type; + _is_unloading_state = nm._is_unloading_state; + _state = not_installed; + + _has_unsafe_access = nm._has_unsafe_access; + _has_wide_vectors = nm._has_wide_vectors; + _has_monitors = nm._has_monitors; + _has_scoped_access = nm._has_scoped_access; + _has_flushed_dependencies = nm._has_flushed_dependencies; + _is_unlinked = nm._is_unlinked; + _load_reported = nm._load_reported; + + _deoptimization_status = nm._deoptimization_status; + + if (nm._pc_desc_container != nullptr) { + _pc_desc_container = new PcDescContainer(scopes_pcs_begin()); + } else { + _pc_desc_container = nullptr; + } + + // Copy nmethod contents excluding header + // - Constant part (doubles, longs and floats used in nmethod) + // - Code part: + // - Code body + // - Exception handler + // - Stub code + // - OOP table + memcpy(consts_begin(), nm.consts_begin(), nm.data_end() - nm.consts_begin()); + + post_init(); +} + +nmethod* nmethod::relocate(CodeBlobType code_blob_type) { + assert(NMethodRelocation, "must enable use of function"); + + // Locks required to be held by caller to ensure the nmethod + // is not modified or purged from code cache during relocation + assert_lock_strong(CodeCache_lock); + assert_lock_strong(Compile_lock); + assert(CompiledICLocker::is_safe(this), "mt unsafe call"); + + if (!is_relocatable()) { + return nullptr; + } + + run_nmethod_entry_barrier(); + nmethod* nm_copy = new (size(), code_blob_type) nmethod(*this); + + if (nm_copy == nullptr) { + return nullptr; + } + + // Fix relocation + RelocIterator iter(nm_copy); + CodeBuffer src(this); + CodeBuffer dst(nm_copy); + while (iter.next()) { +#ifdef USE_TRAMPOLINE_STUB_FIX_OWNER + // Direct calls may no longer be in range and the use of a trampoline may now be required. + // Instead, allow trampoline relocations to update their owners and perform the necessary checks. + if (iter.reloc()->is_call()) { + address trampoline = trampoline_stub_Relocation::get_trampoline_for(iter.reloc()->addr(), nm_copy); + if (trampoline != nullptr) { + continue; + } + } +#endif + + iter.reloc()->fix_relocation_after_move(&src, &dst); + } + + // To make dependency checking during class loading fast, record + // the nmethod dependencies in the classes it is dependent on. + // This allows the dependency checking code to simply walk the + // class hierarchy above the loaded class, checking only nmethods + // which are dependent on those classes. The slow way is to + // check every nmethod for dependencies which makes it linear in + // the number of methods compiled. For applications with a lot + // classes the slow way is too slow. + for (Dependencies::DepStream deps(nm_copy); deps.next(); ) { + if (deps.type() == Dependencies::call_site_target_value) { + // CallSite dependencies are managed on per-CallSite instance basis. + oop call_site = deps.argument_oop(0); + MethodHandles::add_dependent_nmethod(call_site, nm_copy); + } else { + InstanceKlass* ik = deps.context_type(); + if (ik == nullptr) { + continue; // ignore things like evol_method + } + // record this nmethod as dependent on this klass + ik->add_dependent_nmethod(nm_copy); + } + } + + MutexLocker ml_NMethodState_lock(NMethodState_lock, Mutex::_no_safepoint_check_flag); + + // Verify the nm we copied from is still valid + if (!is_marked_for_deoptimization() && is_in_use()) { + assert(method() != nullptr && method()->code() == this, "should be if is in use"); + + nm_copy->clear_inline_caches(); + + // Attempt to start using the copy + if (nm_copy->make_in_use()) { + ICache::invalidate_range(nm_copy->code_begin(), nm_copy->code_size()); + + methodHandle mh(Thread::current(), nm_copy->method()); + nm_copy->method()->set_code(mh, nm_copy); + + make_not_used(); + + nm_copy->post_compiled_method_load_event(); + + nm_copy->log_relocated_nmethod(this); + + return nm_copy; + } + } + + nm_copy->make_not_used(); + + return nullptr; +} + +bool nmethod::is_relocatable() { + if (!is_java_method()) { + return false; + } + + if (!is_in_use()) { + return false; + } + + if (is_osr_method()) { + return false; + } + + if (is_marked_for_deoptimization()) { + return false; + } + +#if INCLUDE_JVMCI + if (jvmci_nmethod_data() != nullptr && jvmci_nmethod_data()->has_mirror()) { + return false; + } +#endif + + if (is_unloading()) { + return false; + } + + if (has_evol_metadata()) { + return false; + } + + return true; +} + void* nmethod::operator new(size_t size, int nmethod_size, int comp_level) throw () { return CodeCache::allocate(nmethod_size, CodeCache::get_code_blob_type(comp_level)); } +void* nmethod::operator new(size_t size, int nmethod_size, CodeBlobType code_blob_type) throw () { + return CodeCache::allocate(nmethod_size, code_blob_type); +} + void* nmethod::operator new(size_t size, int nmethod_size, bool allow_NonNMethod_space) throw () { // Try MethodNonProfiled and MethodProfiled. void* return_value = CodeCache::allocate(nmethod_size, CodeBlobType::MethodNonProfiled); @@ -1494,9 +1751,9 @@ nmethod::nmethod( #if INCLUDE_JVMCI _speculations_offset = _scopes_data_offset + align_up(debug_info->data_size(), oopSize); - DEBUG_ONLY( int immutable_data_end_offset = _speculations_offset + align_up(speculations_len, oopSize); ) + DEBUG_ONLY( int immutable_data_end_offset = _speculations_offset + align_up(speculations_len, oopSize) + align_up(ImmutableDataReferencesCounterSize, oopSize); ) #else - DEBUG_ONLY( int immutable_data_end_offset = _scopes_data_offset + align_up(debug_info->data_size(), oopSize); ) + DEBUG_ONLY( int immutable_data_end_offset = _scopes_data_offset + align_up(debug_info->data_size(), oopSize) + align_up(ImmutableDataReferencesCounterSize, oopSize); ) #endif assert(immutable_data_end_offset <= immutable_data_size, "wrong read-only data size: %d > %d", immutable_data_end_offset, immutable_data_size); @@ -1529,6 +1786,7 @@ nmethod::nmethod( memcpy(speculations_begin(), speculations, speculations_len); } #endif + set_immutable_data_references_counter(1); post_init(); @@ -1595,6 +1853,40 @@ void nmethod::log_new_nmethod() const { } } + +void nmethod::log_relocated_nmethod(nmethod* original) const { + if (LogCompilation && xtty != nullptr) { + ttyLocker ttyl; + xtty->begin_elem("relocated nmethod"); + log_identity(xtty); + xtty->print(" entry='" INTPTR_FORMAT "' size='%d'", p2i(code_begin()), size()); + + const char* original_code_heap_name = CodeCache::get_code_heap_name(CodeCache::get_code_blob_type(original)); + xtty->print(" original_address='" INTPTR_FORMAT "'", p2i(original)); + xtty->print(" original_code_heap='%s'", original_code_heap_name); + + const char* new_code_heap_name = CodeCache::get_code_heap_name(CodeCache::get_code_blob_type(this)); + xtty->print(" new_address='" INTPTR_FORMAT "'", p2i(this)); + xtty->print(" new_code_heap='%s'", new_code_heap_name); + + LOG_OFFSET(xtty, relocation); + LOG_OFFSET(xtty, consts); + LOG_OFFSET(xtty, insts); + LOG_OFFSET(xtty, stub); + LOG_OFFSET(xtty, scopes_data); + LOG_OFFSET(xtty, scopes_pcs); + LOG_OFFSET(xtty, dependencies); + LOG_OFFSET(xtty, handler_table); + LOG_OFFSET(xtty, nul_chk_table); + LOG_OFFSET(xtty, oops); + LOG_OFFSET(xtty, metadata); + + xtty->method(method()); + xtty->stamp(); + xtty->end_elem(); + } +} + #undef LOG_OFFSET @@ -2127,9 +2419,18 @@ void nmethod::purge(bool unregister_nmethod) { delete[] _compiled_ic_data; if (_immutable_data != blob_end()) { - os::free(_immutable_data); + int reference_count = get_immutable_data_references_counter(); + assert(reference_count > 0, "immutable data has no references"); + + set_immutable_data_references_counter(reference_count - 1); + // Free memory if this is the last nmethod referencing immutable data + if (reference_count == 0) { + os::free(_immutable_data); + } + _immutable_data = blob_end(); // Valid not null address } + if (unregister_nmethod) { Universe::heap()->unregister_nmethod(this); } diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 1e876657098..2332766a47c 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -154,6 +154,7 @@ public: // - Scopes data array // - Scopes pcs array // - JVMCI speculations array +// - Nmethod reference counter #if INCLUDE_JVMCI class FailedSpeculation; @@ -167,6 +168,8 @@ class nmethod : public CodeBlob { friend class JVMCINMethodData; friend class DeoptimizationScope; + #define ImmutableDataReferencesCounterSize ((int)sizeof(int)) + private: // Used to track in which deoptimize handshake this method will be deoptimized. @@ -330,8 +333,11 @@ class nmethod : public CodeBlob { #endif ); + nmethod(const nmethod &nm); + // helper methods void* operator new(size_t size, int nmethod_size, int comp_level) throw(); + void* operator new(size_t size, int nmethod_size, CodeBlobType code_blob_type) throw(); // For method handle intrinsics: Try MethodNonProfiled, MethodProfiled and NonNMethod. // Attention: Only allow NonNMethod space for special nmethods which don't need to be @@ -564,6 +570,12 @@ public: #endif ); + // Relocate the nmethod to the code heap identified by code_blob_type. + // Returns nullptr if the code heap does not have enough space, the + // nmethod is unrelocatable, or the nmethod is invalidated during relocation, + // otherwise the relocated nmethod. The original nmethod will be marked not entrant. + nmethod* relocate(CodeBlobType code_blob_type); + static nmethod* new_native_nmethod(const methodHandle& method, int compile_id, CodeBuffer *code_buffer, @@ -580,6 +592,8 @@ public: bool is_java_method () const { return _method != nullptr && !_method->is_native(); } bool is_osr_method () const { return _entry_bci != InvocationEntryBci; } + bool is_relocatable(); + // Compiler task identification. Note that all OSR methods // are numbered in an independent sequence if CICountOSR is true, // and native method wrappers are also numbered independently if @@ -632,11 +646,13 @@ public: #if INCLUDE_JVMCI address scopes_data_end () const { return _immutable_data + _speculations_offset ; } address speculations_begin () const { return _immutable_data + _speculations_offset ; } - address speculations_end () const { return immutable_data_end(); } + address speculations_end () const { return immutable_data_end() - ImmutableDataReferencesCounterSize ; } #else - address scopes_data_end () const { return immutable_data_end(); } + address scopes_data_end () const { return immutable_data_end() - ImmutableDataReferencesCounterSize ; } #endif + address immutable_data_references_counter_begin () const { return immutable_data_end() - ImmutableDataReferencesCounterSize ; } + // Sizes int immutable_data_size() const { return _immutable_data_size; } int consts_size () const { return int( consts_end () - consts_begin ()); } @@ -946,6 +962,9 @@ public: bool load_reported() const { return _load_reported; } void set_load_reported() { _load_reported = true; } + inline int get_immutable_data_references_counter() { return *((int*)immutable_data_references_counter_begin()); } + inline void set_immutable_data_references_counter(int count) { *((int*)immutable_data_references_counter_begin()) = count; } + public: // ScopeDesc retrieval operation PcDesc* pc_desc_at(address pc) { return find_pc_desc(pc, false); } @@ -1014,6 +1033,7 @@ public: // Logging void log_identity(xmlStream* log) const; void log_new_nmethod() const; + void log_relocated_nmethod(nmethod* original) const; void log_state_change(InvalidationReason invalidation_reason) const; // Prints block-level comments, including nmethod specific block labels: diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp index 8fc22596d01..02a1e5faf16 100644 --- a/src/hotspot/share/code/relocInfo.cpp +++ b/src/hotspot/share/code/relocInfo.cpp @@ -406,11 +406,12 @@ void CallRelocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer pd_set_call_destination(callee); } - #ifdef USE_TRAMPOLINE_STUB_FIX_OWNER void trampoline_stub_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { // Finalize owner destination only for nmethods if (dest->blob() != nullptr) return; + // We either relocate a nmethod residing in CodeCache or just generated code from CodeBuffer + assert(src->blob() == nullptr || nativeCall_at(owner())->raw_destination() == owner(), "destination should be empty"); pd_fix_owner_after_move(); } #endif diff --git a/src/hotspot/share/compiler/oopMap.cpp b/src/hotspot/share/compiler/oopMap.cpp index aa010872975..87467d06400 100644 --- a/src/hotspot/share/compiler/oopMap.cpp +++ b/src/hotspot/share/compiler/oopMap.cpp @@ -862,6 +862,12 @@ ImmutableOopMapSet* ImmutableOopMapSet::build_from(const OopMapSet* oopmap_set) return builder.build(); } +ImmutableOopMapSet* ImmutableOopMapSet::clone() const { + address buffer = NEW_C_HEAP_ARRAY(unsigned char, _size, mtCode); + memcpy(buffer, (address)this, _size); + return (ImmutableOopMapSet*)buffer; +} + void ImmutableOopMapSet::operator delete(void* p) { FREE_C_HEAP_ARRAY(unsigned char, p); } diff --git a/src/hotspot/share/compiler/oopMap.hpp b/src/hotspot/share/compiler/oopMap.hpp index ef8845ac9aa..f7a8cd8496c 100644 --- a/src/hotspot/share/compiler/oopMap.hpp +++ b/src/hotspot/share/compiler/oopMap.hpp @@ -348,6 +348,8 @@ public: static ImmutableOopMapSet* build_from(const OopMapSet* oopmap_set); + ImmutableOopMapSet* clone() const; + int find_slot_for_offset(int pc_offset) const; const ImmutableOopMap* find_map_at_offset(int pc_offset) const; const ImmutableOopMap* find_map_at_slot(int slot, int pc_offset) const; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp b/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp index 83151313f75..b248fab7958 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp @@ -103,7 +103,7 @@ public: } virtual bool is_safe(nmethod* nm) { - if (SafepointSynchronize::is_at_safepoint() || nm->is_unloading()) { + if (SafepointSynchronize::is_at_safepoint() || nm->is_unloading() || (NMethodState_lock->owned_by_self() && nm->is_not_installed())) { return true; } diff --git a/src/hotspot/share/gc/z/zUnload.cpp b/src/hotspot/share/gc/z/zUnload.cpp index c8b32385fcd..5c50b3077dd 100644 --- a/src/hotspot/share/gc/z/zUnload.cpp +++ b/src/hotspot/share/gc/z/zUnload.cpp @@ -100,7 +100,7 @@ public: } virtual bool is_safe(nmethod* nm) { - if (SafepointSynchronize::is_at_safepoint() || nm->is_unloading()) { + if (SafepointSynchronize::is_at_safepoint() || nm->is_unloading() || (NMethodState_lock->owned_by_self() && nm->is_not_installed())) { return true; } diff --git a/src/hotspot/share/jvmci/jvmciRuntime.hpp b/src/hotspot/share/jvmci/jvmciRuntime.hpp index f4c322e831c..885ff0dbf9b 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.hpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.hpp @@ -137,6 +137,11 @@ public: // Gets the JVMCI name of the nmethod (which may be null). const char* name() { return has_name() ? (char*)(((address) this) + sizeof(JVMCINMethodData)) : nullptr; } + // Returns true if this nmethod has a mirror + bool has_mirror() const { + return _nmethod_mirror_index != -1; + } + // Clears the HotSpotNmethod.address field in the mirror. If nm // is dead, the HotSpotNmethod.entryPoint field is also cleared. void invalidate_nmethod_mirror(nmethod* nm, nmethod::InvalidationReason invalidation_reason); diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index f77b648ba95..1ecd105f218 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -39,6 +39,7 @@ #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" #include "code/codeCache.hpp" +#include "code/compiledIC.hpp" #include "compiler/compilationPolicy.hpp" #include "compiler/compilerOracle.hpp" #include "compiler/directivesParser.hpp" @@ -1548,19 +1549,23 @@ struct CodeBlobStub { name(os::strdup(blob->name())), size(blob->size()), blob_type(static_cast(WhiteBox::get_blob_type(blob))), - address((jlong) blob) { } + address((jlong) blob), + code_begin((jlong) blob->code_begin()), + is_nmethod((jboolean) blob->is_nmethod()) { } ~CodeBlobStub() { os::free((void*) name); } const char* const name; const jint size; const jint blob_type; const jlong address; + const jlong code_begin; + const jboolean is_nmethod; }; static jobjectArray codeBlob2objectArray(JavaThread* thread, JNIEnv* env, CodeBlobStub* cb) { ResourceMark rm; jclass clazz = env->FindClass(vmSymbols::java_lang_Object()->as_C_string()); CHECK_JNI_EXCEPTION_(env, nullptr); - jobjectArray result = env->NewObjectArray(4, clazz, nullptr); + jobjectArray result = env->NewObjectArray(6, clazz, nullptr); jstring name = env->NewStringUTF(cb->name); CHECK_JNI_EXCEPTION_(env, nullptr); @@ -1578,6 +1583,14 @@ static jobjectArray codeBlob2objectArray(JavaThread* thread, JNIEnv* env, CodeBl CHECK_JNI_EXCEPTION_(env, nullptr); env->SetObjectArrayElement(result, 3, obj); + obj = longBox(thread, env, cb->code_begin); + CHECK_JNI_EXCEPTION_(env, nullptr); + env->SetObjectArrayElement(result, 4, obj); + + obj = booleanBox(thread, env, cb->is_nmethod); + CHECK_JNI_EXCEPTION_(env, nullptr); + env->SetObjectArrayElement(result, 5, obj); + return result; } @@ -1627,6 +1640,44 @@ WB_ENTRY(jobjectArray, WB_GetNMethod(JNIEnv* env, jobject o, jobject method, jbo return result; WB_END +WB_ENTRY(void, WB_RelocateNMethodFromMethod(JNIEnv* env, jobject o, jobject method, jint blob_type)) + ResourceMark rm(THREAD); + jmethodID jmid = reflected_method_to_jmid(thread, env, method); + CHECK_JNI_EXCEPTION(env); + methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); + nmethod* code = mh->code(); + if (code != nullptr) { + MutexLocker ml_Compile_lock(Compile_lock); + CompiledICLocker ic_locker(code); + MutexLocker ml_CodeCache_lock(CodeCache_lock, Mutex::_no_safepoint_check_flag); + code->relocate(static_cast(blob_type)); + } +WB_END + +WB_ENTRY(void, WB_RelocateNMethodFromAddr(JNIEnv* env, jobject o, jlong addr, jint blob_type)) + ResourceMark rm(THREAD); + CHECK_JNI_EXCEPTION(env); + void* address = (void*) addr; + + if (address == nullptr) { + return; + } + + MutexLocker ml_Compile_lock(Compile_lock); + MutexLocker ml_CompiledIC_lock(CompiledIC_lock, Mutex::_no_safepoint_check_flag); + MutexLocker ml_CodeCache_lock(CodeCache_lock, Mutex::_no_safepoint_check_flag); + + // Verify that nmethod address is still valid + CodeBlob* blob = CodeCache::find_blob(address); + if (blob != nullptr && blob->is_nmethod()) { + nmethod* code = blob->as_nmethod(); + if (code->is_in_use()) { + CompiledICLocker ic_locker(code); + code->relocate(static_cast(blob_type)); + } + } +WB_END + CodeBlob* WhiteBox::allocate_code_blob(int size, CodeBlobType blob_type) { guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to be enabled"); BufferBlob* blob; @@ -2916,6 +2967,9 @@ static JNINativeMethod methods[] = { {CC"getCPUFeatures", CC"()Ljava/lang/String;", (void*)&WB_GetCPUFeatures }, {CC"getNMethod0", CC"(Ljava/lang/reflect/Executable;Z)[Ljava/lang/Object;", (void*)&WB_GetNMethod }, + {CC"relocateNMethodFromMethod0", CC"(Ljava/lang/reflect/Executable;I)V", + (void*)&WB_RelocateNMethodFromMethod }, + {CC"relocateNMethodFromAddr", CC"(JI)V", (void*)&WB_RelocateNMethodFromAddr }, {CC"allocateCodeBlob", CC"(II)J", (void*)&WB_AllocateCodeBlob }, {CC"freeCodeBlob", CC"(J)V", (void*)&WB_FreeCodeBlob }, {CC"getCodeHeapEntries", CC"(I)[Ljava/lang/Object;",(void*)&WB_GetCodeHeapEntries }, diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index dac01d018bf..513edaf6588 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1565,6 +1565,9 @@ const int ObjectAlignmentInBytes = 8; "Start aggressive sweeping if less than X[%] of the total code cache is free.")\ range(0, 100) \ \ + product(bool, NMethodRelocation, false, EXPERIMENTAL, \ + "Enables use of experimental function nmethod::relocate()") \ + \ /* interpreter debugging */ \ develop(intx, BinarySwitchThreshold, 5, \ "Minimal number of lookupswitch entries for rewriting to binary " \ diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java index c8ba2e8b5af..939b47fdd2a 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java @@ -37,6 +37,7 @@ import sun.jvm.hotspot.utilities.Observer; public class NMethod extends CodeBlob { private static long pcDescSize; + private static long immutableDataReferencesCounterSize; private static AddressField methodField; /** != InvocationEntryBci if this nmethod is an on-stack replacement method */ private static CIntegerField entryBCIField; @@ -78,24 +79,25 @@ public class NMethod extends CodeBlob { private static void initialize(TypeDataBase db) { Type type = db.lookupType("nmethod"); - methodField = type.getAddressField("_method"); - entryBCIField = type.getCIntegerField("_entry_bci"); - osrLinkField = type.getAddressField("_osr_link"); - immutableDataField = type.getAddressField("_immutable_data"); - immutableDataSizeField = type.getCIntegerField("_immutable_data_size"); - exceptionOffsetField = type.getCIntegerField("_exception_offset"); - deoptHandlerOffsetField = type.getCIntegerField("_deopt_handler_offset"); - origPCOffsetField = type.getCIntegerField("_orig_pc_offset"); - stubOffsetField = type.getCIntegerField("_stub_offset"); - scopesPCsOffsetField = type.getCIntegerField("_scopes_pcs_offset"); - scopesDataOffsetField = type.getCIntegerField("_scopes_data_offset"); - handlerTableOffsetField = new CIntField(type.getCIntegerField("_handler_table_offset"), 0); - nulChkTableOffsetField = new CIntField(type.getCIntegerField("_nul_chk_table_offset"), 0); - entryOffsetField = new CIntField(type.getCIntegerField("_entry_offset"), 0); - verifiedEntryOffsetField = new CIntField(type.getCIntegerField("_verified_entry_offset"), 0); - osrEntryPointField = type.getAddressField("_osr_entry_point"); - compLevelField = new CIntField(type.getCIntegerField("_comp_level"), 0); - pcDescSize = db.lookupType("PcDesc").getSize(); + methodField = type.getAddressField("_method"); + entryBCIField = type.getCIntegerField("_entry_bci"); + osrLinkField = type.getAddressField("_osr_link"); + immutableDataField = type.getAddressField("_immutable_data"); + immutableDataSizeField = type.getCIntegerField("_immutable_data_size"); + exceptionOffsetField = type.getCIntegerField("_exception_offset"); + deoptHandlerOffsetField = type.getCIntegerField("_deopt_handler_offset"); + origPCOffsetField = type.getCIntegerField("_orig_pc_offset"); + stubOffsetField = type.getCIntegerField("_stub_offset"); + scopesPCsOffsetField = type.getCIntegerField("_scopes_pcs_offset"); + scopesDataOffsetField = type.getCIntegerField("_scopes_data_offset"); + handlerTableOffsetField = new CIntField(type.getCIntegerField("_handler_table_offset"), 0); + nulChkTableOffsetField = new CIntField(type.getCIntegerField("_nul_chk_table_offset"), 0); + entryOffsetField = new CIntField(type.getCIntegerField("_entry_offset"), 0); + verifiedEntryOffsetField = new CIntField(type.getCIntegerField("_verified_entry_offset"), 0); + osrEntryPointField = type.getAddressField("_osr_entry_point"); + compLevelField = new CIntField(type.getCIntegerField("_comp_level"), 0); + pcDescSize = db.lookupType("PcDesc").getSize(); + immutableDataReferencesCounterSize = VM.getVM().getIntSize(); } public NMethod(Address addr) { @@ -139,7 +141,7 @@ public class NMethod extends CodeBlob { public Address scopesDataBegin() { return immutableDataBegin().addOffsetTo(getScopesDataOffset()); } public Address scopesDataEnd() { return immutableDataBegin().addOffsetTo(getScopesPCsOffset()); } public Address scopesPCsBegin() { return immutableDataBegin().addOffsetTo(getScopesPCsOffset()); } - public Address scopesPCsEnd() { return immutableDataEnd(); } + public Address scopesPCsEnd() { return immutableDataEnd().addOffsetTo(-immutableDataReferencesCounterSize); } public Address metadataBegin() { return mutableDataBegin().addOffsetTo(getRelocationSize()); } public Address metadataEnd() { return mutableDataEnd(); } @@ -169,7 +171,8 @@ public class NMethod extends CodeBlob { scopesPCsSize() + dependenciesSize() + handlerTableSize() + - nulChkTableSize(); + nulChkTableSize() + + (int) immutableDataReferencesCounterSize; } public boolean constantsContains (Address addr) { return constantsBegin() .lessThanOrEqual(addr) && constantsEnd() .greaterThan(addr); } diff --git a/test/hotspot/jtreg/compiler/whitebox/CompilerWhiteBoxTest.java b/test/hotspot/jtreg/compiler/whitebox/CompilerWhiteBoxTest.java index f87292be019..eb0f70af5c4 100644 --- a/test/hotspot/jtreg/compiler/whitebox/CompilerWhiteBoxTest.java +++ b/test/hotspot/jtreg/compiler/whitebox/CompilerWhiteBoxTest.java @@ -221,15 +221,28 @@ public abstract class CompilerWhiteBoxTest { * compilation level. */ protected final void checkNotCompiled(boolean isOsr) { - if (WHITE_BOX.isMethodQueuedForCompilation(method)) { - throw new RuntimeException(method + " must not be in queue"); + checkNotCompiled(method, isOsr); + } + + /** + * Checks, that the specified executable is not (OSR-)compiled. + * + * @param executable The method or constructor to check. + * @param isOsr Check for OSR compilation if true + * @throws RuntimeException if {@linkplain #method} is in compiler queue or + * is compiled, or if {@linkplain #method} has zero + * compilation level. + */ + protected static final void checkNotCompiled(Executable executable, boolean isOsr) { + if (WHITE_BOX.isMethodQueuedForCompilation(executable)) { + throw new RuntimeException(executable + " must not be in queue"); } - if (WHITE_BOX.isMethodCompiled(method, isOsr)) { - throw new RuntimeException(method + " must not be " + + if (WHITE_BOX.isMethodCompiled(executable, isOsr)) { + throw new RuntimeException(executable + " must not be " + (isOsr ? "osr_" : "") + "compiled"); } - if (WHITE_BOX.getMethodCompilationLevel(method, isOsr) != 0) { - throw new RuntimeException(method + (isOsr ? " osr_" : " ") + + if (WHITE_BOX.getMethodCompilationLevel(executable, isOsr) != 0) { + throw new RuntimeException(executable + (isOsr ? " osr_" : " ") + "comp_level must be == 0"); } } @@ -242,21 +255,34 @@ public abstract class CompilerWhiteBoxTest { * has nonzero compilation level */ protected final void checkCompiled() { + checkCompiled(method, testCase.isOsr()); + } + + /** + * Checks, that the specified executable is compiled. + * + * @param executable The method or constructor to check. + * @param isOsr Check for OSR compilation if true + * @throws RuntimeException if {@linkplain #method} isn't in compiler queue + * and isn't compiled, or if {@linkplain #method} + * has nonzero compilation level + */ + protected static final void checkCompiled(Executable executable, boolean isOsr) { final long start = System.currentTimeMillis(); - waitBackgroundCompilation(); - if (WHITE_BOX.isMethodQueuedForCompilation(method)) { + waitBackgroundCompilation(executable); + if (WHITE_BOX.isMethodQueuedForCompilation(executable)) { System.err.printf("Warning: %s is still in queue after %dms%n", - method, System.currentTimeMillis() - start); + executable, System.currentTimeMillis() - start); return; } - if (!WHITE_BOX.isMethodCompiled(method, testCase.isOsr())) { - throw new RuntimeException(method + " must be " - + (testCase.isOsr() ? "osr_" : "") + "compiled"); + if (!WHITE_BOX.isMethodCompiled(executable, isOsr)) { + throw new RuntimeException(executable + " must be " + + (isOsr ? "osr_" : "") + "compiled"); } - if (WHITE_BOX.getMethodCompilationLevel(method, testCase.isOsr()) + if (WHITE_BOX.getMethodCompilationLevel(executable, isOsr) == 0) { - throw new RuntimeException(method - + (testCase.isOsr() ? " osr_" : " ") + throw new RuntimeException(executable + + (isOsr ? " osr_" : " ") + "comp_level must be != 0"); } } diff --git a/test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java b/test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java new file mode 100644 index 00000000000..25314051fdd --- /dev/null +++ b/test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java @@ -0,0 +1,157 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test id=Serial + * @bug 8316694 + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * @requires vm.opt.DeoptimizeALot != true + * @requires vm.gc.Serial + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseSerialGC + * -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.DeoptimizeRelocatedNMethod + */ + +/* + * @test id=Parallel + * @bug 8316694 + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * @requires vm.opt.DeoptimizeALot != true + * @requires vm.gc.Parallel + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseParallelGC + * -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.DeoptimizeRelocatedNMethod + */ + +/* + * @test id=G1 + * @bug 8316694 + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * @requires vm.opt.DeoptimizeALot != true + * @requires vm.gc.G1 + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseG1GC + * -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.DeoptimizeRelocatedNMethod + */ + +/* + * @test id=Shenandoah + * @bug 8316694 + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * @requires vm.opt.DeoptimizeALot != true + * @requires vm.gc.Shenandoah + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseShenandoahGC + * -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.DeoptimizeRelocatedNMethod + */ + +/* + * @test id=ZGC + * @bug 8316694 + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * @requires vm.opt.DeoptimizeALot != true + * @requires vm.gc.Z + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseZGC + * -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.DeoptimizeRelocatedNMethod + */ + +package compiler.whitebox; + +import compiler.whitebox.CompilerWhiteBoxTest; +import java.lang.reflect.Method; +import jdk.test.whitebox.WhiteBox; +import jdk.test.whitebox.code.BlobType; +import jdk.test.whitebox.code.NMethod; + +public class DeoptimizeRelocatedNMethod { + + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + public static double FUNCTION_RESULT = 0; + + public static void main(String [] args) throws Exception { + // Get method that will be relocated + Method method = DeoptimizeRelocatedNMethod.class.getMethod("function"); + WHITE_BOX.testSetDontInlineMethod(method, true); + + // Verify not initially compiled + CompilerWhiteBoxTest.checkNotCompiled(method, false); + + // Call function enough to compile + callFunction(); + + // Verify now compiled + CompilerWhiteBoxTest.checkCompiled(method, false); + + // Get newly created nmethod + NMethod origNmethod = NMethod.get(method, false); + + // Relocate nmethod and mark old for cleanup + WHITE_BOX.relocateNMethodFromMethod(method, BlobType.MethodProfiled.id); + + // Trigger GC to clean up old nmethod + WHITE_BOX.fullGC(); + + // Verify function still compiled after old was cleaned up + CompilerWhiteBoxTest.checkCompiled(method, false); + + // Get new nmethod and verify it's actually new + NMethod newNmethod = NMethod.get(method, false); + if (origNmethod.entry_point == newNmethod.entry_point) { + throw new RuntimeException("Did not create new nmethod"); + } + + // Call to verify everything still works + function(); + + // Deoptimized method + WHITE_BOX.deoptimizeMethod(method); + + CompilerWhiteBoxTest.checkNotCompiled(method, false); + + // Call to verify everything still works + function(); + } + + // Call function multiple times to trigger compilation + private static void callFunction() { + for (int i = 0; i < CompilerWhiteBoxTest.THRESHOLD; i++) { + function(); + } + } + + public static void function() { + FUNCTION_RESULT = Math.random(); + } +} diff --git a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java new file mode 100644 index 00000000000..c18a8afa400 --- /dev/null +++ b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java @@ -0,0 +1,146 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test id=Serial + * @bug 8316694 + * @summary test that nmethod::relocate() correctly creates a new nmethod + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @requires vm.opt.DeoptimizeALot != true + * @requires vm.gc.Serial + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache + * -XX:+UseSerialGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.RelocateNMethod + */ + +/* + * @test id=Parallel + * @bug 8316694 + * @summary test that nmethod::relocate() correctly creates a new nmethod + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @requires vm.opt.DeoptimizeALot != true + * @requires vm.gc.Parallel + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache + * -XX:+UseParallelGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.RelocateNMethod + */ + +/* + * @test id=G1 + * @bug 8316694 + * @summary test that nmethod::relocate() correctly creates a new nmethod + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @requires vm.opt.DeoptimizeALot != true + * @requires vm.gc.G1 + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache + * -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.RelocateNMethod + */ + +/* + * @test id=Shenandoah + * @bug 8316694 + * @summary test that nmethod::relocate() correctly creates a new nmethod + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @requires vm.opt.DeoptimizeALot != true + * @requires vm.gc.Shenandoah + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache + * -XX:+UseShenandoahGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.RelocateNMethod + */ + +/* + * @test id=ZGC + * @bug 8316694 + * @summary test that nmethod::relocate() correctly creates a new nmethod + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @requires vm.opt.DeoptimizeALot != true + * @requires vm.gc.Z + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache + * -XX:+UseZGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.RelocateNMethod + */ + +package compiler.whitebox; + +import java.lang.reflect.Method; +import jdk.test.whitebox.code.BlobType; +import jdk.test.whitebox.code.NMethod; +import jdk.test.whitebox.WhiteBox; + +import compiler.whitebox.CompilerWhiteBoxTest; + +public class RelocateNMethod extends CompilerWhiteBoxTest { + + public static void main(String[] args) throws Exception { + CompilerWhiteBoxTest.main(RelocateNMethod::new, new String[] {"CONSTRUCTOR_TEST", "METHOD_TEST", "STATIC_TEST"}); + } + + private RelocateNMethod(TestCase testCase) { + super(testCase); + // to prevent inlining of #method + WHITE_BOX.testSetDontInlineMethod(method, true); + } + + @Override + protected void test() throws Exception { + checkNotCompiled(); + + compile(); + + checkCompiled(); + NMethod origNmethod = NMethod.get(method, false); + + WHITE_BOX.relocateNMethodFromMethod(method, BlobType.MethodProfiled.id); + + WHITE_BOX.fullGC(); + + checkCompiled(); + + NMethod newNmethod = NMethod.get(method, false); + if (origNmethod.entry_point == newNmethod.entry_point) { + throw new RuntimeException("Did not create new nmethod"); + } + } +} diff --git a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java new file mode 100644 index 00000000000..49be3eff8c2 --- /dev/null +++ b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java @@ -0,0 +1,261 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test id=SerialC1 + * @bug 8316694 + * @requires vm.debug == true + * @requires vm.gc.Serial + * @summary test that relocated nmethod is correctly deoptimized + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseSerialGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation + * compiler.whitebox.RelocateNMethodMultiplePaths + */ + +/* + * @test id=SerialC2 + * @bug 8316694 + * @requires vm.debug == true + * @requires vm.gc.Serial + * @summary test that relocated nmethod is correctly deoptimized + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+TieredCompilation + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseSerialGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation + * compiler.whitebox.RelocateNMethodMultiplePaths + */ + +/* + * @test id=ParallelC1 + * @bug 8316694 + * @requires vm.debug == true + * @requires vm.gc.Parallel + * @summary test that relocated nmethod is correctly deoptimized + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseParallelGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation + * compiler.whitebox.RelocateNMethodMultiplePaths + */ + +/* + * @test id=ParallelC2 + * @bug 8316694 + * @requires vm.debug == true + * @requires vm.gc.Parallel + * @summary test that relocated nmethod is correctly deoptimized + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+TieredCompilation + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseParallelGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation + * compiler.whitebox.RelocateNMethodMultiplePaths + */ + +/* + * @test id=G1C1 + * @bug 8316694 + * @requires vm.debug == true + * @requires vm.gc.G1 + * @summary test that relocated nmethod is correctly deoptimized + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation + * compiler.whitebox.RelocateNMethodMultiplePaths + */ + +/* + * @test id=G1C2 + * @bug 8316694 + * @requires vm.debug == true + * @requires vm.gc.G1 + * @summary test that relocated nmethod is correctly deoptimized + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+TieredCompilation + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation + * compiler.whitebox.RelocateNMethodMultiplePaths + */ + +/* + * @test id=ShenandoahC1 + * @bug 8316694 + * @requires vm.debug == true + * @requires vm.gc.Shenandoah + * @summary test that relocated nmethod is correctly deoptimized + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseShenandoahGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation + * compiler.whitebox.RelocateNMethodMultiplePaths + */ + +/* + * @test id=ShenandoahC2 + * @bug 8316694 + * @requires vm.debug == true + * @requires vm.gc.Shenandoah + * @summary test that relocated nmethod is correctly deoptimized + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+TieredCompilation + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseShenandoahGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation + * compiler.whitebox.RelocateNMethodMultiplePaths + */ + +/* + * @test id=ZGCC1 + * @bug 8316694 + * @requires vm.debug == true + * @requires vm.gc.Z + * @summary test that relocated nmethod is correctly deoptimized + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseZGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation + * compiler.whitebox.RelocateNMethodMultiplePaths + */ + +/* + * @test id=ZGCC2 + * @bug 8316694 + * @requires vm.debug == true + * @requires vm.gc.Z + * @summary test that relocated nmethod is correctly deoptimized + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+TieredCompilation + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseZGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation + * compiler.whitebox.RelocateNMethodMultiplePaths + */ + +package compiler.whitebox; + +import compiler.whitebox.CompilerWhiteBoxTest; +import java.lang.reflect.Method; +import jdk.test.whitebox.WhiteBox; +import jdk.test.whitebox.code.BlobType; +import jdk.test.whitebox.code.NMethod; + +public class RelocateNMethodMultiplePaths { + + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + private static final int PATH_ONE_RESULT = 1; + private static final int PATH_TWO_RESULT = 2; + + public static void main(String [] args) throws Exception { + // Get method that will be relocated + Method method = RelocateNMethodMultiplePaths.class.getMethod("function", boolean.class); + WHITE_BOX.testSetDontInlineMethod(method, true); + + // Verify not initially compiled + CompilerWhiteBoxTest.checkNotCompiled(method, false); + + // Call function enough to compile + callFunction(true); + + // Verify now compiled + CompilerWhiteBoxTest.checkCompiled(method, false); + + // Get newly created nmethod + NMethod origNmethod = NMethod.get(method, false); + + // Relocate nmethod and mark old for cleanup + WHITE_BOX.relocateNMethodFromMethod(method, BlobType.MethodNonProfiled.id); + + // Trigger GC to clean up old nmethod + WHITE_BOX.fullGC(); + + // Verify function still compiled after old was cleaned up + CompilerWhiteBoxTest.checkCompiled(method, false); + + // Get new nmethod and verify it's actually new + NMethod newNmethod = NMethod.get(method, false); + if (origNmethod.entry_point == newNmethod.entry_point) { + throw new RuntimeException("Did not create new nmethod"); + } + + // Verify function still produces correct result + if (function(true) != PATH_ONE_RESULT) { + throw new RuntimeException("Relocated function produced incorrect result in path one"); + } + + // Call function again with different path and verify result + if (function(false) != PATH_TWO_RESULT) { + throw new RuntimeException("Relocated function produced incorrect result in path two"); + } + + // Verify function can be correctly deoptimized + WHITE_BOX.deoptimizeMethod(method); + CompilerWhiteBoxTest.checkNotCompiled(method, false); + } + + // Call function multiple times to trigger compilation + private static void callFunction(boolean pathOne) { + for (int i = 0; i < CompilerWhiteBoxTest.THRESHOLD; i++) { + function(pathOne); + } + } + + public static int function(boolean pathOne) { + if (pathOne) { + return PATH_ONE_RESULT; + } else { + return PATH_TWO_RESULT; + } + } +} diff --git a/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java b/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java new file mode 100644 index 00000000000..3b397f48306 --- /dev/null +++ b/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java @@ -0,0 +1,239 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test StressNMethodRelocation + * @summary Call and relocate methods concurrently + * @library /test/lib / + * @modules java.base/jdk.internal.misc + * java.management + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+SegmentedCodeCache -XX:+UnlockExperimentalVMOptions + * -XX:+NMethodRelocation compiler.whitebox.StressNMethodRelocation + */ + +package compiler.whitebox; + +import jdk.test.whitebox.WhiteBox; +import jdk.test.whitebox.code.BlobType; +import jdk.test.whitebox.code.CodeBlob; +import jdk.test.whitebox.code.NMethod; + +import jdk.test.lib.compiler.InMemoryJavaCompiler; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.Random; + +public class StressNMethodRelocation { + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + private static final int C2_LEVEL = 4; + private static final int ACTIVE_METHODS = 1024; + + private static TestMethod[] methods; + private static byte[] num1; + private static byte[] num2; + + private static long DURATION = 60_000; + + public static void main(String[] args) throws Exception { + // Initialize defaults + initNums(); + + // Generate compiled code + methods = new TestMethod[ACTIVE_METHODS]; + generateCode(methods); + + // Create thread that runs compiled methods + RunMethods runMethods = new RunMethods(); + Thread runMethodsThread = new Thread(runMethods); + + // Create thread that relocates compiled methods + RelocateNMethods relocate = new RelocateNMethods(); + Thread relocateThread = new Thread(relocate); + + // Start theads + runMethodsThread.start(); + relocateThread.start(); + + // Wait for threads to finish + runMethodsThread.join(); + relocateThread.join(); + } + + private static byte[] genNum(Random random, int digitCount) { + byte[] num = new byte[digitCount]; + int d; + do { + d = random.nextInt(10); + } while (d == 0); + + num[0] = (byte)d; + for (int i = 1; i < digitCount; ++i) { + num[i] = (byte)random.nextInt(10); + } + return num; + } + + private static void initNums() { + final long seed = 8374592837465123L; + Random random = new Random(seed); + + final int digitCount = 40; + num1 = genNum(random, digitCount); + num2 = genNum(random, digitCount); + } + + private static void generateCode(TestMethod[] m) throws Exception { + byte[] result = new byte[num1.length + 1]; + + for (int i = 0; i < ACTIVE_METHODS; ++i) { + m[i] = new TestMethod(); + m[i].profile(num1, num2, result); + m[i].compileWithC2(); + } + } + + private static final class TestMethod { + private static final String CLASS_NAME = "A"; + private static final String METHOD_TO_COMPILE = "sum"; + private static final String JAVA_CODE = """ + public class A { + + public static void sum(byte[] n1, byte[] n2, byte[] out) { + final int digitCount = n1.length; + int carry = 0; + for (int i = digitCount - 1; i >= 0; --i) { + int sum = n1[i] + n2[i] + carry; + out[i] = (byte)(sum % 10); + carry = sum / 10; + } + if (carry != 0) { + for (int i = digitCount; i > 0; --i) { + out[i] = out[i - 1]; + } + out[0] = (byte)carry; + } + } + }"""; + + private static final byte[] BYTE_CODE; + + static { + BYTE_CODE = InMemoryJavaCompiler.compile(CLASS_NAME, JAVA_CODE); + } + + private final Method method; + + private static ClassLoader createClassLoaderFor() { + return new ClassLoader() { + @Override + public Class loadClass(String name) throws ClassNotFoundException { + if (!name.equals(CLASS_NAME)) { + return super.loadClass(name); + } + + return defineClass(name, BYTE_CODE, 0, BYTE_CODE.length); + } + }; + } + + public TestMethod() throws Exception { + var cl = createClassLoaderFor().loadClass(CLASS_NAME); + method = cl.getMethod(METHOD_TO_COMPILE, byte[].class, byte[].class, byte[].class); + WHITE_BOX.testSetDontInlineMethod(method, true); + } + + public void profile(byte[] num1, byte[] num2, byte[] result) throws Exception { + method.invoke(null, num1, num2, result); + WHITE_BOX.markMethodProfiled(method); + } + + public void invoke(byte[] num1, byte[] num2, byte[] result) throws Exception { + method.invoke(null, num1, num2, result); + } + + public void compileWithC2() throws Exception { + WHITE_BOX.enqueueMethodForCompilation(method, C2_LEVEL); + while (WHITE_BOX.isMethodQueuedForCompilation(method)) { + Thread.onSpinWait(); + } + if (WHITE_BOX.getMethodCompilationLevel(method) != C2_LEVEL) { + throw new IllegalStateException("Method " + method + " is not compiled by C2."); + } + } + } + + private static final class RelocateNMethods implements Runnable { + public RelocateNMethods() {} + + // Move nmethod back and forth between NonProfiled and Profiled code heaps + public void run() { + long startTime = System.currentTimeMillis(); + while (System.currentTimeMillis() - startTime < DURATION) { + // Relocate NonProfiled to Profiled + CodeBlob[] nonProfiledBlobs = CodeBlob.getCodeBlobs(BlobType.MethodNonProfiled); + for (CodeBlob blob : nonProfiledBlobs) { + if (blob.isNMethod) { + WHITE_BOX.relocateNMethodFromAddr(blob.address, BlobType.MethodProfiled.id); + } + } + + // Relocate Profiled to NonProfiled + CodeBlob[] profiledBlobs = CodeBlob.getCodeBlobs(BlobType.MethodProfiled); + for (CodeBlob blob : nonProfiledBlobs) { + if (blob.isNMethod) { + WHITE_BOX.relocateNMethodFromAddr(blob.address, BlobType.MethodNonProfiled.id); + } + } + } + } + } + + private static final class RunMethods implements Runnable { + public RunMethods() {} + + public void run() { + try { + long startTime = System.currentTimeMillis(); + while (System.currentTimeMillis() - startTime < DURATION) { + callMethods(); + } + } catch (Exception e) { + throw new RuntimeException(e.getMessage()); + } + } + + private void callMethods() throws Exception { + for (var m : methods) { + byte[] result = new byte[num1.length + 1]; + m.invoke(num1, num2, result); + } + } + } + +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java b/test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java new file mode 100644 index 00000000000..b12e2c3455c --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java @@ -0,0 +1,178 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * + * @bug 8316694 + * @summary Verify that nmethod relocation posts the correct JVMTI events + * @requires vm.jvmti + * @library /test/lib /test/hotspot/jtreg + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm/native NMethodRelocationTest + */ + +import static compiler.whitebox.CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION; + +import java.lang.reflect.Executable; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import jdk.test.lib.Asserts; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.whitebox.WhiteBox; +import jdk.test.whitebox.code.BlobType; +import jdk.test.whitebox.code.NMethod; + + +public class NMethodRelocationTest { + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + "-agentlib:NMethodRelocationTest", + "--enable-native-access=ALL-UNNAMED", + "-Xbootclasspath/a:.", + "-XX:+UseSerialGC", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + "-XX:+SegmentedCodeCache", + "-XX:-TieredCompilation", + "-XX:+UnlockExperimentalVMOptions", + "-XX:+NMethodRelocation", + "DoWork"); + + OutputAnalyzer oa = new OutputAnalyzer(pb.start()); + String output = oa.getOutput(); + if (oa.getExitValue() != 0) { + System.err.println(oa.getOutput()); + throw new RuntimeException("Non-zero exit code returned from the test"); + } + Asserts.assertTrue(oa.getExitValue() == 0); + + Pattern pattern = Pattern.compile("(?m)^Relocated nmethod from (0x[0-9a-f]{16}) to (0x[0-9a-f]{16})$"); + Matcher matcher = pattern.matcher(output); + + if (matcher.find()) { + String fromAddr = matcher.group(1); + String toAddr = matcher.group(2); + + // Confirm events sent for both original and relocated nmethod + oa.shouldContain(": name: compiledMethod, code: " + fromAddr); + oa.shouldContain(": name: compiledMethod, code: " + toAddr); + oa.shouldContain(": name: compiledMethod, code: " + fromAddr); + oa.shouldContain(": name: compiledMethod, code: " + toAddr); + } else { + System.err.println(oa.getOutput()); + throw new RuntimeException("Unable to find relocation information"); + } + } +} + +class DoWork { + + protected static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + /** Load native library if required. */ + static { + try { + System.loadLibrary("NMethodRelocationTest"); + } catch (UnsatisfiedLinkError ule) { + System.err.println("Could not load NMethodRelocationTest library"); + System.err.println("java.library.path: " + + System.getProperty("java.library.path")); + throw ule; + } + } + + /** + * Returns value of VM option. + * + * @param name option's name + * @return value of option or {@code null}, if option doesn't exist + * @throws NullPointerException if name is null + */ + protected static String getVMOption(String name) { + Objects.requireNonNull(name); + return Objects.toString(WHITE_BOX.getVMFlag(name), null); + } + + /** + * Returns value of VM option or default value. + * + * @param name option's name + * @param defaultValue default value + * @return value of option or {@code defaultValue}, if option doesn't exist + * @throws NullPointerException if name is null + * @see #getVMOption(String) + */ + protected static String getVMOption(String name, String defaultValue) { + String result = getVMOption(name); + return result == null ? defaultValue : result; + } + + public static void main(String argv[]) throws Exception { + run(); + } + + public static void run() throws Exception { + Executable method = DoWork.class.getDeclaredMethod("compiledMethod"); + WHITE_BOX.testSetDontInlineMethod(method, true); + + WHITE_BOX.enqueueMethodForCompilation(method, COMP_LEVEL_FULL_OPTIMIZATION); + while (WHITE_BOX.isMethodQueuedForCompilation(method)) { + Thread.onSpinWait(); + } + + NMethod originalNMethod = NMethod.get(method, false); + if (originalNMethod == null) { + throw new AssertionError("Could not find original nmethod"); + } + + WHITE_BOX.relocateNMethodFromMethod(method, BlobType.MethodNonProfiled.id); + + NMethod relocatedNMethod = NMethod.get(method, false); + if (relocatedNMethod == null) { + throw new AssertionError("Could not find relocated nmethod"); + } + + if (originalNMethod.address == relocatedNMethod.address) { + throw new AssertionError("Relocated nmethod same as original"); + } + + WHITE_BOX.deoptimizeAll(); + + WHITE_BOX.fullGC(); + WHITE_BOX.fullGC(); + + WHITE_BOX.lockCompilation(); + + System.out.printf("Relocated nmethod from 0x%016x to 0x%016x%n", originalNMethod.code_begin, relocatedNMethod.code_begin); + System.out.flush(); + } + + public static long compiledMethod() { + return 0; + } +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/libNMethodRelocationTest.cpp b/test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/libNMethodRelocationTest.cpp new file mode 100644 index 00000000000..41ba6b10608 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/libNMethodRelocationTest.cpp @@ -0,0 +1,114 @@ +/* + * 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. + */ + +#include +#include +#include +#include + +/** + * Callback for COMPILED_METHOD_LOAD event. + */ +JNIEXPORT void JNICALL +callbackCompiledMethodLoad(jvmtiEnv* jvmti, jmethodID method, + jint code_size, const void* code_addr, + jint map_length, const jvmtiAddrLocationMap* map, + const void* compile_info) { + char* name = nullptr; + char* sig = nullptr; + + if (jvmti->GetMethodName(method, &name, &sig, nullptr) != JVMTI_ERROR_NONE) { + printf(" [Could not retrieve method name]\n"); + fflush(stdout); + return; + } + + printf(": name: %s, code: 0x%016" PRIxPTR "\n", + name, (uintptr_t)code_addr); + fflush(stdout); +} + +/** + * Callback for COMPILED_METHOD_UNLOAD event. + */ +JNIEXPORT void JNICALL +callbackCompiledMethodUnload(jvmtiEnv* jvmti, jmethodID method, + const void* code_addr) { + char* name = nullptr; + char* sig = nullptr; + + if (jvmti->GetMethodName(method, &name, &sig, nullptr) != JVMTI_ERROR_NONE) { + printf(" [Could not retrieve method name]\n"); + fflush(stdout); + return; + } + printf(": name: %s, code: 0x%016" PRIxPTR "\n", + name, (uintptr_t)code_addr); + fflush(stdout); +} + +JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { + jvmtiEnv* jvmti = nullptr; + jvmtiError error; + + if (jvm->GetEnv((void **)&jvmti, JVMTI_VERSION_1_0) != JNI_OK) { + printf("Unable to access JVMTI!\n"); + return JNI_ERR; + } + + // Add required capabilities + jvmtiCapabilities caps; + memset(&caps, 0, sizeof(caps)); + caps.can_generate_compiled_method_load_events = 1; + error = jvmti->AddCapabilities(&caps); + if (error != JVMTI_ERROR_NONE) { + printf("ERROR: Unable to add capabilities, error=%d\n", error); + return JNI_ERR; + } + + // Set event callbacks + jvmtiEventCallbacks eventCallbacks; + memset(&eventCallbacks, 0, sizeof(eventCallbacks)); + eventCallbacks.CompiledMethodLoad = callbackCompiledMethodLoad; + eventCallbacks.CompiledMethodUnload = callbackCompiledMethodUnload; + error = jvmti->SetEventCallbacks(&eventCallbacks, sizeof(eventCallbacks)); + if (error != JVMTI_ERROR_NONE) { + printf("ERROR: Unable to set event callbacks, error=%d\n", error); + return JNI_ERR; + } + + // Enable events + error = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_LOAD, nullptr); + if (error != JVMTI_ERROR_NONE) { + printf("ERROR: Unable to enable COMPILED_METHOD_LOAD event, error=%d\n", error); + return JNI_ERR; + } + + error = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_UNLOAD, nullptr); + if (error != JVMTI_ERROR_NONE) { + printf("ERROR: Unable to enable COMPILED_METHOD_UNLOAD event, error=%d\n", error); + return JNI_ERR; + } + + return JNI_OK; +} diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index 5adb7bf5127..669ec48b619 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -490,6 +490,12 @@ public class WhiteBox { Objects.requireNonNull(method); return getNMethod0(method, isOsr); } + private native void relocateNMethodFromMethod0(Executable method, int type); + public void relocateNMethodFromMethod(Executable method, int type) { + Objects.requireNonNull(method); + relocateNMethodFromMethod0(method, type); + } + public native void relocateNMethodFromAddr(long address, int type); public native long allocateCodeBlob(int size, int type); public long allocateCodeBlob(long size, int type) { int intSize = (int) size; diff --git a/test/lib/jdk/test/whitebox/code/CodeBlob.java b/test/lib/jdk/test/whitebox/code/CodeBlob.java index c6c23fdff0c..fd95b5a7e7d 100644 --- a/test/lib/jdk/test/whitebox/code/CodeBlob.java +++ b/test/lib/jdk/test/whitebox/code/CodeBlob.java @@ -46,18 +46,22 @@ public class CodeBlob { return new CodeBlob(obj); } protected CodeBlob(Object[] obj) { - assert obj.length == 4; + assert obj.length == 6; name = (String) obj[0]; size = (Integer) obj[1]; int blob_type_index = (Integer) obj[2]; code_blob_type = BlobType.values()[blob_type_index]; assert code_blob_type.id == (Integer) obj[2]; address = (Long) obj[3]; + code_begin = (Long) obj[4]; + isNMethod = (Boolean) obj[5]; } public final String name; public final int size; public final BlobType code_blob_type; public final long address; + public final long code_begin; + public final boolean isNMethod; @Override public String toString() { return "CodeBlob{" @@ -65,6 +69,7 @@ public class CodeBlob { + ", size=" + size + ", code_blob_type=" + code_blob_type + ", address=" + address + + ", code_begin=" + code_begin + '}'; } } From 5d9f94e05e1527745271d0167a418741607619e2 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Sun, 5 Oct 2025 16:20:53 +0000 Subject: [PATCH 023/160] 8369152: Problem list new tests from JDK-8316694 Reviewed-by: jpai, dholmes, serb --- test/hotspot/jtreg/ProblemList.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index d061236c957..f02ba70ba87 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -79,6 +79,17 @@ compiler/c2/TestVerifyConstraintCasts.java 8355574 generic-all compiler/c2/aarch64/TestStaticCallStub.java 8359963 linux-aarch64,macosx-aarch64 +compiler/whitebox/DeoptimizeRelocatedNMethod.java#G1 8369147 generic-all +compiler/whitebox/DeoptimizeRelocatedNMethod.java#Parallel 8369147 generic-all +compiler/whitebox/DeoptimizeRelocatedNMethod.java#Serial 8369147 generic-all +compiler/whitebox/DeoptimizeRelocatedNMethod.java#ZGC 8369147 generic-all +compiler/whitebox/RelocateNMethod.java#G1 8369147 generic-all +compiler/whitebox/RelocateNMethod.java#Parallel 8369147 generic-all +compiler/whitebox/RelocateNMethod.java#Serial 8369147 generic-all +compiler/whitebox/RelocateNMethod.java#ZGC 8369147 generic-all +compiler/whitebox/StressNMethodRelocation.java 8369147,8369148,8369149 generic-all +serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java 8369150,8369151 generic-all + ############################################################################# # :hotspot_gc From ba7bf43c76c94bea85dbbd865794184b7ee0cc86 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Sun, 5 Oct 2025 23:55:53 +0000 Subject: [PATCH 024/160] 8365290: [perf] x86 ArrayFill intrinsic generates SPLIT_STORE for unaligned arrays Reviewed-by: sviswanathan, vpaprotski, kvn --- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 47 ++++++++++++++++++---- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index c1319b2ef7f..77ee71c0382 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -5847,7 +5847,7 @@ void MacroAssembler::generate_fill(BasicType t, bool aligned, orl(value, rtmp); } - cmpptr(count, 2< Date: Mon, 6 Oct 2025 06:17:48 +0000 Subject: [PATCH 025/160] 8355354: C2 crashed: assert(_callee == nullptr || _callee == m) failed: repeated inline attempt with different callee Reviewed-by: vlivanov, dlong --- src/hotspot/share/opto/callGenerator.cpp | 4 ++ src/hotspot/share/opto/callGenerator.hpp | 1 + src/hotspot/share/opto/callnode.cpp | 52 +++++++++++++----------- src/hotspot/share/opto/compile.cpp | 6 +++ src/hotspot/share/opto/compile.hpp | 3 +- 5 files changed, 41 insertions(+), 25 deletions(-) diff --git a/src/hotspot/share/opto/callGenerator.cpp b/src/hotspot/share/opto/callGenerator.cpp index 03225044f5e..483cb731103 100644 --- a/src/hotspot/share/opto/callGenerator.cpp +++ b/src/hotspot/share/opto/callGenerator.cpp @@ -465,6 +465,10 @@ class LateInlineVirtualCallGenerator : public VirtualCallGenerator { // Convert the CallDynamicJava into an inline virtual void do_late_inline(); + virtual ciMethod* callee_method() { + return _callee; + } + virtual void set_callee_method(ciMethod* m) { assert(_callee == nullptr || _callee == m, "repeated inline attempt with different callee"); _callee = m; diff --git a/src/hotspot/share/opto/callGenerator.hpp b/src/hotspot/share/opto/callGenerator.hpp index 82b195e0c76..e24ea5e5356 100644 --- a/src/hotspot/share/opto/callGenerator.hpp +++ b/src/hotspot/share/opto/callGenerator.hpp @@ -88,6 +88,7 @@ class CallGenerator : public ArenaObj { virtual void set_unique_id(jlong id) { fatal("unique id only for late inlines"); }; virtual jlong unique_id() const { fatal("unique id only for late inlines"); return 0; }; + virtual ciMethod* callee_method() { ShouldNotReachHere(); } virtual void set_callee_method(ciMethod* callee) { ShouldNotReachHere(); } // Note: It is possible for a CG to be both inline and virtual. diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp index 995208ba24f..ef1ebc5cef9 100644 --- a/src/hotspot/share/opto/callnode.cpp +++ b/src/hotspot/share/opto/callnode.cpp @@ -1228,33 +1228,37 @@ Node* CallDynamicJavaNode::Ideal(PhaseGVN* phase, bool can_reshape) { assert(IncrementalInlineVirtual, "required"); assert(cg->call_node() == this, "mismatch"); - // Recover symbolic info for method resolution. - ciMethod* caller = jvms()->method(); - ciBytecodeStream iter(caller); - iter.force_bci(jvms()->bci()); + if (cg->callee_method() == nullptr) { + // Recover symbolic info for method resolution. + ciMethod* caller = jvms()->method(); + ciBytecodeStream iter(caller); + iter.force_bci(jvms()->bci()); - bool not_used1; - ciSignature* not_used2; - ciMethod* orig_callee = iter.get_method(not_used1, ¬_used2); // callee in the bytecode - ciKlass* holder = iter.get_declared_method_holder(); - if (orig_callee->is_method_handle_intrinsic()) { - assert(_override_symbolic_info, "required"); - orig_callee = method(); - holder = method()->holder(); + bool not_used1; + ciSignature* not_used2; + ciMethod* orig_callee = iter.get_method(not_used1, ¬_used2); // callee in the bytecode + ciKlass* holder = iter.get_declared_method_holder(); + if (orig_callee->is_method_handle_intrinsic()) { + assert(_override_symbolic_info, "required"); + orig_callee = method(); + holder = method()->holder(); + } + + ciInstanceKlass* klass = ciEnv::get_instance_klass_for_declared_method_holder(holder); + + Node* receiver_node = in(TypeFunc::Parms); + const TypeOopPtr* receiver_type = phase->type(receiver_node)->isa_oopptr(); + + int not_used3; + bool call_does_dispatch; + ciMethod* callee = phase->C->optimize_virtual_call(caller, klass, holder, orig_callee, receiver_type, true /*is_virtual*/, + call_does_dispatch, not_used3); // out-parameters + if (!call_does_dispatch) { + cg->set_callee_method(callee); + } } - - ciInstanceKlass* klass = ciEnv::get_instance_klass_for_declared_method_holder(holder); - - Node* receiver_node = in(TypeFunc::Parms); - const TypeOopPtr* receiver_type = phase->type(receiver_node)->isa_oopptr(); - - int not_used3; - bool call_does_dispatch; - ciMethod* callee = phase->C->optimize_virtual_call(caller, klass, holder, orig_callee, receiver_type, true /*is_virtual*/, - call_does_dispatch, not_used3); // out-parameters - if (!call_does_dispatch) { + if (cg->callee_method() != nullptr) { // Register for late inlining. - cg->set_callee_method(callee); register_for_late_inline(); // MH late inlining prepends to the list, so do the same } } else { diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 47de5acc2f2..7f63efe9e5e 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -2104,6 +2104,12 @@ bool Compile::inline_incrementally_one() { bool is_scheduled_for_igvn_before = C->igvn_worklist()->member(cg->call_node()); bool does_dispatch = cg->is_virtual_late_inline() || cg->is_mh_late_inline(); if (inlining_incrementally() || does_dispatch) { // a call can be either inlined or strength-reduced to a direct call + if (should_stress_inlining()) { + // randomly add repeated inline attempt if stress-inlining + cg->call_node()->set_generator(cg); + C->igvn_worklist()->push(cg->call_node()); + continue; + } cg->do_late_inline(); assert(_late_inlines.at(i) == cg, "no insertions before current position allowed"); if (failing()) { diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index 05c5f22dad9..a68da644d82 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -1094,7 +1094,8 @@ public: bool inline_incrementally_one(); void inline_incrementally_cleanup(PhaseIterGVN& igvn); void inline_incrementally(PhaseIterGVN& igvn); - bool should_delay_inlining() { return AlwaysIncrementalInline || (StressIncrementalInlining && (random() % 2) == 0); } + bool should_stress_inlining() { return StressIncrementalInlining && (random() % 2) == 0; } + bool should_delay_inlining() { return AlwaysIncrementalInline || should_stress_inlining(); } void inline_string_calls(bool parse_time); void inline_boxing_calls(PhaseIterGVN& igvn); bool optimize_loops(PhaseIterGVN& igvn, LoopOptsMode mode); From 069c569a710f50bc715f523c6c4c7aa087694af6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Mon, 6 Oct 2025 07:48:45 +0000 Subject: [PATCH 026/160] 8368097: [asan] heap-buffer-overflow reported in ClassFileParser::skip_over_field_signature Reviewed-by: dholmes, mbaesken --- src/hotspot/share/classfile/classFileParser.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index fddd9df726b..87f2da91288 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -4678,11 +4678,15 @@ const char* ClassFileParser::skip_over_field_signature(const char* signature, return signature + 1; case JVM_SIGNATURE_CLASS: { if (_major_version < JAVA_1_5_VERSION) { + signature++; + length--; // Skip over the class name if one is there - const char* const p = skip_over_field_name(signature + 1, true, --length); - + const char* const p = skip_over_field_name(signature, true, length); + assert(p == nullptr || p > signature, "must parse one character at least"); // The next character better be a semicolon - if (p && (p - signature) > 1 && p[0] == JVM_SIGNATURE_ENDCLASS) { + if (p != nullptr && // Parse of field name succeeded. + p - signature < static_cast(length) && // There is at least one character left to parse. + p[0] == JVM_SIGNATURE_ENDCLASS) { return p + 1; } } From e6781fd9497723a7baab38d6bfb958ba1b1c24ff Mon Sep 17 00:00:00 2001 From: Fredrik Bredberg Date: Mon, 6 Oct 2025 08:10:11 +0000 Subject: [PATCH 027/160] 8367601: Remove held_monitor_count Reviewed-by: mdoerr, pchilanomate, fyang --- .../cpu/aarch64/globalDefinitions_aarch64.hpp | 2 - .../cpu/aarch64/macroAssembler_aarch64.cpp | 32 ---------- .../cpu/aarch64/macroAssembler_aarch64.hpp | 3 - .../cpu/aarch64/sharedRuntime_aarch64.cpp | 47 --------------- src/hotspot/cpu/ppc/globalDefinitions_ppc.hpp | 4 +- src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp | 58 +------------------ .../cpu/riscv/globalDefinitions_riscv.hpp | 4 +- .../cpu/riscv/macroAssembler_riscv.cpp | 30 ---------- .../cpu/riscv/macroAssembler_riscv.hpp | 5 +- src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp | 47 --------------- src/hotspot/cpu/x86/globalDefinitions_x86.hpp | 4 +- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 8 --- src/hotspot/cpu/x86/macroAssembler_x86.hpp | 3 - src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp | 46 --------------- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 1 - src/hotspot/share/runtime/continuation.hpp | 9 ++- .../share/runtime/continuationEntry.cpp | 1 - .../share/runtime/continuationEntry.hpp | 7 --- .../share/runtime/continuationFreezeThaw.cpp | 14 +---- src/hotspot/share/runtime/javaThread.cpp | 43 -------------- src/hotspot/share/runtime/javaThread.hpp | 12 ---- src/hotspot/share/runtime/objectMonitor.cpp | 1 - src/hotspot/share/runtime/sharedRuntime.cpp | 15 ----- src/hotspot/share/runtime/sharedRuntime.hpp | 3 - src/hotspot/share/runtime/synchronizer.cpp | 8 +-- .../share/runtime/synchronizer.inline.hpp | 2 - .../classes/jdk/internal/vm/Continuation.java | 9 +-- 27 files changed, 17 insertions(+), 401 deletions(-) diff --git a/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp b/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp index 948ba97aa22..1e788590b64 100644 --- a/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp @@ -35,8 +35,6 @@ const bool CCallingConventionRequiresIntsAsLongs = false; #define SUPPORTS_NATIVE_CX8 -#define SUPPORT_MONITOR_COUNT - // Aarch64 was not originally defined to be multi-copy-atomic, but now // is. See: "Simplifying ARM Concurrency: Multicopy-atomic Axiomatic // and Operational Models for ARMv8" diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 3999beeec2b..2622bda1d0b 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -5630,38 +5630,6 @@ void MacroAssembler::tlab_allocate(Register obj, bs->tlab_allocate(this, obj, var_size_in_bytes, con_size_in_bytes, t1, t2, slow_case); } -void MacroAssembler::inc_held_monitor_count(Register tmp) { - Address dst(rthread, JavaThread::held_monitor_count_offset()); -#ifdef ASSERT - ldr(tmp, dst); - increment(tmp); - str(tmp, dst); - Label ok; - tbz(tmp, 63, ok); - STOP("assert(held monitor count underflow)"); - should_not_reach_here(); - bind(ok); -#else - increment(dst); -#endif -} - -void MacroAssembler::dec_held_monitor_count(Register tmp) { - Address dst(rthread, JavaThread::held_monitor_count_offset()); -#ifdef ASSERT - ldr(tmp, dst); - decrement(tmp); - str(tmp, dst); - Label ok; - tbz(tmp, 63, ok); - STOP("assert(held monitor count underflow)"); - should_not_reach_here(); - bind(ok); -#else - decrement(dst); -#endif -} - void MacroAssembler::verify_tlab() { #ifdef ASSERT if (UseTLAB && VerifyOops) { diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index 0570fad5b8d..705bd19093c 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -983,9 +983,6 @@ public: void push_cont_fastpath(Register java_thread = rthread); void pop_cont_fastpath(Register java_thread = rthread); - void inc_held_monitor_count(Register tmp); - void dec_held_monitor_count(Register tmp); - // Round up to a power of two void round_to(Register reg, int modulus); diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index 70af8dd91d8..39609cbe0ac 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -985,11 +985,8 @@ static void fill_continuation_entry(MacroAssembler* masm) { __ ldr(rscratch1, Address(rthread, JavaThread::cont_fastpath_offset())); __ str(rscratch1, Address(sp, ContinuationEntry::parent_cont_fastpath_offset())); - __ ldr(rscratch1, Address(rthread, JavaThread::held_monitor_count_offset())); - __ str(rscratch1, Address(sp, ContinuationEntry::parent_held_monitor_count_offset())); __ str(zr, Address(rthread, JavaThread::cont_fastpath_offset())); - __ str(zr, Address(rthread, JavaThread::held_monitor_count_offset())); } // on entry, sp points to the ContinuationEntry @@ -1005,50 +1002,6 @@ static void continuation_enter_cleanup(MacroAssembler* masm) { #endif __ ldr(rscratch1, Address(sp, ContinuationEntry::parent_cont_fastpath_offset())); __ str(rscratch1, Address(rthread, JavaThread::cont_fastpath_offset())); - - if (CheckJNICalls) { - // Check if this is a virtual thread continuation - Label L_skip_vthread_code; - __ ldrw(rscratch1, Address(sp, ContinuationEntry::flags_offset())); - __ cbzw(rscratch1, L_skip_vthread_code); - - // If the held monitor count is > 0 and this vthread is terminating then - // it failed to release a JNI monitor. So we issue the same log message - // that JavaThread::exit does. - __ ldr(rscratch1, Address(rthread, JavaThread::jni_monitor_count_offset())); - __ cbz(rscratch1, L_skip_vthread_code); - - // Save return value potentially containing the exception oop in callee-saved R19. - __ mov(r19, r0); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::log_jni_monitor_still_held)); - // Restore potential return value. - __ mov(r0, r19); - - // For vthreads we have to explicitly zero the JNI monitor count of the carrier - // on termination. The held count is implicitly zeroed below when we restore from - // the parent held count (which has to be zero). - __ str(zr, Address(rthread, JavaThread::jni_monitor_count_offset())); - - __ bind(L_skip_vthread_code); - } -#ifdef ASSERT - else { - // Check if this is a virtual thread continuation - Label L_skip_vthread_code; - __ ldrw(rscratch1, Address(sp, ContinuationEntry::flags_offset())); - __ cbzw(rscratch1, L_skip_vthread_code); - - // See comment just above. If not checking JNI calls the JNI count is only - // needed for assertion checking. - __ str(zr, Address(rthread, JavaThread::jni_monitor_count_offset())); - - __ bind(L_skip_vthread_code); - } -#endif - - __ ldr(rscratch1, Address(sp, ContinuationEntry::parent_held_monitor_count_offset())); - __ str(rscratch1, Address(rthread, JavaThread::held_monitor_count_offset())); - __ ldr(rscratch2, Address(sp, ContinuationEntry::parent_offset())); __ str(rscratch2, Address(rthread, JavaThread::cont_entry_offset())); __ add(rfp, sp, (int)ContinuationEntry::size()); diff --git a/src/hotspot/cpu/ppc/globalDefinitions_ppc.hpp b/src/hotspot/cpu/ppc/globalDefinitions_ppc.hpp index f8f15741301..6c41e56b20b 100644 --- a/src/hotspot/cpu/ppc/globalDefinitions_ppc.hpp +++ b/src/hotspot/cpu/ppc/globalDefinitions_ppc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2016 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -43,8 +43,6 @@ const bool CCallingConventionRequiresIntsAsLongs = true; #define SUPPORTS_NATIVE_CX8 -#define SUPPORT_MONITOR_COUNT - // PPC64 is not specified as multi-copy-atomic // So we must not #define CPU_MULTI_COPY_ATOMIC diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index aec36b3f3f9..9fe7e1f22ff 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -1639,7 +1639,6 @@ static void fill_continuation_entry(MacroAssembler* masm, Register reg_cont_obj, assert_different_registers(reg_cont_obj, reg_flags); Register zero = R8_ARG6; Register tmp2 = R9_ARG7; - Register tmp3 = R10_ARG8; DEBUG_ONLY(__ block_comment("fill {")); #ifdef ASSERT @@ -1655,12 +1654,9 @@ static void fill_continuation_entry(MacroAssembler* masm, Register reg_cont_obj, __ stw(zero, in_bytes(ContinuationEntry::pin_count_offset()), R1_SP); __ ld_ptr(tmp2, JavaThread::cont_fastpath_offset(), R16_thread); - __ ld(tmp3, in_bytes(JavaThread::held_monitor_count_offset()), R16_thread); __ st_ptr(tmp2, ContinuationEntry::parent_cont_fastpath_offset(), R1_SP); - __ std(tmp3, in_bytes(ContinuationEntry::parent_held_monitor_count_offset()), R1_SP); __ st_ptr(zero, JavaThread::cont_fastpath_offset(), R16_thread); - __ std(zero, in_bytes(JavaThread::held_monitor_count_offset()), R16_thread); DEBUG_ONLY(__ block_comment("} fill")); } @@ -1681,7 +1677,6 @@ static void fill_continuation_entry(MacroAssembler* masm, Register reg_cont_obj, static void continuation_enter_cleanup(MacroAssembler* masm) { Register tmp1 = R8_ARG6; Register tmp2 = R9_ARG7; - Register tmp3 = R10_ARG8; #ifdef ASSERT __ block_comment("clean {"); @@ -1692,57 +1687,8 @@ static void continuation_enter_cleanup(MacroAssembler* masm) { __ ld_ptr(tmp1, ContinuationEntry::parent_cont_fastpath_offset(), R1_SP); __ st_ptr(tmp1, JavaThread::cont_fastpath_offset(), R16_thread); - - if (CheckJNICalls) { - // Check if this is a virtual thread continuation - Label L_skip_vthread_code; - __ lwz(R0, in_bytes(ContinuationEntry::flags_offset()), R1_SP); - __ cmpwi(CR0, R0, 0); - __ beq(CR0, L_skip_vthread_code); - - // If the held monitor count is > 0 and this vthread is terminating then - // it failed to release a JNI monitor. So we issue the same log message - // that JavaThread::exit does. - __ ld(R0, in_bytes(JavaThread::jni_monitor_count_offset()), R16_thread); - __ cmpdi(CR0, R0, 0); - __ beq(CR0, L_skip_vthread_code); - - // Save return value potentially containing the exception oop - Register ex_oop = R15_esp; // nonvolatile register - __ mr(ex_oop, R3_RET); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::log_jni_monitor_still_held)); - // Restore potental return value - __ mr(R3_RET, ex_oop); - - // For vthreads we have to explicitly zero the JNI monitor count of the carrier - // on termination. The held count is implicitly zeroed below when we restore from - // the parent held count (which has to be zero). - __ li(tmp1, 0); - __ std(tmp1, in_bytes(JavaThread::jni_monitor_count_offset()), R16_thread); - - __ bind(L_skip_vthread_code); - } -#ifdef ASSERT - else { - // Check if this is a virtual thread continuation - Label L_skip_vthread_code; - __ lwz(R0, in_bytes(ContinuationEntry::flags_offset()), R1_SP); - __ cmpwi(CR0, R0, 0); - __ beq(CR0, L_skip_vthread_code); - - // See comment just above. If not checking JNI calls the JNI count is only - // needed for assertion checking. - __ li(tmp1, 0); - __ std(tmp1, in_bytes(JavaThread::jni_monitor_count_offset()), R16_thread); - - __ bind(L_skip_vthread_code); - } -#endif - - __ ld(tmp2, in_bytes(ContinuationEntry::parent_held_monitor_count_offset()), R1_SP); - __ ld_ptr(tmp3, ContinuationEntry::parent_offset(), R1_SP); - __ std(tmp2, in_bytes(JavaThread::held_monitor_count_offset()), R16_thread); - __ st_ptr(tmp3, JavaThread::cont_entry_offset(), R16_thread); + __ ld_ptr(tmp2, ContinuationEntry::parent_offset(), R1_SP); + __ st_ptr(tmp2, JavaThread::cont_entry_offset(), R16_thread); DEBUG_ONLY(__ block_comment("} clean")); } diff --git a/src/hotspot/cpu/riscv/globalDefinitions_riscv.hpp b/src/hotspot/cpu/riscv/globalDefinitions_riscv.hpp index 407017ee1c0..57223cf4390 100644 --- a/src/hotspot/cpu/riscv/globalDefinitions_riscv.hpp +++ b/src/hotspot/cpu/riscv/globalDefinitions_riscv.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved. * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -44,8 +44,6 @@ const bool CCallingConventionRequiresIntsAsLongs = false; #define SUPPORTS_NATIVE_CX8 -#define SUPPORT_MONITOR_COUNT - #define SUPPORT_RESERVED_STACK_AREA #define USE_POINTERS_TO_REGISTER_IMPL_ARRAY diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 5c85cc13bed..115b90a0087 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -225,36 +225,6 @@ void MacroAssembler::pop_cont_fastpath(Register java_thread) { bind(done); } -void MacroAssembler::inc_held_monitor_count(Register tmp) { - Address dst(xthread, JavaThread::held_monitor_count_offset()); - ld(tmp, dst); - addi(tmp, tmp, 1); - sd(tmp, dst); -#ifdef ASSERT - Label ok; - test_bit(tmp, tmp, 63); - beqz(tmp, ok); - STOP("assert(held monitor count overflow)"); - should_not_reach_here(); - bind(ok); -#endif -} - -void MacroAssembler::dec_held_monitor_count(Register tmp) { - Address dst(xthread, JavaThread::held_monitor_count_offset()); - ld(tmp, dst); - subi(tmp, tmp, 1); - sd(tmp, dst); -#ifdef ASSERT - Label ok; - test_bit(tmp, tmp, 63); - beqz(tmp, ok); - STOP("assert(held monitor count underflow)"); - should_not_reach_here(); - bind(ok); -#endif -} - int MacroAssembler::align(int modulus, int extra_offset) { CompressibleScope scope(this); intptr_t before = offset(); diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index 13b70d5dbd7..9e713e90270 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -849,9 +849,6 @@ public: void push_cont_fastpath(Register java_thread = xthread); void pop_cont_fastpath(Register java_thread = xthread); - void inc_held_monitor_count(Register tmp); - void dec_held_monitor_count(Register tmp); - // if heap base register is used - reinit it with the correct value void reinit_heapbase(); diff --git a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp index 94506e9f19d..b303178a666 100644 --- a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp +++ b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp @@ -885,11 +885,8 @@ static void fill_continuation_entry(MacroAssembler* masm) { __ ld(t0, Address(xthread, JavaThread::cont_fastpath_offset())); __ sd(t0, Address(sp, ContinuationEntry::parent_cont_fastpath_offset())); - __ ld(t0, Address(xthread, JavaThread::held_monitor_count_offset())); - __ sd(t0, Address(sp, ContinuationEntry::parent_held_monitor_count_offset())); __ sd(zr, Address(xthread, JavaThread::cont_fastpath_offset())); - __ sd(zr, Address(xthread, JavaThread::held_monitor_count_offset())); } // on entry, sp points to the ContinuationEntry @@ -905,50 +902,6 @@ static void continuation_enter_cleanup(MacroAssembler* masm) { __ ld(t0, Address(sp, ContinuationEntry::parent_cont_fastpath_offset())); __ sd(t0, Address(xthread, JavaThread::cont_fastpath_offset())); - - if (CheckJNICalls) { - // Check if this is a virtual thread continuation - Label L_skip_vthread_code; - __ lwu(t0, Address(sp, ContinuationEntry::flags_offset())); - __ beqz(t0, L_skip_vthread_code); - - // If the held monitor count is > 0 and this vthread is terminating then - // it failed to release a JNI monitor. So we issue the same log message - // that JavaThread::exit does. - __ ld(t0, Address(xthread, JavaThread::jni_monitor_count_offset())); - __ beqz(t0, L_skip_vthread_code); - - // Save return value potentially containing the exception oop in callee-saved x9 - __ mv(x9, x10); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::log_jni_monitor_still_held)); - // Restore potential return value - __ mv(x10, x9); - - // For vthreads we have to explicitly zero the JNI monitor count of the carrier - // on termination. The held count is implicitly zeroed below when we restore from - // the parent held count (which has to be zero). - __ sd(zr, Address(xthread, JavaThread::jni_monitor_count_offset())); - - __ bind(L_skip_vthread_code); - } -#ifdef ASSERT - else { - // Check if this is a virtual thread continuation - Label L_skip_vthread_code; - __ lwu(t0, Address(sp, ContinuationEntry::flags_offset())); - __ beqz(t0, L_skip_vthread_code); - - // See comment just above. If not checking JNI calls the JNI count is only - // needed for assertion checking. - __ sd(zr, Address(xthread, JavaThread::jni_monitor_count_offset())); - - __ bind(L_skip_vthread_code); - } -#endif - - __ ld(t0, Address(sp, ContinuationEntry::parent_held_monitor_count_offset())); - __ sd(t0, Address(xthread, JavaThread::held_monitor_count_offset())); - __ ld(t0, Address(sp, ContinuationEntry::parent_offset())); __ sd(t0, Address(xthread, JavaThread::cont_entry_offset())); __ add(fp, sp, (int)ContinuationEntry::size() + 2 * wordSize /* 2 extra words to match up with leave() */); diff --git a/src/hotspot/cpu/x86/globalDefinitions_x86.hpp b/src/hotspot/cpu/x86/globalDefinitions_x86.hpp index 3c1474ae861..abbeb66a1ca 100644 --- a/src/hotspot/cpu/x86/globalDefinitions_x86.hpp +++ b/src/hotspot/cpu/x86/globalDefinitions_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,8 +34,6 @@ const bool CCallingConventionRequiresIntsAsLongs = false; #define SUPPORTS_NATIVE_CX8 -#define SUPPORT_MONITOR_COUNT - #define CPU_MULTI_COPY_ATOMIC // The expected size in bytes of a cache line. diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 77ee71c0382..4f19b30b832 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -2431,14 +2431,6 @@ void MacroAssembler::pop_cont_fastpath() { bind(L_done); } -void MacroAssembler::inc_held_monitor_count() { - incrementq(Address(r15_thread, JavaThread::held_monitor_count_offset())); -} - -void MacroAssembler::dec_held_monitor_count() { - decrementq(Address(r15_thread, JavaThread::held_monitor_count_offset())); -} - #ifdef ASSERT void MacroAssembler::stop_if_in_cont(Register cont, const char* name) { Label no_cont; diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index 1c0dbaaefbe..ed1343d9c8c 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -472,9 +472,6 @@ class MacroAssembler: public Assembler { void push_cont_fastpath(); void pop_cont_fastpath(); - void inc_held_monitor_count(); - void dec_held_monitor_count(); - DEBUG_ONLY(void stop_if_in_cont(Register cont_reg, const char* name);) // Round up to a power of two diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index e2a8f36b050..e702b587edd 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -1352,11 +1352,8 @@ static void fill_continuation_entry(MacroAssembler* masm, Register reg_cont_obj, __ movptr(rax, Address(r15_thread, JavaThread::cont_fastpath_offset())); __ movptr(Address(rsp, ContinuationEntry::parent_cont_fastpath_offset()), rax); - __ movq(rax, Address(r15_thread, JavaThread::held_monitor_count_offset())); - __ movq(Address(rsp, ContinuationEntry::parent_held_monitor_count_offset()), rax); __ movptr(Address(r15_thread, JavaThread::cont_fastpath_offset()), 0); - __ movq(Address(r15_thread, JavaThread::held_monitor_count_offset()), 0); } //---------------------------- continuation_enter_cleanup --------------------------- @@ -1380,49 +1377,6 @@ static void continuation_enter_cleanup(MacroAssembler* masm) { #endif __ movptr(rbx, Address(rsp, ContinuationEntry::parent_cont_fastpath_offset())); __ movptr(Address(r15_thread, JavaThread::cont_fastpath_offset()), rbx); - - if (CheckJNICalls) { - // Check if this is a virtual thread continuation - Label L_skip_vthread_code; - __ cmpl(Address(rsp, ContinuationEntry::flags_offset()), 0); - __ jcc(Assembler::equal, L_skip_vthread_code); - - // If the held monitor count is > 0 and this vthread is terminating then - // it failed to release a JNI monitor. So we issue the same log message - // that JavaThread::exit does. - __ cmpptr(Address(r15_thread, JavaThread::jni_monitor_count_offset()), 0); - __ jcc(Assembler::equal, L_skip_vthread_code); - - // rax may hold an exception oop, save it before the call - __ push(rax); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::log_jni_monitor_still_held)); - __ pop(rax); - - // For vthreads we have to explicitly zero the JNI monitor count of the carrier - // on termination. The held count is implicitly zeroed below when we restore from - // the parent held count (which has to be zero). - __ movq(Address(r15_thread, JavaThread::jni_monitor_count_offset()), 0); - - __ bind(L_skip_vthread_code); - } -#ifdef ASSERT - else { - // Check if this is a virtual thread continuation - Label L_skip_vthread_code; - __ cmpl(Address(rsp, ContinuationEntry::flags_offset()), 0); - __ jcc(Assembler::equal, L_skip_vthread_code); - - // See comment just above. If not checking JNI calls the JNI count is only - // needed for assertion checking. - __ movq(Address(r15_thread, JavaThread::jni_monitor_count_offset()), 0); - - __ bind(L_skip_vthread_code); - } -#endif - - __ movq(rbx, Address(rsp, ContinuationEntry::parent_held_monitor_count_offset())); - __ movq(Address(r15_thread, JavaThread::held_monitor_count_offset()), rbx); - __ movptr(rbx, Address(rsp, ContinuationEntry::parent_offset())); __ movptr(Address(r15_thread, JavaThread::cont_entry_offset()), rbx); __ addptr(rsp, checked_cast(ContinuationEntry::size())); diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index b4f033a4f9a..7ef16f6e32c 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -255,7 +255,6 @@ nonstatic_field(JavaThread, _should_post_on_exceptions_flag, int) \ nonstatic_field(JavaThread, _jni_environment, JNIEnv) \ nonstatic_field(JavaThread, _stack_overflow_state._reserved_stack_activation, address) \ - nonstatic_field(JavaThread, _held_monitor_count, intx) \ nonstatic_field(JavaThread, _lock_stack, LockStack) \ nonstatic_field(JavaThread, _om_cache, OMCache) \ nonstatic_field(JavaThread, _cont_entry, ContinuationEntry*) \ diff --git a/src/hotspot/share/runtime/continuation.hpp b/src/hotspot/share/runtime/continuation.hpp index e678e0bd42b..0cfd484361d 100644 --- a/src/hotspot/share/runtime/continuation.hpp +++ b/src/hotspot/share/runtime/continuation.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,10 +53,9 @@ enum freeze_result { freeze_ok_bottom = 1, freeze_pinned_cs = 2, freeze_pinned_native = 3, - freeze_pinned_monitor = 4, - freeze_exception = 5, - freeze_not_mounted = 6, - freeze_unsupported = 7 + freeze_exception = 4, + freeze_not_mounted = 5, + freeze_unsupported = 6 }; class Continuation : AllStatic { diff --git a/src/hotspot/share/runtime/continuationEntry.cpp b/src/hotspot/share/runtime/continuationEntry.cpp index 4551bfa7cc8..69a20808798 100644 --- a/src/hotspot/share/runtime/continuationEntry.cpp +++ b/src/hotspot/share/runtime/continuationEntry.cpp @@ -107,7 +107,6 @@ void ContinuationEntry::describe(FrameValues& values, int frame_no) const { values.describe(frame_no, (intptr_t*)(usp + in_bytes(ContinuationEntry::argsize_offset())), "argsize"); values.describe(frame_no, (intptr_t*)(usp + in_bytes(ContinuationEntry::pin_count_offset())), "pin_count"); values.describe(frame_no, (intptr_t*)(usp + in_bytes(ContinuationEntry::parent_cont_fastpath_offset())), "parent fastpath"); - values.describe(frame_no, (intptr_t*)(usp + in_bytes(ContinuationEntry::parent_held_monitor_count_offset())), "parent held monitor count"); } #endif diff --git a/src/hotspot/share/runtime/continuationEntry.hpp b/src/hotspot/share/runtime/continuationEntry.hpp index 3c8532b9e87..8361f2f912b 100644 --- a/src/hotspot/share/runtime/continuationEntry.hpp +++ b/src/hotspot/share/runtime/continuationEntry.hpp @@ -79,11 +79,6 @@ class ContinuationEntry { // The caller (if there is one) is the still frozen top frame in the StackChunk. int _argsize; intptr_t* _parent_cont_fastpath; -#ifdef _LP64 - int64_t _parent_held_monitor_count; -#else - int32_t _parent_held_monitor_count; -#endif uint32_t _pin_count; public: @@ -94,7 +89,6 @@ class ContinuationEntry { static ByteSize argsize_offset() { return byte_offset_of(ContinuationEntry, _argsize); } static ByteSize pin_count_offset(){ return byte_offset_of(ContinuationEntry, _pin_count); } static ByteSize parent_cont_fastpath_offset() { return byte_offset_of(ContinuationEntry, _parent_cont_fastpath); } - static ByteSize parent_held_monitor_count_offset() { return byte_offset_of(ContinuationEntry, _parent_held_monitor_count); } static address return_pc() { return _return_pc; } static address return_pc_address() { return (address)&_return_pc; } @@ -103,7 +97,6 @@ class ContinuationEntry { static size_t size() { return align_up((int)sizeof(ContinuationEntry), 2*wordSize); } ContinuationEntry* parent() const { return _parent; } - int64_t parent_held_monitor_count() const { return (int64_t)_parent_held_monitor_count; } static address entry_pc() { return _return_pc; } intptr_t* entry_sp() const { return (intptr_t*)this; } diff --git a/src/hotspot/share/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp index 024b69c765f..33b4f2bf488 100644 --- a/src/hotspot/share/runtime/continuationFreezeThaw.cpp +++ b/src/hotspot/share/runtime/continuationFreezeThaw.cpp @@ -1736,13 +1736,10 @@ static inline freeze_result freeze_internal(JavaThread* current, intptr_t* const assert(entry->is_virtual_thread() == (entry->scope(current) == java_lang_VirtualThread::vthread_scope()), ""); - assert((current->held_monitor_count() == 0 && current->jni_monitor_count() == 0), - "Held monitor count should not be used for lightweight locking: " INT64_FORMAT " JNI: " INT64_FORMAT, (int64_t)current->held_monitor_count(), (int64_t)current->jni_monitor_count()); - - if (entry->is_pinned() || current->held_monitor_count() > 0) { - log_develop_debug(continuations)("PINNED due to critical section/hold monitor"); + if (entry->is_pinned()) { + log_develop_debug(continuations)("PINNED due to critical section"); verify_continuation(cont.continuation()); - freeze_result res = entry->is_pinned() ? freeze_pinned_cs : freeze_pinned_monitor; + const freeze_result res = freeze_pinned_cs; if (!preempt) { JFR_ONLY(current->set_last_freeze_fail_result(res);) } @@ -1799,8 +1796,6 @@ static freeze_result is_pinned0(JavaThread* thread, oop cont_scope, bool safepoi } if (entry->is_pinned()) { return freeze_pinned_cs; - } else if (thread->held_monitor_count() > 0) { - return freeze_pinned_monitor; } RegisterMap map(thread, @@ -1836,15 +1831,12 @@ static freeze_result is_pinned0(JavaThread* thread, oop cont_scope, bool safepoi if (scope == cont_scope) { break; } - intx monitor_count = entry->parent_held_monitor_count(); entry = entry->parent(); if (entry == nullptr) { break; } if (entry->is_pinned()) { return freeze_pinned_cs; - } else if (monitor_count > 0) { - return freeze_pinned_monitor; } } } diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index e5af8d7bedd..8bb8095878f 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -488,8 +488,6 @@ JavaThread::JavaThread(MemTag mem_tag) : _cont_entry(nullptr), _cont_fastpath(nullptr), _cont_fastpath_thread_state(1), - _held_monitor_count(0), - _jni_monitor_count(0), _unlocked_inflated_monitor(nullptr), _preempt_alternate_return(nullptr), @@ -927,27 +925,6 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) { "should not have a Java frame when detaching or exiting"); ObjectSynchronizer::release_monitors_owned_by_thread(this); assert(!this->has_pending_exception(), "release_monitors should have cleared"); - // Check for monitor counts being out of sync. - assert(held_monitor_count() == jni_monitor_count(), - "held monitor count should be equal to jni: %zd != %zd", - held_monitor_count(), jni_monitor_count()); - // All in-use monitors, including JNI-locked ones, should have been released above. - assert(held_monitor_count() == 0, "Failed to unlock %zd object monitors", - held_monitor_count()); - } else { - // Check for monitor counts being out of sync. - assert(held_monitor_count() == jni_monitor_count(), - "held monitor count should be equal to jni: %zd != %zd", - held_monitor_count(), jni_monitor_count()); - // It is possible that a terminating thread failed to unlock monitors it locked - // via JNI so we don't assert the count is zero. - } - - if (CheckJNICalls && jni_monitor_count() > 0) { - // We would like a fatal here, but due to we never checked this before there - // is a lot of tests which breaks, even with an error log. - log_debug(jni)("JavaThread %s (tid: %zu) with Objects still locked by JNI MonitorEnter.", - exit_type == JavaThread::normal_exit ? "exiting" : "detaching", os::current_thread_id()); } // These things needs to be done while we are still a Java Thread. Make sure that thread @@ -1988,26 +1965,6 @@ void JavaThread::trace_stack() { #endif // PRODUCT -// Slow-path increment of the held monitor counts. JNI locking is always -// this slow-path. -void JavaThread::inc_held_monitor_count(intx i, bool jni) { -#ifdef SUPPORT_MONITOR_COUNT - // Nothing to do. Just do some sanity check. - assert(_held_monitor_count == 0, "counter should not be used"); - assert(_jni_monitor_count == 0, "counter should not be used"); -#endif // SUPPORT_MONITOR_COUNT -} - -// Slow-path decrement of the held monitor counts. JNI unlocking is always -// this slow-path. -void JavaThread::dec_held_monitor_count(intx i, bool jni) { -#ifdef SUPPORT_MONITOR_COUNT - // Nothing to do. Just do some sanity check. - assert(_held_monitor_count == 0, "counter should not be used"); - assert(_jni_monitor_count == 0, "counter should not be used"); -#endif // SUPPORT_MONITOR_COUNT -} - frame JavaThread::vthread_last_frame() { assert (is_vthread_mounted(), "Virtual thread not mounted"); return last_frame(); diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp index 89c3191669a..c8be1594a69 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -476,9 +476,6 @@ class JavaThread: public Thread { // frame inside the continuation that we know about int _cont_fastpath_thread_state; // whether global thread state allows continuation fastpath (JVMTI) - // It's signed for error detection. - intx _held_monitor_count; // used by continuations for fast lock detection - intx _jni_monitor_count; ObjectMonitor* _unlocked_inflated_monitor; // This is the field we poke in the interpreter and native @@ -662,13 +659,6 @@ private: bool cont_fastpath() const { return _cont_fastpath == nullptr && _cont_fastpath_thread_state != 0; } bool cont_fastpath_thread_state() const { return _cont_fastpath_thread_state != 0; } - void inc_held_monitor_count(intx i = 1, bool jni = false); - void dec_held_monitor_count(intx i = 1, bool jni = false); - - intx held_monitor_count() { return _held_monitor_count; } - intx jni_monitor_count() { return _jni_monitor_count; } - void clear_jni_monitor_count() { _jni_monitor_count = 0; } - // Support for SharedRuntime::monitor_exit_helper() ObjectMonitor* unlocked_inflated_monitor() const { return _unlocked_inflated_monitor; } void clear_unlocked_inflated_monitor() { @@ -897,8 +887,6 @@ public: static ByteSize cont_entry_offset() { return byte_offset_of(JavaThread, _cont_entry); } static ByteSize cont_fastpath_offset() { return byte_offset_of(JavaThread, _cont_fastpath); } - static ByteSize held_monitor_count_offset() { return byte_offset_of(JavaThread, _held_monitor_count); } - static ByteSize jni_monitor_count_offset() { return byte_offset_of(JavaThread, _jni_monitor_count); } static ByteSize preemption_cancelled_offset() { return byte_offset_of(JavaThread, _preemption_cancelled); } static ByteSize preempt_alternate_return_offset() { return byte_offset_of(JavaThread, _preempt_alternate_return); } static ByteSize unlocked_inflated_monitor_offset() { return byte_offset_of(JavaThread, _unlocked_inflated_monitor); } diff --git a/src/hotspot/share/runtime/objectMonitor.cpp b/src/hotspot/share/runtime/objectMonitor.cpp index 8859f6e7f5f..4c00ecac697 100644 --- a/src/hotspot/share/runtime/objectMonitor.cpp +++ b/src/hotspot/share/runtime/objectMonitor.cpp @@ -1952,7 +1952,6 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) { int relock_count = JvmtiDeferredUpdates::get_and_reset_relock_count_after_wait(current); _recursions = save // restore the old recursion count + relock_count; // increased by the deferred relock count - current->inc_held_monitor_count(relock_count); // Deopt never entered these counts. _waiters--; // decrement the number of waiters // Verify a few postconditions diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index cf949fe1e7c..85aeba361ff 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -1980,7 +1980,6 @@ void SharedRuntime::monitor_exit_helper(oopDesc* obj, BasicLock* lock, JavaThrea if (!m->try_enter(current, /*check_for_recursion*/ false)) { // Some other thread acquired the lock (or the monitor was // deflated). Either way we are done. - current->dec_held_monitor_count(); return; } } @@ -2002,20 +2001,6 @@ JRT_LEAF(void, SharedRuntime::complete_monitor_unlocking_C(oopDesc* obj, BasicLo SharedRuntime::monitor_exit_helper(obj, lock, current); JRT_END -// This is only called when CheckJNICalls is true, and only -// for virtual thread termination. -JRT_LEAF(void, SharedRuntime::log_jni_monitor_still_held()) - assert(CheckJNICalls, "Only call this when checking JNI usage"); - if (log_is_enabled(Debug, jni)) { - JavaThread* current = JavaThread::current(); - int64_t vthread_id = java_lang_Thread::thread_id(current->vthread()); - int64_t carrier_id = java_lang_Thread::thread_id(current->threadObj()); - log_debug(jni)("VirtualThread (tid: " INT64_FORMAT ", carrier id: " INT64_FORMAT - ") exiting with Objects still locked by JNI MonitorEnter.", - vthread_id, carrier_id); - } -JRT_END - #ifndef PRODUCT void SharedRuntime::print_statistics() { diff --git a/src/hotspot/share/runtime/sharedRuntime.hpp b/src/hotspot/share/runtime/sharedRuntime.hpp index 6544e380d99..2a19b80c3b5 100644 --- a/src/hotspot/share/runtime/sharedRuntime.hpp +++ b/src/hotspot/share/runtime/sharedRuntime.hpp @@ -404,9 +404,6 @@ class SharedRuntime: AllStatic { static void monitor_exit_helper(oopDesc* obj, BasicLock* lock, JavaThread* current); - // Issue UL warning for unlocked JNI monitor on virtual thread termination - static void log_jni_monitor_still_held(); - private: static Handle find_callee_info(Bytecodes::Code& bc, CallInfo& callinfo, TRAPS); static Handle find_callee_info_helper(vframeStream& vfst, Bytecodes::Code& bc, CallInfo& callinfo, TRAPS); diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp index ff4e09e741f..e513c57fe06 100644 --- a/src/hotspot/share/runtime/synchronizer.cpp +++ b/src/hotspot/share/runtime/synchronizer.cpp @@ -452,7 +452,6 @@ void ObjectSynchronizer::jni_enter(Handle obj, JavaThread* current) { while (true) { BasicLock lock; if (LightweightSynchronizer::inflate_and_enter(obj(), &lock, inflate_cause_jni_enter, current, current) != nullptr) { - current->inc_held_monitor_count(1, true); break; } } @@ -470,7 +469,6 @@ void ObjectSynchronizer::jni_exit(oop obj, TRAPS) { // monitor even if an exception was already pending. if (monitor->check_owner(THREAD)) { monitor->exit(current); - current->dec_held_monitor_count(1, true); } } @@ -1263,8 +1261,7 @@ class ReleaseJavaMonitorsClosure: public MonitorClosure { public: ReleaseJavaMonitorsClosure(JavaThread* thread) : _thread(thread) {} void do_monitor(ObjectMonitor* mid) { - intx rec = mid->complete_exit(_thread); - _thread->dec_held_monitor_count(rec + 1); + mid->complete_exit(_thread); } }; @@ -1290,9 +1287,6 @@ void ObjectSynchronizer::release_monitors_owned_by_thread(JavaThread* current) { ObjectSynchronizer::owned_monitors_iterate(&rjmc, current); assert(!current->has_pending_exception(), "Should not be possible"); current->clear_pending_exception(); - assert(current->held_monitor_count() == 0, "Should not be possible"); - // All monitors (including entered via JNI) have been unlocked above, so we need to clear jni count. - current->clear_jni_monitor_count(); } const char* ObjectSynchronizer::inflate_cause_name(const InflateCause cause) { diff --git a/src/hotspot/share/runtime/synchronizer.inline.hpp b/src/hotspot/share/runtime/synchronizer.inline.hpp index 6a850e5c8ca..cdbeb1daf5b 100644 --- a/src/hotspot/share/runtime/synchronizer.inline.hpp +++ b/src/hotspot/share/runtime/synchronizer.inline.hpp @@ -61,8 +61,6 @@ inline bool ObjectSynchronizer::quick_enter(oop obj, BasicLock* lock, JavaThread } inline void ObjectSynchronizer::exit(oop object, BasicLock* lock, JavaThread* current) { - current->dec_held_monitor_count(); - LightweightSynchronizer::exit(object, lock, current); } diff --git a/src/java.base/share/classes/jdk/internal/vm/Continuation.java b/src/java.base/share/classes/jdk/internal/vm/Continuation.java index a97f9ac9ea4..a7eb3ea6a9f 100644 --- a/src/java.base/share/classes/jdk/internal/vm/Continuation.java +++ b/src/java.base/share/classes/jdk/internal/vm/Continuation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,7 +57,6 @@ public class Continuation { /** Reason for pinning */ public enum Pinned { /** Native frame on stack */ NATIVE, - /** Monitor held */ MONITOR, /** In critical section */ CRITICAL_SECTION, /** Exception (OOME/SOE) */ EXCEPTION } @@ -69,8 +68,7 @@ public class Continuation { /** Permanent failure: continuation already yielding */ PERM_FAIL_YIELDING(null), /** Permanent failure: continuation not mounted on the thread */ PERM_FAIL_NOT_MOUNTED(null), /** Transient failure: continuation pinned due to a held CS */ TRANSIENT_FAIL_PINNED_CRITICAL_SECTION(Pinned.CRITICAL_SECTION), - /** Transient failure: continuation pinned due to native frame */ TRANSIENT_FAIL_PINNED_NATIVE(Pinned.NATIVE), - /** Transient failure: continuation pinned due to a held monitor */ TRANSIENT_FAIL_PINNED_MONITOR(Pinned.MONITOR); + /** Transient failure: continuation pinned due to native frame */ TRANSIENT_FAIL_PINNED_NATIVE(Pinned.NATIVE); final Pinned pinned; private PreemptStatus(Pinned reason) { this.pinned = reason; } @@ -85,8 +83,7 @@ public class Continuation { return switch (reason) { case 2 -> Pinned.CRITICAL_SECTION; case 3 -> Pinned.NATIVE; - case 4 -> Pinned.MONITOR; - case 5 -> Pinned.EXCEPTION; + case 4 -> Pinned.EXCEPTION; default -> throw new AssertionError("Unknown pinned reason: " + reason); }; } From 59e87437b4f9259121710dca5e595ca714c3e71b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Casta=C3=B1eda=20Lozano?= Date: Mon, 6 Oct 2025 08:14:24 +0000 Subject: [PATCH 028/160] 8368753: IGV: improve CFG view of difference graphs Reviewed-by: chagedorn, mhaessig, dfenacci --- .../com/sun/hotspot/igv/data/InputBlock.java | 2 +- .../hotspot/igv/data/services/Scheduler.java | 10 ++-- .../hotspot/igv/difference/Difference.java | 9 ++++ .../ServerCompilerScheduler.java | 54 +++++++++++++------ 4 files changed, 54 insertions(+), 21 deletions(-) diff --git a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputBlock.java b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputBlock.java index 6670470b5e8..a5b282f9de1 100644 --- a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputBlock.java +++ b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputBlock.java @@ -135,7 +135,7 @@ public class InputBlock { successors.add(b); } - void setArtificial() { + public void setArtificial() { this.artificial = true; } diff --git a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/services/Scheduler.java b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/services/Scheduler.java index 1fe6ac3342a..4ff960f7c3d 100644 --- a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/services/Scheduler.java +++ b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/services/Scheduler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,9 +24,7 @@ */ package com.sun.hotspot.igv.data.services; -import com.sun.hotspot.igv.data.InputBlock; import com.sun.hotspot.igv.data.InputGraph; -import java.util.Collection; /** * @@ -34,5 +32,9 @@ import java.util.Collection; */ public interface Scheduler { - public Collection schedule(InputGraph graph); + // Compute a set of scheduled blocks for the given graph, creating new + // blocks if these are not found in the graph. + public void schedule(InputGraph graph); + // Schedule locally the set of blocks in the given graph. + public void scheduleLocally(InputGraph graph); } diff --git a/src/utils/IdealGraphVisualizer/Difference/src/main/java/com/sun/hotspot/igv/difference/Difference.java b/src/utils/IdealGraphVisualizer/Difference/src/main/java/com/sun/hotspot/igv/difference/Difference.java index 89b1434663f..e3888be31be 100644 --- a/src/utils/IdealGraphVisualizer/Difference/src/main/java/com/sun/hotspot/igv/difference/Difference.java +++ b/src/utils/IdealGraphVisualizer/Difference/src/main/java/com/sun/hotspot/igv/difference/Difference.java @@ -114,6 +114,9 @@ public class Difference { Map blocksMap = new HashMap<>(); for (InputBlock blk : a.getBlocks()) { InputBlock diffblk = graph.addBlock(blk.getName()); + if (blk.isArtificial()) { + diffblk.setArtificial(); + } blocksMap.put(blk, diffblk); } for (InputBlock blk : b.getBlocks()) { @@ -121,6 +124,9 @@ public class Difference { if (diffblk == null) { diffblk = graph.addBlock(blk.getName()); } + if (blk.isArtificial()) { + diffblk.setArtificial(); + } blocksMap.put(blk, diffblk); } @@ -249,6 +255,9 @@ public class Difference { } } + Scheduler s = Lookup.getDefault().lookup(Scheduler.class); + s.scheduleLocally(graph); + return graph; } diff --git a/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/java/com/sun/hotspot/igv/servercompiler/ServerCompilerScheduler.java b/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/java/com/sun/hotspot/igv/servercompiler/ServerCompilerScheduler.java index 0a069c53a71..93199ea35a1 100644 --- a/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/java/com/sun/hotspot/igv/servercompiler/ServerCompilerScheduler.java +++ b/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/java/com/sun/hotspot/igv/servercompiler/ServerCompilerScheduler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -296,10 +296,25 @@ public class ServerCompilerScheduler implements Scheduler { return n.getProperties().get("block"); } + private boolean initialize(InputGraph graph) { + nodes = new ArrayList<>(); + inputNodeToNode = new HashMap<>(graph.getNodes().size()); + this.graph = graph; + if (!hasCategoryInformation()) { + ErrorManager.getDefault().log(ErrorManager.WARNING, + "Cannot find node category information in the input graph. " + + "The control-flow graph will not be approximated."); + return false; + } + buildUpGraph(); + markCFGNodes(); + return true; + } + @Override - public Collection schedule(InputGraph graph) { + public void schedule(InputGraph graph) { if (graph.getNodes().isEmpty()) { - return Collections.emptyList(); + return; } if (graph.getBlocks().size() > 0) { @@ -311,20 +326,11 @@ public class ServerCompilerScheduler implements Scheduler { assert graph.getBlock(n) != null; } } - return graph.getBlocks(); + return; } else { - nodes = new ArrayList<>(); - inputNodeToNode = new HashMap<>(graph.getNodes().size()); - - this.graph = graph; - if (!hasCategoryInformation()) { - ErrorManager.getDefault().log(ErrorManager.WARNING, - "Cannot find node category information in the input graph. " + - "The control-flow graph will not be approximated."); - return null; + if (!initialize(graph)) { + return; } - buildUpGraph(); - markCFGNodes(); buildBlocks(); schedulePinned(); buildDominators(); @@ -333,10 +339,26 @@ public class ServerCompilerScheduler implements Scheduler { check(); reportWarnings(); - return blocks; + return; } } + @Override + public void scheduleLocally(InputGraph graph) { + if (!initialize(graph)) { + return; + } + // Import global schedule from the given graph. + blocks = new Vector<>(); + for (InputBlock block : graph.getBlocks()) { + blocks.add(block); + for (InputNode in : block.getNodes()) { + inputNodeToNode.get(in).block = block; + } + } + scheduleLocal(); + } + private void scheduleLocal() { // Leave only local predecessors and successors. for (InputBlock b : blocks) { From baf8bc5701c43425e3345f82d4318b134b26d7c9 Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Mon, 6 Oct 2025 08:14:44 +0000 Subject: [PATCH 029/160] 8369038: Parallel: Use NMethodMarkingScope and ThreadsClaimTokenScope in psParallelCompact Reviewed-by: ayang, shade --- src/hotspot/share/gc/parallel/psParallelCompact.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index af812c652a6..5affa1a3e35 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -28,6 +28,7 @@ #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" +#include "code/nmethod.hpp" #include "compiler/oopMap.hpp" #include "gc/parallel/objectStartArray.inline.hpp" #include "gc/parallel/parallelArguments.hpp" @@ -61,7 +62,6 @@ #include "gc/shared/referenceProcessor.hpp" #include "gc/shared/referenceProcessorPhaseTimes.hpp" #include "gc/shared/spaceDecorator.hpp" -#include "gc/shared/strongRootsScope.hpp" #include "gc/shared/taskTerminator.hpp" #include "gc/shared/weakProcessor.inline.hpp" #include "gc/shared/workerPolicy.hpp" @@ -1085,7 +1085,8 @@ void steal_marking_work(TaskTerminator& terminator, uint worker_id) { } class MarkFromRootsTask : public WorkerTask { - StrongRootsScope _strong_roots_scope; // needed for Threads::possibly_parallel_threads_do + NMethodMarkingScope _nmethod_marking_scope; + ThreadsClaimTokenScope _threads_claim_token_scope; OopStorageSetStrongParState _oop_storage_set_par_state; TaskTerminator _terminator; uint _active_workers; @@ -1093,7 +1094,8 @@ class MarkFromRootsTask : public WorkerTask { public: MarkFromRootsTask(uint active_workers) : WorkerTask("MarkFromRootsTask"), - _strong_roots_scope(active_workers), + _nmethod_marking_scope(), + _threads_claim_token_scope(), _terminator(active_workers, ParCompactionManager::marking_stacks()), _active_workers(active_workers) {} From 2c114d676d9904094dd6058d15f06d801ec7a3d6 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Mon, 6 Oct 2025 09:26:51 +0000 Subject: [PATCH 030/160] 8367899: compiler/c2/gvn/TestBitCompressValueTransform.java intermittent timed out Reviewed-by: dfenacci, chagedorn --- .../c2/gvn/TestBitCompressValueTransform.java | 49 ++++++++----------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/test/hotspot/jtreg/compiler/c2/gvn/TestBitCompressValueTransform.java b/test/hotspot/jtreg/compiler/c2/gvn/TestBitCompressValueTransform.java index 98f26f120b1..3f32f78871c 100644 --- a/test/hotspot/jtreg/compiler/c2/gvn/TestBitCompressValueTransform.java +++ b/test/hotspot/jtreg/compiler/c2/gvn/TestBitCompressValueTransform.java @@ -76,10 +76,7 @@ public class TestBitCompressValueTransform { @Run(test = "test1") public void run1(RunInfo info) { - long res = 0; - for (int i = 0; i < 10000; i++) { - res |= test1(field_L); - } + long res = test1(field_L); Asserts.assertEQ(res, gold_L); } @@ -92,10 +89,7 @@ public class TestBitCompressValueTransform { @Run(test = "test2") public void run2(RunInfo info) { - int res = 0; - for (int i = 0; i < 10000; i++) { - res |= test2(field_I); - } + int res = test2(field_I); Asserts.assertEQ(res, gold_I); } @@ -113,7 +107,7 @@ public class TestBitCompressValueTransform { @Run(test = "test3") public void run3(RunInfo info) { int res = 0; - for (int i = 1; i < 10000; i++) { + for (int i = 1; i < 100; i++) { res |= test3(i); } Asserts.assertLTE(0, res); @@ -133,7 +127,7 @@ public class TestBitCompressValueTransform { @Run(test = "test4") public void run4(RunInfo info) { long res = 0; - for (long i = 1; i < 10000; i++) { + for (long i = 1; i < 100; i++) { res |= test4(i); } Asserts.assertLTE(0L, res); @@ -151,7 +145,7 @@ public class TestBitCompressValueTransform { @Run(test = "test5") public void run5(RunInfo info) { long res = 0; - for (int i = -10000; i < 10000; i++) { + for (int i = -100; i < 100; i++) { res |= test5((long)i); } Asserts.assertEQ(-1L, res); @@ -169,7 +163,7 @@ public class TestBitCompressValueTransform { @Run(test = "test6") public void run6(RunInfo info) { long res = 0; - for (int i = -10000; i < 10000; i++) { + for (int i = -100; i < 100; i++) { res |= test6((long)i); } Asserts.assertLTE(0L, res); @@ -188,7 +182,7 @@ public class TestBitCompressValueTransform { @Run(test = "test7") public void run7(RunInfo info) { long res = Long.MIN_VALUE; - for (int i = -10000; i < 10000; i++) { + for (int i = -100; i < 100; i++) { res = Long.max(test7((long)i), res); } Asserts.assertGTE(10000L, res); @@ -206,7 +200,7 @@ public class TestBitCompressValueTransform { @Run(test = "test8") public void run8(RunInfo info) { int res = 0; - for (int i = -10000; i < 10000; i++) { + for (int i = -100; i < 100; i++) { res |= test8(i); } Asserts.assertEQ(-1, res); @@ -224,7 +218,7 @@ public class TestBitCompressValueTransform { @Run(test = "test9") public void run9(RunInfo info) { int res = 0; - for (int i = -10000; i < 10000; i++) { + for (int i = -100; i < 100; i++) { res |= test9(i); } Asserts.assertLTE(0, res); @@ -243,10 +237,10 @@ public class TestBitCompressValueTransform { @Run(test = "test10") public void run10(RunInfo info) { int res = Integer.MIN_VALUE; - for (int i = -10000; i < 10000; i++) { + for (int i = -100; i < 100; i++) { res = Integer.max(test10(i), res); } - Asserts.assertGTE(10000, res); + Asserts.assertGTE(100, res); } @Test @@ -260,7 +254,7 @@ public class TestBitCompressValueTransform { @Run(test = "test11") public void run11(RunInfo info) { int res = 0; - for (int i = -10000; i < 10000; i++) { + for (int i = -100; i < 100; i++) { res |= test11(i); } Asserts.assertEQ(0, res); @@ -277,7 +271,7 @@ public class TestBitCompressValueTransform { @Run(test = "test12") public void run12(RunInfo info) { long res = 0; - for (int i = -10000; i < 10000; i++) { + for (int i = -100; i < 100; i++) { res |= test12(i); } Asserts.assertEQ(0L, res); @@ -294,7 +288,7 @@ public class TestBitCompressValueTransform { @Run(test = "test13") public void run13(RunInfo info) { int res = 0; - for (int i = -10000; i < 10000; i++) { + for (int i = -100; i < 100; i++) { res |= test13(i); } Asserts.assertEQ(0, res); @@ -311,7 +305,7 @@ public class TestBitCompressValueTransform { @Run(test = "test14") public void run14(RunInfo info) { long res = 0; - for (int i = -10000; i < 10000; i++) { + for (int i = -100; i < 100; i++) { res |= test14(i); } Asserts.assertEQ(0L, res); @@ -327,10 +321,7 @@ public class TestBitCompressValueTransform { @Run (test = "test15") public void run15(RunInfo info) { - int res = 0; - for (int i = 0; i < 10000; i++) { - res |= test15(0, 0); - } + int res = test15(0, 0); Asserts.assertEQ(0, res); } @@ -408,7 +399,7 @@ public class TestBitCompressValueTransform { int actual = 0; int expected = 0; - for (int i = 0; i < 10000; i++) { + for (int i = 0; i < 100; i++) { int arg1 = GEN_I.next(); int arg2 = GEN_I.next(); @@ -492,7 +483,7 @@ public class TestBitCompressValueTransform { int actual = 0; int expected = 0; - for (int i = 0; i < 10000; i++) { + for (int i = 0; i < 100; i++) { int arg1 = GEN_I.next(); int arg2 = GEN_I.next(); @@ -576,7 +567,7 @@ public class TestBitCompressValueTransform { long actual = 0; long expected = 0; - for (int i = 0; i < 10000; i++) { + for (int i = 0; i < 100; i++) { long arg1 = GEN_L.next(); long arg2 = GEN_L.next(); @@ -660,7 +651,7 @@ public class TestBitCompressValueTransform { long actual = 0; long expected = 0; - for (int i = 0; i < 10000; i++) { + for (int i = 0; i < 100; i++) { long arg1 = GEN_L.next(); long arg2 = GEN_L.next(); From 2bfada3f58df6c041d948267368cbc4db915cac3 Mon Sep 17 00:00:00 2001 From: jonghoonpark Date: Mon, 6 Oct 2025 11:53:14 +0000 Subject: [PATCH 031/160] 8364927: Add @requires annotation to TestReclaimStringsLeaksMemory.java Reviewed-by: tschatzl, stefank, ayang --- .../stress/TestReclaimStringsLeaksMemory.java | 49 +++++++++++++++++-- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/test/hotspot/jtreg/gc/stress/TestReclaimStringsLeaksMemory.java b/test/hotspot/jtreg/gc/stress/TestReclaimStringsLeaksMemory.java index 80ab9e21667..1f19222fb8e 100644 --- a/test/hotspot/jtreg/gc/stress/TestReclaimStringsLeaksMemory.java +++ b/test/hotspot/jtreg/gc/stress/TestReclaimStringsLeaksMemory.java @@ -24,19 +24,60 @@ package gc.stress; /* - * @test TestReclaimStringsLeaksMemory + * @test id=Serial * @bug 8180048 - * @summary Ensure that during a Full GC interned string memory is reclaimed completely. - * @requires vm.gc == "null" + * @summary Ensure that during a Full GC interned string memory is reclaimed completely with SerialGC. + * @requires vm.gc.Serial * @requires !vm.debug * @library /test/lib * @modules java.base/jdk.internal.misc - * @run driver/timeout=480 gc.stress.TestReclaimStringsLeaksMemory * @run driver/timeout=480 gc.stress.TestReclaimStringsLeaksMemory -XX:+UseSerialGC + */ + +/* + * @test id=Parallel + * @bug 8180048 + * @summary Ensure that during a Full GC interned string memory is reclaimed completely with ParallelGC. + * @requires vm.gc.Parallel + * @requires !vm.debug + * @library /test/lib + * @modules java.base/jdk.internal.misc * @run driver/timeout=480 gc.stress.TestReclaimStringsLeaksMemory -XX:+UseParallelGC + */ + +/* + * @test id=G1 + * @bug 8180048 + * @summary Ensure that during a Full GC interned string memory is reclaimed completely with G1GC. + * @requires vm.gc.G1 + * @requires !vm.debug + * @library /test/lib + * @modules java.base/jdk.internal.misc * @run driver/timeout=480 gc.stress.TestReclaimStringsLeaksMemory -XX:+UseG1GC */ +/* + * @test id=Shenandoah + * @bug 8180048 + * @summary Ensure that during a Full GC interned string memory is reclaimed completely with ShenandoahGC. + * @requires vm.gc.Shenandoah + * @requires !vm.debug + * @library /test/lib + * @modules java.base/jdk.internal.misc + * @run driver/timeout=480 gc.stress.TestReclaimStringsLeaksMemory -XX:+UseShenandoahGC + */ + +/* + * @test id=Z + * @bug 8180048 + * @summary Ensure that during a Full GC interned string memory is reclaimed completely with ZGC. + * @requires vm.gc.Z + * @requires !vm.debug + * @library /test/lib + * @modules java.base/jdk.internal.misc + * @run driver/timeout=480 gc.stress.TestReclaimStringsLeaksMemory -XX:+UseZGC + */ + import java.util.Arrays; import java.util.ArrayList; import java.util.regex.Pattern; From e3320a9df592a06c466ae9158d8f173921679952 Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Mon, 6 Oct 2025 13:32:46 +0000 Subject: [PATCH 032/160] 8367610: Test tools/sincechecker/modules/java.base/JavaBaseCheckSince.java timed out on Windows Reviewed-by: liach --- .../sincechecker/modules/java.base/JavaBaseCheckSince.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/jdk/tools/sincechecker/modules/java.base/JavaBaseCheckSince.java b/test/jdk/tools/sincechecker/modules/java.base/JavaBaseCheckSince.java index 64d5bf2465f..b75b6d9401a 100644 --- a/test/jdk/tools/sincechecker/modules/java.base/JavaBaseCheckSince.java +++ b/test/jdk/tools/sincechecker/modules/java.base/JavaBaseCheckSince.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,8 +23,8 @@ /* * @test - * @bug 8331051 + * @bug 8331051 8367610 * @summary Test for `@since` in java.base module * @library /test/lib /test/jdk/tools/sincechecker - * @run main SinceChecker java.base --exclude java.lang.classfile + * @run main/timeout=480 SinceChecker java.base --exclude java.lang.classfile */ From b6a4cfecb731615b6ef70828ac10fae4b2264cdc Mon Sep 17 00:00:00 2001 From: Mahendra Chhipa Date: Mon, 6 Oct 2025 15:26:59 +0000 Subject: [PATCH 033/160] 8367114: Update jdk.test.lib.net.SimpleHttpServer to use SimpleFileServer Reviewed-by: dfuchs, vyazici --- .../catalog/CatalogFileInputTest.java | 27 +++- .../sun/net/httpserver/SimpleFileServer.java | 71 -------- .../mrjar/MultiReleaseJarHttpProperties.java | 27 ++-- .../jar/MultiReleaseJarURLConnection.java | 27 ++-- .../jdk/test/lib/net/SimpleHttpServer.java | 152 ------------------ 5 files changed, 53 insertions(+), 251 deletions(-) delete mode 100644 test/jdk/com/sun/net/httpserver/SimpleFileServer.java delete mode 100644 test/lib/jdk/test/lib/net/SimpleHttpServer.java diff --git a/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogFileInputTest.java b/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogFileInputTest.java index 66ddad86785..9a19c0237d7 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogFileInputTest.java +++ b/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogFileInputTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,6 +38,8 @@ import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import javax.xml.catalog.Catalog; import javax.xml.catalog.CatalogException; @@ -49,6 +51,9 @@ import static java.nio.file.StandardOpenOption.APPEND; import static java.nio.file.StandardOpenOption.CREATE; import static jaxp.library.JAXPTestUtilities.getSystemProperty; +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.SimpleFileServer; +import jdk.test.lib.net.URIBuilder; import jdk.test.lib.util.JarUtils; import org.testng.Assert; import org.testng.annotations.AfterClass; @@ -56,13 +61,11 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import org.xml.sax.InputSource; -import jdk.test.lib.net.SimpleHttpServer; /* * @test * @bug 8151154 8171243 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest /test/lib - * @build jdk.test.lib.net.SimpleHttpServer * @run testng/othervm catalog.CatalogFileInputTest * @summary Verifies that the Catalog API accepts valid URIs only; * Verifies that the CatalogFeatures' builder throws @@ -81,9 +84,9 @@ public class CatalogFileInputTest extends CatalogSupportBase { final static String SCHEME_JARFILE = "jar:"; static final String REMOTE_FILE_LOCATION = "/jar/META-INF"; static final String DOCROOT = SRC_DIR; - static final String TESTCONTEXT = REMOTE_FILE_LOCATION; //mapped to local file path - private SimpleHttpServer httpserver; + private HttpServer httpserver; private String remoteFilePath; + private ExecutorService executor; /* * Initializing fields @@ -92,15 +95,23 @@ public class CatalogFileInputTest extends CatalogSupportBase { public void setUpClass() throws Exception { super.setUp(); // set up HttpServer - httpserver = new SimpleHttpServer(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), TESTCONTEXT, DOCROOT); + httpserver = SimpleFileServer.createFileServer(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), + Path.of(DOCROOT), SimpleFileServer.OutputLevel.INFO); + executor = Executors.newCachedThreadPool(); + httpserver.setExecutor(executor); httpserver.start(); - remoteFilePath = httpserver.getAddress() + REMOTE_FILE_LOCATION; + remoteFilePath = URIBuilder.newBuilder() + .scheme("http") + .host(httpserver.getAddress().getAddress()) + .port(httpserver.getAddress().getPort()) + .build().toString() + REMOTE_FILE_LOCATION; } @AfterClass protected void tearDown() { if (httpserver != null) { - httpserver.stop(); + httpserver.stop(0); + executor.shutdown(); } } diff --git a/test/jdk/com/sun/net/httpserver/SimpleFileServer.java b/test/jdk/com/sun/net/httpserver/SimpleFileServer.java deleted file mode 100644 index bff415c0b98..00000000000 --- a/test/jdk/com/sun/net/httpserver/SimpleFileServer.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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.util.concurrent.*; -import java.util.logging.*; -import java.io.*; -import java.net.*; - -import com.sun.net.httpserver.*; - -/** - * Implements a basic static content HTTP server - * which understands text/html, text/plain content types - * - * Must be given an abs pathname to the document root. - * Directory listings together with text + html files - * can be served. - * - * File Server created on files sub-path - * - * Echo server created on echo sub-path - */ -public class SimpleFileServer { - - public static void main (String[] args) throws Exception { - if (args.length != 3) { - System.out.println ("usage: java FileServerHandler rootDir port logfilename"); - System.exit(1); - } - Logger logger = Logger.getLogger("com.sun.net.httpserver"); - ConsoleHandler ch = new ConsoleHandler(); - logger.setLevel(Level.ALL); - ch.setLevel(Level.ALL); - logger.addHandler(ch); - - String rootDir = args[0]; - int port = Integer.parseInt (args[1]); - String logfile = args[2]; - HttpServer server = HttpServer.create (new InetSocketAddress (port), 0); - HttpHandler h = new FileServerHandler (rootDir); - HttpHandler h1 = new EchoHandler (); - - HttpContext c = server.createContext ("/files", h); - c.getFilters().add (new LogFilter (new File (logfile))); - HttpContext c1 = server.createContext ("/echo", h1); - c.getFilters().add (new LogFilter (new File (logfile))); - c1.getFilters().add (new LogFilter (new File (logfile))); - server.setExecutor (Executors.newCachedThreadPool()); - server.start (); - } -} diff --git a/test/jdk/java/util/jar/JarFile/mrjar/MultiReleaseJarHttpProperties.java b/test/jdk/java/util/jar/JarFile/mrjar/MultiReleaseJarHttpProperties.java index 93cf0e0165d..16f764c6674 100644 --- a/test/jdk/java/util/jar/JarFile/mrjar/MultiReleaseJarHttpProperties.java +++ b/test/jdk/java/util/jar/JarFile/mrjar/MultiReleaseJarHttpProperties.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,9 +28,7 @@ * @library /lib/testlibrary/java/util/jar /test/lib * @modules jdk.jartool * jdk.compiler - * jdk.httpserver * @build CreateMultiReleaseTestJars - * jdk.test.lib.net.SimpleHttpServer * jdk.test.lib.compiler.Compiler * jdk.test.lib.util.JarBuilder * @run testng MultiReleaseJarHttpProperties @@ -51,21 +49,28 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.URL; import java.net.URLClassLoader; +import java.nio.file.Path; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; -import jdk.test.lib.net.SimpleHttpServer; +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.SimpleFileServer; import jdk.test.lib.net.URIBuilder; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class MultiReleaseJarHttpProperties extends MultiReleaseJarProperties { - private SimpleHttpServer server; + private HttpServer server; + private ExecutorService executor; static final String TESTCONTEXT = "/multi-release.jar"; //mapped to local file path @BeforeClass public void initialize() throws Exception { - server = new SimpleHttpServer(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), TESTCONTEXT, - System.getProperty("user.dir", ".")); + server = SimpleFileServer.createFileServer(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), + Path.of(System.getProperty("user.dir", ".")), SimpleFileServer.OutputLevel.INFO); + executor = Executors.newCachedThreadPool(); + server.setExecutor(executor); server.start(); super.initialize(); } @@ -73,7 +78,7 @@ public class MultiReleaseJarHttpProperties extends MultiReleaseJarProperties { @Override protected void initializeClassLoader() throws Exception { URL[] urls = new URL[]{ - URIBuilder.newBuilder().scheme("http").port(server.getPort()).loopback() + URIBuilder.newBuilder().scheme("http").port(server.getAddress().getPort()).loopback() .path(TESTCONTEXT).toURL(), }; cldr = new URLClassLoader(urls); @@ -84,8 +89,10 @@ public class MultiReleaseJarHttpProperties extends MultiReleaseJarProperties { @AfterClass public void close() throws IOException { // Windows requires server to stop before file is deleted - if (server != null) - server.stop(); + if (server != null) { + server.stop(0); + executor.shutdown(); + } super.close(); } diff --git a/test/jdk/sun/net/www/protocol/jar/MultiReleaseJarURLConnection.java b/test/jdk/sun/net/www/protocol/jar/MultiReleaseJarURLConnection.java index 2d5ba81194f..f113e7d3fcd 100644 --- a/test/jdk/sun/net/www/protocol/jar/MultiReleaseJarURLConnection.java +++ b/test/jdk/sun/net/www/protocol/jar/MultiReleaseJarURLConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,10 +27,8 @@ * @summary Test that URL connections to multi-release jars can be runtime versioned * @library /lib/testlibrary/java/util/jar /test/lib * @modules jdk.compiler - * jdk.httpserver * jdk.jartool * @build CreateMultiReleaseTestJars - * jdk.test.lib.net.SimpleHttpServer * jdk.test.lib.util.JarBuilder * jdk.test.lib.compiler.Compiler * @run testng MultiReleaseJarURLConnection @@ -51,11 +49,15 @@ import java.net.URL; import java.net.URLClassLoader; import java.net.URLConnection; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import java.util.Enumeration; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.jar.JarFile; -import jdk.test.lib.net.SimpleHttpServer; +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.SimpleFileServer; import jdk.test.lib.net.URIBuilder; import org.testng.Assert; import org.testng.annotations.AfterClass; @@ -68,8 +70,8 @@ public class MultiReleaseJarURLConnection { String unversioned = userdir + "/unversioned.jar"; String unsigned = userdir + "/multi-release.jar"; String signed = userdir + "/signed-multi-release.jar"; - static final String TESTCONTEXT = "/multi-release.jar"; - SimpleHttpServer server; + HttpServer server; + ExecutorService executor; @BeforeClass public void initialize() throws Exception { @@ -78,7 +80,10 @@ public class MultiReleaseJarURLConnection { creator.buildUnversionedJar(); creator.buildMultiReleaseJar(); creator.buildSignedMultiReleaseJar(); - server = new SimpleHttpServer(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), TESTCONTEXT, System.getProperty("user.dir", ".")); + server = SimpleFileServer.createFileServer(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), + Path.of(System.getProperty("user.dir", ".")), SimpleFileServer.OutputLevel.INFO); + executor = Executors.newCachedThreadPool(); + server.setExecutor(executor); server.start(); } @@ -86,7 +91,9 @@ public class MultiReleaseJarURLConnection { public void close() throws IOException { // Windows requires server to stop before file is deleted if (server != null) - server.stop(); + server.stop(0); + executor.shutdown(); + Files.delete(Paths.get(unversioned)); Files.delete(Paths.get(unsigned)); Files.delete(Paths.get(signed)); @@ -176,8 +183,8 @@ public class MultiReleaseJarURLConnection { {"unsigned", new URL("jar:file:" + unsigned + "!/")}, {"signed", new URL("jar:file:" + signed + "!/")}, // external jar received via http protocol - {"http", toHttpJarURL(server.getPort(), "/multi-release.jar", "!/")}, - {"http", URIBuilder.newBuilder().scheme("http").port(server.getPort()) + {"http", toHttpJarURL(server.getAddress().getPort(), "/multi-release.jar", "!/")}, + {"http", URIBuilder.newBuilder().scheme("http").port(server.getAddress().getPort()) .loopback().path("/multi-release.jar").toURL()}, }; } diff --git a/test/lib/jdk/test/lib/net/SimpleHttpServer.java b/test/lib/jdk/test/lib/net/SimpleHttpServer.java deleted file mode 100644 index 1905091eac6..00000000000 --- a/test/lib/jdk/test/lib/net/SimpleHttpServer.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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.test.lib.net; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetSocketAddress; -import java.net.URI; -import java.net.URISyntaxException; -import java.nio.file.FileSystemNotFoundException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -import com.sun.net.httpserver.Headers; -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; -import com.sun.net.httpserver.HttpServer; - -/** - * A simple HTTP Server. - **/ -public class SimpleHttpServer { - private final HttpServer httpServer; - private ExecutorService executor; - private String address; - private final String context; - private final String docRoot; - private final InetSocketAddress inetSocketAddress; - - public SimpleHttpServer(final InetSocketAddress inetSocketAddress, final String context, final String docRoot) - throws IOException { - this.inetSocketAddress = inetSocketAddress; - this.context = context; - this.docRoot = docRoot; - httpServer = HttpServer.create(); - } - - public void start() throws IOException, URISyntaxException { - MyHttpHandler handler = new MyHttpHandler(docRoot); - httpServer.bind(inetSocketAddress, 0); - httpServer.createContext(context, handler); - executor = Executors.newCachedThreadPool(); - httpServer.setExecutor(executor); - httpServer.start(); - address = "http:" + URIBuilder.newBuilder().host(httpServer.getAddress().getAddress()). - port(httpServer.getAddress().getPort()).build().toString(); - } - - public void stop() { - httpServer.stop(0); - executor.shutdown(); - } - - public String getAddress() { - return address; - } - - public int getPort() { - return httpServer.getAddress().getPort(); - } - - class MyHttpHandler implements HttpHandler { - private final URI rootUri; - - MyHttpHandler(final String docroot) { - rootUri = Path.of(docroot).toUri().normalize(); - } - - public void handle(final HttpExchange t) throws IOException { - try (InputStream is = t.getRequestBody()) { - is.readAllBytes(); - Headers rMap = t.getResponseHeaders(); - try (OutputStream os = t.getResponseBody()) { - URI uri = t.getRequestURI(); - String path = uri.getRawPath(); - assert path.isEmpty() || path.startsWith("/"); - Path fPath; - try { - uri = URI.create("file://" + rootUri.getRawPath() + path).normalize(); - fPath = Path.of(uri); - } catch (IllegalArgumentException | FileSystemNotFoundException ex) { - ex.printStackTrace(); - notfound(t, path); - return; - } - byte[] bytes = Files.readAllBytes(fPath); - String method = t.getRequestMethod(); - if (method.equals("HEAD")) { - rMap.set("Content-Length", Long.toString(bytes.length)); - t.sendResponseHeaders(200, -1); - t.close(); - } else if (!method.equals("GET")) { - t.sendResponseHeaders(405, -1); - t.close(); - return; - } - if (path.endsWith(".html") || path.endsWith(".htm")) { - rMap.set("Content-Type", "text/html"); - } else { - rMap.set("Content-Type", "text/plain"); - } - t.sendResponseHeaders(200, bytes.length); - os.write(bytes); - } - } - } - void moved(final HttpExchange t) throws IOException { - Headers req = t.getRequestHeaders(); - Headers map = t.getResponseHeaders(); - URI uri = t.getRequestURI(); - String host = req.getFirst("Host"); - String location = "http://" + host + uri.getPath() + "/"; - map.set("Content-Type", "text/html"); - map.set("Location", location); - t.sendResponseHeaders(301, -1); - t.close(); - } - void notfound(final HttpExchange t, final String p) throws IOException { - t.getResponseHeaders().set("Content-Type", "text/html"); - t.sendResponseHeaders(404, 0); - try (OutputStream os = t.getResponseBody()) { - String s = "

File not found

"; - s = s + p + "

"; - os.write(s.getBytes()); - } - t.close(); - } - } -} From 596af0a7cc37e359d54689be20f855a86ae46567 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 6 Oct 2025 15:44:13 +0000 Subject: [PATCH 034/160] 8369041: Release memory after testing in ThreadsRunner.java Reviewed-by: shade, tschatzl --- .../jtreg/vmTestbase/nsk/share/runner/ThreadsRunner.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/runner/ThreadsRunner.java b/test/hotspot/jtreg/vmTestbase/nsk/share/runner/ThreadsRunner.java index 0401fea13fc..39e7e2c2237 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/runner/ThreadsRunner.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/runner/ThreadsRunner.java @@ -310,6 +310,10 @@ public class ThreadsRunner implements MultiRunner, LogAware, RunParamsAware { log.info("Unexpected exception during the run."); log.info(t); successful = false; + } finally { + // Finished testing; release memory to avoid OOM. + runnables.clear(); + threads.clear(); } } From 0f406c420e35f7a4358dc99711fd23d162f21777 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Mon, 6 Oct 2025 16:11:59 +0000 Subject: [PATCH 035/160] 8369078: Fix faulty test conversion in IllegalCharsetName.java Reviewed-by: naoto, alanb --- test/jdk/java/nio/charset/Charset/IllegalCharsetName.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/jdk/java/nio/charset/Charset/IllegalCharsetName.java b/test/jdk/java/nio/charset/Charset/IllegalCharsetName.java index 266801cf52b..9f2879a3ff0 100644 --- a/test/jdk/java/nio/charset/Charset/IllegalCharsetName.java +++ b/test/jdk/java/nio/charset/Charset/IllegalCharsetName.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,7 @@ public class IllegalCharsetName { assertThrows(IllegalCharsetNameException.class, () -> Charset.forName(name)); assertThrows(IllegalCharsetNameException.class, - () -> Charset.forName(name)); + () -> Charset.isSupported(name)); } // Charset.forName, Charset.isSupported, and the Charset constructor should @@ -60,7 +60,7 @@ public class IllegalCharsetName { assertThrows(IllegalCharsetNameException.class, () -> Charset.forName("")); assertThrows(IllegalCharsetNameException.class, - () -> Charset.forName("")); + () -> Charset.isSupported("")); assertThrows(IllegalCharsetNameException.class, () -> new Charset("", new String[]{}) { @Override From 2376a9e9727e9cb3020dd3f57584950a4cdcdab6 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Mon, 6 Oct 2025 17:30:42 +0000 Subject: [PATCH 036/160] 8365630: jdk/jfr/tool/TestPrintContextual.java fails with wrong spanId Reviewed-by: shade --- test/jdk/jdk/jfr/tool/TestPrintContextual.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/test/jdk/jdk/jfr/tool/TestPrintContextual.java b/test/jdk/jdk/jfr/tool/TestPrintContextual.java index 15486148b9c..e6df9c7c729 100644 --- a/test/jdk/jdk/jfr/tool/TestPrintContextual.java +++ b/test/jdk/jdk/jfr/tool/TestPrintContextual.java @@ -25,6 +25,7 @@ package jdk.jfr.tool; import java.nio.file.Files; import java.nio.file.Path; +import java.time.Instant; import java.util.AbstractMap; import java.util.ArrayList; import java.util.List; @@ -264,7 +265,8 @@ public class TestPrintContextual { } } - private static void span(int depth) { + private static void span(int depth) throws InterruptedException { + awaitUniqueTimestamp(); SpanEvent span = new SpanEvent(); span.name = "span"; span.spanId = depth; @@ -277,6 +279,13 @@ public class TestPrintContextual { span.commit(); } + private static void awaitUniqueTimestamp() throws InterruptedException { + Instant timestamp = Instant.now(); + while (timestamp.equals(Instant.now())) { + Thread.sleep(1); + } + } + // Tests that context values are only inhjected into events in the same thread. private static void testThreadedContext() throws Exception { try (Recording r = new Recording()) { From eb34a117934951af075a425ce2cf8d3b1ced9700 Mon Sep 17 00:00:00 2001 From: Mikael Vidstedt Date: Tue, 7 Oct 2025 00:52:38 +0000 Subject: [PATCH 037/160] 8369242: Rename URL variables in devkit/Tools.gmk Reviewed-by: erikj --- make/devkit/Tools.gmk | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/make/devkit/Tools.gmk b/make/devkit/Tools.gmk index f27d47b822c..6241674071c 100644 --- a/make/devkit/Tools.gmk +++ b/make/devkit/Tools.gmk @@ -117,13 +117,13 @@ dependencies := gcc binutils ccache mpfr gmp mpc gdb $(foreach dep,$(dependencies),$(eval $(dep)_ver := $(dep)-$($(dep)_ver_only))) -GCC := http://ftp.gnu.org/pub/gnu/gcc/$(gcc_ver)/$(gcc_ver).tar.xz -BINUTILS := http://ftp.gnu.org/pub/gnu/binutils/$(binutils_ver).tar.gz -CCACHE := https://github.com/ccache/ccache/releases/download/v$(ccache_ver_only)/$(ccache_ver).tar.xz -MPFR := https://www.mpfr.org/$(mpfr_ver)/$(mpfr_ver).tar.bz2 -GMP := http://ftp.gnu.org/pub/gnu/gmp/$(gmp_ver).tar.bz2 -MPC := http://ftp.gnu.org/pub/gnu/mpc/$(mpc_ver).tar.gz -GDB := http://ftp.gnu.org/gnu/gdb/$(gdb_ver).tar.xz +GCC_URL := http://ftp.gnu.org/pub/gnu/gcc/$(gcc_ver)/$(gcc_ver).tar.xz +BINUTILS_URL := http://ftp.gnu.org/pub/gnu/binutils/$(binutils_ver).tar.gz +CCACHE_URL := https://github.com/ccache/ccache/releases/download/v$(ccache_ver_only)/$(ccache_ver).tar.xz +MPFR_URL := https://www.mpfr.org/$(mpfr_ver)/$(mpfr_ver).tar.bz2 +GMP_URL := http://ftp.gnu.org/pub/gnu/gmp/$(gmp_ver).tar.bz2 +MPC_URL := http://ftp.gnu.org/pub/gnu/mpc/$(mpc_ver).tar.gz +GDB_URL := http://ftp.gnu.org/gnu/gdb/$(gdb_ver).tar.xz REQUIRED_MIN_MAKE_MAJOR_VERSION := 4 ifneq ($(REQUIRED_MIN_MAKE_MAJOR_VERSION),) @@ -201,7 +201,7 @@ download-rpms: # Generate downloading + unpacking of sources. define Download # Allow override - $(1)_DIRNAME ?= $(basename $(basename $(notdir $($(1))))) + $(1)_DIRNAME ?= $(basename $(basename $(notdir $($(1)_URL)))) $(1)_DIR = $(abspath $(SRCDIR)/$$($(1)_DIRNAME)) ifeq ($$($(1)_CMAKE_BASED),) $(1)_CFG = $$($(1)_DIR)/configure @@ -212,7 +212,7 @@ define Download $(1)_SRC_MARKER = $$($(1)_DIR)/CMakeLists.txt $(1)_CONFIG = $$(CMAKE_CONFIG) $$($(1)_DIR) endif - $(1)_FILE = $(DOWNLOAD)/$(notdir $($(1))) + $(1)_FILE = $(DOWNLOAD)/$(notdir $($(1)_URL)) $$($(1)_SRC_MARKER) : $$($(1)_FILE) mkdir -p $$(SRCDIR) @@ -224,7 +224,7 @@ define Download touch $$@ $$($(1)_FILE) : - wget -P $(DOWNLOAD) $$($(1)) + wget -P $(DOWNLOAD) $$($(1)_URL) endef # Download and unpack all source packages From e783c524c17e1d1a3fff4b6370e222134e66edc8 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Tue, 7 Oct 2025 04:08:32 +0000 Subject: [PATCH 038/160] 8368185: Test javax/swing/plaf/synth/SynthButtonUI/6276188/bug6276188.java failed: Synth ButtonUI does not handle PRESSED & MOUSE_OVER state Reviewed-by: tr, aivanov --- .../SynthButtonUI/6276188/bug6276188.java | 51 +++++++++++++------ 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/test/jdk/javax/swing/plaf/synth/SynthButtonUI/6276188/bug6276188.java b/test/jdk/javax/swing/plaf/synth/SynthButtonUI/6276188/bug6276188.java index be9c9457fff..9b689d2fe2c 100644 --- a/test/jdk/javax/swing/plaf/synth/SynthButtonUI/6276188/bug6276188.java +++ b/test/jdk/javax/swing/plaf/synth/SynthButtonUI/6276188/bug6276188.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,40 +21,53 @@ * questions. */ /** - * @test 1.4 08/08/05 + * @test * @key headful * @bug 6276188 * @library ../../../../regtesthelpers * @build Util - * @author Romain Guy * @summary Tests PRESSED and MOUSE_OVER and FOCUSED state for buttons with Synth. * @run main/othervm -Dsun.java2d.uiScale=1 bug6276188 */ -import java.awt.*; -import java.awt.image.*; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.plaf.synth.*; +import java.io.File; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.image.BufferedImage; +import java.awt.event.InputEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import javax.imageio.ImageIO; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.plaf.synth.SynthLookAndFeel; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import java.util.concurrent.CountDownLatch; public class bug6276188 { private static JButton button; - private static Point p; private static JFrame testFrame; // move away from cursor - private final static int OFFSET_X = -20; - private final static int OFFSET_Y = -20; + private final static int OFFSET_X = 20; + private final static int OFFSET_Y = 20; public static void main(String[] args) throws Throwable { + Robot robot = new Robot(); try { - Robot robot = new Robot(); robot.setAutoDelay(100); SynthLookAndFeel lookAndFeel = new SynthLookAndFeel(); lookAndFeel.load(bug6276188.class.getResourceAsStream("bug6276188.xml"), bug6276188.class); UIManager.setLookAndFeel(lookAndFeel); + CountDownLatch latch = new CountDownLatch(1); SwingUtilities.invokeAndWait(new Runnable() { public void run() { @@ -62,6 +75,13 @@ public class bug6276188 { testFrame.setLayout(new BorderLayout()); testFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); testFrame.add(BorderLayout.CENTER, button = new JButton()); + button.addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + System.out.println("Mouse pressed"); + latch.countDown(); + } + }); testFrame.setSize(new Dimension(320, 200)); testFrame.setLocationRelativeTo(null); @@ -72,13 +92,14 @@ public class bug6276188 { robot.waitForIdle(); robot.delay(1000); - p = Util.getCenterPoint(button); + Point p = Util.getCenterPoint(button); System.out.println("Button center point: " + p); robot.mouseMove(p.x , p.y); robot.waitForIdle(); robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); - robot.waitForIdle(); + latch.await(); + robot.delay(1000); Color color = robot.getPixelColor(p.x - OFFSET_X, p.y - OFFSET_Y); robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); @@ -89,7 +110,7 @@ public class bug6276188 { Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); Rectangle screen = new Rectangle(0, 0, (int) screenSize.getWidth(), (int) screenSize.getHeight()); BufferedImage img = robot.createScreenCapture(screen); - javax.imageio.ImageIO.write(img, "png", new java.io.File("image.png")); + ImageIO.write(img, "png", new File("image.png")); throw new RuntimeException("Synth ButtonUI does not handle PRESSED & MOUSE_OVER state"); } } finally { From 07549f3e1539a2dd491a4f9ffe9df8580d7d7dea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Maillard?= Date: Tue, 7 Oct 2025 07:43:43 +0000 Subject: [PATCH 039/160] 8360389: Support printing from C2 compiled code Reviewed-by: kvn, thartmann, mhaessig --- src/hotspot/share/opto/compile.cpp | 155 ++++++++++++++++++++ src/hotspot/share/opto/compile.hpp | 22 +++ src/hotspot/share/opto/runtime.cpp | 56 +++++++ src/hotspot/share/opto/runtime.hpp | 10 ++ src/hotspot/share/runtime/sharedRuntime.cpp | 40 +++++ src/hotspot/share/runtime/sharedRuntime.hpp | 34 +++++ 6 files changed, 317 insertions(+) diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 7f63efe9e5e..6babc13e1b3 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -5378,3 +5378,158 @@ Node* Compile::narrow_value(BasicType bt, Node* value, const Type* type, PhaseGV void Compile::record_method_not_compilable_oom() { record_method_not_compilable(CompilationMemoryStatistic::failure_reason_memlimit()); } + +#ifndef PRODUCT +// Collects all the control inputs from nodes on the worklist and from their data dependencies +static void find_candidate_control_inputs(Unique_Node_List& worklist, Unique_Node_List& candidates) { + // Follow non-control edges until we reach CFG nodes + for (uint i = 0; i < worklist.size(); i++) { + const Node* n = worklist.at(i); + for (uint j = 0; j < n->req(); j++) { + Node* in = n->in(j); + if (in == nullptr || in->is_Root()) { + continue; + } + if (in->is_CFG()) { + if (in->is_Call()) { + // The return value of a call is only available if the call did not result in an exception + Node* control_proj_use = in->as_Call()->proj_out(TypeFunc::Control)->unique_out(); + if (control_proj_use->is_Catch()) { + Node* fall_through = control_proj_use->as_Catch()->proj_out(CatchProjNode::fall_through_index); + candidates.push(fall_through); + continue; + } + } + + if (in->is_Multi()) { + // We got here by following data inputs so we should only have one control use + // (no IfNode, etc) + assert(!n->is_MultiBranch(), "unexpected node type: %s", n->Name()); + candidates.push(in->as_Multi()->proj_out(TypeFunc::Control)); + } else { + candidates.push(in); + } + } else { + worklist.push(in); + } + } + } +} + +// Returns the candidate node that is a descendant to all the other candidates +static Node* pick_control(Unique_Node_List& candidates) { + Unique_Node_List worklist; + worklist.copy(candidates); + + // Traverse backwards through the CFG + for (uint i = 0; i < worklist.size(); i++) { + const Node* n = worklist.at(i); + if (n->is_Root()) { + continue; + } + for (uint j = 0; j < n->req(); j++) { + // Skip backedge of loops to avoid cycles + if (n->is_Loop() && j == LoopNode::LoopBackControl) { + continue; + } + + Node* pred = n->in(j); + if (pred != nullptr && pred != n && pred->is_CFG()) { + worklist.push(pred); + // if pred is an ancestor of n, then pred is an ancestor to at least one candidate + candidates.remove(pred); + } + } + } + + assert(candidates.size() == 1, "unexpected control flow"); + return candidates.at(0); +} + +// Initialize a parameter input for a debug print call, using a placeholder for jlong and jdouble +static void debug_print_init_parm(Node* call, Node* parm, Node* half, int* pos) { + call->init_req((*pos)++, parm); + const BasicType bt = parm->bottom_type()->basic_type(); + if (bt == T_LONG || bt == T_DOUBLE) { + call->init_req((*pos)++, half); + } +} + +Node* Compile::make_debug_print_call(const char* str, address call_addr, PhaseGVN* gvn, + Node* parm0, Node* parm1, + Node* parm2, Node* parm3, + Node* parm4, Node* parm5, + Node* parm6) const { + Node* str_node = gvn->transform(new ConPNode(TypeRawPtr::make(((address) str)))); + const TypeFunc* type = OptoRuntime::debug_print_Type(parm0, parm1, parm2, parm3, parm4, parm5, parm6); + Node* call = new CallLeafNode(type, call_addr, "debug_print", TypeRawPtr::BOTTOM); + + // find the most suitable control input + Unique_Node_List worklist, candidates; + if (parm0 != nullptr) { worklist.push(parm0); + if (parm1 != nullptr) { worklist.push(parm1); + if (parm2 != nullptr) { worklist.push(parm2); + if (parm3 != nullptr) { worklist.push(parm3); + if (parm4 != nullptr) { worklist.push(parm4); + if (parm5 != nullptr) { worklist.push(parm5); + if (parm6 != nullptr) { worklist.push(parm6); + /* close each nested if ===> */ } } } } } } } + find_candidate_control_inputs(worklist, candidates); + Node* control = nullptr; + if (candidates.size() == 0) { + control = C->start()->proj_out(TypeFunc::Control); + } else { + control = pick_control(candidates); + } + + // find all the previous users of the control we picked + GrowableArray users_of_control; + for (DUIterator_Fast kmax, i = control->fast_outs(kmax); i < kmax; i++) { + Node* use = control->fast_out(i); + if (use->is_CFG() && use != control) { + users_of_control.push(use); + } + } + + // we do not actually care about IO and memory as it uses neither + call->init_req(TypeFunc::Control, control); + call->init_req(TypeFunc::I_O, top()); + call->init_req(TypeFunc::Memory, top()); + call->init_req(TypeFunc::FramePtr, C->start()->proj_out(TypeFunc::FramePtr)); + call->init_req(TypeFunc::ReturnAdr, top()); + + int pos = TypeFunc::Parms; + call->init_req(pos++, str_node); + if (parm0 != nullptr) { debug_print_init_parm(call, parm0, top(), &pos); + if (parm1 != nullptr) { debug_print_init_parm(call, parm1, top(), &pos); + if (parm2 != nullptr) { debug_print_init_parm(call, parm2, top(), &pos); + if (parm3 != nullptr) { debug_print_init_parm(call, parm3, top(), &pos); + if (parm4 != nullptr) { debug_print_init_parm(call, parm4, top(), &pos); + if (parm5 != nullptr) { debug_print_init_parm(call, parm5, top(), &pos); + if (parm6 != nullptr) { debug_print_init_parm(call, parm6, top(), &pos); + /* close each nested if ===> */ } } } } } } } + assert(call->in(call->req()-1) != nullptr, "must initialize all parms"); + + call = gvn->transform(call); + Node* call_control_proj = gvn->transform(new ProjNode(call, TypeFunc::Control)); + + // rewire previous users to have the new call as control instead + PhaseIterGVN* igvn = gvn->is_IterGVN(); + for (int i = 0; i < users_of_control.length(); i++) { + Node* use = users_of_control.at(i); + for (uint j = 0; j < use->req(); j++) { + if (use->in(j) == control) { + if (igvn != nullptr) { + igvn->replace_input_of(use, j, call_control_proj); + } else { + gvn->hash_delete(use); + use->set_req(j, call_control_proj); + gvn->hash_insert(use); + } + } + } + } + + return call; +} +#endif // !PRODUCT diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index a68da644d82..66a5497a7ad 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -1316,6 +1316,28 @@ public: BasicType out_bt, BasicType in_bt); static Node* narrow_value(BasicType bt, Node* value, const Type* type, PhaseGVN* phase, bool transform_res); + +#ifndef PRODUCT +private: + // getting rid of the template makes things easier + Node* make_debug_print_call(const char* str, address call_addr, PhaseGVN* gvn, + Node* parm0 = nullptr, Node* parm1 = nullptr, + Node* parm2 = nullptr, Node* parm3 = nullptr, + Node* parm4 = nullptr, Node* parm5 = nullptr, + Node* parm6 = nullptr) const; + +public: + // Creates a CallLeafNode for a runtime call that prints a static string and the values of the + // nodes passed as arguments. + // This function also takes care of doing the necessary wiring, including finding a suitable control + // based on the nodes that need to be printed. Note that passing nodes that have incompatible controls + // is undefined behavior. + template + Node* make_debug_print(const char* str, PhaseGVN* gvn, NN... in) { + address call_addr = CAST_FROM_FN_PTR(address, SharedRuntime::debug_print); + return make_debug_print_call(str, call_addr, gvn, in...); + } +#endif }; #endif // SHARE_OPTO_COMPILE_HPP diff --git a/src/hotspot/share/opto/runtime.cpp b/src/hotspot/share/opto/runtime.cpp index 072b1384921..9de9fe5da03 100644 --- a/src/hotspot/share/opto/runtime.cpp +++ b/src/hotspot/share/opto/runtime.cpp @@ -1780,6 +1780,62 @@ static const TypeFunc* make_osr_end_Type() { return TypeFunc::make(domain, range); } +#ifndef PRODUCT +static void debug_print_convert_type(const Type** fields, int* argp, Node *parm) { + const BasicType bt = parm->bottom_type()->basic_type(); + fields[(*argp)++] = Type::get_const_basic_type(bt); + if (bt == T_LONG || bt == T_DOUBLE) { + fields[(*argp)++] = Type::HALF; + } +} + +static void update_arg_cnt(const Node* parm, int* arg_cnt) { + (*arg_cnt)++; + const BasicType bt = parm->bottom_type()->basic_type(); + if (bt == T_LONG || bt == T_DOUBLE) { + (*arg_cnt)++; + } +} + +const TypeFunc* OptoRuntime::debug_print_Type(Node* parm0, Node* parm1, + Node* parm2, Node* parm3, + Node* parm4, Node* parm5, + Node* parm6) { + int argcnt = 1; + if (parm0 != nullptr) { update_arg_cnt(parm0, &argcnt); + if (parm1 != nullptr) { update_arg_cnt(parm1, &argcnt); + if (parm2 != nullptr) { update_arg_cnt(parm2, &argcnt); + if (parm3 != nullptr) { update_arg_cnt(parm3, &argcnt); + if (parm4 != nullptr) { update_arg_cnt(parm4, &argcnt); + if (parm5 != nullptr) { update_arg_cnt(parm5, &argcnt); + if (parm6 != nullptr) { update_arg_cnt(parm6, &argcnt); + /* close each nested if ===> */ } } } } } } } + + // create input type (domain) + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // static string pointer + + if (parm0 != nullptr) { debug_print_convert_type(fields, &argp, parm0); + if (parm1 != nullptr) { debug_print_convert_type(fields, &argp, parm1); + if (parm2 != nullptr) { debug_print_convert_type(fields, &argp, parm2); + if (parm3 != nullptr) { debug_print_convert_type(fields, &argp, parm3); + if (parm4 != nullptr) { debug_print_convert_type(fields, &argp, parm4); + if (parm5 != nullptr) { debug_print_convert_type(fields, &argp, parm5); + if (parm6 != nullptr) { debug_print_convert_type(fields, &argp, parm6); + /* close each nested if ===> */ } } } } } } } + + assert(argp == TypeFunc::Parms+argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms+argcnt, fields); + + // no result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms+0] = nullptr; // void + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms, fields); + return TypeFunc::make(domain, range); +} +#endif // PRODUCT + //------------------------------------------------------------------------------------- // register policy diff --git a/src/hotspot/share/opto/runtime.hpp b/src/hotspot/share/opto/runtime.hpp index 40e436c0d5c..76e69fd9d36 100644 --- a/src/hotspot/share/opto/runtime.hpp +++ b/src/hotspot/share/opto/runtime.hpp @@ -737,6 +737,16 @@ private: return _dtrace_object_alloc_Type; } +#ifndef PRODUCT + // Signature for runtime calls in debug printing nodes, which depends on which nodes are actually passed + // Note: we do not allow more than 7 node arguments as GraphKit::make_runtime_call only allows 8, and we need + // one for the static string + static const TypeFunc* debug_print_Type(Node* parm0 = nullptr, Node* parm1 = nullptr, + Node* parm2 = nullptr, Node* parm3 = nullptr, + Node* parm4 = nullptr, Node* parm5 = nullptr, + Node* parm6 = nullptr); +#endif // PRODUCT + private: static NamedCounter * volatile _named_counters; diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 85aeba361ff..a8c9a64d63a 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -264,6 +264,46 @@ void SharedRuntime::print_ic_miss_histogram() { tty->print_cr("Total IC misses: %7d", tot_misses); } } + +#ifdef COMPILER2 +// Runtime methods for printf-style debug nodes (same printing format as fieldDescriptor::print_on_for) +void SharedRuntime::debug_print_value(jboolean x) { + tty->print_cr("boolean %d", x); +} + +void SharedRuntime::debug_print_value(jbyte x) { + tty->print_cr("byte %d", x); +} + +void SharedRuntime::debug_print_value(jshort x) { + tty->print_cr("short %d", x); +} + +void SharedRuntime::debug_print_value(jchar x) { + tty->print_cr("char %c %d", isprint(x) ? x : ' ', x); +} + +void SharedRuntime::debug_print_value(jint x) { + tty->print_cr("int %d", x); +} + +void SharedRuntime::debug_print_value(jlong x) { + tty->print_cr("long " JLONG_FORMAT, x); +} + +void SharedRuntime::debug_print_value(jfloat x) { + tty->print_cr("float %f", x); +} + +void SharedRuntime::debug_print_value(jdouble x) { + tty->print_cr("double %lf", x); +} + +void SharedRuntime::debug_print_value(oopDesc* x) { + x->print(); +} +#endif // COMPILER2 + #endif // PRODUCT diff --git a/src/hotspot/share/runtime/sharedRuntime.hpp b/src/hotspot/share/runtime/sharedRuntime.hpp index 2a19b80c3b5..93cd92b3a32 100644 --- a/src/hotspot/share/runtime/sharedRuntime.hpp +++ b/src/hotspot/share/runtime/sharedRuntime.hpp @@ -32,6 +32,7 @@ #include "memory/allStatic.hpp" #include "memory/metaspaceClosure.hpp" #include "memory/resourceArea.hpp" +#include "runtime/safepointVerifiers.hpp" #include "runtime/stubInfo.hpp" #include "utilities/macros.hpp" @@ -635,6 +636,39 @@ class SharedRuntime: AllStatic { static void print_call_statistics(uint64_t comp_total); static void print_ic_miss_histogram(); +#ifdef COMPILER2 + // Runtime methods for printf-style debug nodes + static void debug_print_value(jboolean x); + static void debug_print_value(jbyte x); + static void debug_print_value(jshort x); + static void debug_print_value(jchar x); + static void debug_print_value(jint x); + static void debug_print_value(jlong x); + static void debug_print_value(jfloat x); + static void debug_print_value(jdouble x); + static void debug_print_value(oopDesc* x); + + template + static void debug_print_rec(T arg, Rest... args) { + debug_print_value(arg); + debug_print_rec(args...); + } + + static void debug_print_rec() {} + + // template is required here as we need to know the exact signature at compile-time + template + static void debug_print(const char *str, TT... args) { + // these three lines are the manual expansion of JRT_LEAF ... JRT_END, does not work well with templates + DEBUG_ONLY(NoHandleMark __hm;) + os::verify_stack_alignment(); + DEBUG_ONLY(NoSafepointVerifier __nsv;) + + tty->print_cr("%s", str); + debug_print_rec(args...); + } +#endif // COMPILER2 + #endif // PRODUCT static void print_statistics() PRODUCT_RETURN; From c06d6805aae3af2e6175f3f43deea46c9ce08bc6 Mon Sep 17 00:00:00 2001 From: Daniel Skantz Date: Tue, 7 Oct 2025 09:04:39 +0000 Subject: [PATCH 040/160] 8362394: C2: Repeated stacked string concatenation fails with "Hit MemLimit" and other resourcing errors Reviewed-by: chagedorn, rcastanedalo --- src/hotspot/share/opto/stringopts.cpp | 22 ++++- .../stringopts/TestStackedConcatsMany.java | 95 +++++++++++++++++++ 2 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 test/hotspot/jtreg/compiler/stringopts/TestStackedConcatsMany.java diff --git a/src/hotspot/share/opto/stringopts.cpp b/src/hotspot/share/opto/stringopts.cpp index 25aa82870c3..420423dd246 100644 --- a/src/hotspot/share/opto/stringopts.cpp +++ b/src/hotspot/share/opto/stringopts.cpp @@ -53,6 +53,11 @@ class StringConcat : public ResourceObj { Node_List _uncommon_traps; // Uncommon traps that needs to be rewritten // to restart at the initial JVMState. + static constexpr uint STACKED_CONCAT_UPPER_BOUND = 256; // argument limit for a merged concat. + // The value 256 was derived by measuring + // compilation time on variable length sequences + // of stackable concatenations and chosen to keep + // a safe margin to any critical point. public: // Mode for converting arguments to Strings enum { @@ -295,6 +300,8 @@ StringConcat* StringConcat::merge(StringConcat* other, Node* arg) { } assert(result->_control.contains(other->_end), "what?"); assert(result->_control.contains(_begin), "what?"); + + uint arguments_appended = 0; for (int x = 0; x < num_arguments(); x++) { Node* argx = argument_uncast(x); if (argx == arg) { @@ -303,8 +310,21 @@ StringConcat* StringConcat::merge(StringConcat* other, Node* arg) { for (int y = 0; y < other->num_arguments(); y++) { result->append(other->argument(y), other->mode(y)); } + arguments_appended += other->num_arguments(); } else { result->append(argx, mode(x)); + arguments_appended++; + } + // Check if this concatenation would result in an excessive number of arguments + // -- leading to high memory use, compilation time, and later, a large number of IR nodes + // -- and bail out in that case. + if (arguments_appended > STACKED_CONCAT_UPPER_BOUND) { +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + tty->print_cr("Merge candidate of length %d exceeds argument limit", arguments_appended); + } +#endif + return nullptr; } } result->set_allocation(other->_begin); @@ -680,7 +700,7 @@ PhaseStringOpts::PhaseStringOpts(PhaseGVN* gvn): #endif StringConcat* merged = sc->merge(other, arg); - if (merged->validate_control_flow() && merged->validate_mem_flow()) { + if (merged != nullptr && merged->validate_control_flow() && merged->validate_mem_flow()) { #ifndef PRODUCT AtomicAccess::inc(&_stropts_merged); if (PrintOptimizeStringConcat) { diff --git a/test/hotspot/jtreg/compiler/stringopts/TestStackedConcatsMany.java b/test/hotspot/jtreg/compiler/stringopts/TestStackedConcatsMany.java new file mode 100644 index 00000000000..dbc6e495594 --- /dev/null +++ b/test/hotspot/jtreg/compiler/stringopts/TestStackedConcatsMany.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8362394 + * @summary Test that repeated stacked string concatenations do not + * consume too many compilation resources. + * @requires vm.compiler2.enabled + * @library /test/lib / + * @run main/othervm -XX:-OptoScheduling compiler.stringopts.TestStackedConcatsMany + * @run main/othervm -XX:-TieredCompilation -Xcomp -XX:-OptoScheduling + * -XX:CompileOnly=compiler.stringopts.TestStackedConcatsMany::f + * compiler.stringopts.TestStackedConcatsMany + */ + +// The test uses -XX:-OptoScheduling to avoid the assert "too many D-U pinch points" on aarch64 (JDK-8328078). + +package compiler.stringopts; + +import jdk.test.lib.Asserts; + +public class TestStackedConcatsMany { + + public static void main (String... args) { + new StringBuilder(); // Trigger loading of the StringBuilder class. + String s = f(); + String z = "xy"; + for (int i = 0; i < 24; i++) { + z = z + z; + } + Asserts.assertEQ(s, z); + } + + static String f() { + String s = "xy"; + s = new StringBuilder().append(s).append(s).toString(); + s = new StringBuilder().append(s).append(s).toString(); + + s = new StringBuilder().append(s).append(s).toString(); + s = new StringBuilder().append(s).append(s).toString(); + + s = new StringBuilder().append(s).append(s).toString(); + s = new StringBuilder().append(s).append(s).toString(); + + s = new StringBuilder().append(s).append(s).toString(); + s = new StringBuilder().append(s).append(s).toString(); + + s = new StringBuilder().append(s).append(s).toString(); + s = new StringBuilder().append(s).append(s).toString(); + + s = new StringBuilder().append(s).append(s).toString(); + s = new StringBuilder().append(s).append(s).toString(); + + s = new StringBuilder().append(s).append(s).toString(); + s = new StringBuilder().append(s).append(s).toString(); + + s = new StringBuilder().append(s).append(s).toString(); + s = new StringBuilder().append(s).append(s).toString(); + + s = new StringBuilder().append(s).append(s).toString(); + s = new StringBuilder().append(s).append(s).toString(); + + s = new StringBuilder().append(s).append(s).toString(); + s = new StringBuilder().append(s).append(s).toString(); + + s = new StringBuilder().append(s).append(s).toString(); + s = new StringBuilder().append(s).append(s).toString(); + + s = new StringBuilder().append(s).append(s).toString(); + s = new StringBuilder().append(s).append(s).toString(); + + return s; + } +} From aed9485bbb1d93063e5e5f60ed84bfb36053bdd1 Mon Sep 17 00:00:00 2001 From: Andrew Haley Date: Tue, 7 Oct 2025 10:09:23 +0000 Subject: [PATCH 041/160] 8368303: AlwaysAtomicAccesses is excessively strict Reviewed-by: shade, vlivanov, dlong --- .../share/gc/shared/c1/barrierSetC1.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/shared/c1/barrierSetC1.cpp b/src/hotspot/share/gc/shared/c1/barrierSetC1.cpp index ac640fb88d2..a31078f7e67 100644 --- a/src/hotspot/share/gc/shared/c1/barrierSetC1.cpp +++ b/src/hotspot/share/gc/shared/c1/barrierSetC1.cpp @@ -38,6 +38,16 @@ #define __ gen->lir()-> #endif +// Return true iff an access to bt is single-copy atomic. + +// The JMM requires atomicity for all accesses to fields of primitive +// types other than double and long. In practice, HotSpot assumes that +// on all processors, accesses to memory operands of wordSize and +// smaller are atomic. +static bool access_is_atomic(BasicType bt) { + return type2aelembytes(bt) <= wordSize; +} + LIR_Opr BarrierSetC1::resolve_address(LIRAccess& access, bool resolve_in_register) { DecoratorSet decorators = access.decorators(); bool is_array = (decorators & IS_ARRAY) != 0; @@ -140,7 +150,7 @@ LIR_Opr BarrierSetC1::atomic_add_at(LIRAccess& access, LIRItem& value) { void BarrierSetC1::store_at_resolved(LIRAccess& access, LIR_Opr value) { DecoratorSet decorators = access.decorators(); bool is_volatile = (decorators & MO_SEQ_CST) != 0; - bool is_atomic = is_volatile || AlwaysAtomicAccesses; + bool needs_atomic = AlwaysAtomicAccesses && !access_is_atomic(value->type()); bool needs_patching = (decorators & C1_NEEDS_PATCHING) != 0; bool mask_boolean = (decorators & C1_MASK_BOOLEAN) != 0; LIRGenerator* gen = access.gen(); @@ -154,7 +164,7 @@ void BarrierSetC1::store_at_resolved(LIRAccess& access, LIR_Opr value) { } LIR_PatchCode patch_code = needs_patching ? lir_patch_normal : lir_patch_none; - if (is_atomic && !needs_patching) { + if ((is_volatile || needs_atomic) && !needs_patching) { gen->volatile_field_store(value, access.resolved_addr()->as_address_ptr(), access.access_emit_info()); } else { __ store(value, access.resolved_addr()->as_address_ptr(), access.access_emit_info(), patch_code); @@ -169,7 +179,7 @@ void BarrierSetC1::load_at_resolved(LIRAccess& access, LIR_Opr result) { LIRGenerator *gen = access.gen(); DecoratorSet decorators = access.decorators(); bool is_volatile = (decorators & MO_SEQ_CST) != 0; - bool is_atomic = is_volatile || AlwaysAtomicAccesses; + bool needs_atomic = AlwaysAtomicAccesses && !access_is_atomic(result->type()); bool needs_patching = (decorators & C1_NEEDS_PATCHING) != 0; bool mask_boolean = (decorators & C1_MASK_BOOLEAN) != 0; bool in_native = (decorators & IN_NATIVE) != 0; @@ -181,7 +191,7 @@ void BarrierSetC1::load_at_resolved(LIRAccess& access, LIR_Opr result) { LIR_PatchCode patch_code = needs_patching ? lir_patch_normal : lir_patch_none; if (in_native) { __ move_wide(access.resolved_addr()->as_address_ptr(), result); - } else if (is_atomic && !needs_patching) { + } else if ((is_volatile || needs_atomic) && !needs_patching) { gen->volatile_field_load(access.resolved_addr()->as_address_ptr(), result, access.access_emit_info()); } else { __ load(access.resolved_addr()->as_address_ptr(), result, access.access_emit_info(), patch_code); From 6bec42adcc1d99e16ddd5148bb4012c74a0c3090 Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Tue, 7 Oct 2025 10:21:33 +0000 Subject: [PATCH 042/160] 8368892: Make JEditorPane/TestBrowserBGColor.java headless Reviewed-by: serb, azvegint --- .../swing/JEditorPane/TestBrowserBGColor.java | 139 ++++++++---------- 1 file changed, 62 insertions(+), 77 deletions(-) diff --git a/test/jdk/javax/swing/JEditorPane/TestBrowserBGColor.java b/test/jdk/javax/swing/JEditorPane/TestBrowserBGColor.java index bff0f7c4aaa..9abe286a75d 100644 --- a/test/jdk/javax/swing/JEditorPane/TestBrowserBGColor.java +++ b/test/jdk/javax/swing/JEditorPane/TestBrowserBGColor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,94 +23,79 @@ /* * @test - * @key headful * @bug 8213781 * @summary Verify webpage background color renders correctly in JEditorPane */ -import java.awt.Toolkit; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.io.IOException; -import java.net.MalformedURLException; -import javax.swing.JDialog; -import javax.swing.JEditorPane; -import javax.swing.JFrame; -import javax.swing.JScrollPane; -import javax.swing.SwingUtilities; -import javax.swing.event.HyperlinkEvent; -import javax.swing.event.HyperlinkListener; -import javax.swing.text.html.HTMLFrameHyperlinkEvent; -import javax.swing.text.html.HTMLDocument; import java.awt.Color; -import java.awt.Insets; -import java.awt.Point; -import java.awt.Robot; +import java.awt.Graphics; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.util.Objects; +import java.util.stream.IntStream; -public class TestBrowserBGColor extends JFrame implements HyperlinkListener { +import javax.imageio.ImageIO; +import javax.swing.JEditorPane; +import javax.swing.text.StyleConstants; +import javax.swing.text.View; - private static TestBrowserBGColor b; - private static JEditorPane browser; +import static java.awt.image.BufferedImage.TYPE_INT_RGB; +import static java.lang.Integer.toHexString; + +public final class TestBrowserBGColor { + + private static final String HTML_DOC = + "" + + "" + + "" + + "Title" + + " "; + + private static final int SIZE = 300; public static void main(final String[] args) throws Exception { - Robot r = new Robot(); - SwingUtilities.invokeAndWait(() -> { - try { - b = new TestBrowserBGColor(); - } catch (Exception e) { - throw new RuntimeException(e); - } - b.setSize(Toolkit.getDefaultToolkit().getScreenSize()); - b.setVisible(true); - b.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); - b.addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent e) { - b.dispose(); - b = null; - } - }); - }); - - r.waitForIdle(); - r.delay(500); - - SwingUtilities.invokeAndWait(() -> { - Insets insets = browser.getInsets(); - Point loc = browser.getLocationOnScreen(); - Color c = r.getPixelColor( loc.x + insets.left+100, - loc.y + insets.top + 100); - b.dispose(); - if (!c.equals(Color.WHITE)) { - throw new RuntimeException("webpage background color wrong"); - } - }); - } - - - String htmlDoc = " Title "; - - public TestBrowserBGColor() throws IOException, MalformedURLException { - browser = new JEditorPane("text/html", htmlDoc); + JEditorPane browser = new JEditorPane("text/html", HTML_DOC); browser.setEditable(false); - browser.addHyperlinkListener(this); - JScrollPane scroll = new JScrollPane(browser); - getContentPane().add(scroll); + browser.setSize(SIZE, SIZE); + + BufferedImage image = new BufferedImage(SIZE, SIZE, TYPE_INT_RGB); + Graphics g = image.getGraphics(); + browser.paint(g); + g.dispose(); + + Color bgColor = StyleConstants.getBackground( + getBodyView(browser.getUI() + .getRootView(browser)) + .getAttributes()); + if (!bgColor.equals(Color.WHITE)) { + saveImage(image); + throw new RuntimeException("Wrong background color: " + + toHexString(bgColor.getRGB()) + + " vs " + + toHexString(Color.WHITE.getRGB())); + } } - public void hyperlinkUpdate(final HyperlinkEvent e) { - if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { - JEditorPane pane = (JEditorPane) e.getSource(); - if (e instanceof HTMLFrameHyperlinkEvent) { - HTMLFrameHyperlinkEvent evt = (HTMLFrameHyperlinkEvent) e; - HTMLDocument doc = (HTMLDocument) pane.getDocument(); - doc.processHTMLFrameHyperlinkEvent(evt); - } else { - try { - pane.setPage(e.getURL()); - } catch (Throwable t) { - t.printStackTrace(); - } - } + private static View getBodyView(final View view) { + if ("body".equals(view.getElement() + .getName())) { + return view; + } + + return IntStream.range(0, view.getViewCount()) + .mapToObj(view::getView) + .map(TestBrowserBGColor::getBodyView) + .filter(Objects::nonNull) + .findFirst() + .orElse(null); + } + + private static void saveImage(BufferedImage image) { + try { + ImageIO.write(image, "png", + new File("html-rendering.png")); + } catch (IOException ignored) { } } } From 9c46febcac01b9f1831f5f3e2a68dd1f1612a01f Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Tue, 7 Oct 2025 12:47:40 +0000 Subject: [PATCH 043/160] 8245234: Still seeing missing mixed stack traces, even after JDK-8234624 Reviewed-by: kevinw, cjplummer --- .../linux/amd64/LinuxAMD64CFrame.java | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java index 5f3c9786d6e..3dfb83c9f5a 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -145,17 +145,12 @@ public final class LinuxAMD64CFrame extends BasicCFrame { } DwarfParser nextDwarf = null; - - if ((dwarf != null) && dwarf.isIn(nextPC)) { - nextDwarf = dwarf; - } else { - Address libptr = dbg.findLibPtrByAddress(nextPC); - if (libptr != null) { - try { - nextDwarf = new DwarfParser(libptr); - } catch (DebuggerException e) { - // Bail out to Java frame - } + Address libptr = dbg.findLibPtrByAddress(nextPC); + if (libptr != null) { + try { + nextDwarf = new DwarfParser(libptr); + } catch (DebuggerException e) { + // Bail out to Java frame } } From 4b4d0cd35a32448e4b056109c502af2765766432 Mon Sep 17 00:00:00 2001 From: Johny Jose Date: Tue, 7 Oct 2025 13:13:42 +0000 Subject: [PATCH 044/160] 8365398: TEST_BUG: java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java failing intermittently Reviewed-by: msheppar, smarks, jpai --- test/jdk/ProblemList.txt | 1 - .../checkLeaseInfoLeak/CheckLeaseLeak.java | 25 ++++++++++++++----- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 8d13670805f..48a495bc238 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -608,7 +608,6 @@ java/rmi/transport/rapidExportUnexport/RapidExportUnexport.java 7146541 linux-al java/rmi/registry/readTest/CodebaseTest.java 8173324 windows-all java/rmi/registry/multipleRegistries/MultipleRegistries.java 8268182 macosx-all -java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java 8365398 generic-all java/rmi/Naming/DefaultRegistryPort.java 8005619 windows-all java/rmi/Naming/legalRegistryNames/LegalRegistryNames.java 8005619 windows-all diff --git a/test/jdk/java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java b/test/jdk/java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java index 4de6598a0f4..f40502601d2 100644 --- a/test/jdk/java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java +++ b/test/jdk/java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java @@ -59,10 +59,13 @@ import java.io.*; import java.lang.reflect.*; import java.rmi.registry.*; import sun.rmi.transport.*; +import java.util.concurrent.CountDownLatch; public class CheckLeaseLeak extends UnicastRemoteObject implements LeaseLeak { public CheckLeaseLeak() throws RemoteException { } - public void ping () throws RemoteException { } + public void ping () throws RemoteException { + remoteCallsComplete.countDown(); + } /** * Id to fake the DGC_ID, so we can later get a reference to the @@ -74,6 +77,9 @@ public class CheckLeaseLeak extends UnicastRemoteObject implements LeaseLeak { private final static int numberPingCalls = 0; private final static int CHECK_INTERVAL = 400; private final static int LEASE_VALUE = 20; + private static final int NO_OF_CLIENTS = ITERATIONS; + private static final int GOOD_LUCK_FACTOR = 2; + private static CountDownLatch remoteCallsComplete = new CountDownLatch(NO_OF_CLIENTS); public static void main (String[] args) { CheckLeaseLeak leakServer = null; @@ -113,8 +119,14 @@ public class CheckLeaseLeak extends UnicastRemoteObject implements LeaseLeak { jvm.destroy(); } } + try { + remoteCallsComplete.await(); + System.out.println("remoteCallsComplete . . . "); + } catch (InterruptedException intEx) { + System.out.println("remoteCallsComplete.await interrupted . . . "); + } + Thread.sleep(NO_OF_CLIENTS * LEASE_VALUE * GOOD_LUCK_FACTOR); numLeft = getDGCLeaseTableSize(); - Thread.sleep(3000); } catch(Exception e) { TestLibrary.bomb("CheckLeaseLeak Error: ", e); @@ -125,8 +137,8 @@ public class CheckLeaseLeak extends UnicastRemoteObject implements LeaseLeak { } } - /* numLeft should be 4 - if 11 there is a problem. */ - if (numLeft > 4) { + /* numLeft should not be greater than 2 - if 11 there is a problem. */ + if (numLeft > 2) { TestLibrary.bomb("Too many objects in DGCImpl.leaseTable: "+ numLeft); } else { @@ -204,8 +216,9 @@ public class CheckLeaseLeak extends UnicastRemoteObject implements LeaseLeak { * objects if the LeaseInfo memory leak is not fixed. */ leaseTable = (Map) f.get(dgcImpl[0]); - - numLeaseInfosLeft = leaseTable.size(); + synchronized (leaseTable) { + numLeaseInfosLeft = leaseTable.size(); + } } catch(Exception e) { TestLibrary.bomb(e); From a9c93f865bb5438420bc4df278d211ff3af9a0ad Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Tue, 7 Oct 2025 13:40:19 +0000 Subject: [PATCH 045/160] 8369263: Parallel: Inline PSPromotionManager::push_depth Reviewed-by: iwalulya, shade, fandreuzzi --- src/hotspot/share/gc/parallel/psPromotionManager.hpp | 2 -- src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp | 6 +----- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.hpp index 7d3a1682519..9808a55335d 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.hpp @@ -102,8 +102,6 @@ class PSPromotionManager { void process_array_chunk(PartialArrayState* state, bool stolen); void push_objArray(oop old_obj, oop new_obj); - void push_depth(ScannerTask task); - inline void promotion_trace_event(oop new_obj, Klass* klass, size_t obj_size, uint age, bool tenured, const PSPromotionLAB* lab); diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp index 4c12a4c357f..fb58c22cf29 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp @@ -50,10 +50,6 @@ inline PSPromotionManager* PSPromotionManager::manager_array(uint index) { return &_manager_array[index]; } -inline void PSPromotionManager::push_depth(ScannerTask task) { - claimed_stack_depth()->push(task); -} - template inline void PSPromotionManager::claim_or_forward_depth(T* p) { assert(ParallelScavengeHeap::heap()->is_in(p), "pointer outside heap"); @@ -62,7 +58,7 @@ inline void PSPromotionManager::claim_or_forward_depth(T* p) { oop obj = CompressedOops::decode_not_null(heap_oop); assert(!PSScavenge::is_obj_in_to_space(obj), "revisiting object?"); Prefetch::write(obj->base_addr(), oopDesc::mark_offset_in_bytes()); - push_depth(ScannerTask(p)); + claimed_stack_depth()->push(ScannerTask(p)); } } From 0f2a95c15d7c1e3796660d786c9a72497dab5ab1 Mon Sep 17 00:00:00 2001 From: jonghoonpark Date: Tue, 7 Oct 2025 15:13:23 +0000 Subject: [PATCH 046/160] 8365782: Remove unnecessary inclusion of in jfrOSInterface.cpp Reviewed-by: ayang, tschatzl --- src/hotspot/share/jfr/periodic/jfrOSInterface.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/hotspot/share/jfr/periodic/jfrOSInterface.cpp b/src/hotspot/share/jfr/periodic/jfrOSInterface.cpp index 2d4b99d59ab..18b2d7c5785 100644 --- a/src/hotspot/share/jfr/periodic/jfrOSInterface.cpp +++ b/src/hotspot/share/jfr/periodic/jfrOSInterface.cpp @@ -32,8 +32,6 @@ #include "runtime/vm_version.hpp" #include "utilities/ostream.hpp" -#include // for environment variables - static JfrOSInterface* _instance = nullptr; JfrOSInterface& JfrOSInterface::instance() { @@ -81,10 +79,7 @@ class JfrOSInterface::JfrOSInterfaceImpl : public JfrCHeapObj { // os information int os_version(char** os_version) const; - // environment information - void generate_environment_variables_events(); - - // system processes information + // system processes information int system_processes(SystemProcess** system_processes, int* no_of_sys_processes); int network_utilization(NetworkInterface** network_interfaces); From 8a20656ed03aa26806c7b4a4e361999dea62aa79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Tue, 7 Oct 2025 15:16:08 +0000 Subject: [PATCH 047/160] 8367321: Fix CSS bugs in dark theme 8366942: Dark mode pages briefly blink before going dark Reviewed-by: nbenalla, liach --- .../doclets/formats/html/markup/Head.java | 3 +- .../formats/html/resources/script.js.template | 60 +++++++++++-------- .../formats/html/resources/stylesheet.css | 58 +++++++++--------- .../javadoc/doclet/testSearch/TestSearch.java | 3 +- 4 files changed, 69 insertions(+), 55 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java index 2b6bfa77951..cda4bc9a5be 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java @@ -378,7 +378,8 @@ public class Head extends Content { mainBodyScript.append("const pathtoroot = ") .appendStringLiteral(ptrPath + "/") .append(";\n") - .append("loadScripts(document, 'script');"); + .append("loadScripts();\n") + .append("initTheme();\n"); } addScriptElement(head, DocPaths.JQUERY_JS); addScriptElement(head, DocPaths.JQUERY_UI_JS); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template index b275323b2f5..b91f99b2c42 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template @@ -11,12 +11,13 @@ var typeSearchIndex; var memberSearchIndex; var tagSearchIndex; -var oddRowColor = "odd-row-color"; -var evenRowColor = "even-row-color"; -var sortAsc = "sort-asc"; -var sortDesc = "sort-desc"; -var tableTab = "table-tab"; -var activeTableTab = "active-table-tab"; +const oddRowColor = "odd-row-color"; +const evenRowColor = "even-row-color"; +const sortAsc = "sort-asc"; +const sortDesc = "sort-desc"; +const tableTab = "table-tab"; +const activeTableTab = "active-table-tab"; +const THEMES = Object.freeze(["theme-light", "theme-dark", "theme-os"]); const linkIcon = "##REPLACE:doclet.Link_icon##"; const linkToSection = "##REPLACE:doclet.Link_to_section##"; @@ -30,21 +31,20 @@ if (typeof hljs !== "undefined") { } } -function loadScripts(doc, tag) { - createElem(doc, tag, 'script-files/search.js'); - - createElem(doc, tag, 'module-search-index.js'); - createElem(doc, tag, 'package-search-index.js'); - createElem(doc, tag, 'type-search-index.js'); - createElem(doc, tag, 'member-search-index.js'); - createElem(doc, tag, 'tag-search-index.js'); +function loadScripts() { + createScript('script-files/search.js'); + createScript('module-search-index.js'); + createScript('package-search-index.js'); + createScript('type-search-index.js'); + createScript('member-search-index.js'); + createScript('tag-search-index.js'); } -function createElem(doc, tag, path) { - var script = doc.createElement(tag); - var scriptElement = doc.getElementsByTagName(tag)[0]; +function createScript(path) { + var script = document.createElement("script"); script.src = pathtoroot + path; - scriptElement.parentNode.insertBefore(script, scriptElement); + var firstScript = document.getElementsByTagName("script")[0]; + firstScript.parentNode.insertBefore(script, firstScript); } // Helper for making content containing release names comparable lexicographically @@ -312,21 +312,31 @@ function makeFilterWidget(sidebar, updateToc) { return sidebar; } +function getTheme() { + return localStorage.getItem('theme') || THEMES[0]; +} + +function initTheme() { + document.body.classList.add(getTheme()); +} + function setTopMargin() { // Dynamically set scroll margin to accomodate for draft header var headerHeight = Math.ceil(document.querySelector("header").offsetHeight); document.querySelector(":root") .style.setProperty("--nav-height", headerHeight + "px"); } + document.addEventListener("readystatechange", (e) => { if (document.readyState === "interactive") { setTopMargin(); - } - if (sessionStorage.getItem("sidebar") === "hidden") { - const sidebar = document.querySelector(".main-grid nav.toc"); - if (sidebar) sidebar.classList.add("hide-sidebar"); + if (sessionStorage.getItem("sidebar") === "hidden") { + const sidebar = document.querySelector(".main-grid nav.toc"); + if (sidebar) sidebar.classList.add("hide-sidebar"); + } } }); + document.addEventListener("DOMContentLoaded", function(e) { setTopMargin(); const subnav = document.querySelector("ol.sub-nav-list"); @@ -375,13 +385,16 @@ document.addEventListener("DOMContentLoaded", function(e) { themePanelVisible = false; } } + var currentTheme = getTheme(); themePanel.querySelectorAll("input").forEach(input => { input.removeAttribute("disabled"); + if (input.id === currentTheme) { + input.checked = true; + } input.addEventListener("change", e => { setTheme(e.target.value); }) }); - const THEMES = ["theme-light", "theme-dark", "theme-os"]; function setTheme(theme) { THEMES.forEach(t => { if (t !== theme) document.body.classList.remove(t); @@ -390,7 +403,6 @@ document.addEventListener("DOMContentLoaded", function(e) { localStorage.setItem("theme", theme); document.getElementById(theme).checked = true; } - setTheme(localStorage.getItem("theme") || THEMES[0]); makeFilterWidget(sidebar, updateToc); if (tocMenu) { navbar.appendChild(tocMenu); 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 d61283dc677..4bb0fad4306 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 @@ -73,7 +73,7 @@ body { --selected-link-color: #4a698a; /* Background colors for generated tables */ --table-header-color: #ebeff4; - --even-row-color: #ffffff; + --even-row-color: #fdfdfe; --odd-row-color: #f0f0f2; /* Text color for page title */ --title-color: #2c4557; @@ -109,17 +109,19 @@ body { /* Colors for invalid tag notifications */ --invalid-tag-background-color: #ffe6e6; --invalid-tag-text-color: #000000; + --icon-filter: none; + --caption-link-color: var(--subnav-link-color); } body.theme-dark { --body-text-color: #e8e8e8; --block-text-color: #e8e8e8; - --body-background-color: #222528; + --body-background-color: #1f2124; --section-background-color: var(--body-background-color); --detail-background-color: var(--body-background-color); --code-background-color: #303940; --mark-background-color: #313131; - --detail-block-color: #f4f4f4; + --detail-block-color: #31363c; --navbar-background-color: #395A6F; --navbar-text-color: #ffffff; --subnav-background-color: #3d454d; @@ -133,11 +135,11 @@ body.theme-dark { --odd-row-color: #2d3135; --title-color: #fff; --link-color: #94badb; - --link-color-active: #ffb45b; - --toc-background-color: #31363c; + --link-color-active: #e8a351; + --toc-background-color: #2f3439; --toc-highlight-color: var(--subnav-background-color); --toc-hover-color: #3f4146; - --snippet-background-color: #2d363c; + --snippet-background-color: #2c353b; --snippet-text-color: var(--block-text-color); --snippet-highlight-color: #f7c590; --pre-background-color: var(--snippet-background-color); @@ -155,10 +157,8 @@ body.theme-dark { --button-focus-filter: brightness(104%); --invalid-tag-background-color: #ffe6e6; --invalid-tag-text-color: #000000; - div.main-grid img, - .inherited-list h3 > button { - filter: invert(100%) brightness(160%); - } + --icon-filter: invert(100%) brightness(160%); + --caption-link-color: var(--link-color); } /* @@ -168,12 +168,12 @@ body.theme-dark { body { --body-text-color: #e8e8e8; --block-text-color: #e8e8e8; - --body-background-color: #222528; + --body-background-color: #1f2124; --section-background-color: var(--body-background-color); --detail-background-color: var(--body-background-color); --code-background-color: #303940; --mark-background-color: #313131; - --detail-block-color: #f4f4f4; + --detail-block-color: #31363c; --navbar-background-color: #395A6F; --navbar-text-color: #ffffff; --subnav-background-color: #3d454d; @@ -187,11 +187,11 @@ body.theme-dark { --odd-row-color: #2d3135; --title-color: #fff; --link-color: #94badb; - --link-color-active: #ffb45b; - --toc-background-color: #31363c; + --link-color-active: #e8a351; + --toc-background-color: #2f3439; --toc-highlight-color: var(--subnav-background-color); --toc-hover-color: #3f4146; - --snippet-background-color: #2d363c; + --snippet-background-color: #2c353b; --snippet-text-color: var(--block-text-color); --snippet-highlight-color: #f7c590; --pre-background-color: var(--snippet-background-color); @@ -209,15 +209,13 @@ body.theme-dark { --button-focus-filter: brightness(104%); --invalid-tag-background-color: #ffe6e6; --invalid-tag-text-color: #000000; - div.main-grid img, - .inherited-list h3 > button { - filter: invert(100%) brightness(160%); - } + --icon-filter: invert(100%) brightness(160%); + --caption-link-color: var(--link-color); } body.theme-light { - --body-text-color: #282828; - --block-text-color: #282828; + --body-text-color: #181818; + --block-text-color: #181818; --body-background-color: #ffffff; --section-background-color: var(--body-background-color); --detail-background-color: var(--body-background-color); @@ -233,7 +231,7 @@ body.theme-dark { --selected-text-color: #253441; --selected-link-color: #4a698a; --table-header-color: #ebeff4; - --even-row-color: #ffffff; + --even-row-color: #fdfdfe; --odd-row-color: #f0f0f2; --title-color: #2c4557; --link-color: #437291; @@ -259,10 +257,8 @@ body.theme-dark { --button-focus-filter: brightness(104%); --invalid-tag-background-color: #ffe6e6; --invalid-tag-text-color: #000000; - div.main-grid img, - .inherited-list h3 > button { - filter: none; - } + --icon-filter: none; + --caption-link-color: var(--subnav-link-color); } } /* @@ -288,6 +284,9 @@ div.main-grid { max-width: var(--max-content-width); margin: var(--content-margin); } +div.main-grid img { + filter: var(--icon-filter); +} a:link, a:visited { text-decoration:none; color:var(--link-color); @@ -909,12 +908,12 @@ ul.preview-feature-list input { .caption a:visited, .inherited-list h3 a:link, .inherited-list h3 a:visited { - color:var(--subnav-link-color); + color:var(--caption-link-color); } .caption a:hover, .caption a:active, -.inherited-list.expanded h3 a:hover, -.inherited-list.expanded h3 a:active { +.inherited-list h3 a:hover, +.inherited-list h3 a:active { color: var(--link-color-active); } div.table-tabs { @@ -1539,6 +1538,7 @@ section[class$="-details"] .detail > div { height: 1.6em; vertical-align: middle; top: -2px; + filter: var(--icon-filter); } .inherited-list h3:has(button) { padding-left: 2px; diff --git a/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java b/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java index 8615d9f1e64..00c2f017909 100644 --- a/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java +++ b/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java @@ -427,7 +427,8 @@ public class TestSearch extends JavadocTester { """, """ const pathtoroot = "./"; - loadScripts(document, 'script');""", + loadScripts(); + initTheme();""", "

", """
  • Search
  • """, From eb729f0aaa2297c3b3dbadadf40a502d2d9ed124 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Tue, 7 Oct 2025 15:38:58 +0000 Subject: [PATCH 048/160] 8247776: JFR: TestThreadContextSwitches.java failed "RuntimeException: No events: expected false, was true" Reviewed-by: mgronlun --- .../event/os/TestThreadContextSwitches.java | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/test/jdk/jdk/jfr/event/os/TestThreadContextSwitches.java b/test/jdk/jdk/jfr/event/os/TestThreadContextSwitches.java index 7b3dfc79ce9..acfaecdde7d 100644 --- a/test/jdk/jdk/jfr/event/os/TestThreadContextSwitches.java +++ b/test/jdk/jdk/jfr/event/os/TestThreadContextSwitches.java @@ -28,6 +28,7 @@ import jdk.jfr.Recording; import jdk.jfr.consumer.RecordedEvent; import jdk.test.lib.jfr.EventNames; import jdk.test.lib.jfr.Events; +import jdk.test.lib.Platform; /** * @test @@ -40,15 +41,25 @@ public class TestThreadContextSwitches { private final static String EVENT_NAME = EventNames.ThreadContextSwitchRate; public static void main(String[] args) throws Throwable { - Recording recording = new Recording(); - recording.enable(EVENT_NAME); - recording.start(); - recording.stop(); - List events = Events.fromRecording(recording); - Events.hasEvents(events); - for (RecordedEvent event : events) { - System.out.println("Event: " + event); - Events.assertField(event, "switchRate").atLeast(0.0f); + while (true) { + try (Recording recording = new Recording()) { + recording.enable(EVENT_NAME); + recording.start(); + recording.stop(); + List events = Events.fromRecording(recording); + if (!events.isEmpty()) { + for (RecordedEvent event : events) { + System.out.println("Event: " + event); + Events.assertField(event, "switchRate").atLeast(0.0f); + } + return; + } + // Thread context switch rate is unreliable on Windows because + // the way processes are identified with performance counters. + if (!Platform.isWindows()) { + Events.hasEvents(events); + } + } } } } From eb835e05f9cf8a65d804b733b382ecfba5b12907 Mon Sep 17 00:00:00 2001 From: Volkan Yazici Date: Tue, 7 Oct 2025 15:57:31 +0000 Subject: [PATCH 049/160] 8366040: Change URL.lookupViaProviders to use ScopedValue to detect recursive lookup Reviewed-by: alanb, dfuchs --- src/java.base/share/classes/java/net/URL.java | 22 ++------- .../spi/URLStreamHandlerProvider/Basic.java | 18 ++++++- .../circular.provider.template | 48 +++++++++++++++++++ 3 files changed, 69 insertions(+), 19 deletions(-) create mode 100644 test/jdk/java/net/spi/URLStreamHandlerProvider/circular.provider.template diff --git a/src/java.base/share/classes/java/net/URL.java b/src/java.base/share/classes/java/net/URL.java index 1435d851f41..c82236b5b85 100644 --- a/src/java.base/share/classes/java/net/URL.java +++ b/src/java.base/share/classes/java/net/URL.java @@ -41,7 +41,6 @@ import java.util.ServiceLoader; import jdk.internal.access.JavaNetURLAccess; import jdk.internal.access.SharedSecrets; -import jdk.internal.misc.ThreadTracker; import jdk.internal.misc.VM; import jdk.internal.vm.annotation.AOTRuntimeSetup; import jdk.internal.vm.annotation.AOTSafeClassInitializer; @@ -1394,24 +1393,13 @@ public final class URL implements java.io.Serializable { return handler; } - private static class ThreadTrackHolder { - static final ThreadTracker TRACKER = new ThreadTracker(); - } - - private static Object tryBeginLookup() { - return ThreadTrackHolder.TRACKER.tryBegin(); - } - - private static void endLookup(Object key) { - ThreadTrackHolder.TRACKER.end(key); - } + private static final ScopedValue IN_LOOKUP = ScopedValue.newInstance(); private static URLStreamHandler lookupViaProviders(final String protocol) { - Object key = tryBeginLookup(); - if (key == null) { + if (IN_LOOKUP.isBound()) { throw new Error("Circular loading of URL stream handler providers detected"); } - try { + return ScopedValue.where(IN_LOOKUP, true).call(() -> { final ClassLoader cl = ClassLoader.getSystemClassLoader(); final ServiceLoader sl = ServiceLoader.load(URLStreamHandlerProvider.class, cl); @@ -1423,9 +1411,7 @@ public final class URL implements java.io.Serializable { return h; } return null; - } finally { - endLookup(key); - } + }); } /** diff --git a/test/jdk/java/net/spi/URLStreamHandlerProvider/Basic.java b/test/jdk/java/net/spi/URLStreamHandlerProvider/Basic.java index 9f8381a92c8..a98bf8e129e 100644 --- a/test/jdk/java/net/spi/URLStreamHandlerProvider/Basic.java +++ b/test/jdk/java/net/spi/URLStreamHandlerProvider/Basic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -77,6 +77,7 @@ public class Basic { viaProvider("bert", KNOWN); viaBadProvider("tom", SCE); viaBadProvider("jerry", SCE); + viaCircularProvider("circular", CIRCULAR); } private static String withoutWarning(String in) { @@ -99,6 +100,12 @@ public class Basic { throw new RuntimeException("exitValue: "+ r.exitValue + ", output:[" +r.output +"]"); } }; + static final Consumer CIRCULAR = r -> { + if (r.exitValue == 0 || + !r.output.contains("Circular loading of URL stream handler providers detected")) { + throw new RuntimeException("exitValue: " + r.exitValue + ", output:[" + r.output + "]"); + } + }; static void unknownProtocol(String protocol, Consumer resultChecker) { System.out.println("\nTesting " + protocol); @@ -125,6 +132,15 @@ public class Basic { sysProps); } + static void viaCircularProvider(String protocol, Consumer resultChecker, + String... sysProps) + throws Exception + { + viaProviderWithTemplate(protocol, resultChecker, + TEST_SRC.resolve("circular.provider.template"), + sysProps); + } + static void viaProviderWithTemplate(String protocol, Consumer resultChecker, Path template, String... sysProps) diff --git a/test/jdk/java/net/spi/URLStreamHandlerProvider/circular.provider.template b/test/jdk/java/net/spi/URLStreamHandlerProvider/circular.provider.template new file mode 100644 index 00000000000..b846cc4fec6 --- /dev/null +++ b/test/jdk/java/net/spi/URLStreamHandlerProvider/circular.provider.template @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package $package; + +import java.io.IOException; +import java.net.URI; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; +import java.net.spi.URLStreamHandlerProvider; + +public final class Provider extends URLStreamHandlerProvider { + + private static final String PROTOCOL = "$protocol"; + + @Override + public URLStreamHandler createURLStreamHandler(String protocol) { + try { + // Trigger circular lookup + URI.create("bogus://path/to/nothing").toURL(); + } catch (Exception exception) { + throw new RuntimeException(exception); + } + throw new AssertionError("Should not have reached here!"); + } + +} From 4ca3ab62759b366fd3e0b2267925f1fa70f057b7 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Tue, 7 Oct 2025 16:41:45 +0000 Subject: [PATCH 050/160] 8369123: Still more small Float16 refactorings Reviewed-by: rgiulietti --- .../classes/jdk/incubator/vector/Float16.java | 52 ++++++++++++------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float16.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float16.java index a564cdfed0f..fe2a6bf5580 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float16.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float16.java @@ -35,6 +35,8 @@ import static jdk.incubator.vector.Float16Consts.SIGN_BIT_MASK; import static jdk.incubator.vector.Float16Consts.EXP_BIT_MASK; import static jdk.incubator.vector.Float16Consts.SIGNIF_BIT_MASK; import static jdk.incubator.vector.Float16Consts.MAG_BIT_MASK; +import static jdk.incubator.vector.Float16Consts.EXP_BIAS; +import static jdk.incubator.vector.Float16Consts.SIGNIFICAND_WIDTH; import static java.lang.Float.float16ToFloat; import static java.lang.Float.floatToFloat16; @@ -95,19 +97,26 @@ import jdk.internal.vm.vector.Float16Math; * IEEE Standard for Floating-Point Arithmetic */ -// Currently Float16 is a value-based class and in future it is +// Currently Float16 is a value-based class and in the future it is // expected to be aligned with Value Classes and Object as described in // JEP-401 (https://openjdk.org/jeps/401). @jdk.internal.ValueBased public final class Float16 extends Number implements Comparable { - /** @serial */ + + /** + * Primitive {@code short} field to hold the bits of the {@code Float16}. + * @serial + */ private final short value; + private static final long serialVersionUID = 16; // May not be needed when a value class? // Functionality for future consideration: - // IEEEremainder / remainder operator remainder + // IEEEremainder and separate % operator remainder (which are + // defined to use different rounding modes, see JLS sections 15.4 + // and 15.17.3). // Do *not* define any public constructors /** @@ -147,8 +156,14 @@ public final class Float16 */ public static final Float16 NaN = valueOf(Float.NaN); + /** + * A constant holding a zero (0.0) of type {@code Float16}. + */ private static final Float16 ZERO = valueOf(0); + /** + * A constant holding a one (1.0) of type {@code Float16}. + */ private static final Float16 ONE = valueOf(1); /** @@ -316,10 +331,10 @@ public final class Float16 * @param value a {@code long} value. */ public static Float16 valueOf(long value) { - if (value <= -65_520L) { // -(Float16.MAX_VALUE + Float16.ulp(Float16.MAX_VALUE) / 2) + if (value <= -65_520L) { // -(MAX_VALUE + ulp(MAX_VALUE) / 2) return NEGATIVE_INFINITY; } else { - if (value >= 65_520L) { // Float16.MAX_VALUE + Float16.ulp(Float16.MAX_VALUE) / 2 + if (value >= 65_520L) { // MAX_VALUE + ulp(MAX_VALUE) / 2 return POSITIVE_INFINITY; } // Remaining range of long, the integers in approx. +/- @@ -427,9 +442,8 @@ public final class Float16 // to implement a carry out from rounding the significand. assert (0xf800 & signif_bits) == 0x0; - // Exponent bias adjust in the representation is equal to MAX_EXPONENT. return new Float16((short)(sign_bit | - ( ((exp + MAX_EXPONENT) << (PRECISION - 1)) + signif_bits ) )); + ( ((exp + EXP_BIAS) << (PRECISION - 1)) + signif_bits) )); } /** @@ -468,7 +482,7 @@ public final class Float16 // characters rather than codepoints. if (trialResult == 0.0 // handles signed zeros - || Math.abs(trialResult) > (65504.0 + 32.0) || // Float.MAX_VALUE + ulp(MAX_VALUE), + || Math.abs(trialResult) > (65504.0 + 32.0) || // MAX_VALUE + ulp(MAX_VALUE), // handles infinities too Double.isNaN(trialResult) || noDoubleRoundingToFloat16(trialResult)) { @@ -899,7 +913,7 @@ public final class Float16 */ public static int hashCode(Float16 value) { // Use bit-pattern of canonical NaN for hashing. - Float16 f16 = isNaN(value) ? Float16.NaN : value; + Float16 f16 = isNaN(value) ? NaN : value; return (int)float16ToRawShortBits(f16); } @@ -946,7 +960,7 @@ public final class Float16 */ public static short float16ToShortBits(Float16 f16) { if (isNaN(f16)) { - return Float16.NaN.value; + return NaN.value; } return f16.value; } @@ -1531,8 +1545,8 @@ public final class Float16 */ /*package*/ static int getExponent0(short bits) { // package private to be usable in java.lang.Float. - int bin16ExpBits = 0x0000_7c00 & bits; // Five exponent bits. - return (bin16ExpBits >> (PRECISION - 1)) - 15; + int bin16ExpBits = EXP_BIT_MASK & bits; // Five exponent bits. + return (bin16ExpBits >> (PRECISION - 1)) - EXP_BIAS; } /** @@ -1563,10 +1577,10 @@ public final class Float16 int exp = getExponent(f16); return switch(exp) { - case MAX_EXPONENT + 1 -> abs(f16); // NaN or infinity - case MIN_EXPONENT - 1 -> Float16.MIN_VALUE; // zero or subnormal + case MAX_EXPONENT + 1 -> abs(f16); // NaN or infinity + case MIN_EXPONENT - 1 -> MIN_VALUE; // zero or subnormal default -> { - assert exp <= MAX_EXPONENT && exp >= MIN_EXPONENT; + assert exp <= MAX_EXPONENT && exp >= MIN_EXPONENT: "Out of range exponent"; // ulp(x) is usually 2^(SIGNIFICAND_WIDTH-1)*(2^ilogb(x)) // Let float -> float16 conversion handle encoding issues. yield scalb(ONE, exp - (PRECISION - 1)); @@ -1687,8 +1701,7 @@ public final class Float16 // nonzero value by it would be guaranteed to over or // underflow; due to rounding, scaling down takes an // additional power of two which is reflected here - final int MAX_SCALE = Float16.MAX_EXPONENT + -Float16.MIN_EXPONENT + - Float16Consts.SIGNIFICAND_WIDTH + 1; + final int MAX_SCALE = MAX_EXPONENT + -MIN_EXPONENT + SIGNIFICAND_WIDTH + 1; // Make sure scaling factor is in a reasonable range scaleFactor = Math.clamp(scaleFactor, -MAX_SCALE, MAX_SCALE); @@ -1725,9 +1738,8 @@ public final class Float16 * @see Math#copySign(double, double) */ public static Float16 copySign(Float16 magnitude, Float16 sign) { - return shortBitsToFloat16((short) ((float16ToRawShortBits(sign) & SIGN_BIT_MASK) | - (float16ToRawShortBits(magnitude) & - (EXP_BIT_MASK | SIGNIF_BIT_MASK) ))); + return shortBitsToFloat16((short)((float16ToRawShortBits(sign) & SIGN_BIT_MASK) | + (float16ToRawShortBits(magnitude) & MAG_BIT_MASK))); } /** From ebeb77baaeb6d9098d7462f5ddf61d8583b1e493 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Tue, 7 Oct 2025 16:47:43 +0000 Subject: [PATCH 051/160] 8358058: sun/java2d/OpenGL/DrawImageBg.java Test fails intermittently Reviewed-by: azvegint, serb, psadhukhan --- test/jdk/ProblemList.txt | 1 + .../sun/java2d/OpenGL/DrawBitmaskImage.java | 173 ++++++ test/jdk/sun/java2d/OpenGL/DrawBufImgOp.java | 514 ++++++++++++++++++ test/jdk/sun/java2d/OpenGL/DrawImageBg.java | 145 +++++ test/jdk/sun/java2d/OpenGL/LargeOps.java | 138 +++++ test/jdk/sun/java2d/OpenGL/OpaqueDest.java | 180 ++++++ .../jdk/sun/java2d/OpenGL/ScaleParamsOOB.java | 198 +++++++ test/jdk/sun/java2d/OpenGL/ShapeClip.java | 140 +++++ test/jdk/sun/java2d/OpenGL/SrcMaskOps.java | 188 +++++++ .../sun/java2d/OpenGL/VolatileSubRegion.java | 166 ++++++ test/jdk/sun/java2d/OpenGL/XformVolatile.java | 146 +++++ 11 files changed, 1989 insertions(+) create mode 100644 test/jdk/sun/java2d/OpenGL/DrawBitmaskImage.java create mode 100644 test/jdk/sun/java2d/OpenGL/DrawBufImgOp.java create mode 100644 test/jdk/sun/java2d/OpenGL/DrawImageBg.java create mode 100644 test/jdk/sun/java2d/OpenGL/LargeOps.java create mode 100644 test/jdk/sun/java2d/OpenGL/OpaqueDest.java create mode 100644 test/jdk/sun/java2d/OpenGL/ScaleParamsOOB.java create mode 100644 test/jdk/sun/java2d/OpenGL/ShapeClip.java create mode 100644 test/jdk/sun/java2d/OpenGL/SrcMaskOps.java create mode 100644 test/jdk/sun/java2d/OpenGL/VolatileSubRegion.java create mode 100644 test/jdk/sun/java2d/OpenGL/XformVolatile.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 48a495bc238..fce7fe85069 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -248,6 +248,7 @@ sun/awt/datatransfer/SuplementaryCharactersTransferTest.java 8011371 generic-all sun/awt/shell/ShellFolderMemoryLeak.java 8197794 windows-all sun/java2d/DirectX/OverriddenInsetsTest/OverriddenInsetsTest.java 8196102 generic-all sun/java2d/DirectX/RenderingToCachedGraphicsTest/RenderingToCachedGraphicsTest.java 8196180 windows-all,macosx-all +sun/java2d/OpenGL/OpaqueDest.java#id1 8367574 macosx-all sun/java2d/SunGraphics2D/EmptyClipRenderingTest.java 8144029 macosx-all,linux-all sun/java2d/SunGraphics2D/DrawImageBilinear.java 8297175 linux-all sun/java2d/SunGraphics2D/PolyVertTest.java 6986565 generic-all diff --git a/test/jdk/sun/java2d/OpenGL/DrawBitmaskImage.java b/test/jdk/sun/java2d/OpenGL/DrawBitmaskImage.java new file mode 100644 index 00000000000..d2730593b5b --- /dev/null +++ b/test/jdk/sun/java2d/OpenGL/DrawBitmaskImage.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6248561 6264014 + * @key headful + * @requires (os.family != "mac") + * @summary Verifies that bitmask image copies work properly with the + * OGL pipeline when a SrcOver composite with extra alpha is involved. + * @run main/othervm -Dsun.java2d.opengl=True DrawBitmaskImage + * @run main/othervm DrawBitmaskImage + */ + +/* + * @test + * @bug 6248561 6264014 + * @key headful + * @requires (os.family == "mac") + * @summary Verifies that bitmask image copies work properly with the + * OGL pipeline when a SrcOver composite with extra alpha is involved. + * @run main/othervm -Dsun.java2d.opengl=True DrawBitmaskImage + * @run main/othervm DrawBitmaskImage + */ + +import java.awt.AlphaComposite; +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Transparency; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import java.awt.image.IndexColorModel; +import java.io.File; +import javax.imageio.ImageIO; + +public class DrawBitmaskImage extends Panel { + + static final int TESTW = 200, TESTH = 200; + private static volatile DrawBitmaskImage test; + private static volatile Frame frame; + + public void paint(Graphics g) { + + Graphics2D g2d = (Graphics2D)g; + g2d.setColor(Color.black); + g2d.fillRect(0, 0, getWidth(), getHeight()); + g2d.setComposite(AlphaComposite.SrcOver.derive(0.50f)); + + BufferedImage img = getGraphicsConfiguration().createCompatibleImage(50, 50, + Transparency.BITMASK); + Graphics2D gimg = img.createGraphics(); + gimg.setComposite(AlphaComposite.Src); + gimg.setColor(new Color(0, 0, 0, 0)); + gimg.fillRect(0, 0, 50, 50); + gimg.setColor(Color.red); + gimg.fillRect(10, 10, 30, 30); + gimg.dispose(); + + + g2d.drawImage(img, 10, 10, null); + + // draw a second time to ensure that the cached copy is used + g2d.drawImage(img, 80, 10, null); + } + + public Dimension getPreferredSize() { + return new Dimension(TESTW, TESTH); + } + + static void createUI() { + test = new DrawBitmaskImage(); + frame = new Frame("OpenGL DrawBitmaskImage Test"); + Panel p = new Panel(); + p.add(test); + frame.add(p); + frame.setSize(TESTW+100, TESTH+100); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + + EventQueue.invokeAndWait(DrawBitmaskImage::createUI); + + robot.waitForIdle(); + robot.delay(2000); + + BufferedImage capture = null; + try { + GraphicsConfiguration gc = frame.getGraphicsConfiguration(); + if (gc.getColorModel() instanceof IndexColorModel) { + System.out.println("IndexColorModel detected: " + + "test considered PASSED"); + return; + } + Point pt1 = test.getLocationOnScreen(); + Rectangle rect = new Rectangle(pt1.x, pt1.y, TESTW, TESTH); + capture = robot.createScreenCapture(rect); + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + + // Test background color + int pixel = capture.getRGB(5, 10); + if (pixel != 0xff000000) { + saveImage(capture); + throw new RuntimeException("Failed: Incorrect color for " + + "background (actual=" + + Integer.toHexString(pixel) + ")"); + } + + // Test pixels (allow for small error in the actual red value) + pixel = capture.getRGB(25, 25); + System.out.println("pixel1 is " + Integer.toHexString(pixel)); + + if ((pixel < 0xff7e0000) || (pixel > 0xff900000)) { + saveImage(capture); + throw new RuntimeException("Failed: Incorrect color for " + + "first pixel (actual=" + + Integer.toHexString(pixel) + ")"); + } + + pixel = capture.getRGB(95, 25); + System.out.println("pixel2 is " + Integer.toHexString(pixel)); + if ((pixel < 0xff7e0000) || (pixel > 0xff900000)) { + saveImage(capture); + throw new RuntimeException("Failed: Incorrect color for " + + "second pixel (actual=" + + Integer.toHexString(pixel) + ")"); + } + } + + static void saveImage(BufferedImage img) { + try { + File file = new File("capture.png"); + ImageIO.write(img, "png", file); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/test/jdk/sun/java2d/OpenGL/DrawBufImgOp.java b/test/jdk/sun/java2d/OpenGL/DrawBufImgOp.java new file mode 100644 index 00000000000..5d60eb7e792 --- /dev/null +++ b/test/jdk/sun/java2d/OpenGL/DrawBufImgOp.java @@ -0,0 +1,514 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6514990 + * @key headful + * @requires (os.family != "mac") + * @summary Verifies that calling + * Graphics2D.drawImage(BufferedImage, BufferedImageOp, x, y) to an + * OpenGL-accelerated destination produces the same results when performed + * in software via BufferedImageOp.filter(). + * @run main/othervm -Dsun.java2d.opengl=True DrawBufImgOp -ignore + */ + +/* + * @test + * @bug 6514990 + * @key headful + * @requires (os.family == "mac") + * @summary Verifies that calling + * Graphics2D.drawImage(BufferedImage, BufferedImageOp, x, y) to an + * OpenGL-accelerated destination produces the same results when performed + * in software via BufferedImageOp.filter(). + * @run main/othervm -Dsun.java2d.opengl=True DrawBufImgOp -ignore + */ + +import java.awt.AlphaComposite; +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import java.awt.image.ByteLookupTable; +import java.awt.image.ColorModel; +import java.awt.image.ConvolveOp; +import java.awt.image.IndexColorModel; +import java.awt.image.Kernel; +import java.awt.image.LookupOp; +import java.awt.image.RescaleOp; +import java.awt.image.ShortLookupTable; +import java.awt.image.VolatileImage; +import java.io.File; +import javax.imageio.ImageIO; + +/** + * REMIND: This testcase was originally intended to automatically compare + * the results of the software BufferedImageOp implementations against + * the OGL-accelerated codepaths. However, there are just too many open + * bugs in the mediaLib-based codepaths (see below), which means that + * creating the reference image may cause crashes or exceptions, + * and even if we work around those cases using the "-ignore" flag, + * the visual results of the reference image are often buggy as well + * (so the comparison will fail even though the OGL results are correct). + * Therefore, for now we will run the testcase with the "-ignore" flag + * but without the "-compare" flag, so at least it will be checking for + * any exceptions/crashes in the OGL code. When we fix all of the + * outstanding bugs with the software codepaths, we can remove the + * "-ignore" flag and maybe even restore the "-compare" flag. In the + * meantime, it also functions well as a manual testcase (with either + * the "-show" or "-dump" options). + */ +public class DrawBufImgOp extends Canvas { + + private static final int TESTW = 600; + private static final int TESTH = 500; + + private static volatile DrawBufImgOp test; + private static volatile Frame frame; + + /* + * If true, skips tests that are known to trigger bugs (which in + * turn may cause crashes, exceptions, or other artifacts). + */ + private static boolean ignore; + + // Test both pow2 and non-pow2 sized images + private static final int[] srcSizes = { 32, 17 }; + private static final int[] srcTypes = { + BufferedImage.TYPE_INT_RGB, + BufferedImage.TYPE_INT_ARGB, + BufferedImage.TYPE_INT_ARGB_PRE, + BufferedImage.TYPE_INT_BGR, + BufferedImage.TYPE_3BYTE_BGR, + BufferedImage.TYPE_4BYTE_ABGR, + BufferedImage.TYPE_USHORT_565_RGB, + BufferedImage.TYPE_BYTE_GRAY, + BufferedImage.TYPE_USHORT_GRAY, + }; + + private static final RescaleOp + rescale1band, rescale3band, rescale4band; + private static final LookupOp + lookup1bandbyte, lookup3bandbyte, lookup4bandbyte; + private static final LookupOp + lookup1bandshort, lookup3bandshort, lookup4bandshort; + private static final ConvolveOp + convolve3x3zero, convolve5x5zero, convolve7x7zero; + private static final ConvolveOp + convolve3x3noop, convolve5x5noop, convolve7x7noop; + + static { + rescale1band = new RescaleOp(0.5f, 10.0f, null); + rescale3band = new RescaleOp( + new float[] { 0.6f, 0.4f, 0.6f }, + new float[] { 10.0f, -3.0f, 5.0f }, + null); + rescale4band = new RescaleOp( + new float[] { 0.6f, 0.4f, 0.6f, 0.9f }, + new float[] { -1.0f, 5.0f, 3.0f, 1.0f }, + null); + + // REMIND: we should probably test non-zero offsets, but that + // would require massaging the source image data to avoid going + // outside the lookup table array bounds + int offset = 0; + { + byte invert[] = new byte[256]; + byte halved[] = new byte[256]; + for (int j = 0; j < 256 ; j++) { + invert[j] = (byte) (255-j); + halved[j] = (byte) (j / 2); + } + ByteLookupTable lut1 = new ByteLookupTable(offset, invert); + lookup1bandbyte = new LookupOp(lut1, null); + ByteLookupTable lut3 = + new ByteLookupTable(offset, + new byte[][] {invert, halved, invert}); + lookup3bandbyte = new LookupOp(lut3, null); + ByteLookupTable lut4 = + new ByteLookupTable(offset, + new byte[][] {invert, halved, invert, halved}); + lookup4bandbyte = new LookupOp(lut4, null); + } + + { + short invert[] = new short[256]; + short halved[] = new short[256]; + for (int j = 0; j < 256 ; j++) { + invert[j] = (short) ((255-j) * 255); + halved[j] = (short) ((j / 2) * 255); + } + ShortLookupTable lut1 = new ShortLookupTable(offset, invert); + lookup1bandshort = new LookupOp(lut1, null); + ShortLookupTable lut3 = + new ShortLookupTable(offset, + new short[][] {invert, halved, invert}); + lookup3bandshort = new LookupOp(lut3, null); + ShortLookupTable lut4 = + new ShortLookupTable(offset, + new short[][] {invert, halved, invert, halved}); + lookup4bandshort = new LookupOp(lut4, null); + } + + // 3x3 blur + float[] data3 = { + 0.1f, 0.1f, 0.1f, + 0.1f, 0.2f, 0.1f, + 0.1f, 0.1f, 0.1f, + }; + Kernel k3 = new Kernel(3, 3, data3); + + // 5x5 edge + float[] data5 = { + -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, + -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, + -1.0f, -1.0f, 24.0f, -1.0f, -1.0f, + -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, + -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, + }; + Kernel k5 = new Kernel(5, 5, data5); + + // 7x7 blur + float[] data7 = { + 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, + 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, + 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, + 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, + 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, + 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, + 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, + }; + Kernel k7 = new Kernel(7, 7, data7); + + convolve3x3zero = new ConvolveOp(k3, ConvolveOp.EDGE_ZERO_FILL, null); + convolve5x5zero = new ConvolveOp(k5, ConvolveOp.EDGE_ZERO_FILL, null); + convolve7x7zero = new ConvolveOp(k7, ConvolveOp.EDGE_ZERO_FILL, null); + + convolve3x3noop = new ConvolveOp(k3, ConvolveOp.EDGE_NO_OP, null); + convolve5x5noop = new ConvolveOp(k5, ConvolveOp.EDGE_NO_OP, null); + convolve7x7noop = new ConvolveOp(k7, ConvolveOp.EDGE_NO_OP, null); + } + + public void paint(Graphics g) { + + VolatileImage vimg = createVolatileImage(TESTW, TESTH); + vimg.validate(getGraphicsConfiguration()); + + Graphics2D g2d = vimg.createGraphics(); + renderTest(g2d); + g2d.dispose(); + + g.drawImage(vimg, 0, 0, null); + } + + /* + * foreach source image size (once with pow2, once with non-pow2) + * + * foreach BufferedImage type + * + * RescaleOp (1 band) + * RescaleOp (3 bands, if src has 3 bands) + * RescaleOp (4 bands, if src has 4 bands) + * + * foreach LookupTable type (once with ByteLUT, once with ShortLUT) + * LookupOp (1 band) + * LookupOp (3 bands, if src has 3 bands) + * LookupOp (4 bands, if src has 4 bands) + * + * foreach edge condition (once with ZERO_FILL, once with EDGE_NO_OP) + * ConvolveOp (3x3) + * ConvolveOp (5x5) + * ConvolveOp (7x7) + */ + private void renderTest(Graphics2D g2d) { + g2d.setColor(Color.white); + g2d.fillRect(0, 0, TESTW, TESTH); + + int yorig = 2; + int xinc = 34; + int yinc = srcSizes[0] + srcSizes[1] + 2 + 2; + + for (int srcType : srcTypes) { + int y = yorig; + + for (int srcSize : srcSizes) { + int x = 2; + System.out.printf("type=%d size=%d\n", srcType, srcSize); + + BufferedImage srcImg = makeSourceImage(srcSize, srcType); + ColorModel srcCM = srcImg.getColorModel(); + + // RescaleOp + g2d.drawImage(srcImg, rescale1band, x, y); + x += xinc; + // REMIND: 3-band RescaleOp.filter() throws IAE for images + // that contain an alpha channel (bug to be filed) + if (srcCM.getNumColorComponents() == 3 && + !(ignore && srcCM.hasAlpha())) + { + g2d.drawImage(srcImg, rescale3band, x, y); + } + x += xinc; + if (srcCM.getNumComponents() == 4) { + g2d.drawImage(srcImg, rescale4band, x, y); + } + x += xinc; + + // LookupOp + // REMIND: Our LUTs are only 256 elements long, so won't + // currently work with USHORT_GRAY data + if (srcType != BufferedImage.TYPE_USHORT_GRAY) { + g2d.drawImage(srcImg, lookup1bandbyte, x, y); + x += xinc; + if (srcCM.getNumColorComponents() == 3) { + g2d.drawImage(srcImg, lookup3bandbyte, x, y); + } + x += xinc; + if (srcCM.getNumComponents() == 4) { + g2d.drawImage(srcImg, lookup4bandbyte, x, y); + } + x += xinc; + + // REMIND: LookupOp.createCompatibleDestImage() throws + // IAE for 3BYTE_BGR/4BYTE_ABGR (bug to be filed) + if (!(ignore && + (srcType == BufferedImage.TYPE_3BYTE_BGR || + srcType == BufferedImage.TYPE_4BYTE_ABGR))) + { + g2d.drawImage(srcImg, lookup1bandshort, x, y); + x += xinc; + // REMIND: 3-band LookupOp.filter() throws IAE for + // images that contain an alpha channel + // (bug to be filed) + if (srcCM.getNumColorComponents() == 3 && + !(ignore && srcCM.hasAlpha())) + { + g2d.drawImage(srcImg, lookup3bandshort, x, y); + } + x += xinc; + if (srcCM.getNumComponents() == 4) { + g2d.drawImage(srcImg, lookup4bandshort, x, y); + } + x += xinc; + } else { + x += 3*xinc; + } + } else { + x += 6*xinc; + } + + // ConvolveOp + // REMIND: ConvolveOp.filter() throws ImagingOpException + // for 3BYTE_BGR (see 4957775) + if (srcType != BufferedImage.TYPE_3BYTE_BGR) { + g2d.drawImage(srcImg, convolve3x3zero, x, y); + x += xinc; + g2d.drawImage(srcImg, convolve5x5zero, x, y); + x += xinc; + g2d.drawImage(srcImg, convolve7x7zero, x, y); + x += xinc; + + g2d.drawImage(srcImg, convolve3x3noop, x, y); + x += xinc; + g2d.drawImage(srcImg, convolve5x5noop, x, y); + x += xinc; + g2d.drawImage(srcImg, convolve7x7noop, x, y); + x += xinc; + } else { + x += 6*xinc; + } + + y += srcSize + 2; + } + + yorig += yinc; + } + } + + private BufferedImage makeSourceImage(int size, int type) { + int s2 = size/2; + BufferedImage img = new BufferedImage(size, size, type); + Graphics2D g2d = img.createGraphics(); + g2d.setComposite(AlphaComposite.Src); + g2d.setColor(Color.orange); + g2d.fillRect(0, 0, size, size); + g2d.setColor(Color.red); + g2d.fillRect(0, 0, s2, s2); + g2d.setColor(Color.green); + g2d.fillRect(s2, 0, s2, s2); + g2d.setColor(Color.blue); + g2d.fillRect(0, s2, s2, s2); + g2d.setColor(new Color(255, 255, 0, 128)); + g2d.fillRect(s2, s2, s2, s2); + g2d.setColor(Color.pink); + g2d.fillOval(s2-3, s2-3, 6, 6); + g2d.dispose(); + return img; + } + + public BufferedImage makeReferenceImage() { + BufferedImage img = new BufferedImage(TESTW, TESTH, + BufferedImage.TYPE_INT_RGB); + Graphics2D g2d = img.createGraphics(); + renderTest(g2d); + g2d.dispose(); + return img; + } + + public Dimension getPreferredSize() { + return new Dimension(TESTW, TESTH); + } + + private static void compareImages(BufferedImage refImg, + BufferedImage testImg, + int tolerance) + { + int x1 = 0; + int y1 = 0; + int x2 = refImg.getWidth(); + int y2 = refImg.getHeight(); + + for (int y = y1; y < y2; y++) { + for (int x = x1; x < x2; x++) { + Color expected = new Color(refImg.getRGB(x, y)); + Color actual = new Color(testImg.getRGB(x, y)); + if (!isSameColor(expected, actual, tolerance)) { + saveImage("referenceimage", refImg); + saveImage("testimage", testImg); + throw new RuntimeException("Test failed at x="+x+" y="+y+ + " (expected="+expected+ + " actual="+actual+ + ")"); + } + } + } + } + + private static boolean isSameColor(Color c1, Color c2, int e) { + int r1 = c1.getRed(); + int g1 = c1.getGreen(); + int b1 = c1.getBlue(); + int r2 = c2.getRed(); + int g2 = c2.getGreen(); + int b2 = c2.getBlue(); + int rmin = Math.max(r2-e, 0); + int gmin = Math.max(g2-e, 0); + int bmin = Math.max(b2-e, 0); + int rmax = Math.min(r2+e, 255); + int gmax = Math.min(g2+e, 255); + int bmax = Math.min(b2+e, 255); + if (r1 >= rmin && r1 <= rmax && + g1 >= gmin && g1 <= gmax && + b1 >= bmin && b1 <= bmax) + { + return true; + } + return false; + } + + + static void createUI() { + test = new DrawBufImgOp(); + Panel panel = new Panel(); + panel.add(test); + frame = new Frame("OpenGL DrawBufImgOp Test"); + frame.add(panel); + frame.setSize(TESTW+100, TESTH+100); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public static void main(String[] args) throws Exception { + + boolean show = false; + boolean dump = false; + boolean compare = false; + + for (String arg : args) { + if (arg.equals("-show")) { + show = true; + } else if (arg.equals("-dump")) { + dump = true; + } else if (arg.equals("-compare")) { + compare = true; + } else if (arg.equals("-ignore")) { + ignore = true; + } + } + + Robot robot = new Robot(); + + EventQueue.invokeAndWait(DrawBufImgOp::createUI); + + robot.waitForIdle(); + robot.delay(2000); + + BufferedImage capture = null; + try { + GraphicsConfiguration gc = frame.getGraphicsConfiguration(); + if (gc.getColorModel() instanceof IndexColorModel) { + System.out.println("IndexColorModel detected: " + + "test considered PASSED"); + return; + } + Point pt1 = test.getLocationOnScreen(); + Rectangle rect = new Rectangle(pt1.x, pt1.y, TESTW, TESTH); + capture = robot.createScreenCapture(rect); + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + + // Compare the images (allow for +/- 1 bit differences in color comps) + if (dump || compare) { + BufferedImage ref = test.makeReferenceImage(); + if (dump) { + saveImage("DrawBufImgOp_ref", ref); + saveImage("DrawBufImgOp_cap", capture); + } + if (compare) { + test.compareImages(ref, capture, 1); + } + } + } + + static void saveImage(String name, BufferedImage img) { + try { + File file = new File(name + ".png"); + ImageIO.write(img, "png", file); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/test/jdk/sun/java2d/OpenGL/DrawImageBg.java b/test/jdk/sun/java2d/OpenGL/DrawImageBg.java new file mode 100644 index 00000000000..7fc38d91b06 --- /dev/null +++ b/test/jdk/sun/java2d/OpenGL/DrawImageBg.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4993274 + * @key headful + * @requires (os.family != "mac") + * @summary Verifies that managed image copies and transforms work properly + * with the OGL pipeline when a background color is specified. + * @run main/othervm -Dsun.java2d.opengl=True DrawImageBg + * @run main/othervm DrawImageBg + */ + +/* + * @test + * @bug 4993274 + * @key headful + * @requires (os.family == "mac") + * @summary Verifies that managed image copies and transforms work properly + * with the OGL pipeline when a background color is specified. + * @run main/othervm -Dsun.java2d.opengl=True DrawImageBg + * @run main/othervm DrawImageBg + */ + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.Transparency; +import java.awt.image.BufferedImage; +import java.io.File; +import javax.imageio.ImageIO; + +public class DrawImageBg extends Panel { + + static volatile Frame frame; + static volatile DrawImageBg test; + + public void paint(Graphics g) { + + Graphics2D g2d = (Graphics2D)g; + g2d.setColor(Color.black); + g2d.fillRect(0, 0, getWidth(), getHeight()); + + BufferedImage img = getGraphicsConfiguration().createCompatibleImage(50, 50, + Transparency.BITMASK); + Graphics2D gimg = img.createGraphics(); + gimg.setComposite(AlphaComposite.Src); + gimg.setColor(new Color(0, 0, 0, 0)); + gimg.fillRect(0, 0, 50, 50); + gimg.setColor(Color.red); + gimg.fillRect(10, 10, 30, 30); + gimg.dispose(); + + g2d.drawImage(img, 10, 10, Color.blue, null); + + // draw a second time to ensure that the cached copy is used + g2d.drawImage(img, 80, 10, Color.blue, null); + } + + static void createUI() { + frame = new Frame("OpenGL DrawImageBg Test"); + test = new DrawImageBg(); + frame.add(test); + frame.setSize(300, 300); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public static void main(String[] args) throws Exception { + + BufferedImage capture = null; + Robot robot = new Robot(); + try { + EventQueue.invokeAndWait(DrawImageBg::createUI); + robot.waitForIdle(); + robot.delay(3000); + + // Grab the screen region + Point pt1 = test.getLocationOnScreen(); + Rectangle rect = new Rectangle(pt1.x+80, pt1.y, 80, 80); + capture = robot.createScreenCapture(rect); + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + + if (capture == null) { + throw new RuntimeException("Screen capture is null"); + } + + // Test inner and outer pixels + int pixel1 = capture.getRGB(5, 10); + if (pixel1 != 0xff0000ff) { + saveImage(capture); + throw new RuntimeException(getMsg("outer", pixel1)); + } + int pixel2 = capture.getRGB(25, 25); + if (pixel2 != 0xffff0000) { + saveImage(capture); + throw new RuntimeException(getMsg("inner", pixel2)); + } + } + + static String getMsg(String r, int p1) { + return "Failed: Incorrect color for " + r + " pixel: got " + Integer.toHexString(p1); + } + + static void saveImage(BufferedImage img) { + try { + File file = new File("capture.png"); + ImageIO.write(img, "png", file); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/test/jdk/sun/java2d/OpenGL/LargeOps.java b/test/jdk/sun/java2d/OpenGL/LargeOps.java new file mode 100644 index 00000000000..ace60b7a3c4 --- /dev/null +++ b/test/jdk/sun/java2d/OpenGL/LargeOps.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6219284 6358147 6274813 6578452 + * @key headful + * @summary Verifies that OGLRenderer.drawPoly(), + * OGLTextRenderer.drawGlyphList(), and OGLMaskFill work properly when the + * operation parameters exceed the capacity of the render queue. With the + * single-threaded OpenGL pipeline, there are some operations that require + * a separate buffer to be spawned if the parameters cannot fit entirely on + * the standard buffer. This test exercises this special case. + * @run main/othervm -Dsun.java2d.opengl=True -Dsun.java2d.opengl.lcdshader=true LargeOps + */ + +import java.awt.Canvas; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Font; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Robot; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.image.BufferedImage; +import java.io.File; +import javax.imageio.ImageIO; + +public class LargeOps extends Canvas { + + private static final int NUM_POINTS = 8000; + private int[] xPoints, yPoints; + private String str; + + public LargeOps() { + xPoints = new int[NUM_POINTS]; + yPoints = new int[NUM_POINTS]; + for (int i = 0; i < NUM_POINTS; i++) { + xPoints[i] = (i % 2 == 0) ? 10 : 400; + yPoints[i] = (i % 2 == 1) ? i+3 : i; + } + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < NUM_POINTS; i+=11) { + sb.append("ThisIsATest"); + } + str = sb.toString(); + } + + public void paint(Graphics g) { + Graphics2D g2d = (Graphics2D)g; + g2d.setColor(Color.white); + g2d.fillRect(0, 0, getWidth(), getHeight()); + + // draw large polyline + g2d.setColor(Color.green); + g2d.drawPolyline(xPoints, yPoints, NUM_POINTS); + + // draw long string + g2d.setColor(Color.blue); + g2d.drawString(str, 10, 100); + + // draw long string with larger pt size + Font font = g2d.getFont(); + g2d.setFont(font.deriveFont(40.0f)); + g2d.drawString(str, 10, 150); + + // do the same with LCD hints enabled + g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB); + g2d.setFont(font); + g2d.drawString(str, 10, 200); + g2d.setFont(font.deriveFont(43.0f)); + g2d.drawString(str, 10, 250); + + g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HBGR); + g2d.setFont(font); + g2d.drawString(str, 10, 300); + g2d.setFont(font.deriveFont(37.0f)); + g2d.drawString(str, 10, 350); + } + + static volatile Frame frame; + static volatile LargeOps test; + + static void createUI() { + frame = new Frame("OpenGL LargeOps Test"); + frame.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + frame.dispose(); + } + }); + test = new LargeOps(); + frame.add(test); + frame.setSize(600, 600); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + EventQueue.invokeAndWait(LargeOps::createUI); + robot.waitForIdle(); + robot.delay(6000); + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + } +} diff --git a/test/jdk/sun/java2d/OpenGL/OpaqueDest.java b/test/jdk/sun/java2d/OpenGL/OpaqueDest.java new file mode 100644 index 00000000000..50896316109 --- /dev/null +++ b/test/jdk/sun/java2d/OpenGL/OpaqueDest.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6277977 6319663 + * @key headful + * @requires (os.family != "mac") + * @summary Verifies that blending operations do not inadvertantly leave + * non-opaque alpha values in the framebuffer. Note that this test is + * intended to run on GraphicsConfigs that support a stored alpha channel + * (to verify the bug at hand), but it is also a useful for testing the + * compositing results on any configuration. + * @run main/othervm -Dsun.java2d.opengl=True OpaqueDest + * @run main/othervm OpaqueDest + */ + +/* + * @test + * @bug 6277977 6319663 + * @key headful + * @requires (os.family == "mac") + * @summary Verifies that blending operations do not inadvertantly leave + * non-opaque alpha values in the framebuffer. Note that this test is + * intended to run on GraphicsConfigs that support a stored alpha channel + * (to verify the bug at hand), but it is also a useful for testing the + * compositing results on any configuration. + * @run main/othervm -Dsun.java2d.opengl=True OpaqueDest + * @run main/othervm OpaqueDest + */ + +import java.awt.AlphaComposite; +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import java.awt.image.IndexColorModel; +import java.io.File; +import javax.imageio.ImageIO; + +public class OpaqueDest extends Canvas { + + private static volatile Frame frame; + private static volatile OpaqueDest test; + + public void paint(Graphics g) { + + Graphics2D g2d = (Graphics2D)g; + + g2d.setColor(Color.red); + g2d.fillRect(0, 0, getWidth(), getHeight()); + + // This will clear the rectangle to black + g2d.setComposite(AlphaComposite.Clear); + g2d.fillRect(10, 10, 80, 80); + + // If everything is working properly, then this will fill the + // rectangle with red again. Before this bug was fixed, the previous + // Clear operation would leave zero values in the destination's + // alpha channel (if present), and therefore a SrcIn operation + // would result in all-black. + g2d.setComposite(AlphaComposite.SrcIn); + g2d.fillRect(10, 10, 80, 80); + } + + public Dimension getPreferredSize() { + return new Dimension(100, 100); + } + + static void createUI() { + test = new OpaqueDest(); + frame = new Frame("OpenGL OpaqueDest Test"); + Panel p = new Panel(); + p.add(test); + frame.add(p); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + + EventQueue.invokeAndWait(OpaqueDest::createUI); + + robot.waitForIdle(); + robot.delay(2000); + + BufferedImage capture = null; + try { + GraphicsConfiguration gc = frame.getGraphicsConfiguration(); + if (gc.getColorModel() instanceof IndexColorModel) { + System.out.println("IndexColorModel detected: " + + "test considered PASSED"); + return; + } + Point pt1 = test.getLocationOnScreen(); + Rectangle rect = new Rectangle(pt1.x, pt1.y, 100, 100); + capture = robot.createScreenCapture(rect); + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + + + // Test all pixels (every one should be red) + for (int y = 0; y < 100; y++) { + for (int x = 0; x < 100; x++) { + int actual = capture.getRGB(x, y); + int expected = 0xffff0000; + if (!similar(actual, expected)) { + saveImage(capture); + throw new RuntimeException("Test failed at x="+x+" y="+y+ + " (expected="+ + Integer.toHexString(expected) + + " actual="+ + Integer.toHexString(actual) + + ")"); + } + } + } + } + + static boolean similar(int p1, int p2) { + int a1 = (p1 >> 24) & 0xff; + int r1 = (p1 >> 16) & 0xff; + int g1 = (p1 >> 8) & 0xff; + int b1 = p1 & 0xff; + int a2 = (p2 >> 24) & 0xff; + int r2 = (p2 >> 16) & 0xff; + int g2 = (p2 >> 8) & 0xff; + int b2 = p2 & 0xff; + + int allowedDiff = 0x01; // tiny rounding error allowed. + return + (Math.abs(a1 - a2) <= allowedDiff) && + (Math.abs(r1 - r2) <= allowedDiff) && + (Math.abs(g1 - g2) <= allowedDiff) && + (Math.abs(b1 - b2) <= allowedDiff); + } + + static void saveImage(BufferedImage img) { + try { + File file = new File("capture.png"); + ImageIO.write(img, "png", file); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/test/jdk/sun/java2d/OpenGL/ScaleParamsOOB.java b/test/jdk/sun/java2d/OpenGL/ScaleParamsOOB.java new file mode 100644 index 00000000000..b3d866cfd75 --- /dev/null +++ b/test/jdk/sun/java2d/OpenGL/ScaleParamsOOB.java @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 5104584 8237244 + * @key headful + * @requires (os.family != "mac") + * @summary Verifies that scaling an image works properly when the + * source parameters are outside the source bounds. + * @run main/othervm -Dsun.java2d.opengl=True ScaleParamsOOB + * @run main/othervm ScaleParamsOOB + */ + +/* + * @test + * @bug 5104584 8237244 + * @key headful + * @requires (os.family == "mac") + * @summary Verifies that scaling an image works properly when the + * source parameters are outside the source bounds. + * @run main/othervm -Dsun.java2d.opengl=True ScaleParamsOOB + * @run main/othervm ScaleParamsOOB + */ + + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import java.io.File; +import javax.imageio.ImageIO; + +public class ScaleParamsOOB extends Panel { + + private static final int TOLERANCE = 12; + + private static volatile ScaleParamsOOB test; + private static volatile Frame frame; + + private BufferedImage img; + + public void paint(Graphics g) { + + Graphics2D g2d = (Graphics2D)g; + g2d.setColor(Color.black); + g2d.fillRect(0, 0, getWidth(), getHeight()); + + BufferedImage img = getGraphicsConfiguration().createCompatibleImage(40, 40); + Graphics2D gimg = img.createGraphics(); + gimg.setColor(Color.red); + gimg.fillRect(0, 0, 40, 40); + gimg.dispose(); + + // first time will be a sw->surface blit + g2d.drawImage(img, + 10, 10, 90, 90, + -60, -60, 100, 100, + null); + + // second time will be a texture->surface blit + g2d.drawImage(img, + 110, 10, 190, 90, + -60, -60, 100, 100, + null); + } + + public Dimension getPreferredSize() { + return new Dimension(300, 200); + } + + private static void testRegion(BufferedImage bi, + Rectangle wholeRegion, + Rectangle affectedRegion) + { + int x1 = wholeRegion.x; + int y1 = wholeRegion.y; + int x2 = x1 + wholeRegion.width; + int y2 = y1 + wholeRegion.height; + + for (int y = y1; y < y2; y++) { + for (int x = x1; x < x2; x++) { + int actual = bi.getRGB(x, y); + int expected = 0; + if (affectedRegion.contains(x, y)) { + expected = Color.red.getRGB(); + } else { + expected = Color.black.getRGB(); + } + int alpha = (actual >> 24) & 0xFF; + int red = (actual >> 16) & 0xFF; + int green = (actual >> 8) & 0xFF; + int blue = (actual) & 0xFF; + + int standardAlpha = (expected >> 24) & 0xFF; + int standardRed = (expected >> 16) & 0xFF; + int standardGreen = (expected >> 8) & 0xFF; + int standardBlue = (expected) & 0xFF; + + if ((Math.abs(alpha - standardAlpha) > TOLERANCE) || + (Math.abs(red - standardRed) > TOLERANCE) || + (Math.abs(green - standardGreen) > TOLERANCE) || + (Math.abs(blue - standardBlue) > TOLERANCE)) { + saveImage(bi); + throw new RuntimeException("Test failed at x="+x+" y="+y+ + " (expected="+ + Integer.toHexString(expected) + + " actual="+ + Integer.toHexString(actual) + + ")"); + } + } + } + } + + private static void createAndShowGUI() { + test = new ScaleParamsOOB(); + frame = new Frame("OpenGL ScaleParamsOOB Test"); + frame.setAlwaysOnTop(true); + frame.add(test); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + + EventQueue.invokeAndWait(() -> createAndShowGUI()); + + robot.waitForIdle(); + robot.delay(2000); + + // Grab the screen region + BufferedImage capture = null; + try { + Point pt1 = test.getLocationOnScreen(); + Rectangle rect = new Rectangle(pt1.x, pt1.y, 200, 200); + capture = robot.createScreenCapture(rect); + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + + // Test background color + int pixel = capture.getRGB(5, 5); + if (pixel != 0xff000000) { + saveImage(capture); + throw new RuntimeException("Failed: Incorrect color for " + + "background: " + Integer.toHexString(pixel)); + } + + // Test pixels + testRegion(capture, + new Rectangle(5, 5, 90, 90), + new Rectangle(40, 40, 20, 20)); + testRegion(capture, + new Rectangle(105, 5, 90, 90), + new Rectangle(140, 40, 20, 20)); + } + + static void saveImage(BufferedImage img) { + try { + File file = new File("capture.png"); + ImageIO.write(img, "png", file); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/test/jdk/sun/java2d/OpenGL/ShapeClip.java b/test/jdk/sun/java2d/OpenGL/ShapeClip.java new file mode 100644 index 00000000000..f50b7aff5a6 --- /dev/null +++ b/test/jdk/sun/java2d/OpenGL/ShapeClip.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 5002133 + * @key headful + * @requires (os.family != "mac") + * @summary Verifies that the OpenGL pipeline does not affect the color + * buffer when setting up a complex (shape) clip region. The test fails if + * the circular clip region is filled with a green color (the green region + * should not be visible at all). + * @run main/othervm -Dsun.java2d.opengl=True ShapeClip + * @run main/othervm ShapeClip + */ + +/* + * @test + * @bug 5002133 + * @key headful + * @requires (os.family == "mac") + * @summary Verifies that the OpenGL pipeline does not affect the color + * buffer when setting up a complex (shape) clip region. The test fails if + * the circular clip region is filled with a green color (the green region + * should not be visible at all). + * @run main/othervm -Dsun.java2d.opengl=True ShapeClip + * @run main/othervm ShapeClip + */ + +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.geom.Ellipse2D; +import java.awt.image.BufferedImage; +import java.io.File; +import javax.imageio.ImageIO; + +public class ShapeClip extends Panel { + + private static volatile Frame frame; + private static volatile ShapeClip test; + + public void paint(Graphics g) { + + Graphics2D g2d = (Graphics2D)g; + + int width = getWidth(); + int height = getHeight(); + + g2d.setColor(Color.black); + g2d.fillRect(0, 0, width, height); + + g2d.setColor(Color.green); + g2d.fillRect(0, 0, 1, 1); + g2d.setClip(new Ellipse2D.Double(10, 10, 100, 100)); + g2d.setColor(Color.blue); + g2d.fillRect(30, 30, 20, 20); + } + + static void createUI() { + test = new ShapeClip(); + frame = new Frame("OpenGL ShapeClip Test"); + frame.add(test); + frame.setSize(200, 200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + + EventQueue.invokeAndWait(ShapeClip::createUI); + + robot.waitForIdle(); + robot.delay(2000); + + // Grab the screen region + BufferedImage capture = null; + try { + Point pt1 = test.getLocationOnScreen(); + Rectangle rect = new Rectangle(pt1.x, pt1.y, 80, 80); + capture = robot.createScreenCapture(rect); + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + + // Test blue rectangle + int pixel1 = capture.getRGB(40, 40); + if (pixel1 != 0xff0000ff) { + saveImage(capture); + throw new RuntimeException("Failed: Incorrect color for " + + "rectangle " + Integer.toHexString(pixel1)); + } + + // Test clip region (should be same color as background) + int pixel2 = capture.getRGB(60, 40); + if (pixel2 != 0xff000000) { + saveImage(capture); + throw new RuntimeException("Failed: Incorrect color for " + + "clip region " + Integer.toHexString(pixel2)); + } + } + + static void saveImage(BufferedImage img) { + try { + File file = new File("capture.png"); + ImageIO.write(img, "png", file); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/test/jdk/sun/java2d/OpenGL/SrcMaskOps.java b/test/jdk/sun/java2d/OpenGL/SrcMaskOps.java new file mode 100644 index 00000000000..9908cffdefb --- /dev/null +++ b/test/jdk/sun/java2d/OpenGL/SrcMaskOps.java @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4942939 4970674 + * @key headful + * @requires (os.family != "mac") + * @summary Verifies that OGLMaskFill, OGLMaskBlit, and OGLTextRenderer + * operations work properly for non-SrcOver composites. + * @run main/othervm -Dsun.java2d.opengl=True SrcMaskOps + * @run main/othervm SrcMaskOps + */ + +/* + * @test + * @bug 4942939 4970674 + * @key headful + * @requires (os.family == "mac") + * @summary Verifies that OGLMaskFill, OGLMaskBlit, and OGLTextRenderer + * operations work properly for non-SrcOver composites. + * @run main/othervm -Dsun.java2d.opengl=True SrcMaskOps + * @run main/othervm SrcMaskOps + */ + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Font; +import java.awt.Frame; +import java.awt.GradientPaint; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import java.io.File; +import javax.imageio.ImageIO; + +public class SrcMaskOps extends Panel { + + static volatile Frame frame; + static volatile SrcMaskOps test; + + static final int SRX = 50; + static final int SRY = 50; + static final int GPX = 90; + static final int GPY = 50; + static final int DTX = 120; + static final int DTY = 70; + + public void paint(Graphics g) { + + Graphics2D g2d = (Graphics2D)g; + + g2d.setColor(Color.white); + g2d.fillRect(0, 0, getWidth(), getHeight()); + + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + g2d.setComposite(AlphaComposite.Src); + + g2d.setColor(Color.blue); + g2d.drawRect(SRX, SRY, 20, 20); + + g2d.setPaint(new GradientPaint(0.0f, 0.0f, Color.red, + 100.0f, 100.f, Color.red, true)); + g2d.drawRect(GPX, GPY, 20, 20); + + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_OFF); + + g2d.setColor(Color.red); + Font font = new Font(Font.DIALOG, Font.PLAIN, 20); + g2d.setFont(font); + g2d.drawString("HELLO", DTX, DTY); + } + + static void createUI() { + frame = new Frame("OpenGL SrcMaskOps Test"); + test = new SrcMaskOps(); + frame.add(test); + frame.setSize(300, 300); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public static void main(String[] args) throws Exception { + + Robot robot = new Robot(); + BufferedImage capture = null; + try { + EventQueue.invokeAndWait(SrcMaskOps::createUI); + robot.waitForIdle(); + robot.delay(3000); + + // Grab the screen region + Point pt1 = test.getLocationOnScreen(); + Rectangle rect = new Rectangle(pt1.x, pt1.y, 300, 300); + capture = robot.createScreenCapture(rect); + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + + // Test solid rectangle + int pixel1, pixel2; + pixel1 = capture.getRGB(SRX, SRY); + pixel2 = capture.getRGB(SRX+2, SRY+2); + if (!similar(pixel1, 0xff0000ff) || !similar(pixel2, 0xffffffff)) { + saveImage(capture); + throw new RuntimeException(getMsg("solid rectangle", pixel1, pixel2)); + } + + // Test GradientPaint rectangle + pixel1 = capture.getRGB(GPX, GPY); + pixel2 = capture.getRGB(GPX+2, GPY+2); + if (!similar(pixel1, 0xffff0000) || !similar(pixel2, 0xffffffff)) { + saveImage(capture); + throw new RuntimeException(getMsg("GradientPaint rectangle", pixel1, pixel2)); + } + + // Test solid text + pixel1 = capture.getRGB(DTX+2, DTY-5); + pixel2 = capture.getRGB(DTX+5, DTY-5); + if (!similar(pixel1, 0xffff0000) || !similar(pixel2, 0xffffffff)) { + saveImage(capture); + throw new RuntimeException(getMsg("solid text", pixel1, pixel2)); + } + + } + + static boolean similar(int p1, int p2) { + int a1 = (p1 >> 24) & 0xff; + int r1 = (p1 >> 16) & 0xff; + int g1 = (p1 >> 8) & 0xff; + int b1 = p1 & 0xff; + int a2 = (p2 >> 24) & 0xff; + int r2 = (p2 >> 16) & 0xff; + int g2 = (p2 >> 8) & 0xff; + int b2 = p2 & 0xff; + + int allowedDiff = 0x10; + return + (Math.abs(a1 - a2) <= allowedDiff) && + (Math.abs(r1 - r2) <= allowedDiff) && + (Math.abs(g1 - g2) <= allowedDiff) && + (Math.abs(b1 - b2) <= allowedDiff); + } + + static String getMsg(String r, int p1, int p2) { + return "Failed: Incorrect color[s] for " + r + " got " + + Integer.toHexString(p1) + " and " + Integer.toHexString(p2); + } + + static void saveImage(BufferedImage img) { + try { + File file = new File("capture.png"); + ImageIO.write(img, "png", file); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/test/jdk/sun/java2d/OpenGL/VolatileSubRegion.java b/test/jdk/sun/java2d/OpenGL/VolatileSubRegion.java new file mode 100644 index 00000000000..7ec350bc958 --- /dev/null +++ b/test/jdk/sun/java2d/OpenGL/VolatileSubRegion.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6244071 + * @key headful + * @requires (os.family != "mac") + * @summary Verifies that copying a subregion from a VolatileImage works + * properly with the OGL pipeline. + * @run main/othervm VolatileSubRegion + * @run main/othervm -Dsun.java2d.opengl=True -Dsun.java2d.opengl.fbobject=true VolatileSubRegion + * @run main/othervm -Dsun.java2d.opengl=True -Dsun.java2d.opengl.fbobject=false VolatileSubRegion + */ + +/* + * @test + * @bug 6244071 + * @key headful + * @requires (os.family == "mac") + * @summary Verifies that copying a subregion from a VolatileImage works + * properly with the OGL pipeline. + * @run main/othervm VolatileSubRegion + * @run main/othervm -Dsun.java2d.opengl=True -Dsun.java2d.opengl.fbobject=true VolatileSubRegion + * @run main/othervm -Dsun.java2d.opengl=True -Dsun.java2d.opengl.fbobject=false VolatileSubRegion + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import java.awt.image.IndexColorModel; +import java.awt.image.VolatileImage; +import java.io.File; +import javax.imageio.ImageIO; + +public class VolatileSubRegion extends Panel { + + private VolatileImage img; + + public void paint(Graphics g) { + + Graphics2D g2d = (Graphics2D)g; + + if (img == null) { + img = createVolatileImage(200, 200); + Graphics2D goff = img.createGraphics(); + goff.setColor(Color.green); + goff.fillRect(50, 0, 100, 50); + goff.setColor(Color.blue); + goff.fillRect(0, 0, 200, 200); + goff.setColor(Color.red); + goff.fillRect(50, 50, 100, 100); + goff.setColor(Color.yellow); + goff.fillRect(50, 150, 100, 50); + goff.dispose(); + } + + g2d.setColor(Color.white); + g2d.fillRect(0, 0, getWidth(), getHeight()); + + g2d.drawImage(img, + 50, 50, 200, 200, + 50, 50, 200, 200, + null); + + } + + + private static volatile VolatileSubRegion test; + private static volatile Frame frame; + + static void createUI() { + test = new VolatileSubRegion(); + frame = new Frame("OpenGL VolatileSubRegion Test"); + frame.add(test); + frame.setSize(300, 300); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + + EventQueue.invokeAndWait(VolatileSubRegion::createUI); + + robot.waitForIdle(); + robot.delay(2000); + + BufferedImage capture = null; + try { + GraphicsConfiguration gc = frame.getGraphicsConfiguration(); + if (gc.getColorModel() instanceof IndexColorModel) { + System.out.println("IndexColorModel detected: " + + "test considered PASSED"); + return; + } + Point pt1 = test.getLocationOnScreen(); + Rectangle rect = new Rectangle(pt1.x, pt1.y, 200, 200); + capture = robot.createScreenCapture(rect); + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + + // Test pixels + int pixel1 = capture.getRGB(49, 50); + if (pixel1 != 0xffffffff) { + saveImage(capture); + throw new RuntimeException(getMsg("background pixel", pixel1)); + } + int pixel2 = capture.getRGB(50, 50); + if (pixel2 != 0xffff0000) { + saveImage(capture); + throw new RuntimeException(getMsg("red region", pixel2)); + } + int pixel3 = capture.getRGB(50, 150); + if (pixel3 != 0xffffff00) { + saveImage(capture); + throw new RuntimeException(getMsg("yellow region", pixel3)); + } + } + + static String getMsg(String r, int p1) { + return "Failed: Incorrect color for " + r + " : got " + Integer.toHexString(p1); + } + + static void saveImage(BufferedImage img) { + try { + File file = new File("capture.png"); + ImageIO.write(img, "png", file); + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/test/jdk/sun/java2d/OpenGL/XformVolatile.java b/test/jdk/sun/java2d/OpenGL/XformVolatile.java new file mode 100644 index 00000000000..44e7c7ee8ba --- /dev/null +++ b/test/jdk/sun/java2d/OpenGL/XformVolatile.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4970836 + * @key headful + * @requires (os.family != "mac") + * @summary Verifies that transformed VolatileImage copies work properly with + * the OGL pipeline. + * @run main/othervm XformVolatile + * @run main/othervm -Dsun.java2d.opengl=True -Dsun.java2d.opengl.fbobject=true XformVolatile + * @run main/othervm -Dsun.java2d.opengl=True -Dsun.java2d.opengl.fbobject=false XformVolatile + */ + +/* + * @test + * @bug 4970836 + * @key headful + * @requires (os.family == "mac") + * @summary Verifies that transformed VolatileImage copies work properly with + * the OGL pipeline. + * @run main/othervm XformVolatile + * @run main/othervm -Dsun.java2d.opengl=True -Dsun.java2d.opengl.fbobject=true XformVolatile + * @run main/othervm -Dsun.java2d.opengl=True -Dsun.java2d.opengl.fbobject=false XformVolatile + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import java.awt.image.VolatileImage; +import java.io.File; +import javax.imageio.ImageIO; + +public class XformVolatile extends Panel { + + private static volatile Frame frame; + private static volatile XformVolatile test; + private volatile VolatileImage img; + + public void paint(Graphics g) { + + Graphics2D g2d = (Graphics2D)g; + + if (img == null) { + img = createVolatileImage(200, 200); + Graphics2D goff = img.createGraphics(); + goff.setColor(Color.blue); + goff.fillRect(0, 0, 200, 200); + goff.setColor(Color.red); + goff.fillPolygon(new int[] {10, 100, 190}, + new int[] {190, 10, 190}, 3); + goff.dispose(); + } + + g2d.setColor(Color.black); + g2d.fillRect(0, 0, getWidth(), getHeight()); + + g2d.rotate(Math.toRadians(3.0)); + g2d.drawImage(img, 0, 0, null); + } + + static void createUI() { + test = new XformVolatile(); + frame = new Frame("OpenGL XformVolatile Test"); + frame.add(test); + frame.setSize(300, 300); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public static void main(String[] args) throws Exception { + + Robot robot = new Robot(); + + EventQueue.invokeAndWait(XformVolatile::createUI); + + robot.waitForIdle(); + robot.delay(2000); + + // Grab the screen region + BufferedImage capture = null; + try { + Point pt1 = test.getLocationOnScreen(); + Rectangle rect = new Rectangle(pt1.x, pt1.y, 200, 200); + capture = robot.createScreenCapture(rect); + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + + // Test inner and outer pixels + int pixel1 = capture.getRGB(5, 175); + if (pixel1 != 0xff0000ff) { + saveImage(capture); + throw new RuntimeException(getMsg("inner", pixel1)); + } + int pixel2 = capture.getRGB(5, 188); + if (pixel2 != 0xffff0000) { + saveImage(capture); + throw new RuntimeException(getMsg("inner", pixel2)); + } + } + + static String getMsg(String r, int p1) { + return "Failed: Incorrect color for " + r + " pixel: got " + Integer.toHexString(p1); + } + + static void saveImage(BufferedImage img) { + try { + File file = new File("capture.png"); + ImageIO.write(img, "png", file); + } catch (Exception e) { + e.printStackTrace(); + } + } +} From 1ea8cfa6dc8e6f96fd87553331abaae17ec173ea Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 7 Oct 2025 16:54:36 +0000 Subject: [PATCH 052/160] 8369226: GHA: Switch to MacOS 15 Reviewed-by: erikj, ayang, sgehwolf --- .github/workflows/main.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0d8663fab1a..4d1e8a8be3d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -327,8 +327,8 @@ jobs: uses: ./.github/workflows/build-macos.yml with: platform: macos-x64 - runs-on: 'macos-13' - xcode-toolset-version: '14.3.1' + runs-on: 'macos-15-intel' + xcode-toolset-version: '16.4' configure-arguments: ${{ github.event.inputs.configure-arguments }} make-arguments: ${{ github.event.inputs.make-arguments }} dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }} @@ -340,8 +340,8 @@ jobs: uses: ./.github/workflows/build-macos.yml with: platform: macos-aarch64 - runs-on: 'macos-14' - xcode-toolset-version: '15.4' + runs-on: 'macos-15' + xcode-toolset-version: '16.4' configure-arguments: ${{ github.event.inputs.configure-arguments }} make-arguments: ${{ github.event.inputs.make-arguments }} dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }} @@ -432,9 +432,9 @@ jobs: with: platform: macos-aarch64 bootjdk-platform: macos-aarch64 - runs-on: macos-14 + runs-on: macos-15 dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }} - xcode-toolset-version: '15.4' + xcode-toolset-version: '16.4' debug-suffix: -debug test-windows-x64: From 6b3162620bd808227ec7b4331ae6fc32ceb909e8 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Tue, 7 Oct 2025 17:21:13 +0000 Subject: [PATCH 053/160] 8368845: x-IBM930 uses incorrect character for Hex 42 60 Reviewed-by: sherman, rriggs, iris --- make/data/charsetmapping/IBM930.c2b | 5 ----- make/data/charsetmapping/IBM930.map | 10 +--------- test/jdk/sun/nio/cs/mapping/CoderTest.java | 4 ++-- test/jdk/sun/nio/cs/mapping/ConverterTest.java | 5 +++-- test/jdk/sun/nio/cs/mapping/Cp930.b2c | 2 +- test/jdk/sun/nio/cs/mapping/TestConv.java | 4 ++-- 6 files changed, 9 insertions(+), 21 deletions(-) diff --git a/make/data/charsetmapping/IBM930.c2b b/make/data/charsetmapping/IBM930.c2b index 88754763fe3..72107424104 100644 --- a/make/data/charsetmapping/IBM930.c2b +++ b/make/data/charsetmapping/IBM930.c2b @@ -32,11 +32,6 @@ 547d 92ca 53da 9b7e 446e f86f -# -# we should use this one instead of the 4260<-ff0d -#4260 2212 -4260 ff0d -# 426A 00A6 43A1 301C 444A 2014 diff --git a/make/data/charsetmapping/IBM930.map b/make/data/charsetmapping/IBM930.map index 4b9dad9526b..7939e795bdf 100644 --- a/make/data/charsetmapping/IBM930.map +++ b/make/data/charsetmapping/IBM930.map @@ -25,13 +25,6 @@ # 4260 <--> 2212 # 426A <--> 00A6 # -# Warning: -# "our old" implementation seems agree with above "new" mappings -# except the entries 4260 <-> 2212. To keep the "compatbility" -# with the "old" implementation, I changed the entries "temporarily" -# 4260 <-> 2212 -# 4260 <- ff0d -# 00 0000 01 0001 02 0002 @@ -407,8 +400,7 @@ FF 009F 425D FF09 425E FF1B 425F FFE2 -#4260 FF0D -4260 2212 +4260 FF0D 4261 FF0F 426A FFE4 426B FF0C diff --git a/test/jdk/sun/nio/cs/mapping/CoderTest.java b/test/jdk/sun/nio/cs/mapping/CoderTest.java index 05913a40535..2f766736743 100644 --- a/test/jdk/sun/nio/cs/mapping/CoderTest.java +++ b/test/jdk/sun/nio/cs/mapping/CoderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,7 @@ */ /* @test - @bug 4691554 6221056 6380723 6404504 6419565 6529796 8301119 + @bug 4691554 6221056 6380723 6404504 6419565 6529796 8301119 8368845 @summary Test the supported New I/O coders @modules jdk.charsets @run main CoderTest diff --git a/test/jdk/sun/nio/cs/mapping/ConverterTest.java b/test/jdk/sun/nio/cs/mapping/ConverterTest.java index be8df03230c..8d33670b0a5 100644 --- a/test/jdk/sun/nio/cs/mapping/ConverterTest.java +++ b/test/jdk/sun/nio/cs/mapping/ConverterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,8 @@ * @summary test Bug 4199484 * @modules jdk.charsets * @run main ConverterTest - * @bug 4199484 4199599 4199601 4199602 4159519 4201529 4199604 4201532 4947038 6217210 + * @bug 4199484 4199599 4199601 4199602 4159519 4201529 4199604 4201532 4947038 + * 6217210 8368845 */ import java.util.*; diff --git a/test/jdk/sun/nio/cs/mapping/Cp930.b2c b/test/jdk/sun/nio/cs/mapping/Cp930.b2c index 67cc93fd628..3cd45375e2d 100644 --- a/test/jdk/sun/nio/cs/mapping/Cp930.b2c +++ b/test/jdk/sun/nio/cs/mapping/Cp930.b2c @@ -340,7 +340,7 @@ F9 0039 0E425D0F FF09 0E425E0F FF1B 0E425F0F FFE2 -0E42600F 2212 +0E42600F FF0D 0E42610F FF0F 0E426A0F FFE4 0E426B0F FF0C diff --git a/test/jdk/sun/nio/cs/mapping/TestConv.java b/test/jdk/sun/nio/cs/mapping/TestConv.java index 2f4ea424f6c..3bd0b15a7d3 100644 --- a/test/jdk/sun/nio/cs/mapping/TestConv.java +++ b/test/jdk/sun/nio/cs/mapping/TestConv.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,7 @@ */ /* @test - @bug 4179153 4652234 6529796 + @bug 4179153 4652234 6529796 8368845 @summary Read code mapping table and check code conversion @modules jdk.charsets */ From 7f070d356c479ae30fe84fcf4d322c0b693fa15a Mon Sep 17 00:00:00 2001 From: Mikael Vidstedt Date: Tue, 7 Oct 2025 17:37:31 +0000 Subject: [PATCH 054/160] 8369246: Use https in make/devkit scripts Reviewed-by: ayang, erikj --- make/devkit/Tools.gmk | 10 +++++----- make/devkit/createAutoconfBundle.sh | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/make/devkit/Tools.gmk b/make/devkit/Tools.gmk index 6241674071c..f6ea6749f48 100644 --- a/make/devkit/Tools.gmk +++ b/make/devkit/Tools.gmk @@ -117,13 +117,13 @@ dependencies := gcc binutils ccache mpfr gmp mpc gdb $(foreach dep,$(dependencies),$(eval $(dep)_ver := $(dep)-$($(dep)_ver_only))) -GCC_URL := http://ftp.gnu.org/pub/gnu/gcc/$(gcc_ver)/$(gcc_ver).tar.xz -BINUTILS_URL := http://ftp.gnu.org/pub/gnu/binutils/$(binutils_ver).tar.gz +GCC_URL := https://ftp.gnu.org/pub/gnu/gcc/$(gcc_ver)/$(gcc_ver).tar.xz +BINUTILS_URL := https://ftp.gnu.org/pub/gnu/binutils/$(binutils_ver).tar.gz CCACHE_URL := https://github.com/ccache/ccache/releases/download/v$(ccache_ver_only)/$(ccache_ver).tar.xz MPFR_URL := https://www.mpfr.org/$(mpfr_ver)/$(mpfr_ver).tar.bz2 -GMP_URL := http://ftp.gnu.org/pub/gnu/gmp/$(gmp_ver).tar.bz2 -MPC_URL := http://ftp.gnu.org/pub/gnu/mpc/$(mpc_ver).tar.gz -GDB_URL := http://ftp.gnu.org/gnu/gdb/$(gdb_ver).tar.xz +GMP_URL := https://ftp.gnu.org/pub/gnu/gmp/$(gmp_ver).tar.bz2 +MPC_URL := https://ftp.gnu.org/pub/gnu/mpc/$(mpc_ver).tar.gz +GDB_URL := https://ftp.gnu.org/gnu/gdb/$(gdb_ver).tar.xz REQUIRED_MIN_MAKE_MAJOR_VERSION := 4 ifneq ($(REQUIRED_MIN_MAKE_MAJOR_VERSION),) diff --git a/make/devkit/createAutoconfBundle.sh b/make/devkit/createAutoconfBundle.sh index ebe9c427f76..4697e4eb1e3 100644 --- a/make/devkit/createAutoconfBundle.sh +++ b/make/devkit/createAutoconfBundle.sh @@ -93,7 +93,7 @@ elif test "x$TARGET_PLATFORM" = xlinux_x64; then rpm2cpio $OUTPUT_ROOT/m4-$M4_VERSION.el6.x86_64.rpm | cpio -d -i elif test "x$TARGET_PLATFORM" = xlinux_x86; then M4_VERSION=1.4.13-5 - wget http://yum.oracle.com/repo/OracleLinux/OL6/latest/i386/getPackage/m4-$M4_VERSION.el6.i686.rpm + wget https://yum.oracle.com/repo/OracleLinux/OL6/latest/i386/getPackage/m4-$M4_VERSION.el6.i686.rpm cd $IMAGE_DIR rpm2cpio $OUTPUT_ROOT/m4-$M4_VERSION.el6.i686.rpm | cpio -d -i else From 6bfd018beaf187940ebafc71885045b4aabca673 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Tue, 7 Oct 2025 19:08:22 +0000 Subject: [PATCH 055/160] 8366002: Beans.instantiate needs to describe the lookup procedure Reviewed-by: serb, aivanov --- .../share/classes/java/beans/Beans.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/java.desktop/share/classes/java/beans/Beans.java b/src/java.desktop/share/classes/java/beans/Beans.java index 313bfe98515..a95aeb45cbb 100644 --- a/src/java.desktop/share/classes/java/beans/Beans.java +++ b/src/java.desktop/share/classes/java/beans/Beans.java @@ -64,6 +64,22 @@ public class Beans { *

    * Instantiate a JavaBean. *

    + * The bean is created based on a name relative to a class-loader. + * This name should be a {@linkplain ClassLoader##binary-name binary name} of a class such as "a.b.C". + *

    + * The given name can indicate either a serialized object or a class. + * We first try to treat the {@code beanName} as a serialized object + * name then as a class name. + *

    + * When using the {@code beanName} as a serialized object name we convert the + * given {@code beanName} to a resource pathname and add a trailing ".ser" suffix. + * We then try to load a serialized object from that resource. + *

    + * For example, given a {@code beanName} of "x.y", {@code Beans.instantiate} would first + * try to read a serialized object from the resource "x/y.ser" and if + * that failed it would try to load the class "x.y" and create an + * instance of that class. + * * @return a JavaBean * @param cls the class-loader from which we should create * the bean. If this is null, then the system @@ -84,6 +100,22 @@ public class Beans { *

    * Instantiate a JavaBean. *

    + * The bean is created based on a name relative to a class-loader. + * This name should be a {@linkplain ClassLoader##binary-name binary name} of a class such as "a.b.C". + *

    + * The given name can indicate either a serialized object or a class. + * We first try to treat the {@code beanName} as a serialized object + * name then as a class name. + *

    + * When using the {@code beanName} as a serialized object name we convert the + * given {@code beanName} to a resource pathname and add a trailing ".ser" suffix. + * We then try to load a serialized object from that resource. + *

    + * For example, given a {@code beanName} of "x.y", {@code Beans.instantiate} would first + * try to read a serialized object from the resource "x/y.ser" and if + * that failed it would try to load the class "x.y" and create an + * instance of that class. + * * @return a JavaBean * * @param cls the class-loader from which we should create From 910bb68e5191f830ff6f3dff5753e4e5f6214a7b Mon Sep 17 00:00:00 2001 From: Archie Cobbs Date: Tue, 7 Oct 2025 19:32:08 +0000 Subject: [PATCH 056/160] 8349847: Support configuring individual lint categories as errors Reviewed-by: vromero --- .../com/sun/tools/javac/code/Lint.java | 29 +---- .../sun/tools/javac/main/JavaCompiler.java | 23 +++- .../com/sun/tools/javac/main/Option.java | 18 +++ .../JavacProcessingEnvironment.java | 2 +- .../tools/javac/resources/javac.properties | 10 +- .../classes/com/sun/tools/javac/util/Log.java | 30 ++++- .../com/sun/tools/javac/util/Options.java | 113 ++++++++++++++---- src/jdk.compiler/share/man/javac.md | 13 +- .../tools/javac/warnings/WerrorLint.e1.out | 4 + .../tools/javac/warnings/WerrorLint.e2.out | 5 + .../tools/javac/warnings/WerrorLint.java | 23 ++++ .../tools/javac/warnings/WerrorLint.w1.out | 2 + .../tools/javac/warnings/WerrorLint.w2.out | 3 + 13 files changed, 214 insertions(+), 61 deletions(-) create mode 100644 test/langtools/tools/javac/warnings/WerrorLint.e1.out create mode 100644 test/langtools/tools/javac/warnings/WerrorLint.e2.out create mode 100644 test/langtools/tools/javac/warnings/WerrorLint.java create mode 100644 test/langtools/tools/javac/warnings/WerrorLint.w1.out create mode 100644 test/langtools/tools/javac/warnings/WerrorLint.w2.out diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java index 88c9da5d9e8..3a8b4e5dbea 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java @@ -147,33 +147,10 @@ public class Lint { // Process command line options on demand to allow use of root Lint early during startup private void initializeRootIfNeeded() { - - // Already initialized? - if (values != null) - return; - - // Initialize enabled categories based on "-Xlint" flags - if (options.isSet(Option.XLINT) || options.isSet(Option.XLINT_CUSTOM, Option.LINT_CUSTOM_ALL)) { - // If -Xlint or -Xlint:all is given, enable all categories by default - values = EnumSet.allOf(LintCategory.class); - } else if (options.isSet(Option.XLINT_CUSTOM, Option.LINT_CUSTOM_NONE)) { - // if -Xlint:none is given, disable all categories by default - values = LintCategory.newEmptySet(); - } else { - // otherwise, enable on-by-default categories - values = getDefaults(); + if (values == null) { + values = options.getLintCategoriesOf(Option.XLINT, this::getDefaults); + suppressedValues = LintCategory.newEmptySet(); } - - // Look for specific overrides - for (LintCategory lc : LintCategory.values()) { - if (options.isLintExplicitlyEnabled(lc)) { - values.add(lc); - } else if (options.isLintExplicitlyDisabled(lc)) { - values.remove(lc); - } - } - - suppressedValues = LintCategory.newEmptySet(); } // Obtain the set of on-by-default categories. Note that for a few categories, diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java index ee11304dce9..2469dc9e031 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java @@ -31,6 +31,7 @@ import java.nio.file.InvalidPathException; import java.nio.file.ReadOnlyFileSystemException; import java.util.Collection; import java.util.Comparator; +import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; @@ -55,6 +56,7 @@ import javax.tools.StandardLocation; import com.sun.source.util.TaskEvent; import com.sun.tools.javac.api.MultiTaskListener; import com.sun.tools.javac.code.*; +import com.sun.tools.javac.code.Lint.LintCategory; import com.sun.tools.javac.code.Source.Feature; import com.sun.tools.javac.code.Symbol.ClassSymbol; import com.sun.tools.javac.code.Symbol.CompletionFailure; @@ -440,7 +442,8 @@ public class JavaCompiler { context.get(DiagnosticListener.class) != null; devVerbose = options.isSet("dev"); processPcks = options.isSet("process.packages"); - werror = options.isSet(WERROR); + werrorAny = options.isSet(WERROR) || options.isSet(WERROR_CUSTOM, Option.LINT_CUSTOM_ALL); + werrorLint = options.getLintCategoriesOf(WERROR, LintCategory::newEmptySet); verboseCompilePolicy = options.isSet("verboseCompilePolicy"); @@ -513,9 +516,13 @@ public class JavaCompiler { */ protected boolean processPcks; - /** Switch: treat warnings as errors + /** Switch: treat any kind of warning (lint or non-lint) as an error. */ - protected boolean werror; + protected boolean werrorAny; + + /** Switch: treat lint warnings in the specified {@link LintCategory}s as errors. + */ + protected EnumSet werrorLint; /** Switch: is annotation processing requested explicitly via * CompilationTask.setProcessors? @@ -581,12 +588,20 @@ public class JavaCompiler { */ public int errorCount() { log.reportOutstandingWarnings(); - if (werror && log.nerrors == 0 && log.nwarnings > 0) { + if (log.nerrors == 0 && log.nwarnings > 0 && + (werrorAny || werrorLint.clone().removeAll(log.lintWarnings))) { log.error(Errors.WarningsAndWerror); } return log.nerrors; } + /** + * Should warnings in the given lint category be treated as errors due to a {@code -Werror} flag? + */ + public boolean isWerror(LintCategory lc) { + return werrorAny || werrorLint.contains(lc); + } + protected final Queue stopIfError(CompileState cs, Queue queue) { return shouldStop(cs) ? new ListBuffer() : queue; } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java index 8d5ad4c4d78..c14767a7a8c 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java @@ -563,6 +563,8 @@ public enum Option { // treat warnings as errors WERROR("-Werror", "opt.Werror", STANDARD, BASIC), + WERROR_CUSTOM("-Werror:", "opt.arg.Werror", "opt.Werror.custom", STANDARD, BASIC, ANYOF, getXLintChoices()), + // prompt after each error // new Option("-prompt", "opt.prompt"), PROMPT("-prompt", null, HIDDEN, BASIC), @@ -1132,6 +1134,22 @@ public enum Option { return Option.valueOf(name() + "_CUSTOM"); } + /** + * Like {@link #getCustom} but also requires that the custom option supports lint categories. + * + *

    + * In practice, that means {@code option} must be {@link Option#LINT} or {@link Option#WERROR}. + * + * @param option regular option + * @return corresponding lint custom option + * @throws IllegalArgumentException if no such option exists + */ + public Option getLintCustom() { + if (this == XLINT || this == WERROR) + return getCustom(); + throw new IllegalArgumentException(); + } + public boolean isInBasicOptionGroup() { return group == BASIC; } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java index b28f19bd3af..74d082d4b64 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java @@ -211,7 +211,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea } fatalErrors = options.isSet("fatalEnterError"); showResolveErrors = options.isSet("showResolveErrors"); - werror = options.isSet(Option.WERROR); + werror = compiler.isWerror(PROCESSING); fileManager = context.get(JavaFileManager.class); platformAnnotations = initPlatformAnnotations(); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties index 15a63da06eb..6d4276c794b 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties @@ -95,7 +95,13 @@ javac.opt.source=\ Provide source compatibility with the specified Java SE release.\n\ Supported releases: \n {0} javac.opt.Werror=\ - Terminate compilation if warnings occur + Terminate compilation if any warnings occur +javac.opt.arg.Werror=\ + (,)* +javac.opt.Werror.custom=\ + Specify lint categories for which warnings should terminate compilation,\n\ + separated by comma. Precede a key by ''-'' to exclude the specified category.\n\ + Use --help-lint to see the supported keys. javac.opt.A=\ Options to pass to annotation processors javac.opt.implicit=\ @@ -330,7 +336,7 @@ javac.opt.X=\ javac.opt.help=\ Print this help message javac.opt.help.lint=\ - Print the supported keys for -Xlint + Print the supported keys for -Xlint and -Werror javac.opt.help.lint.header=\ The supported keys for -Xlint are: javac.opt.help.lint.enabled.by.default=\ diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java index 95458f339a1..24a77a751fd 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java @@ -171,7 +171,7 @@ public class Log extends AbstractLog { lint.isEnabled(category) : // then emit if the category is enabled category.annotationSuppression ? // else emit if the category is not suppressed, where !lint.isSuppressed(category) : // ...suppression happens via @SuppressWarnings - !options.isLintDisabled(category); // ...suppression happens via -Xlint:-category + !options.isDisabled(Option.XLINT, category); // ...suppression happens via -Xlint:-category if (!emit) return; } @@ -553,10 +553,14 @@ public class Log extends AbstractLog { */ public int nerrors = 0; - /** The number of warnings encountered so far. + /** The total number of warnings encountered so far. */ public int nwarnings = 0; + /** Tracks whether any warnings have been encountered in each {@link LintCategory}. + */ + public final EnumSet lintWarnings = LintCategory.newEmptySet(); + /** The number of errors encountered after MaxErrors was reached. */ public int nsuppressederrors = 0; @@ -885,6 +889,7 @@ public class Log extends AbstractLog { public void clear() { recorded.clear(); sourceMap.clear(); + lintWarnings.clear(); nerrors = 0; nwarnings = 0; nsuppressederrors = 0; @@ -940,7 +945,6 @@ public class Log extends AbstractLog { // Strict warnings are always emitted if (diagnostic.isFlagSet(STRICT)) { writeDiagnostic(diagnostic); - nwarnings++; return; } @@ -948,7 +952,6 @@ public class Log extends AbstractLog { if (emitWarnings || diagnostic.isMandatory()) { if (nwarnings < MaxWarnings) { writeDiagnostic(diagnostic); - nwarnings++; } else { nsuppressedwarns++; } @@ -959,7 +962,6 @@ public class Log extends AbstractLog { if (diagnostic.isFlagSet(API) || shouldReport(diagnostic)) { if (nerrors < MaxErrors) { writeDiagnostic(diagnostic); - nerrors++; } else { nsuppressederrors++; } @@ -973,9 +975,25 @@ public class Log extends AbstractLog { } /** - * Write out a diagnostic. + * Write out a diagnostic and bump the warning and error counters as needed. */ protected void writeDiagnostic(JCDiagnostic diag) { + + // Increment counter(s) + switch (diag.getType()) { + case WARNING: + nwarnings++; + Optional.of(diag) + .map(JCDiagnostic::getLintCategory) + .ifPresent(lintWarnings::add); + break; + case ERROR: + nerrors++; + break; + default: + break; + } + if (diagListener != null) { diagListener.report(diag); return; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Options.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Options.java index 32a31028b68..030e5b21758 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Options.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Options.java @@ -173,66 +173,139 @@ public class Options { /** * Determine if a specific {@link LintCategory} is enabled via a custom - * option flag of the form {@code -Xlint}, {@code -Xlint:all}, or {@code -Xlint:key}. + * option flag of the form {@code -Flag}, {@code -Flag:all}, or {@code -Flag:key}. + * + *

    + * The given {@code option} must have a custom lint variant (available via {@link Option#getLintCustom}). * *

    * Note: It's possible the category was also disabled; this method does not check that. * + * @param option the plain (non-custom) version of the option (e.g., {@link Option#XLINT}) * @param lc the {@link LintCategory} in question - * @return true if {@code lc} has been enabled + * @return true if {@code lc} is enabled via {@code option}'s lint custom variant (e.g., {@link Option#XLINT_CUSTOM}) + * @throws IllegalArgumentException if there is no lint custom variant of {@code option} */ - public boolean isLintEnabled(LintCategory lc) { - return isLintExplicitlyEnabled(lc) || - isSet(Option.XLINT_CUSTOM) || - isSet(Option.XLINT_CUSTOM, Option.LINT_CUSTOM_ALL); + public boolean isEnabled(Option option, LintCategory lc) { + Option custom = option.getLintCustom(); + return isExplicitlyEnabled(option, lc) || isSet(custom) || isSet(custom, Option.LINT_CUSTOM_ALL); } /** * Determine if a specific {@link LintCategory} is disabled via a custom - * option flag of the form {@code -Xlint:none} or {@code -Xlint:-key}. + * option flag of the form {@code -Flag:none} or {@code -Flag:-key}. + * + *

    + * The given {@code option} must have a custom lint variant (available via {@link Option#getLintCustom}). * *

    * Note: It's possible the category was also enabled; this method does not check that. * + * @param option the plain (non-custom) version of the option (e.g., {@link Option#XLINT}) * @param lc the {@link LintCategory} in question - * @return true if {@code lc} has been disabled + * @return true if {@code lc} is disabled via {@code option}'s lint custom variant (e.g., {@link Option#XLINT_CUSTOM}) + * @throws IllegalArgumentException if there is no lint custom variant of {@code option} */ - public boolean isLintDisabled(LintCategory lc) { - return isLintExplicitlyDisabled(lc) || isSet(Option.XLINT_CUSTOM, Option.LINT_CUSTOM_NONE); + public boolean isDisabled(Option option, LintCategory lc) { + return isExplicitlyDisabled(option, lc) || isSet(option.getLintCustom(), Option.LINT_CUSTOM_NONE); } /** * Determine if a specific {@link LintCategory} is explicitly enabled via a custom - * option flag of the form {@code -Xlint:key}. + * option flag of the form {@code -Flag:key}. * *

    - * Note: This does not check for option flags of the form {@code -Xlint} or {@code -Xlint:all}. + * The given {@code option} must have a custom lint variant (available via {@link Option#getLintCustom}). + * + *

    + * Note: This does not check for option flags of the form {@code -Flag} or {@code -Flag:all}. * *

    * Note: It's possible the category was also disabled; this method does not check that. * + * @param option the plain (non-custom) version of the option (e.g., {@link Option#XLINT}) * @param lc the {@link LintCategory} in question - * @return true if {@code lc} has been explicitly enabled + * @return true if {@code lc} is explicitly enabled via {@code option}'s lint custom variant (e.g., {@link Option#XLINT_CUSTOM}) + * @throws IllegalArgumentException if there is no lint custom variant of {@code option} */ - public boolean isLintExplicitlyEnabled(LintCategory lc) { - return lc.optionList.stream().anyMatch(alias -> isSet(Option.XLINT_CUSTOM, alias)); + public boolean isExplicitlyEnabled(Option option, LintCategory lc) { + Option customOption = option.getLintCustom(); + return lc.optionList.stream().anyMatch(alias -> isSet(customOption, alias)); } /** * Determine if a specific {@link LintCategory} is explicitly disabled via a custom - * option flag of the form {@code -Xlint:-key}. + * option flag of the form {@code -Flag:-key}. * *

    - * Note: This does not check for an option flag of the form {@code -Xlint:none}. + * The given {@code option} must have a custom lint variant (available via {@link Option#getLintCustom}). + * + *

    + * Note: This does not check for an option flag of the form {@code -Flag:none}. * *

    * Note: It's possible the category was also enabled; this method does not check that. * + * @param option the plain (non-custom) version of the option (e.g., {@link Option#XLINT}) * @param lc the {@link LintCategory} in question - * @return true if {@code lc} has been explicitly disabled + * @return true if {@code lc} is explicitly disabled via {@code option}'s lint custom variant (e.g., {@link Option#XLINT_CUSTOM}) + * @throws IllegalArgumentException if there is no lint custom variant of {@code option} */ - public boolean isLintExplicitlyDisabled(LintCategory lc) { - return lc.optionList.stream().anyMatch(alias -> isSet(Option.XLINT_CUSTOM, "-" + alias)); + public boolean isExplicitlyDisabled(Option option, LintCategory lc) { + Option customOption = option.getLintCustom(); + return lc.optionList.stream().anyMatch(alias -> isSet(customOption, "-" + alias)); + } + + /** + * Collect the set of {@link LintCategory}s specified by option flag(s) of the form + * {@code -Flag} and/or {@code -Flag:[-]key,[-]key,...}. + * + *

    + * The given {@code option} must have a custom lint variant (available via {@link Option#getLintCustom}). + * + *

    + * The set of categories is calculated as follows. First, an initial set is created: + *

      + *
    • If {@code -Flag} or {@code -Flag:all} appears, the initial set contains all categories; otherwise, + *
    • If {@code -Flag:none} appears, the initial set is empty; otherwise, + *
    • The {@code defaults} parameter is invoked to construct an initial set. + *
    + * Next, for each lint category key {@code key}: + *
      + *
    • If {@code -Flag:key} flag appears, the corresponding category is added to the set; otherwise + *
    • If {@code -Flag:-key} flag appears, the corresponding category is removed to the set + *
    + * Unrecognized {@code key}s are ignored. + * + * @param option the plain (non-custom) version of the option (e.g., {@link Option#XLINT}) + * @param defaults populates the default set, or null for an empty default set + * @return the specified set of categories + * @throws IllegalArgumentException if there is no lint custom variant of {@code option} + */ + public EnumSet getLintCategoriesOf(Option option, Supplier> defaults) { + + // Create the initial set + EnumSet categories; + Option customOption = option.getLintCustom(); + if (isSet(option) || isSet(customOption, Option.LINT_CUSTOM_ALL)) { + categories = EnumSet.allOf(LintCategory.class); + } else if (isSet(customOption, Option.LINT_CUSTOM_NONE)) { + categories = EnumSet.noneOf(LintCategory.class); + } else { + categories = defaults.get(); + } + + // Apply specific overrides + for (LintCategory category : LintCategory.values()) { + if (isExplicitlyEnabled(option, category)) { + categories.add(category); + } else if (isExplicitlyDisabled(option, category)) { + categories.remove(category); + } + } + + // Done + return categories; } public void put(String name, String value) { diff --git a/src/jdk.compiler/share/man/javac.md b/src/jdk.compiler/share/man/javac.md index b8243cc78fb..46246624e53 100644 --- a/src/jdk.compiler/share/man/javac.md +++ b/src/jdk.compiler/share/man/javac.md @@ -1,5 +1,5 @@ --- -# Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1994, 2025, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -448,7 +448,16 @@ file system locations may be directories, JAR files or JMOD files. : Prints version information. `-Werror` -: Terminates compilation when warnings occur. +: Terminates compilation when any warnings occur; this includes warnings in all lint + categories, as well as non-lint warnings. + +`-Werror:`\[`-`\]*key*(`,`\[`-`\]*key*)\* +: Specify lint categories for which warnings should terminate compilation. The keys + `all` and `none` include or exclude all categories (respectively); other keys include + the corresponding category, or exclude it if preceded by a hyphen (`-`). By default, + no categories are included. In order to terminate compilation, the category must also + be enabled (via [`-Xlint`](#option-Xlint-custom), if necessary). + See [`-Xlint`](#option-Xlint-custom) below for the list of lint category keys. ### Extra Options diff --git a/test/langtools/tools/javac/warnings/WerrorLint.e1.out b/test/langtools/tools/javac/warnings/WerrorLint.e1.out new file mode 100644 index 00000000000..ae99cfa5056 --- /dev/null +++ b/test/langtools/tools/javac/warnings/WerrorLint.e1.out @@ -0,0 +1,4 @@ +WerrorLint.java:20:19: compiler.warn.strictfp +- compiler.err.warnings.and.werror +1 error +1 warning diff --git a/test/langtools/tools/javac/warnings/WerrorLint.e2.out b/test/langtools/tools/javac/warnings/WerrorLint.e2.out new file mode 100644 index 00000000000..1c9bd4d54f8 --- /dev/null +++ b/test/langtools/tools/javac/warnings/WerrorLint.e2.out @@ -0,0 +1,5 @@ +WerrorLint.java:20:19: compiler.warn.strictfp +WerrorLint.java:21:30: compiler.warn.empty.if +- compiler.err.warnings.and.werror +1 error +2 warnings diff --git a/test/langtools/tools/javac/warnings/WerrorLint.java b/test/langtools/tools/javac/warnings/WerrorLint.java new file mode 100644 index 00000000000..3331a664d55 --- /dev/null +++ b/test/langtools/tools/javac/warnings/WerrorLint.java @@ -0,0 +1,23 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8349847 + * + * @compile -XDrawDiagnostics -Xlint:none WerrorLint.java + * @compile -XDrawDiagnostics -Xlint:none -Werror WerrorLint.java + * @compile -XDrawDiagnostics -Xlint:none -Werror:empty WerrorLint.java + * @compile -XDrawDiagnostics -Xlint:none -Werror:strictfp WerrorLint.java + * @compile/ref=WerrorLint.w2.out -XDrawDiagnostics -Xlint:all WerrorLint.java + * @compile/fail/ref=WerrorLint.e2.out -XDrawDiagnostics -Xlint:all -Werror WerrorLint.java + * @compile/fail/ref=WerrorLint.e2.out -XDrawDiagnostics -Xlint:all -Werror:empty WerrorLint.java + * @compile/fail/ref=WerrorLint.e2.out -XDrawDiagnostics -Xlint:all -Werror:strictfp WerrorLint.java + * @compile/ref=WerrorLint.w1.out -XDrawDiagnostics WerrorLint.java + * @compile/fail/ref=WerrorLint.e1.out -XDrawDiagnostics -Werror WerrorLint.java + * @compile/ref=WerrorLint.w1.out -XDrawDiagnostics -Werror:empty WerrorLint.java + * @compile/fail/ref=WerrorLint.e1.out -XDrawDiagnostics -Werror:strictfp WerrorLint.java + */ + +class WerrorLint { + strictfp void m() { // [strictfp] - this category is enabled by default + if (hashCode() == 1) ; // [empty] - this category is disabled by default + } +} diff --git a/test/langtools/tools/javac/warnings/WerrorLint.w1.out b/test/langtools/tools/javac/warnings/WerrorLint.w1.out new file mode 100644 index 00000000000..3e19de51033 --- /dev/null +++ b/test/langtools/tools/javac/warnings/WerrorLint.w1.out @@ -0,0 +1,2 @@ +WerrorLint.java:20:19: compiler.warn.strictfp +1 warning diff --git a/test/langtools/tools/javac/warnings/WerrorLint.w2.out b/test/langtools/tools/javac/warnings/WerrorLint.w2.out new file mode 100644 index 00000000000..bac258706a6 --- /dev/null +++ b/test/langtools/tools/javac/warnings/WerrorLint.w2.out @@ -0,0 +1,3 @@ +WerrorLint.java:20:19: compiler.warn.strictfp +WerrorLint.java:21:30: compiler.warn.empty.if +2 warnings From 4ee6079b11034e7de8be72cd2832fb717c2f140d Mon Sep 17 00:00:00 2001 From: Mikael Vidstedt Date: Wed, 8 Oct 2025 02:05:20 +0000 Subject: [PATCH 057/160] 8369328: Use uppercase variable names in the devkit makefiles Reviewed-by: erikj --- make/devkit/Makefile | 50 +++++++-------- make/devkit/Tools.gmk | 146 +++++++++++++++++++++--------------------- 2 files changed, 98 insertions(+), 98 deletions(-) diff --git a/make/devkit/Makefile b/make/devkit/Makefile index ffa23508a13..30e0dce0839 100644 --- a/make/devkit/Makefile +++ b/make/devkit/Makefile @@ -57,61 +57,61 @@ COMMA := , -os := $(shell uname -o) -cpu := $(shell uname -m) +OS := $(shell uname -o) +CPU := $(shell uname -m) # Figure out what platform this is building on. -me := $(cpu)-$(if $(findstring Linux,$(os)),linux-gnu) +ME := $(CPU)-$(if $(findstring Linux,$(OS)),linux-gnu) -$(info Building on platform $(me)) +$(info Building on platform $(ME)) # # By default just build for the current platform, which is assumed to be Linux # ifeq ($(TARGETS), ) - platforms := $(me) - host_platforms := $(platforms) + PLATFORMS := $(ME) + HOST_PLATFORMS := $(PLATFORMS) else - platforms := $(subst $(COMMA), , $(TARGETS)) - host_platforms := $(me) + PLATFORMS := $(subst $(COMMA), , $(TARGETS)) + HOST_PLATFORMS := $(ME) endif -target_platforms := $(platforms) -$(info host_platforms $(host_platforms)) -$(info target_platforms $(target_platforms)) +TARGET_PLATFORMS := $(PLATFORMS) +$(info HOST_PLATFORMS $(HOST_PLATFORMS)) +$(info TARGET_PLATFORMS $(TARGET_PLATFORMS)) -all compile : $(platforms) +all compile : $(PLATFORMS) ifeq ($(SKIP_ME), ) - $(foreach p,$(filter-out $(me),$(platforms)),$(eval $(p) : $$(me))) + $(foreach p,$(filter-out $(ME),$(PLATFORMS)),$(eval $(p) : $$(ME))) endif OUTPUT_ROOT = $(abspath ../../build/devkit) RESULT = $(OUTPUT_ROOT)/result -submakevars = HOST=$@ BUILD=$(me) RESULT=$(RESULT) OUTPUT_ROOT=$(OUTPUT_ROOT) +SUBMAKEVARS = HOST=$@ BUILD=$(ME) RESULT=$(RESULT) OUTPUT_ROOT=$(OUTPUT_ROOT) -$(host_platforms) : +$(HOST_PLATFORMS) : @echo 'Building compilers for $@' - @echo 'Targets: $(target_platforms)' - for p in $(filter $@, $(target_platforms)) $(filter-out $@, $(target_platforms)); do \ - $(MAKE) -f Tools.gmk download-rpms $(submakevars) \ + @echo 'Targets: $(TARGET_PLATFORMS)' + for p in $(filter $@, $(TARGET_PLATFORMS)) $(filter-out $@, $(TARGET_PLATFORMS)); do \ + $(MAKE) -f Tools.gmk download-rpms $(SUBMAKEVARS) \ TARGET=$$p PREFIX=$(RESULT)/$@-to-$$p && \ - $(MAKE) -f Tools.gmk all $(submakevars) \ + $(MAKE) -f Tools.gmk all $(SUBMAKEVARS) \ TARGET=$$p PREFIX=$(RESULT)/$@-to-$$p && \ - $(MAKE) -f Tools.gmk ccache $(submakevars) \ + $(MAKE) -f Tools.gmk ccache $(SUBMAKEVARS) \ TARGET=$@ PREFIX=$(RESULT)/$@-to-$$p || exit 1 ; \ done @echo 'All done"' -today := $(shell date +%Y%m%d) +TODAY := $(shell date +%Y%m%d) define Mktar - $(1)-to-$(2)_tar = $$(RESULT)/sdk-$(1)-to-$(2)-$$(today).tar.gz + $(1)-to-$(2)_tar = $$(RESULT)/sdk-$(1)-to-$(2)-$$(TODAY).tar.gz $$($(1)-to-$(2)_tar) : PLATFORM = $(1)-to-$(2) TARFILES += $$($(1)-to-$(2)_tar) endef -$(foreach p,$(host_platforms),$(foreach t,$(target_platforms),$(eval $(call Mktar,$(p),$(t))))) +$(foreach p,$(HOST_PLATFORMS),$(foreach t,$(TARGET_PLATFORMS),$(eval $(call Mktar,$(p),$(t))))) tars : all $(TARFILES) onlytars : $(TARFILES) @@ -119,9 +119,9 @@ onlytars : $(TARFILES) $(MAKE) -r -f Tars.gmk SRC_DIR=$(RESULT)/$(PLATFORM) TAR_FILE=$@ clean : - rm -rf $(addprefix ../../build/devkit/, result $(host_platforms)) + rm -rf $(addprefix ../../build/devkit/, result $(HOST_PLATFORMS)) dist-clean: clean rm -rf $(addprefix ../../build/devkit/, src download) FORCE : -.PHONY : all compile tars $(configs) $(host_platforms) clean dist-clean +.PHONY : all compile tars $(HOST_PLATFORMS) clean dist-clean diff --git a/make/devkit/Tools.gmk b/make/devkit/Tools.gmk index f6ea6749f48..77a201d0c38 100644 --- a/make/devkit/Tools.gmk +++ b/make/devkit/Tools.gmk @@ -39,7 +39,7 @@ # Fix this... # -uppercase = $(shell echo $1 | tr a-z A-Z) +lowercase = $(shell echo $1 | tr A-Z a-z) $(info TARGET=$(TARGET)) $(info HOST=$(HOST)) @@ -104,26 +104,26 @@ endif ################################################################################ # Define external dependencies -gcc_ver_only := 14.2.0 -binutils_ver_only := 2.43 -ccache_ver_only := 4.10.2 +GCC_VER_ONLY := 14.2.0 +BINUTILS_VER_ONLY := 2.43 +CCACHE_VER_ONLY := 4.10.2 CCACHE_CMAKE_BASED := 1 -mpfr_ver_only := 4.2.1 -gmp_ver_only := 6.3.0 -mpc_ver_only := 1.3.1 -gdb_ver_only := 15.2 +MPFR_VER_ONLY := 4.2.1 +GMP_VER_ONLY := 6.3.0 +MPC_VER_ONLY := 1.3.1 +GDB_VER_ONLY := 15.2 -dependencies := gcc binutils ccache mpfr gmp mpc gdb +DEPENDENCIES := GCC BINUTILS CCACHE MPFR GMP MPC GDB -$(foreach dep,$(dependencies),$(eval $(dep)_ver := $(dep)-$($(dep)_ver_only))) +$(foreach dep,$(DEPENDENCIES),$(eval $(dep)_VER := $(call lowercase,$(dep)-$($(dep)_VER_ONLY)))) -GCC_URL := https://ftp.gnu.org/pub/gnu/gcc/$(gcc_ver)/$(gcc_ver).tar.xz -BINUTILS_URL := https://ftp.gnu.org/pub/gnu/binutils/$(binutils_ver).tar.gz -CCACHE_URL := https://github.com/ccache/ccache/releases/download/v$(ccache_ver_only)/$(ccache_ver).tar.xz -MPFR_URL := https://www.mpfr.org/$(mpfr_ver)/$(mpfr_ver).tar.bz2 -GMP_URL := https://ftp.gnu.org/pub/gnu/gmp/$(gmp_ver).tar.bz2 -MPC_URL := https://ftp.gnu.org/pub/gnu/mpc/$(mpc_ver).tar.gz -GDB_URL := https://ftp.gnu.org/gnu/gdb/$(gdb_ver).tar.xz +GCC_URL := https://ftp.gnu.org/pub/gnu/gcc/$(GCC_VER)/$(GCC_VER).tar.xz +BINUTILS_URL := https://ftp.gnu.org/pub/gnu/binutils/$(BINUTILS_VER).tar.gz +CCACHE_URL := https://github.com/ccache/ccache/releases/download/v$(CCACHE_VER_ONLY)/$(CCACHE_VER).tar.xz +MPFR_URL := https://www.mpfr.org/$(MPFR_VER)/$(MPFR_VER).tar.bz2 +GMP_URL := https://ftp.gnu.org/pub/gnu/gmp/$(GMP_VER).tar.bz2 +MPC_URL := https://ftp.gnu.org/pub/gnu/mpc/$(MPC_VER).tar.gz +GDB_URL := https://ftp.gnu.org/gnu/gdb/$(GDB_VER).tar.xz REQUIRED_MIN_MAKE_MAJOR_VERSION := 4 ifneq ($(REQUIRED_MIN_MAKE_MAJOR_VERSION),) @@ -180,10 +180,10 @@ DOWNLOAD_RPMS := $(DOWNLOAD)/rpms/$(TARGET)-$(LINUX_VERSION) SRCDIR := $(OUTPUT_ROOT)/src # Marker file for unpacking rpms -rpms := $(SYSROOT)/rpms_unpacked +RPMS := $(SYSROOT)/rpms_unpacked # Need to patch libs that are linker scripts to use non-absolute paths -libs := $(SYSROOT)/libs_patched +LIBS := $(SYSROOT)/libs_patched ################################################################################ # Download RPMs @@ -228,7 +228,7 @@ define Download endef # Download and unpack all source packages -$(foreach dep,$(dependencies),$(eval $(call Download,$(call uppercase,$(dep))))) +$(foreach dep,$(DEPENDENCIES),$(eval $(call Download,$(dep)))) ################################################################################ # Unpack RPMS @@ -250,7 +250,7 @@ RPM_FILE_LIST := $(sort $(foreach a, $(RPM_ARCHS), \ # Note. For building linux you should install rpm2cpio. define unrpm $(SYSROOT)/$(notdir $(1)).unpacked : $(1) - $$(rpms) : $(SYSROOT)/$(notdir $(1)).unpacked + $$(RPMS) : $(SYSROOT)/$(notdir $(1)).unpacked endef %.unpacked : @@ -277,7 +277,7 @@ $(foreach p,$(RPM_FILE_LIST),$(eval $(call unrpm,$(p)))) # have it anyway, but just to make sure... # Patch libc.so and libpthread.so to force linking against libraries in sysroot # and not the ones installed on the build machine. -$(libs) : $(rpms) +$(LIBS) : $(RPMS) @echo Patching libc and pthreads @(for f in `find $(SYSROOT) -name libc.so -o -name libpthread.so`; do \ (cat $$f | sed -e 's|/usr/lib64/||g' \ @@ -293,10 +293,10 @@ $(libs) : $(rpms) # Create links for ffi header files so that they become visible by default when using the # devkit. ifeq ($(ARCH), x86_64) - $(SYSROOT)/usr/include/ffi.h: $(rpms) + $(SYSROOT)/usr/include/ffi.h: $(RPMS) cd $(@D) && rm -f $(@F) && ln -s ../lib/libffi-*/include/$(@F) . - $(SYSROOT)/usr/include/ffitarget.h: $(rpms) + $(SYSROOT)/usr/include/ffitarget.h: $(RPMS) cd $(@D) && rm -f $(@F) && ln -s ../lib/libffi-*/include/$(@F) . SYSROOT_LINKS += $(SYSROOT)/usr/include/ffi.h $(SYSROOT)/usr/include/ffitarget.h @@ -305,7 +305,7 @@ endif ################################################################################ # Define marker files for each source package to be compiled -$(foreach dep,$(dependencies),$(eval $(dep) = $(TARGETDIR)/$($(dep)_ver).done)) +$(foreach dep,$(DEPENDENCIES),$(eval $(dep) = $(TARGETDIR)/$($(dep)_VER).done)) ################################################################################ @@ -345,48 +345,48 @@ TOOLS ?= $(call declare_tools,_FOR_TARGET,$(TARGET)-) # CFLAG_ to most likely -m32. define mk_bfd $$(info Libs for $(1)) - $$(BUILDDIR)/$$(binutils_ver)-$(subst /,-,$(1))/Makefile \ + $$(BUILDDIR)/$$(BINUTILS_VER)-$(subst /,-,$(1))/Makefile \ : CFLAGS += $$(CFLAGS_$(1)) - $$(BUILDDIR)/$$(binutils_ver)-$(subst /,-,$(1))/Makefile \ + $$(BUILDDIR)/$$(BINUTILS_VER)-$(subst /,-,$(1))/Makefile \ : LIBDIRS = --libdir=$(TARGETDIR)/$(1) - bfdlib += $$(TARGETDIR)/$$(binutils_ver)-$(subst /,-,$(1)).done - bfdmakes += $$(BUILDDIR)/$$(binutils_ver)-$(subst /,-,$(1))/Makefile + BFDLIB += $$(TARGETDIR)/$$(BINUTILS_VER)-$(subst /,-,$(1)).done + BFDMAKES += $$(BUILDDIR)/$$(BINUTILS_VER)-$(subst /,-,$(1))/Makefile endef # Create one set of bfds etc for each multilib arch $(foreach l,$(LIBDIRS),$(eval $(call mk_bfd,$(l)))) # Only build these two libs. -$(bfdlib) : MAKECMD = all-libiberty all-bfd -$(bfdlib) : INSTALLCMD = install-libiberty install-bfd +$(BFDLIB) : MAKECMD = all-libiberty all-bfd +$(BFDLIB) : INSTALLCMD = install-libiberty install-bfd # Building targets libbfd + libiberty. HOST==TARGET, i.e not # for a cross env. -$(bfdmakes) : CONFIG = --target=$(TARGET) \ +$(BFDMAKES) : CONFIG = --target=$(TARGET) \ --host=$(TARGET) --build=$(BUILD) \ --prefix=$(TARGETDIR) \ --with-sysroot=$(SYSROOT) \ $(LIBDIRS) -$(bfdmakes) : TOOLS = $(call declare_tools,_FOR_TARGET,$(TARGET)-) $(call declare_tools,,$(TARGET)-) +$(BFDMAKES) : TOOLS = $(call declare_tools,_FOR_TARGET,$(TARGET)-) $(call declare_tools,,$(TARGET)-) ################################################################################ -$(gcc) \ - $(binutils) \ - $(gmp) \ - $(mpfr) \ - $(mpc) \ - $(bfdmakes) \ - $(ccache) : ENVS += $(TOOLS) +$(GCC) \ + $(BINUTILS) \ + $(GMP) \ + $(MPFR) \ + $(MPC) \ + $(BFDMAKES) \ + $(CCACHE) : ENVS += $(TOOLS) # libdir to work around hateful bfd stuff installing into wrong dirs... # ensure we have 64 bit bfd support in the HOST library. I.e our # compiler on i686 will know 64 bit symbols, BUT later # we build just the libs again for TARGET, then with whatever the arch # wants. -$(BUILDDIR)/$(binutils_ver)/Makefile : CONFIG += --enable-64-bit-bfd --libdir=$(PREFIX)/$(word 1,$(LIBDIRS)) +$(BUILDDIR)/$(BINUTILS_VER)/Makefile : CONFIG += --enable-64-bit-bfd --libdir=$(PREFIX)/$(word 1,$(LIBDIRS)) ifeq ($(filter $(ARCH), s390x riscv64 ppc64le), ) # gold compiles but cannot link properly on s390x @ gcc 13.2 and Fedore 41 @@ -397,8 +397,8 @@ endif # Makefile creation. Simply run configure in build dir. # Setting CFLAGS to -O2 generates a much faster ld. -$(bfdmakes) \ -$(BUILDDIR)/$(binutils_ver)/Makefile \ +$(BFDMAKES) \ +$(BUILDDIR)/$(BINUTILS_VER)/Makefile \ : $(BINUTILS_CFG) $(info Configuring $@. Log in $(@D)/log.config) @mkdir -p $(@D) @@ -417,7 +417,7 @@ $(BUILDDIR)/$(binutils_ver)/Makefile \ ) > $(@D)/log.config 2>&1 @echo 'done' -$(BUILDDIR)/$(mpfr_ver)/Makefile \ +$(BUILDDIR)/$(MPFR_VER)/Makefile \ : $(MPFR_CFG) $(info Configuring $@. Log in $(@D)/log.config) @mkdir -p $(@D) @@ -432,7 +432,7 @@ $(BUILDDIR)/$(mpfr_ver)/Makefile \ ) > $(@D)/log.config 2>&1 @echo 'done' -$(BUILDDIR)/$(gmp_ver)/Makefile \ +$(BUILDDIR)/$(GMP_VER)/Makefile \ : $(GMP_CFG) $(info Configuring $@. Log in $(@D)/log.config) @mkdir -p $(@D) @@ -449,7 +449,7 @@ $(BUILDDIR)/$(gmp_ver)/Makefile \ ) > $(@D)/log.config 2>&1 @echo 'done' -$(BUILDDIR)/$(mpc_ver)/Makefile \ +$(BUILDDIR)/$(MPC_VER)/Makefile \ : $(MPC_CFG) $(info Configuring $@. Log in $(@D)/log.config) @mkdir -p $(@D) @@ -468,11 +468,11 @@ $(BUILDDIR)/$(mpc_ver)/Makefile \ # Only valid if glibc target -> linux # proper destructor handling for c++ ifneq (,$(findstring linux,$(TARGET))) - $(BUILDDIR)/$(gcc_ver)/Makefile : CONFIG += --enable-__cxa_atexit + $(BUILDDIR)/$(GCC_VER)/Makefile : CONFIG += --enable-__cxa_atexit endif ifeq ($(ARCH), armhfp) - $(BUILDDIR)/$(gcc_ver)/Makefile : CONFIG += --with-float=hard + $(BUILDDIR)/$(GCC_VER)/Makefile : CONFIG += --with-float=hard endif ifneq ($(filter riscv64 ppc64le s390x, $(ARCH)), ) @@ -487,7 +487,7 @@ endif # skip native language. # and link and assemble with the binutils we created # earlier, so --with-gnu* -$(BUILDDIR)/$(gcc_ver)/Makefile \ +$(BUILDDIR)/$(GCC_VER)/Makefile \ : $(GCC_CFG) $(info Configuring $@. Log in $(@D)/log.config) mkdir -p $(@D) @@ -509,17 +509,17 @@ $(BUILDDIR)/$(gcc_ver)/Makefile \ @echo 'done' # need binutils for gcc -$(gcc) : $(binutils) +$(GCC) : $(BINUTILS) # as of 4.3 or so need these for doing config -$(BUILDDIR)/$(gcc_ver)/Makefile : $(gmp) $(mpfr) $(mpc) -$(mpfr) : $(gmp) -$(mpc) : $(gmp) $(mpfr) +$(BUILDDIR)/$(GCC_VER)/Makefile : $(GMP) $(MPFR) $(MPC) +$(MPFR) : $(GMP) +$(MPC) : $(GMP) $(MPFR) ################################################################################ # Build gdb but only where host and target match ifeq ($(HOST), $(TARGET)) - $(BUILDDIR)/$(gdb_ver)/Makefile: $(GDB_CFG) + $(BUILDDIR)/$(GDB_VER)/Makefile: $(GDB_CFG) $(info Configuring $@. Log in $(@D)/log.config) mkdir -p $(@D) ( \ @@ -532,9 +532,9 @@ ifeq ($(HOST), $(TARGET)) ) > $(@D)/log.config 2>&1 @echo 'done' - $(gdb): $(gcc) + $(GDB): $(GCC) else - $(BUILDDIR)/$(gdb_ver)/Makefile: + $(BUILDDIR)/$(GDB_VER)/Makefile: $(info Faking $@, not used when cross-compiling) mkdir -p $(@D) echo "install:" > $@ @@ -543,7 +543,7 @@ endif ################################################################################ # very straightforward. just build a ccache. it is only for host. -$(BUILDDIR)/$(ccache_ver)/Makefile \ +$(BUILDDIR)/$(CCACHE_VER)/Makefile \ : $(CCACHE_SRC_MARKER) $(info Configuring $@. Log in $(@D)/log.config) @mkdir -p $(@D) @@ -554,12 +554,12 @@ $(BUILDDIR)/$(ccache_ver)/Makefile \ ) > $(@D)/log.config 2>&1 @echo 'done' -gccpatch = $(TARGETDIR)/gcc-patched +GCC_PATCHED = $(TARGETDIR)/gcc-patched ################################################################################ # For some reason cpp is not created as a target-compiler ifeq ($(HOST),$(TARGET)) - $(gccpatch) : $(gcc) link_libs + $(GCC_PATCHED) : $(GCC) link_libs @echo -n 'Creating compiler symlinks...' @for f in cpp; do \ if [ ! -e $(PREFIX)/bin/$(TARGET)-$$f ]; \ @@ -587,7 +587,7 @@ ifeq ($(HOST),$(TARGET)) done;) @echo 'done' else - $(gccpatch) : + $(GCC_PATCHED) : @echo 'done' endif @@ -615,7 +615,7 @@ $(PREFIX)/devkit.info: echo '# This file describes to configure how to interpret the contents of this' >> $@ echo '# devkit' >> $@ echo '' >> $@ - echo 'DEVKIT_NAME="$(gcc_ver) - $(LINUX_VERSION)"' >> $@ + echo 'DEVKIT_NAME="$(GCC_VER) - $(LINUX_VERSION)"' >> $@ echo 'DEVKIT_TOOLCHAIN_PATH="$$DEVKIT_ROOT/bin"' >> $@ echo 'DEVKIT_SYSROOT="$$DEVKIT_ROOT/$(TARGET)/sysroot"' >> $@ echo 'DEVKIT_EXTRA_PATH="$$DEVKIT_ROOT/bin"' >> $@ @@ -651,32 +651,32 @@ ifeq ($(TARGET), $(HOST)) @echo 'Creating missing $* soft link' ln -s $(TARGET)-$* $@ - missing-links := $(addprefix $(PREFIX)/bin/, \ - addr2line ar as c++ c++filt dwp elfedit g++ gcc gcc-$(gcc_ver_only) gprof ld ld.bfd \ + MISSING_LINKS := $(addprefix $(PREFIX)/bin/, \ + addr2line ar as c++ c++filt dwp elfedit g++ gcc gcc-$(GCC_VER_ONLY) gprof ld ld.bfd \ ld.gold nm objcopy objdump ranlib readelf size strings strip) endif # Add link to work around "plugin needed to handle lto object" (JDK-8344272) -$(PREFIX)/lib/bfd-plugins/liblto_plugin.so: $(PREFIX)/libexec/gcc/$(TARGET)/$(gcc_ver_only)/liblto_plugin.so +$(PREFIX)/lib/bfd-plugins/liblto_plugin.so: $(PREFIX)/libexec/gcc/$(TARGET)/$(GCC_VER_ONLY)/liblto_plugin.so @echo 'Creating missing $(@F) soft link' @mkdir -p $(@D) ln -s $$(realpath -s --relative-to=$(@D) $<) $@ -missing-links += $(PREFIX)/lib/bfd-plugins/liblto_plugin.so +MISSING_LINKS += $(PREFIX)/lib/bfd-plugins/liblto_plugin.so ################################################################################ -bfdlib : $(bfdlib) -binutils : $(binutils) -rpms : $(rpms) -libs : $(libs) +bfdlib : $(BFDLIB) +binutils : $(BINUTILS) +rpms : $(RPMS) +libs : $(LIBS) sysroot : rpms libs -gcc : sysroot $(gcc) $(gccpatch) -gdb : $(gdb) -all : binutils gcc bfdlib $(PREFIX)/devkit.info $(missing-links) $(SYSROOT_LINKS) \ +gcc : sysroot $(GCC) $(GCC_PATCHED) +gdb : $(GDB) +all : binutils gcc bfdlib $(PREFIX)/devkit.info $(MISSING_LINKS) $(SYSROOT_LINKS) \ $(THESE_MAKEFILES) gdb # this is only built for host. so separate. -ccache : $(ccache) +ccache : $(CCACHE) .PHONY : gcc all binutils bfdlib link_libs rpms libs sysroot From 650fd35b3b30bf16e8caad968bd335d423c87b7d Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Wed, 8 Oct 2025 03:00:30 +0000 Subject: [PATCH 058/160] 8335646: Nimbus : JLabel not painted with LAF defined foreground color on Ubuntu 24.04 Reviewed-by: aivanov, dnguyen, serb --- test/jdk/javax/swing/plaf/basic/BasicHTML/bug4248210.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/javax/swing/plaf/basic/BasicHTML/bug4248210.java b/test/jdk/javax/swing/plaf/basic/BasicHTML/bug4248210.java index fddfbb28384..54f7744ee90 100644 --- a/test/jdk/javax/swing/plaf/basic/BasicHTML/bug4248210.java +++ b/test/jdk/javax/swing/plaf/basic/BasicHTML/bug4248210.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -71,7 +71,7 @@ public class bug4248210 { UIManager.getDefaults().put("Label.foreground", labelColor); } - JLabel label = new JLabel("Can You Read This?"); + JLabel label = new JLabel("\u2588 \u2588 \u2588 \u2588"); label.setSize(150, 30); BufferedImage img = paintToImage(label); From 2ac24bf1bac9c32704ebd72b93a75819b9404063 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Wed, 8 Oct 2025 03:06:29 +0000 Subject: [PATCH 059/160] 8367389: C2 SuperWord: refactor VTransform to model the whole loop instead of just the basic block Reviewed-by: roland, mhaessig --- src/hotspot/share/opto/phasetype.hpp | 7 +- src/hotspot/share/opto/superword.cpp | 220 +++++------------- src/hotspot/share/opto/superword.hpp | 6 +- .../share/opto/superwordVTransformBuilder.cpp | 60 +++-- .../share/opto/superwordVTransformBuilder.hpp | 2 + src/hotspot/share/opto/vectorization.cpp | 74 +++++- src/hotspot/share/opto/vectorization.hpp | 102 +++++--- src/hotspot/share/opto/vtransform.cpp | 149 ++++++++---- src/hotspot/share/opto/vtransform.hpp | 147 +++++++----- .../lib/ir_framework/CompilePhase.java | 6 +- 10 files changed, 447 insertions(+), 326 deletions(-) diff --git a/src/hotspot/share/opto/phasetype.hpp b/src/hotspot/share/opto/phasetype.hpp index 5c733c7dc0a..f24938b51c1 100644 --- a/src/hotspot/share/opto/phasetype.hpp +++ b/src/hotspot/share/opto/phasetype.hpp @@ -89,10 +89,9 @@ flags(PHASEIDEALLOOP2, "PhaseIdealLoop 2") \ flags(PHASEIDEALLOOP3, "PhaseIdealLoop 3") \ flags(AUTO_VECTORIZATION1_BEFORE_APPLY, "AutoVectorization 1, before Apply") \ - flags(AUTO_VECTORIZATION2_AFTER_REORDER, "AutoVectorization 2, after Apply Memop Reordering") \ - flags(AUTO_VECTORIZATION3_AFTER_ADJUST_LIMIT, "AutoVectorization 3, after Adjusting Pre-loop Limit") \ - flags(AUTO_VECTORIZATION4_AFTER_SPECULATIVE_RUNTIME_CHECKS, "AutoVectorization 4, after Adding Speculative Runtime Checks") \ - flags(AUTO_VECTORIZATION5_AFTER_APPLY, "AutoVectorization 5, after Apply") \ + flags(AUTO_VECTORIZATION3_AFTER_ADJUST_LIMIT, "AutoVectorization 2, after Adjusting Pre-loop Limit") \ + flags(AUTO_VECTORIZATION4_AFTER_SPECULATIVE_RUNTIME_CHECKS, "AutoVectorization 3, after Adding Speculative Runtime Checks") \ + flags(AUTO_VECTORIZATION5_AFTER_APPLY, "AutoVectorization 4, after Apply") \ flags(BEFORE_CCP1, "Before PhaseCCP 1") \ flags(CCP1, "PhaseCCP 1") \ flags(ITER_GVN2, "Iter GVN 2") \ diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index 2b3928781b8..41a4339e4c9 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -40,7 +40,7 @@ SuperWord::SuperWord(const VLoopAnalyzer &vloop_analyzer) : NOT_PRODUCT(COMMA is_trace_superword_packset()) NOT_PRODUCT(COMMA is_trace_superword_rejections()) ), - _mem_ref_for_main_loop_alignment(nullptr), + _vpointer_for_main_loop_alignment(nullptr), _aw_for_main_loop_alignment(0), _do_vector_loop(phase()->C->do_vector_loop()), // whether to do vectorization/simd style _num_work_vecs(0), // amount of vector work we have @@ -455,11 +455,16 @@ bool SuperWord::transform_loop() { // // 8) The pairs are combined into vector sized packs. // -// 9) Reorder the memory slices to co-locate members of the memory packs. +// 9) The packs are split and filtered, to ensure correctness and that +// all packs have corresponding vector nodes implemented in the backend. // -// 10) Generate ideal vector nodes for the final set of packs and where necessary, -// inserting scalar promotion, vector creation from multiple scalars, and -// extraction of scalar values from vectors. +// 10) VTransform (see vtransform.hpp) +// - construct from PackSet +// - schedule (detect circles) +// - apply +// - align main loop +// - add runtime checks (aliasing and alignment) +// - build new loop with vector C2 nodes // // Runtime Checks: // Some required properties cannot be proven statically, and require a @@ -498,7 +503,7 @@ bool SuperWord::SLP_extract() { DEBUG_ONLY(verify_packs();) DEBUG_ONLY(verify_no_extract()); - return schedule_and_apply(); + return do_vtransform(); } int SuperWord::MemOp::cmp_by_group(MemOp* a, MemOp* b) { @@ -660,39 +665,9 @@ void SuperWord::create_adjacent_memop_pairs_in_one_group(const GrowableArrayfast_outs(imax); i < imax; i++) { - PhiNode* phi = cl->fast_out(i)->isa_Phi(); - if (phi != nullptr && _vloop.in_bb(phi) && phi->is_memory_phi()) { - Node* phi_tail = phi->in(LoopNode::LoopBackControl); - if (phi_tail != phi->in(LoopNode::EntryControl)) { - _heads.push(phi); - _tails.push(phi_tail->as_Mem()); - } - } - } - - NOT_PRODUCT( if (_vloop.is_trace_memory_slices()) { print(); } ) -} - -#ifndef PRODUCT -void VLoopMemorySlices::print() const { - tty->print_cr("\nVLoopMemorySlices::print: %s", - heads().length() > 0 ? "" : "NONE"); - for (int m = 0; m < heads().length(); m++) { - tty->print("%6d ", m); heads().at(m)->dump(); - tty->print(" "); tails().at(m)->dump(); - } -} -#endif - // Get all memory nodes of a slice, in reverse order void VLoopMemorySlices::get_slice_in_reverse_order(PhiNode* head, MemNode* tail, GrowableArray &slice) const { + assert(head != nullptr && tail != nullptr, "must be slice with memory state loop"); assert(slice.is_empty(), "start empty"); Node* n = tail; Node* prev = nullptr; @@ -1576,7 +1551,7 @@ void SuperWord::filter_packs_for_alignment() { MemNode const* mem = current->as_constrained()->mem_ref(); Node_List* pack = get_pack(mem); assert(pack != nullptr, "memop of final solution must still be packed"); - _mem_ref_for_main_loop_alignment = mem; + _vpointer_for_main_loop_alignment = &vpointer(mem); _aw_for_main_loop_alignment = pack->size() * mem->memory_size(); } } @@ -1946,7 +1921,9 @@ void PackSet::verify() const { } #endif -bool SuperWord::schedule_and_apply() const { +// Build VTransform from SuperWord Packset, and eventually apply it (create new vectorized C2 loop). +// See description at top of "vtransform.hpp". +bool SuperWord::do_vtransform() const { if (_packset.is_empty()) { return false; } // Make an empty transform. @@ -1959,7 +1936,7 @@ bool SuperWord::schedule_and_apply() const { is_trace_superword_info()); #endif VTransform vtransform(_vloop_analyzer, - _mem_ref_for_main_loop_alignment, + _vpointer_for_main_loop_alignment, _aw_for_main_loop_alignment NOT_PRODUCT(COMMA trace) ); @@ -1988,6 +1965,7 @@ bool SuperWord::schedule_and_apply() const { // Apply the vectorization, i.e. we irreversibly edit the C2 graph. At this point, all // correctness and profitability checks have passed, and the graph was successfully scheduled. +// See description at top of "vtransform.hpp". void VTransform::apply() { #ifndef PRODUCT if (_trace._info || TraceLoopOpts) { @@ -2002,9 +1980,6 @@ void VTransform::apply() { Compile* C = phase()->C; C->print_method(PHASE_AUTO_VECTORIZATION1_BEFORE_APPLY, 4, cl()); - _graph.apply_memops_reordering_with_schedule(); - C->print_method(PHASE_AUTO_VECTORIZATION2_AFTER_REORDER, 4, cl()); - adjust_pre_loop_limit_to_align_main_loop_vectors(); C->print_method(PHASE_AUTO_VECTORIZATION3_AFTER_ADJUST_LIMIT, 4, cl()); @@ -2016,102 +1991,11 @@ void VTransform::apply() { C->print_method(PHASE_AUTO_VECTORIZATION5_AFTER_APPLY, 4, cl()); } -// We prepare the memory graph for the replacement of scalar memops with vector memops. -// We reorder all slices in parallel, ensuring that the memops inside each slice are -// ordered according to the _schedule. This means that all packed memops are consecutive -// in the memory graph after the reordering. -void VTransformGraph::apply_memops_reordering_with_schedule() const { -#ifndef PRODUCT - assert(is_scheduled(), "must be already scheduled"); - if (_trace._info) { - print_memops_schedule(); - } -#endif - - ResourceMark rm; - int max_slices = phase()->C->num_alias_types(); - // When iterating over the schedule, we keep track of the current memory state, - // which is the Phi or a store in the loop. - GrowableArray current_state_in_slice(max_slices, max_slices, nullptr); - // The memory state after the loop is the last store inside the loop. If we reorder the - // loop we may have a different last store, and we need to adjust the uses accordingly. - GrowableArray old_last_store_in_slice(max_slices, max_slices, nullptr); - - const GrowableArray& mem_slice_head = _vloop_analyzer.memory_slices().heads(); - - // (1) Set up the initial memory state from Phi. And find the old last store. - for (int i = 0; i < mem_slice_head.length(); i++) { - Node* phi = mem_slice_head.at(i); - assert(phi->is_Phi(), "must be phi"); - int alias_idx = phase()->C->get_alias_index(phi->adr_type()); - current_state_in_slice.at_put(alias_idx, phi); - - // If we have a memory phi, we have a last store in the loop, find it over backedge. - StoreNode* last_store = phi->in(2)->as_Store(); - old_last_store_in_slice.at_put(alias_idx, last_store); - } - - // (2) Walk over schedule, append memops to the current state - // of that slice. If it is a Store, we take it as the new state. - for_each_memop_in_schedule([&] (MemNode* n) { - assert(n->is_Load() || n->is_Store(), "only loads or stores"); - int alias_idx = phase()->C->get_alias_index(n->adr_type()); - Node* current_state = current_state_in_slice.at(alias_idx); - if (current_state == nullptr) { - // If there are only loads in a slice, we never update the memory - // state in the loop, hence there is no phi for the memory state. - // We just keep the old memory state that was outside the loop. - assert(n->is_Load() && !in_bb(n->in(MemNode::Memory)), - "only loads can have memory state from outside loop"); - } else { - igvn().replace_input_of(n, MemNode::Memory, current_state); - if (n->is_Store()) { - current_state_in_slice.at_put(alias_idx, n); - } - } - }); - - // (3) For each slice, we add the current state to the backedge - // in the Phi. Further, we replace uses of the old last store - // with uses of the new last store (current_state). - GrowableArray uses_after_loop; - for (int i = 0; i < mem_slice_head.length(); i++) { - Node* phi = mem_slice_head.at(i); - int alias_idx = phase()->C->get_alias_index(phi->adr_type()); - Node* current_state = current_state_in_slice.at(alias_idx); - assert(current_state != nullptr, "slice is mapped"); - assert(current_state != phi, "did some work in between"); - assert(current_state->is_Store(), "sanity"); - igvn().replace_input_of(phi, 2, current_state); - - // Replace uses of old last store with current_state (new last store) - // Do it in two loops: first find all the uses, and change the graph - // in as second loop so that we do not break the iterator. - Node* last_store = old_last_store_in_slice.at(alias_idx); - assert(last_store != nullptr, "we have a old last store"); - uses_after_loop.clear(); - for (DUIterator_Fast kmax, k = last_store->fast_outs(kmax); k < kmax; k++) { - Node* use = last_store->fast_out(k); - if (!in_bb(use)) { - uses_after_loop.push(use); - } - } - for (int k = 0; k < uses_after_loop.length(); k++) { - Node* use = uses_after_loop.at(k); - for (uint j = 0; j < use->req(); j++) { - Node* def = use->in(j); - if (def == last_store) { - igvn().replace_input_of(use, j, current_state); - } - } - } - } -} - void VTransformGraph::apply_vectorization_for_each_vtnode(uint& max_vector_length, uint& max_vector_width) const { ResourceMark rm; VTransformApplyState apply_state(_vloop_analyzer, _vtnodes.length()); + // Apply: transform the node and connect with inputs (no backedges). for (int i = 0; i < _schedule.length(); i++) { VTransformNode* vtn = _schedule.at(i); VTransformApplyResult result = vtn->apply(apply_state); @@ -2121,6 +2005,16 @@ void VTransformGraph::apply_vectorization_for_each_vtnode(uint& max_vector_lengt max_vector_length = MAX2(max_vector_length, result.vector_length()); max_vector_width = MAX2(max_vector_width, result.vector_width()); } + + // Cleanup: connect backedges + for (int i = 0; i < _schedule.length(); i++) { + VTransformNode* vtn = _schedule.at(i); + vtn->apply_backedge(apply_state); + } + + // Memory uses after the loop: used to connect to old last store, + // now need to connect to new last store. + apply_state.fix_memory_state_uses_after_loop(); } // We call "apply" on every VTransformNode, which replaces the packed scalar nodes with vector nodes. @@ -2774,10 +2668,10 @@ bool VLoopMemorySlices::same_memory_slice(MemNode* m1, MemNode* m2) const { _vloop.phase()->C->get_alias_index(m2->adr_type()); } -LoadNode::ControlDependency VTransformLoadVectorNode::control_dependency() const { +LoadNode::ControlDependency SuperWordVTransformBuilder::load_control_dependency(const Node_List* pack) const { LoadNode::ControlDependency dep = LoadNode::DependsOnlyOnTest; - for (int i = 0; i < nodes().length(); i++) { - Node* n = nodes().at(i); + for (uint i = 0; i < pack->size(); i++) { + Node* n = pack->at(i); assert(n->is_Load(), "only meaningful for loads"); if (!n->depends_only_on_test()) { if (n->as_Load()->has_unknown_control_dependency() && @@ -2795,22 +2689,24 @@ LoadNode::ControlDependency VTransformLoadVectorNode::control_dependency() const // Find the memop pack with the maximum vector width, unless they were already // determined (e.g. by SuperWord::filter_packs_for_alignment()). -void VTransform::determine_mem_ref_and_aw_for_main_loop_alignment() { - if (_mem_ref_for_main_loop_alignment != nullptr) { - assert(VLoop::vectors_should_be_aligned(), "mem_ref only set if filtered for alignment"); +void VTransform::determine_vpointer_and_aw_for_main_loop_alignment() { + if (_vpointer_for_main_loop_alignment != nullptr) { + assert(VLoop::vectors_should_be_aligned(), "vpointer_for_main_loop_alignment only set if filtered for alignment"); return; } - MemNode const* mem_ref = nullptr; + VPointer const* vpointer = nullptr; int max_aw = 0; + bool vpointer_is_load = false; const GrowableArray& vtnodes = _graph.vtnodes(); for (int i = 0; i < vtnodes.length(); i++) { VTransformMemVectorNode* vtn = vtnodes.at(i)->isa_MemVector(); if (vtn == nullptr) { continue; } - MemNode* p0 = vtn->nodes().at(0)->as_Mem(); - int vw = p0->memory_size() * vtn->nodes().length(); + int vw = vtn->vpointer().size(); + bool vtn_is_load = vtn->is_load_in_loop(); + // Generally, we prefer to align with the largest memory op (load or store). // If there are multiple, then SuperWordAutomaticAlignment determines if we // prefer loads or stores. @@ -2820,15 +2716,16 @@ void VTransform::determine_mem_ref_and_aw_for_main_loop_alignment() { // it is worse if a store is split, and less bad if a load is split. // By default, we have SuperWordAutomaticAlignment=1, i.e. we align with a // store if possible, to avoid splitting that store. - bool prefer_store = mem_ref != nullptr && SuperWordAutomaticAlignment == 1 && mem_ref->is_Load() && p0->is_Store(); - bool prefer_load = mem_ref != nullptr && SuperWordAutomaticAlignment == 2 && mem_ref->is_Store() && p0->is_Load(); + bool prefer_store = SuperWordAutomaticAlignment == 1 && vpointer_is_load && !vtn_is_load; + bool prefer_load = SuperWordAutomaticAlignment == 2 && !vpointer_is_load && vtn_is_load; if (vw > max_aw || (vw == max_aw && (prefer_load || prefer_store))) { + vpointer = &vtn->vpointer(); max_aw = vw; - mem_ref = p0; + vpointer_is_load = vtn_is_load; } } - assert(mem_ref != nullptr && max_aw > 0, "found mem_ref and aw"); - _mem_ref_for_main_loop_alignment = mem_ref; + assert(vpointer != nullptr && max_aw > 0, "found vpointer and aw"); + _vpointer_for_main_loop_alignment = vpointer; _aw_for_main_loop_alignment = max_aw; } @@ -2842,13 +2739,17 @@ void VTransform::determine_mem_ref_and_aw_for_main_loop_alignment() { } \ // Ensure that the main loop vectors are aligned by adjusting the pre loop limit. We memory-align -// the address of "_mem_ref_for_main_loop_alignment" to "_aw_for_main_loop_alignment", which is a +// the address of "_vpointer_for_main_loop_alignment" to "_aw_for_main_loop_alignment", which is a // sufficiently large alignment width. We adjust the pre-loop iteration count by adjusting the // pre-loop limit. void VTransform::adjust_pre_loop_limit_to_align_main_loop_vectors() { - determine_mem_ref_and_aw_for_main_loop_alignment(); - const MemNode* align_to_ref = _mem_ref_for_main_loop_alignment; - const int aw = _aw_for_main_loop_alignment; + determine_vpointer_and_aw_for_main_loop_alignment(); + + assert(cl()->is_main_loop(), "can only do alignment for main loop"); + assert(_vpointer_for_main_loop_alignment != nullptr && + _vpointer_for_main_loop_alignment->is_valid() && + _aw_for_main_loop_alignment > 0, + "must have alignment reference and aw"); if (!VLoop::vectors_should_be_aligned() && SuperWordAutomaticAlignment == 0) { #ifdef ASSERT @@ -2859,8 +2760,8 @@ void VTransform::adjust_pre_loop_limit_to_align_main_loop_vectors() { return; } - assert(align_to_ref != nullptr && aw > 0, "must have alignment reference and aw"); - assert(cl()->is_main_loop(), "can only do alignment for main loop"); + const VPointer& p = *_vpointer_for_main_loop_alignment; + const int aw = _aw_for_main_loop_alignment; // The opaque node for the limit, where we adjust the input Opaque1Node* pre_opaq = _vloop.pre_loop_end()->limit()->as_Opaque1(); @@ -2875,10 +2776,7 @@ void VTransform::adjust_pre_loop_limit_to_align_main_loop_vectors() { Node* orig_limit = pre_opaq->original_loop_limit(); assert(orig_limit != nullptr && igvn().type(orig_limit) != Type::TOP, ""); - const VPointer& p = vpointer(align_to_ref); - assert(p.is_valid(), "sanity"); - - // For the main-loop, we want the address of align_to_ref to be memory aligned + // For the main-loop, we want the address of vpointer p to be memory aligned // with some alignment width (aw, a power of 2). When we enter the main-loop, // we know that iv is equal to the pre-loop limit. If we adjust the pre-loop // limit by executing adjust_pre_iter many extra iterations, we can change the @@ -3013,9 +2911,7 @@ void VTransform::adjust_pre_loop_limit_to_align_main_loop_vectors() { #ifdef ASSERT if (_trace._align_vector) { tty->print_cr("\nVTransform::adjust_pre_loop_limit_to_align_main_loop_vectors:"); - tty->print(" align_to_ref:"); - align_to_ref->dump(); - tty->print(" "); + tty->print(" vpointer_for_main_loop_alignment"); p.print_on(tty); tty->print_cr(" aw: %d", aw); tty->print_cr(" iv_stride: %d", iv_stride); diff --git a/src/hotspot/share/opto/superword.hpp b/src/hotspot/share/opto/superword.hpp index 0940e752f85..118e0aa042c 100644 --- a/src/hotspot/share/opto/superword.hpp +++ b/src/hotspot/share/opto/superword.hpp @@ -410,9 +410,9 @@ class SuperWord : public ResourceObj { PairSet _pairset; PackSet _packset; - // Memory reference, and the alignment width (aw) for which we align the main-loop, + // VPointer, and the alignment width (aw) for which we align the main-loop, // by adjusting the pre-loop limit. - MemNode const* _mem_ref_for_main_loop_alignment; + VPointer const* _vpointer_for_main_loop_alignment; int _aw_for_main_loop_alignment; public: @@ -657,7 +657,7 @@ private: bool is_velt_basic_type_compatible_use_def(Node* use, Node* def) const; - bool schedule_and_apply() const; + bool do_vtransform() const; }; #endif // SHARE_OPTO_SUPERWORD_HPP diff --git a/src/hotspot/share/opto/superwordVTransformBuilder.cpp b/src/hotspot/share/opto/superwordVTransformBuilder.cpp index dbc96c234a9..45c919ccffa 100644 --- a/src/hotspot/share/opto/superwordVTransformBuilder.cpp +++ b/src/hotspot/share/opto/superwordVTransformBuilder.cpp @@ -37,6 +37,10 @@ void SuperWordVTransformBuilder::build() { VectorSet vtn_memory_dependencies; // Shared, but cleared for every vtnode. build_inputs_for_vector_vtnodes(vtn_memory_dependencies); build_inputs_for_scalar_vtnodes(vtn_memory_dependencies); + + // Build vtnodes for all uses of nodes from the loop, and connect them + // as outputs to the nodes in the loop. + build_uses_after_loop(); } void SuperWordVTransformBuilder::build_vector_vtnodes_for_packed_nodes() { @@ -50,8 +54,8 @@ void SuperWordVTransformBuilder::build_vector_vtnodes_for_packed_nodes() { } void SuperWordVTransformBuilder::build_scalar_vtnodes_for_non_packed_nodes() { - for (int i = 0; i < _vloop_analyzer.body().body().length(); i++) { - Node* n = _vloop_analyzer.body().body().at(i); + for (uint i = 0; i < _vloop.lpt()->_body.size(); i++) { + Node* n = _vloop.lpt()->_body.at(i); if (_packset.get_pack(n) != nullptr) { continue; } VTransformNode* vtn = nullptr; @@ -61,6 +65,8 @@ void SuperWordVTransformBuilder::build_scalar_vtnodes_for_non_packed_nodes() { vtn = new (_vtransform.arena()) VTransformMemopScalarNode(_vtransform, mem, mem_p); } else if (n->is_Phi()) { vtn = new (_vtransform.arena()) VTransformLoopPhiNode(_vtransform, n->as_Phi()); + } else if (n->is_CountedLoop()) { + vtn = new (_vtransform.arena()) VTransformCountedLoopNode(_vtransform, n->as_CountedLoop()); } else if (n->is_CFG()) { vtn = new (_vtransform.arena()) VTransformCFGNode(_vtransform, n); } else { @@ -121,8 +127,8 @@ void SuperWordVTransformBuilder::build_inputs_for_vector_vtnodes(VectorSet& vtn_ } void SuperWordVTransformBuilder::build_inputs_for_scalar_vtnodes(VectorSet& vtn_memory_dependencies) { - for (int i = 0; i < _vloop_analyzer.body().body().length(); i++) { - Node* n = _vloop_analyzer.body().body().at(i); + for (uint i = 0; i < _vloop.lpt()->_body.size(); i++) { + Node* n = _vloop.lpt()->_body.at(i); VTransformNode* vtn = get_vtnode(n); if (vtn->isa_Vector() != nullptr) { continue; } vtn_memory_dependencies.clear(); // Add every dependency only once per vtn. @@ -135,18 +141,41 @@ void SuperWordVTransformBuilder::build_inputs_for_scalar_vtnodes(VectorSet& vtn_ init_req_with_scalar(n, vtn, MemNode::ValueIn); add_memory_dependencies_of_node_to_vtnode(n, vtn, vtn_memory_dependencies); } else if (n->is_CountedLoop()) { - continue; // Is "root", has no dependency. - } else if (n->is_Phi()) { - // CountedLoop Phi's: ignore backedge (and entry value). - assert(n->in(0) == _vloop.cl(), "only Phi's from the CountedLoop allowed"); - init_req_with_scalar(n, vtn, 0); - continue; + // Avoid self-loop, it only creates unnecessary issues in scheduling. + init_req_with_scalar(n, vtn, LoopNode::EntryControl); + init_req_with_scalar(n, vtn, LoopNode::LoopBackControl); } else { init_all_req_with_scalars(n, vtn); } } } +// Build vtnodes for all uses of nodes from the loop, and connect them +// as outputs to the nodes in the loop. +void SuperWordVTransformBuilder::build_uses_after_loop() { + for (uint i = 0; i < _vloop.lpt()->_body.size(); i++) { + Node* n = _vloop.lpt()->_body.at(i); + VTransformNode* vtn = get_vtnode(n); + + for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { + Node* use = n->fast_out(i); + + if (!_vloop.in_bb(use)) { + VTransformNode* vtn_use = get_vtnode_or_wrap_as_outer(use); + + // Set all edges + for (uint j = 0; j < use->req(); j++) { + Node* def = use->in(j); + if (n == def && vtn_use->in_req(j) != vtn) { + assert(vtn_use->in_req(j) == nullptr, "should not yet be set"); + vtn_use->init_req(j, vtn); + } + } + } + } + } +} + // Create a vtnode for each pack. No in/out edges set yet. VTransformVectorNode* SuperWordVTransformBuilder::make_vector_vtnode_for_pack(const Node_List* pack) const { Node* p0 = pack->at(0); @@ -159,7 +188,8 @@ VTransformVectorNode* SuperWordVTransformBuilder::make_vector_vtnode_for_pack(co if (p0->is_Load()) { const VPointer& scalar_p = _vloop_analyzer.vpointers().vpointer(p0->as_Load()); const VPointer vector_p(scalar_p.make_with_size(scalar_p.size() * vlen)); - vtn = new (_vtransform.arena()) VTransformLoadVectorNode(_vtransform, properties, vector_p, p0->adr_type()); + const LoadNode::ControlDependency control_dependency = load_control_dependency(pack); + vtn = new (_vtransform.arena()) VTransformLoadVectorNode(_vtransform, properties, vector_p, p0->adr_type(), control_dependency); } else if (p0->is_Store()) { const VPointer& scalar_p = _vloop_analyzer.vpointers().vpointer(p0->as_Store()); const VPointer vector_p(scalar_p.make_with_size(scalar_p.size() * vlen)); @@ -209,7 +239,6 @@ VTransformVectorNode* SuperWordVTransformBuilder::make_vector_vtnode_for_pack(co int vopc = VectorNode::opcode(sopc, bt); vtn = new (_vtransform.arena()) VTransformElementWiseVectorNode(_vtransform, p0->req(), properties, vopc); } - vtn->set_nodes(pack); return vtn; } @@ -276,15 +305,15 @@ VTransformNode* SuperWordVTransformBuilder::get_or_make_vtnode_vector_input_at_i // case of a ConvL2I, it can be int or some narrower type such // as short etc. But given we replicate the input of the Convert // node, we have to use the input type instead. - BasicType element_type = p0->is_Convert() ? p0->in(1)->bottom_type()->basic_type() : _vloop_analyzer.types().velt_basic_type(p0); - if (index == 2 && VectorNode::is_scalar_rotate(p0) && element_type == T_LONG) { + BasicType element_bt = p0->is_Convert() ? p0->in(1)->bottom_type()->basic_type() : _vloop_analyzer.types().velt_basic_type(p0); + if (index == 2 && VectorNode::is_scalar_rotate(p0) && element_bt == 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); conv->init_req(1, same_input_vtn); same_input_vtn = conv; } - VTransformNode* replicate = new (_vtransform.arena()) VTransformReplicateNode(_vtransform, pack->size(), element_type); + VTransformNode* replicate = new (_vtransform.arena()) VTransformReplicateNode(_vtransform, pack->size(), element_bt); replicate->init_req(1, same_input_vtn); return replicate; } @@ -307,6 +336,7 @@ VTransformNode* SuperWordVTransformBuilder::get_vtnode_or_wrap_as_outer(Node* n) assert(!_vloop.in_bb(n), "only nodes outside the loop can be input nodes to the loop"); vtn = new (_vtransform.arena()) VTransformOuterNode(_vtransform, n); map_node_to_vtnode(n, vtn); + assert(vtn == get_vtnode_or_null(n), "consistency"); return vtn; } diff --git a/src/hotspot/share/opto/superwordVTransformBuilder.hpp b/src/hotspot/share/opto/superwordVTransformBuilder.hpp index 6ed8480209a..cc9dd225f01 100644 --- a/src/hotspot/share/opto/superwordVTransformBuilder.hpp +++ b/src/hotspot/share/opto/superwordVTransformBuilder.hpp @@ -56,6 +56,7 @@ private: void build_scalar_vtnodes_for_non_packed_nodes(); void build_inputs_for_vector_vtnodes(VectorSet& vtn_memory_dependencies); void build_inputs_for_scalar_vtnodes(VectorSet& vtn_memory_dependencies); + void build_uses_after_loop(); // Helper methods for building VTransform. VTransformNode* get_vtnode_or_null(Node* n) const { @@ -82,6 +83,7 @@ private: void init_all_req_with_scalars(Node* n, VTransformNode* vtn); void init_all_req_with_vectors(const Node_List* pack, VTransformNode* vtn); void add_memory_dependencies_of_node_to_vtnode(Node* n, VTransformNode* vtn, VectorSet& vtn_memory_dependencies); + LoadNode::ControlDependency load_control_dependency(const Node_List* pack) const; }; #endif // SHARE_OPTO_SUPERWORD_VTRANSFORM_BUILDER_HPP diff --git a/src/hotspot/share/opto/vectorization.cpp b/src/hotspot/share/opto/vectorization.cpp index 8e0f0980ff7..5c4e15fdbb9 100644 --- a/src/hotspot/share/opto/vectorization.cpp +++ b/src/hotspot/share/opto/vectorization.cpp @@ -182,6 +182,11 @@ VStatus VLoopAnalyzer::setup_submodules_helper() { _reductions.mark_reductions(); } + VStatus body_status = _body.construct(); + if (!body_status.is_success()) { + return body_status; + } + _memory_slices.find_memory_slices(); // If there is no memory slice detected, it means there is no store. @@ -192,11 +197,6 @@ VStatus VLoopAnalyzer::setup_submodules_helper() { return VStatus::make_failure(VLoopAnalyzer::FAILURE_NO_REDUCTION_OR_STORE); } - VStatus body_status = _body.construct(); - if (!body_status.is_success()) { - return body_status; - } - _types.compute_vector_element_type(); _vpointers.compute_vpointers(); @@ -206,6 +206,64 @@ VStatus VLoopAnalyzer::setup_submodules_helper() { return VStatus::make_success(); } +// There are 2 kinds of slices: +// - No memory phi: only loads. All have the same input memory state from before the loop. +// - With memory phi. Chain of memory operations inside the loop. +void VLoopMemorySlices::find_memory_slices() { + Compile* C = _vloop.phase()->C; + // We iterate over the body, which is topologically sorted. Hence, if there is a phi + // in a slice, we will find it first, and the loads and stores afterwards. + for (int i = 0; i < _body.body().length(); i++) { + Node* n = _body.body().at(i); + if (n->is_memory_phi()) { + // Memory slice with stores (and maybe loads) + PhiNode* phi = n->as_Phi(); + int alias_idx = C->get_alias_index(phi->adr_type()); + assert(_inputs.at(alias_idx) == nullptr, "did not yet touch this slice"); + _inputs.at_put(alias_idx, phi->in(1)); + _heads.at_put(alias_idx, phi); + } else if (n->is_Load()) { + LoadNode* load = n->as_Load(); + int alias_idx = C->get_alias_index(load->adr_type()); + PhiNode* head = _heads.at(alias_idx); + if (head == nullptr) { + // We did not find a phi on this slice yet -> must be a slice with only loads. + assert(_inputs.at(alias_idx) == nullptr || _inputs.at(alias_idx) == load->in(1), + "not yet touched or the same input"); + _inputs.at_put(alias_idx, load->in(1)); + } // else: the load belongs to a slice with a phi that already set heads and inputs. +#ifdef ASSERT + } else if (n->is_Store()) { + // Found a store. Make sure it is in a slice with a Phi. + StoreNode* store = n->as_Store(); + int alias_idx = C->get_alias_index(store->adr_type()); + PhiNode* head = _heads.at(alias_idx); + assert(head != nullptr, "should have found a mem phi for this slice"); +#endif + } + } + NOT_PRODUCT( if (_vloop.is_trace_memory_slices()) { print(); } ) +} + +#ifndef PRODUCT +void VLoopMemorySlices::print() const { + tty->print_cr("\nVLoopMemorySlices::print: %s", + heads().length() > 0 ? "" : "NONE"); + for (int i = 0; i < _inputs.length(); i++) { + Node* input = _inputs.at(i); + PhiNode* head = _heads.at(i); + if (input != nullptr) { + tty->print("%3d input", i); input->dump(); + if (head == nullptr) { + tty->print_cr(" load only"); + } else { + tty->print(" head "); head->dump(); + } + } + } +} +#endif + void VLoopVPointers::compute_vpointers() { count_vpointers(); allocate_vpointers_array(); @@ -267,7 +325,6 @@ void VLoopVPointers::print() const { // the edge, i.e. spaw the order. void VLoopDependencyGraph::construct() { const GrowableArray& mem_slice_heads = _memory_slices.heads(); - const GrowableArray& mem_slice_tails = _memory_slices.tails(); ResourceMark rm; GrowableArray slice_nodes; @@ -277,7 +334,10 @@ void VLoopDependencyGraph::construct() { // For each memory slice, create the memory subgraph for (int i = 0; i < mem_slice_heads.length(); i++) { PhiNode* head = mem_slice_heads.at(i); - MemNode* tail = mem_slice_tails.at(i); + // If there is no head (memory-phi) for this slice, then we have either no memops + // in the loop, or only loads. We do not need to add any memory edges in that case. + if (head == nullptr) { continue; } + MemNode* tail = head->in(2)->as_Mem(); _memory_slices.get_slice_in_reverse_order(head, tail, slice_nodes); diff --git a/src/hotspot/share/opto/vectorization.hpp b/src/hotspot/share/opto/vectorization.hpp index b39e46cbf35..e006589cce9 100644 --- a/src/hotspot/share/opto/vectorization.hpp +++ b/src/hotspot/share/opto/vectorization.hpp @@ -379,37 +379,6 @@ private: static Node* original_input(const Node* n, uint i); }; -// Submodule of VLoopAnalyzer. -// Find the memory slices in the loop. -class VLoopMemorySlices : public StackObj { -private: - const VLoop& _vloop; - - GrowableArray _heads; - GrowableArray _tails; - -public: - VLoopMemorySlices(Arena* arena, const VLoop& vloop) : - _vloop(vloop), - _heads(arena, 8, 0, nullptr), - _tails(arena, 8, 0, nullptr) {}; - NONCOPYABLE(VLoopMemorySlices); - - void find_memory_slices(); - - const GrowableArray& heads() const { return _heads; } - const GrowableArray& tails() const { return _tails; } - - // Get all memory nodes of a slice, in reverse order - void get_slice_in_reverse_order(PhiNode* head, MemNode* tail, GrowableArray& slice) const; - - bool same_memory_slice(MemNode* m1, MemNode* m2) const; - -#ifndef PRODUCT - void print() const; -#endif -}; - // Submodule of VLoopAnalyzer. // Finds all nodes in the body, and creates a mapping node->_idx to a body_idx. // This mapping is used so that subsequent datastructures sizes only grow with @@ -461,6 +430,73 @@ private: } }; +// Submodule of VLoopAnalyzer. +// Find the memory slices in the loop. There are 3 kinds of slices: +// 1. no use in loop: inputs(i) = nullptr, heads(i) = nullptr +// 2. stores in loop: inputs(i) = entry_mem, heads(i) = phi_mem +// +// = entry_mem +// | +// CountedLoop | +-----------------------+ +// | v v | +// phi_mem | +// | | +// | +// | | +// +---------------------------+ +// | +// +// +// Note: the mem uses after the loop are dependent on the last store in the loop. +// Once we vectorize, we may reorder the loads and stores, and replace +// scalar mem ops with vector mem ops. We will have to make sure that all +// uses after the loop use the new last store. +// See: VTransformApplyState::fix_memory_state_uses_after_loop +// +// 3. only loads but no stores in loop: inputs(i) = entry_mem, heads(i) = nullptr +// +// = entry_mem +// | | +// | CountedLoop | +// | | | +// | +// | +// +// +// Note: the mem uses after the loop are NOT dependent any mem ops in the loop, +// since there are no stores. +// +class VLoopMemorySlices : public StackObj { +private: + const VLoop& _vloop; + const VLoopBody& _body; + + GrowableArray _inputs; + GrowableArray _heads; + +public: + VLoopMemorySlices(Arena* arena, const VLoop& vloop, const VLoopBody& body) : + _vloop(vloop), + _body(body), + _inputs(arena, num_slices(), num_slices(), nullptr), + _heads(arena, num_slices(), num_slices(), nullptr) {}; + NONCOPYABLE(VLoopMemorySlices); + + const GrowableArray& inputs() const { return _inputs; } + const GrowableArray& heads() const { return _heads; } + + void find_memory_slices(); + void get_slice_in_reverse_order(PhiNode* head, MemNode* tail, GrowableArray& slice) const; + bool same_memory_slice(MemNode* m1, MemNode* m2) const; + +private: +#ifndef PRODUCT + void print() const; +#endif + + int num_slices() const { return _vloop.phase()->C->num_alias_types(); } +}; + // Submodule of VLoopAnalyzer. // Compute the vector element type for every node in the loop body. // We need to do this to be able to vectorize the narrower integer @@ -737,8 +773,8 @@ private: // Submodules VLoopReductions _reductions; - VLoopMemorySlices _memory_slices; VLoopBody _body; + VLoopMemorySlices _memory_slices; VLoopTypes _types; VLoopVPointers _vpointers; VLoopDependencyGraph _dependency_graph; @@ -749,8 +785,8 @@ public: _arena(mtCompiler, Arena::Tag::tag_superword), _success(false), _reductions (&_arena, vloop), - _memory_slices (&_arena, vloop), _body (&_arena, vloop, vshared), + _memory_slices (&_arena, vloop, _body), _types (&_arena, vloop, _body), _vpointers (&_arena, vloop, _body), _dependency_graph(&_arena, vloop, _body, _memory_slices, _vpointers) diff --git a/src/hotspot/share/opto/vtransform.cpp b/src/hotspot/share/opto/vtransform.cpp index 8c1210a5a09..27c541c2732 100644 --- a/src/hotspot/share/opto/vtransform.cpp +++ b/src/hotspot/share/opto/vtransform.cpp @@ -78,6 +78,10 @@ bool VTransformGraph::schedule() { // runtime check, see VTransform::apply_speculative_aliasing_runtime_checks. for (uint i = 0; i < vtn->out_strong_edges(); i++) { VTransformNode* use = vtn->out_strong_edge(i); + + // Skip LoopPhi backedge. + if ((use->isa_LoopPhi() != nullptr || use->isa_CountedLoop() != nullptr) && use->in_req(2) == vtn) { continue; } + if (post_visited.test(use->_idx)) { continue; } if (pre_visited.test(use->_idx)) { // Cycle detected! @@ -120,6 +124,11 @@ void VTransformGraph::collect_nodes_without_strong_in_edges(GrowableArrayhas_strong_in_edge()) { stack.push(vtn); } + // If an Outer node has both inputs and outputs, we will most likely have cycles in the final graph. + // This is not a correctness problem, but it just will prevent vectorization. If this ever happens + // try to find a way to avoid the cycle somehow. + assert(vtn->isa_Outer() == nullptr || (vtn->has_strong_in_edge() != (vtn->out_strong_edges() > 0)), + "Outer nodes should either be inputs or outputs, but not both, otherwise we may get cycles"); } } @@ -717,28 +726,111 @@ Node* VTransformApplyState::transformed_node(const VTransformNode* vtn) const { return n; } +void VTransformApplyState::init_memory_states_and_uses_after_loop() { + const GrowableArray& inputs = _vloop_analyzer.memory_slices().inputs(); + const GrowableArray& heads = _vloop_analyzer.memory_slices().heads(); + for (int i = 0; i < inputs.length(); i++) { + PhiNode* head = heads.at(i); + if (head != nullptr) { + // Slice with Phi (i.e. with stores) -> start with the phi (phi_mem) + _memory_states.at_put(i, head); + + // Remember uses outside the loop of the last memory state (store). + StoreNode* last_store = head->in(2)->as_Store(); + assert(vloop().in_bb(last_store), "backedge store should be in the loop"); + for (DUIterator_Fast jmax, j = last_store->fast_outs(jmax); j < jmax; j++) { + Node* use = last_store->fast_out(j); + if (!vloop().in_bb(use)) { + for (uint k = 0; k < use->req(); k++) { + if (use->in(k) == last_store) { + _memory_state_uses_after_loop.push(MemoryStateUseAfterLoop(use, k, i)); + } + } + } + } + } else { + // Slice without Phi (i.e. only loads) -> use the input state (entry_mem) + _memory_states.at_put(i, inputs.at(i)); + } + } +} + +// We may have reordered the scalar stores, or replaced them with vectors. Now +// the last memory state in the loop may have changed. Thus, we need to change +// the uses of the old last memory state the new last memory state. +void VTransformApplyState::fix_memory_state_uses_after_loop() { + for (int i = 0; i < _memory_state_uses_after_loop.length(); i++) { + MemoryStateUseAfterLoop& use = _memory_state_uses_after_loop.at(i); + Node* last_state = memory_state(use._alias_idx); + phase()->igvn().replace_input_of(use._use, use._in_idx, last_state); + } +} + +void VTransformNode::apply_vtn_inputs_to_node(Node* n, VTransformApplyState& apply_state) const { + PhaseIdealLoop* phase = apply_state.phase(); + for (uint i = 0; i < req(); i++) { + VTransformNode* vtn_def = in_req(i); + if (vtn_def != nullptr) { + Node* def = apply_state.transformed_node(vtn_def); + phase->igvn().replace_input_of(n, i, def); + } + } +} + VTransformApplyResult VTransformMemopScalarNode::apply(VTransformApplyState& apply_state) const { - // This was just wrapped. Now we simply unwrap without touching the inputs. + apply_vtn_inputs_to_node(_node, apply_state); + // The memory state has to be applied separately: the vtn does not hold it. This allows reordering. + Node* mem = apply_state.memory_state(_node->adr_type()); + apply_state.phase()->igvn().replace_input_of(_node, 1, mem); + if (_node->is_Store()) { + apply_state.set_memory_state(_node->adr_type(), _node); + } + return VTransformApplyResult::make_scalar(_node); } VTransformApplyResult VTransformDataScalarNode::apply(VTransformApplyState& apply_state) const { - // This was just wrapped. Now we simply unwrap without touching the inputs. + apply_vtn_inputs_to_node(_node, apply_state); return VTransformApplyResult::make_scalar(_node); } VTransformApplyResult VTransformLoopPhiNode::apply(VTransformApplyState& apply_state) const { - // This was just wrapped. Now we simply unwrap without touching the inputs. + PhaseIdealLoop* phase = apply_state.phase(); + Node* in0 = apply_state.transformed_node(in_req(0)); + Node* in1 = apply_state.transformed_node(in_req(1)); + phase->igvn().replace_input_of(_node, 0, in0); + phase->igvn().replace_input_of(_node, 1, in1); + // Note: the backedge is hooked up later. return VTransformApplyResult::make_scalar(_node); } +// Cleanup backedges. In the schedule, the backedges come after their phis. Hence, +// we only have the transformed backedges after the phis are already transformed. +// We hook the backedges into the phis now, during cleanup. +void VTransformLoopPhiNode::apply_backedge(VTransformApplyState& apply_state) const { + PhaseIdealLoop* phase = apply_state.phase(); + if (_node->is_memory_phi()) { + // Memory phi/backedge + // The last memory state of that slice is the backedge. + Node* last_state = apply_state.memory_state(_node->adr_type()); + phase->igvn().replace_input_of(_node, 2, last_state); + } else { + // Data phi/backedge + Node* in2 = apply_state.transformed_node(in_req(2)); + phase->igvn().replace_input_of(_node, 2, in2); + } +} + VTransformApplyResult VTransformCFGNode::apply(VTransformApplyState& apply_state) const { - // This was just wrapped. Now we simply unwrap without touching the inputs. + // We do not modify the inputs of the CountedLoop (and certainly not its backedge) + if (!_node->is_CountedLoop()) { + apply_vtn_inputs_to_node(_node, apply_state); + } return VTransformApplyResult::make_scalar(_node); } VTransformApplyResult VTransformOuterNode::apply(VTransformApplyState& apply_state) const { - // This was just wrapped. Now we simply unwrap without touching the inputs. + apply_vtn_inputs_to_node(_node, apply_state); return VTransformApplyResult::make_scalar(_node); } @@ -797,7 +889,7 @@ VTransformApplyResult VTransformElementWiseVectorNode::apply(VTransformApplyStat vn = VectorNode::make(_vector_opcode, in1, in2, in3, vt); // ternary } - register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); + register_new_node_from_vectorization(apply_state, vn); return VTransformApplyResult::make_vector(vn); } @@ -812,7 +904,7 @@ VTransformApplyResult VTransformElementWiseLongOpWithCastToIntVectorNode::apply( register_new_node_from_vectorization(apply_state, long_vn); // Cast long -> int, to mimic the scalar long -> int operation. VectorNode* vn = VectorCastNode::make(Op_VectorCastL2X, long_vn, T_INT, vlen); - register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); + register_new_node_from_vectorization(apply_state, vn); return VTransformApplyResult::make_vector(vn); } @@ -824,7 +916,7 @@ VTransformApplyResult VTransformReinterpretVectorNode::apply(VTransformApplyStat Node* in1 = apply_state.transformed_node(in_req(1)); VectorNode* vn = new VectorReinterpretNode(in1, src_vt, dst_vt); - register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); + register_new_node_from_vectorization(apply_state, vn); return VTransformApplyResult::make_vector(vn); } @@ -843,7 +935,7 @@ VTransformApplyResult VTransformBoolVectorNode::apply(VTransformApplyState& appl PhaseIdealLoop* phase = apply_state.phase(); ConINode* mask_node = phase->intcon((int)mask); VectorNode* vn = new VectorMaskCmpNode(mask, cmp_in1, cmp_in2, mask_node, vt); - register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); + register_new_node_from_vectorization(apply_state, vn); return VTransformApplyResult::make_vector(vn); } @@ -852,7 +944,7 @@ VTransformApplyResult VTransformReductionVectorNode::apply(VTransformApplyState& Node* vec = apply_state.transformed_node(in_req(2)); ReductionNode* vn = ReductionNode::make(scalar_opcode(), nullptr, init, vec, element_basic_type()); - register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); + register_new_node_from_vectorization(apply_state, vn); return VTransformApplyResult::make_vector(vn, vn->vect_type()); } @@ -861,10 +953,9 @@ VTransformApplyResult VTransformLoadVectorNode::apply(VTransformApplyState& appl uint vlen = vector_length(); BasicType bt = element_basic_type(); - LoadNode* first = nodes().at(0)->as_Load(); + // The memory state has to be applied separately: the vtn does not hold it. This allows reordering. Node* ctrl = apply_state.transformed_node(in_req(MemNode::Control)); - // first has the correct memory state, determined by VTransformGraph::apply_memops_reordering_with_schedule - Node* mem = first->in(MemNode::Memory); + Node* mem = apply_state.memory_state(_adr_type); Node* adr = apply_state.transformed_node(in_req(MemNode::Address)); // Set the memory dependency of the LoadVector as early as possible. @@ -880,10 +971,9 @@ VTransformApplyResult VTransformLoadVectorNode::apply(VTransformApplyState& appl } } - LoadVectorNode* vn = LoadVectorNode::make(sopc, ctrl, mem, adr, _adr_type, vlen, bt, - control_dependency()); + LoadVectorNode* vn = LoadVectorNode::make(sopc, ctrl, mem, adr, _adr_type, vlen, bt, _control_dependency); DEBUG_ONLY( if (VerifyAlignVector) { vn->set_must_verify_alignment(); } ) - register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); + register_new_node_from_vectorization(apply_state, vn); return VTransformApplyResult::make_vector(vn, vn->vect_type()); } @@ -891,27 +981,17 @@ VTransformApplyResult VTransformStoreVectorNode::apply(VTransformApplyState& app int sopc = scalar_opcode(); uint vlen = vector_length(); - StoreNode* first = nodes().at(0)->as_Store(); + // The memory state has to be applied separately: the vtn does not hold it. This allows reordering. Node* ctrl = apply_state.transformed_node(in_req(MemNode::Control)); - // first has the correct memory state, determined by VTransformGraph::apply_memops_reordering_with_schedule - Node* mem = first->in(MemNode::Memory); + Node* mem = apply_state.memory_state(_adr_type); Node* adr = apply_state.transformed_node(in_req(MemNode::Address)); Node* value = apply_state.transformed_node(in_req(MemNode::ValueIn)); StoreVectorNode* vn = StoreVectorNode::make(sopc, ctrl, mem, adr, _adr_type, value, vlen); DEBUG_ONLY( if (VerifyAlignVector) { vn->set_must_verify_alignment(); } ) - register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); - return VTransformApplyResult::make_vector(vn, vn->vect_type()); -} - -void VTransformVectorNode::register_new_node_from_vectorization_and_replace_scalar_nodes(VTransformApplyState& apply_state, Node* vn) const { - PhaseIdealLoop* phase = apply_state.phase(); register_new_node_from_vectorization(apply_state, vn); - - for (int i = 0; i < _nodes.length(); i++) { - Node* n = _nodes.at(i); - phase->igvn().replace_node(n, vn); - } + apply_state.set_memory_state(_adr_type, vn); + return VTransformApplyResult::make_vector(vn, vn->vect_type()); } void VTransformNode::register_new_node_from_vectorization(VTransformApplyState& apply_state, Node* vn) const { @@ -944,15 +1024,6 @@ void VTransformGraph::print_schedule() const { } } -void VTransformGraph::print_memops_schedule() const { - tty->print_cr("\nVTransformGraph::print_memops_schedule:"); - int i = 0; - for_each_memop_in_schedule([&] (MemNode* mem) { - tty->print(" %3d: ", i++); - mem->dump(); - }); -} - void VTransformNode::print() const { tty->print("%3d %s (", _idx, name()); for (uint i = 0; i < _req; i++) { diff --git a/src/hotspot/share/opto/vtransform.hpp b/src/hotspot/share/opto/vtransform.hpp index 9a4e4de01a2..a004962eea7 100644 --- a/src/hotspot/share/opto/vtransform.hpp +++ b/src/hotspot/share/opto/vtransform.hpp @@ -39,7 +39,7 @@ // // This is the life-cycle of a VTransform: // - Construction: -// - From SuperWord, with the SuperWordVTransformBuilder. +// - From SuperWord PackSet, with the SuperWordVTransformBuilder. // // - Future Plans: optimize, if-conversion, etc. // @@ -49,8 +49,16 @@ // // - Apply: // - Changes to the C2 IR are only made once the "apply" method is called. +// - Align the main loop, by adjusting pre loop limit. +// - Add speculative runtime checks (alignment and aliasing). // - Each vtnode generates its corresponding scalar and vector C2 nodes, -// possibly replacing old scalar C2 nodes. +// possibly replacing old scalar C2 nodes. We apply each vtnode in order +// of the schedule, so that all input vtnodes are already applied, i.e. +// all input vtnodes have already generated the transformed C2 nodes. +// - We also build the new memory graph on the fly. The schedule may have +// reordered the memory operations, and so we cannot use the old memory +// graph, but must build it from the scheduled order. We keep track of +// the current memory state in VTransformApplyState. // // Future Plans with VTransform: // - Cost model: estimate if vectorization is profitable. @@ -65,6 +73,7 @@ class VTransformMemopScalarNode; class VTransformDataScalarNode; class VTransformLoopPhiNode; class VTransformCFGNode; +class VTransformCountedLoopNode; class VTransformOuterNode; class VTransformVectorNode; class VTransformElementWiseVectorNode; @@ -176,7 +185,6 @@ public: bool schedule(); bool has_store_to_load_forwarding_failure(const VLoopAnalyzer& vloop_analyzer) const; - void apply_memops_reordering_with_schedule() const; void apply_vectorization_for_each_vtnode(uint& max_vector_length, uint& max_vector_width) const; private: @@ -187,13 +195,9 @@ private: void collect_nodes_without_strong_in_edges(GrowableArray& stack) const; - template - void for_each_memop_in_schedule(Callback callback) const; - #ifndef PRODUCT void print_vtnodes() const; void print_schedule() const; - void print_memops_schedule() const; void trace_schedule_cycle(const GrowableArray& stack, const VectorSet& pre_visited, const VectorSet& post_visited) const; @@ -215,14 +219,14 @@ private: VTransformGraph _graph; - // Memory reference, and the alignment width (aw) for which we align the main-loop, + // VPointer, and the alignment width (aw) for which we align the main-loop, // by adjusting the pre-loop limit. - MemNode const* _mem_ref_for_main_loop_alignment; + VPointer const* _vpointer_for_main_loop_alignment; int _aw_for_main_loop_alignment; public: VTransform(const VLoopAnalyzer& vloop_analyzer, - MemNode const* mem_ref_for_main_loop_alignment, + VPointer const* vpointer_for_main_loop_alignment, int aw_for_main_loop_alignment NOT_PRODUCT( COMMA const VTransformTrace trace) ) : @@ -231,7 +235,7 @@ public: NOT_PRODUCT(_trace(trace) COMMA) _arena(mtCompiler, Arena::Tag::tag_superword), _graph(_vloop_analyzer, _arena NOT_PRODUCT(COMMA _trace)), - _mem_ref_for_main_loop_alignment(mem_ref_for_main_loop_alignment), + _vpointer_for_main_loop_alignment(vpointer_for_main_loop_alignment), _aw_for_main_loop_alignment(aw_for_main_loop_alignment) {} const VLoopAnalyzer& vloop_analyzer() const { return _vloop_analyzer; } @@ -257,7 +261,7 @@ private: } // Ensure that the main loop vectors are aligned by adjusting the pre loop limit. - void determine_mem_ref_and_aw_for_main_loop_alignment(); + void determine_vpointer_and_aw_for_main_loop_alignment(); void adjust_pre_loop_limit_to_align_main_loop_vectors(); void apply_speculative_alignment_runtime_checks(); @@ -271,7 +275,7 @@ private: }; // Keeps track of the state during "VTransform::apply" -// -> keep track of the already transformed nodes +// -> keep track of the already transformed nodes and the memory state. class VTransformApplyState : public StackObj { private: const VLoopAnalyzer& _vloop_analyzer; @@ -281,11 +285,35 @@ private: // generated def (input) nodes when we are generating the use nodes in "apply". GrowableArray _vtnode_idx_to_transformed_node; + // We keep track of the current memory state in each slice. If the slice has only + // loads (and no phi), then this is always the input memory state from before the + // loop. If there is a memory phi, this is initially the memory phi, and each time + // a store is processed, it is updated to that store. + GrowableArray _memory_states; + + // We need to keep track of the memory uses after the loop, for the slices that + // have a memory phi. + // use->in(in_idx) = + class MemoryStateUseAfterLoop : public StackObj { + public: + Node* _use; + int _in_idx; + int _alias_idx; + + MemoryStateUseAfterLoop(Node* use, int in_idx, int alias_idx) : + _use(use), _in_idx(in_idx), _alias_idx(alias_idx) {} + MemoryStateUseAfterLoop() : MemoryStateUseAfterLoop(nullptr, 0, 0) {} + }; + + GrowableArray _memory_state_uses_after_loop; + public: VTransformApplyState(const VLoopAnalyzer& vloop_analyzer, int num_vtnodes) : _vloop_analyzer(vloop_analyzer), - _vtnode_idx_to_transformed_node(num_vtnodes, num_vtnodes, nullptr) + _vtnode_idx_to_transformed_node(num_vtnodes, num_vtnodes, nullptr), + _memory_states(num_slices(), num_slices(), nullptr) { + init_memory_states_and_uses_after_loop(); } const VLoop& vloop() const { return _vloop_analyzer.vloop(); } @@ -294,6 +322,25 @@ public: void set_transformed_node(VTransformNode* vtn, Node* n); Node* transformed_node(const VTransformNode* vtn) const; + + Node* memory_state(int alias_idx) const { return _memory_states.at(alias_idx); } + void set_memory_state(int alias_idx, Node* n) { _memory_states.at_put(alias_idx, n); } + + Node* memory_state(const TypePtr* adr_type) const { + int alias_idx = phase()->C->get_alias_index(adr_type); + return memory_state(alias_idx); + } + + void set_memory_state(const TypePtr* adr_type, Node* n) { + int alias_idx = phase()->C->get_alias_index(adr_type); + return set_memory_state(alias_idx, n); + } + + void fix_memory_state_uses_after_loop(); + +private: + int num_slices() const { return _vloop_analyzer.memory_slices().heads().length(); } + void init_memory_states_and_uses_after_loop(); }; // The vtnodes (VTransformNode) resemble the C2 IR Nodes, and model a part of the @@ -433,6 +480,8 @@ public: } virtual VTransformMemopScalarNode* isa_MemopScalar() { return nullptr; } + virtual VTransformLoopPhiNode* isa_LoopPhi() { return nullptr; } + virtual VTransformCountedLoopNode* isa_CountedLoop() { return nullptr; } virtual VTransformOuterNode* isa_Outer() { return nullptr; } virtual VTransformVectorNode* isa_Vector() { return nullptr; } virtual VTransformElementWiseVectorNode* isa_ElementWiseVector() { return nullptr; } @@ -448,9 +497,8 @@ public: virtual const VPointer& vpointer() const { ShouldNotReachHere(); } virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const = 0; - - Node* find_transformed_input(int i, const GrowableArray& vnode_idx_to_transformed_node) const; - + virtual void apply_backedge(VTransformApplyState& apply_state) const {}; + void apply_vtn_inputs_to_node(Node* n, VTransformApplyState& apply_state) const; void register_new_node_from_vectorization(VTransformApplyState& apply_state, Node* vn) const; NOT_PRODUCT(virtual const char* name() const = 0;) @@ -510,7 +558,9 @@ public: assert(_node->in(0)->is_Loop(), "phi ctrl must be Loop: %s", _node->in(0)->Name()); } + virtual VTransformLoopPhiNode* isa_LoopPhi() override { return this; } virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; + virtual void apply_backedge(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "LoopPhi"; };) NOT_PRODUCT(virtual void print_spec() const override;) }; @@ -531,6 +581,16 @@ public: NOT_PRODUCT(virtual void print_spec() const override;) }; +// Identity transform for CountedLoop, the only CFG node with a backedge. +class VTransformCountedLoopNode : public VTransformCFGNode { +public: + VTransformCountedLoopNode(VTransform& vtransform, CountedLoopNode* n) : + VTransformCFGNode(vtransform, n) {} + + virtual VTransformCountedLoopNode* isa_CountedLoop() override { return this; } + NOT_PRODUCT(virtual const char* name() const override { return "CountedLoop"; };) +}; + // Wrapper node for nodes outside the loop that are inputs to nodes in the loop. // Since we want the loop-internal nodes to be able to reference all inputs as vtnodes, // we must wrap the inputs that are outside the loop into special vtnodes, too. @@ -632,22 +692,9 @@ public: class VTransformVectorNode : public VTransformNode { private: const VTransformVectorNodeProperties _properties; -protected: - GrowableArray _nodes; public: VTransformVectorNode(VTransform& vtransform, const uint req, const VTransformVectorNodeProperties properties) : - VTransformNode(vtransform, req), - _properties(properties), - _nodes(vtransform.arena(), - properties.vector_length(), - properties.vector_length(), - nullptr) {} - - void set_nodes(const Node_List* pack) { - for (uint k = 0; k < pack->size(); k++) { - _nodes.at_put(k, pack->at(k)); - } - } + VTransformNode(vtransform, req), _properties(properties) {} virtual VTransformVectorNode* isa_Vector() override { return this; } void register_new_node_from_vectorization_and_replace_scalar_nodes(VTransformApplyState& apply_state, Node* vn) const; @@ -749,17 +796,23 @@ public: _vpointer(vpointer), _adr_type(adr_type) {} - const GrowableArray& nodes() const { return _nodes; } virtual VTransformMemVectorNode* isa_MemVector() override { return this; } virtual bool is_load_or_store_in_loop() const override { return true; } virtual const VPointer& vpointer() const override { return _vpointer; } }; class VTransformLoadVectorNode : public VTransformMemVectorNode { +private: + const LoadNode::ControlDependency _control_dependency; + public: // req = 3 -> [ctrl, mem, adr] - VTransformLoadVectorNode(VTransform& vtransform, const VTransformVectorNodeProperties properties, const VPointer& vpointer, const TypePtr* adr_type) : - VTransformMemVectorNode(vtransform, 3, properties, vpointer, adr_type) {} + VTransformLoadVectorNode(VTransform& vtransform, + const VTransformVectorNodeProperties properties, + const VPointer& vpointer, + const TypePtr* adr_type, + const LoadNode::ControlDependency control_dependency) : + VTransformMemVectorNode(vtransform, 3, properties, vpointer, adr_type), _control_dependency(control_dependency) {} LoadNode::ControlDependency control_dependency() const; virtual VTransformLoadVectorNode* isa_LoadVector() override { return this; } virtual bool is_load_in_loop() const override { return true; } @@ -777,30 +830,4 @@ public: virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "StoreVector"; };) }; - -// Invoke callback on all memops, in the order of the schedule. -template -void VTransformGraph::for_each_memop_in_schedule(Callback callback) const { - assert(_schedule.length() == _vtnodes.length(), "schedule was computed"); - - for (int i = 0; i < _schedule.length(); i++) { - VTransformNode* vtn = _schedule.at(i); - - // We must ignore nodes outside the loop. - if (vtn->isa_Outer() != nullptr) { continue; } - - VTransformMemopScalarNode* scalar = vtn->isa_MemopScalar(); - if (scalar != nullptr) { - callback(scalar->node()); - } - - VTransformMemVectorNode* vector = vtn->isa_MemVector(); - if (vector != nullptr) { - for (int j = 0; j < vector->nodes().length(); j++) { - callback(vector->nodes().at(j)->as_Mem()); - } - } - } -} - #endif // SHARE_OPTO_VTRANSFORM_HPP diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/CompilePhase.java b/test/hotspot/jtreg/compiler/lib/ir_framework/CompilePhase.java index 8b794e13e3f..06b2afa8a67 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/CompilePhase.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/CompilePhase.java @@ -98,9 +98,9 @@ public enum CompilePhase { PHASEIDEALLOOP2( "PhaseIdealLoop 2"), PHASEIDEALLOOP3( "PhaseIdealLoop 3"), AUTO_VECTORIZATION1_BEFORE_APPLY( "AutoVectorization 1, before Apply"), - AUTO_VECTORIZATION2_AFTER_REORDER( "AutoVectorization 2, after Apply Memop Reordering"), - AUTO_VECTORIZATION3_AFTER_ADJUST_LIMIT( "AutoVectorization 3, after Adjusting Pre-loop Limit"), - AUTO_VECTORIZATION4_AFTER_SPECULATIVE_RUNTIME_CHECKS("AutoVectorization 4, after Adding Speculative Runtime Checks"), + AUTO_VECTORIZATION3_AFTER_ADJUST_LIMIT( "AutoVectorization 2, after Adjusting Pre-loop Limit"), + AUTO_VECTORIZATION4_AFTER_SPECULATIVE_RUNTIME_CHECKS("AutoVectorization 3, after Adding Speculative Runtime Checks"), + AUTO_VECTORIZATION5_AFTER_APPLY( "AutoVectorization 4, after Apply"), BEFORE_CCP1( "Before PhaseCCP 1"), CCP1( "PhaseCCP 1"), ITER_GVN2( "Iter GVN 2"), From 862119565db311fe0e02e383fd3493601ed23ea8 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Wed, 8 Oct 2025 05:32:51 +0000 Subject: [PATCH 060/160] 8363917: SwitchBootstraps.enumSwitch() args not checked as documented Reviewed-by: liach --- .../java/lang/runtime/SwitchBootstraps.java | 37 ++++++++------ .../lang/runtime/SwitchBootstrapsTest.java | 49 +++++++++++++++++-- 2 files changed, 68 insertions(+), 18 deletions(-) diff --git a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java index f4d82595842..99716baf439 100644 --- a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java +++ b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java @@ -165,22 +165,22 @@ public final class SwitchBootstraps { * @param lookup Represents a lookup context with the accessibility * privileges of the caller. When used with {@code invokedynamic}, * this is stacked automatically by the VM. - * @param invocationName unused + * @param invocationName unused, {@code null} is permitted * @param invocationType The invocation type of the {@code CallSite} with two parameters, * a reference type, an {@code int}, and {@code int} as a return type. * @param labels case labels - {@code String} and {@code Integer} constants * and {@code Class} and {@code EnumDesc} instances, in any combination * @return a {@code CallSite} returning the first matching element as described above * - * @throws NullPointerException if any argument is {@code null} + * @throws NullPointerException if any argument is {@code null}, unless noted otherwise * @throws IllegalArgumentException if any element in the labels array is null * @throws IllegalArgumentException if the invocation type is not a method type of first parameter of a reference type, - * second parameter of type {@code int} and with {@code int} as its return type, + * second parameter of type {@code int} and with {@code int} as its return type * @throws IllegalArgumentException if {@code labels} contains an element that is not of type {@code String}, * {@code Integer}, {@code Long}, {@code Float}, {@code Double}, {@code Boolean}, - * {@code Class} or {@code EnumDesc}. + * {@code Class} or {@code EnumDesc} * @throws IllegalArgumentException if {@code labels} contains an element that is not of type {@code Boolean} - * when {@code target} is a {@code Boolean.class}. + * when {@code target} is a {@code Boolean.class} * @jvms 4.4.6 The CONSTANT_NameAndType_info Structure * @jvms 4.4.10 The CONSTANT_Dynamic_info and CONSTANT_InvokeDynamic_info Structures */ @@ -255,29 +255,36 @@ public final class SwitchBootstraps { * enum constant's {@link Enum#name()}. * *

    - * If no element in the {@code labels} array matches the target, then - * the method of the call site return the length of the {@code labels} array. + * If for a given {@code target} there is no element in the {@code labels} + * fulfilling one of the above conditions, then the method of the call + * site returns the length of the {@code labels} array. *

    * The value of the {@code restart} index must be between {@code 0} (inclusive) and * the length of the {@code labels} array (inclusive), - * both or an {@link IndexOutOfBoundsException} is thrown. + * or an {@link IndexOutOfBoundsException} is thrown. + * + * @apiNote It is permissible for the {@code labels} array to contain {@code String} + * values that do not represent any enum constants at runtime. * * @param lookup Represents a lookup context with the accessibility * privileges of the caller. When used with {@code invokedynamic}, * this is stacked automatically by the VM. - * @param invocationName unused + * @param invocationName unused, {@code null} is permitted * @param invocationType The invocation type of the {@code CallSite} with two parameters, * an enum type, an {@code int}, and {@code int} as a return type. * @param labels case labels - {@code String} constants and {@code Class} instances, * in any combination * @return a {@code CallSite} returning the first matching element as described above * - * @throws NullPointerException if any argument is {@code null} - * @throws IllegalArgumentException if any element in the labels array is null, if the - * invocation type is not a method type whose first parameter type is an enum type, - * second parameter of type {@code int} and whose return type is {@code int}, - * or if {@code labels} contains an element that is not of type {@code String} or - * {@code Class} of the target enum type. + * @throws NullPointerException if any argument is {@code null}, unless noted otherwise + * @throws IllegalArgumentException if any element in the labels array is null + * @throws IllegalArgumentException if any element in the labels array is an empty {@code String} + * @throws IllegalArgumentException if the invocation type is not a method type + * whose first parameter type is an enum type, + * second parameter of type {@code int} and + * whose return type is {@code int} + * @throws IllegalArgumentException if {@code labels} contains an element that is not of type {@code String} or + * {@code Class} equal to the target enum type * @jvms 4.4.6 The CONSTANT_NameAndType_info Structure * @jvms 4.4.10 The CONSTANT_Dynamic_info and CONSTANT_InvokeDynamic_info Structures */ diff --git a/test/jdk/java/lang/runtime/SwitchBootstrapsTest.java b/test/jdk/java/lang/runtime/SwitchBootstrapsTest.java index a231501894f..8c6132b2815 100644 --- a/test/jdk/java/lang/runtime/SwitchBootstrapsTest.java +++ b/test/jdk/java/lang/runtime/SwitchBootstrapsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -155,23 +155,60 @@ public class SwitchBootstrapsTest { testEnum(E1.B, 0, 0, "B", "C", "A", E1.class); testEnum(E1.B, 1, 3, "B", "C", "A", E1.class); try { - testEnum(E1.B, 1, 3, "B", "C", "A", E2.class); + testEnum(E1.B, 0, -1, E2.class); fail("Didn't get the expected exception."); } catch (IllegalArgumentException ex) { //OK } try { - testEnum(E1.B, 1, 3, "B", "C", "A", String.class); + testEnum(E1.B, 0, -1, String.class); fail("Didn't get the expected exception."); } catch (IllegalArgumentException ex) { //OK } + try { + testEnum(E1.B, 0, -1, 10); + fail("Didn't get the expected exception."); + } catch (IllegalArgumentException ex) { + //OK + } + try { + testEnum(E1.B, 0, -1, new Object()); + fail("Didn't get the expected exception."); + } catch (IllegalArgumentException ex) { + //OK + } + try { + testEnum(E1.B, 0, -1, new Object[] { null }); + fail("Didn't get the expected exception."); + } catch (IllegalArgumentException ex) { + //OK + } + try { + testEnum(E1.B, 0, -1, ""); + fail("Didn't get the expected exception."); + } catch (IllegalArgumentException ex) { + //OK + } + try { + testEnum(E1.B, 0, -1, (Object[]) null); + fail("Didn't get the expected exception."); + } catch (NullPointerException ex) { + //OK + } testEnum(E1.B, 0, 0, "B", "A"); testEnum(E1.A, 0, 1, "B", "A"); testEnum(E1.A, 0, 0, "A", "A", "B"); testEnum(E1.A, 1, 1, "A", "A", "B"); testEnum(E1.A, 2, 3, "A", "A", "B"); testEnum(E1.A, 0, 0); + testEnum(E1.B, 0, 2, "A", "OLD_REMOVED_CONSTANT", "B", E1.class); + testEnum(E1.B, 1, 2, "A", "OLD_REMOVED_CONSTANT", "B", E1.class); + + //null invocation name: + MethodType switchType = MethodType.methodType(int.class, E1.class, int.class); + MethodHandle indy = ((CallSite) BSM_ENUM_SWITCH.invoke(MethodHandles.lookup(), null, switchType)).dynamicInvoker(); + assertEquals((int) indy.invoke(E1.A, 0), 0); } public void testEnumsWithConstants() throws Throwable { @@ -197,6 +234,9 @@ public class SwitchBootstrapsTest { testEnum(E.class, E.A, 0, 0, "A", "B", "C"); testEnum(E.class, E.B, 0, 1, "A", "B", "C"); testEnum(E.class, E.C, 0, 2, "A", "B", "C"); + testEnum(E.class, E.C, 0, 2, "A", "B"); + testEnum(E.class, E.C, 1, 2, "A", "B"); + testEnum(E.class, E.C, 2, 2, "A", "B"); } public void testWrongSwitchTypes() throws Throwable { @@ -279,6 +319,9 @@ public class SwitchBootstrapsTest { } catch (IllegalArgumentException ex) { //OK } + //null invocationName is OK: + BSM_TYPE_SWITCH.invoke(MethodHandles.lookup(), null, switchType, + new Object[] {Object.class}); } private static AtomicBoolean enumInitialized = new AtomicBoolean(); From bd25db1fb8573fc908f7a8a96bca417b1d44689a Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 8 Oct 2025 07:02:34 +0000 Subject: [PATCH 061/160] 8368960: Adjust java UL logging in the build Reviewed-by: erikj, dholmes --- make/ToolsJdk.gmk | 2 +- make/autoconf/boot-jdk.m4 | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/make/ToolsJdk.gmk b/make/ToolsJdk.gmk index ae0dd069c80..629cadbf83a 100644 --- a/make/ToolsJdk.gmk +++ b/make/ToolsJdk.gmk @@ -63,7 +63,7 @@ TOOL_GENERATECURRENCYDATA = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_ TOOL_TZDB = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ build.tools.tzdb.TzdbZoneRulesCompiler -TOOL_BLOCKED_CERTS = $(JAVA_SMALL) -Xlog:disable -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ +TOOL_BLOCKED_CERTS = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ --add-exports java.base/sun.security.util=ALL-UNNAMED \ build.tools.blockedcertsconverter.BlockedCertsConverter diff --git a/make/autoconf/boot-jdk.m4 b/make/autoconf/boot-jdk.m4 index 1dd768b2ae1..adc9afc349d 100644 --- a/make/autoconf/boot-jdk.m4 +++ b/make/autoconf/boot-jdk.m4 @@ -444,6 +444,9 @@ AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK_ARGUMENTS], # Force en-US environment UTIL_ADD_JVM_ARG_IF_OK([-Duser.language=en -Duser.country=US],boot_jdk_jvmargs,[$JAVA]) + UTIL_ADD_JVM_ARG_IF_OK([-Xlog:all=off:stdout],boot_jdk_jvmargs,[$JAVA]) + UTIL_ADD_JVM_ARG_IF_OK([-Xlog:all=warning:stderr],boot_jdk_jvmargs,[$JAVA]) + if test "x$BOOTJDK_USE_LOCAL_CDS" = xtrue; then # Use our own CDS archive UTIL_ADD_JVM_ARG_IF_OK([$boot_jdk_cds_args -Xshare:auto],boot_jdk_jvmargs,[$JAVA]) From d27649fe22a5bed9db72ac6c2595ac91f1fa28f8 Mon Sep 17 00:00:00 2001 From: Johannes Bechberger Date: Wed, 8 Oct 2025 08:03:32 +0000 Subject: [PATCH 062/160] 8367302: New test jdk/jfr/event/profiling/TestCPUTimeSampleQueueAutoSizes.java from JDK-8366082 is failing Reviewed-by: dholmes, apangin --- .../sampling/jfrCPUTimeThreadSampler.cpp | 23 +-- .../sampling/jfrCPUTimeThreadSampler.hpp | 7 +- src/hotspot/share/prims/whitebox.cpp | 16 +-- test/jdk/ProblemList-Xcomp.txt | 1 - .../TestCPUTimeSampleQueueAutoSizes.java | 131 +++++++++++------- test/lib/jdk/test/whitebox/WhiteBox.java | 5 +- 6 files changed, 92 insertions(+), 91 deletions(-) diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp index 2ce1a93455b..7507b9c994e 100644 --- a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp +++ b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp @@ -230,8 +230,7 @@ class JfrCPUSamplerThread : public NonJavaThread { volatile bool _is_async_processing_of_cpu_time_jfr_requests_triggered; volatile bool _warned_about_timer_creation_failure; volatile bool _signal_handler_installed; - DEBUG_ONLY(volatile bool _out_of_stack_walking_enabled;) - DEBUG_ONLY(volatile u8 _out_of_stack_walking_iterations;) + DEBUG_ONLY(volatile bool _out_of_stack_walking_enabled = true;) static const u4 STOP_SIGNAL_BIT = 0x80000000; @@ -283,10 +282,6 @@ public: void set_out_of_stack_walking_enabled(bool runnable) { AtomicAccess::release_store(&_out_of_stack_walking_enabled, runnable); } - - u8 out_of_stack_walking_iterations() const { - return AtomicAccess::load(&_out_of_stack_walking_iterations); - } #endif }; @@ -394,7 +389,6 @@ void JfrCPUSamplerThread::run() { } DEBUG_ONLY(if (AtomicAccess::load_acquire(&_out_of_stack_walking_enabled)) {) if (AtomicAccess::cmpxchg(&_is_async_processing_of_cpu_time_jfr_requests_triggered, true, false)) { - DEBUG_ONLY(AtomicAccess::inc(&_out_of_stack_walking_iterations);) stackwalk_threads_in_native(); } DEBUG_ONLY(}) @@ -588,18 +582,14 @@ void JfrCPUTimeThreadSampling::handle_timer_signal(siginfo_t* info, void* contex } #ifdef ASSERT -void JfrCPUTimeThreadSampling::set_out_of_stack_walking_enabled(bool runnable) { +bool JfrCPUTimeThreadSampling::set_out_of_stack_walking_enabled(bool runnable) { if (_instance != nullptr && _instance->_sampler != nullptr) { _instance->_sampler->set_out_of_stack_walking_enabled(runnable); + return true; + } else { + return false; } } - -u8 JfrCPUTimeThreadSampling::out_of_stack_walking_iterations() { - if (_instance != nullptr && _instance->_sampler != nullptr) { - return _instance->_sampler->out_of_stack_walking_iterations(); - } - return 0; -} #endif void JfrCPUSamplerThread::sample_thread(JfrSampleRequest& request, void* ucontext, JavaThread* jt, JfrThreadLocal* tl, JfrTicks& now) { @@ -872,8 +862,9 @@ void JfrCPUTimeThreadSampling::on_javathread_terminate(JavaThread* thread) { } #ifdef ASSERT -static void set_out_of_stack_walking_enabled(bool runnable) { +bool JfrCPUTimeThreadSampling::set_out_of_stack_walking_enabled(bool runnable) { warn(); + return false; } #endif diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp index e17e63fc3ed..e7c915fc8be 100644 --- a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp +++ b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp @@ -139,9 +139,7 @@ class JfrCPUTimeThreadSampling : public JfrCHeapObj { static void trigger_async_processing_of_cpu_time_jfr_requests(); - DEBUG_ONLY(static void set_out_of_stack_walking_enabled(bool runnable);) - - DEBUG_ONLY(static u8 out_of_stack_walking_iterations();) + DEBUG_ONLY(static bool set_out_of_stack_walking_enabled(bool runnable);) }; #else @@ -162,8 +160,7 @@ private: static void on_javathread_create(JavaThread* thread); static void on_javathread_terminate(JavaThread* thread); - DEBUG_ONLY(static void set_out_of_stack_walking_enabled(bool runnable)); - DEBUG_ONLY(static u8 out_of_stack_walking_iterations();) + DEBUG_ONLY(static bool set_out_of_stack_walking_enabled(bool runnable)); }; #endif // defined(LINUX) diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 1ecd105f218..b4d100341e0 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -2710,7 +2710,7 @@ WB_ENTRY(void, WB_WaitUnsafe(JNIEnv* env, jobject wb, jint time)) os::naked_short_sleep(time); WB_END -WB_ENTRY(void, WB_BusyWait(JNIEnv* env, jobject wb, jint time)) +WB_ENTRY(void, WB_BusyWaitCPUTime(JNIEnv* env, jobject wb, jint time)) ThreadToNativeFromVM ttn(thread); u8 start = os::current_thread_cpu_time(); u8 target_duration = time * (u8)1000000; @@ -2721,21 +2721,12 @@ WB_END WB_ENTRY(jboolean, WB_CPUSamplerSetOutOfStackWalking(JNIEnv* env, jobject wb, jboolean enable)) #if defined(ASSERT) && INCLUDE_JFR && defined(LINUX) - JfrCPUTimeThreadSampling::set_out_of_stack_walking_enabled(enable == JNI_TRUE); - return JNI_TRUE; + return JfrCPUTimeThreadSampling::set_out_of_stack_walking_enabled(enable == JNI_TRUE) ? JNI_TRUE : JNI_FALSE; #else return JNI_FALSE; #endif WB_END -WB_ENTRY(jlong, WB_CPUSamplerOutOfStackWalkingIterations(JNIEnv* env, jobject wb)) - #if defined(ASSERT) && INCLUDE_JFR && defined(LINUX) - return (jlong)JfrCPUTimeThreadSampling::out_of_stack_walking_iterations(); - #else - return 0; - #endif -WB_END - WB_ENTRY(jstring, WB_GetLibcName(JNIEnv* env, jobject o)) ThreadToNativeFromVM ttn(thread); jstring info_string = env->NewStringUTF(XSTR(LIBC)); @@ -3092,9 +3083,8 @@ static JNINativeMethod methods[] = { {CC"isJVMTIIncluded", CC"()Z", (void*)&WB_IsJVMTIIncluded}, {CC"waitUnsafe", CC"(I)V", (void*)&WB_WaitUnsafe}, - {CC"busyWait", CC"(I)V", (void*)&WB_BusyWait}, + {CC"busyWaitCPUTime", CC"(I)V", (void*)&WB_BusyWaitCPUTime}, {CC"cpuSamplerSetOutOfStackWalking", CC"(Z)Z", (void*)&WB_CPUSamplerSetOutOfStackWalking}, - {CC"cpuSamplerOutOfStackWalkingIterations", CC"()J",(void*)&WB_CPUSamplerOutOfStackWalkingIterations}, {CC"getLibcName", CC"()Ljava/lang/String;", (void*)&WB_GetLibcName}, {CC"pinObject", CC"(Ljava/lang/Object;)V", (void*)&WB_PinObject}, diff --git a/test/jdk/ProblemList-Xcomp.txt b/test/jdk/ProblemList-Xcomp.txt index 8e37e6e15d0..5ed171a1fea 100644 --- a/test/jdk/ProblemList-Xcomp.txt +++ b/test/jdk/ProblemList-Xcomp.txt @@ -29,4 +29,3 @@ java/lang/invoke/MethodHandles/CatchExceptionTest.java 8146623 generic-all java/lang/reflect/callerCache/ReflectionCallerCacheTest.java 8332028 generic-all -jdk/jfr/event/profiling/TestCPUTimeSampleQueueAutoSizes.java 8367302 linux-all diff --git a/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleQueueAutoSizes.java b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleQueueAutoSizes.java index 1ea96e3bad3..819329aabf5 100644 --- a/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleQueueAutoSizes.java +++ b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleQueueAutoSizes.java @@ -24,6 +24,7 @@ package jdk.jfr.event.profiling; import java.time.Duration; +import java.time.Instant; import java.util.ArrayList; import java.util.Comparator; import java.util.stream.Collectors; @@ -41,8 +42,15 @@ import jdk.test.whitebox.WhiteBox; /* * Tests the sample queues increase in size as needed, when loss is recorded. + * + * The test starts CPU time sampling with a short interval (1ms), disabling + * out-of-stack sample processing for the duration of the test. + * It now runs in native for one second, to cause queue overflows, + * then it comes back into Java to trigger the queue walking. + * Repeats the cycle 5 times and verifies that the loss decreases from the first + * to the last iteration. * @test - * @requires vm.hasJFR & os.family == "linux" & vm.debug + * @requires vm.hasJFR & os.family == "linux" & vm.debug & vm.flagless * @library /test/lib * @modules jdk.jfr/jdk.jfr.internal * @build jdk.test.whitebox.WhiteBox @@ -54,15 +62,13 @@ public class TestCPUTimeSampleQueueAutoSizes { private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); - private static final String BURST_THREAD_NAME = "Burst-Thread-1"; - - static volatile boolean alive = true; - record LossEvent(long relativeTimeMillis, long lostSamples) {} /** A data collection from the CPUTimeSampleLost events for the burst thread */ static class LossEventCollection { private final List events = new ArrayList<>(); + private final List sampleEventsInTimeBox = new ArrayList<>(); + private final List timeBoxEnds = new ArrayList<>(); public synchronized void addEvent(LossEvent event) { events.add(event); @@ -74,81 +80,100 @@ public class TestCPUTimeSampleQueueAutoSizes { .collect(Collectors.toList()); } - public List getEventsPerInterval(long widthMillis, long stopTimeMillis) { + public synchronized List getEventsPerTimeBox() { List ret = new ArrayList<>(); - for (long start = 0; start < stopTimeMillis; start += widthMillis) { - long actualStart = Math.min(start, stopTimeMillis - widthMillis); + AtomicLong previousEnd = new AtomicLong(0); + for (Long timeBoxEnd : timeBoxEnds) { long lostSamples = events.stream() - .filter(e -> e.relativeTimeMillis >= actualStart && e.relativeTimeMillis < actualStart + widthMillis) + .filter(e -> e.relativeTimeMillis >= previousEnd.get() && e.relativeTimeMillis <= timeBoxEnd) .mapToLong(e -> e.lostSamples) .sum(); - ret.add(new LossEvent(actualStart, lostSamples)); + ret.add(new LossEvent(previousEnd.get(), lostSamples)); + previousEnd.set(timeBoxEnd); } return ret; } + public synchronized void addTimeBoxEnd(long timeBoxEnd, long sampleEvents) { + timeBoxEnds.add(timeBoxEnd); + sampleEventsInTimeBox.add(sampleEvents); + } + + public synchronized void print() { + System.out.println("Loss event information:"); + for (int i = 0; i < timeBoxEnds.size(); i++) { + System.out.println(" Time box end: " + timeBoxEnds.get(i) + ", sample events: " + sampleEventsInTimeBox.get(i)); + } + for (LossEvent e : events) { + System.out.println(" Lost samples event: " + e.lostSamples + " at " + e.relativeTimeMillis); + } + for (LossEvent e : getEventsPerTimeBox()) { + System.out.println(" Lost samples in time box ending at " + e.relativeTimeMillis + ": " + e.lostSamples); + } + } } public static void main(String[] args) throws Exception { try (RecordingStream rs = new RecordingStream()) { // setup recording - AtomicLong firstSampleTimeMillis = new AtomicLong(0); - AtomicLong lastSampleTimeMillis = new AtomicLong(0); + long burstThreadId = Thread.currentThread().threadId(); + final long startTimeMillis = Instant.now().toEpochMilli(); LossEventCollection lossEvents = new LossEventCollection(); + AtomicLong sampleEventCountInTimeBox = new AtomicLong(0); rs.enable(EventNames.CPUTimeSample).with("throttle", "1ms"); - rs.onEvent(EventNames.CPUTimeSample, e -> { - if (firstSampleTimeMillis.get() == 0 && e.getThread("eventThread").getJavaName().equals(BURST_THREAD_NAME)) { - firstSampleTimeMillis.set(e.getStartTime().toEpochMilli()); - } - if (e.getThread("eventThread").getJavaName().equals(BURST_THREAD_NAME)) { - lastSampleTimeMillis.set(e.getStartTime().toEpochMilli()); - } - }); rs.enable(EventNames.CPUTimeSamplesLost); rs.onEvent(EventNames.CPUTimeSamplesLost, e -> { - if (e.getThread("eventThread").getJavaName().equals(BURST_THREAD_NAME)) { + if (e.getThread("eventThread").getJavaThreadId() == burstThreadId) { long eventTime = e.getStartTime().toEpochMilli(); - long relativeTime = firstSampleTimeMillis.get() > 0 ? (eventTime - firstSampleTimeMillis.get()) : eventTime; - System.out.println("Lost samples: " + e.getLong("lostSamples") + " at " + relativeTime); + long relativeTime = eventTime - startTimeMillis; + System.out.println("Lost samples: " + e.getLong("lostSamples") + " at " + relativeTime + " start time " + startTimeMillis); lossEvents.addEvent(new LossEvent(relativeTime, e.getLong("lostSamples"))); } }); - WHITE_BOX.cpuSamplerSetOutOfStackWalking(false); + rs.onEvent(EventNames.CPUTimeSample, e -> { + if (e.getThread("eventThread").getJavaThreadId() == burstThreadId) { + sampleEventCountInTimeBox.incrementAndGet(); + } + }); rs.startAsync(); - // this thread runs all along - Thread burstThread = new Thread(() -> WHITE_BOX.busyWait(11000)); - burstThread.setName(BURST_THREAD_NAME); - burstThread.start(); - // now we toggle out-of-stack-walking off, wait 1 second and then turn it on for 500ms a few times + // we disable the out-of-stack walking so that the queue fills up and overflows + // while we are in native code + disableOutOfStackWalking(); + + for (int i = 0; i < 5; i++) { - boolean supported = WHITE_BOX.cpuSamplerSetOutOfStackWalking(false); - if (!supported) { - System.out.println("Out-of-stack-walking not supported, skipping test"); - Asserts.assertFalse(true); - return; - } - Thread.sleep(700); - long iterations = WHITE_BOX.cpuSamplerOutOfStackWalkingIterations(); - WHITE_BOX.cpuSamplerSetOutOfStackWalking(true); - Thread.sleep(300); - while (WHITE_BOX.cpuSamplerOutOfStackWalkingIterations() == iterations) { - Thread.sleep(50); // just to make sure the stack walking really ran - } + // run in native for one second + WHITE_BOX.busyWaitCPUTime(1000); + // going out-of-native at the end of the previous call should have triggered + // the safepoint handler, thereby also triggering the stack walking and creation + // of the loss event + WHITE_BOX.forceSafepoint(); // just to be sure + lossEvents.addTimeBoxEnd(Instant.now().toEpochMilli() - startTimeMillis, sampleEventCountInTimeBox.get()); + sampleEventCountInTimeBox.set(0); } + + rs.stop(); rs.close(); - checkThatLossDecreased(lossEvents, lastSampleTimeMillis.get() - firstSampleTimeMillis.get()); + + enableOutOfStackWalking(); + + checkThatLossDecreased(lossEvents); } } - static void checkThatLossDecreased(LossEventCollection lossEvents, long lastSampleTimeMillis) { - List intervalLosses = lossEvents.getEventsPerInterval(1000, lastSampleTimeMillis); - for (LossEvent interval : intervalLosses) { - System.out.println("Lost samples in interval " + interval.relativeTimeMillis + ": " + interval.lostSamples); - } - // check that there are at least 3 intervals - Asserts.assertTrue(intervalLosses.size() > 2); - // check that the second to last interval has far fewer lost samples than the first - Asserts.assertTrue(intervalLosses.get(intervalLosses.size() - 2).lostSamples < - intervalLosses.get(0).lostSamples / 2); + static void disableOutOfStackWalking() { + Asserts.assertTrue(WHITE_BOX.cpuSamplerSetOutOfStackWalking(false), "Out-of-stack-walking not supported"); + } + + static void enableOutOfStackWalking() { + WHITE_BOX.cpuSamplerSetOutOfStackWalking(true); + } + + static void checkThatLossDecreased(LossEventCollection lossEvents) { + lossEvents.print(); + List timeBoxedLosses = lossEvents.getEventsPerTimeBox(); + // check that the last time box has far fewer lost samples than the first + Asserts.assertTrue(timeBoxedLosses.get(timeBoxedLosses.size() - 1).lostSamples <= + timeBoxedLosses.get(0).lostSamples / 2); } } diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index 669ec48b619..d07dedd2a8c 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -847,13 +847,12 @@ public class WhiteBox { public native void waitUnsafe(int time_ms); - public native void busyWait(int cpuTimeMs); + public native void busyWaitCPUTime(int cpuTimeMs); + // returns true if supported, false if not public native boolean cpuSamplerSetOutOfStackWalking(boolean enable); - public native long cpuSamplerOutOfStackWalkingIterations(); - public native void pinObject(Object o); public native void unpinObject(Object o); From f58e17fd27e868e4a8816befc4c4bb8946c1f7fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B3n=20Seoane=20Ampudia?= Date: Wed, 8 Oct 2025 08:58:58 +0000 Subject: [PATCH 063/160] 8368780: IGV: Upgrade to Netbeans Platform 27 Reviewed-by: rcastanedalo, chagedorn --- src/utils/IdealGraphVisualizer/Filter/pom.xml | 4 ++-- src/utils/IdealGraphVisualizer/README.md | 2 +- src/utils/IdealGraphVisualizer/pom.xml | 12 ++++++++---- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/utils/IdealGraphVisualizer/Filter/pom.xml b/src/utils/IdealGraphVisualizer/Filter/pom.xml index 176f7a80180..c22ce274493 100644 --- a/src/utils/IdealGraphVisualizer/Filter/pom.xml +++ b/src/utils/IdealGraphVisualizer/Filter/pom.xml @@ -1,6 +1,6 @@