From d07e530d33360dae687552a6dfbe26408f3fb58e Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Mon, 3 Jun 2024 12:07:11 +0000 Subject: [PATCH 01/14] 8333128: Linux x86_32 configure fail with --with-hsdis=binutils --with-binutils-src Reviewed-by: shade, jwaters, ihse --- make/autoconf/lib-hsdis.m4 | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/make/autoconf/lib-hsdis.m4 b/make/autoconf/lib-hsdis.m4 index 33d8a35f8fdf4..9b9f24d0da199 100644 --- a/make/autoconf/lib-hsdis.m4 +++ b/make/autoconf/lib-hsdis.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -268,14 +268,16 @@ AC_DEFUN([LIB_SETUP_HSDIS_BINUTILS], disasm_header="\"$BINUTILS_INSTALL_DIR/include/dis-asm.h\"" if test -e $BINUTILS_INSTALL_DIR/lib/libbfd.a && \ test -e $BINUTILS_INSTALL_DIR/lib/libopcodes.a && \ - (test -e $BINUTILS_INSTALL_DIR/lib/libiberty.a || test -e $BINUTILS_INSTALL_DIR/lib64/libiberty.a); then + (test -e $BINUTILS_INSTALL_DIR/lib/libiberty.a || test -e $BINUTILS_INSTALL_DIR/lib64/libiberty.a || test -e $BINUTILS_INSTALL_DIR/lib32/libiberty.a); then HSDIS_CFLAGS="-DLIBARCH_$OPENJDK_TARGET_CPU_LEGACY_LIB -I$BINUTILS_INSTALL_DIR/include" - # libiberty ignores --libdir and may be installed in $BINUTILS_INSTALL_DIR/lib or $BINUTILS_INSTALL_DIR/lib64 - # depending on system setup + # libiberty ignores --libdir and may be installed in $BINUTILS_INSTALL_DIR/lib, $BINUTILS_INSTALL_DIR/lib32 + # or $BINUTILS_INSTALL_DIR/lib64, depending on system setup LIBIBERTY_LIB="" if test -e $BINUTILS_INSTALL_DIR/lib/libiberty.a; then LIBIBERTY_LIB="$BINUTILS_INSTALL_DIR/lib/libiberty.a" + elif test -e $BINUTILS_INSTALL_DIR/lib32/libiberty.a; then + LIBIBERTY_LIB="$BINUTILS_INSTALL_DIR/lib32/libiberty.a" else LIBIBERTY_LIB="$BINUTILS_INSTALL_DIR/lib64/libiberty.a" fi From 1c514b34c0260823e70f209996ac933a76ac34c2 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Mon, 3 Jun 2024 13:00:23 +0000 Subject: [PATCH 02/14] 8325435: [macos] Menu or JPopupMenu not closed when main window is resized Reviewed-by: azvegint --- .../native/libawt_lwawt/awt/AWTWindow.m | 6 +- test/jdk/javax/swing/JMenu/TestUngrab.java | 120 ++++++++++++++++++ 2 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 test/jdk/javax/swing/JMenu/TestUngrab.java diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m index 77d1e216a75c2..6aba7d55856d7 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m @@ -1024,7 +1024,11 @@ - (void)sendEvent:(NSEvent *)event { NSRect contentRect = [self.nsWindow contentRectForFrameRect:frame]; // Check if the click happened in the non-client area (title bar) - if (p.y >= (frame.origin.y + contentRect.size.height)) { + // Also, non-client area includes the edges at left, right and botton of frame + if ((p.y >= (frame.origin.y + contentRect.size.height)) || + (p.x >= (frame.origin.x + contentRect.size.width - 3)) || + (fabs(frame.origin.x - p.x) < 3) || + (fabs(frame.origin.y - p.y) < 3)) { JNIEnv *env = [ThreadUtilities getJNIEnvUncached]; jobject platformWindow = (*env)->NewLocalRef(env, self.javaPlatformWindow); if (platformWindow != NULL) { diff --git a/test/jdk/javax/swing/JMenu/TestUngrab.java b/test/jdk/javax/swing/JMenu/TestUngrab.java new file mode 100644 index 0000000000000..64326009c6c77 --- /dev/null +++ b/test/jdk/javax/swing/JMenu/TestUngrab.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8267374 + * @key headful + * @requires (os.family == "mac") + * @summary Verifies menu closes when main window is resized + * @run main TestUngrab + */ + +import java.awt.Point; +import java.awt.Dimension; +import java.awt.Robot; +import java.awt.event.ActionEvent; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.SwingUtilities; + +public class TestUngrab { + /** + * Menu (JMenuBar and JPopupMenu) not hidden when resizing the window. + * -> UngrabEvent not sent. + */ + static JMenu menu; + static JFrame frame; + static volatile Point loc; + static volatile Point point; + static volatile Dimension dim; + static volatile int width; + static volatile int height; + static volatile boolean popupVisible; + + private static void createAndShowGUI() { + frame = new JFrame(); + JMenuBar mb = new JMenuBar(); + menu = new JMenu("Menu"); + menu.add(new JMenuItem("Item 1")); + menu.add(new JMenuItem("Item 2")); + mb.add(menu); + + frame.setJMenuBar(mb); + frame.setSize(300, 300); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + robot.setAutoDelay(100); + SwingUtilities.invokeAndWait(() -> createAndShowGUI()); + robot.waitForIdle(); + robot.delay(1000); + + SwingUtilities.invokeAndWait(() -> { + point = menu.getLocationOnScreen(); + dim = menu.getSize(); + }); + robot.mouseMove(point.x + dim.width / 2, point.y + dim.height / 2); + robot.waitForIdle(); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + + SwingUtilities.invokeAndWait(() -> { + loc = frame.getLocationOnScreen(); + width = frame.getWidth(); + height = frame.getHeight(); + }); + robot.mouseMove(loc.x + width, loc.y + height); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(1000); + + SwingUtilities.invokeAndWait(() -> { + popupVisible = menu.isPopupMenuVisible(); + }); + System.out.println("isPopupMenuVisible " + popupVisible); + if (popupVisible) { + throw new RuntimeException("popup menu not closed on resize"); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + +} From 27af19d921a5cf15f5146471b58961815690b4f2 Mon Sep 17 00:00:00 2001 From: John Engebretson Date: Mon, 3 Jun 2024 13:38:48 +0000 Subject: [PATCH 03/14] 8332586: Avoid cloning empty arrays in java.lang.reflect.{Method,Constructor} Reviewed-by: shade, rriggs, liach --- .../java/lang/reflect/Constructor.java | 7 +- .../classes/java/lang/reflect/Method.java | 6 +- .../lang/reflect/ConstructorBenchmark.java | 85 +++++++++++++++++++ .../java/lang/reflect/MethodBenchmark.java | 85 +++++++++++++++++++ 4 files changed, 176 insertions(+), 7 deletions(-) create mode 100644 test/micro/org/openjdk/bench/java/lang/reflect/ConstructorBenchmark.java create mode 100644 test/micro/org/openjdk/bench/java/lang/reflect/MethodBenchmark.java diff --git a/src/java.base/share/classes/java/lang/reflect/Constructor.java b/src/java.base/share/classes/java/lang/reflect/Constructor.java index 5069530408255..99f14d0153624 100644 --- a/src/java.base/share/classes/java/lang/reflect/Constructor.java +++ b/src/java.base/share/classes/java/lang/reflect/Constructor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -266,7 +266,7 @@ Class[] getSharedExceptionTypes() { */ @Override public Class[] getParameterTypes() { - return parameterTypes.clone(); + return parameterTypes.length == 0 ? parameterTypes : parameterTypes.clone(); } /** @@ -292,10 +292,9 @@ public Type[] getGenericParameterTypes() { */ @Override public Class[] getExceptionTypes() { - return exceptionTypes.clone(); + return exceptionTypes.length == 0 ? exceptionTypes : exceptionTypes.clone(); } - /** * {@inheritDoc} * @throws GenericSignatureFormatError {@inheritDoc} diff --git a/src/java.base/share/classes/java/lang/reflect/Method.java b/src/java.base/share/classes/java/lang/reflect/Method.java index 028577c229cf4..b6ccbaa829452 100644 --- a/src/java.base/share/classes/java/lang/reflect/Method.java +++ b/src/java.base/share/classes/java/lang/reflect/Method.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -315,7 +315,7 @@ Class[] getSharedExceptionTypes() { */ @Override public Class[] getParameterTypes() { - return parameterTypes.clone(); + return parameterTypes.length == 0 ? parameterTypes: parameterTypes.clone(); } /** @@ -342,7 +342,7 @@ public Type[] getGenericParameterTypes() { */ @Override public Class[] getExceptionTypes() { - return exceptionTypes.clone(); + return exceptionTypes.length == 0 ? exceptionTypes : exceptionTypes.clone(); } /** diff --git a/test/micro/org/openjdk/bench/java/lang/reflect/ConstructorBenchmark.java b/test/micro/org/openjdk/bench/java/lang/reflect/ConstructorBenchmark.java new file mode 100644 index 0000000000000..9c734ce65e988 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/reflect/ConstructorBenchmark.java @@ -0,0 +1,85 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.lang.reflect; + +import java.lang.reflect.Constructor; +import java.util.concurrent.TimeUnit; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +/** + * Benchmark measuring the speed of Method/Constructor.getExceptionTypes() and + * getParameterTypes(), in cases where the result array is length zero. + */ +@BenchmarkMode(Mode.AverageTime) +@State(Scope.Benchmark) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Fork(1) +@Warmup(iterations = 3, time = 2, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS) +public class ConstructorBenchmark { + Constructor emptyExceptionsConstructor; + Constructor emptyParametersConstructor; + Constructor oneExceptionConstructor; + Constructor oneParameterConstructor; + + public ConstructorBenchmark() { + try { + emptyParametersConstructor = Object.class.getConstructor(); + oneParameterConstructor = String.class.getConstructor(String.class); + + emptyExceptionsConstructor = emptyParametersConstructor; + oneExceptionConstructor = String.class.getConstructor(byte[].class, String.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Benchmark + public Object[] getExceptionTypes() throws Exception { + return oneExceptionConstructor.getExceptionTypes(); + } + + @Benchmark + public Object[] getExceptionTypesEmpty() throws Exception { + return emptyExceptionsConstructor.getExceptionTypes(); + } + + @Benchmark + public Object[] getParameterTypes() throws Exception { + return oneParameterConstructor.getParameterTypes(); + } + + @Benchmark + public Object[] getParameterTypesEmpty() throws Exception { + return emptyParametersConstructor.getParameterTypes(); + } +} diff --git a/test/micro/org/openjdk/bench/java/lang/reflect/MethodBenchmark.java b/test/micro/org/openjdk/bench/java/lang/reflect/MethodBenchmark.java new file mode 100644 index 0000000000000..96a218d440594 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/reflect/MethodBenchmark.java @@ -0,0 +1,85 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.lang.reflect; + +import java.lang.reflect.Method; +import java.util.concurrent.TimeUnit; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +/** + * Benchmark measuring the speed of Method/Method.getExceptionTypes() and + * getParameterTypes(), in cases where the result array is length zero. + */ +@BenchmarkMode(Mode.AverageTime) +@State(Scope.Benchmark) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Fork(1) +@Warmup(iterations = 3, time = 2, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS) +public class MethodBenchmark { + Method emptyExceptionsMethod; + Method emptyParametersMethod; + Method oneExceptionMethod; + Method oneParameterMethod; + + public MethodBenchmark() { + try { + emptyParametersMethod = Object.class.getDeclaredMethod("hashCode"); + oneParameterMethod = String.class.getDeclaredMethod("getBytes", String.class); + + emptyExceptionsMethod = emptyParametersMethod; + oneExceptionMethod = oneParameterMethod; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Benchmark + public Object[] getExceptionTypes() throws Exception { + return oneExceptionMethod.getExceptionTypes(); + } + + @Benchmark + public Object[] getExceptionTypesEmpty() throws Exception { + return emptyExceptionsMethod.getExceptionTypes(); + } + + @Benchmark + public Object[] getParameterTypes() throws Exception { + return oneParameterMethod.getParameterTypes(); + } + + @Benchmark + public Object[] getParameterTypesEmpty() throws Exception { + return emptyParametersMethod.getParameterTypes(); + } +} From 1f9e62904c624b12bd344d2ef3021eb5d3377197 Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Mon, 3 Jun 2024 14:03:34 +0000 Subject: [PATCH 04/14] 8333434: IGV: Print loop node for PHASE_BEFORE/AFTER_CLOOPS Reviewed-by: thartmann, rcastanedalo --- src/hotspot/share/opto/loopnode.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index b877888fccbe7..d58be5105169a 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -1781,7 +1781,7 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*&loop, BasicType iv_ } assert(x->Opcode() == Op_Loop || x->Opcode() == Op_LongCountedLoop, "regular loops only"); - C->print_method(PHASE_BEFORE_CLOOPS, 3); + C->print_method(PHASE_BEFORE_CLOOPS, 3, x); // =================================================== // We can only convert this loop to a counted loop if we can guarantee that the iv phi will never overflow at runtime. @@ -2289,7 +2289,7 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*&loop, BasicType iv_ } #endif - C->print_method(PHASE_AFTER_CLOOPS, 3); + C->print_method(PHASE_AFTER_CLOOPS, 3, l); // Capture bounds of the loop in the induction variable Phi before // subsequent transformation (iteration splitting) obscures the From 4de620732f03c71fec3e1c233947742d334c88ad Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 3 Jun 2024 15:40:47 +0000 Subject: [PATCH 05/14] 8333229: Parallel: Rename ParMarkBitMap::_region_start to _heap_start Reviewed-by: tschatzl --- .../share/gc/parallel/parMarkBitMap.cpp | 10 +++--- .../share/gc/parallel/parMarkBitMap.hpp | 15 +++----- .../gc/parallel/parMarkBitMap.inline.hpp | 34 +++++++------------ .../share/gc/parallel/psParallelCompact.hpp | 6 ++-- 4 files changed, 26 insertions(+), 39 deletions(-) diff --git a/src/hotspot/share/gc/parallel/parMarkBitMap.cpp b/src/hotspot/share/gc/parallel/parMarkBitMap.cpp index 6452f03b5cba5..434b719aa13ee 100644 --- a/src/hotspot/share/gc/parallel/parMarkBitMap.cpp +++ b/src/hotspot/share/gc/parallel/parMarkBitMap.cpp @@ -36,7 +36,7 @@ bool ParMarkBitMap::initialize(MemRegion covered_region) { - const idx_t bits = bits_required(covered_region); + const idx_t bits = words_to_bits(covered_region.word_size()); const size_t words = bits / BitsPerWord; const size_t raw_bytes = words * sizeof(idx_t); @@ -55,15 +55,15 @@ ParMarkBitMap::initialize(MemRegion covered_region) _virtual_space = new PSVirtualSpace(rs, page_sz); if (_virtual_space != nullptr && _virtual_space->expand_by(_reserved_byte_size)) { - _region_start = covered_region.start(); - _region_size = covered_region.word_size(); + _heap_start = covered_region.start(); + _heap_size = covered_region.word_size(); BitMap::bm_word_t* map = (BitMap::bm_word_t*)_virtual_space->reserved_low_addr(); _beg_bits = BitMapView(map, bits); return true; } - _region_start = 0; - _region_size = 0; + _heap_start = 0; + _heap_size = 0; if (_virtual_space != nullptr) { delete _virtual_space; _virtual_space = nullptr; diff --git a/src/hotspot/share/gc/parallel/parMarkBitMap.hpp b/src/hotspot/share/gc/parallel/parMarkBitMap.hpp index be905be6e906e..eaee37c3a1bc9 100644 --- a/src/hotspot/share/gc/parallel/parMarkBitMap.hpp +++ b/src/hotspot/share/gc/parallel/parMarkBitMap.hpp @@ -74,17 +74,12 @@ class ParMarkBitMap: public CHeapObj { // granularity is 2, 64-bit is 1. static inline int obj_granularity_shift() { return LogMinObjAlignment; } - HeapWord* _region_start; - size_t _region_size; + HeapWord* _heap_start; + size_t _heap_size; BitMapView _beg_bits; PSVirtualSpace* _virtual_space; size_t _reserved_byte_size; - // Return the number of bits required to represent the specified number of - // HeapWords, or the specified region. - static inline idx_t bits_required(size_t words); - static inline idx_t bits_required(MemRegion covered_region); - // Convert sizes from bits to HeapWords and back. An object that is n bits // long will be bits_to_words(n) words long. An object that is m words long // will take up words_to_bits(m) bits in the bitmap. @@ -94,9 +89,9 @@ class ParMarkBitMap: public CHeapObj { // Return word-aligned up range_end, which must not be greater than size(). inline idx_t align_range_end(idx_t range_end) const; - inline HeapWord* region_start() const; - inline HeapWord* region_end() const; - inline size_t region_size() const; + inline HeapWord* heap_start() const; + inline HeapWord* heap_end() const; + inline size_t heap_size() const; inline size_t size() const; // Convert a heap address to/from a bit index. diff --git a/src/hotspot/share/gc/parallel/parMarkBitMap.inline.hpp b/src/hotspot/share/gc/parallel/parMarkBitMap.inline.hpp index 07e2289fb0a06..5cc7b304c9933 100644 --- a/src/hotspot/share/gc/parallel/parMarkBitMap.inline.hpp +++ b/src/hotspot/share/gc/parallel/parMarkBitMap.inline.hpp @@ -31,7 +31,7 @@ #include "utilities/bitMap.inline.hpp" inline ParMarkBitMap::ParMarkBitMap(): - _region_start(nullptr), _region_size(0), _beg_bits(), _virtual_space(nullptr), _reserved_byte_size(0) + _heap_start(nullptr), _heap_size(0), _beg_bits(), _virtual_space(nullptr), _reserved_byte_size(0) { } inline void ParMarkBitMap::clear_range(HeapWord* beg, HeapWord* end) { @@ -40,24 +40,16 @@ inline void ParMarkBitMap::clear_range(HeapWord* beg, HeapWord* end) { _beg_bits.clear_range(beg_bit, end_bit); } -inline ParMarkBitMap::idx_t ParMarkBitMap::bits_required(size_t words) { - return words_to_bits(words); +inline HeapWord* ParMarkBitMap::heap_start() const { + return _heap_start; } -inline ParMarkBitMap::idx_t ParMarkBitMap::bits_required(MemRegion covered_region) { - return bits_required(covered_region.word_size()); +inline HeapWord* ParMarkBitMap::heap_end() const { + return heap_start() + heap_size(); } -inline HeapWord* ParMarkBitMap::region_start() const { - return _region_start; -} - -inline HeapWord* ParMarkBitMap::region_end() const { - return region_start() + region_size(); -} - -inline size_t ParMarkBitMap::region_size() const { - return _region_size; +inline size_t ParMarkBitMap::heap_size() const { + return _heap_size; } inline size_t ParMarkBitMap::size() const { @@ -98,12 +90,12 @@ inline bool ParMarkBitMap::mark_obj(oop obj) { inline ParMarkBitMap::idx_t ParMarkBitMap::addr_to_bit(HeapWord* addr) const { DEBUG_ONLY(verify_addr(addr);) - return words_to_bits(pointer_delta(addr, region_start())); + return words_to_bits(pointer_delta(addr, heap_start())); } inline HeapWord* ParMarkBitMap::bit_to_addr(idx_t bit) const { DEBUG_ONLY(verify_bit(bit);) - return region_start() + bits_to_words(bit); + return heap_start() + bits_to_words(bit); } inline ParMarkBitMap::idx_t ParMarkBitMap::align_range_end(idx_t range_end) const { @@ -136,10 +128,10 @@ inline void ParMarkBitMap::verify_bit(idx_t bit) const { inline void ParMarkBitMap::verify_addr(HeapWord* addr) const { // Allow one past the last valid address; useful for loop bounds. - assert(addr >= region_start(), - "addr too small, addr: " PTR_FORMAT " region start: " PTR_FORMAT, p2i(addr), p2i(region_start())); - assert(addr <= region_end(), - "addr too big, addr: " PTR_FORMAT " region end: " PTR_FORMAT, p2i(addr), p2i(region_end())); + assert(addr >= heap_start(), + "addr too small, addr: " PTR_FORMAT " heap start: " PTR_FORMAT, p2i(addr), p2i(heap_start())); + assert(addr <= heap_end(), + "addr too big, addr: " PTR_FORMAT " heap end: " PTR_FORMAT, p2i(addr), p2i(heap_end())); } #endif // #ifdef ASSERT diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.hpp index 7c16f969e2b89..5df188c9076fb 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp @@ -520,7 +520,7 @@ inline size_t ParallelCompactData::region_offset(const HeapWord* addr) const { assert(addr >= _heap_start, "bad addr"); - // would mistakenly return 0 for _region_end + // This method would mistakenly return 0 for _heap_end; hence exclusive. assert(addr < _heap_end, "bad addr"); return (size_t(addr) & RegionAddrOffsetMask) >> LogHeapWordSize; } @@ -528,8 +528,8 @@ ParallelCompactData::region_offset(const HeapWord* addr) const inline size_t ParallelCompactData::addr_to_region_idx(const HeapWord* addr) const { - assert(addr >= _heap_start, "bad addr " PTR_FORMAT " _region_start " PTR_FORMAT, p2i(addr), p2i(_heap_start)); - assert(addr <= _heap_end, "bad addr " PTR_FORMAT " _region_end " PTR_FORMAT, p2i(addr), p2i(_heap_end)); + assert(addr >= _heap_start, "bad addr " PTR_FORMAT " _heap_start " PTR_FORMAT, p2i(addr), p2i(_heap_start)); + assert(addr <= _heap_end, "bad addr " PTR_FORMAT " _heap_end " PTR_FORMAT, p2i(addr), p2i(_heap_end)); return pointer_delta(addr, _heap_start) >> Log2RegionSize; } From 9686e804a2b058955ff88149c54a0a7896c0a2eb Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Mon, 3 Jun 2024 15:52:21 +0000 Subject: [PATCH 06/14] 8333103: Re-examine the console provider loading Reviewed-by: redestad, jpai --- .../share/classes/java/io/Console.java | 41 +++++++++++-------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/src/java.base/share/classes/java/io/Console.java b/src/java.base/share/classes/java/io/Console.java index c735f9af85362..0aa12bdf4c8b5 100644 --- a/src/java.base/share/classes/java/io/Console.java +++ b/src/java.base/share/classes/java/io/Console.java @@ -636,7 +636,7 @@ private static UnsupportedOperationException newUnsupportedOperationException() CHARSET = cs; - cons = instantiateConsole(istty); + cons = instantiateConsole(); // Set up JavaIOAccess in SharedSecrets SharedSecrets.setJavaIOAccess(new JavaIOAccess() { @@ -647,7 +647,7 @@ public Console console() { } @SuppressWarnings("removal") - private static Console instantiateConsole(boolean istty) { + private static Console instantiateConsole() { Console c; try { @@ -655,24 +655,29 @@ private static Console instantiateConsole(boolean istty) { * The JdkConsole provider used for Console instantiation can be specified * with the system property "jdk.console", whose value designates the module * name of the implementation, and which defaults to the value of - * {@code JdkConsoleProvider.DEFAULT_PROVIDER_MODULE_NAME}. If no - * providers are available, or instantiation failed, java.base built-in + * {@code JdkConsoleProvider.DEFAULT_PROVIDER_MODULE_NAME}. If multiple + * provider implementations exist in that module, the first one found is used. + * If no providers are available, or instantiation failed, java.base built-in * Console implementation is used. */ - PrivilegedAction pa = () -> { - var consModName = System.getProperty("jdk.console", - JdkConsoleProvider.DEFAULT_PROVIDER_MODULE_NAME); - return ServiceLoader.load(ModuleLayer.boot(), JdkConsoleProvider.class).stream() - .map(ServiceLoader.Provider::get) - .filter(jcp -> consModName.equals(jcp.getClass().getModule().getName())) - .map(jcp -> jcp.console(istty, CHARSET)) - .filter(Objects::nonNull) - .findAny() - .map(jc -> (Console) new ProxyingConsole(jc)) - .orElse(null); - }; - c = AccessController.doPrivileged(pa); - } catch (ServiceConfigurationError ignore) { + c = AccessController.doPrivileged(new PrivilegedAction() { + public Console run() { + var consModName = System.getProperty("jdk.console", + JdkConsoleProvider.DEFAULT_PROVIDER_MODULE_NAME); + + for (var jcp : ServiceLoader.load(ModuleLayer.boot(), JdkConsoleProvider.class)) { + if (consModName.equals(jcp.getClass().getModule().getName())) { + var jc = jcp.console(istty, CHARSET); + if (jc != null) { + return new ProxyingConsole(jc); + } + break; + } + } + return null; + } + }); + } catch (ServiceConfigurationError _) { c = null; } From 6dac8d64527b4e9ade783b99f82fbecd81c426a6 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Mon, 3 Jun 2024 22:00:31 +0000 Subject: [PATCH 07/14] 8332424: Update IANA Language Subtag Registry to Version 2024-05-16 Reviewed-by: naoto, iris --- .../share/data/lsrdata/language-subtag-registry.txt | 8 +++++++- test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java | 4 ++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/data/lsrdata/language-subtag-registry.txt b/src/java.base/share/data/lsrdata/language-subtag-registry.txt index 4737c50e425c5..512134311e485 100644 --- a/src/java.base/share/data/lsrdata/language-subtag-registry.txt +++ b/src/java.base/share/data/lsrdata/language-subtag-registry.txt @@ -1,4 +1,4 @@ -File-Date: 2024-03-07 +File-Date: 2024-05-16 %% Type: language Subtag: aa @@ -9402,6 +9402,7 @@ Macrolanguage: doi %% Type: language Subtag: dgr +Description: Tlicho Description: Dogrib Description: Tłı̨chǫ Added: 2005-10-16 @@ -15255,6 +15256,11 @@ Description: Isu (Menchum Division) Added: 2009-07-29 %% Type: language +Subtag: isv +Description: Interslavic +Added: 2024-05-15 +%% +Type: language Subtag: itb Description: Binongan Itneg Added: 2009-07-29 diff --git a/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java b/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java index 04a6e89db7b59..184e007becd9d 100644 --- a/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java +++ b/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java @@ -25,9 +25,9 @@ * @test * @bug 8025703 8040211 8191404 8203872 8222980 8225435 8241082 8242010 8247432 * 8258795 8267038 8287180 8302512 8304761 8306031 8308021 8313702 8318322 - * 8327631 + * 8327631 8332424 * @summary Checks the IANA language subtag registry data update - * (LSR Revision: 2024-03-07) with Locale and Locale.LanguageRange + * (LSR Revision: 2024-05-16) with Locale and Locale.LanguageRange * class methods. * @run main LanguageSubtagRegistryTest */ From 1512011eaf24e056974d2d1485152ab3c8960743 Mon Sep 17 00:00:00 2001 From: Sonia Zaldana Calles Date: Tue, 4 Jun 2024 01:33:59 +0000 Subject: [PATCH 08/14] 8332123: [nmt] Move mallocLimit code to the nmt subdir Reviewed-by: dholmes, stuefe --- src/hotspot/share/{services => nmt}/mallocLimit.cpp | 2 +- src/hotspot/share/{services => nmt}/mallocLimit.hpp | 4 ++++ src/hotspot/share/nmt/mallocTracker.cpp | 6 +++--- src/hotspot/share/nmt/mallocTracker.inline.hpp | 4 ++-- src/hotspot/share/nmt/memTracker.cpp | 2 +- test/hotspot/gtest/nmt/test_nmt_malloclimit.cpp | 4 ++-- 6 files changed, 13 insertions(+), 9 deletions(-) rename src/hotspot/share/{services => nmt}/mallocLimit.cpp (99%) rename src/hotspot/share/{services => nmt}/mallocLimit.hpp (97%) diff --git a/src/hotspot/share/services/mallocLimit.cpp b/src/hotspot/share/nmt/mallocLimit.cpp similarity index 99% rename from src/hotspot/share/services/mallocLimit.cpp rename to src/hotspot/share/nmt/mallocLimit.cpp index de3e8e872eec7..746c3b9201bd9 100644 --- a/src/hotspot/share/services/mallocLimit.cpp +++ b/src/hotspot/share/nmt/mallocLimit.cpp @@ -24,11 +24,11 @@ */ #include "precompiled.hpp" +#include "nmt/mallocLimit.hpp" #include "nmt/memflags.hpp" #include "nmt/nmtCommon.hpp" #include "runtime/java.hpp" #include "runtime/globals.hpp" -#include "services/mallocLimit.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/parseInteger.hpp" #include "utilities/ostream.hpp" diff --git a/src/hotspot/share/services/mallocLimit.hpp b/src/hotspot/share/nmt/mallocLimit.hpp similarity index 97% rename from src/hotspot/share/services/mallocLimit.hpp rename to src/hotspot/share/nmt/mallocLimit.hpp index 281cfa513961a..2034e3ce24b77 100644 --- a/src/hotspot/share/services/mallocLimit.hpp +++ b/src/hotspot/share/nmt/mallocLimit.hpp @@ -26,6 +26,7 @@ #ifndef SHARE_SERVICES_MALLOCLIMIT_HPP #define SHARE_SERVICES_MALLOCLIMIT_HPP +#include "memory/allStatic.hpp" #include "nmt/memflags.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" @@ -40,6 +41,9 @@ struct malloclimit { MallocLimitMode mode; // Behavior flags }; +// forward declaration +class outputStream; + class MallocLimitSet { malloclimit _glob; // global limit malloclimit _cat[mt_number_of_types]; // per-category limit diff --git a/src/hotspot/share/nmt/mallocTracker.cpp b/src/hotspot/share/nmt/mallocTracker.cpp index 9b55202cbd5ac..ab323b3bae6db 100644 --- a/src/hotspot/share/nmt/mallocTracker.cpp +++ b/src/hotspot/share/nmt/mallocTracker.cpp @@ -1,7 +1,7 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, 2023 SAP SE. All rights reserved. - * Copyright (c) 2023, Red Hat, Inc. and/or its affiliates. + * Copyright (c) 2023, 2024, Red Hat, Inc. and/or its affiliates. * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -30,6 +30,7 @@ #include "logging/log.hpp" #include "logging/logStream.hpp" #include "nmt/mallocHeader.inline.hpp" +#include "nmt/mallocLimit.hpp" #include "nmt/mallocSiteTable.hpp" #include "nmt/mallocTracker.hpp" #include "nmt/memTracker.hpp" @@ -38,7 +39,6 @@ #include "runtime/globals.hpp" #include "runtime/os.hpp" #include "runtime/safefetch.hpp" -#include "services/mallocLimit.hpp" #include "utilities/debug.hpp" #include "utilities/macros.hpp" #include "utilities/ostream.hpp" diff --git a/src/hotspot/share/nmt/mallocTracker.inline.hpp b/src/hotspot/share/nmt/mallocTracker.inline.hpp index f226d56bc3d22..243f965a3829a 100644 --- a/src/hotspot/share/nmt/mallocTracker.inline.hpp +++ b/src/hotspot/share/nmt/mallocTracker.inline.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2023 SAP SE. All rights reserved. - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,8 +26,8 @@ #ifndef SHARE_NMT_MALLOCTRACKER_INLINE_HPP #define SHARE_NMT_MALLOCTRACKER_INLINE_HPP +#include "nmt/mallocLimit.hpp" #include "nmt/mallocTracker.hpp" -#include "services/mallocLimit.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" diff --git a/src/hotspot/share/nmt/memTracker.cpp b/src/hotspot/share/nmt/memTracker.cpp index 955bd816737b1..7c02ac8dbb2d8 100644 --- a/src/hotspot/share/nmt/memTracker.cpp +++ b/src/hotspot/share/nmt/memTracker.cpp @@ -27,6 +27,7 @@ #include "logging/log.hpp" #include "logging/logStream.hpp" #include "memory/metaspaceUtils.hpp" +#include "nmt/mallocLimit.hpp" #include "nmt/mallocTracker.hpp" #include "nmt/memBaseline.hpp" #include "nmt/memReporter.hpp" @@ -39,7 +40,6 @@ #include "runtime/orderAccess.hpp" #include "runtime/vmOperations.hpp" #include "runtime/vmThread.hpp" -#include "services/mallocLimit.hpp" #include "utilities/debug.hpp" #include "utilities/defaultStream.hpp" #include "utilities/vmError.hpp" diff --git a/test/hotspot/gtest/nmt/test_nmt_malloclimit.cpp b/test/hotspot/gtest/nmt/test_nmt_malloclimit.cpp index 003063144f3ab..7f6000b1212fb 100644 --- a/test/hotspot/gtest/nmt/test_nmt_malloclimit.cpp +++ b/test/hotspot/gtest/nmt/test_nmt_malloclimit.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2023 SAP SE. All rights reserved. - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,10 +24,10 @@ #include "precompiled.hpp" #include "memory/allocation.hpp" +#include "nmt/mallocLimit.hpp" #include "nmt/memTracker.hpp" #include "nmt/nmtCommon.hpp" #include "runtime/os.hpp" -#include "services/mallocLimit.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" From d230b30353f59135287436b09949b80e9fd73a93 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Tue, 4 Jun 2024 01:53:18 +0000 Subject: [PATCH 09/14] 8333398: Uncomment the commented test in test/jdk/java/util/jar/JarFile/mrjar/MultiReleaseJarAPI.java Reviewed-by: iris, lancea --- .../java/util/jar/JarFile/mrjar/MultiReleaseJarAPI.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/test/jdk/java/util/jar/JarFile/mrjar/MultiReleaseJarAPI.java b/test/jdk/java/util/jar/JarFile/mrjar/MultiReleaseJarAPI.java index 114816d4787c8..e8abec354ed16 100644 --- a/test/jdk/java/util/jar/JarFile/mrjar/MultiReleaseJarAPI.java +++ b/test/jdk/java/util/jar/JarFile/mrjar/MultiReleaseJarAPI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -101,15 +101,12 @@ public void isMultiReleaseJar() throws Exception { testCustomMultiReleaseValue("true", true); testCustomMultiReleaseValue("true\r\nOther: value", true); testCustomMultiReleaseValue("true\nOther: value", true); - // JDK-8200530: '\r' support in Manifest/Attributes will be addressed separately - // testCustomMultiReleaseValue("true\rOther: value", true); + testCustomMultiReleaseValue("true\rOther: value", true); testCustomMultiReleaseValue("false", false); testCustomMultiReleaseValue(" true", false); testCustomMultiReleaseValue("true ", false); testCustomMultiReleaseValue("true\n true", false); - - // JDK-8200530: '\r' support in Manifest/Attributes will be addressed separately testCustomMultiReleaseValue("true\r true", false); testCustomMultiReleaseValue("true\r\n true", false); From c7d2a5c1c4e86955100f4c40170dc25222abd07f Mon Sep 17 00:00:00 2001 From: Alexander Scherbatiy Date: Tue, 4 Jun 2024 03:12:40 +0000 Subject: [PATCH 10/14] 8314070: javax.print: Support IPP output-bin attribute extension Reviewed-by: psadhukhan, prr --- .../classes/sun/lwawt/macosx/CPrinterJob.java | 40 ++ .../native/libawt_lwawt/awt/CPrinterJob.m | 18 + .../print/attribute/standard/OutputBin.java | 201 ++++++++++ .../attribute/standard/package-info.java | 7 + .../classes/sun/print/CustomOutputBin.java | 108 +++++ .../share/classes/sun/print/PSPrinterJob.java | 16 +- .../classes/sun/print/RasterPrinterJob.java | 30 ++ .../classes/sun/print/ServiceDialog.java | 108 +++++ .../sun/print/resources/serviceui.properties | 2 + .../print/resources/serviceui_de.properties | 2 + .../print/resources/serviceui_es.properties | 2 + .../print/resources/serviceui_fr.properties | 2 + .../print/resources/serviceui_it.properties | 2 + .../print/resources/serviceui_ja.properties | 2 + .../print/resources/serviceui_ko.properties | 2 + .../resources/serviceui_pt_BR.properties | 2 + .../print/resources/serviceui_sv.properties | 2 + .../resources/serviceui_zh_CN.properties | 2 + .../resources/serviceui_zh_TW.properties | 2 + .../unix/classes/sun/print/CUPSPrinter.java | 24 ++ .../classes/sun/print/IPPPrintService.java | 59 +++ .../unix/native/common/awt/CUPSfuncs.c | 90 +++++ .../CheckSupportedOutputBinsTest.java | 116 ++++++ .../OutputBinAttributePrintDialogTest.java | 368 ++++++++++++++++++ .../attribute/OutputBinAttributeTest.java | 275 +++++++++++++ 25 files changed, 1479 insertions(+), 3 deletions(-) create mode 100644 src/java.desktop/share/classes/javax/print/attribute/standard/OutputBin.java create mode 100644 src/java.desktop/share/classes/sun/print/CustomOutputBin.java create mode 100644 test/jdk/javax/print/attribute/CheckSupportedOutputBinsTest.java create mode 100644 test/jdk/javax/print/attribute/OutputBinAttributePrintDialogTest.java create mode 100644 test/jdk/javax/print/attribute/OutputBinAttributeTest.java diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java index 407af09810c50..416a3ee002bbc 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java @@ -44,6 +44,7 @@ import javax.print.attribute.standard.MediaPrintableArea; import javax.print.attribute.standard.MediaSize; import javax.print.attribute.standard.MediaSizeName; +import javax.print.attribute.standard.OutputBin; import javax.print.attribute.standard.PageRanges; import javax.print.attribute.standard.Sides; import javax.print.attribute.Attribute; @@ -70,6 +71,8 @@ public final class CPrinterJob extends RasterPrinterJob { private String tray = null; + private String outputBin = null; + // This is the NSPrintInfo for this PrinterJob. Protect multi thread // access to it. It is used by the pageDialog, jobDialog, and printLoop. // This way the state of these items is shared across these calls. @@ -191,6 +194,8 @@ protected void setAttributes(PrintRequestAttributeSet attributes) throws Printer tray = customTray.getChoiceName(); } + outputBin = getOutputBinValue(attributes.get(OutputBin.class)); + PageRanges pageRangesAttr = (PageRanges)attributes.get(PageRanges.class); if (isSupportedValue(pageRangesAttr, attributes)) { SunPageSelection rangeSelect = (SunPageSelection)attributes.get(SunPageSelection.class); @@ -658,6 +663,41 @@ private String getPrinterTray() { return tray; } + private String getOutputBin() { + return outputBin; + } + + private void setOutputBin(String outputBinName) { + + OutputBin outputBin = toOutputBin(outputBinName); + if (outputBin != null) { + attributes.add(outputBin); + } + } + + private OutputBin toOutputBin(String outputBinName) { + + PrintService ps = getPrintService(); + if (ps == null) { + return null; + } + + OutputBin[] supportedBins = (OutputBin[]) ps.getSupportedAttributeValues(OutputBin.class, null, null); + if (supportedBins == null || supportedBins.length == 0) { + return null; + } + + for (OutputBin bin : supportedBins) { + if (bin instanceof CustomOutputBin customBin){ + if (customBin.getChoiceName().equals(outputBinName)) { + return customBin; + } + } + } + + return null; + } + private void setPrinterServiceFromNative(String printerName) { // This is called from the native side. PrintService[] services = PrintServiceLookup.lookupPrintServices(DocFlavor.SERVICE_FORMATTED.PAGEABLE, null); diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/CPrinterJob.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/CPrinterJob.m index 9cbd48bf843fb..f4794d40d315e 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/CPrinterJob.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/CPrinterJob.m @@ -383,6 +383,7 @@ static void nsPrintInfoToJavaPrinterJob(JNIEnv* env, NSPrintInfo* src, jobject d DECLARE_METHOD(jm_setPrintToFile, sjc_CPrinterJob, "setPrintToFile", "(Z)V"); DECLARE_METHOD(jm_setDestinationFile, sjc_CPrinterJob, "setDestinationFile", "(Ljava/lang/String;)V"); DECLARE_METHOD(jm_setSides, sjc_CPrinterJob, "setSides", "(I)V"); + DECLARE_METHOD(jm_setOutputBin, sjc_CPrinterJob, "setOutputBin", "(Ljava/lang/String;)V"); // get the selected printer's name, and set the appropriate PrintService on the Java side NSString *name = [[src printer] name]; @@ -449,6 +450,13 @@ static void nsPrintInfoToJavaPrinterJob(JNIEnv* env, NSPrintInfo* src, jobject d (*env)->CallVoidMethod(env, dstPrinterJob, jm_setSides, sides); // AWT_THREADING Safe (known object) CHECK_EXCEPTION(); } + + NSString* outputBin = [[src printSettings] objectForKey:@"OutputBin"]; + if (outputBin != nil) { + jstring outputBinName = NSStringToJavaString(env, outputBin); + (*env)->CallVoidMethod(env, dstPrinterJob, jm_setOutputBin, outputBinName); + CHECK_EXCEPTION(); + } } } @@ -468,6 +476,7 @@ static void javaPrinterJobToNSPrintInfo(JNIEnv* env, jobject srcPrinterJob, jobj DECLARE_METHOD(jm_getPageFormat, sjc_CPrinterJob, "getPageFormatFromAttributes", "()Ljava/awt/print/PageFormat;"); DECLARE_METHOD(jm_getDestinationFile, sjc_CPrinterJob, "getDestinationFile", "()Ljava/lang/String;"); DECLARE_METHOD(jm_getSides, sjc_CPrinterJob, "getSides", "()I"); + DECLARE_METHOD(jm_getOutputBin, sjc_CPrinterJob, "getOutputBin", "()Ljava/lang/String;"); NSMutableDictionary* printingDictionary = [dst dictionary]; @@ -538,6 +547,15 @@ static void javaPrinterJobToNSPrintInfo(JNIEnv* env, jobject srcPrinterJob, jobj [dst updateFromPMPrintSettings]; } } + + jobject outputBin = (*env)->CallObjectMethod(env, srcPrinterJob, jm_getOutputBin); + CHECK_EXCEPTION(); + if (outputBin != NULL) { + NSString *nsOutputBinStr = JavaStringToNSString(env, outputBin); + if (nsOutputBinStr != nil) { + [[dst printSettings] setObject:nsOutputBinStr forKey:@"OutputBin"]; + } + } } /* diff --git a/src/java.desktop/share/classes/javax/print/attribute/standard/OutputBin.java b/src/java.desktop/share/classes/javax/print/attribute/standard/OutputBin.java new file mode 100644 index 0000000000000..3f817fe6c9be2 --- /dev/null +++ b/src/java.desktop/share/classes/javax/print/attribute/standard/OutputBin.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, BELLSOFT. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package javax.print.attribute.standard; + +import java.io.Serial; + +import javax.print.attribute.Attribute; +import javax.print.attribute.DocAttribute; +import javax.print.attribute.EnumSyntax; +import javax.print.attribute.PrintJobAttribute; +import javax.print.attribute.PrintRequestAttribute; + +import sun.print.CustomOutputBin; + +/** + * Class {@code OutputBin} is a printing attribute class, an enumeration, that + * specifies the output bin for the job. + *

+ * Class {@code OutputBin} declares keywords for standard output bin kind values. + *

+ * IPP Compatibility: This attribute is not an IPP 1.1 attribute; it is + * an attribute in the "output-bin" attribute extension + * ( + * PDF) of IPP 1.1. The category name returned by {@code getName()} is the + * IPP attribute name. The enumeration's integer value is the IPP enum value. + * The {@code toString()} method returns the IPP string representation of the + * attribute value. + */ +public sealed class OutputBin extends EnumSyntax implements PrintRequestAttribute, PrintJobAttribute permits CustomOutputBin { + + @Serial + private static final long serialVersionUID = -3718893309873137109L; + + /** + * The top output bin in the printer. + */ + public static final OutputBin TOP = new OutputBin(0); + + /** + * The middle output bin in the printer. + */ + public static final OutputBin MIDDLE = new OutputBin(1); + + /** + * The bottom output bin in the printer. + */ + public static final OutputBin BOTTOM = new OutputBin(2); + + /** + * The side output bin in the printer. + */ + public static final OutputBin SIDE = new OutputBin(3); + + /** + * The left output bin in the printer. + */ + public static final OutputBin LEFT = new OutputBin(4); + + /** + * The right output bin in the printer. + */ + public static final OutputBin RIGHT = new OutputBin(5); + + /** + * The center output bin in the printer. + */ + public static final OutputBin CENTER = new OutputBin(6); + + /** + * The rear output bin in the printer. + */ + public static final OutputBin REAR = new OutputBin(7); + + /** + * The face up output bin in the printer. + */ + public static final OutputBin FACE_UP = new OutputBin(8); + + /** + * The face down output bin in the printer. + */ + public static final OutputBin FACE_DOWN = new OutputBin(9); + + /** + * The large-capacity output bin in the printer. + */ + public static final OutputBin LARGE_CAPACITY = new OutputBin(10); + + /** + * Construct a new output bin enumeration value with the given integer + * value. + * + * @param value Integer value + */ + protected OutputBin(int value) { + super(value); + } + + /** + * The string table for class {@code OutputBin}. + */ + private static final String[] myStringTable = { + "top", + "middle", + "bottom", + "side", + "left", + "right", + "center", + "rear", + "face-up", + "face-down", + "large-capacity", + }; + + /** + * The enumeration value table for class {@code OutputBin}. + */ + private static final OutputBin[] myEnumValueTable = { + TOP, + MIDDLE, + BOTTOM, + SIDE, + LEFT, + RIGHT, + CENTER, + REAR, + FACE_UP, + FACE_DOWN, + LARGE_CAPACITY, + }; + + /** + * Returns the string table for class {@code OutputBin}. + */ + @Override + protected String[] getStringTable() { + return myStringTable.clone(); + } + + /** + * Returns the enumeration value table for class {@code OutputBin}. + */ + @Override + protected EnumSyntax[] getEnumValueTable() { + return (EnumSyntax[]) myEnumValueTable.clone(); + } + + /** + * Get the printing attribute class which is to be used as the "category" + * for this printing attribute value. + *

+ * For class {@code OutputBin} and any vendor-defined subclasses, the category + * is class {@code OutputBin} itself. + * + * @return printing attribute class (category), an instance of class + * {@link Class java.lang.Class} + */ + @Override + public final Class getCategory() { + return OutputBin.class; + } + + /** + * Get the name of the category of which this attribute value is an + * instance. + *

+ * For class {@code OutputBin} and any vendor-defined subclasses, the category + * name is {@code "output-bin"}. + * + * @return attribute category name + */ + @Override + public final String getName() { + return "output-bin"; + } +} diff --git a/src/java.desktop/share/classes/javax/print/attribute/standard/package-info.java b/src/java.desktop/share/classes/javax/print/attribute/standard/package-info.java index 31f4b17366cf6..08badfdb4920d 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/standard/package-info.java +++ b/src/java.desktop/share/classes/javax/print/attribute/standard/package-info.java @@ -335,6 +335,13 @@ *   *   * + * OutputBin + *   + * X + * X + *   + *   + * * * DateTimeAtCompleted *   diff --git a/src/java.desktop/share/classes/sun/print/CustomOutputBin.java b/src/java.desktop/share/classes/sun/print/CustomOutputBin.java new file mode 100644 index 0000000000000..71c63c9157029 --- /dev/null +++ b/src/java.desktop/share/classes/sun/print/CustomOutputBin.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, BELLSOFT. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.print; + +import java.io.Serial; +import java.util.ArrayList; + +import javax.print.attribute.EnumSyntax; +import javax.print.attribute.standard.Media; +import javax.print.attribute.standard.OutputBin; + +public final class CustomOutputBin extends OutputBin { + private static ArrayList customStringTable = new ArrayList<>(); + private static ArrayList customEnumTable = new ArrayList<>(); + private String choiceName; + + private CustomOutputBin(int x) { + super(x); + } + + private static synchronized int nextValue(String name) { + customStringTable.add(name); + return (customStringTable.size()-1); + } + + private CustomOutputBin(String name, String choice) { + super(nextValue(name)); + choiceName = choice; + customEnumTable.add(this); + } + + /** + * Creates a custom output bin + */ + public static synchronized CustomOutputBin createOutputBin(String name, String choice) { + for (CustomOutputBin bin : customEnumTable) { + if (bin.getChoiceName().equals(choice) && bin.getCustomName().equals(name)) { + return bin; + } + } + return new CustomOutputBin(name, choice); + } + + private static final long serialVersionUID = 3018751086294120717L; + + /** + * Returns the command string for this media tray. + */ + public String getChoiceName() { + return choiceName; + } + + /** + * Returns the string table for super class MediaTray. + */ + public OutputBin[] getSuperEnumTable() { + return (OutputBin[])super.getEnumValueTable(); + } + + /** + * Returns the string table for class CustomOutputBin. + */ + @Override + protected String[] getStringTable() { + String[] nameTable = new String[customStringTable.size()]; + return customStringTable.toArray(nameTable); + } + + /** + * Returns a custom bin name + */ + public String getCustomName() { + return customStringTable.get(getValue() - getOffset()); + } + + /** + * Returns the enumeration value table for class CustomOutputBin. + */ + @Override + protected CustomOutputBin[] getEnumValueTable() { + CustomOutputBin[] enumTable = new CustomOutputBin[customEnumTable.size()]; + return customEnumTable.toArray(enumTable); + } +} diff --git a/src/java.desktop/share/classes/sun/print/PSPrinterJob.java b/src/java.desktop/share/classes/sun/print/PSPrinterJob.java index 8973467fb9771..e64fb2cb0d501 100644 --- a/src/java.desktop/share/classes/sun/print/PSPrinterJob.java +++ b/src/java.desktop/share/classes/sun/print/PSPrinterJob.java @@ -61,6 +61,7 @@ import javax.print.attribute.standard.Destination; import javax.print.attribute.standard.DialogTypeSelection; import javax.print.attribute.standard.JobName; +import javax.print.attribute.standard.OutputBin; import javax.print.attribute.standard.Sides; import java.io.BufferedOutputStream; @@ -491,14 +492,19 @@ protected void setAttributes(PrintRequestAttributeSet attributes) if (attributes == null) { return; // now always use attributes, so this shouldn't happen. } + mOptions = ""; Attribute attr = attributes.get(Media.class); if (attr instanceof CustomMediaTray) { CustomMediaTray customTray = (CustomMediaTray)attr; String choice = customTray.getChoiceName(); if (choice != null) { - mOptions = " InputSlot="+ choice; + mOptions += " InputSlot="+ choice; } } + String outputBin = getOutputBinValue(outputBinAttr); + if (outputBin != null) { + mOptions += " output-bin=" + outputBin; + } } /** @@ -1643,7 +1649,9 @@ private String[] printExecCmd(String printer, String options, execCmd[n++] = "-o job-sheets=standard"; } if ((pFlags & OPTIONS) != 0) { - execCmd[n++] = "-o" + options; + for (String option : options.trim().split(" ")) { + execCmd[n++] = "-o " + option; + } } } else { ncomps+=1; //add 1 arg for lp @@ -1666,7 +1674,9 @@ private String[] printExecCmd(String printer, String options, execCmd[n++] = "-o job-sheets=standard"; } if ((pFlags & OPTIONS) != 0) { - execCmd[n++] = "-o" + options; + for (String option : options.trim().split(" ")) { + execCmd[n++] = "-o " + option; + } } } execCmd[n++] = spoolFile; diff --git a/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java b/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java index fc47c25806c65..0dfa5e42d9a89 100644 --- a/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java +++ b/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java @@ -81,6 +81,7 @@ import javax.print.attribute.standard.MediaSize; import javax.print.attribute.standard.MediaSizeName; import javax.print.attribute.standard.OrientationRequested; +import javax.print.attribute.standard.OutputBin; import javax.print.attribute.standard.PageRanges; import javax.print.attribute.standard.PrinterResolution; import javax.print.attribute.standard.PrinterState; @@ -279,6 +280,7 @@ public abstract class RasterPrinterJob extends PrinterJob { private PageRanges pageRangesAttr; protected PrinterResolution printerResAttr; protected Sides sidesAttr; + protected OutputBin outputBinAttr; protected String destinationAttr; protected boolean noJobSheet = false; protected int mDestType = RasterPrinterJob.FILE; @@ -1228,6 +1230,7 @@ protected void setAttributes(PrintRequestAttributeSet attributes) /* reset all values to defaults */ setCollated(false); sidesAttr = null; + outputBinAttr = null; printerResAttr = null; pageRangesAttr = null; copiesAttr = 0; @@ -1274,6 +1277,11 @@ protected void setAttributes(PrintRequestAttributeSet attributes) sidesAttr = Sides.ONE_SIDED; } + outputBinAttr = (OutputBin)attributes.get(OutputBin.class); + if (!isSupportedValue(outputBinAttr, attributes)) { + outputBinAttr = null; + } + printerResAttr = (PrinterResolution)attributes.get(PrinterResolution.class); if (service.isAttributeCategorySupported(PrinterResolution.class)) { if (!isSupportedValue(printerResAttr, attributes)) { @@ -2617,4 +2625,26 @@ private void setParentWindowID(PrintRequestAttributeSet attrs) { parentWindowID = DialogOwnerAccessor.getID(onTop); } } + + protected String getOutputBinValue(Attribute attr) { + if (attr instanceof CustomOutputBin customOutputBin) { + return customOutputBin.getChoiceName(); + } else if (attr instanceof OutputBin) { + PrintService ps = getPrintService(); + if (ps == null) { + return null; + } + String name = attr.toString(); + OutputBin[] outputBins = (OutputBin[]) ps + .getSupportedAttributeValues(OutputBin.class, null, null); + for (OutputBin outputBin : outputBins) { + String choice = ((CustomOutputBin) outputBin).getChoiceName(); + if (name.equalsIgnoreCase(choice) || name.replaceAll("-", "").equalsIgnoreCase(choice)) { + return choice; + } + } + return null; + } + return null; + } } diff --git a/src/java.desktop/share/classes/sun/print/ServiceDialog.java b/src/java.desktop/share/classes/sun/print/ServiceDialog.java index 7167ba1884f16..6f2bdecb8099a 100644 --- a/src/java.desktop/share/classes/sun/print/ServiceDialog.java +++ b/src/java.desktop/share/classes/sun/print/ServiceDialog.java @@ -69,6 +69,7 @@ import java.net.URISyntaxException; import java.lang.reflect.Field; import java.net.MalformedURLException; +import sun.awt.OSInfo; /** * A class which implements a cross-platform print dialog. @@ -2300,6 +2301,7 @@ private class AppearancePanel extends JPanel { private QualityPanel pnlQuality; private JobAttributesPanel pnlJobAttributes; private SidesPanel pnlSides; + private OutputPanel pnlOutput; public AppearancePanel() { super(); @@ -2330,6 +2332,11 @@ public AppearancePanel() { pnlJobAttributes = new JobAttributesPanel(); addToGB(pnlJobAttributes, this, gridbag, c); + if (OSInfo.getOSType() != OSInfo.OSType.WINDOWS) { + c.gridwidth = GridBagConstraints.REMAINDER; + pnlOutput = new OutputPanel(); + addToGB(pnlOutput, this, gridbag, c); + } } public void updateInfo() { @@ -2337,6 +2344,9 @@ public void updateInfo() { pnlQuality.updateInfo(); pnlSides.updateInfo(); pnlJobAttributes.updateInfo(); + if (pnlOutput != null) { + pnlOutput.updateInfo(); + } } } @@ -2818,8 +2828,106 @@ public void updateInfo() { } } + @SuppressWarnings("serial") // Superclass is not serializable across versions + private class OutputPanel extends JPanel implements ItemListener { + + private final String strTitle = getMsg("border.output"); + private JLabel lblOutput; + private JComboBox cbOutput; + private Vector outputs = new Vector<>(); + + public OutputPanel() { + super(); + + GridBagLayout gridbag = new GridBagLayout(); + GridBagConstraints c = new GridBagConstraints(); + setLayout(gridbag); + setBorder(BorderFactory.createTitledBorder(strTitle)); + cbOutput = new JComboBox<>(); + + c.fill = GridBagConstraints.BOTH; + c.insets = compInsets; + c.weighty = 1.0; + + c.weightx = 0.0; + lblOutput = new JLabel(getMsg("label.outputbins"), JLabel.TRAILING); + lblOutput.setDisplayedMnemonic(getMnemonic("label.outputbins")); + lblOutput.setLabelFor(cbOutput); + addToGB(lblOutput, this, gridbag, c); + c.weightx = 1.0; + c.gridwidth = GridBagConstraints.REMAINDER; + addToGB(cbOutput, this, gridbag, c); + } + + public void itemStateChanged(ItemEvent e) { + + Object source = e.getSource(); + if (e.getStateChange() == ItemEvent.SELECTED) { + if (source == cbOutput) { + int index = cbOutput.getSelectedIndex(); + if ((index >= 0) && (index < outputs.size())) { + asCurrent.add(outputs.get(index)); + } else if (index == cbOutput.getItemCount() - 1) { + asCurrent.remove(OutputBin.class); + } + } + } + } + + public void updateInfo() { + + Class obCategory = OutputBin.class; + + cbOutput.removeItemListener(this); + cbOutput.removeAllItems(); + + outputs.clear(); + + boolean outputEnabled = false; + + if (psCurrent.isAttributeCategorySupported(obCategory)) { + + Object values = + psCurrent.getSupportedAttributeValues(obCategory, + docFlavor, + asCurrent); + + if (values instanceof OutputBin[]) { + OutputBin[] outputBins = (OutputBin[])values; + + for (OutputBin outputBin: outputBins) { + outputs.add(outputBin); + cbOutput.addItem(outputBin.toString()); + } + + cbOutput.addItem(""); + cbOutput.setSelectedIndex(cbOutput.getItemCount() - 1); + + OutputBin current = (OutputBin) asCurrent.get(obCategory); + if (current != null) { + for (int i = 0; i < outputs.size(); i++) { + if (current.equals(outputs.get(i))) { + cbOutput.setSelectedIndex(i); + break; + } + } + } else if (outputBins.length == 1) { + cbOutput.setSelectedIndex(0); + } + + outputEnabled = outputBins.length > 1; + } + } + + cbOutput.setEnabled(outputEnabled); + lblOutput.setEnabled(outputEnabled); + if (outputEnabled) { + cbOutput.addItemListener(this); + } + } + } /** * A special widget that groups a JRadioButton with an associated icon, diff --git a/src/java.desktop/share/classes/sun/print/resources/serviceui.properties b/src/java.desktop/share/classes/sun/print/resources/serviceui.properties index 7b7027239b85e..39fd3cd8d8ecc 100644 --- a/src/java.desktop/share/classes/sun/print/resources/serviceui.properties +++ b/src/java.desktop/share/classes/sun/print/resources/serviceui.properties @@ -29,6 +29,7 @@ border.chromaticity=Color Appearance border.copies=Copies border.jobattributes=Job Attributes border.media=Media +border.output=Output border.orientation=Orientation border.printrange=Print Range border.printservice=Print Service @@ -62,6 +63,7 @@ label.pstype=Type: label.rangeto=To label.size=Si&ze: label.source=Sour&ce: +label.outputbins=Out&put trays: label.status=Status: label.username=&User Name: label.millimetres=(mm) diff --git a/src/java.desktop/share/classes/sun/print/resources/serviceui_de.properties b/src/java.desktop/share/classes/sun/print/resources/serviceui_de.properties index 72e73ad473585..a50c78d060dbc 100644 --- a/src/java.desktop/share/classes/sun/print/resources/serviceui_de.properties +++ b/src/java.desktop/share/classes/sun/print/resources/serviceui_de.properties @@ -29,6 +29,7 @@ border.chromaticity=Farbdarstellung border.copies=Kopien border.jobattributes=Jobattribute border.media=Medien +border.output=Ausgabe border.orientation=Ausrichtung border.printrange=Druckbereich border.printservice=Druckservice @@ -62,6 +63,7 @@ label.pstype=Typ: label.rangeto=Bis label.size=G&röße: label.source=&Quelle: +label.outputbins=A&usgabefächer: label.status=Status: label.username=&Benutzername: label.millimetres=(mm) diff --git a/src/java.desktop/share/classes/sun/print/resources/serviceui_es.properties b/src/java.desktop/share/classes/sun/print/resources/serviceui_es.properties index 0b22979016512..170e7b0b91f74 100644 --- a/src/java.desktop/share/classes/sun/print/resources/serviceui_es.properties +++ b/src/java.desktop/share/classes/sun/print/resources/serviceui_es.properties @@ -29,6 +29,7 @@ border.chromaticity=Apariencia del Color border.copies=Copias border.jobattributes=Atributos del Trabajo border.media=Soporte +border.output=Salida border.orientation=Orientación border.printrange=Rango de Impresión border.printservice=Servicio de Impresión @@ -62,6 +63,7 @@ label.pstype=Tipo: label.rangeto=A label.size=Tama&ño: label.source=Orig&en: +label.outputbins=Band&ejas de salida: label.status=Estado: label.username=&Usuario: label.millimetres=(mm) diff --git a/src/java.desktop/share/classes/sun/print/resources/serviceui_fr.properties b/src/java.desktop/share/classes/sun/print/resources/serviceui_fr.properties index 3a77589e8b36f..8222bf21e8d82 100644 --- a/src/java.desktop/share/classes/sun/print/resources/serviceui_fr.properties +++ b/src/java.desktop/share/classes/sun/print/resources/serviceui_fr.properties @@ -29,6 +29,7 @@ border.chromaticity=Couleur border.copies=Copies border.jobattributes=Attributs de tâche border.media=Support +border.output=Sortir border.orientation=Orientation border.printrange=Plage d'impression border.printservice=Service d'impression @@ -62,6 +63,7 @@ label.pstype=Type : label.rangeto=A label.size=Tai&lle : label.source=Sour&ce : +label.outputbins=Bacs de s&ortie : label.status=Statut : label.username=Nom ut&ilisateur : label.millimetres=(mm) diff --git a/src/java.desktop/share/classes/sun/print/resources/serviceui_it.properties b/src/java.desktop/share/classes/sun/print/resources/serviceui_it.properties index 2f029b7bfc9c0..bac068e46ac93 100644 --- a/src/java.desktop/share/classes/sun/print/resources/serviceui_it.properties +++ b/src/java.desktop/share/classes/sun/print/resources/serviceui_it.properties @@ -29,6 +29,7 @@ border.chromaticity=Aspetto colore border.copies=Copie border.jobattributes=Attributi job border.media=Supporti +border.output=Output border.orientation=Orientamento border.printrange=Intervallo di stampa border.printservice=Servizio di stampa @@ -62,6 +63,7 @@ label.pstype=Tipo: label.rangeto=A label.size=Di&mensioni: label.source=O&rigine: +label.outputbins=&Vassoi di uscita: label.status=Stato: label.username=Nome &utente: label.millimetres=(mm) diff --git a/src/java.desktop/share/classes/sun/print/resources/serviceui_ja.properties b/src/java.desktop/share/classes/sun/print/resources/serviceui_ja.properties index 889df23016160..ee8e591d15a7e 100644 --- a/src/java.desktop/share/classes/sun/print/resources/serviceui_ja.properties +++ b/src/java.desktop/share/classes/sun/print/resources/serviceui_ja.properties @@ -29,6 +29,7 @@ border.chromaticity=色の表現 border.copies=印刷部数 border.jobattributes=ジョブの属性 border.media=メディア +border.output=出力 border.orientation=用紙の向き border.printrange=印刷範囲 border.printservice=印刷サービス @@ -62,6 +63,7 @@ label.pstype=タイプ: label.rangeto=印刷範囲 label.size=サイズ(&Z): label.source=ソース(&C): +label.outputbins=出力トレイ(&P): label.status=状態: label.username=ユーザー名(&U): label.millimetres=(mm) diff --git a/src/java.desktop/share/classes/sun/print/resources/serviceui_ko.properties b/src/java.desktop/share/classes/sun/print/resources/serviceui_ko.properties index 61d38f5295337..d737b987db1a1 100644 --- a/src/java.desktop/share/classes/sun/print/resources/serviceui_ko.properties +++ b/src/java.desktop/share/classes/sun/print/resources/serviceui_ko.properties @@ -29,6 +29,7 @@ border.chromaticity=색상 모양 border.copies=복사 border.jobattributes=작업 속성 border.media=매체 +border.output=출력물 border.orientation=방향 border.printrange=인쇄 범위 border.printservice=인쇄 서비스 @@ -62,6 +63,7 @@ label.pstype=유형: label.rangeto=종료 label.size=크기(&Z): label.source=소스(&C): +label.outputbins=출력 트레이(&P): label.status=상태: label.username=사용자 이름(&U): label.millimetres=(mm) diff --git a/src/java.desktop/share/classes/sun/print/resources/serviceui_pt_BR.properties b/src/java.desktop/share/classes/sun/print/resources/serviceui_pt_BR.properties index 0617aa2e005dd..5f157b9f5f7ad 100644 --- a/src/java.desktop/share/classes/sun/print/resources/serviceui_pt_BR.properties +++ b/src/java.desktop/share/classes/sun/print/resources/serviceui_pt_BR.properties @@ -29,6 +29,7 @@ border.chromaticity=Aparência da Cor border.copies=Cópias border.jobattributes=Atributos do Job border.media=Mídia +border.output=Saída border.orientation=Orientação border.printrange=Faixa de Impressão border.printservice=Serviço de Impressão @@ -62,6 +63,7 @@ label.pstype=Tipo: label.rangeto=Até label.size=Ta&manho: label.source=&Origem: +label.outputbins=Bande&jas de saída: label.status=Status: label.username=Nome do &Usuário: label.millimetres=(mm) diff --git a/src/java.desktop/share/classes/sun/print/resources/serviceui_sv.properties b/src/java.desktop/share/classes/sun/print/resources/serviceui_sv.properties index eac40fa6744db..8d84d54dc28e7 100644 --- a/src/java.desktop/share/classes/sun/print/resources/serviceui_sv.properties +++ b/src/java.desktop/share/classes/sun/print/resources/serviceui_sv.properties @@ -29,6 +29,7 @@ border.chromaticity=Färg border.copies=Antal exemplar border.jobattributes=Utskriftsattribut border.media=Media +border.output=Utmatning border.orientation=Orientering border.printrange=Utskriftsintervall border.printservice=Utskriftstjänst @@ -62,6 +63,7 @@ label.pstype=Typ: label.rangeto=Till label.size=Stor&lek: label.source=&Källa: +label.outputbins=Utma&tningsfack: label.status=Status: label.username=A&nvändarnamn: label.millimetres=(mm) diff --git a/src/java.desktop/share/classes/sun/print/resources/serviceui_zh_CN.properties b/src/java.desktop/share/classes/sun/print/resources/serviceui_zh_CN.properties index 598441e24d937..f4a1982f05638 100644 --- a/src/java.desktop/share/classes/sun/print/resources/serviceui_zh_CN.properties +++ b/src/java.desktop/share/classes/sun/print/resources/serviceui_zh_CN.properties @@ -29,6 +29,7 @@ border.chromaticity=颜色外观 border.copies=份数 border.jobattributes=作业属性 border.media=介质 +border.output=出纸 border.orientation=方向 border.printrange=打印区域 border.printservice=打印服务 @@ -62,6 +63,7 @@ label.pstype=类型: label.rangeto=至 label.size=大小(&Z): label.source=来源(&C): +label.outputbins=出纸托盘(&P): label.status=状态: label.username=用户名(&U): label.millimetres=(毫米) diff --git a/src/java.desktop/share/classes/sun/print/resources/serviceui_zh_TW.properties b/src/java.desktop/share/classes/sun/print/resources/serviceui_zh_TW.properties index 845122a0eb2b4..de600e74ec60f 100644 --- a/src/java.desktop/share/classes/sun/print/resources/serviceui_zh_TW.properties +++ b/src/java.desktop/share/classes/sun/print/resources/serviceui_zh_TW.properties @@ -29,6 +29,7 @@ border.chromaticity=色彩外觀 border.copies=份數 border.jobattributes=工作屬性 border.media=媒體 +border.output=出紙 border.orientation=方向 border.printrange=列印範圍 border.printservice=列印服務 @@ -62,6 +63,7 @@ label.pstype=類型: label.rangeto=至 label.size=大小(&Z): label.source=來源(&C): +label.outputbins=输出纸盒(&P): label.status=狀態: label.username=使用者名稱(&U): label.millimetres=(mm) diff --git a/src/java.desktop/unix/classes/sun/print/CUPSPrinter.java b/src/java.desktop/unix/classes/sun/print/CUPSPrinter.java index 6c75949731d05..4d2a4d616aa41 100644 --- a/src/java.desktop/unix/classes/sun/print/CUPSPrinter.java +++ b/src/java.desktop/unix/classes/sun/print/CUPSPrinter.java @@ -34,11 +34,13 @@ import sun.print.IPPPrintService; import sun.print.CustomMediaSizeName; import sun.print.CustomMediaTray; +import sun.print.CustomOutputBin; import javax.print.attribute.standard.Media; import javax.print.attribute.standard.MediaSizeName; import javax.print.attribute.standard.MediaSize; import javax.print.attribute.standard.MediaTray; import javax.print.attribute.standard.MediaPrintableArea; +import javax.print.attribute.standard.OutputBin; import javax.print.attribute.standard.PrinterResolution; import javax.print.attribute.Size2DSyntax; import javax.print.attribute.Attribute; @@ -60,6 +62,7 @@ public class CUPSPrinter { // CUPS does not support multi-threading. private static synchronized native String[] getMedia(String printer); private static synchronized native float[] getPageSizes(String printer); + private static synchronized native String[] getOutputBins(String printer); private static synchronized native void getResolutions(String printer, ArrayList resolutionList); //public static boolean useIPPMedia = false; will be used later @@ -68,10 +71,12 @@ public class CUPSPrinter { private MediaSizeName[] cupsMediaSNames; private CustomMediaSizeName[] cupsCustomMediaSNames; private MediaTray[] cupsMediaTrays; + private OutputBin[] cupsOutputBins; public int nPageSizes = 0; public int nTrays = 0; private String[] media; + private String[] outputBins; private float[] pageSizes; int[] resolutionsArray; private String printer; @@ -144,6 +149,8 @@ public Void run() { for (int i=0; i < resolutionList.size(); i++) { resolutionsArray[i] = resolutionList.get(i); } + + outputBins = getOutputBins(printer); } } @@ -185,6 +192,14 @@ MediaTray[] getMediaTrays() { return cupsMediaTrays; } + /** + * Returns array of OutputBins derived from PPD. + */ + OutputBin[] getOutputBins() { + initMedia(); + return cupsOutputBins; + } + /** * return the raw packed array of supported printer resolutions. */ @@ -261,6 +276,15 @@ private synchronized void initMedia() { cupsMediaTrays[i] = mt; } + if (outputBins == null) { + cupsOutputBins = new OutputBin[0]; + } else { + int nBins = outputBins.length / 2; + cupsOutputBins = new OutputBin[nBins]; + for (int i = 0; i < nBins; i++) { + cupsOutputBins[i] = CustomOutputBin.createOutputBin(outputBins[i*2], outputBins[i*2+1]); + } + } } /** diff --git a/src/java.desktop/unix/classes/sun/print/IPPPrintService.java b/src/java.desktop/unix/classes/sun/print/IPPPrintService.java index 25123045f51a7..5a6437014ddc3 100644 --- a/src/java.desktop/unix/classes/sun/print/IPPPrintService.java +++ b/src/java.desktop/unix/classes/sun/print/IPPPrintService.java @@ -80,6 +80,7 @@ import javax.print.attribute.standard.MediaTray; import javax.print.attribute.standard.NumberUp; import javax.print.attribute.standard.OrientationRequested; +import javax.print.attribute.standard.OutputBin; import javax.print.attribute.standard.PDLOverrideSupported; import javax.print.attribute.standard.PageRanges; import javax.print.attribute.standard.PagesPerMinute; @@ -138,6 +139,7 @@ protected static void debug_println(String str) { private DocFlavor[] supportedDocFlavors; private Class[] supportedCats; private MediaTray[] mediaTrays; + private OutputBin[] outputBins; private MediaSizeName[] mediaSizeNames; private CustomMediaSizeName[] customMediaSizeNames; private int defaultMediaIndex; @@ -211,6 +213,7 @@ protected static void debug_println(String str) { new RequestingUserName("", Locale.getDefault()), //SheetCollate.UNCOLLATED, //CUPS has no sheet collate? Sides.ONE_SIDED, + OutputBin.TOP, }; @@ -440,6 +443,7 @@ private void initAttributes() { if ((urlConnection = getIPPConnection(myURL)) == null) { mediaSizeNames = new MediaSizeName[0]; mediaTrays = new MediaTray[0]; + outputBins = new OutputBin[0]; debug_println(debugPrefix+"initAttributes, NULL urlConnection "); init = true; return; @@ -460,6 +464,9 @@ private void initAttributes() { cps = new CUPSPrinter(printer); mediaSizeNames = cps.getMediaSizeNames(); mediaTrays = cps.getMediaTrays(); + outputBins = PrintServiceLookupProvider.isMac() + ? cps.getOutputBins() + : getSupportedOutputBins(); customMediaSizeNames = cps.getCustomMediaSizeNames(); defaultMediaIndex = cps.getDefaultMediaIndex(); rawResolutions = cps.getRawResolutions(); @@ -493,6 +500,11 @@ private void initAttributes() { mediaTrays = new MediaTray[trayList.size()]; mediaTrays = trayList.toArray(mediaTrays); } + + if (outputBins == null) { + outputBins = getSupportedOutputBins(); + } + urlConnection.disconnect(); init = true; @@ -827,6 +839,8 @@ public DocPrintJob createPrintJob() { new PrinterResolution[supportedRes.length]; System.arraycopy(supportedRes, 0, arr, 0, supportedRes.length); return arr; + } else if (category == OutputBin.class) { + return Arrays.copyOf(outputBins, outputBins.length); } return null; @@ -1053,6 +1067,25 @@ private Media[] getSupportedMedia() { return new Media[0]; } + private OutputBin[] getSupportedOutputBins() { + if ((getAttMap != null) && getAttMap.containsKey("output-bin-supported")) { + + AttributeClass attribClass = getAttMap.get("output-bin-supported"); + + if (attribClass != null) { + String[] values = attribClass.getArrayOfStringValues(); + if (values == null || values.length == 0) { + return null; + } + OutputBin[] outputBinNames = new OutputBin[values.length]; + for (int i = 0; i < values.length; i++) { + outputBinNames[i] = CustomOutputBin.createOutputBin(values[i], values[i]); + } + return outputBinNames; + } + } + return null; + } public synchronized Class[] getSupportedAttributeCategories() { if (supportedCats != null) { @@ -1070,6 +1103,11 @@ public synchronized Class[] getSupportedAttributeCategories() { (PrintRequestAttribute)printReqAttribDefault[i]; if (getAttMap != null && getAttMap.containsKey(pra.getName()+"-supported")) { + + if (pra == OutputBin.TOP && (outputBins == null || outputBins.length == 0)) { + continue; + } + catList.add(pra.getCategory()); } } @@ -1148,6 +1186,11 @@ public synchronized Class[] getSupportedAttributeCategories() { return true; } + if (category == OutputBin.class + && (outputBins == null || outputBins.length == 0)) { + return false; + } + for (int i=0;iGetStringUTFChars(env, printer, NULL); + if (name == NULL) { + (*env)->ExceptionClear(env); + JNU_ThrowOutOfMemoryError(env, "Could not create printer name"); + return NULL; + } + + // NOTE: cupsGetPPD returns a pointer to a filename of a temporary file. + // unlink() must be caled to remove the file when finished using it. + filename = j2d_cupsGetPPD(name); + (*env)->ReleaseStringUTFChars(env, printer, name); + CHECK_NULL_RETURN(filename, NULL); + + cls = (*env)->FindClass(env, "java/lang/String"); + CHECK_NULL_RETURN(cls, NULL); + + if ((ppd = j2d_ppdOpenFile(filename)) == NULL) { + unlink(filename); + DPRINTF("CUPSfuncs::unable to open PPD %s\n", filename); + return NULL; + } + + outputBin = j2d_ppdFindOption(ppd, "OutputBin"); + if (outputBin != NULL) { + nBins = outputBin->num_choices; + } + + if (nBins > 0) { + nameArray = (*env)->NewObjectArray(env, nBins * 2, cls, NULL); + if (nameArray == NULL) { + unlink(filename); + j2d_ppdClose(ppd); + DPRINTF("CUPSfuncs::bad alloc new array\n", "") + if (!(*env)->ExceptionCheck(env)) { + JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); + } + return NULL; + } + + for (i = 0; outputBin!=NULL && ichoices)+i; + utf_str = JNU_NewStringPlatform(env, choice->text); + if (utf_str == NULL) { + unlink(filename); + j2d_ppdClose(ppd); + DPRINTF("CUPSfuncs::bad alloc new string text\n", "") + if (!(*env)->ExceptionCheck(env)) { + JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); + } + return NULL; + } + (*env)->SetObjectArrayElement(env, nameArray, i*2, utf_str); + (*env)->DeleteLocalRef(env, utf_str); + utf_str = JNU_NewStringPlatform(env, choice->choice); + if (utf_str == NULL) { + unlink(filename); + j2d_ppdClose(ppd); + DPRINTF("CUPSfuncs::bad alloc new string choice\n", "") + if (!(*env)->ExceptionCheck(env)) { + JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); + } + return NULL; + } + (*env)->SetObjectArrayElement(env, nameArray, i*2+1, utf_str); + (*env)->DeleteLocalRef(env, utf_str); + } + } + + j2d_ppdClose(ppd); + unlink(filename); + return nameArray; +} /* * Returns list of page sizes and imageable area. diff --git a/test/jdk/javax/print/attribute/CheckSupportedOutputBinsTest.java b/test/jdk/javax/print/attribute/CheckSupportedOutputBinsTest.java new file mode 100644 index 0000000000000..67f370aeed3c9 --- /dev/null +++ b/test/jdk/javax/print/attribute/CheckSupportedOutputBinsTest.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, BELLSOFT. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.Arrays; +import java.util.Set; + +import javax.print.PrintService; +import javax.print.PrintServiceLookup; +import javax.print.attribute.Attribute; +import javax.print.attribute.standard.OutputBin; + +/* + * @test + * @bug 8314070 + * @key printer + * @summary javax.print: Support IPP output-bin attribute extension + */ + +public class CheckSupportedOutputBinsTest { + + public static void main(String[] args) throws Exception { + + PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null); + + if (services == null) { + System.out.printf("Skip the test as there are no available PrintServices.%n"); + return; + } + + System.out.printf("Print services: %d%n", services.length); + + for (PrintService service : services) { + checkSupportedOutputBins(service); + } + } + + private static void checkSupportedOutputBins(PrintService service) throws Exception { + + System.out.printf("Check printService: %s%n", service); + + boolean isOutputBinCategorySupported = service.isAttributeCategorySupported(OutputBin.class); + OutputBin defaultOutputBin = (OutputBin) service.getDefaultAttributeValue(OutputBin.class); + Set> supportedAttributeCategories = Set.of(service.getSupportedAttributeCategories()); + OutputBin[] supportedOutputBins = (OutputBin[]) service + .getSupportedAttributeValues(OutputBin.class, null, null); + + if (!isOutputBinCategorySupported) { + + if (supportedAttributeCategories.contains(OutputBin.class)) { + throw new Exception("OutputBin category is not supported" + + " and supported attribute categories contain OutputBin.class."); + } + + if (defaultOutputBin != null) { + throw new Exception("OutputBin category is not supported" + + " and the default output bin is not null."); + } + + if (supportedOutputBins != null && supportedOutputBins.length > 0) { + throw new Exception("OutputBin category is not supported" + + " and array of supported output bins is not null or its size is not zero."); + } + + return; + } + + if (!supportedAttributeCategories.contains(OutputBin.class)) { + throw new Exception("OutputBin category is supported" + + " and supported attribute categories do not contain OutputBin.class."); + } + + if (defaultOutputBin == null) { + throw new Exception("OutputBin category is supported" + + " and the default output bin is null."); + } + + if (supportedOutputBins == null || supportedOutputBins.length == 0) { + throw new Exception("OutputBin category is supported" + + " and PrintService.getSupportedAttributeValues() returns null or an array with zero elements."); + } + + if (!service.isAttributeValueSupported(defaultOutputBin, null, null)) { + throw new Exception("OutputBin category is supported" + + " and the default output bin " + defaultOutputBin + " is not supported"); + } + + for (OutputBin outputBin : supportedOutputBins) { + if (!service.isAttributeValueSupported(outputBin, null, null)) { + throw new Exception("OutputBin category is supported" + + " and the output bin " + outputBin + " from supported attribute values" + + " is not supported"); + } + } + } +} \ No newline at end of file diff --git a/test/jdk/javax/print/attribute/OutputBinAttributePrintDialogTest.java b/test/jdk/javax/print/attribute/OutputBinAttributePrintDialogTest.java new file mode 100644 index 0000000000000..72bfcfe177bdb --- /dev/null +++ b/test/jdk/javax/print/attribute/OutputBinAttributePrintDialogTest.java @@ -0,0 +1,368 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, BELLSOFT. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; +import javax.print.PrintService; +import javax.print.attribute.Attribute; +import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.PrintRequestAttributeSet; +import javax.print.attribute.standard.DialogTypeSelection; +import javax.print.attribute.standard.MediaSizeName; +import javax.print.attribute.standard.OutputBin; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dialog; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Window; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.print.PageFormat; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/* + * @test + * @bug 8314070 + * @key printer + * @requires (os.family == "linux" | os.family == "mac") + * @summary javax.print: Support IPP output-bin attribute extension + * @run main/manual OutputBinAttributePrintDialogTest COMMON + * @run main/manual OutputBinAttributePrintDialogTest NATIVE + */ + +public class OutputBinAttributePrintDialogTest { + + private static final long TIMEOUT = 10 * 60_000; + private static volatile boolean testPassed = true; + private static volatile boolean testSkipped = false; + private static volatile boolean testFinished = false; + private static volatile boolean printJobCanceled = false; + private static volatile boolean timeout = false; + + private static volatile boolean isNativeDialog; + + private static volatile int testCount; + private static volatile int testTotalCount; + + public static void main(String[] args) throws Exception { + + if (args.length < 1) { + throw new RuntimeException("COMMON or NATIVE print dialog type argument is not provided!"); + } + + final DialogTypeSelection dialogTypeSelection = getDialogTypeSelection(args[0]); + isNativeDialog = (dialogTypeSelection == DialogTypeSelection.NATIVE); + + if (dialogTypeSelection == DialogTypeSelection.NATIVE) { + String os = System.getProperty("os.name").toLowerCase(); + if (os.startsWith("linux")) { + System.out.println("Skip the native print dialog type test on Linux as it is the same as the common."); + return; + } + } + + final OutputBin[] supportedOutputBins = getSupportedOutputBinttributes(); + if (supportedOutputBins == null) { + return; + } + + if (supportedOutputBins.length < 2) { + System.out.println("Skip the test as the number of supported output bins is less than 2."); + return; + } + + SwingUtilities.invokeLater(() -> { + testTotalCount = supportedOutputBins.length; + for (OutputBin outputBin : supportedOutputBins) { + if (testSkipped) { + break; + } + testPrint(dialogTypeSelection, outputBin, supportedOutputBins); + } + testFinished = true; + }); + + long time = System.currentTimeMillis() + TIMEOUT; + + while (System.currentTimeMillis() < time) { + if (!testPassed || testFinished) { + break; + } + Thread.sleep(500); + } + + timeout = true; + + closeDialogs(); + + if (testSkipped) { + System.out.printf("Test is skipped!%n"); + return; + } + + if (!testPassed) { + throw new Exception("Test failed!"); + } + + if (testCount != testTotalCount) { + throw new Exception( + "Timeout: " + testCount + " tests passed out from " + testTotalCount); + } + } + + private static void print(DialogTypeSelection dialogTypeSelection, OutputBin outputBin) throws PrinterException { + PrintRequestAttributeSet attr = new HashPrintRequestAttributeSet(); + attr.add(MediaSizeName.ISO_A4); + attr.add(dialogTypeSelection); + + for (Attribute attribute : attr.toArray()) { + System.out.printf("Used print request attribute: %s%n", attribute); + } + + PrinterJob job = PrinterJob.getPrinterJob(); + job.setJobName("Print to " + outputBin + " output bin through " + dialogTypeSelection + " print dialog"); + job.setPrintable(new OutputBinAttributePrintable(outputBin)); + + if (job.printDialog(attr)) { + job.print(); + } else if (isNativeDialog) { + printJobCanceled = true; + } else { + throw new RuntimeException(dialogTypeSelection + " print dialog for " + outputBin + " is canceled!"); + } + } + + private static class OutputBinAttributePrintable implements Printable { + + private final OutputBin outputBinAttr; + + public OutputBinAttributePrintable(OutputBin outputBinAttr) { + this.outputBinAttr = outputBinAttr; + } + + @Override + public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException { + + if (pageIndex != 0) { + return NO_SUCH_PAGE; + } + + int x = (int) (pageFormat.getImageableX() + pageFormat.getImageableWidth() / 10); + int y = (int) (pageFormat.getImageableY() + pageFormat.getImageableHeight() / 5); + + Graphics2D g = (Graphics2D) graphics; + g.setColor(Color.BLACK); + g.drawString(getPageText(outputBinAttr), x, y); + return PAGE_EXISTS; + } + } + + private static String getPageText(OutputBin outputBin) { + return String.format("Output bin: %s", outputBin); + } + + private static OutputBin[] getSupportedOutputBinttributes() { + + PrinterJob printerJob = PrinterJob.getPrinterJob(); + PrintService service = printerJob.getPrintService(); + if (service == null) { + System.out.printf("No print service found."); + return null; + } + + if (!service.isAttributeCategorySupported(OutputBin.class)) { + System.out.printf("Skipping the test as OutputBin category is not supported for this printer."); + return null; + } + + Object obj = service.getSupportedAttributeValues(OutputBin.class, null, null); + + if (obj instanceof OutputBin[]) { + return (OutputBin[]) obj; + } + + throw new RuntimeException("OutputBin category is supported but no supported attribute values are returned."); + } + + private static void pass() { + testCount++; + } + + private static void skip() { + testSkipped = true; + } + + private static void fail(OutputBin outputBin) { + System.out.printf("Failed test: %s%n", getPageText(outputBin)); + testPassed = false; + } + + private static void runPrint(DialogTypeSelection dialogTypeSelection, OutputBin outputBin) { + try { + print(dialogTypeSelection, outputBin); + } catch (PrinterException e) { + e.printStackTrace(); + fail(outputBin); + closeDialogs(); + } + } + + private static void testPrint(DialogTypeSelection dialogTypeSelection, OutputBin outputBin, OutputBin[] supportedOutputBins) { + + System.out.printf("Test dialog: %s%n", dialogTypeSelection); + + String[] instructions = { + "Up to " + testTotalCount + " tests will run and it will test all output bins:", + Arrays.toString(supportedOutputBins), + "supported by the printer.", + "", + "The test is " + (testCount + 1) + " from " + testTotalCount + ".", + "", + "On-screen inspection is not possible for this printing-specific", + "test therefore its only output is a page printed to the printer", + outputBin + " output bin.", + "", + "To be able to run this test it is required to have a default", + "printer configured in your user environment.", + "", + " - Press 'Start Test' button.", + " The " + dialogTypeSelection + " print dialog should appear.", + String.join("\n", getPrintDialogInstructions(dialogTypeSelection, outputBin)), + "", + "Visual inspection of the printed pages is needed.", + "", + "A passing test will print the page with the text: '" + getPageText(outputBin) + "'", + "to the corresponding printer " + outputBin + " ouput bin.", + "", + "The test fails if the page is not printed in to the corresponding output bin.", + }; + + String title = String.format("Print %s dialog with %s output bin test: %d from %d", + dialogTypeSelection, outputBin, testCount + 1, testTotalCount); + final JDialog dialog = new JDialog((Frame) null, title, Dialog.ModalityType.DOCUMENT_MODAL); + JTextArea textArea = new JTextArea(String.join("\n", instructions)); + textArea.setEditable(false); + final JButton testButton = new JButton("Start Test"); + final JButton skipButton = new JButton("Skip Test"); + final JButton passButton = new JButton("PASS"); + skipButton.setEnabled(false); + passButton.setEnabled(false); + passButton.addActionListener((e) -> { + pass(); + dialog.dispose(); + }); + skipButton.addActionListener((e) -> { + skip(); + dialog.dispose(); + }); + final JButton failButton = new JButton("FAIL"); + failButton.setEnabled(false); + failButton.addActionListener((e) -> { + fail(outputBin); + dialog.dispose(); + }); + testButton.addActionListener((e) -> { + testButton.setEnabled(false); + runPrint(dialogTypeSelection, outputBin); + skipButton.setEnabled(true); + passButton.setEnabled(true); + failButton.setEnabled(true); + }); + + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.add(textArea, BorderLayout.CENTER); + JPanel buttonPanel = new JPanel(new FlowLayout()); + buttonPanel.add(testButton); + if (isNativeDialog) { + buttonPanel.add(skipButton); + } + buttonPanel.add(passButton); + buttonPanel.add(failButton); + mainPanel.add(buttonPanel, BorderLayout.SOUTH); + dialog.add(mainPanel); + dialog.pack(); + dialog.setVisible(true); + dialog.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + System.out.println("Dialog closing"); + fail(outputBin); + } + }); + } + + private static void closeDialogs() { + for (Window w : Dialog.getWindows()) { + w.dispose(); + } + } + + private static DialogTypeSelection getDialogTypeSelection(String dialogTypeSelection) { + switch (dialogTypeSelection) { + case "COMMON": + return DialogTypeSelection.COMMON; + case "NATIVE": + return DialogTypeSelection.NATIVE; + default: + throw new RuntimeException("Unknown dialog type selection: " + dialogTypeSelection); + } + } + + private static String[] getPrintDialogInstructions(DialogTypeSelection dialogTypeSelection, OutputBin outputBin) { + if (dialogTypeSelection == DialogTypeSelection.COMMON) { + return new String[]{ + " - Select 'Appearance' tab.", + " - Select '" + outputBin + "' output tray from 'Output trays' combo box.", + " - Press 'Print' button." + }; + } else if (dialogTypeSelection == DialogTypeSelection.NATIVE) { + return new String[]{ + " - Press 'Show Details' buttons if the details are hidded.", + " - Check that the native print dialog contains 'Finishing Options' in the drop-down list.", + " - If there is no 'Finishing Options' in the drop-down list then", + " - Press 'Cancel' button on the print dialog.", + " - Press 'Skip Test' button on the test dialog.", + " otherwise", + " - Select 'Finishing Options' from the drop-down list.", + " - Select '" + outputBin + "' Output Bin.", + " - Press 'Print' button." + }; + } + throw new RuntimeException("Unknown dialog type selection: " + dialogTypeSelection); + } +} diff --git a/test/jdk/javax/print/attribute/OutputBinAttributeTest.java b/test/jdk/javax/print/attribute/OutputBinAttributeTest.java new file mode 100644 index 0000000000000..4d3ca71f5fb5f --- /dev/null +++ b/test/jdk/javax/print/attribute/OutputBinAttributeTest.java @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, BELLSOFT. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; +import javax.print.PrintService; +import javax.print.attribute.Attribute; +import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.PrintRequestAttributeSet; +import javax.print.attribute.standard.MediaSizeName; +import javax.print.attribute.standard.OutputBin; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dialog; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Window; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.print.PageFormat; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/* + * @test + * @bug 8314070 + * @key printer + * @requires (os.family == "linux" | os.family == "mac") + * @summary javax.print: Support IPP output-bin attribute extension + * @run main/manual OutputBinAttributeTest + */ + +public class OutputBinAttributeTest { + + private static final long TIMEOUT = 10 * 60_000; + private static volatile boolean testPassed = true; + private static volatile boolean testFinished = false; + private static volatile boolean timeout = false; + + private static volatile int testCount; + private static volatile int testTotalCount; + + public static void main(String[] args) throws Exception { + + SwingUtilities.invokeLater(() -> { + Set supportedOutputBins = getSupportedOutputBinttributes(); + if (supportedOutputBins != null) { + if (supportedOutputBins.size() > 1) { + testTotalCount = supportedOutputBins.size(); + for (OutputBin outputBin : supportedOutputBins) { + testPrint(outputBin, supportedOutputBins); + } + } else { + System.out.println("Skip the test as the number of supported output bins is less than 2."); + } + } + testFinished = true; + }); + + long time = System.currentTimeMillis() + TIMEOUT; + + while (System.currentTimeMillis() < time) { + if (!testPassed || testFinished) { + break; + } + Thread.sleep(500); + } + + timeout = true; + + closeDialogs(); + + if (!testPassed) { + throw new Exception("Test failed!"); + } + + if (testCount != testTotalCount) { + throw new Exception( + "Timeout: " + testCount + " tests passed out from " + testTotalCount); + } + } + + private static void print(OutputBin outputBin) throws PrinterException { + PrintRequestAttributeSet attr = new HashPrintRequestAttributeSet(); + attr.add(MediaSizeName.ISO_A4); + attr.add(outputBin); + + for (Attribute attribute : attr.toArray()) { + System.out.printf("Used print request attribute: %s%n", attribute); + } + + PrinterJob job = PrinterJob.getPrinterJob(); + job.setJobName("Print to " + outputBin + " output bin"); + job.setPrintable(new OutputBinAttributePrintable(outputBin)); + + job.print(attr); + } + + private static class OutputBinAttributePrintable implements Printable { + + private final OutputBin outputBinAttr; + + public OutputBinAttributePrintable(OutputBin outputBinAttr) { + this.outputBinAttr = outputBinAttr; + } + + @Override + public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException { + + if (pageIndex != 0) { + return NO_SUCH_PAGE; + } + + int x = (int) (pageFormat.getImageableX() + pageFormat.getImageableWidth() / 10); + int y = (int) (pageFormat.getImageableY() + pageFormat.getImageableHeight() / 5); + + Graphics2D g = (Graphics2D) graphics; + g.setColor(Color.BLACK); + g.drawString(getPageText(outputBinAttr), x, y); + return PAGE_EXISTS; + } + } + + private static String getPageText(OutputBin outputBin) { + return String.format("Output bin: %s", outputBin); + } + + private static Set getSupportedOutputBinttributes() { + Set supportedOutputBins = new HashSet<>(); + + PrinterJob printerJob = PrinterJob.getPrinterJob(); + PrintService service = printerJob.getPrintService(); + if (service == null) { + System.out.printf("No print service found."); + return null; + } + + if (!service.isAttributeCategorySupported(OutputBin.class)) { + System.out.printf("Skipping the test as OutputBin category is not supported for this printer."); + return null; + } + + Object obj = service.getSupportedAttributeValues(OutputBin.class, null, null); + + if (obj instanceof OutputBin[]) { + Collections.addAll(supportedOutputBins, (OutputBin[]) obj); + return supportedOutputBins; + } + + throw new RuntimeException("OutputBin category is supported but no supported attribute values are returned."); + } + + private static void pass() { + testCount++; + } + + private static void fail(OutputBin outputBin) { + System.out.printf("Failed test: %s%n", getPageText(outputBin)); + testPassed = false; + } + + private static void runPrint(OutputBin outputBin) { + try { + print(outputBin); + } catch (PrinterException e) { + e.printStackTrace(); + fail(outputBin); + } + } + + private static void testPrint(OutputBin outputBin, Set supportedOutputBins) { + + String[] instructions = { + "Up to " + testTotalCount + " tests will run and it will test all output bins:", + supportedOutputBins.toString(), + "supported by the printer.", + "", + "The test is " + (testCount + 1) + " from " + testTotalCount + ".", + "", + "On-screen inspection is not possible for this printing-specific", + "test therefore its only output is a page printed to the printer", + outputBin + " output bin.", + "To be able to run this test it is required to have a default", + "printer configured in your user environment.", + "", + "Visual inspection of the printed pages is needed.", + "", + "A passing test will print the page with the text: '" + getPageText(outputBin) + "'", + "to the corresponding printer " + outputBin + " ouput bin.", + "", + "The test fails if the page is not printed in to the corresponding output bin.", + }; + + String title = String.format("Print %s output bin test: %d from %d", + outputBin, testCount + 1, testTotalCount); + final JDialog dialog = new JDialog((Frame) null, title, Dialog.ModalityType.DOCUMENT_MODAL); + JTextArea textArea = new JTextArea(String.join("\n", instructions)); + textArea.setEditable(false); + final JButton testButton = new JButton("Start Test"); + final JButton passButton = new JButton("PASS"); + passButton.setEnabled(false); + passButton.addActionListener((e) -> { + pass(); + dialog.dispose(); + }); + final JButton failButton = new JButton("FAIL"); + failButton.setEnabled(false); + failButton.addActionListener((e) -> { + fail(outputBin); + dialog.dispose(); + }); + testButton.addActionListener((e) -> { + testButton.setEnabled(false); + runPrint(outputBin); + passButton.setEnabled(true); + failButton.setEnabled(true); + }); + + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.add(textArea, BorderLayout.CENTER); + JPanel buttonPanel = new JPanel(new FlowLayout()); + buttonPanel.add(testButton); + buttonPanel.add(passButton); + buttonPanel.add(failButton); + mainPanel.add(buttonPanel, BorderLayout.SOUTH); + dialog.add(mainPanel); + dialog.pack(); + dialog.setVisible(true); + dialog.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + System.out.println("Dialog closing"); + fail(outputBin); + } + }); + } + + private static void closeDialogs() { + for (Window w : Dialog.getWindows()) { + w.dispose(); + } + } +} From 29e10e4582c1a844a6db4c42ba01bd1d6d4dfd52 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Tue, 4 Jun 2024 04:02:49 +0000 Subject: [PATCH 11/14] 8332547: Unloaded signature classes in DirectMethodHandles Reviewed-by: jvernee, liach --- .../lang/invoke/InvokerBytecodeGenerator.java | 2 +- .../classes/java/lang/invoke/MemberName.java | 8 +-- .../classes/sun/invoke/util/VerifyAccess.java | 22 ++++--- .../unloaded/TestUnloadedSignatureClass.java | 66 +++++++++++++++++++ 4 files changed, 83 insertions(+), 15 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/runtime/unloaded/TestUnloadedSignatureClass.java diff --git a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java index 207d1e345ae94..4e3ebb3834d91 100644 --- a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java +++ b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java @@ -632,7 +632,7 @@ private String getInternalName(Class c) { else if (c == Object[].class) return OBJARY; else if (c == Class.class) return CLS; else if (c == MethodHandle.class) return MH; - assert(VerifyAccess.isTypeVisible(c, Object.class)) : c.getName(); + assert(VerifyAccess.ensureTypeVisible(c, Object.class)) : c.getName(); if (c == lastClass) { return lastInternalName; diff --git a/src/java.base/share/classes/java/lang/invoke/MemberName.java b/src/java.base/share/classes/java/lang/invoke/MemberName.java index c8b38b1d16dfc..9b8c215e4c3d0 100644 --- a/src/java.base/share/classes/java/lang/invoke/MemberName.java +++ b/src/java.base/share/classes/java/lang/invoke/MemberName.java @@ -800,7 +800,7 @@ void initResolved(boolean isResolved) { assert(isResolved() == isResolved); } - void checkForTypeAlias(Class refc) { + void ensureTypeVisible(Class refc) { if (isInvocable()) { MethodType type; if (this.type instanceof MethodType mt) @@ -808,7 +808,7 @@ void checkForTypeAlias(Class refc) { else this.type = type = getMethodType(); if (type.erase() == type) return; - if (VerifyAccess.isTypeVisible(type, refc)) return; + if (VerifyAccess.ensureTypeVisible(type, refc)) return; throw new LinkageError("bad method type alias: "+type+" not visible from "+refc); } else { Class type; @@ -816,7 +816,7 @@ void checkForTypeAlias(Class refc) { type = cl; else this.type = type = getFieldType(); - if (VerifyAccess.isTypeVisible(type, refc)) return; + if (VerifyAccess.ensureTypeVisible(type, refc)) return; throw new LinkageError("bad field type alias: "+type+" not visible from "+refc); } } @@ -958,7 +958,7 @@ private MemberName resolve(byte refKind, MemberName ref, Class lookupClass, i if (m == null && speculativeResolve) { return null; } - m.checkForTypeAlias(m.getDeclaringClass()); + m.ensureTypeVisible(m.getDeclaringClass()); m.resolution = null; } catch (ClassNotFoundException | LinkageError ex) { // JVM reports that the "bytecode behavior" would get an error diff --git a/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java b/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java index 28373ad6bda44..076d04632c9fc 100644 --- a/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java +++ b/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java @@ -268,7 +268,7 @@ public static boolean isModuleAccessible(Class refc, Module m1, Module m2) { * @param type the supposed type of a member or symbolic reference of refc * @param refc the class attempting to make the reference */ - public static boolean isTypeVisible(Class type, Class refc) { + public static boolean ensureTypeVisible(Class type, Class refc) { if (type == refc) { return true; // easy check } @@ -284,12 +284,14 @@ public static boolean isTypeVisible(Class type, Class refc) { if (refcLoader == null && typeLoader != null) { return false; } - if (typeLoader == null && type.getName().startsWith("java.")) { - // Note: The API for actually loading classes, ClassLoader.defineClass, - // guarantees that classes with names beginning "java." cannot be aliased, - // because class loaders cannot load them directly. - return true; - } + + // The API for actually loading classes, ClassLoader.defineClass, + // guarantees that classes with names beginning "java." cannot be aliased, + // because class loaders cannot load them directly. However, it is beneficial + // for JIT-compilers to ensure all signature classes are loaded. + // JVM doesn't install any loader contraints when performing MemberName resolution, + // so eagerly resolving signature classes is a way to match what JVM achieves + // with loader constraints during method resolution for invoke bytecodes. // Do it the hard way: Look up the type name from the refc loader. // @@ -338,12 +340,12 @@ public Class run() { * @param type the supposed type of a member or symbolic reference of refc * @param refc the class attempting to make the reference */ - public static boolean isTypeVisible(java.lang.invoke.MethodType type, Class refc) { - if (!isTypeVisible(type.returnType(), refc)) { + public static boolean ensureTypeVisible(java.lang.invoke.MethodType type, Class refc) { + if (!ensureTypeVisible(type.returnType(), refc)) { return false; } for (int n = 0, max = type.parameterCount(); n < max; n++) { - if (!isTypeVisible(type.parameterType(n), refc)) { + if (!ensureTypeVisible(type.parameterType(n), refc)) { return false; } } diff --git a/test/hotspot/jtreg/compiler/runtime/unloaded/TestUnloadedSignatureClass.java b/test/hotspot/jtreg/compiler/runtime/unloaded/TestUnloadedSignatureClass.java new file mode 100644 index 0000000000000..01982e4bda438 --- /dev/null +++ b/test/hotspot/jtreg/compiler/runtime/unloaded/TestUnloadedSignatureClass.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib + * @run driver compiler.runtime.unloaded.TestUnloadedSignatureClass + */ + +package compiler.runtime.unloaded; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class TestUnloadedSignatureClass { + static class Test { + static int test(Integer i) { + // Bound to a wrapper around a method with (Ljava/lang/Object;ILjava/util/function/BiPredicate;Ljava/util/List;)I signature. + // Neither BiPredicate nor List are guaranteed to be resolved by the context class loader. + return switch (i) { + case null -> -1; + case 0 -> 0; + default -> 1; + }; + } + + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + test(i); + } + } + } + + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + "-Xbatch", "-XX:-TieredCompilation", + "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly,*::test", + "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintCompilation", "-XX:+PrintInlining", + Test.class.getName() + ); + + OutputAnalyzer out = new OutputAnalyzer(pb.start()); + out.shouldHaveExitValue(0); + out.shouldNotContain("unloaded signature classes"); + } +} From ca3072635215755766575b4eb70dc6267969a550 Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Tue, 4 Jun 2024 05:11:41 +0000 Subject: [PATCH 12/14] 8332866: Crash in ImageIO JPEG decoding when MEM_STATS in enabled Reviewed-by: abhiscxk, psadhukhan --- src/java.desktop/share/native/libjavajpeg/imageioJPEG.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c b/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c index 85476f0f2e6cf..4e2ba2a35c5d3 100644 --- a/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c +++ b/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -666,8 +666,6 @@ static void imageio_reset(JNIEnv *env, static void imageio_dispose(j_common_ptr info) { if (info != NULL) { - free(info->err); - info->err = NULL; if (info->is_decompressor) { j_decompress_ptr dinfo = (j_decompress_ptr) info; free(dinfo->src); @@ -678,6 +676,8 @@ static void imageio_dispose(j_common_ptr info) { cinfo->dest = NULL; } jpeg_destroy(info); + free(info->err); + info->err = NULL; free(info); } } From 67d6f3ca9e8d1312c9e3a85dbe19903619f59064 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Tue, 4 Jun 2024 06:20:31 +0000 Subject: [PATCH 13/14] 8332905: C2 SuperWord: bad AD file, with RotateRightV and first operand not a pack Reviewed-by: chagedorn, thartmann --- src/hotspot/share/opto/superword.cpp | 2 +- .../runner/ArrayShiftOpTest.java | 22 +++++++++++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index f41e8a7b8b354..0b940a13c5481 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -2435,7 +2435,7 @@ bool SuperWord::output() { vn = StoreVectorNode::make(opc, ctl, mem, adr, atyp, val, vlen); vlen_in_bytes = vn->as_StoreVector()->memory_size(); } else if (VectorNode::is_scalar_rotate(n)) { - Node* in1 = first->in(1); + Node* in1 = vector_opd(p, 1); Node* in2 = first->in(2); // If rotation count is non-constant or greater than 8bit value create a vector. if (!in2->is_Con() || !Matcher::supports_vector_constant_rotates(in2->get_int())) { diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/ArrayShiftOpTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/ArrayShiftOpTest.java index 40307ba7e1b39..08e194db5f691 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/ArrayShiftOpTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/ArrayShiftOpTest.java @@ -23,6 +23,7 @@ /* * @test + * @bug 8183390 8332905 * @summary Vectorization test on bug-prone shift operation * @library /test/lib / * @@ -48,6 +49,7 @@ public class ArrayShiftOpTest extends VectorizationTestRunner { private static final int SIZE = 543; + private static int size = 543; private int[] ints; private long[] longs; @@ -71,7 +73,7 @@ public ArrayShiftOpTest() { } @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512f", "true"}, + @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true"}, counts = {IRNode.STORE_VECTOR, ">0"}) @IR(applyIfCPUFeature = {"avx512f", "true"}, counts = {IRNode.ROTATE_RIGHT_V, ">0"}) @@ -87,7 +89,23 @@ public int[] intCombinedRotateShift() { } @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512f", "true"}, + @IR(applyIfCPUFeatureOr = {"sve", "true", "avx2", "true"}, + counts = {IRNode.STORE_VECTOR, ">0"}) + @IR(applyIfCPUFeature = {"avx512f", "true"}, + counts = {IRNode.ROTATE_RIGHT_V, ">0"}) + // Requires size to not be known at compile time, otherwise the shift + // can get constant folded with the (iv + const) pattern from the + // PopulateIndex. + public int[] intCombinedRotateShiftWithPopulateIndex() { + int[] res = new int[size]; + for (int i = 0; i < size; i++) { + res[i] = (i << 14) | (i >>> 18); + } + return res; + } + + @Test + @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true"}, counts = {IRNode.STORE_VECTOR, ">0"}) @IR(applyIfCPUFeature = {"avx512f", "true"}, counts = {IRNode.ROTATE_RIGHT_V, ">0"}) From 454660d361e39f362ff0e10a5c2389af910cca23 Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Tue, 4 Jun 2024 07:04:57 +0000 Subject: [PATCH 14/14] 8332900: RISC-V: refactor nativeInst_riscv.cpp and macroAssembler_riscv.cpp Reviewed-by: fyang, luhenry --- .../riscv/gc/z/zBarrierSetAssembler_riscv.cpp | 2 +- .../cpu/riscv/macroAssembler_riscv.cpp | 216 +++++++++++--- .../cpu/riscv/macroAssembler_riscv.hpp | 226 ++++++++++++++- src/hotspot/cpu/riscv/nativeInst_riscv.cpp | 139 +-------- src/hotspot/cpu/riscv/nativeInst_riscv.hpp | 264 ++---------------- src/hotspot/cpu/riscv/relocInfo_riscv.cpp | 8 +- 6 files changed, 434 insertions(+), 421 deletions(-) diff --git a/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp index 7f7f19957e92a..8fbeaa45371d1 100644 --- a/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp @@ -629,7 +629,7 @@ void ZBarrierSetAssembler::patch_barrier_relocation(address addr, int format) { case ZBarrierRelocationFormatMarkBadMask: case ZBarrierRelocationFormatStoreGoodBits: case ZBarrierRelocationFormatStoreBadMask: - assert(NativeInstruction::is_li16u_at(addr), "invalide zgc barrier"); + assert(MacroAssembler::is_li16u_at(addr), "invalide zgc barrier"); bytes = MacroAssembler::pd_patch_instruction_size(addr, (address)(uintptr_t)value); break; default: diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 20a0cf5680f41..9961ce8e6dd39 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -38,7 +38,6 @@ #include "interpreter/interpreter.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" -#include "nativeInst_riscv.hpp" #include "oops/accessDecorators.hpp" #include "oops/compressedKlass.inline.hpp" #include "oops/compressedOops.inline.hpp" @@ -65,6 +64,138 @@ #define STOP(str) stop(str); #define BIND(label) bind(label); __ BLOCK_COMMENT(#label ":") + + +Register MacroAssembler::extract_rs1(address instr) { + assert_cond(instr != nullptr); + return as_Register(Assembler::extract(Assembler::ld_instr(instr), 19, 15)); +} + +Register MacroAssembler::extract_rs2(address instr) { + assert_cond(instr != nullptr); + return as_Register(Assembler::extract(Assembler::ld_instr(instr), 24, 20)); +} + +Register MacroAssembler::extract_rd(address instr) { + assert_cond(instr != nullptr); + return as_Register(Assembler::extract(Assembler::ld_instr(instr), 11, 7)); +} + +uint32_t MacroAssembler::extract_opcode(address instr) { + assert_cond(instr != nullptr); + return Assembler::extract(Assembler::ld_instr(instr), 6, 0); +} + +uint32_t MacroAssembler::extract_funct3(address instr) { + assert_cond(instr != nullptr); + return Assembler::extract(Assembler::ld_instr(instr), 14, 12); +} + +bool MacroAssembler::is_pc_relative_at(address instr) { + // auipc + jalr + // auipc + addi + // auipc + load + // auipc + fload_load + return (is_auipc_at(instr)) && + (is_addi_at(instr + instruction_size) || + is_jalr_at(instr + instruction_size) || + is_load_at(instr + instruction_size) || + is_float_load_at(instr + instruction_size)) && + check_pc_relative_data_dependency(instr); +} + +// ie:ld(Rd, Label) +bool MacroAssembler::is_load_pc_relative_at(address instr) { + return is_auipc_at(instr) && // auipc + is_ld_at(instr + instruction_size) && // ld + check_load_pc_relative_data_dependency(instr); +} + +bool MacroAssembler::is_movptr1_at(address instr) { + return is_lui_at(instr) && // Lui + is_addi_at(instr + instruction_size) && // Addi + is_slli_shift_at(instr + instruction_size * 2, 11) && // Slli Rd, Rs, 11 + is_addi_at(instr + instruction_size * 3) && // Addi + is_slli_shift_at(instr + instruction_size * 4, 6) && // Slli Rd, Rs, 6 + (is_addi_at(instr + instruction_size * 5) || + is_jalr_at(instr + instruction_size * 5) || + is_load_at(instr + instruction_size * 5)) && // Addi/Jalr/Load + check_movptr1_data_dependency(instr); +} + +bool MacroAssembler::is_movptr2_at(address instr) { + return is_lui_at(instr) && // lui + is_lui_at(instr + instruction_size) && // lui + is_slli_shift_at(instr + instruction_size * 2, 18) && // slli Rd, Rs, 18 + is_add_at(instr + instruction_size * 3) && + (is_addi_at(instr + instruction_size * 4) || + is_jalr_at(instr + instruction_size * 4) || + is_load_at(instr + instruction_size * 4)) && // Addi/Jalr/Load + check_movptr2_data_dependency(instr); +} + +bool MacroAssembler::is_li16u_at(address instr) { + return is_lui_at(instr) && // lui + is_srli_at(instr + instruction_size) && // srli + check_li16u_data_dependency(instr); +} + +bool MacroAssembler::is_li32_at(address instr) { + return is_lui_at(instr) && // lui + is_addiw_at(instr + instruction_size) && // addiw + check_li32_data_dependency(instr); +} + +bool MacroAssembler::is_li64_at(address instr) { + return is_lui_at(instr) && // lui + is_addi_at(instr + instruction_size) && // addi + is_slli_shift_at(instr + instruction_size * 2, 12) && // Slli Rd, Rs, 12 + is_addi_at(instr + instruction_size * 3) && // addi + is_slli_shift_at(instr + instruction_size * 4, 12) && // Slli Rd, Rs, 12 + is_addi_at(instr + instruction_size * 5) && // addi + is_slli_shift_at(instr + instruction_size * 6, 8) && // Slli Rd, Rs, 8 + is_addi_at(instr + instruction_size * 7) && // addi + check_li64_data_dependency(instr); +} + +bool MacroAssembler::is_lwu_to_zr(address instr) { + assert_cond(instr != nullptr); + return (extract_opcode(instr) == 0b0000011 && + extract_funct3(instr) == 0b110 && + extract_rd(instr) == zr); // zr +} + +uint32_t MacroAssembler::get_membar_kind(address addr) { + assert_cond(addr != nullptr); + assert(is_membar(addr), "no membar found"); + + uint32_t insn = Bytes::get_native_u4(addr); + + uint32_t predecessor = Assembler::extract(insn, 27, 24); + uint32_t successor = Assembler::extract(insn, 23, 20); + + return MacroAssembler::pred_succ_to_membar_mask(predecessor, successor); +} + +void MacroAssembler::set_membar_kind(address addr, uint32_t order_kind) { + assert_cond(addr != nullptr); + assert(is_membar(addr), "no membar found"); + + uint32_t predecessor = 0; + uint32_t successor = 0; + + MacroAssembler::membar_mask_to_pred_succ(order_kind, predecessor, successor); + + uint32_t insn = Bytes::get_native_u4(addr); + address pInsn = (address) &insn; + Assembler::patch(pInsn, 27, 24, predecessor); + Assembler::patch(pInsn, 23, 20, successor); + + address membar = addr; + Assembler::sd_instr(membar, insn); +} + + static void pass_arg0(MacroAssembler* masm, Register arg) { if (c_rarg0 != arg) { masm->mv(c_rarg0, arg); @@ -1405,7 +1536,7 @@ static int patch_offset_in_jal(address branch, int64_t offset) { Assembler::patch(branch, 30, 21, (offset >> 1) & 0x3ff); // offset[10:1] ==> branch[30:21] Assembler::patch(branch, 20, 20, (offset >> 11) & 0x1); // offset[11] ==> branch[20] Assembler::patch(branch, 19, 12, (offset >> 12) & 0xff); // offset[19:12] ==> branch[19:12] - return NativeInstruction::instruction_size; // only one instruction + return MacroAssembler::instruction_size; // only one instruction } static int patch_offset_in_conditional_branch(address branch, int64_t offset) { @@ -1415,14 +1546,14 @@ static int patch_offset_in_conditional_branch(address branch, int64_t offset) { Assembler::patch(branch, 30, 25, (offset >> 5) & 0x3f); // offset[10:5] ==> branch[30:25] Assembler::patch(branch, 7, 7, (offset >> 11) & 0x1); // offset[11] ==> branch[7] Assembler::patch(branch, 11, 8, (offset >> 1) & 0xf); // offset[4:1] ==> branch[11:8] - return NativeInstruction::instruction_size; // only one instruction + return MacroAssembler::instruction_size; // only one instruction } static int patch_offset_in_pc_relative(address branch, int64_t offset) { const int PC_RELATIVE_INSTRUCTION_NUM = 2; // auipc, addi/jalr/load Assembler::patch(branch, 31, 12, ((offset + 0x800) >> 12) & 0xfffff); // Auipc. offset[31:12] ==> branch[31:12] Assembler::patch(branch + 4, 31, 20, offset & 0xfff); // Addi/Jalr/Load. offset[11:0] ==> branch[31:20] - return PC_RELATIVE_INSTRUCTION_NUM * NativeInstruction::instruction_size; + return PC_RELATIVE_INSTRUCTION_NUM * MacroAssembler::instruction_size; } static int patch_addr_in_movptr1(address branch, address target) { @@ -1432,7 +1563,7 @@ static int patch_addr_in_movptr1(address branch, address target) { Assembler::patch(branch + 4, 31, 20, (lower >> 17) & 0xfff); // Addi. target[28:17] ==> branch[31:20] Assembler::patch(branch + 12, 31, 20, (lower >> 6) & 0x7ff); // Addi. target[16: 6] ==> branch[31:20] Assembler::patch(branch + 20, 31, 20, lower & 0x3f); // Addi/Jalr/Load. target[ 5: 0] ==> branch[31:20] - return NativeMovConstReg::movptr1_instruction_size; + return MacroAssembler::movptr1_instruction_size; } static int patch_addr_in_movptr2(address instruction_address, address target) { @@ -1444,15 +1575,15 @@ static int patch_addr_in_movptr2(address instruction_address, address target) { int low12 = (lower30 << 20) >> 20; int mid18 = ((lower30 - low12) >> 12); - Assembler::patch(instruction_address + (NativeInstruction::instruction_size * 0), 31, 12, (upper18 & 0xfffff)); // Lui - Assembler::patch(instruction_address + (NativeInstruction::instruction_size * 1), 31, 12, (mid18 & 0xfffff)); // Lui + Assembler::patch(instruction_address + (MacroAssembler::instruction_size * 0), 31, 12, (upper18 & 0xfffff)); // Lui + Assembler::patch(instruction_address + (MacroAssembler::instruction_size * 1), 31, 12, (mid18 & 0xfffff)); // Lui // Slli // Add - Assembler::patch(instruction_address + (NativeInstruction::instruction_size * 4), 31, 20, low12 & 0xfff); // Addi/Jalr/Load + Assembler::patch(instruction_address + (MacroAssembler::instruction_size * 4), 31, 20, low12 & 0xfff); // Addi/Jalr/Load assert(MacroAssembler::target_addr_for_insn(instruction_address) == target, "Must be"); - return NativeMovConstReg::movptr2_instruction_size; + return MacroAssembler::movptr2_instruction_size; } static int patch_imm_in_li64(address branch, address target) { @@ -1473,12 +1604,12 @@ static int patch_imm_in_li64(address branch, address target) { Assembler::patch(branch + 12, 31, 20, ((int32_t)lower >> 20) & 0xfff); // Addi. Assembler::patch(branch + 20, 31, 20, (((intptr_t)target << 44) >> 52) & 0xfff); // Addi. Assembler::patch(branch + 28, 31, 20, (intptr_t)target & 0xff); // Addi. - return LI64_INSTRUCTIONS_NUM * NativeInstruction::instruction_size; + return LI64_INSTRUCTIONS_NUM * MacroAssembler::instruction_size; } static int patch_imm_in_li16u(address branch, uint16_t target) { Assembler::patch(branch, 31, 12, target); // patch lui only - return NativeInstruction::instruction_size; + return MacroAssembler::instruction_size; } int MacroAssembler::patch_imm_in_li32(address branch, int32_t target) { @@ -1489,7 +1620,7 @@ int MacroAssembler::patch_imm_in_li32(address branch, int32_t target) { upper = (int32_t)upper; Assembler::patch(branch + 0, 31, 12, (upper >> 12) & 0xfffff); // Lui. Assembler::patch(branch + 4, 31, 20, lower & 0xfff); // Addiw. - return LI32_INSTRUCTIONS_NUM * NativeInstruction::instruction_size; + return LI32_INSTRUCTIONS_NUM * MacroAssembler::instruction_size; } static long get_offset_of_jal(address insn_addr) { @@ -1537,11 +1668,11 @@ static address get_target_of_movptr1(address insn_addr) { static address get_target_of_movptr2(address insn_addr) { assert_cond(insn_addr != nullptr); - int32_t upper18 = ((Assembler::sextract(Assembler::ld_instr(insn_addr + NativeInstruction::instruction_size * 0), 31, 12)) & 0xfffff); // Lui - int32_t mid18 = ((Assembler::sextract(Assembler::ld_instr(insn_addr + NativeInstruction::instruction_size * 1), 31, 12)) & 0xfffff); // Lui + int32_t upper18 = ((Assembler::sextract(Assembler::ld_instr(insn_addr + MacroAssembler::instruction_size * 0), 31, 12)) & 0xfffff); // Lui + int32_t mid18 = ((Assembler::sextract(Assembler::ld_instr(insn_addr + MacroAssembler::instruction_size * 1), 31, 12)) & 0xfffff); // Lui // 2 // Slli // 3 // Add - int32_t low12 = ((Assembler::sextract(Assembler::ld_instr(insn_addr + NativeInstruction::instruction_size * 4), 31, 20))); // Addi/Jalr/Load. + int32_t low12 = ((Assembler::sextract(Assembler::ld_instr(insn_addr + MacroAssembler::instruction_size * 4), 31, 20))); // Addi/Jalr/Load. address ret = (address)(((intptr_t)upper18<<30ll) + ((intptr_t)mid18<<12ll) + low12); return ret; } @@ -1568,22 +1699,22 @@ address MacroAssembler::get_target_of_li32(address insn_addr) { int MacroAssembler::pd_patch_instruction_size(address instruction_address, address target) { assert_cond(instruction_address != nullptr); int64_t offset = target - instruction_address; - if (NativeInstruction::is_jal_at(instruction_address)) { // jal + if (MacroAssembler::is_jal_at(instruction_address)) { // jal return patch_offset_in_jal(instruction_address, offset); - } else if (NativeInstruction::is_branch_at(instruction_address)) { // beq/bge/bgeu/blt/bltu/bne + } else if (MacroAssembler::is_branch_at(instruction_address)) { // beq/bge/bgeu/blt/bltu/bne return patch_offset_in_conditional_branch(instruction_address, offset); - } else if (NativeInstruction::is_pc_relative_at(instruction_address)) { // auipc, addi/jalr/load + } else if (MacroAssembler::is_pc_relative_at(instruction_address)) { // auipc, addi/jalr/load return patch_offset_in_pc_relative(instruction_address, offset); - } else if (NativeInstruction::is_movptr1_at(instruction_address)) { // movptr1 + } else if (MacroAssembler::is_movptr1_at(instruction_address)) { // movptr1 return patch_addr_in_movptr1(instruction_address, target); - } else if (NativeInstruction::is_movptr2_at(instruction_address)) { // movptr2 + } else if (MacroAssembler::is_movptr2_at(instruction_address)) { // movptr2 return patch_addr_in_movptr2(instruction_address, target); - } else if (NativeInstruction::is_li64_at(instruction_address)) { // li64 + } else if (MacroAssembler::is_li64_at(instruction_address)) { // li64 return patch_imm_in_li64(instruction_address, target); - } else if (NativeInstruction::is_li32_at(instruction_address)) { // li32 + } else if (MacroAssembler::is_li32_at(instruction_address)) { // li32 int64_t imm = (intptr_t)target; return patch_imm_in_li32(instruction_address, (int32_t)imm); - } else if (NativeInstruction::is_li16u_at(instruction_address)) { + } else if (MacroAssembler::is_li16u_at(instruction_address)) { int64_t imm = (intptr_t)target; return patch_imm_in_li16u(instruction_address, (uint16_t)imm); } else { @@ -1600,19 +1731,19 @@ int MacroAssembler::pd_patch_instruction_size(address instruction_address, addre address MacroAssembler::target_addr_for_insn(address insn_addr) { long offset = 0; assert_cond(insn_addr != nullptr); - if (NativeInstruction::is_jal_at(insn_addr)) { // jal + if (MacroAssembler::is_jal_at(insn_addr)) { // jal offset = get_offset_of_jal(insn_addr); - } else if (NativeInstruction::is_branch_at(insn_addr)) { // beq/bge/bgeu/blt/bltu/bne + } else if (MacroAssembler::is_branch_at(insn_addr)) { // beq/bge/bgeu/blt/bltu/bne offset = get_offset_of_conditional_branch(insn_addr); - } else if (NativeInstruction::is_pc_relative_at(insn_addr)) { // auipc, addi/jalr/load + } else if (MacroAssembler::is_pc_relative_at(insn_addr)) { // auipc, addi/jalr/load offset = get_offset_of_pc_relative(insn_addr); - } else if (NativeInstruction::is_movptr1_at(insn_addr)) { // movptr1 + } else if (MacroAssembler::is_movptr1_at(insn_addr)) { // movptr1 return get_target_of_movptr1(insn_addr); - } else if (NativeInstruction::is_movptr2_at(insn_addr)) { // movptr2 + } else if (MacroAssembler::is_movptr2_at(insn_addr)) { // movptr2 return get_target_of_movptr2(insn_addr); - } else if (NativeInstruction::is_li64_at(insn_addr)) { // li64 + } else if (MacroAssembler::is_li64_at(insn_addr)) { // li64 return get_target_of_li64(insn_addr); - } else if (NativeInstruction::is_li32_at(insn_addr)) { // li32 + } else if (MacroAssembler::is_li32_at(insn_addr)) { // li32 return get_target_of_li32(insn_addr); } else { ShouldNotReachHere(); @@ -1624,14 +1755,14 @@ int MacroAssembler::patch_oop(address insn_addr, address o) { // OOPs are either narrow (32 bits) or wide (48 bits). We encode // narrow OOPs by setting the upper 16 bits in the first // instruction. - if (NativeInstruction::is_li32_at(insn_addr)) { + if (MacroAssembler::is_li32_at(insn_addr)) { // Move narrow OOP uint32_t n = CompressedOops::narrow_oop_value(cast_to_oop(o)); return patch_imm_in_li32(insn_addr, (int32_t)n); - } else if (NativeInstruction::is_movptr1_at(insn_addr)) { + } else if (MacroAssembler::is_movptr1_at(insn_addr)) { // Move wide OOP return patch_addr_in_movptr1(insn_addr, o); - } else if (NativeInstruction::is_movptr2_at(insn_addr)) { + } else if (MacroAssembler::is_movptr2_at(insn_addr)) { // Move wide OOP return patch_addr_in_movptr2(insn_addr, o); } @@ -2779,14 +2910,13 @@ void MacroAssembler::lookup_virtual_method(Register recv_klass, } void MacroAssembler::membar(uint32_t order_constraint) { - address prev = pc() - NativeMembar::instruction_size; + address prev = pc() - MacroAssembler::instruction_size; address last = code()->last_insn(); - if (last != nullptr && nativeInstruction_at(last)->is_membar() && prev == last) { - NativeMembar *bar = NativeMembar_at(prev); + if (last != nullptr && is_membar(last) && prev == last) { // We are merging two memory barrier instructions. On RISCV we // can do this simply by ORing them together. - bar->set_kind(bar->get_kind() | order_constraint); + set_membar_kind(prev, get_membar_kind(prev) | order_constraint); BLOCK_COMMENT("merged membar"); } else { code()->set_last_insn(pc()); @@ -3653,7 +3783,7 @@ address MacroAssembler::ic_call(address entry, jint method_index) { int MacroAssembler::ic_check_size() { // No compressed - return (NativeInstruction::instruction_size * (2 /* 2 loads */ + 1 /* branch */)) + + return (MacroAssembler::instruction_size * (2 /* 2 loads */ + 1 /* branch */)) + far_branch_size(); } @@ -3720,7 +3850,7 @@ address MacroAssembler::emit_trampoline_stub(int insts_call_instruction_offset, // instructions code-section. // Make sure the address of destination 8-byte aligned after 3 instructions. - align(wordSize, NativeCallTrampolineStub::data_offset); + align(wordSize, MacroAssembler::trampoline_stub_data_offset); RelocationHolder rh = trampoline_stub_Relocation::spec(code()->insts()->start() + insts_call_instruction_offset); @@ -3733,7 +3863,7 @@ address MacroAssembler::emit_trampoline_stub(int insts_call_instruction_offset, ld(t0, target); // auipc + ld jr(t0); // jalr bind(target); - assert(offset() - stub_start_offset == NativeCallTrampolineStub::data_offset, + assert(offset() - stub_start_offset == MacroAssembler::trampoline_stub_data_offset, "should be"); assert(offset() % wordSize == 0, "bad alignment"); emit_int64((int64_t)dest); @@ -3741,7 +3871,7 @@ address MacroAssembler::emit_trampoline_stub(int insts_call_instruction_offset, const address stub_start_addr = addr_at(stub_start_offset); - assert(is_NativeCallTrampolineStub_at(stub_start_addr), "doesn't look like a trampoline"); + assert(MacroAssembler::is_trampoline_stub_at(stub_start_addr), "doesn't look like a trampoline"); end_a_stub(); return stub_start_addr; @@ -3749,12 +3879,12 @@ address MacroAssembler::emit_trampoline_stub(int insts_call_instruction_offset, int MacroAssembler::max_trampoline_stub_size() { // Max stub size: alignment nop, TrampolineStub. - return NativeInstruction::instruction_size + NativeCallTrampolineStub::instruction_size; + return MacroAssembler::instruction_size + MacroAssembler::trampoline_stub_instruction_size; } int MacroAssembler::static_call_stub_size() { // (lui, addi, slli, addi, slli, addi) + (lui + lui + slli + add) + jalr - return 11 * NativeInstruction::instruction_size; + return 11 * MacroAssembler::instruction_size; } Address MacroAssembler::add_memory_helper(const Address dst, Register tmp) { diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index e5800b0aa916d..4e9a41625ad46 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -30,7 +30,6 @@ #include "asm/assembler.inline.hpp" #include "code/vmreg.hpp" #include "metaprogramming/enableIf.hpp" -#include "nativeInst_riscv.hpp" #include "oops/compressedOops.hpp" #include "utilities/powerOfTwo.hpp" @@ -42,6 +41,7 @@ class MacroAssembler: public Assembler { public: + MacroAssembler(CodeBuffer* code) : Assembler(code) {} void safepoint_poll(Label& slow_path, bool at_return, bool acquire, bool in_nmethod); @@ -49,7 +49,7 @@ class MacroAssembler: public Assembler { // Alignment int align(int modulus, int extra_offset = 0); - static inline void assert_alignment(address pc, int alignment = NativeInstruction::instruction_size) { + static inline void assert_alignment(address pc, int alignment = MacroAssembler::instruction_size) { assert(is_aligned(pc, alignment), "bad alignment"); } @@ -1232,7 +1232,7 @@ class MacroAssembler: public Assembler { address ic_call(address entry, jint method_index = 0); static int ic_check_size(); - int ic_check(int end_alignment = NativeInstruction::instruction_size); + int ic_check(int end_alignment = MacroAssembler::instruction_size); // Support for memory inc/dec // n.b. increment/decrement calls with an Address destination will @@ -1542,6 +1542,226 @@ class MacroAssembler: public Assembler { public: void lightweight_lock(Register obj, Register tmp1, Register tmp2, Register tmp3, Label& slow); void lightweight_unlock(Register obj, Register tmp1, Register tmp2, Register tmp3, Label& slow); + +public: + enum { + // Refer to function emit_trampoline_stub. + trampoline_stub_instruction_size = 3 * instruction_size + wordSize, // auipc + ld + jr + target address + trampoline_stub_data_offset = 3 * instruction_size, // auipc + ld + jr + + // movptr + movptr1_instruction_size = 6 * instruction_size, // lui, addi, slli, addi, slli, addi. See movptr1(). + movptr2_instruction_size = 5 * instruction_size, // lui, lui, slli, add, addi. See movptr2(). + load_pc_relative_instruction_size = 2 * instruction_size // auipc, ld + }; + + static bool is_load_pc_relative_at(address branch); + static bool is_li16u_at(address instr); + + static bool is_trampoline_stub_at(address addr) { + // Ensure that the stub is exactly + // ld t0, L--->auipc + ld + // jr t0 + // L: + + // judge inst + register + imm + // 1). check the instructions: auipc + ld + jalr + // 2). check if auipc[11:7] == t0 and ld[11:7] == t0 and ld[19:15] == t0 && jr[19:15] == t0 + // 3). check if the offset in ld[31:20] equals the data_offset + assert_cond(addr != nullptr); + const int instr_size = instruction_size; + if (is_auipc_at(addr) && + is_ld_at(addr + instr_size) && + is_jalr_at(addr + 2 * instr_size) && + (extract_rd(addr) == x5) && + (extract_rd(addr + instr_size) == x5) && + (extract_rs1(addr + instr_size) == x5) && + (extract_rs1(addr + 2 * instr_size) == x5) && + (Assembler::extract(Assembler::ld_instr(addr + 4), 31, 20) == trampoline_stub_data_offset)) { + return true; + } + return false; + } + + static bool is_call_at(address instr) { + if (is_jal_at(instr) || is_jalr_at(instr)) { + return true; + } + return false; + } + + static bool is_jal_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b1101111; } + static bool is_jalr_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b1100111 && extract_funct3(instr) == 0b000; } + static bool is_branch_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b1100011; } + static bool is_ld_at(address instr) { assert_cond(instr != nullptr); return is_load_at(instr) && extract_funct3(instr) == 0b011; } + static bool is_load_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b0000011; } + static bool is_float_load_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b0000111; } + static bool is_auipc_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b0010111; } + static bool is_jump_at(address instr) { assert_cond(instr != nullptr); return is_branch_at(instr) || is_jal_at(instr) || is_jalr_at(instr); } + static bool is_add_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b0110011 && extract_funct3(instr) == 0b000; } + static bool is_addi_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b0010011 && extract_funct3(instr) == 0b000; } + static bool is_addiw_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b0011011 && extract_funct3(instr) == 0b000; } + static bool is_addiw_to_zr_at(address instr){ assert_cond(instr != nullptr); return is_addiw_at(instr) && extract_rd(instr) == zr; } + static bool is_lui_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b0110111; } + static bool is_lui_to_zr_at(address instr) { assert_cond(instr != nullptr); return is_lui_at(instr) && extract_rd(instr) == zr; } + + static bool is_srli_at(address instr) { + assert_cond(instr != nullptr); + return extract_opcode(instr) == 0b0010011 && + extract_funct3(instr) == 0b101 && + Assembler::extract(((unsigned*)instr)[0], 31, 26) == 0b000000; + } + + static bool is_slli_shift_at(address instr, uint32_t shift) { + assert_cond(instr != nullptr); + return (extract_opcode(instr) == 0b0010011 && // opcode field + extract_funct3(instr) == 0b001 && // funct3 field, select the type of operation + Assembler::extract(Assembler::ld_instr(instr), 25, 20) == shift); // shamt field + } + + static bool is_movptr1_at(address instr); + static bool is_movptr2_at(address instr); + + static bool is_lwu_to_zr(address instr); + +private: + static Register extract_rs1(address instr); + static Register extract_rs2(address instr); + static Register extract_rd(address instr); + static uint32_t extract_opcode(address instr); + static uint32_t extract_funct3(address instr); + + // the instruction sequence of movptr is as below: + // lui + // addi + // slli + // addi + // slli + // addi/jalr/load + static bool check_movptr1_data_dependency(address instr) { + address lui = instr; + address addi1 = lui + instruction_size; + address slli1 = addi1 + instruction_size; + address addi2 = slli1 + instruction_size; + address slli2 = addi2 + instruction_size; + address last_instr = slli2 + instruction_size; + return extract_rs1(addi1) == extract_rd(lui) && + extract_rs1(addi1) == extract_rd(addi1) && + extract_rs1(slli1) == extract_rd(addi1) && + extract_rs1(slli1) == extract_rd(slli1) && + extract_rs1(addi2) == extract_rd(slli1) && + extract_rs1(addi2) == extract_rd(addi2) && + extract_rs1(slli2) == extract_rd(addi2) && + extract_rs1(slli2) == extract_rd(slli2) && + extract_rs1(last_instr) == extract_rd(slli2); + } + + // the instruction sequence of movptr2 is as below: + // lui + // lui + // slli + // add + // addi/jalr/load + static bool check_movptr2_data_dependency(address instr) { + address lui1 = instr; + address lui2 = lui1 + instruction_size; + address slli = lui2 + instruction_size; + address add = slli + instruction_size; + address last_instr = add + instruction_size; + return extract_rd(add) == extract_rd(lui2) && + extract_rs1(add) == extract_rd(lui2) && + extract_rs2(add) == extract_rd(slli) && + extract_rs1(slli) == extract_rd(lui1) && + extract_rd(slli) == extract_rd(lui1) && + extract_rs1(last_instr) == extract_rd(add); + } + + // the instruction sequence of li64 is as below: + // lui + // addi + // slli + // addi + // slli + // addi + // slli + // addi + static bool check_li64_data_dependency(address instr) { + address lui = instr; + address addi1 = lui + instruction_size; + address slli1 = addi1 + instruction_size; + address addi2 = slli1 + instruction_size; + address slli2 = addi2 + instruction_size; + address addi3 = slli2 + instruction_size; + address slli3 = addi3 + instruction_size; + address addi4 = slli3 + instruction_size; + return extract_rs1(addi1) == extract_rd(lui) && + extract_rs1(addi1) == extract_rd(addi1) && + extract_rs1(slli1) == extract_rd(addi1) && + extract_rs1(slli1) == extract_rd(slli1) && + extract_rs1(addi2) == extract_rd(slli1) && + extract_rs1(addi2) == extract_rd(addi2) && + extract_rs1(slli2) == extract_rd(addi2) && + extract_rs1(slli2) == extract_rd(slli2) && + extract_rs1(addi3) == extract_rd(slli2) && + extract_rs1(addi3) == extract_rd(addi3) && + extract_rs1(slli3) == extract_rd(addi3) && + extract_rs1(slli3) == extract_rd(slli3) && + extract_rs1(addi4) == extract_rd(slli3) && + extract_rs1(addi4) == extract_rd(addi4); + } + + // the instruction sequence of li16u is as below: + // lui + // srli + static bool check_li16u_data_dependency(address instr) { + address lui = instr; + address srli = lui + instruction_size; + + return extract_rs1(srli) == extract_rd(lui) && + extract_rs1(srli) == extract_rd(srli); + } + + // the instruction sequence of li32 is as below: + // lui + // addiw + static bool check_li32_data_dependency(address instr) { + address lui = instr; + address addiw = lui + instruction_size; + + return extract_rs1(addiw) == extract_rd(lui) && + extract_rs1(addiw) == extract_rd(addiw); + } + + // the instruction sequence of pc-relative is as below: + // auipc + // jalr/addi/load/float_load + static bool check_pc_relative_data_dependency(address instr) { + address auipc = instr; + address last_instr = auipc + instruction_size; + + return extract_rs1(last_instr) == extract_rd(auipc); + } + + // the instruction sequence of load_label is as below: + // auipc + // load + static bool check_load_pc_relative_data_dependency(address instr) { + address auipc = instr; + address load = auipc + instruction_size; + + return extract_rd(load) == extract_rd(auipc) && + extract_rs1(load) == extract_rd(load); + } + + static bool is_li32_at(address instr); + static bool is_li64_at(address instr); + static bool is_pc_relative_at(address branch); + + static bool is_membar(address addr) { + return (Bytes::get_native_u4(addr) & 0x7f) == 0b1111 && extract_funct3(addr) == 0; + } + static uint32_t get_membar_kind(address addr); + static void set_membar_kind(address addr, uint32_t order_kind); }; #ifdef ASSERT diff --git a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp index dd54329e521d5..348a00b6767f9 100644 --- a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp +++ b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp @@ -39,112 +39,20 @@ #include "c1/c1_Runtime1.hpp" #endif -Register NativeInstruction::extract_rs1(address instr) { - assert_cond(instr != nullptr); - return as_Register(Assembler::extract(Assembler::ld_instr(instr), 19, 15)); -} - -Register NativeInstruction::extract_rs2(address instr) { - assert_cond(instr != nullptr); - return as_Register(Assembler::extract(Assembler::ld_instr(instr), 24, 20)); -} - -Register NativeInstruction::extract_rd(address instr) { - assert_cond(instr != nullptr); - return as_Register(Assembler::extract(Assembler::ld_instr(instr), 11, 7)); -} - -uint32_t NativeInstruction::extract_opcode(address instr) { - assert_cond(instr != nullptr); - return Assembler::extract(Assembler::ld_instr(instr), 6, 0); -} - -uint32_t NativeInstruction::extract_funct3(address instr) { - assert_cond(instr != nullptr); - return Assembler::extract(Assembler::ld_instr(instr), 14, 12); -} - -bool NativeInstruction::is_pc_relative_at(address instr) { - // auipc + jalr - // auipc + addi - // auipc + load - // auipc + fload_load - return (is_auipc_at(instr)) && - (is_addi_at(instr + instruction_size) || - is_jalr_at(instr + instruction_size) || - is_load_at(instr + instruction_size) || - is_float_load_at(instr + instruction_size)) && - check_pc_relative_data_dependency(instr); -} - -// ie:ld(Rd, Label) -bool NativeInstruction::is_load_pc_relative_at(address instr) { - return is_auipc_at(instr) && // auipc - is_ld_at(instr + instruction_size) && // ld - check_load_pc_relative_data_dependency(instr); -} - -bool NativeInstruction::is_movptr1_at(address instr) { - return is_lui_at(instr) && // Lui - is_addi_at(instr + instruction_size) && // Addi - is_slli_shift_at(instr + instruction_size * 2, 11) && // Slli Rd, Rs, 11 - is_addi_at(instr + instruction_size * 3) && // Addi - is_slli_shift_at(instr + instruction_size * 4, 6) && // Slli Rd, Rs, 6 - (is_addi_at(instr + instruction_size * 5) || - is_jalr_at(instr + instruction_size * 5) || - is_load_at(instr + instruction_size * 5)) && // Addi/Jalr/Load - check_movptr1_data_dependency(instr); -} - -bool NativeInstruction::is_movptr2_at(address instr) { - return is_lui_at(instr) && // lui - is_lui_at(instr + instruction_size) && // lui - is_slli_shift_at(instr + instruction_size * 2, 18) && // slli Rd, Rs, 18 - is_add_at(instr + instruction_size * 3) && - (is_addi_at(instr + instruction_size * 4) || - is_jalr_at(instr + instruction_size * 4) || - is_load_at(instr + instruction_size * 4)) && // Addi/Jalr/Load - check_movptr2_data_dependency(instr); -} - -bool NativeInstruction::is_li16u_at(address instr) { - return is_lui_at(instr) && // lui - is_srli_at(instr + instruction_size) && // srli - check_li16u_data_dependency(instr); -} - -bool NativeInstruction::is_li32_at(address instr) { - return is_lui_at(instr) && // lui - is_addiw_at(instr + instruction_size) && // addiw - check_li32_data_dependency(instr); -} - -bool NativeInstruction::is_li64_at(address instr) { - return is_lui_at(instr) && // lui - is_addi_at(instr + instruction_size) && // addi - is_slli_shift_at(instr + instruction_size * 2, 12) && // Slli Rd, Rs, 12 - is_addi_at(instr + instruction_size * 3) && // addi - is_slli_shift_at(instr + instruction_size * 4, 12) && // Slli Rd, Rs, 12 - is_addi_at(instr + instruction_size * 5) && // addi - is_slli_shift_at(instr + instruction_size * 6, 8) && // Slli Rd, Rs, 8 - is_addi_at(instr + instruction_size * 7) && // addi - check_li64_data_dependency(instr); -} - void NativeCall::verify() { - assert(NativeCall::is_call_at((address)this), "unexpected code at call site"); + assert(MacroAssembler::is_call_at((address)this), "unexpected code at call site"); } address NativeCall::destination() const { address addr = (address)this; - assert(NativeInstruction::is_jal_at(instruction_address()), "inst must be jal."); + assert(MacroAssembler::is_jal_at(instruction_address()), "inst must be jal."); address destination = MacroAssembler::target_addr_for_insn(instruction_address()); // Do we use a trampoline stub for this call? CodeBlob* cb = CodeCache::find_blob(addr); assert(cb && cb->is_nmethod(), "sanity"); nmethod *nm = (nmethod *)cb; - if (nm != nullptr && nm->stub_contains(destination) && is_NativeCallTrampolineStub_at(destination)) { + if (nm != nullptr && nm->stub_contains(destination) && MacroAssembler::is_trampoline_stub_at(destination)) { // Yes we do, so get the destination from the trampoline stub. const address trampoline_stub_addr = destination; destination = nativeCallTrampolineStub_at(trampoline_stub_addr)->destination(); @@ -168,12 +76,12 @@ void NativeCall::set_destination_mt_safe(address dest, bool assert_lock) { "concurrent code patching"); address addr_call = addr_at(0); - assert(NativeCall::is_call_at(addr_call), "unexpected code at call site"); + assert(MacroAssembler::is_call_at(addr_call), "unexpected code at call site"); // Patch the constant in the call's trampoline stub. address trampoline_stub_addr = get_trampoline(); if (trampoline_stub_addr != nullptr) { - assert (!is_NativeCallTrampolineStub_at(dest), "chained trampolines"); + assert (!MacroAssembler::is_trampoline_stub_at(dest), "chained trampolines"); nativeCallTrampolineStub_at(trampoline_stub_addr)->set_destination(dest); } @@ -195,7 +103,7 @@ address NativeCall::get_trampoline() { assert(code != nullptr, "Could not find the containing code blob"); address jal_destination = MacroAssembler::pd_call_destination(call_addr); - if (code != nullptr && code->contains(jal_destination) && is_NativeCallTrampolineStub_at(jal_destination)) { + if (code != nullptr && code->contains(jal_destination) && MacroAssembler::is_trampoline_stub_at(jal_destination)) { return jal_destination; } @@ -341,14 +249,7 @@ address NativeGeneralJump::jump_destination() const { //------------------------------------------------------------------- bool NativeInstruction::is_safepoint_poll() { - return is_lwu_to_zr(address(this)); -} - -bool NativeInstruction::is_lwu_to_zr(address instr) { - assert_cond(instr != nullptr); - return (extract_opcode(instr) == 0b0000011 && - extract_funct3(instr) == 0b110 && - extract_rd(instr) == zr); // zr + return MacroAssembler::is_lwu_to_zr(address(this)); } // A 16-bit instruction with all bits ones is permanently reserved as an illegal instruction. @@ -435,30 +336,6 @@ void NativeCallTrampolineStub::set_destination(address new_destination) { OrderAccess::release(); } -uint32_t NativeMembar::get_kind() { - uint32_t insn = uint_at(0); - - uint32_t predecessor = Assembler::extract(insn, 27, 24); - uint32_t successor = Assembler::extract(insn, 23, 20); - - return MacroAssembler::pred_succ_to_membar_mask(predecessor, successor); -} - -void NativeMembar::set_kind(uint32_t order_kind) { - uint32_t predecessor = 0; - uint32_t successor = 0; - - MacroAssembler::membar_mask_to_pred_succ(order_kind, predecessor, successor); - - uint32_t insn = uint_at(0); - address pInsn = (address) &insn; - Assembler::patch(pInsn, 27, 24, predecessor); - Assembler::patch(pInsn, 23, 20, successor); - - address membar = addr_at(0); - Assembler::sd_instr(membar, insn); -} - void NativePostCallNop::make_deopt() { MacroAssembler::assert_alignment(addr_at(0)); NativeDeoptInstruction::insert(addr_at(0)); @@ -481,7 +358,7 @@ bool NativePostCallNop::patch(int32_t oopmap_slot, int32_t cb_offset) { } int32_t data = (oopmap_slot << 24) | cb_offset; assert(data != 0, "must be"); - assert(is_lui_to_zr_at(addr_at(4)) && is_addiw_to_zr_at(addr_at(8)), "must be"); + assert(MacroAssembler::is_lui_to_zr_at(addr_at(4)) && MacroAssembler::is_addiw_to_zr_at(addr_at(8)), "must be"); MacroAssembler::patch_imm_in_li32(addr_at(4), data); return true; // successfully encoded diff --git a/src/hotspot/cpu/riscv/nativeInst_riscv.hpp b/src/hotspot/cpu/riscv/nativeInst_riscv.hpp index dcdf525aafb9e..e9b3624d9d29d 100644 --- a/src/hotspot/cpu/riscv/nativeInst_riscv.hpp +++ b/src/hotspot/cpu/riscv/nativeInst_riscv.hpp @@ -27,6 +27,7 @@ #ifndef CPU_RISCV_NATIVEINST_RISCV_HPP #define CPU_RISCV_NATIVEINST_RISCV_HPP +#include "macroAssembler_riscv.hpp" #include "asm/assembler.hpp" #include "runtime/continuation.hpp" #include "runtime/icache.hpp" @@ -52,198 +53,24 @@ class NativeCall; class NativeInstruction { friend class Relocation; - friend bool is_NativeCallTrampolineStub_at(address); public: enum { - instruction_size = 4, - compressed_instruction_size = 2, + instruction_size = MacroAssembler::instruction_size, + compressed_instruction_size = MacroAssembler::compressed_instruction_size, }; juint encoding() const { return uint_at(0); } - bool is_jal() const { return is_jal_at(addr_at(0)); } - bool is_movptr() const { return is_movptr1_at(addr_at(0)) || - is_movptr2_at(addr_at(0)); } - bool is_movptr1() const { return is_movptr1_at(addr_at(0)); } - bool is_movptr2() const { return is_movptr2_at(addr_at(0)); } - bool is_auipc() const { return is_auipc_at(addr_at(0)); } - bool is_call() const { return is_call_at(addr_at(0)); } - bool is_jump() const { return is_jump_at(addr_at(0)); } - - static bool is_jal_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b1101111; } - static bool is_jalr_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b1100111 && extract_funct3(instr) == 0b000; } - static bool is_branch_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b1100011; } - static bool is_ld_at(address instr) { assert_cond(instr != nullptr); return is_load_at(instr) && extract_funct3(instr) == 0b011; } - static bool is_load_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b0000011; } - static bool is_float_load_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b0000111; } - static bool is_auipc_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b0010111; } - static bool is_jump_at(address instr) { assert_cond(instr != nullptr); return is_branch_at(instr) || is_jal_at(instr) || is_jalr_at(instr); } - static bool is_add_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b0110011 && extract_funct3(instr) == 0b000; } - static bool is_addi_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b0010011 && extract_funct3(instr) == 0b000; } - static bool is_addiw_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b0011011 && extract_funct3(instr) == 0b000; } - static bool is_addiw_to_zr_at(address instr){ assert_cond(instr != nullptr); return is_addiw_at(instr) && extract_rd(instr) == zr; } - static bool is_lui_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b0110111; } - static bool is_lui_to_zr_at(address instr) { assert_cond(instr != nullptr); return is_lui_at(instr) && extract_rd(instr) == zr; } - - static bool is_srli_at(address instr) { - assert_cond(instr != nullptr); - return extract_opcode(instr) == 0b0010011 && - extract_funct3(instr) == 0b101 && - Assembler::extract(((unsigned*)instr)[0], 31, 26) == 0b000000; - } - - static bool is_slli_shift_at(address instr, uint32_t shift) { - assert_cond(instr != nullptr); - return (extract_opcode(instr) == 0b0010011 && // opcode field - extract_funct3(instr) == 0b001 && // funct3 field, select the type of operation - Assembler::extract(Assembler::ld_instr(instr), 25, 20) == shift); // shamt field - } - - static Register extract_rs1(address instr); - static Register extract_rs2(address instr); - static Register extract_rd(address instr); - static uint32_t extract_opcode(address instr); - static uint32_t extract_funct3(address instr); - - // the instruction sequence of movptr is as below: - // lui - // addi - // slli - // addi - // slli - // addi/jalr/load - static bool check_movptr1_data_dependency(address instr) { - address lui = instr; - address addi1 = lui + instruction_size; - address slli1 = addi1 + instruction_size; - address addi2 = slli1 + instruction_size; - address slli2 = addi2 + instruction_size; - address last_instr = slli2 + instruction_size; - return extract_rs1(addi1) == extract_rd(lui) && - extract_rs1(addi1) == extract_rd(addi1) && - extract_rs1(slli1) == extract_rd(addi1) && - extract_rs1(slli1) == extract_rd(slli1) && - extract_rs1(addi2) == extract_rd(slli1) && - extract_rs1(addi2) == extract_rd(addi2) && - extract_rs1(slli2) == extract_rd(addi2) && - extract_rs1(slli2) == extract_rd(slli2) && - extract_rs1(last_instr) == extract_rd(slli2); - } - - // the instruction sequence of movptr2 is as below: - // lui - // lui - // slli - // add - // addi/jalr/load - static bool check_movptr2_data_dependency(address instr) { - address lui1 = instr; - address lui2 = lui1 + instruction_size; - address slli = lui2 + instruction_size; - address add = slli + instruction_size; - address last_instr = add + instruction_size; - return extract_rd(add) == extract_rd(lui2) && - extract_rs1(add) == extract_rd(lui2) && - extract_rs2(add) == extract_rd(slli) && - extract_rs1(slli) == extract_rd(lui1) && - extract_rd(slli) == extract_rd(lui1) && - extract_rs1(last_instr) == extract_rd(add); - } - - // the instruction sequence of li64 is as below: - // lui - // addi - // slli - // addi - // slli - // addi - // slli - // addi - static bool check_li64_data_dependency(address instr) { - address lui = instr; - address addi1 = lui + instruction_size; - address slli1 = addi1 + instruction_size; - address addi2 = slli1 + instruction_size; - address slli2 = addi2 + instruction_size; - address addi3 = slli2 + instruction_size; - address slli3 = addi3 + instruction_size; - address addi4 = slli3 + instruction_size; - return extract_rs1(addi1) == extract_rd(lui) && - extract_rs1(addi1) == extract_rd(addi1) && - extract_rs1(slli1) == extract_rd(addi1) && - extract_rs1(slli1) == extract_rd(slli1) && - extract_rs1(addi2) == extract_rd(slli1) && - extract_rs1(addi2) == extract_rd(addi2) && - extract_rs1(slli2) == extract_rd(addi2) && - extract_rs1(slli2) == extract_rd(slli2) && - extract_rs1(addi3) == extract_rd(slli2) && - extract_rs1(addi3) == extract_rd(addi3) && - extract_rs1(slli3) == extract_rd(addi3) && - extract_rs1(slli3) == extract_rd(slli3) && - extract_rs1(addi4) == extract_rd(slli3) && - extract_rs1(addi4) == extract_rd(addi4); - } - - // the instruction sequence of li16u is as below: - // lui - // srli - static bool check_li16u_data_dependency(address instr) { - address lui = instr; - address srli = lui + instruction_size; - - return extract_rs1(srli) == extract_rd(lui) && - extract_rs1(srli) == extract_rd(srli); - } - - // the instruction sequence of li32 is as below: - // lui - // addiw - static bool check_li32_data_dependency(address instr) { - address lui = instr; - address addiw = lui + instruction_size; - - return extract_rs1(addiw) == extract_rd(lui) && - extract_rs1(addiw) == extract_rd(addiw); - } - - // the instruction sequence of pc-relative is as below: - // auipc - // jalr/addi/load/float_load - static bool check_pc_relative_data_dependency(address instr) { - address auipc = instr; - address last_instr = auipc + instruction_size; - - return extract_rs1(last_instr) == extract_rd(auipc); - } - - // the instruction sequence of load_label is as below: - // auipc - // load - static bool check_load_pc_relative_data_dependency(address instr) { - address auipc = instr; - address load = auipc + instruction_size; - - return extract_rd(load) == extract_rd(auipc) && - extract_rs1(load) == extract_rd(load); - } - - static bool is_movptr1_at(address instr); - static bool is_movptr2_at(address instr); - static bool is_li16u_at(address instr); - static bool is_li32_at(address instr); - static bool is_li64_at(address instr); - static bool is_pc_relative_at(address branch); - static bool is_load_pc_relative_at(address branch); - - static bool is_call_at(address instr) { - if (is_jal_at(instr) || is_jalr_at(instr)) { - return true; - } - return false; - } - static bool is_lwu_to_zr(address instr); + bool is_jal() const { return MacroAssembler::is_jal_at(addr_at(0)); } + bool is_movptr() const { return MacroAssembler::is_movptr1_at(addr_at(0)) || + MacroAssembler::is_movptr2_at(addr_at(0)); } + bool is_movptr1() const { return MacroAssembler::is_movptr1_at(addr_at(0)); } + bool is_movptr2() const { return MacroAssembler::is_movptr2_at(addr_at(0)); } + bool is_auipc() const { return MacroAssembler::is_auipc_at(addr_at(0)); } + bool is_call() const { return MacroAssembler::is_call_at(addr_at(0)); } + bool is_jump() const { return MacroAssembler::is_jump_at(addr_at(0)); } inline bool is_nop() const; inline bool is_jump_or_nop(); @@ -272,11 +99,7 @@ class NativeInstruction { inline friend NativeInstruction* nativeInstruction_at(address addr); static bool maybe_cpool_ref(address instr) { - return is_auipc_at(instr); - } - - bool is_membar() { - return (uint_at(0) & 0x7f) == 0b1111 && extract_funct3(addr_at(0)) == 0; + return MacroAssembler::is_auipc_at(instr); } }; @@ -332,7 +155,7 @@ class NativeCall: public NativeInstruction { inline friend NativeCall* nativeCall_before(address return_address); static bool is_call_before(address return_address) { - return is_call_at(return_address - NativeCall::return_address_offset); + return MacroAssembler::is_call_at(return_address - NativeCall::return_address_offset); } // MT-safe patching of a call instruction. @@ -377,9 +200,9 @@ inline NativeCall* nativeCall_before(address return_address) { class NativeMovConstReg: public NativeInstruction { public: enum RISCV_specific_constants { - movptr1_instruction_size = 6 * NativeInstruction::instruction_size, // lui, addi, slli, addi, slli, addi. See movptr1(). - movptr2_instruction_size = 5 * NativeInstruction::instruction_size, // lui, lui, slli, add, addi. See movptr2(). - load_pc_relative_instruction_size = 2 * NativeInstruction::instruction_size // auipc, ld + movptr1_instruction_size = MacroAssembler::movptr1_instruction_size, // lui, addi, slli, addi, slli, addi. See movptr1(). + movptr2_instruction_size = MacroAssembler::movptr2_instruction_size, // lui, lui, slli, add, addi. See movptr2(). + load_pc_relative_instruction_size = MacroAssembler::load_pc_relative_instruction_size // auipc, ld }; address instruction_address() const { return addr_at(0); } @@ -389,23 +212,23 @@ class NativeMovConstReg: public NativeInstruction { // and the next instruction address should be addr_at(6 * instruction_size). // However, when the instruction at 5 * instruction_size isn't addi, // the next instruction address should be addr_at(5 * instruction_size) - if (is_movptr1_at(instruction_address())) { - if (is_addi_at(addr_at(movptr1_instruction_size - NativeInstruction::instruction_size))) { + if (MacroAssembler::is_movptr1_at(instruction_address())) { + if (MacroAssembler::is_addi_at(addr_at(movptr1_instruction_size - NativeInstruction::instruction_size))) { // Assume: lui, addi, slli, addi, slli, addi return addr_at(movptr1_instruction_size); } else { // Assume: lui, addi, slli, addi, slli return addr_at(movptr1_instruction_size - NativeInstruction::instruction_size); } - } else if (is_movptr2_at(instruction_address())) { - if (is_addi_at(addr_at(movptr2_instruction_size - NativeInstruction::instruction_size))) { + } else if (MacroAssembler::is_movptr2_at(instruction_address())) { + if (MacroAssembler::is_addi_at(addr_at(movptr2_instruction_size - NativeInstruction::instruction_size))) { // Assume: lui, lui, slli, add, addi return addr_at(movptr2_instruction_size); } else { // Assume: lui, lui, slli, add return addr_at(movptr2_instruction_size - NativeInstruction::instruction_size); } - } else if (is_load_pc_relative_at(instruction_address())) { + } else if (MacroAssembler::is_load_pc_relative_at(instruction_address())) { // Assume: auipc, ld return addr_at(load_pc_relative_instruction_size); } @@ -548,8 +371,8 @@ class NativeCallTrampolineStub : public NativeInstruction { enum RISCV_specific_constants { // Refer to function emit_trampoline_stub. - instruction_size = 3 * NativeInstruction::instruction_size + wordSize, // auipc + ld + jr + target address - data_offset = 3 * NativeInstruction::instruction_size, // auipc + ld + jr + instruction_size = MacroAssembler::trampoline_stub_instruction_size, // auipc + ld + jr + target address + data_offset = MacroAssembler::trampoline_stub_data_offset, // auipc + ld + jr }; address destination(nmethod *nm = nullptr) const; @@ -557,49 +380,12 @@ class NativeCallTrampolineStub : public NativeInstruction { ptrdiff_t destination_offset() const; }; -inline bool is_NativeCallTrampolineStub_at(address addr) { - // Ensure that the stub is exactly - // ld t0, L--->auipc + ld - // jr t0 - // L: - - // judge inst + register + imm - // 1). check the instructions: auipc + ld + jalr - // 2). check if auipc[11:7] == t0 and ld[11:7] == t0 and ld[19:15] == t0 && jr[19:15] == t0 - // 3). check if the offset in ld[31:20] equals the data_offset - assert_cond(addr != nullptr); - const int instr_size = NativeInstruction::instruction_size; - if (NativeInstruction::is_auipc_at(addr) && - NativeInstruction::is_ld_at(addr + instr_size) && - NativeInstruction::is_jalr_at(addr + 2 * instr_size) && - (NativeInstruction::extract_rd(addr) == x5) && - (NativeInstruction::extract_rd(addr + instr_size) == x5) && - (NativeInstruction::extract_rs1(addr + instr_size) == x5) && - (NativeInstruction::extract_rs1(addr + 2 * instr_size) == x5) && - (Assembler::extract(Assembler::ld_instr(addr + 4), 31, 20) == NativeCallTrampolineStub::data_offset)) { - return true; - } - return false; -} - inline NativeCallTrampolineStub* nativeCallTrampolineStub_at(address addr) { assert_cond(addr != nullptr); - assert(is_NativeCallTrampolineStub_at(addr), "no call trampoline found"); + assert(MacroAssembler::is_trampoline_stub_at(addr), "no call trampoline found"); return (NativeCallTrampolineStub*)addr; } -class NativeMembar : public NativeInstruction { -public: - uint32_t get_kind(); - void set_kind(uint32_t order_kind); -}; - -inline NativeMembar *NativeMembar_at(address addr) { - assert_cond(addr != nullptr); - assert(nativeInstruction_at(addr)->is_membar(), "no membar found"); - return (NativeMembar*)addr; -} - // A NativePostCallNop takes the form of three instructions: // nop; lui zr, hi20; addiw zr, lo12 // @@ -613,7 +399,7 @@ class NativePostCallNop: public NativeInstruction { // These instructions only ever appear together in a post-call // NOP, so it's unnecessary to check that the third instruction is // an addiw as well. - return is_nop() && is_lui_to_zr_at(addr_at(4)); + return is_nop() && MacroAssembler::is_lui_to_zr_at(addr_at(4)); } bool decode(int32_t& oopmap_slot, int32_t& cb_offset) const; bool patch(int32_t oopmap_slot, int32_t cb_offset); diff --git a/src/hotspot/cpu/riscv/relocInfo_riscv.cpp b/src/hotspot/cpu/riscv/relocInfo_riscv.cpp index b3cdb93a979d8..43a9b8f89aeaa 100644 --- a/src/hotspot/cpu/riscv/relocInfo_riscv.cpp +++ b/src/hotspot/cpu/riscv/relocInfo_riscv.cpp @@ -42,7 +42,7 @@ void Relocation::pd_set_data_value(address x, bool verify_only) { case relocInfo::oop_type: { oop_Relocation *reloc = (oop_Relocation *)this; // in movoop when BarrierSet::barrier_set()->barrier_set_nmethod() isn't null - if (NativeInstruction::is_load_pc_relative_at(addr())) { + if (MacroAssembler::is_load_pc_relative_at(addr())) { address constptr = (address)code()->oop_addr_at(reloc->oop_index()); bytes = MacroAssembler::pd_patch_instruction_size(addr(), constptr); assert((address)Bytes::get_native_u8(constptr) == x, "error in oop relocation"); @@ -60,7 +60,7 @@ void Relocation::pd_set_data_value(address x, bool verify_only) { address Relocation::pd_call_destination(address orig_addr) { assert(is_call(), "should be an address instruction here"); - if (NativeCall::is_call_at(addr())) { + if (MacroAssembler::is_call_at(addr())) { address trampoline = nativeCall_at(addr())->get_trampoline(); if (trampoline != nullptr) { return nativeCallTrampolineStub_at(trampoline)->destination(); @@ -81,7 +81,7 @@ address Relocation::pd_call_destination(address orig_addr) { void Relocation::pd_set_call_destination(address x) { assert(is_call(), "should be an address instruction here"); - if (NativeCall::is_call_at(addr())) { + if (MacroAssembler::is_call_at(addr())) { address trampoline = nativeCall_at(addr())->get_trampoline(); if (trampoline != nullptr) { nativeCall_at(addr())->set_destination_mt_safe(x, /* assert_lock */false); @@ -94,7 +94,7 @@ void Relocation::pd_set_call_destination(address x) { } address* Relocation::pd_address_in_code() { - assert(NativeCall::is_load_pc_relative_at(addr()), "Not the expected instruction sequence!"); + assert(MacroAssembler::is_load_pc_relative_at(addr()), "Not the expected instruction sequence!"); return (address*)(MacroAssembler::target_addr_for_insn(addr())); }