From 7f19c700707573000a37910dd6d2f2bb6e8439ad Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Tue, 8 Feb 2022 17:48:48 +0000 Subject: [PATCH 001/203] 8281061: [s390] JFR runs into assertions while validating interpreter frames Reviewed-by: lucy, rrich --- src/hotspot/cpu/s390/frame_s390.cpp | 18 ++++++++---------- .../os_cpu/linux_s390/thread_linux_s390.cpp | 13 +++++++------ 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/hotspot/cpu/s390/frame_s390.cpp b/src/hotspot/cpu/s390/frame_s390.cpp index bfb38ffcdaf..3588915f79d 100644 --- a/src/hotspot/cpu/s390/frame_s390.cpp +++ b/src/hotspot/cpu/s390/frame_s390.cpp @@ -117,8 +117,8 @@ bool frame::safe_for_sender(JavaThread *thread) { return false; } - z_abi_160* sender_abi = (z_abi_160*) fp; - intptr_t* sender_sp = (intptr_t*) sender_abi->callers_sp; + z_abi_16* sender_abi = (z_abi_16*)fp; + intptr_t* sender_sp = (intptr_t*) fp; address sender_pc = (address) sender_abi->return_pc; // We must always be able to find a recognizable pc. @@ -142,7 +142,7 @@ bool frame::safe_for_sender(JavaThread *thread) { // sender_fp must be within the stack and above (but not // equal) current frame's fp. if (!thread->is_in_stack_range_excl(sender_fp, fp)) { - return false; + return false; } // If the potential sender is the interpreter then we can do some more checking. @@ -319,8 +319,8 @@ bool frame::is_interpreted_frame_valid(JavaThread* thread) const { // do some validation of frame elements // first the method - - Method* m = *interpreter_frame_method_addr(); + // Need to use "unchecked" versions to avoid "z_istate_magic_number" assertion. + Method* m = (Method*)(ijava_state_unchecked()->method); // validate the method we'd find in this potential sender if (!Method::is_valid_method(m)) return false; @@ -335,19 +335,17 @@ bool frame::is_interpreted_frame_valid(JavaThread* thread) const { } // validate bci/bcx - - address bcp = interpreter_frame_bcp(); + address bcp = (address)(ijava_state_unchecked()->bcp); if (m->validate_bci_from_bcp(bcp) < 0) { return false; } // validate constantPoolCache* - ConstantPoolCache* cp = *interpreter_frame_cache_addr(); + ConstantPoolCache* cp = (ConstantPoolCache*)(ijava_state_unchecked()->cpoolCache); if (MetaspaceObj::is_valid(cp) == false) return false; // validate locals - - address locals = (address) *interpreter_frame_locals_addr(); + address locals = (address)(ijava_state_unchecked()->locals); return thread->is_in_stack_range_incl(locals, (address)fp()); } diff --git a/src/hotspot/os_cpu/linux_s390/thread_linux_s390.cpp b/src/hotspot/os_cpu/linux_s390/thread_linux_s390.cpp index d06b851a99f..3b16096784f 100644 --- a/src/hotspot/os_cpu/linux_s390/thread_linux_s390.cpp +++ b/src/hotspot/os_cpu/linux_s390/thread_linux_s390.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016, 2019 SAP SE. All rights reserved. + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2022 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,14 +58,15 @@ bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, // if we were running Java code when SIGPROF came in. if (isInJava) { ucontext_t* uc = (ucontext_t*) ucontext; - frame ret_frame((intptr_t*)uc->uc_mcontext.gregs[15/*Z_SP*/], - (address)uc->uc_mcontext.psw.addr); + address pc = (address)uc->uc_mcontext.psw.addr; - if (ret_frame.pc() == NULL) { + if (pc == NULL) { // ucontext wasn't useful return false; } + frame ret_frame((intptr_t*)uc->uc_mcontext.gregs[15/*Z_SP*/], pc); + if (ret_frame.fp() == NULL) { // The found frame does not have a valid frame pointer. // Bail out because this will create big trouble later on, either @@ -100,7 +101,7 @@ bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, if (ret_frame.is_interpreted_frame()) { frame::z_ijava_state* istate = ret_frame.ijava_state_unchecked(); - if (is_in_full_stack((address)istate)) { + if (!is_in_full_stack((address)istate)) { return false; } const Method *m = (const Method*)(istate->method); -- GitLab From 92f4f40da6c4ff55c7ed334007c9c6ca0dc15d99 Mon Sep 17 00:00:00 2001 From: Christian Stein Date: Tue, 8 Feb 2022 17:53:42 +0000 Subject: [PATCH 002/203] 8281104: jar --create should create missing parent directories Reviewed-by: lancea --- .../share/classes/sun/tools/jar/Main.java | 15 ++- .../sun/tools/jar/resources/jar.properties | 6 +- .../jar/CreateMissingParentDirectories.java | 114 ++++++++++++++++++ 3 files changed, 128 insertions(+), 7 deletions(-) create mode 100644 test/jdk/tools/jar/CreateMissingParentDirectories.java diff --git a/src/jdk.jartool/share/classes/sun/tools/jar/Main.java b/src/jdk.jartool/share/classes/sun/tools/jar/Main.java index 3436c01928b..c582f2d80ce 100644 --- a/src/jdk.jartool/share/classes/sun/tools/jar/Main.java +++ b/src/jdk.jartool/share/classes/sun/tools/jar/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -427,10 +427,10 @@ public class Main { fatalError(e); ok = false; } catch (Error ee) { - ee.printStackTrace(); + ee.printStackTrace(err); ok = false; } catch (Throwable t) { - t.printStackTrace(); + t.printStackTrace(err); ok = false; } finally { if (tmpFile != null && tmpFile.exists()) @@ -461,7 +461,12 @@ public class Main { try { if (ok) { if (fname != null) { - Files.move(path, Paths.get(fname), StandardCopyOption.REPLACE_EXISTING); + Path target = Paths.get(fname); + Path parent = target.getParent(); + if (parent != null) { + Files.createDirectories(parent); + } + Files.move(path, target, StandardCopyOption.REPLACE_EXISTING); } else { Files.copy(path, new FileOutputStream(FileDescriptor.out)); } @@ -1653,7 +1658,7 @@ public class Main { * A fatal exception has been caught. No recovery possible */ void fatalError(Exception e) { - e.printStackTrace(); + e.printStackTrace(err); } /** diff --git a/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties b/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties index 87bff689102..c08c6ff7f06 100644 --- a/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties +++ b/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties @@ -169,7 +169,7 @@ usage.compat=\ \n\ Usage: jar {ctxui}[vfmn0PMe] [jar-file] [manifest-file] [entry-point] [-C dir] files] ...\n\ Options:\n\ -\ \ -c create new archive\n\ +\ \ -c create new archive (including missing parent directories)\n\ \ \ -t list table of contents for archive\n\ \ \ -x extract named (or all) files from archive\n\ \ \ -u update existing archive\n\ @@ -227,7 +227,9 @@ text file and pass it to the jar command with the at sign (@) as a prefix.\n\ main.help.opt.main=\ \ Main operation mode:\n main.help.opt.main.create=\ -\ -c, --create Create the archive +\ -c, --create Create the archive. When the archive file name specified\n\ +\ by -f or --file contains a path, missing parent directories\n\ +\ will also be created main.help.opt.main.generate-index=\ \ -i, --generate-index=FILE Generate index information for the specified jar\n\ \ archives diff --git a/test/jdk/tools/jar/CreateMissingParentDirectories.java b/test/jdk/tools/jar/CreateMissingParentDirectories.java new file mode 100644 index 00000000000..93d6d4ce01d --- /dev/null +++ b/test/jdk/tools/jar/CreateMissingParentDirectories.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8281104 + * @modules jdk.jartool + * @summary jar --create --file a/b/test.jar should create directories a/b + */ + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.spi.ToolProvider; +import java.util.stream.Stream; + +public class CreateMissingParentDirectories { + private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar") + .orElseThrow(() -> + new RuntimeException("jar tool not found") + ); + + /** + * Remove dirs & files needed for test. + */ + private static void cleanup(Path dir) { + try { + if (Files.isDirectory(dir)) { + try (Stream s = Files.list(dir)) { + s.forEach(p -> cleanup(p)); + } + } + Files.delete(dir); + } catch (Exception x) { + fail(x.toString()); + } + } + + public static void realMain(String[] args) throws Throwable { + Path topDir = Files.createTempDirectory("delete"); + try { + Path entry = Files.writeString(topDir.resolve("test.txt"), "Some text..."); + + doHappyPathTest(topDir.resolve("test.jar"), entry); + doHappyPathTest(topDir.resolve("a/test.jar"), entry); + doHappyPathTest(topDir.resolve("a/b/test.jar"), entry); + + doFailingTest(topDir.toString() + "/a/*/test.jar", entry); + Path blocker = Files.writeString(topDir.resolve("blocker.txt"), "Blocked!"); + doFailingTest(topDir.resolve("blocker.txt/test.jar").toString(), entry); + } finally { + cleanup(topDir); + } + } + + private static void doHappyPathTest(Path jar, Path entry) throws Throwable { + String[] jarArgs = new String[]{"cf", jar.toString(), entry.toString()}; + if (JAR_TOOL.run(System.out, System.err, jarArgs) != 0) { + fail("Could not create jar file: " + jar); + return; + } + pass(); + } + + private static void doFailingTest(String jar, Path entry) throws Throwable { + StringWriter out = new StringWriter(); + StringWriter err = new StringWriter(); + String[] jarArgs = new String[]{"cf", jar, entry.toString()}; + + if (JAR_TOOL.run(new PrintWriter(out, true), new PrintWriter(err, true), jarArgs) == 0) { + fail("Should have failed creating jar file: " + jar); + return; + } + // non-zero exit code expected, check error message contains jar file's name + check(err.toString().contains(jar)); + pass(); + } + + //--------------------- Infrastructure --------------------------- + static volatile int passed = 0, failed = 0; + static void pass() {passed++;} + static void fail() {failed++; Thread.dumpStack();} + static void fail(String msg) {System.out.println(msg); fail();} + static void unexpected(Throwable t) {failed++; t.printStackTrace();} + static void check(boolean cond) {if (cond) pass(); else fail();} + static void equal(Object x, Object y) { + if (x == null ? y == null : x.equals(y)) pass(); + else fail(x + " not equal to " + y);} + public static void main(String[] args) throws Throwable { + try {realMain(args);} catch (Throwable t) {unexpected(t);} + System.out.println("\nPassed = " + passed + " failed = " + failed); + if (failed > 0) throw new AssertionError("Some tests failed");} +} -- GitLab From 5fb56dbb0b4e3345ca6f48ba9c01bd467f04aa6f Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Tue, 8 Feb 2022 20:16:34 +0000 Subject: [PATCH 003/203] 8281476: ProblemList tools/jar/CreateMissingParentDirectories.java Reviewed-by: azvegint, bpb, lancea --- test/jdk/ProblemList.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 6b54c726277..1d08673243f 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -765,6 +765,7 @@ javax/swing/JTree/4908142/bug4908142.java 8278348 macosx-all # core_tools tools/jlink/plugins/CompressorPluginTest.java 8247407 generic-all +tools/jar/CreateMissingParentDirectories.java 8281470 generic-all ############################################################################ -- GitLab From d658d945cf57bab8e61302841dcb56b36e48eff3 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 8 Feb 2022 20:29:04 +0000 Subject: [PATCH 004/203] 8280828: Improve invariants in NonblockingQueue::append Reviewed-by: iwalulya, tschatzl --- .../utilities/nonblockingQueue.inline.hpp | 65 +++++++++++-------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/src/hotspot/share/utilities/nonblockingQueue.inline.hpp b/src/hotspot/share/utilities/nonblockingQueue.inline.hpp index 2fbd26f2dca..e16c8cb57d0 100644 --- a/src/hotspot/share/utilities/nonblockingQueue.inline.hpp +++ b/src/hotspot/share/utilities/nonblockingQueue.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -94,34 +94,41 @@ size_t NonblockingQueue::length() const { // push/append operations, each may introduce another such segment. But they // all eventually get resolved by their respective updates of their old tail's // "next" value. This also means that try_pop operation must handle an object -// with a NULL "next" value specially. +// differently depending on its "next" value. // // A push operation is just a degenerate append, where the object being pushed // is both the head and the tail of the list being appended. template void NonblockingQueue::append(T& first, T& last) { assert(next(last) == NULL, "precondition"); + // Make last the new end of the queue. Any further push/appends will + // extend after last. We will try to extend from the previous end of + // queue. set_next(last, end_marker()); T* old_tail = Atomic::xchg(&_tail, &last); - bool is_old_tail_null = (old_tail == NULL); - if (is_old_tail_null || - // Try to install first as old_tail's next. - !is_end(Atomic::cmpxchg(next_ptr(*old_tail), end_marker(), &first))) { - // Install first as the new head if either - // (1) the list was empty, or - // (2) a concurrent try_pop claimed old_tail, so it is no longer in the list. - // Note that multiple concurrent push/append operations cannot modify - // _head simultaneously, because the Atomic::xchg() above orders these - // push/append operations so they perform Atomic::cmpxchg() on different - // old_tail. Thus, the cmpxchg can only fail because of a concurrent try_pop. + if (old_tail == NULL) { + // If old_tail is NULL then the queue was empty, and _head must also be + // NULL. The correctness of this assertion depends on try_pop clearing + // first _head then _tail when taking the last entry. + assert(Atomic::load(&_head) == NULL, "invariant"); + // Fall through to common update of _head. + } else if (is_end(Atomic::cmpxchg(next_ptr(*old_tail), end_marker(), &first))) { + // Successfully extended the queue list from old_tail to first. No + // other push/append could have competed with us, because we claimed + // old_tail for extension. We won any races with try_pop by changing + // away from end-marker. So we're done. + return; + } else { + // A concurrent try_pop has claimed old_tail, so it is no longer in the + // list. The queue was logically empty. _head is either NULL or + // old_tail, depending on how far try_pop operations have progressed. DEBUG_ONLY(T* old_head = Atomic::load(&_head);) - // If old_tail is NULL, old_head could be NULL, or an unseen object - // that is being popped. Otherwise, old_head must be either NULL - // or the same as old_tail. - assert(is_old_tail_null || - old_head == NULL || old_head == old_tail, "invariant"); - Atomic::store(&_head, &first); + assert((old_head == NULL) || (old_head == old_tail), "invariant"); + // Fall through to common update of _head. } + // The queue was empty, and first should become the new _head. The queue + // will appear to be empty to any further try_pops until done. + Atomic::store(&_head, &first); } template @@ -161,7 +168,9 @@ bool NonblockingQueue::try_pop(T** node_ptr) { // _head to NULL, "helping" the competing try_pop. _head will remain // NULL until a subsequent push/append. This is a lost race, and we // report it as such for consistency, though we could report the queue - // was empty. + // was empty. We don't attempt to further help [Clause 2] by also + // trying to set _tail to NULL, as that would just ensure that one or + // the other cmpxchg is a wasted failure. return false; } else { // [Clause 1c] @@ -181,17 +190,21 @@ bool NonblockingQueue::try_pop(T** node_ptr) { // Any further try_pops will consider the queue empty until a // push/append completes by installing a new head. - // Attempt to change the queue tail from result to NULL. Failure of the - // cmpxchg indicates that a concurrent push/append updated the tail first. - // That operation will eventually recognize the old tail (our result) is - // no longer in the list and update head from the list being appended. - Atomic::cmpxchg(&_tail, result, (T*)NULL); + // The order of the two cmpxchgs doesn't matter algorithmically, but + // dealing with _head first gives a stronger invariant in append, and is + // also consistent with [Clause 1b]. // Attempt to change the queue head from result to NULL. Failure of the // cmpxchg indicates a concurrent operation updated _head first. That - // could be either a push/extend or a try_pop in [Clause 1b]. + // could be either a push/append or a try_pop in [Clause 1b]. Atomic::cmpxchg(&_head, result, (T*)NULL); + // Attempt to change the queue tail from result to NULL. Failure of the + // cmpxchg indicates that a concurrent push/append updated _tail first. + // That operation will eventually recognize the old tail (our result) is + // no longer in the list and update _head from the list being appended. + Atomic::cmpxchg(&_tail, result, (T*)NULL); + // The queue has been restored to order, and we can return the result. *node_ptr = result; return true; -- GitLab From fb17a8ece0a3593c51a8be60533916bf70778a93 Mon Sep 17 00:00:00 2001 From: Quan Anh Mai Date: Tue, 8 Feb 2022 23:38:09 +0000 Subject: [PATCH 005/203] 8278947: Support for array constants in constant table Reviewed-by: kvn, vlivanov --- src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp | 20 +++ src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp | 2 + src/hotspot/cpu/x86/x86.ad | 161 ++++++------------ src/hotspot/share/asm/assembler.hpp | 27 ++- src/hotspot/share/opto/constantTable.cpp | 137 ++++++++------- src/hotspot/share/opto/constantTable.hpp | 25 ++- 6 files changed, 200 insertions(+), 172 deletions(-) diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index 65166197616..1f86ac0ebb9 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -1493,6 +1493,26 @@ void C2_MacroAssembler::load_vector_mask(KRegister dst, XMMRegister src, XMMRegi } } +void C2_MacroAssembler::load_vector(XMMRegister dst, Address src, int vlen_in_bytes) { + switch (vlen_in_bytes) { + case 4: movdl(dst, src); break; + case 8: movq(dst, src); break; + case 16: movdqu(dst, src); break; + case 32: vmovdqu(dst, src); break; + case 64: evmovdquq(dst, src, Assembler::AVX_512bit); break; + default: ShouldNotReachHere(); + } +} + +void C2_MacroAssembler::load_vector(XMMRegister dst, AddressLiteral src, int vlen_in_bytes, Register rscratch) { + if (reachable(src)) { + load_vector(dst, as_Address(src), vlen_in_bytes); + } else { + lea(rscratch, src); + load_vector(dst, Address(rscratch, 0), vlen_in_bytes); + } +} + void C2_MacroAssembler::load_iota_indices(XMMRegister dst, Register scratch, int vlen_in_bytes) { ExternalAddress addr(StubRoutines::x86::vector_iota_indices()); if (vlen_in_bytes == 4) { diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp index b97c1ed607d..3df87043f09 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp @@ -144,6 +144,8 @@ public: void load_vector_mask(XMMRegister dst, XMMRegister src, int vlen_in_bytes, BasicType elem_bt, bool is_legacy); void load_vector_mask(KRegister dst, XMMRegister src, XMMRegister xtmp, Register tmp, bool novlbwdq, int vlen_enc); + void load_vector(XMMRegister dst, Address src, int vlen_in_bytes); + void load_vector(XMMRegister dst, AddressLiteral src, int vlen_in_bytes, Register rscratch = rscratch1); void load_iota_indices(XMMRegister dst, Register scratch, int vlen_in_bytes); // Reductions for vectors of bytes, shorts, ints, longs, floats, and doubles. diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index a9dc2997e21..664f630a8cd 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -2552,15 +2552,21 @@ void vec_spill_helper(CodeBuffer *cbuf, bool is_load, } } -static inline jlong replicate8_imm(int con, int width) { - // Load a constant of "width" (in bytes) and replicate it to fill 64bit. - assert(width == 1 || width == 2 || width == 4, "only byte, short or int types here"); - int bit_width = width * 8; - jlong val = con; - val &= (((jlong) 1) << bit_width) - 1; // mask off sign bits - while(bit_width < 64) { - val |= (val << bit_width); - bit_width <<= 1; +template +static inline GrowableArray* vreplicate_imm(BasicType bt, T con, int len) { + GrowableArray* val = new GrowableArray(len); + jvalue ele; + switch (bt) { + case T_BYTE: ele.b = con; break; + case T_SHORT: ele.s = con; break; + case T_INT: ele.i = con; break; + case T_LONG: ele.j = con; break; + case T_FLOAT: ele.f = con; break; + case T_DOUBLE: ele.d = con; break; + default: ShouldNotReachHere(); + } + for (int i = 0; i < len; i++) { + val->append(ele); } return val; } @@ -3824,14 +3830,7 @@ instruct loadV(vec dst, memory mem) %{ ins_cost(125); format %{ "load_vector $dst,$mem" %} ins_encode %{ - switch (Matcher::vector_length_in_bytes(this)) { - case 4: __ movdl ($dst$$XMMRegister, $mem$$Address); break; - case 8: __ movq ($dst$$XMMRegister, $mem$$Address); break; - case 16: __ movdqu ($dst$$XMMRegister, $mem$$Address); break; - case 32: __ vmovdqu ($dst$$XMMRegister, $mem$$Address); break; - case 64: __ evmovdqul($dst$$XMMRegister, $mem$$Address, Assembler::AVX_512bit); break; - default: ShouldNotReachHere(); - } + __ load_vector($dst$$XMMRegister, $mem$$Address, Matcher::vector_length_in_bytes(this)); %} ins_pipe( pipe_slow ); %} @@ -4009,43 +4008,12 @@ instruct ReplB_imm(vec dst, immI con) %{ match(Set dst (ReplicateB con)); format %{ "replicateB $dst,$con" %} ins_encode %{ - uint vlen = Matcher::vector_length(this); - InternalAddress const_addr = $constantaddress(replicate8_imm($con$$constant, 1)); - if (vlen == 4) { - __ movdl($dst$$XMMRegister, const_addr); - } else { - __ movq($dst$$XMMRegister, const_addr); - if (vlen >= 16) { - if (VM_Version::supports_avx2()) { - int vlen_enc = vector_length_encoding(this); - __ vpbroadcastq($dst$$XMMRegister, $dst$$XMMRegister, vlen_enc); - } else { - assert(vlen == 16, "sanity"); - __ punpcklqdq($dst$$XMMRegister, $dst$$XMMRegister); - } - } - } + InternalAddress addr = $constantaddress(T_BYTE, vreplicate_imm(T_BYTE, $con$$constant, Matcher::vector_length(this))); + __ load_vector($dst$$XMMRegister, addr, Matcher::vector_length_in_bytes(this)); %} ins_pipe( pipe_slow ); %} -// Replicate byte scalar zero to be vector -instruct ReplB_zero(vec dst, immI_0 zero) %{ - match(Set dst (ReplicateB zero)); - format %{ "replicateB $dst,$zero" %} - ins_encode %{ - uint vlen = Matcher::vector_length(this); - if (vlen <= 16) { - __ pxor($dst$$XMMRegister, $dst$$XMMRegister); - } else { - // Use vpxor since AVX512F does not have 512bit vxorpd (requires AVX512DQ). - int vlen_enc = vector_length_encoding(this); - __ vpxor($dst$$XMMRegister, $dst$$XMMRegister, $dst$$XMMRegister, vlen_enc); - } - %} - ins_pipe( fpu_reg_reg ); -%} - // ====================ReplicateS======================================= instruct ReplS_reg(vec dst, rRegI src) %{ @@ -4091,39 +4059,10 @@ instruct ReplS_imm(vec dst, immI con) %{ match(Set dst (ReplicateS con)); format %{ "replicateS $dst,$con" %} ins_encode %{ - uint vlen = Matcher::vector_length(this); - InternalAddress const_addr = $constantaddress(replicate8_imm($con$$constant, 2)); - if (vlen == 2) { - __ movdl($dst$$XMMRegister, const_addr); - } else { - __ movq($dst$$XMMRegister, const_addr); - if (vlen >= 8) { - if (VM_Version::supports_avx2()) { - int vlen_enc = vector_length_encoding(this); - __ vpbroadcastw($dst$$XMMRegister, $dst$$XMMRegister, vlen_enc); - } else { - assert(vlen == 8, "sanity"); - __ punpcklqdq($dst$$XMMRegister, $dst$$XMMRegister); - } - } - } - %} - ins_pipe( fpu_reg_reg ); -%} - -instruct ReplS_zero(vec dst, immI_0 zero) %{ - match(Set dst (ReplicateS zero)); - format %{ "replicateS $dst,$zero" %} - ins_encode %{ - uint vlen = Matcher::vector_length(this); - if (vlen <= 8) { - __ pxor($dst$$XMMRegister, $dst$$XMMRegister); - } else { - int vlen_enc = vector_length_encoding(this); - __ vpxor($dst$$XMMRegister, $dst$$XMMRegister, $dst$$XMMRegister, vlen_enc); - } + InternalAddress addr = $constantaddress(T_SHORT, vreplicate_imm(T_SHORT, $con$$constant, Matcher::vector_length(this))); + __ load_vector($dst$$XMMRegister, addr, Matcher::vector_length_in_bytes(this)); %} - ins_pipe( fpu_reg_reg ); + ins_pipe( pipe_slow ); %} // ====================ReplicateI======================================= @@ -4173,30 +4112,21 @@ instruct ReplI_imm(vec dst, immI con) %{ match(Set dst (ReplicateI con)); format %{ "replicateI $dst,$con" %} ins_encode %{ - uint vlen = Matcher::vector_length(this); - InternalAddress const_addr = $constantaddress(replicate8_imm($con$$constant, 4)); - if (vlen <= 4) { - __ movq($dst$$XMMRegister, const_addr); - if (vlen == 4) { - __ punpcklqdq($dst$$XMMRegister, $dst$$XMMRegister); - } - } else { - assert(VM_Version::supports_avx2(), "sanity"); - int vlen_enc = vector_length_encoding(this); - __ movq($dst$$XMMRegister, const_addr); - __ vpbroadcastd($dst$$XMMRegister, $dst$$XMMRegister, vlen_enc); - } + InternalAddress addr = $constantaddress(T_INT, vreplicate_imm(T_INT, $con$$constant, Matcher::vector_length(this))); + __ load_vector($dst$$XMMRegister, addr, Matcher::vector_length_in_bytes(this)); %} ins_pipe( pipe_slow ); %} -// Replicate integer (4 byte) scalar zero to be vector +// Replicate scalar zero to be vector instruct ReplI_zero(vec dst, immI_0 zero) %{ + match(Set dst (ReplicateB zero)); + match(Set dst (ReplicateS zero)); match(Set dst (ReplicateI zero)); format %{ "replicateI $dst,$zero" %} ins_encode %{ - uint vlen = Matcher::vector_length(this); - if (vlen <= 4) { + uint vsize = Matcher::vector_length_in_bytes(this); + if (vsize <= 16) { __ pxor($dst$$XMMRegister, $dst$$XMMRegister); } else { int vlen_enc = vector_length_encoding(this); @@ -4327,17 +4257,8 @@ instruct ReplL_imm(vec dst, immL con) %{ match(Set dst (ReplicateL con)); format %{ "replicateL $dst,$con" %} ins_encode %{ - uint vlen = Matcher::vector_length(this); - InternalAddress const_addr = $constantaddress($con); - if (vlen == 2) { - __ movq($dst$$XMMRegister, const_addr); - __ punpcklqdq($dst$$XMMRegister, $dst$$XMMRegister); - } else { - assert(VM_Version::supports_avx2(), "sanity"); - int vlen_enc = vector_length_encoding(this); - __ movq($dst$$XMMRegister, const_addr); - __ vpbroadcastq($dst$$XMMRegister, $dst$$XMMRegister, vlen_enc); - } + InternalAddress addr = $constantaddress(T_LONG, vreplicate_imm(T_LONG, $con$$constant, Matcher::vector_length(this))); + __ load_vector($dst$$XMMRegister, addr, Matcher::vector_length_in_bytes(this)); %} ins_pipe( pipe_slow ); %} @@ -4407,6 +4328,17 @@ instruct ReplF_mem(vec dst, memory mem) %{ ins_pipe( pipe_slow ); %} +// Replicate float scalar immediate to be vector by loading from const table. +instruct ReplF_imm(vec dst, immF con) %{ + match(Set dst (ReplicateF con)); + format %{ "replicateF $dst,$con" %} + ins_encode %{ + InternalAddress addr = $constantaddress(T_FLOAT, vreplicate_imm(T_FLOAT, $con$$constant, Matcher::vector_length(this))); + __ load_vector($dst$$XMMRegister, addr, Matcher::vector_length_in_bytes(this)); + %} + ins_pipe( pipe_slow ); +%} + instruct ReplF_zero(vec dst, immF0 zero) %{ match(Set dst (ReplicateF zero)); format %{ "replicateF $dst,$zero" %} @@ -4461,6 +4393,17 @@ instruct ReplD_mem(vec dst, memory mem) %{ ins_pipe( pipe_slow ); %} +// Replicate double (8 byte) scalar immediate to be vector by loading from const table. +instruct ReplD_imm(vec dst, immD con) %{ + match(Set dst (ReplicateD con)); + format %{ "replicateD $dst,$con" %} + ins_encode %{ + InternalAddress addr = $constantaddress(T_DOUBLE, vreplicate_imm(T_DOUBLE, $con$$constant, Matcher::vector_length(this))); + __ load_vector($dst$$XMMRegister, addr, Matcher::vector_length_in_bytes(this)); + %} + ins_pipe( pipe_slow ); +%} + instruct ReplD_zero(vec dst, immD0 zero) %{ match(Set dst (ReplicateD zero)); format %{ "replicateD $dst,$zero" %} diff --git a/src/hotspot/share/asm/assembler.hpp b/src/hotspot/share/asm/assembler.hpp index 10fa79eb30a..dc38a53b031 100644 --- a/src/hotspot/share/asm/assembler.hpp +++ b/src/hotspot/share/asm/assembler.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -429,6 +429,31 @@ class AbstractAssembler : public ResourceObj { } return ptr; } + address array_constant(BasicType bt, GrowableArray* c) { + CodeSection* c1 = _code_section; + int len = c->length(); + int size = type2aelembytes(bt) * len; + address ptr = start_a_const(size, MIN2(round_up_power_of_2(size), 8)); + if (ptr != NULL) { + for (int i = 0; i < len; i++) { + jvalue e = c->at(i); + switch(bt) { + case T_BOOLEAN: emit_int8(e.z); break; + case T_BYTE: emit_int8(e.b); break; + case T_CHAR: emit_int16(e.c); break; + case T_SHORT: emit_int16(e.s); break; + case T_INT: emit_int32(e.i); break; + case T_LONG: emit_int64(e.j); break; + case T_FLOAT: emit_float(e.f); break; + case T_DOUBLE: emit_double(e.d); break; + default: + ShouldNotReachHere(); + } + } + end_a_const(c1); + } + return ptr; + } // Bang stack to trigger StackOverflowError at a safe location // implementation delegates to machine-specific bang_stack_with_offset diff --git a/src/hotspot/share/opto/constantTable.cpp b/src/hotspot/share/opto/constantTable.cpp index 285c273bb22..c3bb5c97730 100644 --- a/src/hotspot/share/opto/constantTable.cpp +++ b/src/hotspot/share/opto/constantTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,12 +35,15 @@ bool ConstantTable::Constant::operator==(const Constant& other) { if (type() != other.type() ) return false; if (can_be_reused() != other.can_be_reused()) return false; + if (is_array() || other.is_array()) { + return is_array() && other.is_array() && _v._array == other._v._array; + } // For floating point values we compare the bit pattern. switch (type()) { - case T_INT: - case T_FLOAT: return (_v._value.i == other._v._value.i); - case T_LONG: - case T_DOUBLE: return (_v._value.j == other._v._value.j); + case T_INT: return (_v._value.i == other._v._value.i); + case T_FLOAT: return jint_cast(_v._value.f) == jint_cast(other._v._value.f); + case T_LONG: return (_v._value.j == other._v._value.j); + case T_DOUBLE: return jlong_cast(_v._value.d) == jlong_cast(other._v._value.d); case T_OBJECT: case T_ADDRESS: return (_v._value.l == other._v._value.l); case T_VOID: return (_v._value.l == other._v._value.l); // jump-table entries @@ -56,8 +59,11 @@ int ConstantTable::qsort_comparator(Constant* a, Constant* b) { return 0; } -static int type_to_size_in_bytes(BasicType t) { - switch (t) { +static int constant_size(ConstantTable::Constant* con) { + if (con->is_array()) { + return type2aelembytes(con->type()) * con->get_array()->length(); + } + switch (con->type()) { case T_INT: return sizeof(jint ); case T_LONG: return sizeof(jlong ); case T_FLOAT: return sizeof(jfloat ); @@ -96,8 +102,9 @@ void ConstantTable::calculate_offsets_and_size() { Constant* con = _constants.adr_at(i); // Align offset for type. - int typesize = type_to_size_in_bytes(con->type()); - offset = align_up(offset, typesize); + int typesize = constant_size(con); + assert(typesize <= 8 || con->is_array(), "sanity"); + offset = align_up(offset, MIN2(round_up_power_of_2(typesize), 8)); con->set_offset(offset); // set constant's offset if (con->type() == T_VOID) { @@ -119,62 +126,66 @@ bool ConstantTable::emit(CodeBuffer& cb) const { for (int i = 0; i < _constants.length(); i++) { Constant con = _constants.at(i); address constant_addr = NULL; - switch (con.type()) { - case T_INT: constant_addr = _masm.int_constant( con.get_jint() ); break; - case T_LONG: constant_addr = _masm.long_constant( con.get_jlong() ); break; - case T_FLOAT: constant_addr = _masm.float_constant( con.get_jfloat() ); break; - case T_DOUBLE: constant_addr = _masm.double_constant(con.get_jdouble()); break; - case T_OBJECT: { - jobject obj = con.get_jobject(); - int oop_index = _masm.oop_recorder()->find_index(obj); - constant_addr = _masm.address_constant((address) obj, oop_Relocation::spec(oop_index)); - break; - } - case T_ADDRESS: { - address addr = (address) con.get_jobject(); - constant_addr = _masm.address_constant(addr); - break; - } - // We use T_VOID as marker for jump-table entries (labels) which - // need an internal word relocation. - case T_VOID: { - MachConstantNode* n = (MachConstantNode*) con.get_jobject(); - // Fill the jump-table with a dummy word. The real value is - // filled in later in fill_jump_table. - address dummy = (address) n; - constant_addr = _masm.address_constant(dummy); - if (constant_addr == NULL) { - return false; + if (con.is_array()) { + constant_addr = _masm.array_constant(con.type(), con.get_array()); + } else { + switch (con.type()) { + case T_INT: constant_addr = _masm.int_constant( con.get_jint() ); break; + case T_LONG: constant_addr = _masm.long_constant( con.get_jlong() ); break; + case T_FLOAT: constant_addr = _masm.float_constant( con.get_jfloat() ); break; + case T_DOUBLE: constant_addr = _masm.double_constant(con.get_jdouble()); break; + case T_OBJECT: { + jobject obj = con.get_jobject(); + int oop_index = _masm.oop_recorder()->find_index(obj); + constant_addr = _masm.address_constant((address) obj, oop_Relocation::spec(oop_index)); + break; } - assert((constant_addr - _masm.code()->consts()->start()) == con.offset(), - "must be: %d == %d", (int)(constant_addr - _masm.code()->consts()->start()), (int)(con.offset())); - - // Expand jump-table - address last_addr = NULL; - for (uint j = 1; j < n->outcnt(); j++) { - last_addr = _masm.address_constant(dummy + j); - if (last_addr == NULL) { + case T_ADDRESS: { + address addr = (address) con.get_jobject(); + constant_addr = _masm.address_constant(addr); + break; + } + // We use T_VOID as marker for jump-table entries (labels) which + // need an internal word relocation. + case T_VOID: { + MachConstantNode* n = (MachConstantNode*) con.get_jobject(); + // Fill the jump-table with a dummy word. The real value is + // filled in later in fill_jump_table. + address dummy = (address) n; + constant_addr = _masm.address_constant(dummy); + if (constant_addr == NULL) { return false; } - } + assert((constant_addr - _masm.code()->consts()->start()) == con.offset(), + "must be: %d == %d", (int)(constant_addr - _masm.code()->consts()->start()), (int)(con.offset())); + + // Expand jump-table + address last_addr = NULL; + for (uint j = 1; j < n->outcnt(); j++) { + last_addr = _masm.address_constant(dummy + j); + if (last_addr == NULL) { + return false; + } + } #ifdef ASSERT - address start = _masm.code()->consts()->start(); - address new_constant_addr = last_addr - ((n->outcnt() - 1) * sizeof(address)); - // Expanding the jump-table could result in an expansion of the const code section. - // In that case, we need to check if the new constant address matches the offset. - assert((constant_addr - start == con.offset()) || (new_constant_addr - start == con.offset()), - "must be: %d == %d or %d == %d (after an expansion)", (int)(constant_addr - start), (int)(con.offset()), - (int)(new_constant_addr - start), (int)(con.offset())); + address start = _masm.code()->consts()->start(); + address new_constant_addr = last_addr - ((n->outcnt() - 1) * sizeof(address)); + // Expanding the jump-table could result in an expansion of the const code section. + // In that case, we need to check if the new constant address matches the offset. + assert((constant_addr - start == con.offset()) || (new_constant_addr - start == con.offset()), + "must be: %d == %d or %d == %d (after an expansion)", (int)(constant_addr - start), (int)(con.offset()), + (int)(new_constant_addr - start), (int)(con.offset())); #endif - continue; // Loop - } - case T_METADATA: { - Metadata* obj = con.get_metadata(); - int metadata_index = _masm.oop_recorder()->find_index(obj); - constant_addr = _masm.address_constant((address) obj, metadata_Relocation::spec(metadata_index)); - break; - } - default: ShouldNotReachHere(); + continue; // Loop + } + case T_METADATA: { + Metadata* obj = con.get_metadata(); + int metadata_index = _masm.oop_recorder()->find_index(obj); + constant_addr = _masm.address_constant((address) obj, metadata_Relocation::spec(metadata_index)); + break; + } + default: ShouldNotReachHere(); + } } if (constant_addr == NULL) { @@ -218,6 +229,12 @@ ConstantTable::Constant ConstantTable::add(Metadata* metadata) { return con; } +ConstantTable::Constant ConstantTable::add(MachConstantNode* n, BasicType bt, GrowableArray* array) { + Constant con(bt, array); + add(con); + return con; +} + ConstantTable::Constant ConstantTable::add(MachConstantNode* n, MachOper* oper) { jvalue value; BasicType type = oper->type()->basic_type(); diff --git a/src/hotspot/share/opto/constantTable.hpp b/src/hotspot/share/opto/constantTable.hpp index fe0d0e3f1a5..1452a27d046 100644 --- a/src/hotspot/share/opto/constantTable.hpp +++ b/src/hotspot/share/opto/constantTable.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,18 +38,21 @@ public: class Constant { private: BasicType _type; + bool _is_array; union { jvalue _value; Metadata* _metadata; + GrowableArray* _array; } _v; int _offset; // offset of this constant (in bytes) relative to the constant table base. float _freq; bool _can_be_reused; // true (default) if the value can be shared with other users. public: - Constant() : _type(T_ILLEGAL), _offset(-1), _freq(0.0f), _can_be_reused(true) { _v._value.l = 0; } + Constant() : _type(T_ILLEGAL), _is_array(false), _offset(-1), _freq(0.0f), _can_be_reused(true) { _v._value.l = 0; } Constant(BasicType type, jvalue value, float freq = 0.0f, bool can_be_reused = true) : _type(type), + _is_array(false), _offset(-1), _freq(freq), _can_be_reused(can_be_reused) @@ -59,16 +62,31 @@ public: } Constant(Metadata* metadata, bool can_be_reused = true) : _type(T_METADATA), + _is_array(false), _offset(-1), _freq(0.0f), _can_be_reused(can_be_reused) { _v._metadata = metadata; } + Constant(BasicType type, GrowableArray* array) : + _type(type), + _is_array(true), + _offset(-1), + _freq(0.0f), + _can_be_reused(false) + { + assert(is_java_primitive(type), "not applicable for %s", type2name(type)); + _v._array = new GrowableArray(array->length()); + for (jvalue ele : *array) { + _v._array->append(ele); + } + } bool operator==(const Constant& other); BasicType type() const { return _type; } + bool is_array() const { return _is_array; } jint get_jint() const { return _v._value.i; } jlong get_jlong() const { return _v._value.j; } @@ -78,6 +96,8 @@ public: Metadata* get_metadata() const { return _v._metadata; } + GrowableArray* get_array() const { return _v._array; } + int offset() const { return _offset; } void set_offset(int offset) { _offset = offset; } @@ -124,6 +144,7 @@ public: void add(Constant& con); Constant add(MachConstantNode* n, BasicType type, jvalue value); Constant add(Metadata* metadata); + Constant add(MachConstantNode* n, BasicType bt, GrowableArray* array); Constant add(MachConstantNode* n, MachOper* oper); Constant add(MachConstantNode* n, jint i) { jvalue value; value.i = i; -- GitLab From 2f46af05ce2d43e19e0095680eb3a52fd904c774 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Wed, 9 Feb 2022 01:26:42 +0000 Subject: [PATCH 006/203] 8280132: Incorrect comparator com.sun.beans.introspect.MethodInfo.MethodOrder Reviewed-by: prr --- .../com/sun/beans/introspect/MethodInfo.java | 20 +- .../Introspector/MethodOrderException.java | 1537 ++++++++++++++++- 2 files changed, 1528 insertions(+), 29 deletions(-) diff --git a/src/java.desktop/share/classes/com/sun/beans/introspect/MethodInfo.java b/src/java.desktop/share/classes/com/sun/beans/introspect/MethodInfo.java index e5e79dc2a2f..5216f4423d4 100644 --- a/src/java.desktop/share/classes/com/sun/beans/introspect/MethodInfo.java +++ b/src/java.desktop/share/classes/com/sun/beans/introspect/MethodInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -98,10 +98,7 @@ final class MethodInfo { /** * A comparator that defines a total order so that methods have the same - * name and identical signatures appear next to each others. The methods are - * sorted in such a way that methods which override each other will sit next - * to each other, with the overridden method last - e.g. is Integer getFoo() - * placed before Object getFoo(). + * name and identical signatures appear next to each others. **/ private static final class MethodOrder implements Comparator { @@ -132,18 +129,7 @@ final class MethodInfo { } final Class aret = a.getReturnType(); final Class bret = b.getReturnType(); - if (aret == bret) { - return 0; - } - - // Super type comes last: Integer, Number, Object - if (aret.isAssignableFrom(bret)) { - return 1; - } - if (bret.isAssignableFrom(aret)) { - return -1; - } - return aret.getName().compareTo(bret.getName()); + return aret == bret ? 0 : aret.getName().compareTo(bret.getName()); } static final MethodOrder instance = new MethodOrder(); diff --git a/test/jdk/java/beans/Introspector/MethodOrderException.java b/test/jdk/java/beans/Introspector/MethodOrderException.java index d6c79b5d768..b69981002e6 100644 --- a/test/jdk/java/beans/Introspector/MethodOrderException.java +++ b/test/jdk/java/beans/Introspector/MethodOrderException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,40 +35,1553 @@ import java.util.RandomAccess; /** * @test - * @bug 8211147 + * @bug 8211147 8280132 * @modules java.desktop/com.sun.beans.introspect:open */ public final class MethodOrderException { public static void main(final String[] args) throws Exception { - // Public API, fails rarely - testPublicAPI(); - // Test using internal API, fails always - testPrivateAPI(); + for (Class beanClass : List.of(D.class, X.class, A_258.class)) { + // Public API, fails rarely + testPublicAPI(beanClass); + // Test using internal API, fails always + testPrivateAPI(beanClass); + } } - private static void testPublicAPI() throws Exception { - Introspector.getBeanInfo(X.class); + private static void testPublicAPI(Class beanClass) throws Exception { + Introspector.getBeanInfo(beanClass); } - private static void testPrivateAPI() throws Exception { + private static void testPrivateAPI(Class beanClass) throws Exception { Class name = Class.forName( "com.sun.beans.introspect.MethodInfo$MethodOrder"); Field instance = name.getDeclaredField("instance"); instance.setAccessible(true); Comparator o = (Comparator) instance.get(name); - List methods = List.of(X.class.getDeclaredMethods()); + List methods = List.of(beanClass.getDeclaredMethods()); methods.forEach(m1 -> { methods.forEach(m2 -> { if (o.compare(m1, m2) != -o.compare(m2, m1)) { - System.err.println("Method1 = "+ m1); - System.err.println("Method2 = "+ m2); + System.err.println("Method1 = " + m1); + System.err.println("Method2 = " + m2); throw new RuntimeException("Broken contract!"); } + methods.forEach(m3 -> { + if (o.compare(m1, m2) < 0 && o.compare(m2, m3) < 0) { + if (o.compare(m1, m3) >= 0) { + System.err.println("Method1 = " + m1); + System.err.println("Method2 = " + m2); + System.err.println("Method3 = " + m3); + throw new RuntimeException("Broken contract!"); + } + } + }); }); }); } + interface C1 { + C1 foo0(); + } + interface C2 { + C2 foo0(); + } + interface C3 extends C1 { + C3 foo0(); + } + interface D extends C3, C2, C1 { + D foo0(); + } + public interface A_239 { + } + public interface A_240 { + } + public interface A_000 { + } + public interface A_238 { + } + public interface A_035 extends A_195, A_106, A_240 { + A_035 a_040(); + A_035 a_000(); + A_035 a_018(); + } + public static class A_258 implements A_053, A_196, A_200, A_070, A_106, + A_057, A_094, A_098, A_105, A_107, A_097, A_093, A_214, A_215, + A_210, A_129, A_067, A_180, A_108, A_184, A_110, A_111, A_082, + A_221, A_172, A_171, A_168, A_139, A_143, A_140, A_075, A_081, + A_080, A_163, A_165, A_164, A_159, A_161, A_155, A_158, A_157, + A_156, A_195, A_197, A_114, A_213, A_236, A_220, A_201, A_035, + A_136, A_135, A_226, A_227, A_005, A_054, A_203, A_202, A_071, + A_115, A_113, A_112, A_058, A_095, A_096, A_099, A_100, A_237, + A_091, A_092, A_217, A_218, A_216, A_211, A_130, A_063, A_062, + A_064, A_065, A_066, A_061, A_060, A_181, A_208, A_207, A_209, + A_185, A_186, A_083, A_173, A_176, A_222, A_223, A_174, A_169, + A_153, A_154, A_194, A_190, A_104, A_132, A_141, A_142, A_166, + A_167, A_160, A_162, A_076, A_077, A_078, A_079, A_074, A_085, + A_192, A_188, A_134, A_138, A_137, A_228 { + @Override + public A_258 a_052() { + return null; + } + @Override + public A_258 a_071() { + return null; + } + @Override + public A_258 a_029() { + return null; + } + @Override + public A_258 a_046() { + return null; + } + @Override + public A_258 a_045() { + return null; + } + @Override + public A_258 a_047() { + return null; + } + @Override + public A_258 a_048() { + return null; + } + @Override + public A_258 a_049() { + return null; + } + @Override + public A_258 a_044() { + return null; + } + @Override + public A_258 a_043() { + return null; + } + @Override + public A_258 a_026() { + return null; + } + @Override + public A_258 a_027() { + return null; + } + @Override + public A_258 a_074() { + return null; + } + @Override + public A_258 a_079() { + return null; + } + @Override + public A_258 a_012() { + return null; + } + @Override + public A_258 a_100() { + return null; + } + @Override + public A_258 a_085() { + return null; + } + @Override + public A_258 a_084() { + return null; + } + @Override + public A_258 a_011() { + return null; + } + @Override + public A_258 a_059() { + return null; + } + @Override + public A_258 a_058() { + return null; + } + @Override + public A_258 a_080() { + return null; + } + @Override + public A_258 a_030() { + return null; + } + @Override + public A_258 a_031() { + return null; + } + @Override + public A_258 a_081() { + return null; + } + @Override + public A_258 a_077() { + return null; + } + @Override + public A_258 a_036() { + return null; + } + @Override + public A_258 a_056() { + return null; + } + @Override + public A_258 a_078() { + return null; + } + @Override + public A_258 a_076() { + return null; + } + @Override + public A_258 a_057() { + return null; + } + @Override + public A_258 a_005() { + return null; + } + @Override + public A_258 a_089() { + return null; + } + @Override + public A_258 a_088() { + return null; + } + @Override + public A_258 a_090() { + return null; + } + @Override + public A_258 a_072() { + return null; + } + @Override + public A_258 a_002() { + return null; + } + @Override + public A_258 a_040() { + return null; + } + @Override + public A_258 a_060() { + return null; + } + @Override + public A_258 a_061() { + return null; + } + @Override + public A_258 a_039() { + return null; + } + @Override + public A_258 a_032() { + return null; + } + @Override + public A_258 a_033() { + return null; + } + @Override + public A_258 a_000() { + return null; + } + @Override + public A_258 a_037() { + return null; + } + @Override + public A_258 a_014() { + return null; + } + @Override + public A_258 a_015() { + return null; + } + @Override + public A_258 a_016() { + return null; + } + @Override + public A_258 a_017() { + return null; + } + @Override + public A_258 a_091() { + return null; + } + @Override + public A_258 a_065() { + return null; + } + @Override + public A_258 a_066() { + return null; + } + @Override + public A_258 a_018() { + return null; + } + @Override + public A_258 a_093() { + return null; + } + @Override + public A_258 a_092() { + return null; + } + @Override + public A_258 a_095() { + return null; + } + @Override + public A_258 a_096() { + return null; + } + @Override + public A_258 a_069() { + return null; + } + } + public interface A_250 extends A_239 { + A_250 a_094(); + } + public interface A_253 extends A_239 { + A_253 a_000(); + } + public interface A_256 extends A_239 { + A_256 a_009(); + } + public interface A_248 extends A_239 { + A_248 a_022(); + } + public interface A_255 extends A_239 { + A_255 a_007(); + } + public interface A_241 extends A_248, A_250, A_251, A_249, A_239 { + } + public interface A_254 extends A_239 { + A_254 a_008(); + } + public interface A_251 extends A_239 { + A_251 a_097(); + } + public interface A_252 extends A_241, A_255, A_253, A_257, A_254, A_256, + A_239 { + A_252 a_022(); + A_252 a_094(); + A_252 a_097(); + A_252 a_087(); + } + public interface A_229 extends A_239 { + A_229 a_000(); + } + public interface A_232 extends A_239 { + } + public interface A_249 extends A_239 { + A_249 a_087(); + } + public interface A_230 extends A_239 { + } + public interface A_234 extends A_239 { + A_234 a_026(); + } + public interface A_037 extends A_239 { + A_037 a_013(); + } + public interface A_233 extends A_239 { + A_233 a_018(); + } + public interface A_231 extends A_239 { + A_231 a_007(); + } + public interface A_049 extends A_239 { + A_049 a_068(); + } + public interface A_257 extends A_239 { + A_257 a_018(); + } + public interface A_235 extends A_239 { + } + public interface A_040 extends A_239 { + A_040 a_025(); + } + public interface A_133 extends A_000, A_005, A_134, A_240 { + A_133 a_040(); + A_133 a_057(); + } + public interface A_001 extends A_239 { + A_001 a_020(); + } + public interface A_031 extends A_239 { + } + public interface A_089 extends A_239 { + A_089 a_098(); + } + public interface A_166 extends A_239 { + A_166 a_065(); + } + public interface A_054 extends A_239 { + A_054 a_000(); + } + public interface A_190 extends A_239 { + A_190 a_077(); + } + public interface A_169 extends A_239 { + A_169 a_037(); + } + public interface A_217 extends A_239 { + A_217 a_093(); + } + public interface A_078 extends A_239 { + A_078 a_016(); + } + public interface A_192 extends A_239 { + } + public interface A_222 extends A_239 { + A_222 a_095(); + } + public interface A_112 extends A_239 { + A_112 a_033(); + } + public interface A_066 extends A_239 { + A_066 a_049(); + } + public interface A_074 extends A_239 { + A_074 a_012(); + } + public interface A_003 extends A_239 { + A_003 a_039(); + } + public interface A_083 extends A_239 { + } + public interface A_050 extends A_239 { + A_050 a_070(); + } + public interface A_087 extends A_239 { + } + public interface A_058 extends A_239 { + } + public interface A_128 extends A_239 { + } + public interface A_092 extends A_239 { + } + public interface A_004 extends A_240 { + A_004 a_040(); + } + public interface A_115 extends A_239 { + A_115 a_039(); + } + public interface A_176 extends A_239 { + A_176 a_071(); + } + public interface A_162 extends A_239 { + } + public interface A_132 extends A_239 { + A_132 a_056(); + } + public interface A_064 extends A_239 { + A_064 a_047(); + } + public interface A_021 extends A_239 { + } + public interface A_160 extends A_239 { + } + public interface A_141 extends A_239 { + A_141 a_060(); + } + public interface A_091 extends A_239 { + A_091 a_026(); + } + public interface A_034 extends A_239 { + A_034 a_084(); + } + public interface A_151 extends A_239 { + } + public interface A_026 extends A_239 { + A_026 a_026(); + } + public interface A_130 extends A_239 { + A_130 a_052(); + } + public interface A_242 extends A_239 { + A_242 a_001(); + } + public interface A_205 extends A_239 { + A_205 a_086(); + } + public interface A_048 extends A_239 { + A_048 a_065(); + } + public interface A_044 extends A_240 { + A_044 a_040(); + } + public interface A_023 extends A_239 { + } + public interface A_027 extends A_239 { + } + public interface A_138 extends A_239 { + A_138 a_059(); + } + public interface A_024 extends A_239 { + A_024 a_011(); + } + public interface A_038 extends A_239 { + A_038 a_021(); + } + public interface A_016 extends A_239 { + } + public interface A_118 extends A_239 { + A_118 a_045(); + } + public interface A_071 extends A_239 { + A_071 a_011(); + } + public interface A_203 extends A_239 { + A_203 a_084(); + } + public interface A_137 extends A_239 { + } + public interface A_119 extends A_239 { + A_119 a_046(); + } + public interface A_145 extends A_239 { + } + public interface A_045 extends A_239 { + A_045 a_041(); + } + public interface A_069 extends A_239 { + A_069 a_010(); + } + public interface A_150 extends A_239 { + } + public interface A_047 extends A_239 { + A_047 a_057(); + } + public interface A_179 extends A_239 { + } + public interface A_207 extends A_239 { + A_207 a_088(); + } + public interface A_228 extends A_239 { + A_228 a_100(); + } + public interface A_005 extends A_240 { + A_005 a_040(); + } + public interface A_030 extends A_239 { + A_030 a_039(); + } + public interface A_173 extends A_239 { + A_173 a_069(); + } + public interface A_060 extends A_239 { + A_060 a_043(); + } + public interface A_245 extends A_239 { + A_245 a_009(); + } + public interface A_042 extends A_239 { + A_042 a_035(); + } + public interface A_209 extends A_239 { + A_209 a_090(); + } + public interface A_216 extends A_239 { + } + public interface A_142 extends A_239 { + } + public interface A_246 extends A_239 { + A_246 a_019(); + } + public interface A_223 extends A_239 { + } + public interface A_211 extends A_239 { + A_211 a_091(); + } + public interface A_244 extends A_239 { + A_244 a_008(); + } + public interface A_019 extends A_239 { + A_019 a_050(); + } + public interface A_041 extends A_239 { + A_041 a_034(); + } + public interface A_208 extends A_239 { + A_208 a_089(); + } + public interface A_065 extends A_239 { + } + public interface A_127 extends A_239 { + A_127 a_083(); + } + public interface A_033 extends A_239 { + } + public interface A_153 extends A_239 { + } + public interface A_079 extends A_239 { + } + public interface A_025 extends A_239 { + } + public interface A_046 extends A_239 { + A_046 a_042(); + } + public interface A_002 extends A_239 { + } + public interface A_154 extends A_239 { + } + public interface A_077 extends A_239 { + A_077 a_015(); + } + public interface A_121 extends A_239 { + A_121 a_053(); + } + public interface A_036 extends A_239 { + A_036 a_003(); + } + public interface A_225 extends A_239 { + A_225 a_054(); + } + public interface A_181 extends A_239 { + A_181 a_005(); + } + public interface A_134 extends A_239 { + A_134 a_057(); + } + public interface A_017 extends A_239 { + } + public interface A_194 extends A_239 { + A_194 a_081(); + } + public interface A_243 extends A_239 { + A_243 a_006(); + } + public interface A_015 extends A_239 { + A_015 a_004(); + } + public interface A_028 extends A_239 { + A_028 a_032(); + } + public interface A_218 extends A_239 { + } + public interface A_174 extends A_239 { + } + public interface A_039 extends A_239 { + A_039 a_023(); + } + public interface A_029 extends A_239 { + } + public interface A_095 extends A_239 { + A_095 a_029(); + } + public interface A_096 extends A_239 { + } + public interface A_124 extends A_239 { + A_124 a_028(); + } + public interface A_202 extends A_239 { + A_202 a_085(); + } + public interface A_186 extends A_239 { + } + public interface A_120 extends A_239 { + } + public interface A_076 extends A_239 { + A_076 a_014(); + } + public interface A_052 extends A_239 { + A_052 a_099(); + } + public interface A_056 extends A_239 { + } + public interface A_020 extends A_239 { + A_020 a_062(); + } + public interface A_018 extends A_239 { + A_018 a_045(); + } + public interface A_149 extends A_239 { + A_149 a_051(); + } + public interface A_022 extends A_239 { + A_022 a_075(); + } + public interface A_063 extends A_239 { + A_063 a_046(); + } + public interface A_043 extends A_239 { + A_043 a_038(); + } + public interface A_167 extends A_239 { + } + public interface A_085 extends A_239 { + A_085 a_018(); + } + public interface A_032 extends A_239 { + } + public interface A_188 extends A_239 { + A_188 a_076(); + } + public interface A_126 extends A_239 { + } + public interface A_113 extends A_239 { + A_113 a_032(); + } + public interface A_051 extends A_239 { + A_051 a_082(); + } + public interface A_185 extends A_239 { + A_185 a_074(); + } + public interface A_099 extends A_239 { + } + public interface A_062 extends A_239 { + A_062 a_045(); + } + public interface A_237 extends A_239 { + A_237 a_027(); + } + public interface A_100 extends A_239 { + } + public interface A_189 extends A_000, A_005, A_190, A_240 { + A_189 a_040(); + A_189 a_077(); + } + public interface A_061 extends A_239 { + A_061 a_044(); + } + public interface A_104 extends A_239 { + A_104 a_036(); + } + public interface A_084 extends A_000, A_005, A_085, A_240 { + A_084 a_040(); + A_084 a_018(); + } + public interface A_129 extends A_000, A_005, A_130, A_240 { + A_129 a_040(); + A_129 a_052(); + } + public interface A_086 extends A_000, A_005, A_087, A_089, A_240 { + A_086 a_040(); + A_086 a_024(); + A_086 a_098(); + } + public interface A_125 extends A_239 { + } + public interface A_212 extends A_053, A_084, A_005, A_054, A_085, A_217, + A_218, A_240 { + A_212 a_040(); + A_212 a_000(); + A_212 a_018(); + A_212 a_093(); + } + public interface A_171 extends A_170, A_175, A_005, A_173, A_176, A_174, + A_240 { + A_171 a_040(); + A_171 a_069(); + A_171 a_071(); + A_171 a_072(); + } + public interface A_247 extends A_239 { + } + public interface A_183 extends A_053, A_084, A_005, A_054, A_085, A_185, + A_186, A_240 { + A_183 a_040(); + A_183 a_000(); + A_183 a_018(); + A_183 a_074(); + } + public interface A_198 extends A_053, A_196, A_070, A_131, A_005, A_054, + A_203, A_071, A_132, A_240 { + A_198 a_040(); + A_198 a_000(); + A_198 a_084(); + A_198 a_011(); + A_198 a_056(); + } + public interface A_070 extends A_000, A_005, A_071, A_240 { + A_070 a_040(); + A_070 a_011(); + } + public interface A_109 extends A_106, A_212, A_005, A_115, A_113, A_112, + A_054, A_085, A_217, A_218, A_240 { + A_109 a_040(); + A_109 a_039(); + A_109 a_032(); + A_109 a_033(); + A_109 a_000(); + A_109 a_018(); + A_109 a_093(); + } + public interface A_158 extends A_159, A_161, A_152, A_005, A_054, A_160, + A_162, A_153, A_154, A_240 { + A_158 a_040(); + A_158 a_000(); + A_158 a_079(); + } + public interface A_110 extends A_106, A_212, A_183, A_005, A_054, A_085, + A_115, A_113, A_112, A_217, A_218, A_185, A_186, A_240 { + A_110 a_040(); + A_110 a_000(); + A_110 a_018(); + A_110 a_039(); + A_110 a_032(); + A_110 a_033(); + A_110 a_093(); + A_110 a_074(); + } + public interface A_200 extends A_000, A_005, A_202, A_240 { + A_200 a_040(); + A_200 a_085(); + } + public interface A_161 extends A_053, A_005, A_054, A_162, A_240 { + A_161 a_040(); + A_161 a_000(); + } + public interface A_175 extends A_000, A_005, A_176, A_240 { + A_175 a_040(); + A_175 a_071(); + } + public interface A_103 extends A_000, A_084, A_005, A_085, A_104, A_240 { + A_103 a_040(); + A_103 a_018(); + A_103 a_036(); + } + public interface A_093 extends A_090, A_152, A_005, A_054, A_085, A_091, + A_092, A_153, A_154, A_240 { + A_093 a_040(); + A_093 a_000(); + A_093 a_018(); + A_093 a_026(); + A_093 a_079(); + A_093 a_027(); + } + public interface A_204 extends A_000, A_005, A_205, A_240 { + A_204 a_040(); + A_204 a_086(); + } + public interface A_067 extends A_059, A_152, A_005, A_054, A_085, A_063, + A_062, A_064, A_065, A_066, A_061, A_060, A_153, A_154, A_240 { + A_067 a_040(); + A_067 a_000(); + A_067 a_018(); + A_067 a_046(); + A_067 a_045(); + A_067 a_047(); + A_067 a_049(); + A_067 a_044(); + A_067 a_043(); + A_067 a_079(); + } + public interface A_101 extends A_070, A_005, A_071, A_240 { + A_101 a_040(); + A_101 a_011(); + } + public interface A_224 extends A_000, A_225, A_240 { + A_224 a_054(); + A_224 a_040(); + } + public interface A_156 extends A_053, A_084, A_155, A_059, A_005, A_054, + A_085, A_160, A_162, A_063, A_062, A_064, A_065, A_066, A_061, + A_060, A_240 { + A_156 a_040(); + A_156 a_000(); + A_156 a_018(); + A_156 a_046(); + A_156 a_045(); + A_156 a_047(); + A_156 a_049(); + A_156 a_044(); + A_156 a_043(); + } + public interface A_122 extends A_116, A_152, A_005, A_054, A_085, A_121, + A_119, A_118, A_120, A_153, A_154, A_240 { + A_122 a_040(); + A_122 a_000(); + A_122 a_018(); + A_122 a_053(); + A_122 a_046(); + A_122 a_045(); + A_122 a_048(); + A_122 a_079(); + A_122 a_080(); + } + public interface A_184 extends A_183, A_152, A_005, A_054, A_085, A_185, + A_186, A_153, A_154, A_240 { + A_184 a_040(); + A_184 a_000(); + A_184 a_018(); + A_184 a_074(); + A_184 a_079(); + } + public interface A_180 extends A_000, A_181, A_240 { + A_180 a_005(); + A_180 a_040(); + } + public interface A_191 extends A_000, A_005, A_192, A_240 { + A_191 a_040(); + A_191 a_078(); + } + public interface A_107 extends A_106, A_094, A_005, A_115, A_113, A_112, + A_095, A_096, A_240 { + A_107 a_040(); + A_107 a_039(); + A_107 a_032(); + A_107 a_033(); + A_107 a_029(); + A_107 a_000(); + A_107 a_018(); + } + public interface A_102 extends A_196, A_005, A_203, A_240 { + A_102 a_040(); + A_102 a_084(); + } + public interface A_177 extends A_000, A_005, A_179, A_240 { + A_177 a_040(); + } + public interface A_123 extends A_195, A_005, A_054, A_124, A_127, A_128, + A_126, A_125, A_240 { + A_123 a_040(); + A_123 a_000(); + A_123 a_028(); + A_123 a_083(); + A_123 a_064(); + A_123 a_055(); + A_123 a_018(); + A_123 a_079(); + A_123 a_080(); + A_123 a_081(); + A_123 a_077(); + A_123 a_036(); + A_123 a_056(); + A_123 a_012(); + A_123 a_078(); + A_123 a_076(); + A_123 a_057(); + } + public interface A_088 extends A_106, A_086, A_240 { + A_088 a_040(); + A_088 a_039(); + A_088 a_032(); + A_088 a_033(); + A_088 a_000(); + A_088 a_018(); + A_088 a_024(); + A_088 a_098(); + } + public interface A_094 extends A_084, A_005, A_085, A_095, A_096, A_240 { + A_094 a_040(); + A_094 a_018(); + A_094 a_029(); + } + public interface A_105 extends A_098, A_236, A_005, A_085, A_153, A_074, + A_099, A_100, A_240 { + A_105 a_040(); + A_105 a_018(); + A_105 a_079(); + A_105 a_012(); + A_105 a_030(); + A_105 a_031(); + A_105 a_000(); + A_105 a_081(); + A_105 a_077(); + A_105 a_036(); + A_105 a_056(); + A_105 a_078(); + A_105 a_076(); + A_105 a_057(); + } + public interface A_199 extends A_196, A_090, A_005, A_054, A_085, A_091, + A_092, A_203, A_240 { + A_199 a_040(); + A_199 a_000(); + A_199 a_018(); + A_199 a_026(); + A_199 a_084(); + A_199 a_027(); + } + public interface A_080 extends A_075, A_236, A_005, A_085, A_153, A_074, + A_076, A_077, A_078, A_079, A_240 { + A_080 a_040(); + A_080 a_018(); + A_080 a_079(); + A_080 a_012(); + A_080 a_014(); + A_080 a_015(); + A_080 a_016(); + A_080 a_000(); + A_080 a_080(); + A_080 a_081(); + A_080 a_077(); + A_080 a_036(); + A_080 a_056(); + A_080 a_078(); + A_080 a_076(); + A_080 a_057(); + } + public interface A_172 extends A_170, A_219, A_005, A_054, A_085, A_173, + A_222, A_223, A_174, A_240 { + A_172 a_040(); + A_172 a_000(); + A_172 a_018(); + A_172 a_069(); + A_172 a_095(); + A_172 a_072(); + } + public interface A_108 extends A_106, A_180, A_206, A_005, A_115, A_113, + A_112, A_181, A_208, A_207, A_209, A_240 { + A_108 a_040(); + A_108 a_039(); + A_108 a_032(); + A_108 a_033(); + A_108 a_005(); + A_108 a_089(); + A_108 a_088(); + A_108 a_090(); + A_108 a_000(); + A_108 a_018(); + } + public interface A_195 extends A_053, A_084, A_152, A_193, A_189, A_103, + A_131, A_073, A_191, A_187, A_133, A_005, A_054, A_085, A_153, + A_154, A_194, A_190, A_104, A_132, A_074, A_192, A_188, A_134, + A_240 { + A_195 a_040(); + A_195 a_000(); + A_195 a_018(); + A_195 a_079(); + A_195 a_080(); + A_195 a_081(); + A_195 a_077(); + A_195 a_036(); + A_195 a_056(); + A_195 a_012(); + A_195 a_078(); + A_195 a_076(); + A_195 a_057(); + } + public interface A_220 extends A_219, A_236, A_005, A_085, A_153, A_074, + A_240 { + A_220 a_040(); + A_220 a_018(); + A_220 a_079(); + A_220 a_012(); + A_220 a_000(); + A_220 a_095(); + A_220 a_080(); + A_220 a_081(); + A_220 a_077(); + A_220 a_036(); + A_220 a_056(); + A_220 a_078(); + A_220 a_076(); + A_220 a_057(); + } + public interface A_146 extends A_000, A_005, A_151, A_150, A_149, A_240 { + A_146 a_040(); + A_146 a_073(); + A_146 a_051(); + } + public interface A_090 extends A_000, A_053, A_084, A_005, A_054, A_085, + A_237, A_091, A_092, A_240 { + A_090 a_040(); + A_090 a_000(); + A_090 a_018(); + A_090 a_027(); + A_090 a_026(); + } + public interface A_057 extends A_106, A_058, A_240 { + A_057 a_002(); + A_057 a_040(); + A_057 a_039(); + A_057 a_032(); + A_057 a_033(); + A_057 a_000(); + A_057 a_018(); + } + public interface A_098 extends A_084, A_005, A_085, A_099, A_100, A_240 { + } + public interface A_136 extends A_084, A_005, A_085, A_138, A_137, A_240 { + } + public interface A_116 extends A_053, A_084, A_005, A_054, A_085, A_121, + A_119, A_118, A_120, A_240 { + A_116 a_040(); + A_116 a_000(); + A_116 a_018(); + A_116 a_053(); + A_116 a_046(); + A_116 a_045(); + A_116 a_048(); + } + public interface A_159 extends A_053, A_005, A_054, A_160, A_240 { + A_159 a_040(); + A_159 a_000(); + } + public interface A_140 extends A_139, A_236, A_005, A_085, A_153, A_074, + A_141, A_142, A_240 { + A_140 a_040(); + A_140 a_018(); + A_140 a_079(); + A_140 a_012(); + A_140 a_060(); + A_140 a_061(); + A_140 a_000(); + A_140 a_080(); + A_140 a_081(); + A_140 a_077(); + A_140 a_036(); + A_140 a_056(); + A_140 a_078(); + A_140 a_076(); + A_140 a_057(); + } + public interface A_178 extends A_177, A_144, A_005, A_179, A_145, A_240 { + A_178 a_040(); + } + public interface A_139 extends A_053, A_005, A_054, A_141, A_142, A_240 { + A_139 a_040(); + A_139 a_000(); + A_139 a_060(); + A_139 a_061(); + } + public interface A_165 extends A_163, A_152, A_005, A_054, A_166, A_167, + A_153, A_154, A_240 { + A_165 a_040(); + A_165 a_000(); + A_165 a_065(); + A_165 a_066(); + A_165 a_079(); + A_165 a_080(); + } + public interface A_053 extends A_000, A_238, A_005, A_054, A_240 { + A_053 a_040(); + A_053 a_000(); + } + public interface A_135 extends A_136, A_236, A_005, A_085, A_153, A_074, + A_138, A_137, A_240 { + A_135 a_040(); + A_135 a_018(); + A_135 a_079(); + A_135 a_012(); + A_135 a_059(); + A_135 a_058(); + A_135 a_000(); + A_135 a_081(); + A_135 a_077(); + A_135 a_036(); + A_135 a_056(); + A_135 a_078(); + A_135 a_076(); + A_135 a_057(); + } + public interface A_148 extends A_146, A_236, A_005, A_085, A_153, A_074, + A_240 { + A_148 a_040(); + A_148 a_018(); + A_148 a_079(); + A_148 a_012(); + A_148 a_051(); + A_148 a_000(); + A_148 a_081(); + A_148 a_077(); + A_148 a_036(); + A_148 a_056(); + A_148 a_078(); + A_148 a_076(); + A_148 a_057(); + } + public interface A_206 extends A_000, A_005, A_208, A_207, A_209, A_240 { + A_206 a_040(); + A_206 a_089(); + A_206 a_088(); + A_206 a_090(); + } + public interface A_215 extends A_000, A_005, A_216, A_240 { + A_215 a_040(); + A_215 a_092(); + } + public interface A_117 extends A_116, A_090, A_005, A_054, A_085, A_121, + A_119, A_118, A_120, A_091, A_092, A_240 { + A_117 a_040(); + A_117 a_000(); + A_117 a_018(); + A_117 a_053(); + A_117 a_046(); + A_117 a_045(); + A_117 a_048(); + A_117 a_026(); + A_117 a_027(); + } + public interface A_082 extends A_000, A_005, A_083, A_240 { + A_082 a_040(); + } + public interface A_182 extends A_053, A_084, A_152, A_193, A_189, A_005, + A_054, A_085, A_153, A_154, A_194, A_190, A_240 { + A_182 a_040(); + A_182 a_000(); + A_182 a_018(); + A_182 a_079(); + A_182 a_080(); + A_182 a_081(); + A_182 a_077(); + } + public interface A_055 extends A_000, A_005, A_056, A_240 { + } + public interface A_193 extends A_000, A_005, A_194, A_240 { + A_193 a_040(); + A_193 a_081(); + } + public interface A_214 extends A_212, A_152, A_005, A_054, A_085, A_217, + A_218, A_153, A_154, A_240 { + A_214 a_040(); + A_214 a_000(); + A_214 a_018(); + A_214 a_093(); + A_214 a_079(); + } + public interface A_059 extends A_053, A_084, A_005, A_054, A_085, A_063, + A_062, A_064, A_065, A_066, A_061, A_060, A_240 { + A_059 a_040(); + A_059 a_000(); + A_059 a_018(); + A_059 a_046(); + A_059 a_045(); + A_059 a_047(); + A_059 a_048(); + A_059 a_049(); + A_059 a_044(); + A_059 a_043(); + } + public interface A_226 extends A_000, A_228, A_240 { + A_226 a_100(); + A_226 a_040(); + } + public interface A_210 extends A_053, A_005, A_054, A_211, A_240 { + A_210 a_040(); + A_210 a_000(); + A_210 a_091(); + } + public interface A_073 extends A_000, A_005, A_074, A_240 { + A_073 a_040(); + A_073 a_012(); + } + public interface A_157 extends A_155, A_236, A_005, A_085, A_153, A_074, + A_160, A_162, A_240 { + A_157 a_040(); + A_157 a_018(); + A_157 a_079(); + A_157 a_012(); + A_157 a_000(); + A_157 a_081(); + A_157 a_077(); + A_157 a_036(); + A_157 a_056(); + A_157 a_078(); + A_157 a_076(); + A_157 a_057(); + } + public interface A_131 extends A_053, A_005, A_054, A_132, A_240 { + A_131 a_040(); + A_131 a_000(); + A_131 a_056(); + } + public interface A_152 extends A_053, A_005, A_054, A_153, A_154, A_240 { + A_152 a_040(); + A_152 a_000(); + A_152 a_079(); + } + public interface A_106 extends A_053, A_084, A_005, A_115, A_113, A_112, + A_240 { + A_106 a_040(); + A_106 a_039(); + A_106 a_032(); + A_106 a_033(); + A_106 a_000(); + A_106 a_018(); + } + public interface A_147 extends A_106, A_236, A_005, A_085, A_153, A_074, + A_240 { + A_147 a_040(); + A_147 a_018(); + A_147 a_012(); + A_147 a_039(); + A_147 a_032(); + A_147 a_033(); + A_147 a_000(); + A_147 a_081(); + A_147 a_077(); + A_147 a_036(); + A_147 a_056(); + A_147 a_078(); + A_147 a_076(); + A_147 a_057(); + } + public interface A_081 extends A_075, A_152, A_005, A_054, A_076, A_077, + A_078, A_079, A_153, A_154, A_240 { + A_081 a_040(); + A_081 a_000(); + A_081 a_014(); + A_081 a_015(); + A_081 a_016(); + A_081 a_079(); + A_081 a_080(); + } + public interface A_197 extends A_196, A_070, A_236, A_005, A_085, A_153, + A_074, A_203, A_071, A_240 { + A_197 a_040(); + A_197 a_018(); + A_197 a_079(); + A_197 a_012(); + A_197 a_084(); + A_197 a_011(); + A_197 a_000(); + A_197 a_081(); + A_197 a_077(); + A_197 a_036(); + A_197 a_056(); + A_197 a_078(); + A_197 a_076(); + A_197 a_057(); + } + public interface A_213 extends A_212, A_215, A_236, A_005, A_085, A_153, + A_074, A_240 { + A_213 a_040(); + A_213 a_018(); + A_213 a_079(); + A_213 a_012(); + A_213 a_000(); + A_213 a_093(); + A_213 a_092(); + A_213 a_081(); + A_213 a_077(); + A_213 a_036(); + A_213 a_056(); + A_213 a_078(); + A_213 a_076(); + A_213 a_057(); + } + public interface A_143 extends A_139, A_152, A_005, A_141, A_142, A_153, + A_154, A_240 { + A_143 a_040(); + A_143 a_060(); + A_143 a_061(); + A_143 a_079(); + A_143 a_080(); + A_143 a_000(); + } + public interface A_221 extends A_219, A_152, A_005, A_054, A_085, A_222, + A_223, A_153, A_154, A_240 { + A_221 a_040(); + A_221 a_000(); + A_221 a_018(); + A_221 a_095(); + A_221 a_079(); + A_221 a_080(); + } + public interface A_196 extends A_000, A_005, A_203, A_240 { + A_196 a_040(); + A_196 a_084(); + } + public interface A_155 extends A_159, A_161, A_005, A_054, A_160, A_162, + A_240 { + A_155 a_040(); + A_155 a_000(); + } + public interface A_097 extends A_094, A_152, A_005, A_085, A_095, A_096, + A_153, A_154, A_240 { + A_097 a_040(); + A_097 a_018(); + A_097 a_029(); + A_097 a_079(); + A_097 a_000(); + } + public interface A_219 extends A_053, A_084, A_005, A_054, A_085, A_222, + A_223, A_240 { + A_219 a_040(); + A_219 a_000(); + A_219 a_018(); + A_219 a_095(); + A_219 a_096(); + } + public interface A_068 extends A_053, A_005, A_054, A_069, A_240 { + A_068 a_040(); + A_068 a_000(); + A_068 a_010(); + } + public interface A_114 extends A_106, A_236, A_005, A_085, A_153, A_074, + A_115, A_113, A_240 { + A_114 a_040(); + A_114 a_018(); + A_114 a_079(); + A_114 a_012(); + A_114 a_039(); + A_114 a_032(); + A_114 a_033(); + A_114 a_000(); + A_114 a_080(); + A_114 a_081(); + A_114 a_077(); + A_114 a_036(); + A_114 a_056(); + A_114 a_078(); + A_114 a_076(); + A_114 a_057(); + } + public interface A_163 extends A_053, A_005, A_054, A_166, A_167, A_240 { + A_163 a_040(); + A_163 a_000(); + A_163 a_065(); + A_163 a_066(); + } + public interface A_187 extends A_000, A_005, A_188, A_240 { + A_187 a_040(); + A_187 a_076(); + } + public interface A_144 extends A_000, A_005, A_145, A_240 { + A_144 a_040(); + } + public interface A_111 extends A_106, A_212, A_219, A_170, A_005, A_054, + A_085, A_115, A_113, A_112, A_217, A_218, A_222, A_223, A_173, + A_240 { + A_111 a_040(); + A_111 a_000(); + A_111 a_018(); + A_111 a_039(); + A_111 a_032(); + A_111 a_033(); + A_111 a_093(); + A_111 a_095(); + A_111 a_069(); + } + public interface A_168 extends A_000, A_053, A_005, A_054, A_169, A_240 { + A_168 a_040(); + A_168 a_000(); + A_168 a_037(); + } + public interface A_227 extends A_226, A_236, A_005, A_085, A_153, A_074, + A_228, A_240 { + A_227 a_040(); + A_227 a_018(); + A_227 a_079(); + A_227 a_012(); + A_227 a_100(); + A_227 a_000(); + A_227 a_081(); + A_227 a_077(); + A_227 a_036(); + A_227 a_056(); + A_227 a_078(); + A_227 a_076(); + A_227 a_057(); + } + public interface A_075 extends A_053, A_005, A_054, A_076, A_077, A_078, + A_079, A_240 { + A_075 a_040(); + A_075 a_000(); + A_075 a_014(); + A_075 a_015(); + A_075 a_016(); + A_075 a_017(); + } + public interface A_008 extends A_239 { + A_008 a_040(); + } + public interface A_072 extends A_070, A_090, A_005, A_054, A_085, A_091, + A_092, A_071, A_240 { + A_072 a_040(); + A_072 a_000(); + A_072 a_018(); + A_072 a_026(); + A_072 a_011(); + A_072 a_027(); + } + public interface A_170 extends A_000, A_005, A_173, A_174, A_240 { + A_170 a_040(); + A_170 a_069(); + A_170 a_072(); + } + public interface A_012 extends A_239 { + A_012 a_063(); + } + public interface A_164 extends A_163, A_236, A_005, A_085, A_153, A_074, + A_166, A_167, A_240 { + A_164 a_040(); + A_164 a_018(); + A_164 a_079(); + A_164 a_012(); + A_164 a_065(); + A_164 a_066(); + A_164 a_000(); + A_164 a_080(); + A_164 a_081(); + A_164 a_077(); + A_164 a_036(); + A_164 a_056(); + A_164 a_078(); + A_164 a_076(); + A_164 a_057(); + } + public interface A_006 extends A_239 { + A_006 a_004(); + } + public interface A_007 extends A_239 { + } + public interface A_201 extends A_200, A_236, A_005, A_085, A_153, A_074, + A_240 { + A_201 a_040(); + A_201 a_018(); + A_201 a_079(); + A_201 a_012(); + A_201 a_085(); + A_201 a_000(); + A_201 a_081(); + A_201 a_077(); + A_201 a_036(); + A_201 a_056(); + A_201 a_078(); + A_201 a_076(); + A_201 a_057(); + } + public interface A_011 extends A_239 { + A_011 a_062(); + } + public interface A_014 extends A_239 { + A_014 a_075(); + } + public interface A_009 extends A_239 { + A_009 a_045(); + } + public interface A_010 extends A_239 { + A_010 a_050(); + } + public interface A_013 extends A_239 { + A_013 a_067(); + } + public interface A_236 extends A_195, A_005, A_085, A_153, A_074, A_240 { + A_236 a_040(); + A_236 a_018(); + A_236 a_079(); + A_236 a_012(); + A_236 a_000(); + A_236 a_081(); + A_236 a_077(); + A_236 a_036(); + A_236 a_056(); + A_236 a_078(); + A_236 a_076(); + A_236 a_057(); + } + interface X_1 { AbstractList x_8(); -- GitLab From 13f739d330e393f840d134f5327a025957e1f795 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 9 Feb 2022 04:10:37 +0000 Subject: [PATCH 007/203] 8280830: Change NonblockingQueue::try_pop variable named "result" Reviewed-by: dholmes --- .../utilities/nonblockingQueue.inline.hpp | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/hotspot/share/utilities/nonblockingQueue.inline.hpp b/src/hotspot/share/utilities/nonblockingQueue.inline.hpp index e16c8cb57d0..2845822b204 100644 --- a/src/hotspot/share/utilities/nonblockingQueue.inline.hpp +++ b/src/hotspot/share/utilities/nonblockingQueue.inline.hpp @@ -135,36 +135,36 @@ template bool NonblockingQueue::try_pop(T** node_ptr) { // We only need memory_order_consume. Upgrade it to "load_acquire" // as the memory_order_consume API is not ready for use yet. - T* result = Atomic::load_acquire(&_head); - if (result == NULL) { + T* old_head = Atomic::load_acquire(&_head); + if (old_head == NULL) { *node_ptr = NULL; return true; // Queue is empty. } - T* next_node = Atomic::load_acquire(next_ptr(*result)); + T* next_node = Atomic::load_acquire(next_ptr(*old_head)); if (!is_end(next_node)) { // [Clause 1] // There are several cases for next_node. // (1) next_node is the extension of the queue's list. - // (2) next_node is NULL, because a competing try_pop took result. + // (2) next_node is NULL, because a competing try_pop took old_head. // (3) next_node is the extension of some unrelated list, because a - // competing try_pop took result and put it in some other list. + // competing try_pop took old_head and put it in some other list. // - // Attempt to advance the list, replacing result with next_node in + // Attempt to advance the list, replacing old_head with next_node in // _head. The success or failure of that attempt, along with the value // of next_node, are used to partially determine which case we're in and // how to proceed. In particular, advancement will fail for case (3). - if (result != Atomic::cmpxchg(&_head, result, next_node)) { + if (old_head != Atomic::cmpxchg(&_head, old_head, next_node)) { // [Clause 1a] // The cmpxchg to advance the list failed; a concurrent try_pop won - // the race and claimed result. This can happen for any of the + // the race and claimed old_head. This can happen for any of the // next_node cases. return false; } else if (next_node == NULL) { // [Clause 1b] // The cmpxchg to advance the list succeeded, but a concurrent try_pop - // has already claimed result (see [Clause 2] - result was the last - // entry in the list) by nulling result's next field. The advance set + // has already claimed old_head (see [Clause 2] - old_head was the last + // entry in the list) by nulling old_head's next field. The advance set // _head to NULL, "helping" the competing try_pop. _head will remain // NULL until a subsequent push/append. This is a lost race, and we // report it as such for consistency, though we could report the queue @@ -174,17 +174,17 @@ bool NonblockingQueue::try_pop(T** node_ptr) { return false; } else { // [Clause 1c] - // Successfully advanced the list and claimed result. next_node was - // in the extension of the queue's list. Return result after + // Successfully advanced the list and claimed old_head. next_node was + // in the extension of the queue's list. Return old_head after // unlinking it from next_node. - set_next(*result, NULL); - *node_ptr = result; + set_next(*old_head, NULL); + *node_ptr = old_head; return true; } - } else if (is_end(Atomic::cmpxchg(next_ptr(*result), next_node, (T*)NULL))) { + } else if (is_end(Atomic::cmpxchg(next_ptr(*old_head), next_node, (T*)NULL))) { // [Clause 2] - // Result was the last entry and we've claimed it by setting its next + // Old_head was the last entry and we've claimed it by setting its next // value to NULL. However, this leaves the queue in disarray. Fix up // the queue, possibly in conjunction with other concurrent operations. // Any further try_pops will consider the queue empty until a @@ -194,24 +194,24 @@ bool NonblockingQueue::try_pop(T** node_ptr) { // dealing with _head first gives a stronger invariant in append, and is // also consistent with [Clause 1b]. - // Attempt to change the queue head from result to NULL. Failure of the + // Attempt to change the queue head from old_head to NULL. Failure of the // cmpxchg indicates a concurrent operation updated _head first. That // could be either a push/append or a try_pop in [Clause 1b]. - Atomic::cmpxchg(&_head, result, (T*)NULL); + Atomic::cmpxchg(&_head, old_head, (T*)NULL); - // Attempt to change the queue tail from result to NULL. Failure of the + // Attempt to change the queue tail from old_head to NULL. Failure of the // cmpxchg indicates that a concurrent push/append updated _tail first. - // That operation will eventually recognize the old tail (our result) is + // That operation will eventually recognize the old tail (our old_head) is // no longer in the list and update _head from the list being appended. - Atomic::cmpxchg(&_tail, result, (T*)NULL); + Atomic::cmpxchg(&_tail, old_head, (T*)NULL); - // The queue has been restored to order, and we can return the result. - *node_ptr = result; + // The queue has been restored to order, and we can return old_head. + *node_ptr = old_head; return true; } else { // [Clause 3] - // Result was the last entry in the list, but either a concurrent + // Old_head was the last entry in the list, but either a concurrent // try_pop claimed it first or a concurrent push/append extended the // list from it. Either way, we lost the race to claim it. return false; -- GitLab From bce5dd17665d1cdf2901690ca54f84ec200560af Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 9 Feb 2022 04:38:11 +0000 Subject: [PATCH 008/203] 8280438: Improve BufferNode::Allocator::release to avoid walking pending list Reviewed-by: iwalulya, tschatzl --- src/hotspot/share/gc/shared/ptrQueue.cpp | 93 +++++++++++++++--------- src/hotspot/share/gc/shared/ptrQueue.hpp | 33 +++++++-- 2 files changed, 87 insertions(+), 39 deletions(-) diff --git a/src/hotspot/share/gc/shared/ptrQueue.cpp b/src/hotspot/share/gc/shared/ptrQueue.cpp index 3838b4f37ee..0a95e36de2b 100644 --- a/src/hotspot/share/gc/shared/ptrQueue.cpp +++ b/src/hotspot/share/gc/shared/ptrQueue.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,11 +56,38 @@ void BufferNode::deallocate(BufferNode* node) { FREE_C_HEAP_ARRAY(char, node); } +BufferNode::Allocator::PendingList::PendingList() : + _tail(nullptr), _head(nullptr), _count(0) {} + +BufferNode::Allocator::PendingList::~PendingList() { + delete_list(Atomic::load(&_head)); +} + +size_t BufferNode::Allocator::PendingList::add(BufferNode* node) { + assert(node->next() == nullptr, "precondition"); + BufferNode* old_head = Atomic::xchg(&_head, node); + if (old_head != nullptr) { + node->set_next(old_head); + } else { + assert(_tail == nullptr, "invariant"); + _tail = node; + } + return Atomic::add(&_count, size_t(1)); +} + +BufferNodeList BufferNode::Allocator::PendingList::take_all() { + BufferNodeList result{Atomic::load(&_head), _tail, Atomic::load(&_count)}; + Atomic::store(&_head, (BufferNode*)nullptr); + _tail = nullptr; + Atomic::store(&_count, size_t(0)); + return result; +} + BufferNode::Allocator::Allocator(const char* name, size_t buffer_size) : _buffer_size(buffer_size), - _pending_list(), + _pending_lists(), + _active_pending_list(0), _free_list(), - _pending_count(0), _free_count(0), _transfer_lock(false) { @@ -70,7 +97,6 @@ BufferNode::Allocator::Allocator(const char* name, size_t buffer_size) : BufferNode::Allocator::~Allocator() { delete_list(_free_list.pop_all()); - delete_list(_pending_list.pop_all()); } void BufferNode::Allocator::delete_list(BufferNode* list) { @@ -109,14 +135,11 @@ BufferNode* BufferNode::Allocator::allocate() { // pop inside a critical section, and release synchronizes on the // critical sections before adding to the _free_list. But we don't // want to make every release have to do a synchronize. Instead, we -// initially place released nodes on the _pending_list, and transfer +// initially place released nodes on the pending list, and transfer // them to the _free_list in batches. Only one transfer at a time is -// permitted, with a lock bit to control access to that phase. A -// transfer takes all the nodes from the _pending_list, synchronizes on -// the _free_list pops, and then adds the former pending nodes to the -// _free_list. While that's happening, other threads might be adding -// other nodes to the _pending_list, to be dealt with by some later -// transfer. +// permitted, with a lock bit to control access to that phase. While +// a transfer is in progress, other threads might be adding other nodes +// to the pending list, to be dealt with by some later transfer. void BufferNode::Allocator::release(BufferNode* node) { assert(node != NULL, "precondition"); assert(node->next() == NULL, "precondition"); @@ -130,15 +153,20 @@ void BufferNode::Allocator::release(BufferNode* node) { // similar, due to how the buffers are used. const size_t trigger_transfer = 10; - // Add to pending list. Update count first so no underflow in transfer. - size_t pending_count = Atomic::add(&_pending_count, 1u); - _pending_list.push(*node); - if (pending_count > trigger_transfer) { - try_transfer_pending(); + // The pending list is double-buffered. Add node to the currently active + // pending list, within a critical section so a transfer will wait until + // we're done with what might be the pending list to be transferred. + { + GlobalCounter::CriticalSection cs(Thread::current()); + uint index = Atomic::load_acquire(&_active_pending_list); + size_t count = _pending_lists[index].add(node); + if (count <= trigger_transfer) return; } + // Attempt transfer when number pending exceeds the transfer threshold. + try_transfer_pending(); } -// Try to transfer nodes from _pending_list to _free_list, with a +// Try to transfer nodes from the pending list to _free_list, with a // synchronization delay for any in-progress pops from the _free_list, // to solve ABA there. Return true if performed a (possibly empty) // transfer, false if blocked from doing so by some other thread's @@ -151,27 +179,26 @@ bool BufferNode::Allocator::try_transfer_pending() { } // Have the lock; perform the transfer. - // Claim all the pending nodes. - BufferNode* first = _pending_list.pop_all(); - if (first != NULL) { - // Prepare to add the claimed nodes, and update _pending_count. - BufferNode* last = first; - size_t count = 1; - for (BufferNode* next = first->next(); next != NULL; next = next->next()) { - last = next; - ++count; - } - Atomic::sub(&_pending_count, count); + // Change which pending list is active. Don't need an atomic RMW since + // we have the lock and we're the only writer. + uint index = Atomic::load(&_active_pending_list); + uint new_active = (index + 1) % ARRAY_SIZE(_pending_lists); + Atomic::release_store(&_active_pending_list, new_active); - // Wait for any in-progress pops, to avoid ABA for them. - GlobalCounter::write_synchronize(); + // Wait for all critical sections in the buffer life-cycle to complete. + // This includes _free_list pops and adding to the now inactive pending + // list. + GlobalCounter::write_synchronize(); - // Add synchronized nodes to _free_list. + // Transfer the inactive pending list to _free_list. + BufferNodeList transfer_list = _pending_lists[index].take_all(); + size_t count = transfer_list._entry_count; + if (count > 0) { // Update count first so no underflow in allocate(). Atomic::add(&_free_count, count); - _free_list.prepend(*first, *last); + _free_list.prepend(*transfer_list._head, *transfer_list._tail); log_trace(gc, ptrqueue, freelist) - ("Transferred %s pending to free: " SIZE_FORMAT, name(), count); + ("Transferred %s pending to free: %zu", name(), count); } Atomic::release_store(&_transfer_lock, false); return true; diff --git a/src/hotspot/share/gc/shared/ptrQueue.hpp b/src/hotspot/share/gc/shared/ptrQueue.hpp index f1533e5128d..be07f3e58b3 100644 --- a/src/hotspot/share/gc/shared/ptrQueue.hpp +++ b/src/hotspot/share/gc/shared/ptrQueue.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #ifndef SHARE_GC_SHARED_PTRQUEUE_HPP #define SHARE_GC_SHARED_PTRQUEUE_HPP +#include "gc/shared/bufferNodeList.hpp" #include "memory/padded.hpp" #include "utilities/align.hpp" #include "utilities/debug.hpp" @@ -181,17 +182,37 @@ class BufferNode::Allocator { #define DECLARE_PADDED_MEMBER(Id, Type, Name) \ Type Name; DEFINE_PAD_MINUS_SIZE(Id, DEFAULT_CACHE_LINE_SIZE, sizeof(Type)) + class PendingList { + BufferNode* _tail; + DECLARE_PADDED_MEMBER(1, BufferNode* volatile, _head); + DECLARE_PADDED_MEMBER(2, volatile size_t, _count); + + NONCOPYABLE(PendingList); + + public: + PendingList(); + ~PendingList(); + + // Add node to the list. Returns the number of nodes in the list. + // Thread-safe against concurrent add operations. + size_t add(BufferNode* node); + + // Return the nodes in the list, leaving the list empty. + // Not thread-safe. + BufferNodeList take_all(); + }; + const size_t _buffer_size; char _name[DEFAULT_CACHE_LINE_SIZE - sizeof(size_t)]; // Use name as padding. - DECLARE_PADDED_MEMBER(1, Stack, _pending_list); + PendingList _pending_lists[2]; + DECLARE_PADDED_MEMBER(1, volatile uint, _active_pending_list); DECLARE_PADDED_MEMBER(2, Stack, _free_list); - DECLARE_PADDED_MEMBER(3, volatile size_t, _pending_count); - DECLARE_PADDED_MEMBER(4, volatile size_t, _free_count); - DECLARE_PADDED_MEMBER(5, volatile bool, _transfer_lock); + DECLARE_PADDED_MEMBER(3, volatile size_t, _free_count); + DECLARE_PADDED_MEMBER(4, volatile bool, _transfer_lock); #undef DECLARE_PADDED_MEMBER - void delete_list(BufferNode* list); + static void delete_list(BufferNode* list); bool try_transfer_pending(); NONCOPYABLE(Allocator); -- GitLab From fc77217814eb1a346d7380299abdc2b01a69b4de Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 9 Feb 2022 06:28:00 +0000 Subject: [PATCH 009/203] 8281168: Micro-optimize VarForm.getMemberName for interpreter Reviewed-by: redestad, vlivanov, mchung --- .../share/classes/java/lang/invoke/VarForm.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/lang/invoke/VarForm.java b/src/java.base/share/classes/java/lang/invoke/VarForm.java index 7b118dbe470..1308c48cebb 100644 --- a/src/java.base/share/classes/java/lang/invoke/VarForm.java +++ b/src/java.base/share/classes/java/lang/invoke/VarForm.java @@ -109,9 +109,14 @@ final class VarForm { @ForceInline final MemberName getMemberName(int mode) { - MemberName mn = getMemberNameOrNull(mode); + // Can be simplified by calling getMemberNameOrNull, but written in this + // form to improve interpreter/coldpath performance. + MemberName mn = memberName_table[mode]; if (mn == null) { - throw new UnsupportedOperationException(); + mn = resolveMemberName(mode); + if (mn == null) { + throw new UnsupportedOperationException(); + } } return mn; } -- GitLab From cb2f8caed2de1bf0a85a7ebfd232c36371e06c98 Mon Sep 17 00:00:00 2001 From: Artem Semenov Date: Wed, 9 Feb 2022 06:50:35 +0000 Subject: [PATCH 010/203] 8281338: NSAccessibilityPressAction action for tree node and NSAccessibilityShowMenuAcgtion action not working Reviewed-by: ant, kizune --- .../awt/JavaAccessibilityAction.m | 4 +- .../java/awt/a11y/AccessibleActionsTest.java | 183 ++++++++++++++++++ 2 files changed, 185 insertions(+), 2 deletions(-) create mode 100644 test/jdk/java/awt/a11y/AccessibleActionsTest.java diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaAccessibilityAction.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaAccessibilityAction.m index 06e998ec409..173ad891051 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaAccessibilityAction.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaAccessibilityAction.m @@ -161,8 +161,8 @@ void initializeActions() { [sActions setObject:NSAccessibilityPressAction forKey:@"click"]; [sActions setObject:NSAccessibilityIncrementAction forKey:@"increment"]; [sActions setObject:NSAccessibilityDecrementAction forKey:@"decrement"]; - [sActions setObject:NSAccessibilityShowMenuAction forKey:@"togglePopup"]; - [sActions setObject:NSAccessibilityPressAction forKey:@"toggleExpand"]; + [sActions setObject:NSAccessibilityShowMenuAction forKey:@"toggle popup"]; + [sActions setObject:NSAccessibilityPressAction forKey:@"toggleexpand"]; sActionSelectors = [[NSMutableDictionary alloc] initWithCapacity:actionsCount]; diff --git a/test/jdk/java/awt/a11y/AccessibleActionsTest.java b/test/jdk/java/awt/a11y/AccessibleActionsTest.java new file mode 100644 index 00000000000..b8f6e5d28f9 --- /dev/null +++ b/test/jdk/java/awt/a11y/AccessibleActionsTest.java @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, JetBrains s.r.o.. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8281338 + * @summary Test for an element that has more than one Accessibility Action + * @author Artem.Semenov@jetbrains.com + * @run main/manual AccessibleActionsTest + * @requires (os.family == "mac") + */ + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleAction; +import javax.accessibility.AccessibleContext; +import javax.swing.*; +import javax.swing.tree.TreeModel; +import javax.swing.tree.TreePath; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Hashtable; +import java.util.concurrent.CountDownLatch; + +public class AccessibleActionsTest extends AccessibleComponentTest { + + @Override + public CountDownLatch createCountDownLatch() { + return new CountDownLatch(1); + } + + void createTest() { + INSTRUCTIONS = "INSTRUCTIONS:\n" + + "Check a11y actions.\n\n" + + "Turn screen reader on, and Tab to the label.\n\n" + + "Perform the VO action \"Press\" (VO+space)\n" + + "Perform the VO action \"Show menu\" (VO+m)\n\n" + + "If after the first action the text of the label has changed, and after the second action the menu appears tab further and press PASS, otherwise press FAIL."; + + exceptionString = "AccessibleAction test failed!"; + super.createUI(new AccessibleActionsTestFrame(), "AccessibleActionsTest"); + } + + void createTree() { + INSTRUCTIONS = "INSTRUCTIONS:\n" + + "Check a11y actions.\n\n" + + "Turn screen reader on, and Tab to the label.\n\n" + + "Perform the VO action \"Press\" (VO+space) on tree nodes\n\n" + + "If after press the tree node is expanded tab further and press PASS, otherwise press FAIL."; + + String root = "Root"; + String[] nodes = new String[] {"One node", "Two node"}; + String[][] leafs = new String[][]{{"leaf 1.1", "leaf 1.2", "leaf 1.3", "leaf 1.4"}, + {"leaf 2.1", "leaf 2.2", "leaf 2.3", "leaf 2.4"}}; + + Hashtable data = new Hashtable(); + for (int i = 0; i < nodes.length; i++) { + data.put(nodes[i], leafs[i]); + } + + JTree tree = new JTree(data); + tree.setRootVisible(true); + + JPanel panel = new JPanel(); + panel.setLayout(new FlowLayout()); + JScrollPane scrollPane = new JScrollPane(tree); + panel.add(scrollPane); + panel.setFocusable(false); + + exceptionString = "AccessibleAction test failed!"; + super.createUI(panel, "AccessibleActionsTest"); + } + + public static void main(String[] args) throws Exception { + AccessibleActionsTest test = new AccessibleActionsTest(); + + countDownLatch = test.createCountDownLatch(); + SwingUtilities.invokeLater(test::createTest); + countDownLatch.await(); + + if (!testResult) { + throw new RuntimeException(a11yTest.exceptionString); + } + + countDownLatch = test.createCountDownLatch(); + SwingUtilities.invokeLater(test::createTree); + countDownLatch.await(); + + if (!testResult) { + throw new RuntimeException(a11yTest.exceptionString); + } + } + + private class AccessibleActionsTestFrame extends JPanel { + + public AccessibleActionsTestFrame() { + MyLabel label = new MyLabel("I'm waiting for the push"); + label.setComponentPopupMenu(createPopup()); + label.setFocusable(true); + add(label); + setLayout(new FlowLayout()); + } + + private static class MyLabel extends JLabel { + public MyLabel(String text) { + super(text); + } + + @Override + public AccessibleContext getAccessibleContext() { + if (accessibleContext == null) { + accessibleContext = new MyAccessibleJLabel(); + } + return accessibleContext; + } + + private class MyAccessibleJLabel extends JLabel.AccessibleJLabel { + @Override + public AccessibleAction getAccessibleAction() { + return new AccessibleAction() { + @Override + public int getAccessibleActionCount() { + return 2; + } + + @Override + public String getAccessibleActionDescription(int i) { + if (i == 0) { + return AccessibleAction.CLICK; + } + return AccessibleAction.TOGGLE_POPUP; + } + + @Override + public boolean doAccessibleAction(int i) { + if (i == 0) { + changeText(MyLabel.this, "label is pressed"); + return true; + } + JPopupMenu popup = createPopup(); + popup.show(MyLabel.this, 0, 0); + return true; + } + }; + } + } + } + + private static JPopupMenu createPopup() { + JPopupMenu popup = new JPopupMenu("MENU"); + popup.add("One"); + popup.add("Two"); + popup.add("Three"); + return popup; + } + + private static void changeText(JLabel label, String text) { + label.setText(text); + } + + } +} -- GitLab From 072e7b4da0449ab7c1ab1ba0cfbb3db233823e7c Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 9 Feb 2022 06:53:09 +0000 Subject: [PATCH 011/203] 8272807: Permit use of memory concurrent with pretouch Reviewed-by: shade, stuefe --- src/hotspot/share/runtime/os.cpp | 30 ++++++++++++++++++++++++------ src/hotspot/share/runtime/os.hpp | 7 +++---- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 29a3d7622f6..a85be30ec48 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -1745,13 +1745,31 @@ void os::print_memory_mappings(outputStream* st) { os::print_memory_mappings(nullptr, (size_t)-1, st); } +// Pretouching must use a store, not just a load. On many OSes loads from +// fresh memory would be satisfied from a single mapped page containing all +// zeros. We need to store something to each page to get them backed by +// their own memory, which is the effect we want here. An atomic add of +// zero is used instead of a simple store, allowing the memory to be used +// while pretouch is in progress, rather than requiring users of the memory +// to wait until the entire range has been touched. This is technically +// a UB data race, but doesn't cause any problems for us. void os::pretouch_memory(void* start, void* end, size_t page_size) { - for (volatile char *p = (char*)start; p < (char*)end; p += page_size) { - // Note: this must be a store, not a load. On many OSes loads from fresh - // memory would be satisfied from a single mapped page containing all zeros. - // We need to store something to each page to get them backed by their own - // memory, which is the effect we want here. - *p = 0; + assert(start <= end, "invalid range: " PTR_FORMAT " -> " PTR_FORMAT, p2i(start), p2i(end)); + assert(is_power_of_2(page_size), "page size misaligned: %zu", page_size); + assert(page_size >= sizeof(int), "page size too small: %zu", page_size); + if (start < end) { + // We're doing concurrent-safe touch and memory state has page + // granularity, so we can touch anywhere in a page. Touch at the + // beginning of each page to simplify iteration. + char* cur = static_cast(align_down(start, page_size)); + void* last = align_down(static_cast(end) - 1, page_size); + assert(cur <= last, "invariant"); + // Iterate from first page through last (inclusive), being careful to + // avoid overflow if the last page abuts the end of the address range. + for ( ; true; cur += page_size) { + Atomic::add(reinterpret_cast(cur), 0, memory_order_relaxed); + if (cur >= last) break; + } } } diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index b63637e3576..1ad15f0d8ea 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -365,10 +365,9 @@ class os: AllStatic { // Prints all mappings static void print_memory_mappings(outputStream* st); - // Touch memory pages that cover the memory range from start to end (exclusive) - // to make the OS back the memory range with actual memory. - // Current implementation may not touch the last page if unaligned addresses - // are passed. + // Touch memory pages that cover the memory range from start to end + // (exclusive) to make the OS back the memory range with actual memory. + // Other threads may use the memory range concurrently with pretouch. static void pretouch_memory(void* start, void* end, size_t page_size = vm_page_size()); enum ProtType { MEM_PROT_NONE, MEM_PROT_READ, MEM_PROT_RW, MEM_PROT_RWX }; -- GitLab From f924e50c42c2f9548d2983449a98c45af40b0d35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Wed, 9 Feb 2022 08:34:47 +0000 Subject: [PATCH 012/203] 8281440: AWT: Conversion from string literal loses const qualifier Reviewed-by: prr, aivanov --- .../windows/native/libawt/windows/WPrinterJob.cpp | 6 +++--- .../windows/native/libawt/windows/awt_Debug.cpp | 2 +- .../libawt/windows/awt_DesktopProperties.cpp | 14 +++++++------- .../native/libawt/windows/awt_DrawingSurface.cpp | 2 +- .../windows/native/libawt/windows/awt_Font.cpp | 6 +++--- .../windows/native/libawt/windows/awt_Font.h | 2 +- .../native/libawt/windows/awt_PrintControl.cpp | 2 +- .../windows/native/libawt/windows/awt_PrintJob.cpp | 6 +++--- .../windows/native/libawt/windows/awt_Toolkit.cpp | 2 +- .../native/libawt/windows/awt_Win32GraphicsEnv.cpp | 2 +- 10 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/java.desktop/windows/native/libawt/windows/WPrinterJob.cpp b/src/java.desktop/windows/native/libawt/windows/WPrinterJob.cpp index 812d0df3bbb..16b20afd030 100644 --- a/src/java.desktop/windows/native/libawt/windows/WPrinterJob.cpp +++ b/src/java.desktop/windows/native/libawt/windows/WPrinterJob.cpp @@ -729,7 +729,7 @@ Java_sun_print_Win32PrintService_getPrinterPort(JNIEnv *env, } jstring jPort; - LPTSTR printerName = NULL, printerPort = TEXT("LPT1"); + LPTSTR printerName = NULL, printerPort = (LPTSTR)TEXT("LPT1"); LPBYTE buffer = NULL; DWORD cbBuf = 0; @@ -745,7 +745,7 @@ Java_sun_print_Win32PrintService_getPrinterPort(JNIEnv *env, } if (printerPort == NULL) { - printerPort = TEXT("LPT1"); + printerPort = (LPTSTR)TEXT("LPT1"); } jPort = JNU_NewStringPlatform(env, printerPort); delete [] buffer; @@ -1110,7 +1110,7 @@ Java_sun_print_Win32PrintJob_startPrintRawData(JNIEnv *env, // Fill in the structure with info about this "document." DocInfo.pDocName = jname; DocInfo.pOutputFile = NULL; - DocInfo.pDatatype = TEXT("RAW"); + DocInfo.pDatatype = (LPTSTR)TEXT("RAW"); // Inform the spooler the document is beginning. if( (::StartDocPrinter(hPrinter, 1, (LPBYTE)&DocInfo)) == 0 ) { diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Debug.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Debug.cpp index 5faa5f3a634..88dc0f17abe 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Debug.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Debug.cpp @@ -193,7 +193,7 @@ void AwtDebugSupport::AssertCallback(const char * expr, const char * file, int l NULL); if (msgBuffer == NULL) { - msgBuffer = ""; + msgBuffer = (LPSTR)""; } // format the assertion message _snprintf(assertMsg, ASSERT_MSG_SIZE, AssertFmt, expr, file, line, lastError, msgBuffer); diff --git a/src/java.desktop/windows/native/libawt/windows/awt_DesktopProperties.cpp b/src/java.desktop/windows/native/libawt/windows/awt_DesktopProperties.cpp index e9d4161c89b..9b3668c1798 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_DesktopProperties.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_DesktopProperties.cpp @@ -138,7 +138,7 @@ void AwtDesktopProperties::GetSystemProperties() { // Note that it uses malloc() and returns the pointer to allocated // memory, so remember to use free() when you are done with its // result. -static LPTSTR resolveShellDialogFont(LPTSTR fontName, HKEY handle) { +static LPTSTR resolveShellDialogFont(LPCTSTR fontName, HKEY handle) { DWORD valueType, valueSize; if (RegQueryValueEx((HKEY)handle, fontName, NULL, &valueType, NULL, &valueSize) != 0) { @@ -164,7 +164,7 @@ static LPTSTR resolveShellDialogFont(LPTSTR fontName, HKEY handle) { // memory, so remember to use free() when you are done with its // result. static LPTSTR resolveShellDialogFont() { - LPTSTR subKey = TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes"); + LPCTSTR subKey = TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes"); HKEY handle; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, subKey, 0, KEY_READ, &handle) != 0) { @@ -183,7 +183,7 @@ static LPTSTR resolveShellDialogFont() { // Note that it uses malloc() and returns the pointer to allocated // memory, so remember to use free() when you are done with its // result. -static LPTSTR getWindowsPropFromReg(LPTSTR subKey, LPTSTR valueName, DWORD *valueType) { +static LPTSTR getWindowsPropFromReg(LPCTSTR subKey, LPCTSTR valueName, DWORD *valueType) { HKEY handle; if (RegOpenKeyEx(HKEY_CURRENT_USER, subKey, 0, KEY_READ, &handle) != 0) { return NULL; @@ -221,7 +221,7 @@ static LPTSTR getWindowsPropFromReg(LPTSTR subKey, LPTSTR valueName, DWORD *valu } } -static LPTSTR getXPStylePropFromReg(LPTSTR valueName) { +static LPTSTR getXPStylePropFromReg(LPCTSTR valueName) { DWORD valueType; return getWindowsPropFromReg(TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\ThemeManager"), valueName, &valueType); @@ -651,11 +651,11 @@ void AwtDesktopProperties::GetOtherParameters() { throw; } - LPTSTR valueName = TEXT("PlaceN"); + LPCTSTR valueName = TEXT("PlaceN"); LPTSTR valueNameBuf = (LPTSTR)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, (lstrlen(valueName) + 1), sizeof(TCHAR)); lstrcpy(valueNameBuf, valueName); - LPTSTR propKey = TEXT("win.comdlg.placesBarPlaceN"); + LPCTSTR propKey = TEXT("win.comdlg.placesBarPlaceN"); LPTSTR propKeyBuf; try { @@ -672,7 +672,7 @@ void AwtDesktopProperties::GetOtherParameters() { valueNameBuf[5] = _T('0' + i++); propKeyBuf[25] = valueNameBuf[5]; - LPTSTR key = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\comdlg32\\PlacesBar"); + LPCTSTR key = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\comdlg32\\PlacesBar"); try { value = NULL; if ((value = getWindowsPropFromReg(key, valueNameBuf, &valueType)) != NULL) { diff --git a/src/java.desktop/windows/native/libawt/windows/awt_DrawingSurface.cpp b/src/java.desktop/windows/native/libawt/windows/awt_DrawingSurface.cpp index 019295ac2b5..de7f7fd895c 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_DrawingSurface.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_DrawingSurface.cpp @@ -275,7 +275,7 @@ extern "C" JNIEXPORT void JNICALL DSUnlockAWT(JNIEnv* env) // EmbeddedFrame support -static char *const embeddedClassName = "sun/awt/windows/WEmbeddedFrame"; +static const char *const embeddedClassName = "sun/awt/windows/WEmbeddedFrame"; JNIEXPORT jobject JNICALL awt_CreateEmbeddedFrame (JNIEnv* env, void* platformInfo) diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Font.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Font.cpp index cef2e3d1046..48b78183b20 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Font.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Font.cpp @@ -345,7 +345,7 @@ AwtFont* AwtFont::Create(JNIEnv *env, jobject font, jint angle, jfloat awScale) wName = L"Arial"; } - WCHAR* wEName; + LPCWSTR wEName; if (!wcscmp(wName, L"Helvetica") || !wcscmp(wName, L"SansSerif")) { wEName = L"Arial"; } else if (!wcscmp(wName, L"TimesRoman") || @@ -388,7 +388,7 @@ AwtFont* AwtFont::Create(JNIEnv *env, jobject font, jint angle, jfloat awScale) return awtFont; } -static void strip_tail(wchar_t* text, wchar_t* tail) { // strips tail and any possible whitespace before it from the end of text +static void strip_tail(wchar_t* text, const wchar_t* tail) { // strips tail and any possible whitespace before it from the end of text if (wcslen(text)<=wcslen(tail)) { return; } @@ -495,7 +495,7 @@ static HFONT CreateHFont_sub(LPCWSTR name, int style, int height, return hFont; } -HFONT AwtFont::CreateHFont(WCHAR* name, int style, int height, +HFONT AwtFont::CreateHFont(LPCWSTR name, int style, int height, int angle, float awScale) { WCHAR longName[80]; diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Font.h b/src/java.desktop/windows/native/libawt/windows/awt_Font.h index 3f4d8e6a67d..aa1d7241f10 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Font.h +++ b/src/java.desktop/windows/native/libawt/windows/awt_Font.h @@ -155,7 +155,7 @@ public: */ static AwtFont* Create(JNIEnv *env, jobject font, jint angle = 0, jfloat awScale=1.0f); - static HFONT CreateHFont(WCHAR* name, int style, int height, + static HFONT CreateHFont(LPCWSTR name, int style, int height, int angle = 0, float awScale=1.0f); static void Cleanup(); diff --git a/src/java.desktop/windows/native/libawt/windows/awt_PrintControl.cpp b/src/java.desktop/windows/native/libawt/windows/awt_PrintControl.cpp index c29d4c4e7ac..5064bb4fb45 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_PrintControl.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_PrintControl.cpp @@ -1045,7 +1045,7 @@ BOOL AwtPrintControl::UpdateAttributes(JNIEnv *env, DEVNAMES *devnames = (DEVNAMES*)::GlobalLock(pd.hDevNames); DASSERT(!IsBadReadPtr(devnames, sizeof(DEVNAMES))); LPTSTR lpcNames = (LPTSTR)devnames; - LPTSTR pbuf = (_tcslen(lpcNames + devnames->wDeviceOffset) == 0 ? + LPCTSTR pbuf = (_tcslen(lpcNames + devnames->wDeviceOffset) == 0 ? TEXT("") : lpcNames + devnames->wDeviceOffset); if (pbuf != NULL) { jstring jstr = JNU_NewStringPlatform(env, pbuf); diff --git a/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp b/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp index 9eec4d89b15..874ce94c434 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp @@ -64,8 +64,8 @@ extern "C" { /*** Private Constants ***/ -static char *kJavaIntStr = "I"; -static char *kJavaLongStr = "J"; +static const char *kJavaIntStr = "I"; +static const char *kJavaLongStr = "J"; /* 2D printing uses 3 byte BGR pixels in Raster printing */ static int J2DRasterBPP = 3; @@ -1353,7 +1353,7 @@ Java_sun_awt_windows_WPrinterJob__1startDoc(JNIEnv *env, jobject self, } else { destination = VerifyDestination(env, self); } - LPTSTR docname = NULL; + LPCTSTR docname = NULL; if (jobname != NULL) { LPTSTR tmp = (LPTSTR)JNU_GetStringPlatformChars(env, jobname, NULL); if (tmp == NULL) { diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp index 17e69d70b15..687eba5deff 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp @@ -530,7 +530,7 @@ void ToolkitThreadProc(void *param) JNIEnv *env; JavaVMAttachArgs attachArgs; attachArgs.version = JNI_VERSION_1_2; - attachArgs.name = "AWT-Windows"; + attachArgs.name = (char*)"AWT-Windows"; attachArgs.group = data->threadGroup; jint res = jvm->AttachCurrentThreadAsDaemon((void **)&env, &attachArgs); diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsEnv.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsEnv.cpp index bc0d6a939fa..434050215a3 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsEnv.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsEnv.cpp @@ -234,7 +234,7 @@ Java_sun_awt_Win32FontManager_getEUDCFontFile(JNIEnv *env, jclass cl) { unsigned long fontPathLen = MAX_PATH + 1; WCHAR tmpPath[MAX_PATH + 1]; LPWSTR fontPath = fontPathBuf; - LPWSTR eudcKey = NULL; + LPCWSTR eudcKey = NULL; LANGID langID = GetSystemDefaultLangID(); //lookup for encoding ID, EUDC only supported in -- GitLab From f092babafb58563a4044463e157e02c397d8c9bc Mon Sep 17 00:00:00 2001 From: Alexey Pavlyutkin Date: Wed, 9 Feb 2022 09:33:35 +0000 Subject: [PATCH 013/203] 8281195: Mistakenly used logging causes significant overhead in interpreter Reviewed-by: shade, dholmes --- src/hotspot/share/interpreter/oopMapCache.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/interpreter/oopMapCache.cpp b/src/hotspot/share/interpreter/oopMapCache.cpp index 8799275683a..84bef74bed9 100644 --- a/src/hotspot/share/interpreter/oopMapCache.cpp +++ b/src/hotspot/share/interpreter/oopMapCache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -276,26 +276,26 @@ bool OopMapCacheEntry::verify_mask(CellTypeState* vars, CellTypeState* stack, in // Check if map is generated correctly // (Use ?: operator to make sure all 'true' & 'false' are represented exactly the same so we can use == afterwards) - Log(interpreter, oopmap) logv; - LogStream st(logv.trace()); + const bool log = log_is_enabled(Trace, interpreter, oopmap); + LogStream st(Log(interpreter, oopmap)::trace()); - st.print("Locals (%d): ", max_locals); + if (log) st.print("Locals (%d): ", max_locals); for(int i = 0; i < max_locals; i++) { bool v1 = is_oop(i) ? true : false; bool v2 = vars[i].is_reference() ? true : false; assert(v1 == v2, "locals oop mask generation error"); - st.print("%d", v1 ? 1 : 0); + if (log) st.print("%d", v1 ? 1 : 0); } - st.cr(); + if (log) st.cr(); - st.print("Stack (%d): ", stack_top); + if (log) st.print("Stack (%d): ", stack_top); for(int j = 0; j < stack_top; j++) { bool v1 = is_oop(max_locals + j) ? true : false; bool v2 = stack[j].is_reference() ? true : false; assert(v1 == v2, "stack oop mask generation error"); - st.print("%d", v1 ? 1 : 0); + if (log) st.print("%d", v1 ? 1 : 0); } - st.cr(); + if (log) st.cr(); return true; } -- GitLab From 69e390a0e86f82eaa7bcdbc3ef509734dbe3b22f Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Wed, 9 Feb 2022 10:18:27 +0000 Subject: [PATCH 014/203] 8262721: Add Tests to verify single iteration loops are properly optimized Reviewed-by: neliasso, chagedorn, kvn --- .../irTests/TestFewIterationsCountedLoop.java | 139 ++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/TestFewIterationsCountedLoop.java diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestFewIterationsCountedLoop.java b/test/hotspot/jtreg/compiler/c2/irTests/TestFewIterationsCountedLoop.java new file mode 100644 index 00000000000..1d3fed1c87a --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestFewIterationsCountedLoop.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.c2.irTests; + +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8262721 + * @summary Add Tests to verify single iteration loops are properly optimized + * @library /test/lib / + * @run driver compiler.c2.irTests.TestFewIterationsCountedLoop + */ + +public class TestFewIterationsCountedLoop { + + public static void main(String[] args) { + TestFramework.runWithFlags("-XX:LoopUnrollLimit=0"); + TestFramework.run(); + } + + static volatile int barrier; + static final Object object = new Object(); + + @Test + @IR(failOn = { IRNode.COUNTEDLOOP, IRNode.LOOP }) + public static void singleIterationFor() { + for (int i = 0; i < 1; i++) { + barrier = 0x42; // something that can't be optimized out + } + } + + @Test + @IR(failOn = { IRNode.COUNTEDLOOP, IRNode.LOOP }) + public static void singleIterationWhile() { + int i = 0; + while (i < 1) { + barrier = 0x42; + i++; + } + } + + @Test + @IR(failOn = { IRNode.COUNTEDLOOP, IRNode.LOOP }) + @Warmup(1) // So C2 can't rely on profile data + public static void singleIterationDoWhile() { + int i = 0; + do { + synchronized(object) {} // so loop head is not cloned by ciTypeFlow + barrier = 0x42; + i++; + } while (i < 1); + } + + @Test + @IR(applyIf = { "LoopUnrollLimit", "0" }, counts = { IRNode.COUNTEDLOOP, "1" }) + @IR(applyIf = { "LoopUnrollLimit", "> 0" }, failOn = { IRNode.COUNTEDLOOP, IRNode.LOOP }) + public static void twoIterationsFor() { + for (int i = 0; i < 2; i++) { + barrier = 0x42; // something that can't be optimized out + } + } + + @Test + @IR(applyIf = { "LoopUnrollLimit", "0" }, counts = { IRNode.COUNTEDLOOP, "1" }) + @IR(applyIf = { "LoopUnrollLimit", "> 0" }, failOn = { IRNode.COUNTEDLOOP, IRNode.LOOP }) + public static void twoIterationsWhile() { + int i = 0; + while (i < 2) { + barrier = 0x42; + i++; + } + } + + @Test + @IR(applyIf = { "LoopUnrollLimit", "0" }, counts = { IRNode.COUNTEDLOOP, "1" }) + @IR(applyIf = { "LoopUnrollLimit", "> 0" }, failOn = { IRNode.COUNTEDLOOP, IRNode.LOOP }) + public static void twoIterationsDoWhile() { + int i = 0; + do { + synchronized(object) {} // so loop head is not cloned by ciTypeFlow + barrier = 0x42; + i++; + } while (i < 2); + } + + @Test + @IR(applyIf = { "LoopUnrollLimit", "0" }, counts = { IRNode.COUNTEDLOOP, "1" }) + @IR(applyIf = { "LoopUnrollLimit", "> 0" }, failOn = { IRNode.COUNTEDLOOP, IRNode.LOOP }) + public static void threadIterationsFor() { + for (int i = 0; i < 2; i++) { + barrier = 0x42; // something that can't be optimized out + } + } + + @Test + @IR(applyIf = { "LoopUnrollLimit", "0" }, counts = { IRNode.COUNTEDLOOP, "1" }) + @IR(applyIf = { "LoopUnrollLimit", "> 0" }, failOn = { IRNode.COUNTEDLOOP, IRNode.LOOP }) + public static void threeIterationsWhile() { + int i = 0; + while (i < 2) { + barrier = 0x42; + i++; + } + } + + @Test + @IR(applyIf = { "LoopUnrollLimit", "0" }, counts = { IRNode.COUNTEDLOOP, "1" }) + @IR(applyIf = { "LoopUnrollLimit", "> 0" }, failOn = { IRNode.COUNTEDLOOP, IRNode.LOOP }) + public static void threeIterationsDoWhile() { + int i = 0; + do { + synchronized(object) {} // so loop head is not cloned by ciTypeFlow + barrier = 0x42; + i++; + } while (i < 2); + } +} -- GitLab From bb2e10ccea0c0b89b06ace034c99253e9999ec47 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 9 Feb 2022 11:33:16 +0000 Subject: [PATCH 015/203] 8281274: deal with ActiveProcessorCount in os::Linux::print_container_info Reviewed-by: stuefe, sgehwolf, dholmes, iklam --- src/hotspot/os/linux/os_linux.cpp | 6 +++++- test/hotspot/jtreg/containers/docker/TestMisc.java | 12 +++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 28477ba8bcb..18b908cfc8f 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -2174,7 +2174,11 @@ bool os::Linux::print_container_info(outputStream* st) { int i = OSContainer::active_processor_count(); st->print("active_processor_count: "); if (i > 0) { - st->print_cr("%d", i); + if (ActiveProcessorCount > 0) { + st->print_cr("%d, but overridden by -XX:ActiveProcessorCount %d", i, ActiveProcessorCount); + } else { + st->print_cr("%d", i); + } } else { st->print_cr("not supported"); } diff --git a/test/hotspot/jtreg/containers/docker/TestMisc.java b/test/hotspot/jtreg/containers/docker/TestMisc.java index e242bdf6632..5625fe828bb 100644 --- a/test/hotspot/jtreg/containers/docker/TestMisc.java +++ b/test/hotspot/jtreg/containers/docker/TestMisc.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,6 +56,7 @@ public class TestMisc { testMinusContainerSupport(); testIsContainerized(); testPrintContainerInfo(); + testPrintContainerInfoActiveProcessorCount(); } finally { DockerTestUtils.removeDockerImage(imageName); } @@ -92,6 +93,15 @@ public class TestMisc { checkContainerInfo(Common.run(opts)); } + private static void testPrintContainerInfoActiveProcessorCount() throws Exception { + Common.logNewTestCase("Test print_container_info()"); + + DockerRunOptions opts = Common.newOpts(imageName, "PrintContainerInfo").addJavaOpts("-XX:ActiveProcessorCount=2"); + Common.addWhiteBoxOpts(opts); + + OutputAnalyzer out = Common.run(opts); + out.shouldContain("but overridden by -XX:ActiveProcessorCount 2"); + } private static void checkContainerInfo(OutputAnalyzer out) throws Exception { String[] expectedToContain = new String[] { -- GitLab From 8b384b986a0a6a972c29a2f7a4d9fd40dc479b48 Mon Sep 17 00:00:00 2001 From: Christian Stein Date: Wed, 9 Feb 2022 11:34:22 +0000 Subject: [PATCH 016/203] 8281470: tools/jar/CreateMissingParentDirectories.java fails with "Should have failed creating jar file" Reviewed-by: lancea --- test/jdk/ProblemList.txt | 1 - .../jdk/tools/jar/CreateMissingParentDirectories.java | 11 +++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 1d08673243f..6b54c726277 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -765,7 +765,6 @@ javax/swing/JTree/4908142/bug4908142.java 8278348 macosx-all # core_tools tools/jlink/plugins/CompressorPluginTest.java 8247407 generic-all -tools/jar/CreateMissingParentDirectories.java 8281470 generic-all ############################################################################ diff --git a/test/jdk/tools/jar/CreateMissingParentDirectories.java b/test/jdk/tools/jar/CreateMissingParentDirectories.java index 93d6d4ce01d..1f8fa4deb38 100644 --- a/test/jdk/tools/jar/CreateMissingParentDirectories.java +++ b/test/jdk/tools/jar/CreateMissingParentDirectories.java @@ -32,6 +32,7 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.nio.file.Files; import java.nio.file.Path; +import java.util.List; import java.util.spi.ToolProvider; import java.util.stream.Stream; @@ -66,7 +67,6 @@ public class CreateMissingParentDirectories { doHappyPathTest(topDir.resolve("a/test.jar"), entry); doHappyPathTest(topDir.resolve("a/b/test.jar"), entry); - doFailingTest(topDir.toString() + "/a/*/test.jar", entry); Path blocker = Files.writeString(topDir.resolve("blocker.txt"), "Blocked!"); doFailingTest(topDir.resolve("blocker.txt/test.jar").toString(), entry); } finally { @@ -77,7 +77,12 @@ public class CreateMissingParentDirectories { private static void doHappyPathTest(Path jar, Path entry) throws Throwable { String[] jarArgs = new String[]{"cf", jar.toString(), entry.toString()}; if (JAR_TOOL.run(System.out, System.err, jarArgs) != 0) { - fail("Could not create jar file: " + jar); + fail("Could not create jar file: " + List.of(jarArgs)); + return; + } + jarArgs = new String[]{"--create", "--file", jar.toString(), entry.toString()}; + if (JAR_TOOL.run(System.out, System.err, jarArgs) != 0) { + fail("Could not create jar file: " + List.of(jarArgs)); return; } pass(); @@ -92,8 +97,6 @@ public class CreateMissingParentDirectories { fail("Should have failed creating jar file: " + jar); return; } - // non-zero exit code expected, check error message contains jar file's name - check(err.toString().contains(jar)); pass(); } -- GitLab From f823bed043dc38d838baaf8c2024ef24b8a50e9b Mon Sep 17 00:00:00 2001 From: Bhavana Kilambi Date: Wed, 9 Feb 2022 13:18:29 +0000 Subject: [PATCH 017/203] 8280007: Enable Neoverse N1 optimizations for Arm Neoverse V1 & N2 Reviewed-by: phh --- src/hotspot/cpu/aarch64/vm_version_aarch64.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index 833a6ec9f6d..b0c0c64f6d9 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2020, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -197,8 +197,10 @@ void VM_Version::initialize() { } } - // Neoverse N1 - if (_cpu == CPU_ARM && (_model == 0xd0c || _model2 == 0xd0c)) { + // Neoverse N1, N2 and V1 + if (_cpu == CPU_ARM && ((_model == 0xd0c || _model2 == 0xd0c) + || (_model == 0xd49 || _model2 == 0xd49) + || (_model == 0xd40 || _model2 == 0xd40))) { if (FLAG_IS_DEFAULT(UseSIMDForMemoryOps)) { FLAG_SET_DEFAULT(UseSIMDForMemoryOps, true); } -- GitLab From c5c8c0644d9442846de15422285fffeb91c3e0a1 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Wed, 9 Feb 2022 13:56:23 +0000 Subject: [PATCH 018/203] 8279822: CI: Constant pool entries in error state are not supported Reviewed-by: kvn, thartmann --- src/hotspot/share/ci/bcEscapeAnalyzer.cpp | 6 +- src/hotspot/share/ci/ciConstant.hpp | 11 + src/hotspot/share/ci/ciEnv.cpp | 40 +-- src/hotspot/share/ci/ciStreams.cpp | 8 + src/hotspot/share/ci/ciStreams.hpp | 19 +- src/hotspot/share/ci/ciTypeFlow.cpp | 19 +- src/hotspot/share/oops/constantPool.cpp | 38 ++- src/hotspot/share/opto/parse2.cpp | 36 +-- src/hotspot/share/utilities/constantTag.hpp | 33 +- .../runtime/TestConstantsInError.java | 283 ++++++++++++++++++ 10 files changed, 403 insertions(+), 90 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/runtime/TestConstantsInError.java diff --git a/src/hotspot/share/ci/bcEscapeAnalyzer.cpp b/src/hotspot/share/ci/bcEscapeAnalyzer.cpp index a10a9d3d551..7fd8b5c04f3 100644 --- a/src/hotspot/share/ci/bcEscapeAnalyzer.cpp +++ b/src/hotspot/share/ci/bcEscapeAnalyzer.cpp @@ -416,11 +416,11 @@ void BCEscapeAnalyzer::iterate_one_block(ciBlock *blk, StateInfo &state, Growabl // Avoid calling get_constant() which will try to allocate // unloaded constant. We need only constant's type. int index = s.get_constant_pool_index(); - constantTag tag = s.get_constant_pool_tag(index); - if (tag.is_long() || tag.is_double()) { + BasicType con_bt = s.get_basic_type_for_constant_at(index); + if (con_bt == T_LONG || con_bt == T_DOUBLE) { // Only longs and doubles use 2 stack slots. state.lpush(); - } else if (tag.basic_type() == T_OBJECT) { + } else if (con_bt == T_OBJECT) { state.apush(unknown_obj); } else { state.spush(); diff --git a/src/hotspot/share/ci/ciConstant.hpp b/src/hotspot/share/ci/ciConstant.hpp index c9351771d17..25591699045 100644 --- a/src/hotspot/share/ci/ciConstant.hpp +++ b/src/hotspot/share/ci/ciConstant.hpp @@ -127,6 +127,17 @@ public: bool is_valid() const { return basic_type() != T_ILLEGAL; } + + bool is_loaded() const { + if (is_valid()) { + if (is_reference_type(basic_type())) { + return as_object()->is_loaded(); + } else { + return true; + } + } + return false; + } // Debugging output void print(); }; diff --git a/src/hotspot/share/ci/ciEnv.cpp b/src/hotspot/share/ci/ciEnv.cpp index 323d67c986f..bdbd86d9018 100644 --- a/src/hotspot/share/ci/ciEnv.cpp +++ b/src/hotspot/share/ci/ciEnv.cpp @@ -503,13 +503,6 @@ ciKlass* ciEnv::get_klass_by_name_impl(ciKlass* accessing_klass, domain = Handle(current, accessing_klass->protection_domain()); } - // setup up the proper type to return on OOM - ciKlass* fail_type; - if (sym->char_at(0) == JVM_SIGNATURE_ARRAY) { - fail_type = _unloaded_ciobjarrayklass; - } else { - fail_type = _unloaded_ciinstance_klass; - } Klass* found_klass; { ttyUnlocker ttyul; // release tty lock to avoid ordering problems @@ -591,7 +584,6 @@ ciKlass* ciEnv::get_klass_by_index_impl(const constantPoolHandle& cpool, int index, bool& is_accessible, ciInstanceKlass* accessor) { - EXCEPTION_CONTEXT; Klass* klass = NULL; Symbol* klass_name = NULL; @@ -599,7 +591,7 @@ ciKlass* ciEnv::get_klass_by_index_impl(const constantPoolHandle& cpool, klass_name = cpool->symbol_at(index); } else { // Check if it's resolved if it's not a symbol constant pool entry. - klass = ConstantPool::klass_at_if_loaded(cpool, index); + klass = ConstantPool::klass_at_if_loaded(cpool, index); // Try to look it up by name. if (klass == NULL) { klass_name = cpool->klass_name_at(index); @@ -666,7 +658,6 @@ ciConstant ciEnv::get_constant_by_index_impl(const constantPoolHandle& cpool, int pool_index, int cache_index, ciInstanceKlass* accessor) { bool ignore_will_link; - EXCEPTION_CONTEXT; int index = pool_index; if (cache_index >= 0) { assert(index < 0, "only one kind of index at a time"); @@ -677,12 +668,14 @@ ciConstant ciEnv::get_constant_by_index_impl(const constantPoolHandle& cpool, return ciConstant(T_OBJECT, get_object(NULL)); } BasicType bt = T_OBJECT; - if (cpool->tag_at(index).is_dynamic_constant()) + if (cpool->tag_at(index).is_dynamic_constant()) { bt = Signature::basic_type(cpool->uncached_signature_ref_at(index)); - if (is_reference_type(bt)) { - } else { + } + if (!is_reference_type(bt)) { // we have to unbox the primitive value - if (!is_java_primitive(bt)) return ciConstant(); + if (!is_java_primitive(bt)) { + return ciConstant(); + } jvalue value; BasicType bt2 = java_lang_boxing_object::get_value(obj, &value); assert(bt2 == bt, ""); @@ -717,6 +710,7 @@ ciConstant ciEnv::get_constant_by_index_impl(const constantPoolHandle& cpool, } else if (tag.is_double()) { return ciConstant((jdouble)cpool->double_at(index)); } else if (tag.is_string()) { + EXCEPTION_CONTEXT; oop string = NULL; assert(cache_index >= 0, "should have a cache index"); string = cpool->string_at(index, cache_index, THREAD); @@ -733,24 +727,18 @@ ciConstant ciEnv::get_constant_by_index_impl(const constantPoolHandle& cpool, return ciConstant(T_OBJECT, constant); } } else if (tag.is_unresolved_klass_in_error()) { - return ciConstant(); + return ciConstant(T_OBJECT, get_unloaded_klass_mirror(NULL)); } else if (tag.is_klass() || tag.is_unresolved_klass()) { - // 4881222: allow ldc to take a class type ciKlass* klass = get_klass_by_index_impl(cpool, index, ignore_will_link, accessor); - if (HAS_PENDING_EXCEPTION) { - CLEAR_PENDING_EXCEPTION; - record_out_of_memory_failure(); - return ciConstant(); - } assert (klass->is_instance_klass() || klass->is_array_klass(), "must be an instance or array klass "); return ciConstant(T_OBJECT, klass->java_mirror()); - } else if (tag.is_method_type()) { + } else if (tag.is_method_type() || tag.is_method_type_in_error()) { // must execute Java code to link this CP entry into cache[i].f1 ciSymbol* signature = get_symbol(cpool->method_type_signature_at(index)); ciObject* ciobj = get_unloaded_method_type_constant(signature); return ciConstant(T_OBJECT, ciobj); - } else if (tag.is_method_handle()) { + } else if (tag.is_method_handle() || tag.is_method_handle_in_error()) { // must execute Java code to link this CP entry into cache[i].f1 int ref_kind = cpool->method_handle_ref_kind_at(index); int callee_index = cpool->method_handle_klass_index_at(index); @@ -759,10 +747,10 @@ ciConstant ciEnv::get_constant_by_index_impl(const constantPoolHandle& cpool, ciSymbol* signature = get_symbol(cpool->method_handle_signature_ref_at(index)); ciObject* ciobj = get_unloaded_method_handle_constant(callee, name, signature, ref_kind); return ciConstant(T_OBJECT, ciobj); - } else if (tag.is_dynamic_constant()) { - return ciConstant(); + } else if (tag.is_dynamic_constant() || tag.is_dynamic_constant_in_error()) { + return ciConstant(); // not supported } else { - ShouldNotReachHere(); + assert(false, "unknown tag: %d (%s)", tag.value(), tag.internal_name()); return ciConstant(); } } diff --git a/src/hotspot/share/ci/ciStreams.cpp b/src/hotspot/share/ci/ciStreams.cpp index a1e6c5bffe8..46f52f19412 100644 --- a/src/hotspot/share/ci/ciStreams.cpp +++ b/src/hotspot/share/ci/ciStreams.cpp @@ -251,6 +251,14 @@ constantTag ciBytecodeStream::get_constant_pool_tag(int index) const { return _method->get_Method()->constants()->constant_tag_at(index); } +// ------------------------------------------------------------------ +// ciBytecodeStream::get_basic_type_for_constant_at +// +BasicType ciBytecodeStream::get_basic_type_for_constant_at(int index) const { + VM_ENTRY_MARK; + return _method->get_Method()->constants()->basic_type_for_constant_at(index); +} + // ------------------------------------------------------------------ // ciBytecodeStream::get_field_index // diff --git a/src/hotspot/share/ci/ciStreams.hpp b/src/hotspot/share/ci/ciStreams.hpp index 8f46510a0d2..e46b2e2bfa2 100644 --- a/src/hotspot/share/ci/ciStreams.hpp +++ b/src/hotspot/share/ci/ciStreams.hpp @@ -140,7 +140,7 @@ public: bool is_wide() const { return ( _pc == _was_wide ); } - // Does this instruction contain an index which refes into the CP cache? + // Does this instruction contain an index which refers into the CP cache? bool has_cache_index() const { return Bytecodes::uses_cp_cache(cur_bc_raw()); } int get_index_u1() const { @@ -226,8 +226,9 @@ public: // constant. Do not attempt to resolve it, since that would require // execution of Java code. If it is not resolved, return an unloaded // object (ciConstant.as_object()->is_loaded() == false). - ciConstant get_constant(); + ciConstant get_constant(); constantTag get_constant_pool_tag(int index) const; + BasicType get_basic_type_for_constant_at(int index) const; // True if the klass-using bytecode points to an unresolved klass bool is_unresolved_klass() const { @@ -235,9 +236,17 @@ public: return tag.is_unresolved_klass(); } - bool is_unresolved_klass_in_error() const { - constantTag tag = get_constant_pool_tag(get_klass_index()); - return tag.is_unresolved_klass_in_error(); + bool is_in_error() const { + assert(cur_bc() == Bytecodes::_ldc || + cur_bc() == Bytecodes::_ldc_w || + cur_bc() == Bytecodes::_ldc2_w, "not supported: %s", Bytecodes::name(cur_bc())); + + int index = get_constant_pool_index(); + constantTag tag = get_constant_pool_tag(index); + return tag.is_unresolved_klass_in_error() || + tag.is_method_handle_in_error() || + tag.is_method_type_in_error() || + tag.is_dynamic_constant_in_error(); } // If this bytecode is one of get_field, get_static, put_field, diff --git a/src/hotspot/share/ci/ciTypeFlow.cpp b/src/hotspot/share/ci/ciTypeFlow.cpp index fc8553aac48..2d7c60356d1 100644 --- a/src/hotspot/share/ci/ciTypeFlow.cpp +++ b/src/hotspot/share/ci/ciTypeFlow.cpp @@ -720,6 +720,11 @@ void ciTypeFlow::StateVector::do_jsr(ciBytecodeStream* str) { // ------------------------------------------------------------------ // ciTypeFlow::StateVector::do_ldc void ciTypeFlow::StateVector::do_ldc(ciBytecodeStream* str) { + if (str->is_in_error()) { + trap(str, NULL, Deoptimization::make_trap_request(Deoptimization::Reason_unhandled, + Deoptimization::Action_none)); + return; + } ciConstant con = str->get_constant(); if (con.is_valid()) { BasicType basic_type = con.basic_type(); @@ -735,14 +740,10 @@ void ciTypeFlow::StateVector::do_ldc(ciBytecodeStream* str) { push_translate(ciType::make(basic_type)); } } else { - if (str->is_unresolved_klass_in_error()) { - trap(str, NULL, Deoptimization::make_trap_request(Deoptimization::Reason_unhandled, - Deoptimization::Action_none)); - } else { - // OutOfMemoryError in the CI while loading constant - push_null(); - outer()->record_failure("ldc did not link"); - } + // OutOfMemoryError in the CI while loading constant. + // Unresolved condy also lands here (not yet supported). + push_null(); + outer()->record_failure("ldc did not link"); } } @@ -2173,7 +2174,7 @@ bool ciTypeFlow::can_trap(ciBytecodeStream& str) { case Bytecodes::_ldc: case Bytecodes::_ldc_w: case Bytecodes::_ldc2_w: - return str.is_unresolved_klass_in_error(); + return str.is_in_error(); case Bytecodes::_aload_0: // These bytecodes can trap for rewriting. We need to assume that diff --git a/src/hotspot/share/oops/constantPool.cpp b/src/hotspot/share/oops/constantPool.cpp index 1ff1abbb57d..d12ccd64cb6 100644 --- a/src/hotspot/share/oops/constantPool.cpp +++ b/src/hotspot/share/oops/constantPool.cpp @@ -885,11 +885,9 @@ void ConstantPool::save_and_throw_exception(const constantPoolHandle& this_cp, i constantTag ConstantPool::constant_tag_at(int which) { constantTag tag = tag_at(which); - if (tag.is_dynamic_constant() || - tag.is_dynamic_constant_in_error()) { + if (tag.is_dynamic_constant()) { BasicType bt = basic_type_for_constant_at(which); - // dynamic constant could return an array, treat as object - return constantTag::ofBasicType(is_reference_type(bt) ? T_OBJECT : bt); + return constantTag(constantTag::type2tag(bt)); } return tag; } @@ -976,7 +974,6 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, switch (tag.value()) { case JVM_CONSTANT_UnresolvedClass: - case JVM_CONSTANT_UnresolvedClassInError: case JVM_CONSTANT_Class: { assert(cache_index == _no_index_sentinel, "should not have been set"); @@ -1044,14 +1041,6 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, result_oop = string_at_impl(this_cp, index, cache_index, CHECK_NULL); break; - case JVM_CONSTANT_DynamicInError: - case JVM_CONSTANT_MethodHandleInError: - case JVM_CONSTANT_MethodTypeInError: - { - throw_resolution_error(this_cp, index, CHECK_NULL); - break; - } - case JVM_CONSTANT_MethodHandle: { int ref_kind = this_cp->method_handle_ref_kind_at(index); @@ -1065,11 +1054,14 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, callee_index, name->as_C_string(), signature->as_C_string()); } - Klass* callee = klass_at_impl(this_cp, callee_index, CHECK_NULL); + Klass* callee = klass_at_impl(this_cp, callee_index, THREAD); + if (HAS_PENDING_EXCEPTION) { + save_and_throw_exception(this_cp, index, tag, CHECK_NULL); + } // Check constant pool method consistency if ((callee->is_interface() && m_tag.is_method()) || - ((!callee->is_interface() && m_tag.is_interface_method()))) { + (!callee->is_interface() && m_tag.is_interface_method())) { ResourceMark rm(THREAD); stringStream ss; ss.print("Inconsistent constant pool data in classfile for class %s. " @@ -1081,17 +1073,18 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, index, callee->is_interface() ? "CONSTANT_MethodRef" : "CONSTANT_InterfaceMethodRef", callee->is_interface() ? "CONSTANT_InterfaceMethodRef" : "CONSTANT_MethodRef"); - THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string()); + Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_IncompatibleClassChangeError(), "%s", ss.as_string()); + save_and_throw_exception(this_cp, index, tag, CHECK_NULL); } Klass* klass = this_cp->pool_holder(); Handle value = SystemDictionary::link_method_handle_constant(klass, ref_kind, callee, name, signature, THREAD); - result_oop = value(); if (HAS_PENDING_EXCEPTION) { save_and_throw_exception(this_cp, index, tag, CHECK_NULL); } + result_oop = value(); break; } @@ -1136,10 +1129,15 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, result_oop = java_lang_boxing_object::create(T_DOUBLE, &prim_value, CHECK_NULL); break; + case JVM_CONSTANT_UnresolvedClassInError: + case JVM_CONSTANT_DynamicInError: + case JVM_CONSTANT_MethodHandleInError: + case JVM_CONSTANT_MethodTypeInError: + throw_resolution_error(this_cp, index, CHECK_NULL); + break; + default: - DEBUG_ONLY( tty->print_cr("*** %p: tag at CP[%d/%d] = %d", - this_cp(), index, cache_index, tag.value())); - assert(false, "unexpected constant tag"); + fatal("unexpected constant tag at CP %p[%d/%d] = %d", this_cp(), index, cache_index, tag.value()); break; } diff --git a/src/hotspot/share/opto/parse2.cpp b/src/hotspot/share/opto/parse2.cpp index 7ad08841476..14cca6cac26 100644 --- a/src/hotspot/share/opto/parse2.cpp +++ b/src/hotspot/share/opto/parse2.cpp @@ -1865,33 +1865,35 @@ void Parse::do_one_bytecode() { case Bytecodes::_bipush: push(intcon(iter().get_constant_u1())); break; case Bytecodes::_sipush: push(intcon(iter().get_constant_u2())); break; case Bytecodes::_aconst_null: push(null()); break; + case Bytecodes::_ldc: case Bytecodes::_ldc_w: - case Bytecodes::_ldc2_w: - // If the constant is unresolved, run this BC once in the interpreter. - { - ciConstant constant = iter().get_constant(); - if (!constant.is_valid() || - (constant.basic_type() == T_OBJECT && - !constant.as_object()->is_loaded())) { - int index = iter().get_constant_pool_index(); - constantTag tag = iter().get_constant_pool_tag(index); - uncommon_trap(Deoptimization::make_trap_request - (Deoptimization::Reason_unloaded, - Deoptimization::Action_reinterpret, - index), - NULL, tag.internal_name()); - break; - } + case Bytecodes::_ldc2_w: { + ciConstant constant = iter().get_constant(); + if (constant.is_loaded()) { assert(constant.basic_type() != T_OBJECT || constant.as_object()->is_instance(), "must be java_mirror of klass"); const Type* con_type = Type::make_from_constant(constant); if (con_type != NULL) { push_node(con_type->basic_type(), makecon(con_type)); } - } + } else { + // If the constant is unresolved or in error state, run this BC in the interpreter. + if (iter().is_in_error()) { + uncommon_trap(Deoptimization::make_trap_request(Deoptimization::Reason_unhandled, + Deoptimization::Action_none), + NULL, "constant in error state", true /* must_throw */); + } else { + int index = iter().get_constant_pool_index(); + uncommon_trap(Deoptimization::make_trap_request(Deoptimization::Reason_unloaded, + Deoptimization::Action_reinterpret, + index), + NULL, "unresolved constant", false /* must_throw */); + } + } break; + } case Bytecodes::_aload_0: push( local(0) ); diff --git a/src/hotspot/share/utilities/constantTag.hpp b/src/hotspot/share/utilities/constantTag.hpp index 4926eafa81c..d826fc0acc0 100644 --- a/src/hotspot/share/utilities/constantTag.hpp +++ b/src/hotspot/share/utilities/constantTag.hpp @@ -86,6 +86,13 @@ class constantTag { return _tag == JVM_CONSTANT_DynamicInError; } + bool is_in_error() const { + return is_unresolved_klass_in_error() || + is_method_handle_in_error() || + is_method_type_in_error() || + is_dynamic_constant_in_error(); + } + bool is_klass_index() const { return _tag == JVM_CONSTANT_ClassIndex; } bool is_string_index() const { return _tag == JVM_CONSTANT_StringIndex; } @@ -121,18 +128,24 @@ class constantTag { _tag = tag; } - static constantTag ofBasicType(BasicType bt) { - if (is_subword_type(bt)) bt = T_INT; + static jbyte type2tag(BasicType bt) { + if (is_subword_type(bt)) { + bt = T_INT; + } + if (bt == T_ARRAY) { + bt = T_OBJECT; + } switch (bt) { - case T_OBJECT: return constantTag(JVM_CONSTANT_String); - case T_INT: return constantTag(JVM_CONSTANT_Integer); - case T_LONG: return constantTag(JVM_CONSTANT_Long); - case T_FLOAT: return constantTag(JVM_CONSTANT_Float); - case T_DOUBLE: return constantTag(JVM_CONSTANT_Double); - default: break; + case T_INT: return JVM_CONSTANT_Integer; + case T_LONG: return JVM_CONSTANT_Long; + case T_FLOAT: return JVM_CONSTANT_Float; + case T_DOUBLE: return JVM_CONSTANT_Double; + case T_OBJECT: return JVM_CONSTANT_String; + + default: + assert(false, "not supported: %s", type2name(bt)); + return JVM_CONSTANT_Invalid; } - assert(false, "bad basic type for tag"); - return constantTag(); } jbyte value() const { return _tag; } diff --git a/test/hotspot/jtreg/compiler/runtime/TestConstantsInError.java b/test/hotspot/jtreg/compiler/runtime/TestConstantsInError.java new file mode 100644 index 00000000000..be5225bee4c --- /dev/null +++ b/test/hotspot/jtreg/compiler/runtime/TestConstantsInError.java @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8279822 + * @requires vm.flagless + * @library /test/lib + * @modules java.base/jdk.internal.org.objectweb.asm + * + * @run main compiler.runtime.TestConstantsInError + */ +package compiler.runtime; + +import jdk.internal.org.objectweb.asm.*; +import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandleProxies; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.ArrayList; +import java.util.List; + +import static jdk.internal.org.objectweb.asm.ClassWriter.*; +import static jdk.internal.org.objectweb.asm.Opcodes.*; + +interface OutputProcessor { + default void process(OutputAnalyzer output, boolean isC1) {} +} + +public abstract class TestConstantsInError implements OutputProcessor { + static final String TEST_PREFIX = class2desc(TestConstantsInError.class) + "$Test"; + + public interface Test extends Runnable {} + + + interface Generator { + void generate(MethodVisitor mv); + } + + static String class2desc(Class cls) { + return cls.getName().replace('.', '/'); + } + + public static final String PATH = System.getProperty("test.classes", ".") + java.io.File.separator; + + static byte[] generateClassFile(String suffix, Generator g) throws IOException { + var cw = new ClassWriter(COMPUTE_MAXS | COMPUTE_FRAMES); + String name = TEST_PREFIX + "_" + suffix; + cw.visit(V19, ACC_PUBLIC | ACC_SUPER, name, null, "java/lang/Object", null); + + { + var mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "test", "()V", null, null); + mv.visitCode(); + g.generate(mv); + mv.visitInsn(RETURN); + mv.visitMaxs(0, 0); + } + byte[] classFile = cw.toByteArray(); + + try (FileOutputStream fos = new FileOutputStream(PATH + name + ".class")) { + fos.write(classFile); + } + + return classFile; + } + + static Test generate(String suffix, Class expectedError, Generator g) { + try { + byte[] classFile = generateClassFile(suffix, g); + MethodHandles.Lookup testLookup = MethodHandles.lookup().defineHiddenClass(classFile, true); + MethodHandle testMH = testLookup.findStatic(testLookup.lookupClass(), "test", MethodType.methodType(void.class)); + + testMH = MethodHandles.filterReturnValue(testMH, + MethodHandles.insertArguments( + MethodHandles.throwException(void.class, AssertionError.class), + 0, new AssertionError("no exception thrown"))); + + // Install empty handler for linkage exceptions. + testMH = MethodHandles.catchException(testMH, expectedError, + MethodHandles.empty(MethodType.methodType(void.class, expectedError))); + + return MethodHandleProxies.asInterfaceInstance(Test.class, testMH); + } catch (Throwable e) { + throw new InternalError(e); + } + } + + static void run(String name, Class expectedError, Generator g) { + Test test = generate(name, expectedError, g); + for (int i = 0; i < 1000; i++) { + test.run(); + } + } + + static class TestConstantClass extends TestConstantsInError { + public static void main(String[] args) { + run("C1", NoClassDefFoundError.class, mv -> mv.visitLdcInsn(Type.getType("LUnknownClass;"))); // non-existent class + run("C2", IllegalAccessError.class, mv -> mv.visitLdcInsn(Type.getType("Ljava/lang/invoke/LambdaForm;"))); // inaccessible + + // class loader constraints? + } + + public void process(OutputAnalyzer results, boolean isC1) { + results.shouldMatch("Test_C1/.*::test \\(3 bytes\\)$") + .shouldMatch("Test_C2/.*::test \\(3 bytes\\)$"); + + if (isC1 && Platform.isAArch64()) { // no code patching + results.shouldMatch("Test_C1/.*::test \\(3 bytes\\) made not entrant") + .shouldMatch("Test_C2/.*::test \\(3 bytes\\) made not entrant"); + } else { + results.shouldNotContain("made not entrant"); + } + } + + public void processC2(OutputAnalyzer results) { + results.shouldNotContain("made not entrant"); + } + } + + static class TestConstantMethodHandle extends TestConstantsInError { + public static void main(String[] args) { + // Non-existent holder class + run("MH1", NoClassDefFoundError.class, + mv -> mv.visitLdcInsn(new Handle(H_INVOKESTATIC, "UnknownClass", "ignored", "()V", false))); + + // Inaccessible holder class + run("MH2", IllegalAccessError.class, + mv -> mv.visitLdcInsn(new Handle(H_INVOKESTATIC, "java/lang/invoke/LambdaForm", "ignored", "()V", false))); + + // Method vs InterfaceMethod mismatch + run("MH3", IncompatibleClassChangeError.class, + mv -> mv.visitLdcInsn(new Handle(H_INVOKESTATIC, "java/lang/Object", "ignored", "()V", true))); + + // Non-existent method + run("MH4", NoSuchMethodError.class, + mv -> mv.visitLdcInsn(new Handle(H_INVOKESTATIC, "java/lang/Object", "cast", "()V", false))); + } + + public void process(OutputAnalyzer results, boolean isC1) { + results.shouldMatch("Test_MH1/.*::test \\(3 bytes\\)$") + .shouldMatch("Test_MH2/.*::test \\(3 bytes\\)$") + .shouldMatch("Test_MH3/.*::test \\(3 bytes\\)$") + .shouldMatch("Test_MH4/.*::test \\(3 bytes\\)$"); + + if (isC1 && Platform.isAArch64()) { // no code patching + results.shouldMatch("Test_MH1/.*::test \\(3 bytes\\) made not entrant") + .shouldMatch("Test_MH2/.*::test \\(3 bytes\\) made not entrant") + .shouldMatch("Test_MH3/.*::test \\(3 bytes\\) made not entrant") + .shouldMatch("Test_MH4/.*::test \\(3 bytes\\) made not entrant"); + } else { + results.shouldNotContain("made not entrant"); + } + } + } + + static class TestConstantMethodType extends TestConstantsInError { + public static void main(String[] args) { + run("MT1", NoClassDefFoundError.class, + mv -> mv.visitLdcInsn(Type.getMethodType("(LUnknownClass;)V"))); + run("MT2", NoClassDefFoundError.class, + mv -> mv.visitLdcInsn(Type.getMethodType("()LUnknownClass;"))); + } + + public void process(OutputAnalyzer results, boolean isC1) { + results.shouldMatch("Test_MT1/.*::test \\(3 bytes\\)$") + .shouldMatch("Test_MT2/.*::test \\(3 bytes\\)$"); + + if (isC1 && Platform.isAArch64()) { // no code patching + results.shouldMatch("Test_MT1/.*::test \\(3 bytes\\) made not entrant") + .shouldMatch("Test_MT2/.*::test \\(3 bytes\\) made not entrant"); + } else { + results.shouldNotContain("made not entrant"); + } + } + } + + static class TestConstantDynamic extends TestConstantsInError { + static int bsm1() throws Exception { + throw new AssertionError("should not be invoked"); + } + + static int bsm2(MethodHandles.Lookup lookup, String name, Class c) throws Exception { + throw new Exception("expected"); + } + + static final Handle BSM1 = new Handle(H_INVOKESTATIC, class2desc(TestConstantDynamic.class), "bsm1", "()I", false); + static final Handle BSM2 = new Handle(H_INVOKESTATIC, class2desc(TestConstantDynamic.class), "bsm2", + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)I", + false); + + public static void main(String[] args) { + run("CD1", NoClassDefFoundError.class, + mv -> { + Handle bsm = new Handle(H_INVOKESTATIC, "UnknownClass", "unknown", "()LUnknownClass;", false); + mv.visitLdcInsn(new ConstantDynamic("tmp", "LUnknownClass;", bsm)); + }); + run("CD2", NoSuchMethodError.class, + mv -> { + Handle bsm = new Handle(H_INVOKESTATIC, class2desc(TestConstantDynamic.class), "unknown", "()I", false); + mv.visitLdcInsn(new ConstantDynamic("tmp", "LUnknownClass;", bsm)); + }); + run("CD3", BootstrapMethodError.class, mv -> mv.visitLdcInsn(new ConstantDynamic("tmp", "I", BSM1))); + run("CD4", BootstrapMethodError.class, mv -> mv.visitLdcInsn(new ConstantDynamic("tmp", "I", BSM2))); + } + + public void process(OutputAnalyzer results, boolean isC1) { + if (isC1) { + results.shouldMatch("Test_CD1.*::test \\(3 bytes\\) COMPILE SKIPPED: could not resolve a constant") + .shouldMatch("Test_CD2.*::test \\(3 bytes\\) COMPILE SKIPPED: could not resolve a constant") + .shouldMatch("Test_CD3.*::test \\(3 bytes\\) COMPILE SKIPPED: could not resolve a constant") + .shouldMatch("Test_CD4.*::test \\(3 bytes\\) COMPILE SKIPPED: could not resolve a constant"); + } else { + results.shouldMatch("Test_CD1.*::test \\(3 bytes\\)$") + .shouldMatch("Test_CD2.*::test \\(3 bytes\\)$") + .shouldMatch("Test_CD3.*::test \\(3 bytes\\)$") + .shouldMatch("Test_CD4.*::test \\(3 bytes\\)$"); + } + } + } + + static void run(TestConstantsInError test) throws Exception { + List commonArgs = List.of( + "--add-exports", "java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED", + "-Xbatch", "-XX:CompileThreshold=100", + "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly,*::test", + "-XX:+PrintCompilation", + "-XX:CompileCommand=print,*::test", + "-Dtest.classes=" + System.getProperty("test.classes", "."), + "-XX:+IgnoreUnrecognizedVMOptions", + test.getClass().getName()); + + ArrayList c1Args = new ArrayList<>(); + c1Args.addAll(List.of("-XX:+TieredCompilation", "-XX:TieredStopAtLevel=1", "-XX:+TracePatching")); + c1Args.addAll(commonArgs); + + OutputAnalyzer outputC1 = ProcessTools.executeTestJvm(c1Args) + .shouldHaveExitValue(0); + + test.process(outputC1, true); + + ArrayList c2Args = new ArrayList<>(); + c2Args.add("-XX:-TieredCompilation"); + c2Args.addAll(commonArgs); + + OutputAnalyzer outputC2 = ProcessTools.executeTestJvm(c2Args) + .shouldHaveExitValue(0); + + test.process(outputC2, false); + } + + public static void main(String[] args) throws Exception { + run(new TestConstantClass()); + run(new TestConstantMethodType()); + run(new TestConstantMethodHandle()); + run(new TestConstantDynamic()); + } +} -- GitLab From 178b962e01cc6c150442bf41dc6bd199caff0042 Mon Sep 17 00:00:00 2001 From: Hai-May Chao Date: Wed, 9 Feb 2022 16:53:48 +0000 Subject: [PATCH 019/203] 8265765: DomainKeyStore may stop enumerating aliases if a constituting KeyStore is empty Reviewed-by: weijun --- .../sun/security/provider/DomainKeyStore.java | 16 ++- .../KeyStore/DksWithEmptyKeystore.java | 125 ++++++++++++++++++ 2 files changed, 134 insertions(+), 7 deletions(-) create mode 100644 test/jdk/sun/security/provider/KeyStore/DksWithEmptyKeystore.java diff --git a/src/java.base/share/classes/sun/security/provider/DomainKeyStore.java b/src/java.base/share/classes/sun/security/provider/DomainKeyStore.java index be0e91a55a3..588f2ed78e6 100644 --- a/src/java.base/share/classes/sun/security/provider/DomainKeyStore.java +++ b/src/java.base/share/classes/sun/security/provider/DomainKeyStore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -419,20 +419,22 @@ abstract class DomainKeyStore extends KeyStoreSpi { if (aliases.hasMoreElements()) { return true; } else { - if (iterator.hasNext()) { + while (iterator.hasNext()) { keystoresEntry = iterator.next(); prefix = keystoresEntry.getKey() + - entryNameSeparator; + entryNameSeparator; aliases = keystoresEntry.getValue().aliases(); - } else { - return false; + if (aliases.hasMoreElements()) { + return true; + } else { + continue; + } } + return false; } } catch (KeyStoreException e) { return false; } - - return aliases.hasMoreElements(); } public String nextElement() { diff --git a/test/jdk/sun/security/provider/KeyStore/DksWithEmptyKeystore.java b/test/jdk/sun/security/provider/KeyStore/DksWithEmptyKeystore.java new file mode 100644 index 00000000000..050c470a3d0 --- /dev/null +++ b/test/jdk/sun/security/provider/KeyStore/DksWithEmptyKeystore.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8265765 + * @summary Test DomainKeyStore with a collection of keystores that has an empty one in between + * based on the test in the bug report + */ + +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.DomainLoadStoreParameter; +import java.security.KeyStore; +import java.util.Enumeration; +import java.util.LinkedHashMap; +import java.util.Map; +import javax.crypto.KeyGenerator; + +public class DksWithEmptyKeystore { + private static void write(Path p, KeyStore keystore) throws Exception { + try (OutputStream outputStream = Files.newOutputStream(p)) { + keystore.store(outputStream, new char[] { 'x' }); + } + } + + public static void main(String[] args) throws Exception { + KeyGenerator kg = KeyGenerator.getInstance("AES"); + kg.init(256); + + // Create a keystore with one key + KeyStore nonEmptyKeystore = KeyStore.getInstance("PKCS12"); + nonEmptyKeystore.load(null, null); + + Path nonEmptyPath = Path.of("non_empty.p12"); + nonEmptyKeystore.setKeyEntry("aeskey", kg.generateKey(), new char[] { 'a' }, null); + write(nonEmptyPath, nonEmptyKeystore); + + // Create an empty keystore + KeyStore emptyKeystore = KeyStore.getInstance("PKCS12"); + emptyKeystore.load(null, null); + + Path emptyPath = Path.of("empty.p12"); + write(emptyPath, emptyKeystore); + + // Create a domain keystore with two non-empty keystores + Path dksWithTwoPartsPath = Path.of("two-parts.dks"); + var twoPartsConfiguration = """ + domain Combo { + keystore a keystoreURI="%s"; + keystore b keystoreURI="%s"; + }; + """; + Files.writeString(dksWithTwoPartsPath, String.format(twoPartsConfiguration, + nonEmptyPath.toUri(), nonEmptyPath.toUri())); + Map protectionParameters = new LinkedHashMap<>(); + + KeyStore dksKeystore = KeyStore.getInstance("DKS"); + dksKeystore.load(new DomainLoadStoreParameter(dksWithTwoPartsPath.toUri(), protectionParameters)); + System.out.printf("%s size: %d%n", dksWithTwoPartsPath, dksKeystore.size()); + + int index = 0; + for (Enumeration enumeration = dksKeystore.aliases(); enumeration.hasMoreElements(); ) { + System.out.printf("%d: %s%n", index, enumeration.nextElement()); + index++; + } + + System.out.printf("enumerated aliases from %s: %d%n", dksWithTwoPartsPath, index); + if (index != dksKeystore.size()) { + throw new Exception("Failed to get the number of aliases in the domain keystore " + + "that has two keystores."); + } + + // Create a domain keystore with two non-empty keystores and an empty one in between + Path dksWithThreePartsPath = Path.of("three-parts.dks"); + var threePartsConfiguration = """ + domain Combo { + keystore a keystoreURI="%s"; + keystore b keystoreURI="%s"; + keystore c keystoreURI="%s"; + }; + """; + Files.writeString(dksWithThreePartsPath, String.format(threePartsConfiguration, + nonEmptyPath.toUri(), emptyPath.toUri(), nonEmptyPath.toUri())); + + KeyStore dksKeystore1 = KeyStore.getInstance("DKS"); + dksKeystore1.load(new DomainLoadStoreParameter(dksWithThreePartsPath.toUri(), protectionParameters)); + System.out.printf("%s size: %d%n", dksWithThreePartsPath, dksKeystore1.size()); + + index = 0; + for (Enumeration enumeration = dksKeystore1.aliases(); enumeration.hasMoreElements(); ) { + System.out.printf("%d: %s%n", index, enumeration.nextElement()); + index++; + } + + System.out.printf("enumerated aliases from %s: %d%n", dksWithThreePartsPath, index); + if (index != dksKeystore1.size()) { + throw new Exception("Failed to get the number of aliases in the domain keystore " + + "that has three keystores with an empty one in between."); + } else { + System.out.printf("Test completed successfully"); + } + } +} -- GitLab From fd8a3dcc52dc5d6b62edd83eacef5934f6294e80 Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Wed, 9 Feb 2022 19:12:20 +0000 Subject: [PATCH 020/203] 8280820: Clean up bug8033699 and bug8075609.java tests: regtesthelpers aren't used Reviewed-by: prr --- .../JRadioButton/8033699/bug8033699.java | 63 +++++++++---------- .../JRadioButton/8075609/bug8075609.java | 60 +++++++++--------- 2 files changed, 62 insertions(+), 61 deletions(-) diff --git a/test/jdk/javax/swing/JRadioButton/8033699/bug8033699.java b/test/jdk/javax/swing/JRadioButton/8033699/bug8033699.java index 06622f71819..9365e6ba45b 100644 --- a/test/jdk/javax/swing/JRadioButton/8033699/bug8033699.java +++ b/test/jdk/javax/swing/JRadioButton/8033699/bug8033699.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,11 +21,9 @@ * questions. */ - /* +/* * @test * @key headful - * @library ../../regtesthelpers - * @build Util * @bug 8033699 8154043 8167160 8208640 8226892 * @summary Incorrect radio button behavior when pressing tab key * @run main bug8033699 @@ -34,8 +32,7 @@ import java.awt.KeyboardFocusManager; import java.awt.Robot; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; -import java.util.logging.Level; -import java.util.logging.Logger; + import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.ButtonGroup; @@ -45,7 +42,6 @@ import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.SwingUtilities; import javax.swing.UIManager; -import javax.swing.UnsupportedLookAndFeelException; public class bug8033699 { @@ -59,7 +55,7 @@ public class bug8033699 { private static JRadioButton radioBtn3; private static JRadioButton radioBtnSingle; - public static void main(String args[]) throws Throwable { + public static void main(String[] args) throws Throwable { SwingUtilities.invokeAndWait(() -> { changeLAF(); createAndShowGUI(); @@ -67,6 +63,7 @@ public class bug8033699 { robot = new Robot(); Thread.sleep(100); + robot.waitForIdle(); robot.setAutoDelay(100); @@ -76,7 +73,7 @@ public class bug8033699 { // tab key test non-grouped radio button runTest2(); - // shift tab key test grouped and non grouped radio button + // shift tab key test grouped and non-grouped radio button runTest3(); // left/up key test in grouped radio button @@ -152,16 +149,16 @@ public class bug8033699 { mainFrame.setLayout(new BoxLayout(mainFrame.getContentPane(), BoxLayout.Y_AXIS)); mainFrame.setSize(300, 300); - mainFrame.setLocation(200, 200); + mainFrame.setLocationRelativeTo(null); mainFrame.setVisible(true); mainFrame.toFront(); } // Radio button Group as a single component when traversing through tab key private static void runTest1() throws Exception { - hitKey(robot, KeyEvent.VK_TAB); - hitKey(robot, KeyEvent.VK_TAB); - hitKey(robot, KeyEvent.VK_TAB); + hitKey(KeyEvent.VK_TAB); + hitKey(KeyEvent.VK_TAB); + hitKey(KeyEvent.VK_TAB); SwingUtilities.invokeAndWait(() -> { if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtnSingle) { @@ -173,7 +170,7 @@ public class bug8033699 { // Non-Grouped Radio button as a single component when traversing through tab key private static void runTest2() throws Exception { - hitKey(robot, KeyEvent.VK_TAB); + hitKey(KeyEvent.VK_TAB); SwingUtilities.invokeAndWait(() -> { if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != btnEnd) { System.out.println("Non Grouped Radio Button Go To Next Component through Tab Key failed"); @@ -184,9 +181,9 @@ public class bug8033699 { // Non-Grouped Radio button and Group Radio button as a single component when traversing through shift-tab key private static void runTest3() throws Exception { - hitKey(robot, KeyEvent.VK_SHIFT, KeyEvent.VK_TAB); - hitKey(robot, KeyEvent.VK_SHIFT, KeyEvent.VK_TAB); - hitKey(robot, KeyEvent.VK_SHIFT, KeyEvent.VK_TAB); + hitKey(KeyEvent.VK_SHIFT, KeyEvent.VK_TAB); + hitKey(KeyEvent.VK_SHIFT, KeyEvent.VK_TAB); + hitKey(KeyEvent.VK_SHIFT, KeyEvent.VK_TAB); SwingUtilities.invokeAndWait(() -> { if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtn1) { System.out.println("Radio button Group/Non Grouped Radio Button SHIFT-Tab Key Test failed"); @@ -197,8 +194,8 @@ public class bug8033699 { // Using arrow key to move focus in radio button group private static void runTest4() throws Exception { - hitKey(robot, KeyEvent.VK_DOWN); - hitKey(robot, KeyEvent.VK_RIGHT); + hitKey(KeyEvent.VK_DOWN); + hitKey(KeyEvent.VK_RIGHT); SwingUtilities.invokeAndWait(() -> { if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtn3) { System.out.println("Radio button Group UP/LEFT Arrow Key Move Focus Failed"); @@ -208,8 +205,8 @@ public class bug8033699 { } private static void runTest5() throws Exception { - hitKey(robot, KeyEvent.VK_UP); - hitKey(robot, KeyEvent.VK_LEFT); + hitKey(KeyEvent.VK_UP); + hitKey(KeyEvent.VK_LEFT); SwingUtilities.invokeAndWait(() -> { if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtn1) { System.out.println("Radio button Group Left/Up Arrow Key Move Focus Failed"); @@ -219,8 +216,8 @@ public class bug8033699 { } private static void runTest6() throws Exception { - hitKey(robot, KeyEvent.VK_UP); - hitKey(robot, KeyEvent.VK_UP); + hitKey(KeyEvent.VK_UP); + hitKey(KeyEvent.VK_UP); SwingUtilities.invokeAndWait(() -> { if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtn2) { System.out.println("Radio button Group Circle Back To First Button Test"); @@ -230,7 +227,7 @@ public class bug8033699 { } private static void runTest7() throws Exception { - hitKey(robot, KeyEvent.VK_TAB); + hitKey(KeyEvent.VK_TAB); SwingUtilities.invokeAndWait(() -> { if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != btnMiddle) { System.out.println("Separate Component added in button group layout"); @@ -240,7 +237,7 @@ public class bug8033699 { } private static void runTest8() throws Exception { - hitKey(robot, KeyEvent.VK_TAB); + hitKey(KeyEvent.VK_TAB); SwingUtilities.invokeAndWait(() -> { if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtnSingle) { System.out.println("Separate Component added in button group layout"); @@ -249,9 +246,9 @@ public class bug8033699 { }); } - private static Boolean actRB1 = false; - private static Boolean actRB2 = false; - private static Boolean actRB3 = false; + private static boolean actRB1 = false; + private static boolean actRB2 = false; + private static boolean actRB3 = false; // JDK-8226892: Verify that ActionListener is called when a RadioButton is selected using arrow key. private static void runTest9() throws Exception { @@ -268,9 +265,9 @@ public class bug8033699 { radioBtn2.addActionListener(actLrRB2); radioBtn3.addActionListener(actLrRB3); - hitKey(robot, KeyEvent.VK_DOWN); - hitKey(robot, KeyEvent.VK_DOWN); - hitKey(robot, KeyEvent.VK_DOWN); + hitKey(KeyEvent.VK_DOWN); + hitKey(KeyEvent.VK_DOWN); + hitKey(KeyEvent.VK_DOWN); String failMessage = "ActionListener not invoked when selected using arrow key."; if (!actRB2) { @@ -288,13 +285,13 @@ public class bug8033699 { radioBtn3.removeActionListener(actLrRB3); } - private static void hitKey(Robot robot, int keycode) { + private static void hitKey(int keycode) { robot.keyPress(keycode); robot.keyRelease(keycode); robot.waitForIdle(); } - private static void hitKey(Robot robot, int mode, int keycode) { + private static void hitKey(int mode, int keycode) { robot.keyPress(mode); robot.keyPress(keycode); robot.keyRelease(keycode); diff --git a/test/jdk/javax/swing/JRadioButton/8075609/bug8075609.java b/test/jdk/javax/swing/JRadioButton/8075609/bug8075609.java index 31c99206b7a..4c29a33ffa0 100644 --- a/test/jdk/javax/swing/JRadioButton/8075609/bug8075609.java +++ b/test/jdk/javax/swing/JRadioButton/8075609/bug8075609.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,44 +21,49 @@ * questions. */ - /* +/* * @test * @key headful - * @library ../../regtesthelpers - * @build Util * @bug 8075609 * @summary IllegalArgumentException when transferring focus from JRadioButton using tab - * @author Vivi An * @run main bug8075609 */ - -import javax.swing.*; -import javax.swing.event.*; -import java.awt.event.*; -import java.awt.*; +import java.awt.BorderLayout; +import java.awt.Robot; +import java.awt.event.KeyEvent; + +import javax.swing.ButtonGroup; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.JTextField; +import javax.swing.LayoutFocusTraversalPolicy; +import javax.swing.SwingUtilities; public class bug8075609 { private static Robot robot; private static JTextField textField; private static JFrame mainFrame; - public static void main(String args[]) throws Throwable { + public static void main(String[] args) throws Throwable { try { - SwingUtilities.invokeAndWait(new Runnable() { - public void run() { - createAndShowGUI(); - } - }); + SwingUtilities.invokeAndWait(bug8075609::createAndShowGUI); robot = new Robot(); Thread.sleep(100); + robot.waitForIdle(); robot.setAutoDelay(100); // Radio button group tab key test runTest1(); } finally { - if (mainFrame != null) SwingUtilities.invokeAndWait(() -> mainFrame.dispose()); + SwingUtilities.invokeAndWait(() -> { + if (mainFrame != null) { + mainFrame.dispose(); + } + }); } } @@ -91,26 +96,25 @@ public class bug8075609 { mainFrame.add(rootPanel); mainFrame.pack(); + mainFrame.setLocationRelativeTo(null); mainFrame.setVisible(true); mainFrame.toFront(); } // Radio button Group as a single component when traversing through tab key - private static void runTest1() throws Exception{ - hitKey(robot, KeyEvent.VK_TAB); - - robot.delay(1000 ); - SwingUtilities.invokeAndWait(new Runnable() { - public void run() { - if (!textField.hasFocus()) { - System.out.println("Radio Button Group Go To Next Component through Tab Key failed"); - throw new RuntimeException("Focus is not on textField as Expected"); - } + private static void runTest1() throws Exception { + hitKey(KeyEvent.VK_TAB); + + robot.delay(1000); + SwingUtilities.invokeAndWait(() -> { + if (!textField.hasFocus()) { + System.out.println("Radio Button Group Go To Next Component through Tab Key failed"); + throw new RuntimeException("Focus is not on textField as Expected"); } }); } - private static void hitKey(Robot robot, int keycode) { + private static void hitKey(int keycode) { robot.keyPress(keycode); robot.keyRelease(keycode); robot.waitForIdle(); -- GitLab From 7218d8449bfaa3f121b66088a88a194f77f06753 Mon Sep 17 00:00:00 2001 From: John Jiang Date: Thu, 10 Feb 2022 08:11:08 +0000 Subject: [PATCH 021/203] 8281567: Remove @throws IOException from X509CRLImpl::getExtension docs Reviewed-by: xuelei, jiefu --- src/java.base/share/classes/sun/security/x509/X509CRLImpl.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/java.base/share/classes/sun/security/x509/X509CRLImpl.java b/src/java.base/share/classes/sun/security/x509/X509CRLImpl.java index 1523cde227d..551e38ad31c 100644 --- a/src/java.base/share/classes/sun/security/x509/X509CRLImpl.java +++ b/src/java.base/share/classes/sun/security/x509/X509CRLImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1047,7 +1047,6 @@ public class X509CRLImpl extends X509CRL implements DerEncoder { * * @param oid ObjectIdentifier of extension desired * @return Object of type {@code } or null, if not found - * @throws IOException on error */ public Object getExtension(ObjectIdentifier oid) { if (extensions == null) -- GitLab From fa0a72c030432f9ea4ad9913a2bb4096324410aa Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Thu, 10 Feb 2022 09:29:53 +0000 Subject: [PATCH 022/203] 8252496: C2: Useless code in MergeMemNode::Ideal Reviewed-by: thartmann, chagedorn, vlivanov --- src/hotspot/share/opto/memnode.cpp | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index 815cbb2f450..c2e2e939bf3 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -4752,29 +4752,6 @@ Node *MergeMemNode::Ideal(PhaseGVN *phase, bool can_reshape) { // the base memory might contribute new slices beyond my req() if (old_mbase) grow_to_match(old_mbase); - // Look carefully at the base node if it is a phi. - PhiNode* phi_base; - if (new_base != NULL && new_base->is_Phi()) - phi_base = new_base->as_Phi(); - else - phi_base = NULL; - - Node* phi_reg = NULL; - uint phi_len = (uint)-1; - if (phi_base != NULL) { - phi_reg = phi_base->region(); - phi_len = phi_base->req(); - // see if the phi is unfinished - for (uint i = 1; i < phi_len; i++) { - if (phi_base->in(i) == NULL) { - // incomplete phi; do not look at it yet! - phi_reg = NULL; - phi_len = (uint)-1; - break; - } - } - } - // Note: We do not call verify_sparse on entry, because inputs // can normalize to the base_memory via subsume_node or similar // mechanisms. This method repairs that damage. @@ -4975,7 +4952,6 @@ Node* MergeMemNode::memory_at(uint alias_idx) const { // Otherwise, it is a narrow slice. Node* n = alias_idx < req() ? in(alias_idx) : empty_memory(); - Compile *C = Compile::current(); if (is_empty_memory(n)) { // the array is sparse; empty slots are the "top" node n = base_memory(); -- GitLab From c820d1acb7c6e600a890e4205eef0be8a4c7a791 Mon Sep 17 00:00:00 2001 From: Leo Korinth Date: Thu, 10 Feb 2022 10:34:16 +0000 Subject: [PATCH 023/203] 8281379: Assign package declarations to all jtreg test cases under gc Reviewed-by: kbarrett, tschatzl --- test/hotspot/jtreg/gc/g1/TestG1SkipCompaction.java | 4 +++- test/hotspot/jtreg/gc/g1/numa/TestG1NUMATouchRegions.java | 8 +++++--- test/hotspot/jtreg/gc/z/TestGarbageCollectorMXBean.java | 8 +++++--- test/hotspot/jtreg/gc/z/TestMemoryMXBean.java | 8 +++++--- test/hotspot/jtreg/gc/z/TestMemoryManagerMXBean.java | 6 ++++-- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/test/hotspot/jtreg/gc/g1/TestG1SkipCompaction.java b/test/hotspot/jtreg/gc/g1/TestG1SkipCompaction.java index f5fadcbb880..9824186c43c 100644 --- a/test/hotspot/jtreg/gc/g1/TestG1SkipCompaction.java +++ b/test/hotspot/jtreg/gc/g1/TestG1SkipCompaction.java @@ -21,6 +21,8 @@ * questions. */ +package gc.g1; + /* * @test TestG1SkipCompaction * @summary Test for JDK-8262068 Improve G1 Full GC by skipping compaction @@ -29,7 +31,7 @@ * @library /test/lib * @modules java.base/jdk.internal.misc * java.management - * @run main/othervm -Xms256m -Xmx256m TestG1SkipCompaction + * @run main/othervm -Xms256m -Xmx256m gc.g1.TestG1SkipCompaction */ import java.util.regex.Matcher; import java.util.regex.Pattern; diff --git a/test/hotspot/jtreg/gc/g1/numa/TestG1NUMATouchRegions.java b/test/hotspot/jtreg/gc/g1/numa/TestG1NUMATouchRegions.java index 6cdbd2c797a..868e5b185f2 100644 --- a/test/hotspot/jtreg/gc/g1/numa/TestG1NUMATouchRegions.java +++ b/test/hotspot/jtreg/gc/g1/numa/TestG1NUMATouchRegions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,7 +21,7 @@ * questions. */ -package gc.g1; +package gc.g1.numa; /** * @test TestG1NUMATouchRegions @@ -33,7 +33,9 @@ package gc.g1; * java.management * @build sun.hotspot.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm -XX:+UseG1GC -Xbootclasspath/a:. -XX:+UseNUMA -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI gc.g1.TestG1NUMATouchRegions + * @run main/othervm -XX:+UseG1GC -Xbootclasspath/a:. -XX:+UseNUMA + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * gc.g1.numa.TestG1NUMATouchRegions */ import java.util.LinkedList; diff --git a/test/hotspot/jtreg/gc/z/TestGarbageCollectorMXBean.java b/test/hotspot/jtreg/gc/z/TestGarbageCollectorMXBean.java index e29d75b009c..7a011edd8c9 100644 --- a/test/hotspot/jtreg/gc/z/TestGarbageCollectorMXBean.java +++ b/test/hotspot/jtreg/gc/z/TestGarbageCollectorMXBean.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,13 +21,15 @@ * questions. */ +package gc.z; + /** * @test TestGarbageCollectorMXBean * @requires vm.gc.Z * @summary Test ZGC garbage collector MXBean * @modules java.management - * @run main/othervm -XX:+UseZGC -Xms256M -Xmx512M -Xlog:gc TestGarbageCollectorMXBean 256 512 - * @run main/othervm -XX:+UseZGC -Xms512M -Xmx512M -Xlog:gc TestGarbageCollectorMXBean 512 512 + * @run main/othervm -XX:+UseZGC -Xms256M -Xmx512M -Xlog:gc gc.z.TestGarbageCollectorMXBean 256 512 + * @run main/othervm -XX:+UseZGC -Xms512M -Xmx512M -Xlog:gc gc.z.TestGarbageCollectorMXBean 512 512 */ import java.lang.management.ManagementFactory; diff --git a/test/hotspot/jtreg/gc/z/TestMemoryMXBean.java b/test/hotspot/jtreg/gc/z/TestMemoryMXBean.java index 47545d1bcf5..18c18985759 100644 --- a/test/hotspot/jtreg/gc/z/TestMemoryMXBean.java +++ b/test/hotspot/jtreg/gc/z/TestMemoryMXBean.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,13 +21,15 @@ * questions. */ +package gc.z; + /** * @test TestMemoryMXBean * @requires vm.gc.Z * @summary Test ZGC heap memory MXBean * @modules java.management - * @run main/othervm -XX:+UseZGC -Xms128M -Xmx256M -Xlog:gc* TestMemoryMXBean 128 256 - * @run main/othervm -XX:+UseZGC -Xms256M -Xmx256M -Xlog:gc* TestMemoryMXBean 256 256 + * @run main/othervm -XX:+UseZGC -Xms128M -Xmx256M -Xlog:gc* gc.z.TestMemoryMXBean 128 256 + * @run main/othervm -XX:+UseZGC -Xms256M -Xmx256M -Xlog:gc* gc.z.TestMemoryMXBean 256 256 */ import java.lang.management.ManagementFactory; diff --git a/test/hotspot/jtreg/gc/z/TestMemoryManagerMXBean.java b/test/hotspot/jtreg/gc/z/TestMemoryManagerMXBean.java index a5c5c1367e7..803201d576e 100644 --- a/test/hotspot/jtreg/gc/z/TestMemoryManagerMXBean.java +++ b/test/hotspot/jtreg/gc/z/TestMemoryManagerMXBean.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,12 +21,14 @@ * questions. */ +package gc.z; + /** * @test TestMemoryManagerMXBean * @requires vm.gc.Z * @summary Test ZGC memory manager MXBean * @modules java.management - * @run main/othervm -XX:+UseZGC -Xmx128M TestMemoryManagerMXBean + * @run main/othervm -XX:+UseZGC -Xmx128M gc.z.TestMemoryManagerMXBean */ import java.lang.management.ManagementFactory; -- GitLab From d442328bc2f2f4bc35dd054487a78552e3d9a759 Mon Sep 17 00:00:00 2001 From: Maxim Kartashev Date: Thu, 10 Feb 2022 10:46:35 +0000 Subject: [PATCH 024/203] 8281262: Windows builds in different directories are not fully reproducible Co-authored-by: Erik Joelsson Reviewed-by: erikj, ihse --- make/TestImage.gmk | 4 ++-- make/autoconf/flags-cflags.m4 | 4 +--- test/jdk/build/AbsPathsInImage.java | 7 +++++++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/make/TestImage.gmk b/make/TestImage.gmk index 26d10f95d3b..b719d6824da 100644 --- a/make/TestImage.gmk +++ b/make/TestImage.gmk @@ -35,8 +35,8 @@ BUILD_INFO_PROPERTIES := $(TEST_IMAGE_DIR)/build-info.properties $(BUILD_INFO_PROPERTIES): $(call MakeTargetDir) $(ECHO) "# Build info properties for JDK tests" > $@ - $(ECHO) "build.workspace.root=$(call FixPath, $(WORKSPACE_ROOT))" >> $@ - $(ECHO) "build.output.root=$(call FixPath, $(OUTPUTDIR))" >> $@ + $(ECHO) 'build.workspace.root=$(call FixPath, $(WORKSPACE_ROOT))' >> $@ + $(ECHO) 'build.output.root=$(call FixPath, $(OUTPUTDIR))' >> $@ README := $(TEST_IMAGE_DIR)/Readme.txt diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4 index ba4cb3e9ac7..76724235ec4 100644 --- a/make/autoconf/flags-cflags.m4 +++ b/make/autoconf/flags-cflags.m4 @@ -782,10 +782,8 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_CPU_DEP], test "x$ENABLE_REPRODUCIBLE_BUILD" = xtrue; then # There is a known issue with the pathmap if the mapping is made to the # empty string. Add a minimal string "s" as prefix to work around this. - workspace_root_win=`$FIXPATH_BASE print "${WORKSPACE_ROOT%/}"` # PATHMAP_FLAGS is also added to LDFLAGS in flags-ldflags.m4. - PATHMAP_FLAGS="-pathmap:${workspace_root_win//\//\\\\}=s \ - -pathmap:${workspace_root_win}=s" + PATHMAP_FLAGS="-pathmap:${WORKSPACE_ROOT}=s" FILE_MACRO_CFLAGS="$PATHMAP_FLAGS" FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [${FILE_MACRO_CFLAGS}], PREFIX: $3, diff --git a/test/jdk/build/AbsPathsInImage.java b/test/jdk/build/AbsPathsInImage.java index 3fd7dda239a..0e4b6d8caff 100644 --- a/test/jdk/build/AbsPathsInImage.java +++ b/test/jdk/build/AbsPathsInImage.java @@ -96,6 +96,13 @@ public class AbsPathsInImage { if (buildOutputRoot == null) { throw new Error("Could not find build output root, test cannot run"); } + // Validate the root paths + if (!Paths.get(buildWorkspaceRoot).isAbsolute()) { + throw new Error("Workspace root is not an absolute path: " + buildWorkspaceRoot); + } + if (!Paths.get(buildOutputRoot).isAbsolute()) { + throw new Error("Output root is not an absolute path: " + buildOutputRoot); + } List searchPatterns = new ArrayList<>(); expandPatterns(searchPatterns, buildWorkspaceRoot); -- GitLab From 3ce1c5b6ce02749ef8f9d35409b7bcbf27f47203 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Thu, 10 Feb 2022 11:28:04 +0000 Subject: [PATCH 025/203] 8280832: Update usage docs for NonblockingQueue Reviewed-by: iwalulya, dholmes --- src/hotspot/share/utilities/nonblockingQueue.hpp | 4 +++- src/hotspot/share/utilities/nonblockingQueue.inline.hpp | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/utilities/nonblockingQueue.hpp b/src/hotspot/share/utilities/nonblockingQueue.hpp index 6f8936b019f..a271aaa38d8 100644 --- a/src/hotspot/share/utilities/nonblockingQueue.hpp +++ b/src/hotspot/share/utilities/nonblockingQueue.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -96,9 +96,11 @@ public: inline size_t length() const; // Thread-safe add the object to the end of the queue. + // Subject to ABA behavior; callers must ensure usage is safe. inline void push(T& node) { append(node, node); } // Thread-safe add the objects from first to last to the end of the queue. + // Subject to ABA behavior; callers must ensure usage is safe. inline void append(T& first, T& last); // Thread-safe attempt to remove and return the first object in the queue. diff --git a/src/hotspot/share/utilities/nonblockingQueue.inline.hpp b/src/hotspot/share/utilities/nonblockingQueue.inline.hpp index 2845822b204..2ecb1663e45 100644 --- a/src/hotspot/share/utilities/nonblockingQueue.inline.hpp +++ b/src/hotspot/share/utilities/nonblockingQueue.inline.hpp @@ -117,6 +117,12 @@ void NonblockingQueue::append(T& first, T& last) { // other push/append could have competed with us, because we claimed // old_tail for extension. We won any races with try_pop by changing // away from end-marker. So we're done. + // + // Note that ABA is possible here. A concurrent try_pop could take + // old_tail before our update of old_tail's next_ptr, old_tail gets + // recycled and re-added to the end of this queue, and then we + // successfully cmpxchg, making the list in _tail circular. Callers + // must ensure this can't happen. return; } else { // A concurrent try_pop has claimed old_tail, so it is no longer in the -- GitLab From 039313d65d47dc85cb8c91d3e1d2752d365f70f9 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Thu, 10 Feb 2022 12:02:05 +0000 Subject: [PATCH 026/203] 8054449: Incompatible type in example code in TreePath Reviewed-by: aivanov, dmarkov --- src/java.desktop/share/classes/javax/swing/tree/TreePath.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.desktop/share/classes/javax/swing/tree/TreePath.java b/src/java.desktop/share/classes/javax/swing/tree/TreePath.java index e8abb0597df..f55cbe4961b 100644 --- a/src/java.desktop/share/classes/javax/swing/tree/TreePath.java +++ b/src/java.desktop/share/classes/javax/swing/tree/TreePath.java @@ -51,8 +51,8 @@ import java.beans.ConstructorProperties; * ... * TreePath selectedPath = tree.getSelectionPath(); * DefaultMutableTreeNode selectedNode = - * ((DefaultMutableTreeNode)selectedPath.getLastPathComponent()). - * getUserObject(); + * ((DefaultMutableTreeNode)selectedPath.getLastPathComponent()); + * Object myObject= selectedNode.getUserObject(); * * Subclasses typically need override only {@code * getLastPathComponent}, and {@code getParentPath}. As {@code JTree} -- GitLab From 83b6e4bc04db89a846a1b6c2d0666efe139f8f61 Mon Sep 17 00:00:00 2001 From: Paul Sandoz Date: Thu, 10 Feb 2022 18:37:21 +0000 Subject: [PATCH 027/203] 8281294: [vectorapi] FIRST_NONZERO reduction operation throws IllegalArgumentExcept on zero vectors Reviewed-by: jrose --- .../jdk/incubator/vector/ByteVector.java | 36 +---- .../jdk/incubator/vector/DoubleVector.java | 32 +---- .../jdk/incubator/vector/FloatVector.java | 32 +---- .../jdk/incubator/vector/IntVector.java | 36 +---- .../jdk/incubator/vector/LongVector.java | 36 +---- .../jdk/incubator/vector/ShortVector.java | 36 +---- .../incubator/vector/X-Vector.java.template | 40 +----- .../incubator/vector/Byte128VectorTests.java | 127 ++++++++++++++--- .../incubator/vector/Byte256VectorTests.java | 127 ++++++++++++++--- .../incubator/vector/Byte512VectorTests.java | 129 +++++++++++++++--- .../incubator/vector/Byte64VectorTests.java | 127 ++++++++++++++--- .../incubator/vector/ByteMaxVectorTests.java | 129 +++++++++++++++--- .../vector/Double128VectorTests.java | 127 ++++++++++++++--- .../vector/Double256VectorTests.java | 127 ++++++++++++++--- .../vector/Double512VectorTests.java | 127 ++++++++++++++--- .../incubator/vector/Double64VectorTests.java | 127 ++++++++++++++--- .../vector/DoubleMaxVectorTests.java | 127 ++++++++++++++--- .../incubator/vector/Float128VectorTests.java | 127 ++++++++++++++--- .../incubator/vector/Float256VectorTests.java | 127 ++++++++++++++--- .../incubator/vector/Float512VectorTests.java | 127 ++++++++++++++--- .../incubator/vector/Float64VectorTests.java | 127 ++++++++++++++--- .../incubator/vector/FloatMaxVectorTests.java | 127 ++++++++++++++--- .../incubator/vector/Int128VectorTests.java | 127 ++++++++++++++--- .../incubator/vector/Int256VectorTests.java | 127 ++++++++++++++--- .../incubator/vector/Int512VectorTests.java | 127 ++++++++++++++--- .../incubator/vector/Int64VectorTests.java | 127 ++++++++++++++--- .../incubator/vector/IntMaxVectorTests.java | 127 ++++++++++++++--- .../incubator/vector/Long128VectorTests.java | 127 ++++++++++++++--- .../incubator/vector/Long256VectorTests.java | 127 ++++++++++++++--- .../incubator/vector/Long512VectorTests.java | 127 ++++++++++++++--- .../incubator/vector/Long64VectorTests.java | 127 ++++++++++++++--- .../incubator/vector/LongMaxVectorTests.java | 127 ++++++++++++++--- .../incubator/vector/Short128VectorTests.java | 127 ++++++++++++++--- .../incubator/vector/Short256VectorTests.java | 127 ++++++++++++++--- .../incubator/vector/Short512VectorTests.java | 127 ++++++++++++++--- .../incubator/vector/Short64VectorTests.java | 127 ++++++++++++++--- .../incubator/vector/ShortMaxVectorTests.java | 127 ++++++++++++++--- test/jdk/jdk/incubator/vector/gen-template.sh | 36 ++--- .../Kernel-Reduction-Masked-Min-op.template | 21 --- ... Kernel-Reduction-Masked-op-func.template} | 2 +- .../Kernel-Reduction-Min-op.template | 19 --- ...late => Kernel-Reduction-op-func.template} | 2 +- .../Unit-Reduction-Masked-Min-op.template | 6 - ...=> Unit-Reduction-Masked-op-func.template} | 0 .../templates/Unit-Reduction-Min-op.template | 6 - ...it-Reduction-Scalar-Masked-Min-op.template | 19 --- ...-Reduction-Scalar-Masked-op-func.template} | 9 +- .../Unit-Reduction-Scalar-Min-op.template | 17 --- ...=> Unit-Reduction-Scalar-op-func.template} | 6 +- ...mplate => Unit-Reduction-op-func.template} | 0 .../vector/templates/Unit-header.template | 4 + 51 files changed, 3272 insertions(+), 937 deletions(-) delete mode 100644 test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-Min-op.template rename test/jdk/jdk/incubator/vector/templates/{Kernel-Reduction-Masked-Max-op.template => Kernel-Reduction-Masked-op-func.template} (90%) delete mode 100644 test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Min-op.template rename test/jdk/jdk/incubator/vector/templates/{Kernel-Reduction-Max-op.template => Kernel-Reduction-op-func.template} (89%) delete mode 100644 test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-Min-op.template rename test/jdk/jdk/incubator/vector/templates/{Unit-Reduction-Masked-Max-op.template => Unit-Reduction-Masked-op-func.template} (100%) delete mode 100644 test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Min-op.template delete mode 100644 test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Masked-Min-op.template rename test/jdk/jdk/incubator/vector/templates/{Unit-Reduction-Scalar-Masked-Max-op.template => Unit-Reduction-Scalar-Masked-op-func.template} (60%) delete mode 100644 test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Min-op.template rename test/jdk/jdk/incubator/vector/templates/{Unit-Reduction-Scalar-Max-op.template => Unit-Reduction-Scalar-op-func.template} (65%) rename test/jdk/jdk/incubator/vector/templates/{Unit-Reduction-Max-op.template => Unit-Reduction-op-func.template} (100%) diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java index 256e1a5700f..d67f86f7985 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java @@ -2595,7 +2595,8 @@ public abstract class ByteVector extends AbstractVector { VectorMask m) { m.check(maskClass, this); if (op == FIRST_NONZERO) { - ByteVector v = reduceIdentityVector(op).blend(this, m); + // FIXME: The JIT should handle this. + ByteVector v = broadcast((byte) 0).blend(this, m); return v.reduceLanesTemplate(op); } int opc = opCode(op); @@ -2610,10 +2611,11 @@ public abstract class ByteVector extends AbstractVector { final byte reduceLanesTemplate(VectorOperators.Associative op) { if (op == FIRST_NONZERO) { - // FIXME: The JIT should handle this, and other scan ops alos. + // FIXME: The JIT should handle this. VectorMask thisNZ = this.viewAsIntegralLanes().compare(NE, (byte) 0); - return this.lane(thisNZ.firstTrue()); + int ft = thisNZ.firstTrue(); + return ft < length() ? this.lane(ft) : (byte) 0; } int opc = opCode(op); return fromBits(VectorSupport.reductionCoerced( @@ -2646,34 +2648,6 @@ public abstract class ByteVector extends AbstractVector { } } - private - @ForceInline - ByteVector reduceIdentityVector(VectorOperators.Associative op) { - int opc = opCode(op); - UnaryOperator fn - = REDUCE_ID_IMPL.find(op, opc, (opc_) -> { - switch (opc_) { - case VECTOR_OP_ADD: - case VECTOR_OP_OR: - case VECTOR_OP_XOR: - return v -> v.broadcast(0); - case VECTOR_OP_MUL: - return v -> v.broadcast(1); - case VECTOR_OP_AND: - return v -> v.broadcast(-1); - case VECTOR_OP_MIN: - return v -> v.broadcast(MAX_OR_INF); - case VECTOR_OP_MAX: - return v -> v.broadcast(MIN_OR_INF); - default: return null; - } - }); - return fn.apply(this); - } - private static final - ImplCache> REDUCE_ID_IMPL - = new ImplCache<>(Associative.class, ByteVector.class); - private static final byte MIN_OR_INF = Byte.MIN_VALUE; private static final byte MAX_OR_INF = Byte.MAX_VALUE; diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java index 8455e354678..063a4bbb191 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java @@ -2419,7 +2419,8 @@ public abstract class DoubleVector extends AbstractVector { VectorMask m) { m.check(maskClass, this); if (op == FIRST_NONZERO) { - DoubleVector v = reduceIdentityVector(op).blend(this, m); + // FIXME: The JIT should handle this. + DoubleVector v = broadcast((double) 0).blend(this, m); return v.reduceLanesTemplate(op); } int opc = opCode(op); @@ -2434,10 +2435,11 @@ public abstract class DoubleVector extends AbstractVector { final double reduceLanesTemplate(VectorOperators.Associative op) { if (op == FIRST_NONZERO) { - // FIXME: The JIT should handle this, and other scan ops alos. + // FIXME: The JIT should handle this. VectorMask thisNZ = this.viewAsIntegralLanes().compare(NE, (long) 0); - return this.lane(thisNZ.firstTrue()); + int ft = thisNZ.firstTrue(); + return ft < length() ? this.lane(ft) : (double) 0; } int opc = opCode(op); return fromBits(VectorSupport.reductionCoerced( @@ -2464,30 +2466,6 @@ public abstract class DoubleVector extends AbstractVector { } } - private - @ForceInline - DoubleVector reduceIdentityVector(VectorOperators.Associative op) { - int opc = opCode(op); - UnaryOperator fn - = REDUCE_ID_IMPL.find(op, opc, (opc_) -> { - switch (opc_) { - case VECTOR_OP_ADD: - return v -> v.broadcast(0); - case VECTOR_OP_MUL: - return v -> v.broadcast(1); - case VECTOR_OP_MIN: - return v -> v.broadcast(MAX_OR_INF); - case VECTOR_OP_MAX: - return v -> v.broadcast(MIN_OR_INF); - default: return null; - } - }); - return fn.apply(this); - } - private static final - ImplCache> REDUCE_ID_IMPL - = new ImplCache<>(Associative.class, DoubleVector.class); - private static final double MIN_OR_INF = Double.NEGATIVE_INFINITY; private static final double MAX_OR_INF = Double.POSITIVE_INFINITY; diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java index 1dc63aa1de3..f78d9814514 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java @@ -2439,7 +2439,8 @@ public abstract class FloatVector extends AbstractVector { VectorMask m) { m.check(maskClass, this); if (op == FIRST_NONZERO) { - FloatVector v = reduceIdentityVector(op).blend(this, m); + // FIXME: The JIT should handle this. + FloatVector v = broadcast((float) 0).blend(this, m); return v.reduceLanesTemplate(op); } int opc = opCode(op); @@ -2454,10 +2455,11 @@ public abstract class FloatVector extends AbstractVector { final float reduceLanesTemplate(VectorOperators.Associative op) { if (op == FIRST_NONZERO) { - // FIXME: The JIT should handle this, and other scan ops alos. + // FIXME: The JIT should handle this. VectorMask thisNZ = this.viewAsIntegralLanes().compare(NE, (int) 0); - return this.lane(thisNZ.firstTrue()); + int ft = thisNZ.firstTrue(); + return ft < length() ? this.lane(ft) : (float) 0; } int opc = opCode(op); return fromBits(VectorSupport.reductionCoerced( @@ -2484,30 +2486,6 @@ public abstract class FloatVector extends AbstractVector { } } - private - @ForceInline - FloatVector reduceIdentityVector(VectorOperators.Associative op) { - int opc = opCode(op); - UnaryOperator fn - = REDUCE_ID_IMPL.find(op, opc, (opc_) -> { - switch (opc_) { - case VECTOR_OP_ADD: - return v -> v.broadcast(0); - case VECTOR_OP_MUL: - return v -> v.broadcast(1); - case VECTOR_OP_MIN: - return v -> v.broadcast(MAX_OR_INF); - case VECTOR_OP_MAX: - return v -> v.broadcast(MIN_OR_INF); - default: return null; - } - }); - return fn.apply(this); - } - private static final - ImplCache> REDUCE_ID_IMPL - = new ImplCache<>(Associative.class, FloatVector.class); - private static final float MIN_OR_INF = Float.NEGATIVE_INFINITY; private static final float MAX_OR_INF = Float.POSITIVE_INFINITY; diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java index 29dbfe5a796..c80b61cb7a2 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java @@ -2594,7 +2594,8 @@ public abstract class IntVector extends AbstractVector { VectorMask m) { m.check(maskClass, this); if (op == FIRST_NONZERO) { - IntVector v = reduceIdentityVector(op).blend(this, m); + // FIXME: The JIT should handle this. + IntVector v = broadcast((int) 0).blend(this, m); return v.reduceLanesTemplate(op); } int opc = opCode(op); @@ -2609,10 +2610,11 @@ public abstract class IntVector extends AbstractVector { final int reduceLanesTemplate(VectorOperators.Associative op) { if (op == FIRST_NONZERO) { - // FIXME: The JIT should handle this, and other scan ops alos. + // FIXME: The JIT should handle this. VectorMask thisNZ = this.viewAsIntegralLanes().compare(NE, (int) 0); - return this.lane(thisNZ.firstTrue()); + int ft = thisNZ.firstTrue(); + return ft < length() ? this.lane(ft) : (int) 0; } int opc = opCode(op); return fromBits(VectorSupport.reductionCoerced( @@ -2645,34 +2647,6 @@ public abstract class IntVector extends AbstractVector { } } - private - @ForceInline - IntVector reduceIdentityVector(VectorOperators.Associative op) { - int opc = opCode(op); - UnaryOperator fn - = REDUCE_ID_IMPL.find(op, opc, (opc_) -> { - switch (opc_) { - case VECTOR_OP_ADD: - case VECTOR_OP_OR: - case VECTOR_OP_XOR: - return v -> v.broadcast(0); - case VECTOR_OP_MUL: - return v -> v.broadcast(1); - case VECTOR_OP_AND: - return v -> v.broadcast(-1); - case VECTOR_OP_MIN: - return v -> v.broadcast(MAX_OR_INF); - case VECTOR_OP_MAX: - return v -> v.broadcast(MIN_OR_INF); - default: return null; - } - }); - return fn.apply(this); - } - private static final - ImplCache> REDUCE_ID_IMPL - = new ImplCache<>(Associative.class, IntVector.class); - private static final int MIN_OR_INF = Integer.MIN_VALUE; private static final int MAX_OR_INF = Integer.MAX_VALUE; diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java index 365740c90c2..6934469b213 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java @@ -2460,7 +2460,8 @@ public abstract class LongVector extends AbstractVector { VectorMask m) { m.check(maskClass, this); if (op == FIRST_NONZERO) { - LongVector v = reduceIdentityVector(op).blend(this, m); + // FIXME: The JIT should handle this. + LongVector v = broadcast((long) 0).blend(this, m); return v.reduceLanesTemplate(op); } int opc = opCode(op); @@ -2475,10 +2476,11 @@ public abstract class LongVector extends AbstractVector { final long reduceLanesTemplate(VectorOperators.Associative op) { if (op == FIRST_NONZERO) { - // FIXME: The JIT should handle this, and other scan ops alos. + // FIXME: The JIT should handle this. VectorMask thisNZ = this.viewAsIntegralLanes().compare(NE, (long) 0); - return this.lane(thisNZ.firstTrue()); + int ft = thisNZ.firstTrue(); + return ft < length() ? this.lane(ft) : (long) 0; } int opc = opCode(op); return fromBits(VectorSupport.reductionCoerced( @@ -2511,34 +2513,6 @@ public abstract class LongVector extends AbstractVector { } } - private - @ForceInline - LongVector reduceIdentityVector(VectorOperators.Associative op) { - int opc = opCode(op); - UnaryOperator fn - = REDUCE_ID_IMPL.find(op, opc, (opc_) -> { - switch (opc_) { - case VECTOR_OP_ADD: - case VECTOR_OP_OR: - case VECTOR_OP_XOR: - return v -> v.broadcast(0); - case VECTOR_OP_MUL: - return v -> v.broadcast(1); - case VECTOR_OP_AND: - return v -> v.broadcast(-1); - case VECTOR_OP_MIN: - return v -> v.broadcast(MAX_OR_INF); - case VECTOR_OP_MAX: - return v -> v.broadcast(MIN_OR_INF); - default: return null; - } - }); - return fn.apply(this); - } - private static final - ImplCache> REDUCE_ID_IMPL - = new ImplCache<>(Associative.class, LongVector.class); - private static final long MIN_OR_INF = Long.MIN_VALUE; private static final long MAX_OR_INF = Long.MAX_VALUE; diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java index d527500bb1a..b3c89e87cc4 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java @@ -2595,7 +2595,8 @@ public abstract class ShortVector extends AbstractVector { VectorMask m) { m.check(maskClass, this); if (op == FIRST_NONZERO) { - ShortVector v = reduceIdentityVector(op).blend(this, m); + // FIXME: The JIT should handle this. + ShortVector v = broadcast((short) 0).blend(this, m); return v.reduceLanesTemplate(op); } int opc = opCode(op); @@ -2610,10 +2611,11 @@ public abstract class ShortVector extends AbstractVector { final short reduceLanesTemplate(VectorOperators.Associative op) { if (op == FIRST_NONZERO) { - // FIXME: The JIT should handle this, and other scan ops alos. + // FIXME: The JIT should handle this. VectorMask thisNZ = this.viewAsIntegralLanes().compare(NE, (short) 0); - return this.lane(thisNZ.firstTrue()); + int ft = thisNZ.firstTrue(); + return ft < length() ? this.lane(ft) : (short) 0; } int opc = opCode(op); return fromBits(VectorSupport.reductionCoerced( @@ -2646,34 +2648,6 @@ public abstract class ShortVector extends AbstractVector { } } - private - @ForceInline - ShortVector reduceIdentityVector(VectorOperators.Associative op) { - int opc = opCode(op); - UnaryOperator fn - = REDUCE_ID_IMPL.find(op, opc, (opc_) -> { - switch (opc_) { - case VECTOR_OP_ADD: - case VECTOR_OP_OR: - case VECTOR_OP_XOR: - return v -> v.broadcast(0); - case VECTOR_OP_MUL: - return v -> v.broadcast(1); - case VECTOR_OP_AND: - return v -> v.broadcast(-1); - case VECTOR_OP_MIN: - return v -> v.broadcast(MAX_OR_INF); - case VECTOR_OP_MAX: - return v -> v.broadcast(MIN_OR_INF); - default: return null; - } - }); - return fn.apply(this); - } - private static final - ImplCache> REDUCE_ID_IMPL - = new ImplCache<>(Associative.class, ShortVector.class); - private static final short MIN_OR_INF = Short.MIN_VALUE; private static final short MAX_OR_INF = Short.MAX_VALUE; diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template index ae12e5fecff..1cd50a11b8b 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template @@ -3021,7 +3021,8 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { VectorMask<$Boxtype$> m) { m.check(maskClass, this); if (op == FIRST_NONZERO) { - $abstractvectortype$ v = reduceIdentityVector(op).blend(this, m); + // FIXME: The JIT should handle this. + $abstractvectortype$ v = broadcast(($type$) 0).blend(this, m); return v.reduceLanesTemplate(op); } int opc = opCode(op); @@ -3036,10 +3037,11 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { final $type$ reduceLanesTemplate(VectorOperators.Associative op) { if (op == FIRST_NONZERO) { - // FIXME: The JIT should handle this, and other scan ops alos. + // FIXME: The JIT should handle this. VectorMask<$Boxbitstype$> thisNZ = this.viewAsIntegralLanes().compare(NE, ($bitstype$) 0); - return this.lane(thisNZ.firstTrue()); + int ft = thisNZ.firstTrue(); + return ft < length() ? this.lane(ft) : ($type$) 0; } int opc = opCode(op); return fromBits(VectorSupport.reductionCoerced( @@ -3074,38 +3076,6 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { } } - private - @ForceInline - $abstractvectortype$ reduceIdentityVector(VectorOperators.Associative op) { - int opc = opCode(op); - UnaryOperator<$abstractvectortype$> fn - = REDUCE_ID_IMPL.find(op, opc, (opc_) -> { - switch (opc_) { - case VECTOR_OP_ADD: -#if[BITWISE] - case VECTOR_OP_OR: - case VECTOR_OP_XOR: -#end[BITWISE] - return v -> v.broadcast(0); - case VECTOR_OP_MUL: - return v -> v.broadcast(1); -#if[BITWISE] - case VECTOR_OP_AND: - return v -> v.broadcast(-1); -#end[BITWISE] - case VECTOR_OP_MIN: - return v -> v.broadcast(MAX_OR_INF); - case VECTOR_OP_MAX: - return v -> v.broadcast(MIN_OR_INF); - default: return null; - } - }); - return fn.apply(this); - } - private static final - ImplCache> REDUCE_ID_IMPL - = new ImplCache<>(Associative.class, $Type$Vector.class); - #if[FP] private static final $type$ MIN_OR_INF = $Boxtype$.NEGATIVE_INFINITY; private static final $type$ MAX_OR_INF = $Boxtype$.POSITIVE_INFINITY; diff --git a/test/jdk/jdk/incubator/vector/Byte128VectorTests.java b/test/jdk/jdk/incubator/vector/Byte128VectorTests.java index df3e773388a..22e07e05a06 100644 --- a/test/jdk/jdk/incubator/vector/Byte128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte128VectorTests.java @@ -1201,6 +1201,10 @@ public class Byte128VectorTests extends AbstractVectorTest { return Byte.compareUnsigned(a, b) >= 0; } + static byte firstNonZero(byte a, byte b) { + return Byte.compare(a, (byte) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { ByteVector three = ByteVector.broadcast(SPECIES, (byte)-3); @@ -3216,7 +3220,7 @@ public class Byte128VectorTests extends AbstractVectorTest { static byte MINReduce(byte[] a, int idx) { byte res = Byte.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (byte)Math.min(res, a[i]); + res = (byte) Math.min(res, a[i]); } return res; @@ -3224,8 +3228,8 @@ public class Byte128VectorTests extends AbstractVectorTest { static byte MINReduceAll(byte[] a) { byte res = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (byte)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.min(res, MINReduce(a, i)); } return res; @@ -3247,7 +3251,7 @@ public class Byte128VectorTests extends AbstractVectorTest { ra = Byte.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3257,8 +3261,8 @@ public class Byte128VectorTests extends AbstractVectorTest { static byte MINReduceMasked(byte[] a, int idx, boolean[] mask) { byte res = Byte.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (byte) Math.min(res, a[i]); } return res; @@ -3266,9 +3270,8 @@ public class Byte128VectorTests extends AbstractVectorTest { static byte MINReduceAllMasked(byte[] a, boolean[] mask) { byte res = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3292,7 +3295,7 @@ public class Byte128VectorTests extends AbstractVectorTest { ra = Byte.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3302,7 +3305,7 @@ public class Byte128VectorTests extends AbstractVectorTest { static byte MAXReduce(byte[] a, int idx) { byte res = Byte.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (byte)Math.max(res, a[i]); + res = (byte) Math.max(res, a[i]); } return res; @@ -3310,8 +3313,8 @@ public class Byte128VectorTests extends AbstractVectorTest { static byte MAXReduceAll(byte[] a) { byte res = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (byte)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.max(res, MAXReduce(a, i)); } return res; @@ -3333,7 +3336,7 @@ public class Byte128VectorTests extends AbstractVectorTest { ra = Byte.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3343,8 +3346,8 @@ public class Byte128VectorTests extends AbstractVectorTest { static byte MAXReduceMasked(byte[] a, int idx, boolean[] mask) { byte res = Byte.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (byte) Math.max(res, a[i]); } return res; @@ -3352,9 +3355,8 @@ public class Byte128VectorTests extends AbstractVectorTest { static byte MAXReduceAllMasked(byte[] a, boolean[] mask) { byte res = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3378,13 +3380,98 @@ public class Byte128VectorTests extends AbstractVectorTest { ra = Byte.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Byte128VectorTests::MAXReduceMasked, Byte128VectorTests::MAXReduceAllMasked); } + static byte FIRST_NONZEROReduce(byte[] a, int idx) { + byte res = (byte) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static byte FIRST_NONZEROReduceAll(byte[] a) { + byte res = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "byteUnaryOpProvider") + static void FIRST_NONZEROReduceByte128VectorTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + byte ra = (byte) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Byte128VectorTests::FIRST_NONZEROReduce, Byte128VectorTests::FIRST_NONZEROReduceAll); + } + static byte FIRST_NONZEROReduceMasked(byte[] a, int idx, boolean[] mask) { + byte res = (byte) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static byte FIRST_NONZEROReduceAllMasked(byte[] a, boolean[] mask) { + byte res = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "byteUnaryOpMaskProvider") + static void FIRST_NONZEROReduceByte128VectorTestsMasked(IntFunction fa, IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + byte ra = (byte) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Byte128VectorTests::FIRST_NONZEROReduceMasked, Byte128VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; diff --git a/test/jdk/jdk/incubator/vector/Byte256VectorTests.java b/test/jdk/jdk/incubator/vector/Byte256VectorTests.java index 85da0f82e81..9a631c47993 100644 --- a/test/jdk/jdk/incubator/vector/Byte256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte256VectorTests.java @@ -1201,6 +1201,10 @@ public class Byte256VectorTests extends AbstractVectorTest { return Byte.compareUnsigned(a, b) >= 0; } + static byte firstNonZero(byte a, byte b) { + return Byte.compare(a, (byte) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { ByteVector three = ByteVector.broadcast(SPECIES, (byte)-3); @@ -3216,7 +3220,7 @@ public class Byte256VectorTests extends AbstractVectorTest { static byte MINReduce(byte[] a, int idx) { byte res = Byte.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (byte)Math.min(res, a[i]); + res = (byte) Math.min(res, a[i]); } return res; @@ -3224,8 +3228,8 @@ public class Byte256VectorTests extends AbstractVectorTest { static byte MINReduceAll(byte[] a) { byte res = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (byte)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.min(res, MINReduce(a, i)); } return res; @@ -3247,7 +3251,7 @@ public class Byte256VectorTests extends AbstractVectorTest { ra = Byte.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3257,8 +3261,8 @@ public class Byte256VectorTests extends AbstractVectorTest { static byte MINReduceMasked(byte[] a, int idx, boolean[] mask) { byte res = Byte.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (byte) Math.min(res, a[i]); } return res; @@ -3266,9 +3270,8 @@ public class Byte256VectorTests extends AbstractVectorTest { static byte MINReduceAllMasked(byte[] a, boolean[] mask) { byte res = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3292,7 +3295,7 @@ public class Byte256VectorTests extends AbstractVectorTest { ra = Byte.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3302,7 +3305,7 @@ public class Byte256VectorTests extends AbstractVectorTest { static byte MAXReduce(byte[] a, int idx) { byte res = Byte.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (byte)Math.max(res, a[i]); + res = (byte) Math.max(res, a[i]); } return res; @@ -3310,8 +3313,8 @@ public class Byte256VectorTests extends AbstractVectorTest { static byte MAXReduceAll(byte[] a) { byte res = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (byte)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.max(res, MAXReduce(a, i)); } return res; @@ -3333,7 +3336,7 @@ public class Byte256VectorTests extends AbstractVectorTest { ra = Byte.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3343,8 +3346,8 @@ public class Byte256VectorTests extends AbstractVectorTest { static byte MAXReduceMasked(byte[] a, int idx, boolean[] mask) { byte res = Byte.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (byte) Math.max(res, a[i]); } return res; @@ -3352,9 +3355,8 @@ public class Byte256VectorTests extends AbstractVectorTest { static byte MAXReduceAllMasked(byte[] a, boolean[] mask) { byte res = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3378,13 +3380,98 @@ public class Byte256VectorTests extends AbstractVectorTest { ra = Byte.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Byte256VectorTests::MAXReduceMasked, Byte256VectorTests::MAXReduceAllMasked); } + static byte FIRST_NONZEROReduce(byte[] a, int idx) { + byte res = (byte) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static byte FIRST_NONZEROReduceAll(byte[] a) { + byte res = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "byteUnaryOpProvider") + static void FIRST_NONZEROReduceByte256VectorTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + byte ra = (byte) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Byte256VectorTests::FIRST_NONZEROReduce, Byte256VectorTests::FIRST_NONZEROReduceAll); + } + static byte FIRST_NONZEROReduceMasked(byte[] a, int idx, boolean[] mask) { + byte res = (byte) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static byte FIRST_NONZEROReduceAllMasked(byte[] a, boolean[] mask) { + byte res = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "byteUnaryOpMaskProvider") + static void FIRST_NONZEROReduceByte256VectorTestsMasked(IntFunction fa, IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + byte ra = (byte) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Byte256VectorTests::FIRST_NONZEROReduceMasked, Byte256VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; diff --git a/test/jdk/jdk/incubator/vector/Byte512VectorTests.java b/test/jdk/jdk/incubator/vector/Byte512VectorTests.java index d7659d86871..203f233e4e8 100644 --- a/test/jdk/jdk/incubator/vector/Byte512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte512VectorTests.java @@ -24,7 +24,7 @@ /* * @test * @modules jdk.incubator.vector - * @run testng/othervm/timeout=240 -ea -esa -Xbatch -XX:-TieredCompilation Byte512VectorTests + * @run testng/othervm -ea -esa -Xbatch -XX:-TieredCompilation Byte512VectorTests */ // -- This file was mechanically generated: Do not edit! -- // @@ -1201,6 +1201,10 @@ public class Byte512VectorTests extends AbstractVectorTest { return Byte.compareUnsigned(a, b) >= 0; } + static byte firstNonZero(byte a, byte b) { + return Byte.compare(a, (byte) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { ByteVector three = ByteVector.broadcast(SPECIES, (byte)-3); @@ -3216,7 +3220,7 @@ public class Byte512VectorTests extends AbstractVectorTest { static byte MINReduce(byte[] a, int idx) { byte res = Byte.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (byte)Math.min(res, a[i]); + res = (byte) Math.min(res, a[i]); } return res; @@ -3224,8 +3228,8 @@ public class Byte512VectorTests extends AbstractVectorTest { static byte MINReduceAll(byte[] a) { byte res = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (byte)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.min(res, MINReduce(a, i)); } return res; @@ -3247,7 +3251,7 @@ public class Byte512VectorTests extends AbstractVectorTest { ra = Byte.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3257,8 +3261,8 @@ public class Byte512VectorTests extends AbstractVectorTest { static byte MINReduceMasked(byte[] a, int idx, boolean[] mask) { byte res = Byte.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (byte) Math.min(res, a[i]); } return res; @@ -3266,9 +3270,8 @@ public class Byte512VectorTests extends AbstractVectorTest { static byte MINReduceAllMasked(byte[] a, boolean[] mask) { byte res = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3292,7 +3295,7 @@ public class Byte512VectorTests extends AbstractVectorTest { ra = Byte.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3302,7 +3305,7 @@ public class Byte512VectorTests extends AbstractVectorTest { static byte MAXReduce(byte[] a, int idx) { byte res = Byte.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (byte)Math.max(res, a[i]); + res = (byte) Math.max(res, a[i]); } return res; @@ -3310,8 +3313,8 @@ public class Byte512VectorTests extends AbstractVectorTest { static byte MAXReduceAll(byte[] a) { byte res = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (byte)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.max(res, MAXReduce(a, i)); } return res; @@ -3333,7 +3336,7 @@ public class Byte512VectorTests extends AbstractVectorTest { ra = Byte.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3343,8 +3346,8 @@ public class Byte512VectorTests extends AbstractVectorTest { static byte MAXReduceMasked(byte[] a, int idx, boolean[] mask) { byte res = Byte.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (byte) Math.max(res, a[i]); } return res; @@ -3352,9 +3355,8 @@ public class Byte512VectorTests extends AbstractVectorTest { static byte MAXReduceAllMasked(byte[] a, boolean[] mask) { byte res = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3378,13 +3380,98 @@ public class Byte512VectorTests extends AbstractVectorTest { ra = Byte.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Byte512VectorTests::MAXReduceMasked, Byte512VectorTests::MAXReduceAllMasked); } + static byte FIRST_NONZEROReduce(byte[] a, int idx) { + byte res = (byte) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static byte FIRST_NONZEROReduceAll(byte[] a) { + byte res = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "byteUnaryOpProvider") + static void FIRST_NONZEROReduceByte512VectorTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + byte ra = (byte) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Byte512VectorTests::FIRST_NONZEROReduce, Byte512VectorTests::FIRST_NONZEROReduceAll); + } + static byte FIRST_NONZEROReduceMasked(byte[] a, int idx, boolean[] mask) { + byte res = (byte) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static byte FIRST_NONZEROReduceAllMasked(byte[] a, boolean[] mask) { + byte res = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "byteUnaryOpMaskProvider") + static void FIRST_NONZEROReduceByte512VectorTestsMasked(IntFunction fa, IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + byte ra = (byte) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Byte512VectorTests::FIRST_NONZEROReduceMasked, Byte512VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; diff --git a/test/jdk/jdk/incubator/vector/Byte64VectorTests.java b/test/jdk/jdk/incubator/vector/Byte64VectorTests.java index cc8c2e1c24c..110e741ea43 100644 --- a/test/jdk/jdk/incubator/vector/Byte64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte64VectorTests.java @@ -1201,6 +1201,10 @@ public class Byte64VectorTests extends AbstractVectorTest { return Byte.compareUnsigned(a, b) >= 0; } + static byte firstNonZero(byte a, byte b) { + return Byte.compare(a, (byte) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { ByteVector three = ByteVector.broadcast(SPECIES, (byte)-3); @@ -3216,7 +3220,7 @@ public class Byte64VectorTests extends AbstractVectorTest { static byte MINReduce(byte[] a, int idx) { byte res = Byte.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (byte)Math.min(res, a[i]); + res = (byte) Math.min(res, a[i]); } return res; @@ -3224,8 +3228,8 @@ public class Byte64VectorTests extends AbstractVectorTest { static byte MINReduceAll(byte[] a) { byte res = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (byte)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.min(res, MINReduce(a, i)); } return res; @@ -3247,7 +3251,7 @@ public class Byte64VectorTests extends AbstractVectorTest { ra = Byte.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3257,8 +3261,8 @@ public class Byte64VectorTests extends AbstractVectorTest { static byte MINReduceMasked(byte[] a, int idx, boolean[] mask) { byte res = Byte.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (byte) Math.min(res, a[i]); } return res; @@ -3266,9 +3270,8 @@ public class Byte64VectorTests extends AbstractVectorTest { static byte MINReduceAllMasked(byte[] a, boolean[] mask) { byte res = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3292,7 +3295,7 @@ public class Byte64VectorTests extends AbstractVectorTest { ra = Byte.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3302,7 +3305,7 @@ public class Byte64VectorTests extends AbstractVectorTest { static byte MAXReduce(byte[] a, int idx) { byte res = Byte.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (byte)Math.max(res, a[i]); + res = (byte) Math.max(res, a[i]); } return res; @@ -3310,8 +3313,8 @@ public class Byte64VectorTests extends AbstractVectorTest { static byte MAXReduceAll(byte[] a) { byte res = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (byte)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.max(res, MAXReduce(a, i)); } return res; @@ -3333,7 +3336,7 @@ public class Byte64VectorTests extends AbstractVectorTest { ra = Byte.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3343,8 +3346,8 @@ public class Byte64VectorTests extends AbstractVectorTest { static byte MAXReduceMasked(byte[] a, int idx, boolean[] mask) { byte res = Byte.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (byte) Math.max(res, a[i]); } return res; @@ -3352,9 +3355,8 @@ public class Byte64VectorTests extends AbstractVectorTest { static byte MAXReduceAllMasked(byte[] a, boolean[] mask) { byte res = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3378,13 +3380,98 @@ public class Byte64VectorTests extends AbstractVectorTest { ra = Byte.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Byte64VectorTests::MAXReduceMasked, Byte64VectorTests::MAXReduceAllMasked); } + static byte FIRST_NONZEROReduce(byte[] a, int idx) { + byte res = (byte) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static byte FIRST_NONZEROReduceAll(byte[] a) { + byte res = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "byteUnaryOpProvider") + static void FIRST_NONZEROReduceByte64VectorTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + byte ra = (byte) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Byte64VectorTests::FIRST_NONZEROReduce, Byte64VectorTests::FIRST_NONZEROReduceAll); + } + static byte FIRST_NONZEROReduceMasked(byte[] a, int idx, boolean[] mask) { + byte res = (byte) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static byte FIRST_NONZEROReduceAllMasked(byte[] a, boolean[] mask) { + byte res = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "byteUnaryOpMaskProvider") + static void FIRST_NONZEROReduceByte64VectorTestsMasked(IntFunction fa, IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + byte ra = (byte) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Byte64VectorTests::FIRST_NONZEROReduceMasked, Byte64VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; diff --git a/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java b/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java index eb438cb2042..e4a9ebf19f5 100644 --- a/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java @@ -24,7 +24,7 @@ /* * @test * @modules jdk.incubator.vector - * @run testng/othervm/timeout=240 -ea -esa -Xbatch -XX:-TieredCompilation ByteMaxVectorTests + * @run testng/othervm -ea -esa -Xbatch -XX:-TieredCompilation ByteMaxVectorTests */ // -- This file was mechanically generated: Do not edit! -- // @@ -1206,6 +1206,10 @@ public class ByteMaxVectorTests extends AbstractVectorTest { return Byte.compareUnsigned(a, b) >= 0; } + static byte firstNonZero(byte a, byte b) { + return Byte.compare(a, (byte) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { ByteVector three = ByteVector.broadcast(SPECIES, (byte)-3); @@ -3221,7 +3225,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { static byte MINReduce(byte[] a, int idx) { byte res = Byte.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (byte)Math.min(res, a[i]); + res = (byte) Math.min(res, a[i]); } return res; @@ -3229,8 +3233,8 @@ public class ByteMaxVectorTests extends AbstractVectorTest { static byte MINReduceAll(byte[] a) { byte res = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (byte)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.min(res, MINReduce(a, i)); } return res; @@ -3252,7 +3256,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { ra = Byte.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3262,8 +3266,8 @@ public class ByteMaxVectorTests extends AbstractVectorTest { static byte MINReduceMasked(byte[] a, int idx, boolean[] mask) { byte res = Byte.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (byte) Math.min(res, a[i]); } return res; @@ -3271,9 +3275,8 @@ public class ByteMaxVectorTests extends AbstractVectorTest { static byte MINReduceAllMasked(byte[] a, boolean[] mask) { byte res = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3297,7 +3300,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { ra = Byte.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3307,7 +3310,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { static byte MAXReduce(byte[] a, int idx) { byte res = Byte.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (byte)Math.max(res, a[i]); + res = (byte) Math.max(res, a[i]); } return res; @@ -3315,8 +3318,8 @@ public class ByteMaxVectorTests extends AbstractVectorTest { static byte MAXReduceAll(byte[] a) { byte res = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (byte)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.max(res, MAXReduce(a, i)); } return res; @@ -3338,7 +3341,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { ra = Byte.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3348,8 +3351,8 @@ public class ByteMaxVectorTests extends AbstractVectorTest { static byte MAXReduceMasked(byte[] a, int idx, boolean[] mask) { byte res = Byte.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (byte) Math.max(res, a[i]); } return res; @@ -3357,9 +3360,8 @@ public class ByteMaxVectorTests extends AbstractVectorTest { static byte MAXReduceAllMasked(byte[] a, boolean[] mask) { byte res = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3383,13 +3385,98 @@ public class ByteMaxVectorTests extends AbstractVectorTest { ra = Byte.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, ByteMaxVectorTests::MAXReduceMasked, ByteMaxVectorTests::MAXReduceAllMasked); } + static byte FIRST_NONZEROReduce(byte[] a, int idx) { + byte res = (byte) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static byte FIRST_NONZEROReduceAll(byte[] a) { + byte res = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "byteUnaryOpProvider") + static void FIRST_NONZEROReduceByteMaxVectorTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + byte ra = (byte) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + ByteMaxVectorTests::FIRST_NONZEROReduce, ByteMaxVectorTests::FIRST_NONZEROReduceAll); + } + static byte FIRST_NONZEROReduceMasked(byte[] a, int idx, boolean[] mask) { + byte res = (byte) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static byte FIRST_NONZEROReduceAllMasked(byte[] a, boolean[] mask) { + byte res = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "byteUnaryOpMaskProvider") + static void FIRST_NONZEROReduceByteMaxVectorTestsMasked(IntFunction fa, IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + byte ra = (byte) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + ByteMaxVectorTests::FIRST_NONZEROReduceMasked, ByteMaxVectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; diff --git a/test/jdk/jdk/incubator/vector/Double128VectorTests.java b/test/jdk/jdk/incubator/vector/Double128VectorTests.java index 646570f3752..c79b1e2f4ef 100644 --- a/test/jdk/jdk/incubator/vector/Double128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double128VectorTests.java @@ -1299,6 +1299,10 @@ public class Double128VectorTests extends AbstractVectorTest { } + static double firstNonZero(double a, double b) { + return Double.compare(a, (double) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { DoubleVector three = DoubleVector.broadcast(SPECIES, (byte)-3); @@ -2277,7 +2281,7 @@ public class Double128VectorTests extends AbstractVectorTest { static double MINReduce(double[] a, int idx) { double res = Double.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (double)Math.min(res, a[i]); + res = (double) Math.min(res, a[i]); } return res; @@ -2285,8 +2289,8 @@ public class Double128VectorTests extends AbstractVectorTest { static double MINReduceAll(double[] a) { double res = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (double)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.min(res, MINReduce(a, i)); } return res; @@ -2308,7 +2312,7 @@ public class Double128VectorTests extends AbstractVectorTest { ra = Double.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -2318,8 +2322,8 @@ public class Double128VectorTests extends AbstractVectorTest { static double MINReduceMasked(double[] a, int idx, boolean[] mask) { double res = Double.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (double) Math.min(res, a[i]); } return res; @@ -2327,9 +2331,8 @@ public class Double128VectorTests extends AbstractVectorTest { static double MINReduceAllMasked(double[] a, boolean[] mask) { double res = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -2353,7 +2356,7 @@ public class Double128VectorTests extends AbstractVectorTest { ra = Double.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -2363,7 +2366,7 @@ public class Double128VectorTests extends AbstractVectorTest { static double MAXReduce(double[] a, int idx) { double res = Double.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (double)Math.max(res, a[i]); + res = (double) Math.max(res, a[i]); } return res; @@ -2371,8 +2374,8 @@ public class Double128VectorTests extends AbstractVectorTest { static double MAXReduceAll(double[] a) { double res = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (double)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.max(res, MAXReduce(a, i)); } return res; @@ -2394,7 +2397,7 @@ public class Double128VectorTests extends AbstractVectorTest { ra = Double.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -2404,8 +2407,8 @@ public class Double128VectorTests extends AbstractVectorTest { static double MAXReduceMasked(double[] a, int idx, boolean[] mask) { double res = Double.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (double) Math.max(res, a[i]); } return res; @@ -2413,9 +2416,8 @@ public class Double128VectorTests extends AbstractVectorTest { static double MAXReduceAllMasked(double[] a, boolean[] mask) { double res = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -2439,13 +2441,98 @@ public class Double128VectorTests extends AbstractVectorTest { ra = Double.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Double128VectorTests::MAXReduceMasked, Double128VectorTests::MAXReduceAllMasked); } + static double FIRST_NONZEROReduce(double[] a, int idx) { + double res = (double) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static double FIRST_NONZEROReduceAll(double[] a) { + double res = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "doubleUnaryOpProvider") + static void FIRST_NONZEROReduceDouble128VectorTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + double ra = (double) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Double128VectorTests::FIRST_NONZEROReduce, Double128VectorTests::FIRST_NONZEROReduceAll); + } + static double FIRST_NONZEROReduceMasked(double[] a, int idx, boolean[] mask) { + double res = (double) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static double FIRST_NONZEROReduceAllMasked(double[] a, boolean[] mask) { + double res = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "doubleUnaryOpMaskProvider") + static void FIRST_NONZEROReduceDouble128VectorTestsMasked(IntFunction fa, IntFunction fm) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + double ra = (double) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Double128VectorTests::FIRST_NONZEROReduceMasked, Double128VectorTests::FIRST_NONZEROReduceAllMasked); + } diff --git a/test/jdk/jdk/incubator/vector/Double256VectorTests.java b/test/jdk/jdk/incubator/vector/Double256VectorTests.java index a7d0a2c0b9f..6d459901d13 100644 --- a/test/jdk/jdk/incubator/vector/Double256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double256VectorTests.java @@ -1299,6 +1299,10 @@ public class Double256VectorTests extends AbstractVectorTest { } + static double firstNonZero(double a, double b) { + return Double.compare(a, (double) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { DoubleVector three = DoubleVector.broadcast(SPECIES, (byte)-3); @@ -2277,7 +2281,7 @@ public class Double256VectorTests extends AbstractVectorTest { static double MINReduce(double[] a, int idx) { double res = Double.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (double)Math.min(res, a[i]); + res = (double) Math.min(res, a[i]); } return res; @@ -2285,8 +2289,8 @@ public class Double256VectorTests extends AbstractVectorTest { static double MINReduceAll(double[] a) { double res = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (double)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.min(res, MINReduce(a, i)); } return res; @@ -2308,7 +2312,7 @@ public class Double256VectorTests extends AbstractVectorTest { ra = Double.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -2318,8 +2322,8 @@ public class Double256VectorTests extends AbstractVectorTest { static double MINReduceMasked(double[] a, int idx, boolean[] mask) { double res = Double.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (double) Math.min(res, a[i]); } return res; @@ -2327,9 +2331,8 @@ public class Double256VectorTests extends AbstractVectorTest { static double MINReduceAllMasked(double[] a, boolean[] mask) { double res = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -2353,7 +2356,7 @@ public class Double256VectorTests extends AbstractVectorTest { ra = Double.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -2363,7 +2366,7 @@ public class Double256VectorTests extends AbstractVectorTest { static double MAXReduce(double[] a, int idx) { double res = Double.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (double)Math.max(res, a[i]); + res = (double) Math.max(res, a[i]); } return res; @@ -2371,8 +2374,8 @@ public class Double256VectorTests extends AbstractVectorTest { static double MAXReduceAll(double[] a) { double res = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (double)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.max(res, MAXReduce(a, i)); } return res; @@ -2394,7 +2397,7 @@ public class Double256VectorTests extends AbstractVectorTest { ra = Double.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -2404,8 +2407,8 @@ public class Double256VectorTests extends AbstractVectorTest { static double MAXReduceMasked(double[] a, int idx, boolean[] mask) { double res = Double.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (double) Math.max(res, a[i]); } return res; @@ -2413,9 +2416,8 @@ public class Double256VectorTests extends AbstractVectorTest { static double MAXReduceAllMasked(double[] a, boolean[] mask) { double res = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -2439,13 +2441,98 @@ public class Double256VectorTests extends AbstractVectorTest { ra = Double.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Double256VectorTests::MAXReduceMasked, Double256VectorTests::MAXReduceAllMasked); } + static double FIRST_NONZEROReduce(double[] a, int idx) { + double res = (double) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static double FIRST_NONZEROReduceAll(double[] a) { + double res = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "doubleUnaryOpProvider") + static void FIRST_NONZEROReduceDouble256VectorTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + double ra = (double) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Double256VectorTests::FIRST_NONZEROReduce, Double256VectorTests::FIRST_NONZEROReduceAll); + } + static double FIRST_NONZEROReduceMasked(double[] a, int idx, boolean[] mask) { + double res = (double) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static double FIRST_NONZEROReduceAllMasked(double[] a, boolean[] mask) { + double res = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "doubleUnaryOpMaskProvider") + static void FIRST_NONZEROReduceDouble256VectorTestsMasked(IntFunction fa, IntFunction fm) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + double ra = (double) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Double256VectorTests::FIRST_NONZEROReduceMasked, Double256VectorTests::FIRST_NONZEROReduceAllMasked); + } diff --git a/test/jdk/jdk/incubator/vector/Double512VectorTests.java b/test/jdk/jdk/incubator/vector/Double512VectorTests.java index 26a699454bc..82299753e65 100644 --- a/test/jdk/jdk/incubator/vector/Double512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double512VectorTests.java @@ -1299,6 +1299,10 @@ public class Double512VectorTests extends AbstractVectorTest { } + static double firstNonZero(double a, double b) { + return Double.compare(a, (double) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { DoubleVector three = DoubleVector.broadcast(SPECIES, (byte)-3); @@ -2277,7 +2281,7 @@ public class Double512VectorTests extends AbstractVectorTest { static double MINReduce(double[] a, int idx) { double res = Double.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (double)Math.min(res, a[i]); + res = (double) Math.min(res, a[i]); } return res; @@ -2285,8 +2289,8 @@ public class Double512VectorTests extends AbstractVectorTest { static double MINReduceAll(double[] a) { double res = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (double)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.min(res, MINReduce(a, i)); } return res; @@ -2308,7 +2312,7 @@ public class Double512VectorTests extends AbstractVectorTest { ra = Double.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -2318,8 +2322,8 @@ public class Double512VectorTests extends AbstractVectorTest { static double MINReduceMasked(double[] a, int idx, boolean[] mask) { double res = Double.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (double) Math.min(res, a[i]); } return res; @@ -2327,9 +2331,8 @@ public class Double512VectorTests extends AbstractVectorTest { static double MINReduceAllMasked(double[] a, boolean[] mask) { double res = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -2353,7 +2356,7 @@ public class Double512VectorTests extends AbstractVectorTest { ra = Double.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -2363,7 +2366,7 @@ public class Double512VectorTests extends AbstractVectorTest { static double MAXReduce(double[] a, int idx) { double res = Double.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (double)Math.max(res, a[i]); + res = (double) Math.max(res, a[i]); } return res; @@ -2371,8 +2374,8 @@ public class Double512VectorTests extends AbstractVectorTest { static double MAXReduceAll(double[] a) { double res = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (double)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.max(res, MAXReduce(a, i)); } return res; @@ -2394,7 +2397,7 @@ public class Double512VectorTests extends AbstractVectorTest { ra = Double.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -2404,8 +2407,8 @@ public class Double512VectorTests extends AbstractVectorTest { static double MAXReduceMasked(double[] a, int idx, boolean[] mask) { double res = Double.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (double) Math.max(res, a[i]); } return res; @@ -2413,9 +2416,8 @@ public class Double512VectorTests extends AbstractVectorTest { static double MAXReduceAllMasked(double[] a, boolean[] mask) { double res = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -2439,13 +2441,98 @@ public class Double512VectorTests extends AbstractVectorTest { ra = Double.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Double512VectorTests::MAXReduceMasked, Double512VectorTests::MAXReduceAllMasked); } + static double FIRST_NONZEROReduce(double[] a, int idx) { + double res = (double) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static double FIRST_NONZEROReduceAll(double[] a) { + double res = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "doubleUnaryOpProvider") + static void FIRST_NONZEROReduceDouble512VectorTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + double ra = (double) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Double512VectorTests::FIRST_NONZEROReduce, Double512VectorTests::FIRST_NONZEROReduceAll); + } + static double FIRST_NONZEROReduceMasked(double[] a, int idx, boolean[] mask) { + double res = (double) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static double FIRST_NONZEROReduceAllMasked(double[] a, boolean[] mask) { + double res = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "doubleUnaryOpMaskProvider") + static void FIRST_NONZEROReduceDouble512VectorTestsMasked(IntFunction fa, IntFunction fm) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + double ra = (double) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Double512VectorTests::FIRST_NONZEROReduceMasked, Double512VectorTests::FIRST_NONZEROReduceAllMasked); + } diff --git a/test/jdk/jdk/incubator/vector/Double64VectorTests.java b/test/jdk/jdk/incubator/vector/Double64VectorTests.java index 017889f8b9a..82fd826ffcb 100644 --- a/test/jdk/jdk/incubator/vector/Double64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double64VectorTests.java @@ -1299,6 +1299,10 @@ public class Double64VectorTests extends AbstractVectorTest { } + static double firstNonZero(double a, double b) { + return Double.compare(a, (double) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { DoubleVector three = DoubleVector.broadcast(SPECIES, (byte)-3); @@ -2277,7 +2281,7 @@ public class Double64VectorTests extends AbstractVectorTest { static double MINReduce(double[] a, int idx) { double res = Double.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (double)Math.min(res, a[i]); + res = (double) Math.min(res, a[i]); } return res; @@ -2285,8 +2289,8 @@ public class Double64VectorTests extends AbstractVectorTest { static double MINReduceAll(double[] a) { double res = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (double)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.min(res, MINReduce(a, i)); } return res; @@ -2308,7 +2312,7 @@ public class Double64VectorTests extends AbstractVectorTest { ra = Double.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -2318,8 +2322,8 @@ public class Double64VectorTests extends AbstractVectorTest { static double MINReduceMasked(double[] a, int idx, boolean[] mask) { double res = Double.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (double) Math.min(res, a[i]); } return res; @@ -2327,9 +2331,8 @@ public class Double64VectorTests extends AbstractVectorTest { static double MINReduceAllMasked(double[] a, boolean[] mask) { double res = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -2353,7 +2356,7 @@ public class Double64VectorTests extends AbstractVectorTest { ra = Double.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -2363,7 +2366,7 @@ public class Double64VectorTests extends AbstractVectorTest { static double MAXReduce(double[] a, int idx) { double res = Double.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (double)Math.max(res, a[i]); + res = (double) Math.max(res, a[i]); } return res; @@ -2371,8 +2374,8 @@ public class Double64VectorTests extends AbstractVectorTest { static double MAXReduceAll(double[] a) { double res = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (double)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.max(res, MAXReduce(a, i)); } return res; @@ -2394,7 +2397,7 @@ public class Double64VectorTests extends AbstractVectorTest { ra = Double.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -2404,8 +2407,8 @@ public class Double64VectorTests extends AbstractVectorTest { static double MAXReduceMasked(double[] a, int idx, boolean[] mask) { double res = Double.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (double) Math.max(res, a[i]); } return res; @@ -2413,9 +2416,8 @@ public class Double64VectorTests extends AbstractVectorTest { static double MAXReduceAllMasked(double[] a, boolean[] mask) { double res = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -2439,13 +2441,98 @@ public class Double64VectorTests extends AbstractVectorTest { ra = Double.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Double64VectorTests::MAXReduceMasked, Double64VectorTests::MAXReduceAllMasked); } + static double FIRST_NONZEROReduce(double[] a, int idx) { + double res = (double) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static double FIRST_NONZEROReduceAll(double[] a) { + double res = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "doubleUnaryOpProvider") + static void FIRST_NONZEROReduceDouble64VectorTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + double ra = (double) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Double64VectorTests::FIRST_NONZEROReduce, Double64VectorTests::FIRST_NONZEROReduceAll); + } + static double FIRST_NONZEROReduceMasked(double[] a, int idx, boolean[] mask) { + double res = (double) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static double FIRST_NONZEROReduceAllMasked(double[] a, boolean[] mask) { + double res = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "doubleUnaryOpMaskProvider") + static void FIRST_NONZEROReduceDouble64VectorTestsMasked(IntFunction fa, IntFunction fm) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + double ra = (double) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Double64VectorTests::FIRST_NONZEROReduceMasked, Double64VectorTests::FIRST_NONZEROReduceAllMasked); + } diff --git a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java index c4eb2b2182b..af9054efbb0 100644 --- a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java @@ -1304,6 +1304,10 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { } + static double firstNonZero(double a, double b) { + return Double.compare(a, (double) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { DoubleVector three = DoubleVector.broadcast(SPECIES, (byte)-3); @@ -2282,7 +2286,7 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { static double MINReduce(double[] a, int idx) { double res = Double.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (double)Math.min(res, a[i]); + res = (double) Math.min(res, a[i]); } return res; @@ -2290,8 +2294,8 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { static double MINReduceAll(double[] a) { double res = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (double)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.min(res, MINReduce(a, i)); } return res; @@ -2313,7 +2317,7 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { ra = Double.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -2323,8 +2327,8 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { static double MINReduceMasked(double[] a, int idx, boolean[] mask) { double res = Double.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (double) Math.min(res, a[i]); } return res; @@ -2332,9 +2336,8 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { static double MINReduceAllMasked(double[] a, boolean[] mask) { double res = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -2358,7 +2361,7 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { ra = Double.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -2368,7 +2371,7 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { static double MAXReduce(double[] a, int idx) { double res = Double.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (double)Math.max(res, a[i]); + res = (double) Math.max(res, a[i]); } return res; @@ -2376,8 +2379,8 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { static double MAXReduceAll(double[] a) { double res = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (double)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.max(res, MAXReduce(a, i)); } return res; @@ -2399,7 +2402,7 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { ra = Double.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -2409,8 +2412,8 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { static double MAXReduceMasked(double[] a, int idx, boolean[] mask) { double res = Double.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (double) Math.max(res, a[i]); } return res; @@ -2418,9 +2421,8 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { static double MAXReduceAllMasked(double[] a, boolean[] mask) { double res = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -2444,13 +2446,98 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { ra = Double.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, DoubleMaxVectorTests::MAXReduceMasked, DoubleMaxVectorTests::MAXReduceAllMasked); } + static double FIRST_NONZEROReduce(double[] a, int idx) { + double res = (double) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static double FIRST_NONZEROReduceAll(double[] a) { + double res = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "doubleUnaryOpProvider") + static void FIRST_NONZEROReduceDoubleMaxVectorTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + double ra = (double) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + DoubleMaxVectorTests::FIRST_NONZEROReduce, DoubleMaxVectorTests::FIRST_NONZEROReduceAll); + } + static double FIRST_NONZEROReduceMasked(double[] a, int idx, boolean[] mask) { + double res = (double) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static double FIRST_NONZEROReduceAllMasked(double[] a, boolean[] mask) { + double res = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "doubleUnaryOpMaskProvider") + static void FIRST_NONZEROReduceDoubleMaxVectorTestsMasked(IntFunction fa, IntFunction fm) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + double ra = (double) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + DoubleMaxVectorTests::FIRST_NONZEROReduceMasked, DoubleMaxVectorTests::FIRST_NONZEROReduceAllMasked); + } diff --git a/test/jdk/jdk/incubator/vector/Float128VectorTests.java b/test/jdk/jdk/incubator/vector/Float128VectorTests.java index b3e7b05d2a2..c793515b6c6 100644 --- a/test/jdk/jdk/incubator/vector/Float128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float128VectorTests.java @@ -1309,6 +1309,10 @@ public class Float128VectorTests extends AbstractVectorTest { } + static float firstNonZero(float a, float b) { + return Float.compare(a, (float) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { FloatVector three = FloatVector.broadcast(SPECIES, (byte)-3); @@ -2287,7 +2291,7 @@ public class Float128VectorTests extends AbstractVectorTest { static float MINReduce(float[] a, int idx) { float res = Float.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (float)Math.min(res, a[i]); + res = (float) Math.min(res, a[i]); } return res; @@ -2295,8 +2299,8 @@ public class Float128VectorTests extends AbstractVectorTest { static float MINReduceAll(float[] a) { float res = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (float)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.min(res, MINReduce(a, i)); } return res; @@ -2318,7 +2322,7 @@ public class Float128VectorTests extends AbstractVectorTest { ra = Float.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -2328,8 +2332,8 @@ public class Float128VectorTests extends AbstractVectorTest { static float MINReduceMasked(float[] a, int idx, boolean[] mask) { float res = Float.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (float) Math.min(res, a[i]); } return res; @@ -2337,9 +2341,8 @@ public class Float128VectorTests extends AbstractVectorTest { static float MINReduceAllMasked(float[] a, boolean[] mask) { float res = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -2363,7 +2366,7 @@ public class Float128VectorTests extends AbstractVectorTest { ra = Float.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -2373,7 +2376,7 @@ public class Float128VectorTests extends AbstractVectorTest { static float MAXReduce(float[] a, int idx) { float res = Float.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (float)Math.max(res, a[i]); + res = (float) Math.max(res, a[i]); } return res; @@ -2381,8 +2384,8 @@ public class Float128VectorTests extends AbstractVectorTest { static float MAXReduceAll(float[] a) { float res = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (float)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.max(res, MAXReduce(a, i)); } return res; @@ -2404,7 +2407,7 @@ public class Float128VectorTests extends AbstractVectorTest { ra = Float.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -2414,8 +2417,8 @@ public class Float128VectorTests extends AbstractVectorTest { static float MAXReduceMasked(float[] a, int idx, boolean[] mask) { float res = Float.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (float) Math.max(res, a[i]); } return res; @@ -2423,9 +2426,8 @@ public class Float128VectorTests extends AbstractVectorTest { static float MAXReduceAllMasked(float[] a, boolean[] mask) { float res = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -2449,13 +2451,98 @@ public class Float128VectorTests extends AbstractVectorTest { ra = Float.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Float128VectorTests::MAXReduceMasked, Float128VectorTests::MAXReduceAllMasked); } + static float FIRST_NONZEROReduce(float[] a, int idx) { + float res = (float) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static float FIRST_NONZEROReduceAll(float[] a) { + float res = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "floatUnaryOpProvider") + static void FIRST_NONZEROReduceFloat128VectorTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + float ra = (float) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Float128VectorTests::FIRST_NONZEROReduce, Float128VectorTests::FIRST_NONZEROReduceAll); + } + static float FIRST_NONZEROReduceMasked(float[] a, int idx, boolean[] mask) { + float res = (float) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static float FIRST_NONZEROReduceAllMasked(float[] a, boolean[] mask) { + float res = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "floatUnaryOpMaskProvider") + static void FIRST_NONZEROReduceFloat128VectorTestsMasked(IntFunction fa, IntFunction fm) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + float ra = (float) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Float128VectorTests::FIRST_NONZEROReduceMasked, Float128VectorTests::FIRST_NONZEROReduceAllMasked); + } diff --git a/test/jdk/jdk/incubator/vector/Float256VectorTests.java b/test/jdk/jdk/incubator/vector/Float256VectorTests.java index 120fc4cabd2..61593a8c23a 100644 --- a/test/jdk/jdk/incubator/vector/Float256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float256VectorTests.java @@ -1309,6 +1309,10 @@ public class Float256VectorTests extends AbstractVectorTest { } + static float firstNonZero(float a, float b) { + return Float.compare(a, (float) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { FloatVector three = FloatVector.broadcast(SPECIES, (byte)-3); @@ -2287,7 +2291,7 @@ public class Float256VectorTests extends AbstractVectorTest { static float MINReduce(float[] a, int idx) { float res = Float.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (float)Math.min(res, a[i]); + res = (float) Math.min(res, a[i]); } return res; @@ -2295,8 +2299,8 @@ public class Float256VectorTests extends AbstractVectorTest { static float MINReduceAll(float[] a) { float res = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (float)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.min(res, MINReduce(a, i)); } return res; @@ -2318,7 +2322,7 @@ public class Float256VectorTests extends AbstractVectorTest { ra = Float.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -2328,8 +2332,8 @@ public class Float256VectorTests extends AbstractVectorTest { static float MINReduceMasked(float[] a, int idx, boolean[] mask) { float res = Float.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (float) Math.min(res, a[i]); } return res; @@ -2337,9 +2341,8 @@ public class Float256VectorTests extends AbstractVectorTest { static float MINReduceAllMasked(float[] a, boolean[] mask) { float res = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -2363,7 +2366,7 @@ public class Float256VectorTests extends AbstractVectorTest { ra = Float.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -2373,7 +2376,7 @@ public class Float256VectorTests extends AbstractVectorTest { static float MAXReduce(float[] a, int idx) { float res = Float.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (float)Math.max(res, a[i]); + res = (float) Math.max(res, a[i]); } return res; @@ -2381,8 +2384,8 @@ public class Float256VectorTests extends AbstractVectorTest { static float MAXReduceAll(float[] a) { float res = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (float)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.max(res, MAXReduce(a, i)); } return res; @@ -2404,7 +2407,7 @@ public class Float256VectorTests extends AbstractVectorTest { ra = Float.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -2414,8 +2417,8 @@ public class Float256VectorTests extends AbstractVectorTest { static float MAXReduceMasked(float[] a, int idx, boolean[] mask) { float res = Float.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (float) Math.max(res, a[i]); } return res; @@ -2423,9 +2426,8 @@ public class Float256VectorTests extends AbstractVectorTest { static float MAXReduceAllMasked(float[] a, boolean[] mask) { float res = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -2449,13 +2451,98 @@ public class Float256VectorTests extends AbstractVectorTest { ra = Float.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Float256VectorTests::MAXReduceMasked, Float256VectorTests::MAXReduceAllMasked); } + static float FIRST_NONZEROReduce(float[] a, int idx) { + float res = (float) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static float FIRST_NONZEROReduceAll(float[] a) { + float res = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "floatUnaryOpProvider") + static void FIRST_NONZEROReduceFloat256VectorTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + float ra = (float) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Float256VectorTests::FIRST_NONZEROReduce, Float256VectorTests::FIRST_NONZEROReduceAll); + } + static float FIRST_NONZEROReduceMasked(float[] a, int idx, boolean[] mask) { + float res = (float) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static float FIRST_NONZEROReduceAllMasked(float[] a, boolean[] mask) { + float res = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "floatUnaryOpMaskProvider") + static void FIRST_NONZEROReduceFloat256VectorTestsMasked(IntFunction fa, IntFunction fm) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + float ra = (float) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Float256VectorTests::FIRST_NONZEROReduceMasked, Float256VectorTests::FIRST_NONZEROReduceAllMasked); + } diff --git a/test/jdk/jdk/incubator/vector/Float512VectorTests.java b/test/jdk/jdk/incubator/vector/Float512VectorTests.java index 75fbccaed27..421338f053c 100644 --- a/test/jdk/jdk/incubator/vector/Float512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float512VectorTests.java @@ -1309,6 +1309,10 @@ public class Float512VectorTests extends AbstractVectorTest { } + static float firstNonZero(float a, float b) { + return Float.compare(a, (float) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { FloatVector three = FloatVector.broadcast(SPECIES, (byte)-3); @@ -2287,7 +2291,7 @@ public class Float512VectorTests extends AbstractVectorTest { static float MINReduce(float[] a, int idx) { float res = Float.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (float)Math.min(res, a[i]); + res = (float) Math.min(res, a[i]); } return res; @@ -2295,8 +2299,8 @@ public class Float512VectorTests extends AbstractVectorTest { static float MINReduceAll(float[] a) { float res = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (float)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.min(res, MINReduce(a, i)); } return res; @@ -2318,7 +2322,7 @@ public class Float512VectorTests extends AbstractVectorTest { ra = Float.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -2328,8 +2332,8 @@ public class Float512VectorTests extends AbstractVectorTest { static float MINReduceMasked(float[] a, int idx, boolean[] mask) { float res = Float.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (float) Math.min(res, a[i]); } return res; @@ -2337,9 +2341,8 @@ public class Float512VectorTests extends AbstractVectorTest { static float MINReduceAllMasked(float[] a, boolean[] mask) { float res = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -2363,7 +2366,7 @@ public class Float512VectorTests extends AbstractVectorTest { ra = Float.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -2373,7 +2376,7 @@ public class Float512VectorTests extends AbstractVectorTest { static float MAXReduce(float[] a, int idx) { float res = Float.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (float)Math.max(res, a[i]); + res = (float) Math.max(res, a[i]); } return res; @@ -2381,8 +2384,8 @@ public class Float512VectorTests extends AbstractVectorTest { static float MAXReduceAll(float[] a) { float res = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (float)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.max(res, MAXReduce(a, i)); } return res; @@ -2404,7 +2407,7 @@ public class Float512VectorTests extends AbstractVectorTest { ra = Float.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -2414,8 +2417,8 @@ public class Float512VectorTests extends AbstractVectorTest { static float MAXReduceMasked(float[] a, int idx, boolean[] mask) { float res = Float.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (float) Math.max(res, a[i]); } return res; @@ -2423,9 +2426,8 @@ public class Float512VectorTests extends AbstractVectorTest { static float MAXReduceAllMasked(float[] a, boolean[] mask) { float res = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -2449,13 +2451,98 @@ public class Float512VectorTests extends AbstractVectorTest { ra = Float.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Float512VectorTests::MAXReduceMasked, Float512VectorTests::MAXReduceAllMasked); } + static float FIRST_NONZEROReduce(float[] a, int idx) { + float res = (float) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static float FIRST_NONZEROReduceAll(float[] a) { + float res = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "floatUnaryOpProvider") + static void FIRST_NONZEROReduceFloat512VectorTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + float ra = (float) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Float512VectorTests::FIRST_NONZEROReduce, Float512VectorTests::FIRST_NONZEROReduceAll); + } + static float FIRST_NONZEROReduceMasked(float[] a, int idx, boolean[] mask) { + float res = (float) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static float FIRST_NONZEROReduceAllMasked(float[] a, boolean[] mask) { + float res = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "floatUnaryOpMaskProvider") + static void FIRST_NONZEROReduceFloat512VectorTestsMasked(IntFunction fa, IntFunction fm) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + float ra = (float) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Float512VectorTests::FIRST_NONZEROReduceMasked, Float512VectorTests::FIRST_NONZEROReduceAllMasked); + } diff --git a/test/jdk/jdk/incubator/vector/Float64VectorTests.java b/test/jdk/jdk/incubator/vector/Float64VectorTests.java index dbe87867b9a..cbe82a7e22d 100644 --- a/test/jdk/jdk/incubator/vector/Float64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float64VectorTests.java @@ -1309,6 +1309,10 @@ public class Float64VectorTests extends AbstractVectorTest { } + static float firstNonZero(float a, float b) { + return Float.compare(a, (float) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { FloatVector three = FloatVector.broadcast(SPECIES, (byte)-3); @@ -2287,7 +2291,7 @@ public class Float64VectorTests extends AbstractVectorTest { static float MINReduce(float[] a, int idx) { float res = Float.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (float)Math.min(res, a[i]); + res = (float) Math.min(res, a[i]); } return res; @@ -2295,8 +2299,8 @@ public class Float64VectorTests extends AbstractVectorTest { static float MINReduceAll(float[] a) { float res = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (float)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.min(res, MINReduce(a, i)); } return res; @@ -2318,7 +2322,7 @@ public class Float64VectorTests extends AbstractVectorTest { ra = Float.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -2328,8 +2332,8 @@ public class Float64VectorTests extends AbstractVectorTest { static float MINReduceMasked(float[] a, int idx, boolean[] mask) { float res = Float.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (float) Math.min(res, a[i]); } return res; @@ -2337,9 +2341,8 @@ public class Float64VectorTests extends AbstractVectorTest { static float MINReduceAllMasked(float[] a, boolean[] mask) { float res = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -2363,7 +2366,7 @@ public class Float64VectorTests extends AbstractVectorTest { ra = Float.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -2373,7 +2376,7 @@ public class Float64VectorTests extends AbstractVectorTest { static float MAXReduce(float[] a, int idx) { float res = Float.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (float)Math.max(res, a[i]); + res = (float) Math.max(res, a[i]); } return res; @@ -2381,8 +2384,8 @@ public class Float64VectorTests extends AbstractVectorTest { static float MAXReduceAll(float[] a) { float res = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (float)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.max(res, MAXReduce(a, i)); } return res; @@ -2404,7 +2407,7 @@ public class Float64VectorTests extends AbstractVectorTest { ra = Float.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -2414,8 +2417,8 @@ public class Float64VectorTests extends AbstractVectorTest { static float MAXReduceMasked(float[] a, int idx, boolean[] mask) { float res = Float.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (float) Math.max(res, a[i]); } return res; @@ -2423,9 +2426,8 @@ public class Float64VectorTests extends AbstractVectorTest { static float MAXReduceAllMasked(float[] a, boolean[] mask) { float res = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -2449,13 +2451,98 @@ public class Float64VectorTests extends AbstractVectorTest { ra = Float.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Float64VectorTests::MAXReduceMasked, Float64VectorTests::MAXReduceAllMasked); } + static float FIRST_NONZEROReduce(float[] a, int idx) { + float res = (float) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static float FIRST_NONZEROReduceAll(float[] a) { + float res = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "floatUnaryOpProvider") + static void FIRST_NONZEROReduceFloat64VectorTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + float ra = (float) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Float64VectorTests::FIRST_NONZEROReduce, Float64VectorTests::FIRST_NONZEROReduceAll); + } + static float FIRST_NONZEROReduceMasked(float[] a, int idx, boolean[] mask) { + float res = (float) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static float FIRST_NONZEROReduceAllMasked(float[] a, boolean[] mask) { + float res = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "floatUnaryOpMaskProvider") + static void FIRST_NONZEROReduceFloat64VectorTestsMasked(IntFunction fa, IntFunction fm) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + float ra = (float) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Float64VectorTests::FIRST_NONZEROReduceMasked, Float64VectorTests::FIRST_NONZEROReduceAllMasked); + } diff --git a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java index 5d3e65b765b..e8680eb1d94 100644 --- a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java @@ -1314,6 +1314,10 @@ public class FloatMaxVectorTests extends AbstractVectorTest { } + static float firstNonZero(float a, float b) { + return Float.compare(a, (float) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { FloatVector three = FloatVector.broadcast(SPECIES, (byte)-3); @@ -2292,7 +2296,7 @@ public class FloatMaxVectorTests extends AbstractVectorTest { static float MINReduce(float[] a, int idx) { float res = Float.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (float)Math.min(res, a[i]); + res = (float) Math.min(res, a[i]); } return res; @@ -2300,8 +2304,8 @@ public class FloatMaxVectorTests extends AbstractVectorTest { static float MINReduceAll(float[] a) { float res = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (float)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.min(res, MINReduce(a, i)); } return res; @@ -2323,7 +2327,7 @@ public class FloatMaxVectorTests extends AbstractVectorTest { ra = Float.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -2333,8 +2337,8 @@ public class FloatMaxVectorTests extends AbstractVectorTest { static float MINReduceMasked(float[] a, int idx, boolean[] mask) { float res = Float.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (float) Math.min(res, a[i]); } return res; @@ -2342,9 +2346,8 @@ public class FloatMaxVectorTests extends AbstractVectorTest { static float MINReduceAllMasked(float[] a, boolean[] mask) { float res = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -2368,7 +2371,7 @@ public class FloatMaxVectorTests extends AbstractVectorTest { ra = Float.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -2378,7 +2381,7 @@ public class FloatMaxVectorTests extends AbstractVectorTest { static float MAXReduce(float[] a, int idx) { float res = Float.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (float)Math.max(res, a[i]); + res = (float) Math.max(res, a[i]); } return res; @@ -2386,8 +2389,8 @@ public class FloatMaxVectorTests extends AbstractVectorTest { static float MAXReduceAll(float[] a) { float res = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (float)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.max(res, MAXReduce(a, i)); } return res; @@ -2409,7 +2412,7 @@ public class FloatMaxVectorTests extends AbstractVectorTest { ra = Float.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -2419,8 +2422,8 @@ public class FloatMaxVectorTests extends AbstractVectorTest { static float MAXReduceMasked(float[] a, int idx, boolean[] mask) { float res = Float.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (float) Math.max(res, a[i]); } return res; @@ -2428,9 +2431,8 @@ public class FloatMaxVectorTests extends AbstractVectorTest { static float MAXReduceAllMasked(float[] a, boolean[] mask) { float res = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -2454,13 +2456,98 @@ public class FloatMaxVectorTests extends AbstractVectorTest { ra = Float.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, FloatMaxVectorTests::MAXReduceMasked, FloatMaxVectorTests::MAXReduceAllMasked); } + static float FIRST_NONZEROReduce(float[] a, int idx) { + float res = (float) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static float FIRST_NONZEROReduceAll(float[] a) { + float res = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "floatUnaryOpProvider") + static void FIRST_NONZEROReduceFloatMaxVectorTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + float ra = (float) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + FloatMaxVectorTests::FIRST_NONZEROReduce, FloatMaxVectorTests::FIRST_NONZEROReduceAll); + } + static float FIRST_NONZEROReduceMasked(float[] a, int idx, boolean[] mask) { + float res = (float) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static float FIRST_NONZEROReduceAllMasked(float[] a, boolean[] mask) { + float res = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "floatUnaryOpMaskProvider") + static void FIRST_NONZEROReduceFloatMaxVectorTestsMasked(IntFunction fa, IntFunction fm) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + float ra = (float) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + FloatMaxVectorTests::FIRST_NONZEROReduceMasked, FloatMaxVectorTests::FIRST_NONZEROReduceAllMasked); + } diff --git a/test/jdk/jdk/incubator/vector/Int128VectorTests.java b/test/jdk/jdk/incubator/vector/Int128VectorTests.java index d23295f5b4e..99bc02b8239 100644 --- a/test/jdk/jdk/incubator/vector/Int128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int128VectorTests.java @@ -1161,6 +1161,10 @@ public class Int128VectorTests extends AbstractVectorTest { return Integer.compareUnsigned(a, b) >= 0; } + static int firstNonZero(int a, int b) { + return Integer.compare(a, (int) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { IntVector three = IntVector.broadcast(SPECIES, (byte)-3); @@ -3181,7 +3185,7 @@ public class Int128VectorTests extends AbstractVectorTest { static int MINReduce(int[] a, int idx) { int res = Integer.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (int)Math.min(res, a[i]); + res = (int) Math.min(res, a[i]); } return res; @@ -3189,8 +3193,8 @@ public class Int128VectorTests extends AbstractVectorTest { static int MINReduceAll(int[] a) { int res = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (int)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.min(res, MINReduce(a, i)); } return res; @@ -3212,7 +3216,7 @@ public class Int128VectorTests extends AbstractVectorTest { ra = Integer.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3222,8 +3226,8 @@ public class Int128VectorTests extends AbstractVectorTest { static int MINReduceMasked(int[] a, int idx, boolean[] mask) { int res = Integer.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (int) Math.min(res, a[i]); } return res; @@ -3231,9 +3235,8 @@ public class Int128VectorTests extends AbstractVectorTest { static int MINReduceAllMasked(int[] a, boolean[] mask) { int res = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3257,7 +3260,7 @@ public class Int128VectorTests extends AbstractVectorTest { ra = Integer.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3267,7 +3270,7 @@ public class Int128VectorTests extends AbstractVectorTest { static int MAXReduce(int[] a, int idx) { int res = Integer.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (int)Math.max(res, a[i]); + res = (int) Math.max(res, a[i]); } return res; @@ -3275,8 +3278,8 @@ public class Int128VectorTests extends AbstractVectorTest { static int MAXReduceAll(int[] a) { int res = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (int)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.max(res, MAXReduce(a, i)); } return res; @@ -3298,7 +3301,7 @@ public class Int128VectorTests extends AbstractVectorTest { ra = Integer.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3308,8 +3311,8 @@ public class Int128VectorTests extends AbstractVectorTest { static int MAXReduceMasked(int[] a, int idx, boolean[] mask) { int res = Integer.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (int) Math.max(res, a[i]); } return res; @@ -3317,9 +3320,8 @@ public class Int128VectorTests extends AbstractVectorTest { static int MAXReduceAllMasked(int[] a, boolean[] mask) { int res = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3343,13 +3345,98 @@ public class Int128VectorTests extends AbstractVectorTest { ra = Integer.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Int128VectorTests::MAXReduceMasked, Int128VectorTests::MAXReduceAllMasked); } + static int FIRST_NONZEROReduce(int[] a, int idx) { + int res = (int) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static int FIRST_NONZEROReduceAll(int[] a) { + int res = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "intUnaryOpProvider") + static void FIRST_NONZEROReduceInt128VectorTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + int ra = (int) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Int128VectorTests::FIRST_NONZEROReduce, Int128VectorTests::FIRST_NONZEROReduceAll); + } + static int FIRST_NONZEROReduceMasked(int[] a, int idx, boolean[] mask) { + int res = (int) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static int FIRST_NONZEROReduceAllMasked(int[] a, boolean[] mask) { + int res = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "intUnaryOpMaskProvider") + static void FIRST_NONZEROReduceInt128VectorTestsMasked(IntFunction fa, IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + int ra = (int) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Int128VectorTests::FIRST_NONZEROReduceMasked, Int128VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; diff --git a/test/jdk/jdk/incubator/vector/Int256VectorTests.java b/test/jdk/jdk/incubator/vector/Int256VectorTests.java index f6bc1f7fd4c..e4b3f491e31 100644 --- a/test/jdk/jdk/incubator/vector/Int256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int256VectorTests.java @@ -1161,6 +1161,10 @@ public class Int256VectorTests extends AbstractVectorTest { return Integer.compareUnsigned(a, b) >= 0; } + static int firstNonZero(int a, int b) { + return Integer.compare(a, (int) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { IntVector three = IntVector.broadcast(SPECIES, (byte)-3); @@ -3181,7 +3185,7 @@ public class Int256VectorTests extends AbstractVectorTest { static int MINReduce(int[] a, int idx) { int res = Integer.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (int)Math.min(res, a[i]); + res = (int) Math.min(res, a[i]); } return res; @@ -3189,8 +3193,8 @@ public class Int256VectorTests extends AbstractVectorTest { static int MINReduceAll(int[] a) { int res = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (int)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.min(res, MINReduce(a, i)); } return res; @@ -3212,7 +3216,7 @@ public class Int256VectorTests extends AbstractVectorTest { ra = Integer.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3222,8 +3226,8 @@ public class Int256VectorTests extends AbstractVectorTest { static int MINReduceMasked(int[] a, int idx, boolean[] mask) { int res = Integer.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (int) Math.min(res, a[i]); } return res; @@ -3231,9 +3235,8 @@ public class Int256VectorTests extends AbstractVectorTest { static int MINReduceAllMasked(int[] a, boolean[] mask) { int res = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3257,7 +3260,7 @@ public class Int256VectorTests extends AbstractVectorTest { ra = Integer.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3267,7 +3270,7 @@ public class Int256VectorTests extends AbstractVectorTest { static int MAXReduce(int[] a, int idx) { int res = Integer.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (int)Math.max(res, a[i]); + res = (int) Math.max(res, a[i]); } return res; @@ -3275,8 +3278,8 @@ public class Int256VectorTests extends AbstractVectorTest { static int MAXReduceAll(int[] a) { int res = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (int)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.max(res, MAXReduce(a, i)); } return res; @@ -3298,7 +3301,7 @@ public class Int256VectorTests extends AbstractVectorTest { ra = Integer.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3308,8 +3311,8 @@ public class Int256VectorTests extends AbstractVectorTest { static int MAXReduceMasked(int[] a, int idx, boolean[] mask) { int res = Integer.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (int) Math.max(res, a[i]); } return res; @@ -3317,9 +3320,8 @@ public class Int256VectorTests extends AbstractVectorTest { static int MAXReduceAllMasked(int[] a, boolean[] mask) { int res = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3343,13 +3345,98 @@ public class Int256VectorTests extends AbstractVectorTest { ra = Integer.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Int256VectorTests::MAXReduceMasked, Int256VectorTests::MAXReduceAllMasked); } + static int FIRST_NONZEROReduce(int[] a, int idx) { + int res = (int) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static int FIRST_NONZEROReduceAll(int[] a) { + int res = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "intUnaryOpProvider") + static void FIRST_NONZEROReduceInt256VectorTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + int ra = (int) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Int256VectorTests::FIRST_NONZEROReduce, Int256VectorTests::FIRST_NONZEROReduceAll); + } + static int FIRST_NONZEROReduceMasked(int[] a, int idx, boolean[] mask) { + int res = (int) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static int FIRST_NONZEROReduceAllMasked(int[] a, boolean[] mask) { + int res = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "intUnaryOpMaskProvider") + static void FIRST_NONZEROReduceInt256VectorTestsMasked(IntFunction fa, IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + int ra = (int) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Int256VectorTests::FIRST_NONZEROReduceMasked, Int256VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; diff --git a/test/jdk/jdk/incubator/vector/Int512VectorTests.java b/test/jdk/jdk/incubator/vector/Int512VectorTests.java index 7f5ce407da6..503d24ab05c 100644 --- a/test/jdk/jdk/incubator/vector/Int512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int512VectorTests.java @@ -1161,6 +1161,10 @@ public class Int512VectorTests extends AbstractVectorTest { return Integer.compareUnsigned(a, b) >= 0; } + static int firstNonZero(int a, int b) { + return Integer.compare(a, (int) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { IntVector three = IntVector.broadcast(SPECIES, (byte)-3); @@ -3181,7 +3185,7 @@ public class Int512VectorTests extends AbstractVectorTest { static int MINReduce(int[] a, int idx) { int res = Integer.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (int)Math.min(res, a[i]); + res = (int) Math.min(res, a[i]); } return res; @@ -3189,8 +3193,8 @@ public class Int512VectorTests extends AbstractVectorTest { static int MINReduceAll(int[] a) { int res = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (int)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.min(res, MINReduce(a, i)); } return res; @@ -3212,7 +3216,7 @@ public class Int512VectorTests extends AbstractVectorTest { ra = Integer.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3222,8 +3226,8 @@ public class Int512VectorTests extends AbstractVectorTest { static int MINReduceMasked(int[] a, int idx, boolean[] mask) { int res = Integer.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (int) Math.min(res, a[i]); } return res; @@ -3231,9 +3235,8 @@ public class Int512VectorTests extends AbstractVectorTest { static int MINReduceAllMasked(int[] a, boolean[] mask) { int res = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3257,7 +3260,7 @@ public class Int512VectorTests extends AbstractVectorTest { ra = Integer.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3267,7 +3270,7 @@ public class Int512VectorTests extends AbstractVectorTest { static int MAXReduce(int[] a, int idx) { int res = Integer.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (int)Math.max(res, a[i]); + res = (int) Math.max(res, a[i]); } return res; @@ -3275,8 +3278,8 @@ public class Int512VectorTests extends AbstractVectorTest { static int MAXReduceAll(int[] a) { int res = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (int)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.max(res, MAXReduce(a, i)); } return res; @@ -3298,7 +3301,7 @@ public class Int512VectorTests extends AbstractVectorTest { ra = Integer.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3308,8 +3311,8 @@ public class Int512VectorTests extends AbstractVectorTest { static int MAXReduceMasked(int[] a, int idx, boolean[] mask) { int res = Integer.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (int) Math.max(res, a[i]); } return res; @@ -3317,9 +3320,8 @@ public class Int512VectorTests extends AbstractVectorTest { static int MAXReduceAllMasked(int[] a, boolean[] mask) { int res = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3343,13 +3345,98 @@ public class Int512VectorTests extends AbstractVectorTest { ra = Integer.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Int512VectorTests::MAXReduceMasked, Int512VectorTests::MAXReduceAllMasked); } + static int FIRST_NONZEROReduce(int[] a, int idx) { + int res = (int) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static int FIRST_NONZEROReduceAll(int[] a) { + int res = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "intUnaryOpProvider") + static void FIRST_NONZEROReduceInt512VectorTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + int ra = (int) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Int512VectorTests::FIRST_NONZEROReduce, Int512VectorTests::FIRST_NONZEROReduceAll); + } + static int FIRST_NONZEROReduceMasked(int[] a, int idx, boolean[] mask) { + int res = (int) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static int FIRST_NONZEROReduceAllMasked(int[] a, boolean[] mask) { + int res = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "intUnaryOpMaskProvider") + static void FIRST_NONZEROReduceInt512VectorTestsMasked(IntFunction fa, IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + int ra = (int) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Int512VectorTests::FIRST_NONZEROReduceMasked, Int512VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; diff --git a/test/jdk/jdk/incubator/vector/Int64VectorTests.java b/test/jdk/jdk/incubator/vector/Int64VectorTests.java index 6da8ecf04e4..2bebc06d0e2 100644 --- a/test/jdk/jdk/incubator/vector/Int64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int64VectorTests.java @@ -1161,6 +1161,10 @@ public class Int64VectorTests extends AbstractVectorTest { return Integer.compareUnsigned(a, b) >= 0; } + static int firstNonZero(int a, int b) { + return Integer.compare(a, (int) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { IntVector three = IntVector.broadcast(SPECIES, (byte)-3); @@ -3181,7 +3185,7 @@ public class Int64VectorTests extends AbstractVectorTest { static int MINReduce(int[] a, int idx) { int res = Integer.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (int)Math.min(res, a[i]); + res = (int) Math.min(res, a[i]); } return res; @@ -3189,8 +3193,8 @@ public class Int64VectorTests extends AbstractVectorTest { static int MINReduceAll(int[] a) { int res = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (int)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.min(res, MINReduce(a, i)); } return res; @@ -3212,7 +3216,7 @@ public class Int64VectorTests extends AbstractVectorTest { ra = Integer.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3222,8 +3226,8 @@ public class Int64VectorTests extends AbstractVectorTest { static int MINReduceMasked(int[] a, int idx, boolean[] mask) { int res = Integer.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (int) Math.min(res, a[i]); } return res; @@ -3231,9 +3235,8 @@ public class Int64VectorTests extends AbstractVectorTest { static int MINReduceAllMasked(int[] a, boolean[] mask) { int res = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3257,7 +3260,7 @@ public class Int64VectorTests extends AbstractVectorTest { ra = Integer.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3267,7 +3270,7 @@ public class Int64VectorTests extends AbstractVectorTest { static int MAXReduce(int[] a, int idx) { int res = Integer.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (int)Math.max(res, a[i]); + res = (int) Math.max(res, a[i]); } return res; @@ -3275,8 +3278,8 @@ public class Int64VectorTests extends AbstractVectorTest { static int MAXReduceAll(int[] a) { int res = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (int)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.max(res, MAXReduce(a, i)); } return res; @@ -3298,7 +3301,7 @@ public class Int64VectorTests extends AbstractVectorTest { ra = Integer.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3308,8 +3311,8 @@ public class Int64VectorTests extends AbstractVectorTest { static int MAXReduceMasked(int[] a, int idx, boolean[] mask) { int res = Integer.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (int) Math.max(res, a[i]); } return res; @@ -3317,9 +3320,8 @@ public class Int64VectorTests extends AbstractVectorTest { static int MAXReduceAllMasked(int[] a, boolean[] mask) { int res = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3343,13 +3345,98 @@ public class Int64VectorTests extends AbstractVectorTest { ra = Integer.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Int64VectorTests::MAXReduceMasked, Int64VectorTests::MAXReduceAllMasked); } + static int FIRST_NONZEROReduce(int[] a, int idx) { + int res = (int) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static int FIRST_NONZEROReduceAll(int[] a) { + int res = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "intUnaryOpProvider") + static void FIRST_NONZEROReduceInt64VectorTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + int ra = (int) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Int64VectorTests::FIRST_NONZEROReduce, Int64VectorTests::FIRST_NONZEROReduceAll); + } + static int FIRST_NONZEROReduceMasked(int[] a, int idx, boolean[] mask) { + int res = (int) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static int FIRST_NONZEROReduceAllMasked(int[] a, boolean[] mask) { + int res = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "intUnaryOpMaskProvider") + static void FIRST_NONZEROReduceInt64VectorTestsMasked(IntFunction fa, IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + int ra = (int) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Int64VectorTests::FIRST_NONZEROReduceMasked, Int64VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; diff --git a/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java b/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java index 0e59f7f0ed5..faf232e2985 100644 --- a/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java @@ -1166,6 +1166,10 @@ public class IntMaxVectorTests extends AbstractVectorTest { return Integer.compareUnsigned(a, b) >= 0; } + static int firstNonZero(int a, int b) { + return Integer.compare(a, (int) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { IntVector three = IntVector.broadcast(SPECIES, (byte)-3); @@ -3186,7 +3190,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { static int MINReduce(int[] a, int idx) { int res = Integer.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (int)Math.min(res, a[i]); + res = (int) Math.min(res, a[i]); } return res; @@ -3194,8 +3198,8 @@ public class IntMaxVectorTests extends AbstractVectorTest { static int MINReduceAll(int[] a) { int res = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (int)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.min(res, MINReduce(a, i)); } return res; @@ -3217,7 +3221,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { ra = Integer.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3227,8 +3231,8 @@ public class IntMaxVectorTests extends AbstractVectorTest { static int MINReduceMasked(int[] a, int idx, boolean[] mask) { int res = Integer.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (int) Math.min(res, a[i]); } return res; @@ -3236,9 +3240,8 @@ public class IntMaxVectorTests extends AbstractVectorTest { static int MINReduceAllMasked(int[] a, boolean[] mask) { int res = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3262,7 +3265,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { ra = Integer.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3272,7 +3275,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { static int MAXReduce(int[] a, int idx) { int res = Integer.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (int)Math.max(res, a[i]); + res = (int) Math.max(res, a[i]); } return res; @@ -3280,8 +3283,8 @@ public class IntMaxVectorTests extends AbstractVectorTest { static int MAXReduceAll(int[] a) { int res = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (int)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.max(res, MAXReduce(a, i)); } return res; @@ -3303,7 +3306,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { ra = Integer.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3313,8 +3316,8 @@ public class IntMaxVectorTests extends AbstractVectorTest { static int MAXReduceMasked(int[] a, int idx, boolean[] mask) { int res = Integer.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (int) Math.max(res, a[i]); } return res; @@ -3322,9 +3325,8 @@ public class IntMaxVectorTests extends AbstractVectorTest { static int MAXReduceAllMasked(int[] a, boolean[] mask) { int res = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3348,13 +3350,98 @@ public class IntMaxVectorTests extends AbstractVectorTest { ra = Integer.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, IntMaxVectorTests::MAXReduceMasked, IntMaxVectorTests::MAXReduceAllMasked); } + static int FIRST_NONZEROReduce(int[] a, int idx) { + int res = (int) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static int FIRST_NONZEROReduceAll(int[] a) { + int res = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "intUnaryOpProvider") + static void FIRST_NONZEROReduceIntMaxVectorTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + int ra = (int) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + IntMaxVectorTests::FIRST_NONZEROReduce, IntMaxVectorTests::FIRST_NONZEROReduceAll); + } + static int FIRST_NONZEROReduceMasked(int[] a, int idx, boolean[] mask) { + int res = (int) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static int FIRST_NONZEROReduceAllMasked(int[] a, boolean[] mask) { + int res = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "intUnaryOpMaskProvider") + static void FIRST_NONZEROReduceIntMaxVectorTestsMasked(IntFunction fa, IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + int ra = (int) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + IntMaxVectorTests::FIRST_NONZEROReduceMasked, IntMaxVectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; diff --git a/test/jdk/jdk/incubator/vector/Long128VectorTests.java b/test/jdk/jdk/incubator/vector/Long128VectorTests.java index ebd7acb104d..74d251476b2 100644 --- a/test/jdk/jdk/incubator/vector/Long128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long128VectorTests.java @@ -1183,6 +1183,10 @@ public class Long128VectorTests extends AbstractVectorTest { return Long.compareUnsigned(a, b) >= 0; } + static long firstNonZero(long a, long b) { + return Long.compare(a, (long) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { LongVector three = LongVector.broadcast(SPECIES, (byte)-3); @@ -3203,7 +3207,7 @@ public class Long128VectorTests extends AbstractVectorTest { static long MINReduce(long[] a, int idx) { long res = Long.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (long)Math.min(res, a[i]); + res = (long) Math.min(res, a[i]); } return res; @@ -3211,8 +3215,8 @@ public class Long128VectorTests extends AbstractVectorTest { static long MINReduceAll(long[] a) { long res = Long.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (long)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.min(res, MINReduce(a, i)); } return res; @@ -3234,7 +3238,7 @@ public class Long128VectorTests extends AbstractVectorTest { ra = Long.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3244,8 +3248,8 @@ public class Long128VectorTests extends AbstractVectorTest { static long MINReduceMasked(long[] a, int idx, boolean[] mask) { long res = Long.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (long) Math.min(res, a[i]); } return res; @@ -3253,9 +3257,8 @@ public class Long128VectorTests extends AbstractVectorTest { static long MINReduceAllMasked(long[] a, boolean[] mask) { long res = Long.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3279,7 +3282,7 @@ public class Long128VectorTests extends AbstractVectorTest { ra = Long.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3289,7 +3292,7 @@ public class Long128VectorTests extends AbstractVectorTest { static long MAXReduce(long[] a, int idx) { long res = Long.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (long)Math.max(res, a[i]); + res = (long) Math.max(res, a[i]); } return res; @@ -3297,8 +3300,8 @@ public class Long128VectorTests extends AbstractVectorTest { static long MAXReduceAll(long[] a) { long res = Long.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (long)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.max(res, MAXReduce(a, i)); } return res; @@ -3320,7 +3323,7 @@ public class Long128VectorTests extends AbstractVectorTest { ra = Long.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3330,8 +3333,8 @@ public class Long128VectorTests extends AbstractVectorTest { static long MAXReduceMasked(long[] a, int idx, boolean[] mask) { long res = Long.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (long) Math.max(res, a[i]); } return res; @@ -3339,9 +3342,8 @@ public class Long128VectorTests extends AbstractVectorTest { static long MAXReduceAllMasked(long[] a, boolean[] mask) { long res = Long.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3365,13 +3367,98 @@ public class Long128VectorTests extends AbstractVectorTest { ra = Long.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Long128VectorTests::MAXReduceMasked, Long128VectorTests::MAXReduceAllMasked); } + static long FIRST_NONZEROReduce(long[] a, int idx) { + long res = (long) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static long FIRST_NONZEROReduceAll(long[] a) { + long res = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "longUnaryOpProvider") + static void FIRST_NONZEROReduceLong128VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + long ra = (long) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Long128VectorTests::FIRST_NONZEROReduce, Long128VectorTests::FIRST_NONZEROReduceAll); + } + static long FIRST_NONZEROReduceMasked(long[] a, int idx, boolean[] mask) { + long res = (long) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static long FIRST_NONZEROReduceAllMasked(long[] a, boolean[] mask) { + long res = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "longUnaryOpMaskProvider") + static void FIRST_NONZEROReduceLong128VectorTestsMasked(IntFunction fa, IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + long ra = (long) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Long128VectorTests::FIRST_NONZEROReduceMasked, Long128VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; diff --git a/test/jdk/jdk/incubator/vector/Long256VectorTests.java b/test/jdk/jdk/incubator/vector/Long256VectorTests.java index 5065745e5f8..4d2acbddd86 100644 --- a/test/jdk/jdk/incubator/vector/Long256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long256VectorTests.java @@ -1183,6 +1183,10 @@ public class Long256VectorTests extends AbstractVectorTest { return Long.compareUnsigned(a, b) >= 0; } + static long firstNonZero(long a, long b) { + return Long.compare(a, (long) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { LongVector three = LongVector.broadcast(SPECIES, (byte)-3); @@ -3203,7 +3207,7 @@ public class Long256VectorTests extends AbstractVectorTest { static long MINReduce(long[] a, int idx) { long res = Long.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (long)Math.min(res, a[i]); + res = (long) Math.min(res, a[i]); } return res; @@ -3211,8 +3215,8 @@ public class Long256VectorTests extends AbstractVectorTest { static long MINReduceAll(long[] a) { long res = Long.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (long)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.min(res, MINReduce(a, i)); } return res; @@ -3234,7 +3238,7 @@ public class Long256VectorTests extends AbstractVectorTest { ra = Long.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3244,8 +3248,8 @@ public class Long256VectorTests extends AbstractVectorTest { static long MINReduceMasked(long[] a, int idx, boolean[] mask) { long res = Long.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (long) Math.min(res, a[i]); } return res; @@ -3253,9 +3257,8 @@ public class Long256VectorTests extends AbstractVectorTest { static long MINReduceAllMasked(long[] a, boolean[] mask) { long res = Long.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3279,7 +3282,7 @@ public class Long256VectorTests extends AbstractVectorTest { ra = Long.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3289,7 +3292,7 @@ public class Long256VectorTests extends AbstractVectorTest { static long MAXReduce(long[] a, int idx) { long res = Long.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (long)Math.max(res, a[i]); + res = (long) Math.max(res, a[i]); } return res; @@ -3297,8 +3300,8 @@ public class Long256VectorTests extends AbstractVectorTest { static long MAXReduceAll(long[] a) { long res = Long.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (long)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.max(res, MAXReduce(a, i)); } return res; @@ -3320,7 +3323,7 @@ public class Long256VectorTests extends AbstractVectorTest { ra = Long.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3330,8 +3333,8 @@ public class Long256VectorTests extends AbstractVectorTest { static long MAXReduceMasked(long[] a, int idx, boolean[] mask) { long res = Long.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (long) Math.max(res, a[i]); } return res; @@ -3339,9 +3342,8 @@ public class Long256VectorTests extends AbstractVectorTest { static long MAXReduceAllMasked(long[] a, boolean[] mask) { long res = Long.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3365,13 +3367,98 @@ public class Long256VectorTests extends AbstractVectorTest { ra = Long.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Long256VectorTests::MAXReduceMasked, Long256VectorTests::MAXReduceAllMasked); } + static long FIRST_NONZEROReduce(long[] a, int idx) { + long res = (long) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static long FIRST_NONZEROReduceAll(long[] a) { + long res = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "longUnaryOpProvider") + static void FIRST_NONZEROReduceLong256VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + long ra = (long) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Long256VectorTests::FIRST_NONZEROReduce, Long256VectorTests::FIRST_NONZEROReduceAll); + } + static long FIRST_NONZEROReduceMasked(long[] a, int idx, boolean[] mask) { + long res = (long) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static long FIRST_NONZEROReduceAllMasked(long[] a, boolean[] mask) { + long res = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "longUnaryOpMaskProvider") + static void FIRST_NONZEROReduceLong256VectorTestsMasked(IntFunction fa, IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + long ra = (long) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Long256VectorTests::FIRST_NONZEROReduceMasked, Long256VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; diff --git a/test/jdk/jdk/incubator/vector/Long512VectorTests.java b/test/jdk/jdk/incubator/vector/Long512VectorTests.java index dd0c71e1dbc..9bb6f568fca 100644 --- a/test/jdk/jdk/incubator/vector/Long512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long512VectorTests.java @@ -1183,6 +1183,10 @@ public class Long512VectorTests extends AbstractVectorTest { return Long.compareUnsigned(a, b) >= 0; } + static long firstNonZero(long a, long b) { + return Long.compare(a, (long) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { LongVector three = LongVector.broadcast(SPECIES, (byte)-3); @@ -3203,7 +3207,7 @@ public class Long512VectorTests extends AbstractVectorTest { static long MINReduce(long[] a, int idx) { long res = Long.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (long)Math.min(res, a[i]); + res = (long) Math.min(res, a[i]); } return res; @@ -3211,8 +3215,8 @@ public class Long512VectorTests extends AbstractVectorTest { static long MINReduceAll(long[] a) { long res = Long.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (long)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.min(res, MINReduce(a, i)); } return res; @@ -3234,7 +3238,7 @@ public class Long512VectorTests extends AbstractVectorTest { ra = Long.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3244,8 +3248,8 @@ public class Long512VectorTests extends AbstractVectorTest { static long MINReduceMasked(long[] a, int idx, boolean[] mask) { long res = Long.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (long) Math.min(res, a[i]); } return res; @@ -3253,9 +3257,8 @@ public class Long512VectorTests extends AbstractVectorTest { static long MINReduceAllMasked(long[] a, boolean[] mask) { long res = Long.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3279,7 +3282,7 @@ public class Long512VectorTests extends AbstractVectorTest { ra = Long.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3289,7 +3292,7 @@ public class Long512VectorTests extends AbstractVectorTest { static long MAXReduce(long[] a, int idx) { long res = Long.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (long)Math.max(res, a[i]); + res = (long) Math.max(res, a[i]); } return res; @@ -3297,8 +3300,8 @@ public class Long512VectorTests extends AbstractVectorTest { static long MAXReduceAll(long[] a) { long res = Long.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (long)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.max(res, MAXReduce(a, i)); } return res; @@ -3320,7 +3323,7 @@ public class Long512VectorTests extends AbstractVectorTest { ra = Long.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3330,8 +3333,8 @@ public class Long512VectorTests extends AbstractVectorTest { static long MAXReduceMasked(long[] a, int idx, boolean[] mask) { long res = Long.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (long) Math.max(res, a[i]); } return res; @@ -3339,9 +3342,8 @@ public class Long512VectorTests extends AbstractVectorTest { static long MAXReduceAllMasked(long[] a, boolean[] mask) { long res = Long.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3365,13 +3367,98 @@ public class Long512VectorTests extends AbstractVectorTest { ra = Long.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Long512VectorTests::MAXReduceMasked, Long512VectorTests::MAXReduceAllMasked); } + static long FIRST_NONZEROReduce(long[] a, int idx) { + long res = (long) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static long FIRST_NONZEROReduceAll(long[] a) { + long res = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "longUnaryOpProvider") + static void FIRST_NONZEROReduceLong512VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + long ra = (long) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Long512VectorTests::FIRST_NONZEROReduce, Long512VectorTests::FIRST_NONZEROReduceAll); + } + static long FIRST_NONZEROReduceMasked(long[] a, int idx, boolean[] mask) { + long res = (long) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static long FIRST_NONZEROReduceAllMasked(long[] a, boolean[] mask) { + long res = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "longUnaryOpMaskProvider") + static void FIRST_NONZEROReduceLong512VectorTestsMasked(IntFunction fa, IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + long ra = (long) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Long512VectorTests::FIRST_NONZEROReduceMasked, Long512VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; diff --git a/test/jdk/jdk/incubator/vector/Long64VectorTests.java b/test/jdk/jdk/incubator/vector/Long64VectorTests.java index 919f6ef0f6a..50976531dac 100644 --- a/test/jdk/jdk/incubator/vector/Long64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long64VectorTests.java @@ -1183,6 +1183,10 @@ public class Long64VectorTests extends AbstractVectorTest { return Long.compareUnsigned(a, b) >= 0; } + static long firstNonZero(long a, long b) { + return Long.compare(a, (long) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { LongVector three = LongVector.broadcast(SPECIES, (byte)-3); @@ -3203,7 +3207,7 @@ public class Long64VectorTests extends AbstractVectorTest { static long MINReduce(long[] a, int idx) { long res = Long.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (long)Math.min(res, a[i]); + res = (long) Math.min(res, a[i]); } return res; @@ -3211,8 +3215,8 @@ public class Long64VectorTests extends AbstractVectorTest { static long MINReduceAll(long[] a) { long res = Long.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (long)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.min(res, MINReduce(a, i)); } return res; @@ -3234,7 +3238,7 @@ public class Long64VectorTests extends AbstractVectorTest { ra = Long.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3244,8 +3248,8 @@ public class Long64VectorTests extends AbstractVectorTest { static long MINReduceMasked(long[] a, int idx, boolean[] mask) { long res = Long.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (long) Math.min(res, a[i]); } return res; @@ -3253,9 +3257,8 @@ public class Long64VectorTests extends AbstractVectorTest { static long MINReduceAllMasked(long[] a, boolean[] mask) { long res = Long.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3279,7 +3282,7 @@ public class Long64VectorTests extends AbstractVectorTest { ra = Long.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3289,7 +3292,7 @@ public class Long64VectorTests extends AbstractVectorTest { static long MAXReduce(long[] a, int idx) { long res = Long.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (long)Math.max(res, a[i]); + res = (long) Math.max(res, a[i]); } return res; @@ -3297,8 +3300,8 @@ public class Long64VectorTests extends AbstractVectorTest { static long MAXReduceAll(long[] a) { long res = Long.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (long)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.max(res, MAXReduce(a, i)); } return res; @@ -3320,7 +3323,7 @@ public class Long64VectorTests extends AbstractVectorTest { ra = Long.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3330,8 +3333,8 @@ public class Long64VectorTests extends AbstractVectorTest { static long MAXReduceMasked(long[] a, int idx, boolean[] mask) { long res = Long.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (long) Math.max(res, a[i]); } return res; @@ -3339,9 +3342,8 @@ public class Long64VectorTests extends AbstractVectorTest { static long MAXReduceAllMasked(long[] a, boolean[] mask) { long res = Long.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3365,13 +3367,98 @@ public class Long64VectorTests extends AbstractVectorTest { ra = Long.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Long64VectorTests::MAXReduceMasked, Long64VectorTests::MAXReduceAllMasked); } + static long FIRST_NONZEROReduce(long[] a, int idx) { + long res = (long) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static long FIRST_NONZEROReduceAll(long[] a) { + long res = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "longUnaryOpProvider") + static void FIRST_NONZEROReduceLong64VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + long ra = (long) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Long64VectorTests::FIRST_NONZEROReduce, Long64VectorTests::FIRST_NONZEROReduceAll); + } + static long FIRST_NONZEROReduceMasked(long[] a, int idx, boolean[] mask) { + long res = (long) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static long FIRST_NONZEROReduceAllMasked(long[] a, boolean[] mask) { + long res = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "longUnaryOpMaskProvider") + static void FIRST_NONZEROReduceLong64VectorTestsMasked(IntFunction fa, IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + long ra = (long) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Long64VectorTests::FIRST_NONZEROReduceMasked, Long64VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; diff --git a/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java b/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java index 443de01cdb4..eb16136a0d6 100644 --- a/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java @@ -1188,6 +1188,10 @@ public class LongMaxVectorTests extends AbstractVectorTest { return Long.compareUnsigned(a, b) >= 0; } + static long firstNonZero(long a, long b) { + return Long.compare(a, (long) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { LongVector three = LongVector.broadcast(SPECIES, (byte)-3); @@ -3208,7 +3212,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { static long MINReduce(long[] a, int idx) { long res = Long.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (long)Math.min(res, a[i]); + res = (long) Math.min(res, a[i]); } return res; @@ -3216,8 +3220,8 @@ public class LongMaxVectorTests extends AbstractVectorTest { static long MINReduceAll(long[] a) { long res = Long.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (long)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.min(res, MINReduce(a, i)); } return res; @@ -3239,7 +3243,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { ra = Long.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3249,8 +3253,8 @@ public class LongMaxVectorTests extends AbstractVectorTest { static long MINReduceMasked(long[] a, int idx, boolean[] mask) { long res = Long.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (long) Math.min(res, a[i]); } return res; @@ -3258,9 +3262,8 @@ public class LongMaxVectorTests extends AbstractVectorTest { static long MINReduceAllMasked(long[] a, boolean[] mask) { long res = Long.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3284,7 +3287,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { ra = Long.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3294,7 +3297,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { static long MAXReduce(long[] a, int idx) { long res = Long.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (long)Math.max(res, a[i]); + res = (long) Math.max(res, a[i]); } return res; @@ -3302,8 +3305,8 @@ public class LongMaxVectorTests extends AbstractVectorTest { static long MAXReduceAll(long[] a) { long res = Long.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (long)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.max(res, MAXReduce(a, i)); } return res; @@ -3325,7 +3328,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { ra = Long.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3335,8 +3338,8 @@ public class LongMaxVectorTests extends AbstractVectorTest { static long MAXReduceMasked(long[] a, int idx, boolean[] mask) { long res = Long.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (long) Math.max(res, a[i]); } return res; @@ -3344,9 +3347,8 @@ public class LongMaxVectorTests extends AbstractVectorTest { static long MAXReduceAllMasked(long[] a, boolean[] mask) { long res = Long.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3370,13 +3372,98 @@ public class LongMaxVectorTests extends AbstractVectorTest { ra = Long.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, LongMaxVectorTests::MAXReduceMasked, LongMaxVectorTests::MAXReduceAllMasked); } + static long FIRST_NONZEROReduce(long[] a, int idx) { + long res = (long) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static long FIRST_NONZEROReduceAll(long[] a) { + long res = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "longUnaryOpProvider") + static void FIRST_NONZEROReduceLongMaxVectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + long ra = (long) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + LongMaxVectorTests::FIRST_NONZEROReduce, LongMaxVectorTests::FIRST_NONZEROReduceAll); + } + static long FIRST_NONZEROReduceMasked(long[] a, int idx, boolean[] mask) { + long res = (long) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static long FIRST_NONZEROReduceAllMasked(long[] a, boolean[] mask) { + long res = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "longUnaryOpMaskProvider") + static void FIRST_NONZEROReduceLongMaxVectorTestsMasked(IntFunction fa, IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + long ra = (long) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + LongMaxVectorTests::FIRST_NONZEROReduceMasked, LongMaxVectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; diff --git a/test/jdk/jdk/incubator/vector/Short128VectorTests.java b/test/jdk/jdk/incubator/vector/Short128VectorTests.java index 2e50b940b0e..2a060c354cd 100644 --- a/test/jdk/jdk/incubator/vector/Short128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short128VectorTests.java @@ -1191,6 +1191,10 @@ public class Short128VectorTests extends AbstractVectorTest { return Short.compareUnsigned(a, b) >= 0; } + static short firstNonZero(short a, short b) { + return Short.compare(a, (short) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { ShortVector three = ShortVector.broadcast(SPECIES, (byte)-3); @@ -3206,7 +3210,7 @@ public class Short128VectorTests extends AbstractVectorTest { static short MINReduce(short[] a, int idx) { short res = Short.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (short)Math.min(res, a[i]); + res = (short) Math.min(res, a[i]); } return res; @@ -3214,8 +3218,8 @@ public class Short128VectorTests extends AbstractVectorTest { static short MINReduceAll(short[] a) { short res = Short.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (short)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.min(res, MINReduce(a, i)); } return res; @@ -3237,7 +3241,7 @@ public class Short128VectorTests extends AbstractVectorTest { ra = Short.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3247,8 +3251,8 @@ public class Short128VectorTests extends AbstractVectorTest { static short MINReduceMasked(short[] a, int idx, boolean[] mask) { short res = Short.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (short) Math.min(res, a[i]); } return res; @@ -3256,9 +3260,8 @@ public class Short128VectorTests extends AbstractVectorTest { static short MINReduceAllMasked(short[] a, boolean[] mask) { short res = Short.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3282,7 +3285,7 @@ public class Short128VectorTests extends AbstractVectorTest { ra = Short.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3292,7 +3295,7 @@ public class Short128VectorTests extends AbstractVectorTest { static short MAXReduce(short[] a, int idx) { short res = Short.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (short)Math.max(res, a[i]); + res = (short) Math.max(res, a[i]); } return res; @@ -3300,8 +3303,8 @@ public class Short128VectorTests extends AbstractVectorTest { static short MAXReduceAll(short[] a) { short res = Short.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (short)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.max(res, MAXReduce(a, i)); } return res; @@ -3323,7 +3326,7 @@ public class Short128VectorTests extends AbstractVectorTest { ra = Short.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3333,8 +3336,8 @@ public class Short128VectorTests extends AbstractVectorTest { static short MAXReduceMasked(short[] a, int idx, boolean[] mask) { short res = Short.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (short) Math.max(res, a[i]); } return res; @@ -3342,9 +3345,8 @@ public class Short128VectorTests extends AbstractVectorTest { static short MAXReduceAllMasked(short[] a, boolean[] mask) { short res = Short.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3368,13 +3370,98 @@ public class Short128VectorTests extends AbstractVectorTest { ra = Short.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Short128VectorTests::MAXReduceMasked, Short128VectorTests::MAXReduceAllMasked); } + static short FIRST_NONZEROReduce(short[] a, int idx) { + short res = (short) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static short FIRST_NONZEROReduceAll(short[] a) { + short res = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "shortUnaryOpProvider") + static void FIRST_NONZEROReduceShort128VectorTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + short ra = (short) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Short128VectorTests::FIRST_NONZEROReduce, Short128VectorTests::FIRST_NONZEROReduceAll); + } + static short FIRST_NONZEROReduceMasked(short[] a, int idx, boolean[] mask) { + short res = (short) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static short FIRST_NONZEROReduceAllMasked(short[] a, boolean[] mask) { + short res = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "shortUnaryOpMaskProvider") + static void FIRST_NONZEROReduceShort128VectorTestsMasked(IntFunction fa, IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + short ra = (short) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Short128VectorTests::FIRST_NONZEROReduceMasked, Short128VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; diff --git a/test/jdk/jdk/incubator/vector/Short256VectorTests.java b/test/jdk/jdk/incubator/vector/Short256VectorTests.java index 67fc08c6194..46626d63aaf 100644 --- a/test/jdk/jdk/incubator/vector/Short256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short256VectorTests.java @@ -1191,6 +1191,10 @@ public class Short256VectorTests extends AbstractVectorTest { return Short.compareUnsigned(a, b) >= 0; } + static short firstNonZero(short a, short b) { + return Short.compare(a, (short) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { ShortVector three = ShortVector.broadcast(SPECIES, (byte)-3); @@ -3206,7 +3210,7 @@ public class Short256VectorTests extends AbstractVectorTest { static short MINReduce(short[] a, int idx) { short res = Short.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (short)Math.min(res, a[i]); + res = (short) Math.min(res, a[i]); } return res; @@ -3214,8 +3218,8 @@ public class Short256VectorTests extends AbstractVectorTest { static short MINReduceAll(short[] a) { short res = Short.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (short)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.min(res, MINReduce(a, i)); } return res; @@ -3237,7 +3241,7 @@ public class Short256VectorTests extends AbstractVectorTest { ra = Short.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3247,8 +3251,8 @@ public class Short256VectorTests extends AbstractVectorTest { static short MINReduceMasked(short[] a, int idx, boolean[] mask) { short res = Short.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (short) Math.min(res, a[i]); } return res; @@ -3256,9 +3260,8 @@ public class Short256VectorTests extends AbstractVectorTest { static short MINReduceAllMasked(short[] a, boolean[] mask) { short res = Short.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3282,7 +3285,7 @@ public class Short256VectorTests extends AbstractVectorTest { ra = Short.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3292,7 +3295,7 @@ public class Short256VectorTests extends AbstractVectorTest { static short MAXReduce(short[] a, int idx) { short res = Short.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (short)Math.max(res, a[i]); + res = (short) Math.max(res, a[i]); } return res; @@ -3300,8 +3303,8 @@ public class Short256VectorTests extends AbstractVectorTest { static short MAXReduceAll(short[] a) { short res = Short.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (short)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.max(res, MAXReduce(a, i)); } return res; @@ -3323,7 +3326,7 @@ public class Short256VectorTests extends AbstractVectorTest { ra = Short.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3333,8 +3336,8 @@ public class Short256VectorTests extends AbstractVectorTest { static short MAXReduceMasked(short[] a, int idx, boolean[] mask) { short res = Short.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (short) Math.max(res, a[i]); } return res; @@ -3342,9 +3345,8 @@ public class Short256VectorTests extends AbstractVectorTest { static short MAXReduceAllMasked(short[] a, boolean[] mask) { short res = Short.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3368,13 +3370,98 @@ public class Short256VectorTests extends AbstractVectorTest { ra = Short.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Short256VectorTests::MAXReduceMasked, Short256VectorTests::MAXReduceAllMasked); } + static short FIRST_NONZEROReduce(short[] a, int idx) { + short res = (short) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static short FIRST_NONZEROReduceAll(short[] a) { + short res = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "shortUnaryOpProvider") + static void FIRST_NONZEROReduceShort256VectorTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + short ra = (short) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Short256VectorTests::FIRST_NONZEROReduce, Short256VectorTests::FIRST_NONZEROReduceAll); + } + static short FIRST_NONZEROReduceMasked(short[] a, int idx, boolean[] mask) { + short res = (short) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static short FIRST_NONZEROReduceAllMasked(short[] a, boolean[] mask) { + short res = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "shortUnaryOpMaskProvider") + static void FIRST_NONZEROReduceShort256VectorTestsMasked(IntFunction fa, IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + short ra = (short) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Short256VectorTests::FIRST_NONZEROReduceMasked, Short256VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; diff --git a/test/jdk/jdk/incubator/vector/Short512VectorTests.java b/test/jdk/jdk/incubator/vector/Short512VectorTests.java index 63bc3709481..2cff4a4802a 100644 --- a/test/jdk/jdk/incubator/vector/Short512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short512VectorTests.java @@ -1191,6 +1191,10 @@ public class Short512VectorTests extends AbstractVectorTest { return Short.compareUnsigned(a, b) >= 0; } + static short firstNonZero(short a, short b) { + return Short.compare(a, (short) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { ShortVector three = ShortVector.broadcast(SPECIES, (byte)-3); @@ -3206,7 +3210,7 @@ public class Short512VectorTests extends AbstractVectorTest { static short MINReduce(short[] a, int idx) { short res = Short.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (short)Math.min(res, a[i]); + res = (short) Math.min(res, a[i]); } return res; @@ -3214,8 +3218,8 @@ public class Short512VectorTests extends AbstractVectorTest { static short MINReduceAll(short[] a) { short res = Short.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (short)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.min(res, MINReduce(a, i)); } return res; @@ -3237,7 +3241,7 @@ public class Short512VectorTests extends AbstractVectorTest { ra = Short.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3247,8 +3251,8 @@ public class Short512VectorTests extends AbstractVectorTest { static short MINReduceMasked(short[] a, int idx, boolean[] mask) { short res = Short.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (short) Math.min(res, a[i]); } return res; @@ -3256,9 +3260,8 @@ public class Short512VectorTests extends AbstractVectorTest { static short MINReduceAllMasked(short[] a, boolean[] mask) { short res = Short.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3282,7 +3285,7 @@ public class Short512VectorTests extends AbstractVectorTest { ra = Short.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3292,7 +3295,7 @@ public class Short512VectorTests extends AbstractVectorTest { static short MAXReduce(short[] a, int idx) { short res = Short.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (short)Math.max(res, a[i]); + res = (short) Math.max(res, a[i]); } return res; @@ -3300,8 +3303,8 @@ public class Short512VectorTests extends AbstractVectorTest { static short MAXReduceAll(short[] a) { short res = Short.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (short)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.max(res, MAXReduce(a, i)); } return res; @@ -3323,7 +3326,7 @@ public class Short512VectorTests extends AbstractVectorTest { ra = Short.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3333,8 +3336,8 @@ public class Short512VectorTests extends AbstractVectorTest { static short MAXReduceMasked(short[] a, int idx, boolean[] mask) { short res = Short.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (short) Math.max(res, a[i]); } return res; @@ -3342,9 +3345,8 @@ public class Short512VectorTests extends AbstractVectorTest { static short MAXReduceAllMasked(short[] a, boolean[] mask) { short res = Short.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3368,13 +3370,98 @@ public class Short512VectorTests extends AbstractVectorTest { ra = Short.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Short512VectorTests::MAXReduceMasked, Short512VectorTests::MAXReduceAllMasked); } + static short FIRST_NONZEROReduce(short[] a, int idx) { + short res = (short) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static short FIRST_NONZEROReduceAll(short[] a) { + short res = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "shortUnaryOpProvider") + static void FIRST_NONZEROReduceShort512VectorTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + short ra = (short) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Short512VectorTests::FIRST_NONZEROReduce, Short512VectorTests::FIRST_NONZEROReduceAll); + } + static short FIRST_NONZEROReduceMasked(short[] a, int idx, boolean[] mask) { + short res = (short) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static short FIRST_NONZEROReduceAllMasked(short[] a, boolean[] mask) { + short res = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "shortUnaryOpMaskProvider") + static void FIRST_NONZEROReduceShort512VectorTestsMasked(IntFunction fa, IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + short ra = (short) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Short512VectorTests::FIRST_NONZEROReduceMasked, Short512VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; diff --git a/test/jdk/jdk/incubator/vector/Short64VectorTests.java b/test/jdk/jdk/incubator/vector/Short64VectorTests.java index 8c05159737d..481081b75da 100644 --- a/test/jdk/jdk/incubator/vector/Short64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short64VectorTests.java @@ -1191,6 +1191,10 @@ public class Short64VectorTests extends AbstractVectorTest { return Short.compareUnsigned(a, b) >= 0; } + static short firstNonZero(short a, short b) { + return Short.compare(a, (short) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { ShortVector three = ShortVector.broadcast(SPECIES, (byte)-3); @@ -3206,7 +3210,7 @@ public class Short64VectorTests extends AbstractVectorTest { static short MINReduce(short[] a, int idx) { short res = Short.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (short)Math.min(res, a[i]); + res = (short) Math.min(res, a[i]); } return res; @@ -3214,8 +3218,8 @@ public class Short64VectorTests extends AbstractVectorTest { static short MINReduceAll(short[] a) { short res = Short.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (short)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.min(res, MINReduce(a, i)); } return res; @@ -3237,7 +3241,7 @@ public class Short64VectorTests extends AbstractVectorTest { ra = Short.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3247,8 +3251,8 @@ public class Short64VectorTests extends AbstractVectorTest { static short MINReduceMasked(short[] a, int idx, boolean[] mask) { short res = Short.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (short) Math.min(res, a[i]); } return res; @@ -3256,9 +3260,8 @@ public class Short64VectorTests extends AbstractVectorTest { static short MINReduceAllMasked(short[] a, boolean[] mask) { short res = Short.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3282,7 +3285,7 @@ public class Short64VectorTests extends AbstractVectorTest { ra = Short.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3292,7 +3295,7 @@ public class Short64VectorTests extends AbstractVectorTest { static short MAXReduce(short[] a, int idx) { short res = Short.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (short)Math.max(res, a[i]); + res = (short) Math.max(res, a[i]); } return res; @@ -3300,8 +3303,8 @@ public class Short64VectorTests extends AbstractVectorTest { static short MAXReduceAll(short[] a) { short res = Short.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (short)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.max(res, MAXReduce(a, i)); } return res; @@ -3323,7 +3326,7 @@ public class Short64VectorTests extends AbstractVectorTest { ra = Short.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3333,8 +3336,8 @@ public class Short64VectorTests extends AbstractVectorTest { static short MAXReduceMasked(short[] a, int idx, boolean[] mask) { short res = Short.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (short) Math.max(res, a[i]); } return res; @@ -3342,9 +3345,8 @@ public class Short64VectorTests extends AbstractVectorTest { static short MAXReduceAllMasked(short[] a, boolean[] mask) { short res = Short.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3368,13 +3370,98 @@ public class Short64VectorTests extends AbstractVectorTest { ra = Short.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Short64VectorTests::MAXReduceMasked, Short64VectorTests::MAXReduceAllMasked); } + static short FIRST_NONZEROReduce(short[] a, int idx) { + short res = (short) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static short FIRST_NONZEROReduceAll(short[] a) { + short res = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "shortUnaryOpProvider") + static void FIRST_NONZEROReduceShort64VectorTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + short ra = (short) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Short64VectorTests::FIRST_NONZEROReduce, Short64VectorTests::FIRST_NONZEROReduceAll); + } + static short FIRST_NONZEROReduceMasked(short[] a, int idx, boolean[] mask) { + short res = (short) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static short FIRST_NONZEROReduceAllMasked(short[] a, boolean[] mask) { + short res = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "shortUnaryOpMaskProvider") + static void FIRST_NONZEROReduceShort64VectorTestsMasked(IntFunction fa, IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + short ra = (short) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Short64VectorTests::FIRST_NONZEROReduceMasked, Short64VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; diff --git a/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java b/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java index b196aad5218..00d99484a13 100644 --- a/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java @@ -1196,6 +1196,10 @@ public class ShortMaxVectorTests extends AbstractVectorTest { return Short.compareUnsigned(a, b) >= 0; } + static short firstNonZero(short a, short b) { + return Short.compare(a, (short) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { ShortVector three = ShortVector.broadcast(SPECIES, (byte)-3); @@ -3211,7 +3215,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { static short MINReduce(short[] a, int idx) { short res = Short.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (short)Math.min(res, a[i]); + res = (short) Math.min(res, a[i]); } return res; @@ -3219,8 +3223,8 @@ public class ShortMaxVectorTests extends AbstractVectorTest { static short MINReduceAll(short[] a) { short res = Short.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (short)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.min(res, MINReduce(a, i)); } return res; @@ -3242,7 +3246,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { ra = Short.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3252,8 +3256,8 @@ public class ShortMaxVectorTests extends AbstractVectorTest { static short MINReduceMasked(short[] a, int idx, boolean[] mask) { short res = Short.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (short) Math.min(res, a[i]); } return res; @@ -3261,9 +3265,8 @@ public class ShortMaxVectorTests extends AbstractVectorTest { static short MINReduceAllMasked(short[] a, boolean[] mask) { short res = Short.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3287,7 +3290,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { ra = Short.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3297,7 +3300,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { static short MAXReduce(short[] a, int idx) { short res = Short.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (short)Math.max(res, a[i]); + res = (short) Math.max(res, a[i]); } return res; @@ -3305,8 +3308,8 @@ public class ShortMaxVectorTests extends AbstractVectorTest { static short MAXReduceAll(short[] a) { short res = Short.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (short)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.max(res, MAXReduce(a, i)); } return res; @@ -3328,7 +3331,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { ra = Short.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3338,8 +3341,8 @@ public class ShortMaxVectorTests extends AbstractVectorTest { static short MAXReduceMasked(short[] a, int idx, boolean[] mask) { short res = Short.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (short) Math.max(res, a[i]); } return res; @@ -3347,9 +3350,8 @@ public class ShortMaxVectorTests extends AbstractVectorTest { static short MAXReduceAllMasked(short[] a, boolean[] mask) { short res = Short.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3373,13 +3375,98 @@ public class ShortMaxVectorTests extends AbstractVectorTest { ra = Short.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, ShortMaxVectorTests::MAXReduceMasked, ShortMaxVectorTests::MAXReduceAllMasked); } + static short FIRST_NONZEROReduce(short[] a, int idx) { + short res = (short) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static short FIRST_NONZEROReduceAll(short[] a) { + short res = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "shortUnaryOpProvider") + static void FIRST_NONZEROReduceShortMaxVectorTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + short ra = (short) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + ShortMaxVectorTests::FIRST_NONZEROReduce, ShortMaxVectorTests::FIRST_NONZEROReduceAll); + } + static short FIRST_NONZEROReduceMasked(short[] a, int idx, boolean[] mask) { + short res = (short) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static short FIRST_NONZEROReduceAllMasked(short[] a, boolean[] mask) { + short res = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "shortUnaryOpMaskProvider") + static void FIRST_NONZEROReduceShortMaxVectorTestsMasked(IntFunction fa, IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + short ra = (short) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + ShortMaxVectorTests::FIRST_NONZEROReduceMasked, ShortMaxVectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; diff --git a/test/jdk/jdk/incubator/vector/gen-template.sh b/test/jdk/jdk/incubator/vector/gen-template.sh index 544cd0dc317..51fb155fd84 100644 --- a/test/jdk/jdk/incubator/vector/gen-template.sh +++ b/test/jdk/jdk/incubator/vector/gen-template.sh @@ -55,17 +55,13 @@ compare_template="Compare" compare_masked_template="Compare-Masked" compare_broadcast_template="Compare-Broadcast" reduction_scalar="Reduction-Scalar-op" -reduction_scalar_min="Reduction-Scalar-Min-op" -reduction_scalar_max="Reduction-Scalar-Max-op" +reduction_scalar_func="Reduction-Scalar-op-func" reduction_scalar_masked="Reduction-Scalar-Masked-op" -reduction_scalar_min_masked="Reduction-Scalar-Masked-Min-op" -reduction_scalar_max_masked="Reduction-Scalar-Masked-Max-op" +reduction_scalar_masked_func="Reduction-Scalar-Masked-op-func" reduction_op="Reduction-op" -reduction_op_min="Reduction-Min-op" -reduction_op_max="Reduction-Max-op" +reduction_op_func="Reduction-op-func" reduction_op_masked="Reduction-Masked-op" -reduction_op_min_masked="Reduction-Masked-Min-op" -reduction_op_max_masked="Reduction-Masked-Max-op" +reduction_op_masked_func="Reduction-Masked-op-func" unary_math_template="Unary-op-math" binary_math_template="Binary-op-math" binary_math_broadcast_template="Binary-Broadcast-op-math" @@ -337,20 +333,12 @@ function gen_reduction_op { gen_op_tmpl $reduction_op_masked "$@" } -function gen_reduction_op_min { +function gen_reduction_op_func { echo "Generating reduction op $1 ($2)..." - gen_op_tmpl $reduction_scalar_min "$@" - gen_op_tmpl $reduction_op_min "$@" - gen_op_tmpl $reduction_scalar_min_masked "$@" - gen_op_tmpl $reduction_op_min_masked "$@" -} - -function gen_reduction_op_max { - echo "Generating reduction op $1 ($2)..." - gen_op_tmpl $reduction_scalar_max "$@" - gen_op_tmpl $reduction_op_max "$@" - gen_op_tmpl $reduction_scalar_max_masked "$@" - gen_op_tmpl $reduction_op_max_masked "$@" + gen_op_tmpl $reduction_scalar_func "$@" + gen_op_tmpl $reduction_op_func "$@" + gen_op_tmpl $reduction_scalar_masked_func "$@" + gen_op_tmpl $reduction_op_masked_func "$@" } function gen_bool_reduction_op { @@ -462,9 +450,9 @@ gen_reduction_op "OR" "|" "BITWISE" "0" gen_reduction_op "XOR" "^" "BITWISE" "0" gen_reduction_op "ADD" "+" "" "0" gen_reduction_op "MUL" "*" "" "1" -gen_reduction_op_min "MIN" "" "" "\$Wideboxtype\$.\$MaxValue\$" -gen_reduction_op_max "MAX" "" "" "\$Wideboxtype\$.\$MinValue\$" -#gen_reduction_op "reduce_FIRST_NONZERO" "lanewise_FIRST_NONZERO" "{#if[FP]?Double.doubleToLongBits}(a)=0?a:b" "" "1" +gen_reduction_op_func "MIN" "(\$type\$) Math.min" "" "\$Wideboxtype\$.\$MaxValue\$" +gen_reduction_op_func "MAX" "(\$type\$) Math.max" "" "\$Wideboxtype\$.\$MinValue\$" +gen_reduction_op_func "FIRST_NONZERO" "firstNonZero" "" "(\$type\$) 0" # Boolean reductions. gen_bool_reduction_op "anyTrue" "|" "BITWISE" "false" diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-Min-op.template b/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-Min-op.template deleted file mode 100644 index 041b61da0e1..00000000000 --- a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-Min-op.template +++ /dev/null @@ -1,21 +0,0 @@ - $type$[] a = fa.apply(SPECIES.length()); - $type$[] r = fr.apply(SPECIES.length()); - boolean[] mask = fm.apply(SPECIES.length()); - VectorMask<$Wideboxtype$> vmask = VectorMask.fromArray(SPECIES, mask, 0); - $type$ ra = [[TEST_INIT]]; - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { - $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.[[TEST]], vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = [[TEST_INIT]]; - for (int i = 0; i < a.length; i += SPECIES.length()) { - $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - ra = ($type$)Math.min(ra, av.reduceLanes(VectorOperators.[[TEST]], vmask)); - } - } - diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-Max-op.template b/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-op-func.template similarity index 90% rename from test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-Max-op.template rename to test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-op-func.template index d317aaf4f8a..bf03a4d0430 100644 --- a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-Max-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-op-func.template @@ -15,7 +15,7 @@ ra = [[TEST_INIT]]; for (int i = 0; i < a.length; i += SPECIES.length()) { $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - ra = ($type$)Math.max(ra, av.reduceLanes(VectorOperators.[[TEST]], vmask)); + ra = [[TEST_OP]](ra, av.reduceLanes(VectorOperators.[[TEST]], vmask)); } } diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Min-op.template b/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Min-op.template deleted file mode 100644 index d6d53e4ef21..00000000000 --- a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Min-op.template +++ /dev/null @@ -1,19 +0,0 @@ - $type$[] a = fa.apply(SPECIES.length()); - $type$[] r = fr.apply(SPECIES.length()); - $type$ ra = [[TEST_INIT]]; - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { - $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.[[TEST]]); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = [[TEST_INIT]]; - for (int i = 0; i < a.length; i += SPECIES.length()) { - $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - ra = ($type$)Math.min(ra, av.reduceLanes(VectorOperators.[[TEST]])); - } - } - diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Max-op.template b/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-op-func.template similarity index 89% rename from test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Max-op.template rename to test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-op-func.template index 3af5b8cfde9..7082ff0795e 100644 --- a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Max-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-op-func.template @@ -13,7 +13,7 @@ ra = [[TEST_INIT]]; for (int i = 0; i < a.length; i += SPECIES.length()) { $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - ra = ($type$)Math.max(ra, av.reduceLanes(VectorOperators.[[TEST]])); + ra = [[TEST_OP]](ra, av.reduceLanes(VectorOperators.[[TEST]])); } } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-Min-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-Min-op.template deleted file mode 100644 index 70ffa79bf6f..00000000000 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-Min-op.template +++ /dev/null @@ -1,6 +0,0 @@ - @Test(dataProvider = "$type$UnaryOpMaskProvider") - static void [[TEST]]Reduce$vectorteststype$Masked(IntFunction<$type$[]> fa, IntFunction fm) { -[[KERNEL]] - assertReductionArraysEqualsMasked(r, ra, a, mask, - $vectorteststype$::[[TEST]]ReduceMasked, $vectorteststype$::[[TEST]]ReduceAllMasked); - } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-Max-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-op-func.template similarity index 100% rename from test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-Max-op.template rename to test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-op-func.template diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Min-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Min-op.template deleted file mode 100644 index b86248f3f09..00000000000 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Min-op.template +++ /dev/null @@ -1,6 +0,0 @@ - @Test(dataProvider = "$type$UnaryOpProvider") - static void [[TEST]]Reduce$vectorteststype$(IntFunction<$type$[]> fa) { -[[KERNEL]] - assertReductionArraysEquals(r, ra, a, - $vectorteststype$::[[TEST]]Reduce, $vectorteststype$::[[TEST]]ReduceAll); - } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Masked-Min-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Masked-Min-op.template deleted file mode 100644 index 6a491c05734..00000000000 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Masked-Min-op.template +++ /dev/null @@ -1,19 +0,0 @@ - static $type$ [[TEST]]ReduceMasked($type$[] a, int idx, boolean[] mask) { - $type$ res = [[TEST_INIT]]; - for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = ($type$)Math.min(res, a[i]); - } - - return res; - } - - static $type$ [[TEST]]ReduceAllMasked($type$[] a, boolean[] mask) { - $type$ res = [[TEST_INIT]]; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = ($type$)Math.min(res, a[i]); - } - - return res; - } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Masked-Max-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Masked-op-func.template similarity index 60% rename from test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Masked-Max-op.template rename to test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Masked-op-func.template index b4a2c764b84..00b8ed390bc 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Masked-Max-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Masked-op-func.template @@ -1,8 +1,8 @@ static $type$ [[TEST]]ReduceMasked($type$[] a, int idx, boolean[] mask) { $type$ res = [[TEST_INIT]]; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = ($type$)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = [[TEST_OP]](res, a[i]); } return res; @@ -10,9 +10,8 @@ static $type$ [[TEST]]ReduceAllMasked($type$[] a, boolean[] mask) { $type$ res = [[TEST_INIT]]; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = ($type$)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = [[TEST_OP]](res, [[TEST]]ReduceMasked(a, i, mask)); } return res; diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Min-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Min-op.template deleted file mode 100644 index 9e84bd13034..00000000000 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Min-op.template +++ /dev/null @@ -1,17 +0,0 @@ - static $type$ [[TEST]]Reduce($type$[] a, int idx) { - $type$ res = [[TEST_INIT]]; - for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = ($type$)Math.min(res, a[i]); - } - - return res; - } - - static $type$ [[TEST]]ReduceAll($type$[] a) { - $type$ res = [[TEST_INIT]]; - for (int i = 0; i < a.length; i++) { - res = ($type$)Math.min(res, a[i]); - } - - return res; - } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Max-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-op-func.template similarity index 65% rename from test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Max-op.template rename to test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-op-func.template index 528f4ddb5f3..2abdcd295b4 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Max-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-op-func.template @@ -1,7 +1,7 @@ static $type$ [[TEST]]Reduce($type$[] a, int idx) { $type$ res = [[TEST_INIT]]; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = ($type$)Math.max(res, a[i]); + res = [[TEST_OP]](res, a[i]); } return res; @@ -9,8 +9,8 @@ static $type$ [[TEST]]ReduceAll($type$[] a) { $type$ res = [[TEST_INIT]]; - for (int i = 0; i < a.length; i++) { - res = ($type$)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = [[TEST_OP]](res, [[TEST]]Reduce(a, i)); } return res; diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Max-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op-func.template similarity index 100% rename from test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Max-op.template rename to test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op-func.template diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-header.template b/test/jdk/jdk/incubator/vector/templates/Unit-header.template index f73d697e2a7..239596bf433 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-header.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-header.template @@ -1451,6 +1451,10 @@ public class $vectorteststype$ extends AbstractVectorTest { } #end[!FP] + static $type$ firstNonZero($type$ a, $type$ b) { + return $Boxtype$.compare(a, ($type$) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { $abstractvectortype$ three = $abstractvectortype$.broadcast(SPECIES, (byte)-3); -- GitLab From 58c2bd315836b9c4fbffa212497fd84c8f589c17 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Thu, 10 Feb 2022 22:51:39 +0000 Subject: [PATCH 028/203] 8281536: JFR: Improve jdk.jfr.ContentType documentation Reviewed-by: mgronlun --- .../share/classes/jdk/jfr/ContentType.java | 16 ++++ .../jdk/jfr/snippet-files/Snippets.java | 82 +++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/ContentType.java b/src/jdk.jfr/share/classes/jdk/jfr/ContentType.java index 13a5ae226ba..3580997ad24 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/ContentType.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/ContentType.java @@ -33,6 +33,22 @@ import java.lang.annotation.Target; /** * Meta annotation, specifies that an annotation represents a content type, such * as a time span or a frequency. + *

+ * The following example shows how a temperature content type can be created and + * used. + *

+ * First declare a temperature annotation using the {@code ContentType} + * annotation: + * + * {@snippet class="Snippets" region="ContentTypeDeclaration"} + * + * Then declare an event, annotate a field and commit the data: + * + * {@snippet class="Snippets" region="ContentTypeEvent"} + * + * Finally, inspect the annotation when displaying event data: + * + * {@snippet class="Snippets" region="ContentTypeConsumption"} * * @since 9 */ diff --git a/src/jdk.jfr/share/classes/jdk/jfr/snippet-files/Snippets.java b/src/jdk.jfr/share/classes/jdk/jfr/snippet-files/Snippets.java index b2d4fff29de..ef95e2ffb35 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/snippet-files/Snippets.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/snippet-files/Snippets.java @@ -32,7 +32,10 @@ import jdk.jfr.Name; import jdk.jfr.Label; import jdk.jfr.Description; import jdk.jfr.Category; +import jdk.jfr.ContentType; +import jdk.jfr.Period; import jdk.jfr.Recording; +import jdk.jfr.StackTrace; import jdk.jfr.MetadataDefinition; import jdk.jfr.Relational; import jdk.jfr.consumer.RecordingFile; @@ -40,6 +43,7 @@ import jdk.jfr.Configuration; import jdk.jfr.SettingDefinition; import jdk.jfr.SettingControl; import jdk.jfr.FlightRecorder; +import jdk.jfr.consumer.RecordedEvent; import java.io.IOException; import java.nio.file.Files; @@ -78,6 +82,84 @@ public class Snippets { // @end } + record CPU(String id, float temperature) { + } + + private static List listCPUs() { + return List.of(); + } + + // @start region="ContentTypeDeclaration" + @MetadataDefinition + @ContentType + @Name("com.example.Temperature") + @Label("Temperature") + @Target(ElementType.FIELD) + @Retention(RetentionPolicy.RUNTIME) + public @interface Temperature { + public final static String KELVIN = "KELVIN"; + public final static String CELSIUS = "CELSIUS"; + public final static String FAHRENEHIT = "FAHRENHEIT"; + + String value() default CELSIUS; + } + // @end + + // @start region="ContentTypeEvent" + @Name("com.example.CPU") + @Label("CPU") + @Category({ "Hardware", "CPU" }) + @Period("1 s") + @StackTrace(false) + static public class CPUEvent extends Event { + @Label("ID") + String id; + + @Temperature(Temperature.KELVIN) + @Label("Temperature") + float temperature; + } + + public static void main(String... args) throws InterruptedException { + FlightRecorder.addPeriodicEvent(CPUEvent.class, () -> { + for (var cpu : listCPUs()) { + CPUEvent event = new CPUEvent(); + event.id = cpu.id(); + event.temperature = cpu.temperature(); // in Kelvin + event.commit(); + } + }); + Thread.sleep(10_000); + } + // @end + + // @start region="ContentTypeConsumption" + void printTemperaturesInCelsius(Path file) throws IOException { + for (RecordedEvent event : RecordingFile.readAllEvents(file)) { + for (ValueDescriptor field : event.getEventType().getFields()) { + for (AnnotationElement ae : field.getAnnotationElements()) { + ContentType type = ae.getAnnotation(ContentType.class); + if (type != null) { + if (ae.getTypeName().equals("com.example.Temperature")) { + double value = event.getDouble(field.getName()); + String unit = (String) ae.getValue("value"); + double celsius = switch (unit) { + case "CELSIUS" -> value; + case "KELVIN" -> value - 273.15; + case "FAHRENHEIT" -> (value - 32) / 1.8; + default -> throw new IllegalStateException("Unknown temperature unit '" + unit + "'"); + }; + System.out.println(celsius + " C"); + } else { + System.err.println("Can't format content type " + ae.getTypeName() + " for field " + field.getName()); + } + } + } + } + } + } + // @end + // @start region="EventOverview" public class Example { -- GitLab From 84868e39be4522ba87e603beea0f8da9efa43b6d Mon Sep 17 00:00:00 2001 From: David Holmes Date: Thu, 10 Feb 2022 23:23:48 +0000 Subject: [PATCH 029/203] 8281275: Upgrading from 8 to 11 no longer accepts '/' as filepath separator in gc paths Reviewed-by: shade, dcubed --- .../share/logging/logConfiguration.cpp | 8 +++--- .../gtest/logging/test_logConfiguration.cpp | 25 ++++++++++++++++++- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/logging/logConfiguration.cpp b/src/hotspot/share/logging/logConfiguration.cpp index a46af599215..518e7979ef8 100644 --- a/src/hotspot/share/logging/logConfiguration.cpp +++ b/src/hotspot/share/logging/logConfiguration.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -365,9 +365,9 @@ bool LogConfiguration::parse_command_line_arguments(const char* opts) { // Find the next colon or quote char* next = strpbrk(str, ":\""); #ifdef _WINDOWS - // Skip over Windows paths such as "C:\..." - // Handle both C:\... and file=C:\..." - if (next != NULL && next[0] == ':' && next[1] == '\\') { + // Skip over Windows paths such as "C:\..." and "C:/...". + // Handles both "C:\..." and "file=C:\...". + if (next != NULL && next[0] == ':' && (next[1] == '\\' || next[1] == '/')) { if (next == str + 1 || (strncmp(str, "file=", 5) == 0)) { next = strpbrk(next + 1, ":\""); } diff --git a/test/hotspot/gtest/logging/test_logConfiguration.cpp b/test/hotspot/gtest/logging/test_logConfiguration.cpp index 0d092dc0d75..38997af68cb 100644 --- a/test/hotspot/gtest/logging/test_logConfiguration.cpp +++ b/test/hotspot/gtest/logging/test_logConfiguration.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -359,6 +359,29 @@ TEST_VM_F(LogConfigurationTest, parse_command_line_arguments) { ret = jio_snprintf(buf, sizeof(buf), ":%s", TestLogFileName); ASSERT_NE(-1, ret); EXPECT_TRUE(LogConfiguration::parse_command_line_arguments(buf)); + +#ifdef _WINDOWS + // We need to test the special-case parsing for drive letters in + // log file paths e.g. c:\log.txt and c:/log.txt. Our temp directory + // based TestLogFileName should already be the \ format (we print it + // below to visually verify) so we only need to convert to /. + printf("Checked: %s\n", buf); + // First disable logging so the current log file will be closed and we + // can delete it, so that UL won't try to perform log file rotation. + // The rotated file would not be auto-deleted. + set_log_config(TestLogFileName, "all=off"); + delete_file(TestLogFileName); + + // now convert \ to / + char* current_pos = strchr(buf,'\\'); + while (current_pos != nullptr) { + *current_pos = '/'; + current_pos = strchr(current_pos + 1, '\\'); + } + printf("Checking: %s\n", buf); + EXPECT_TRUE(LogConfiguration::parse_command_line_arguments(buf)); +#endif + } // Test split up log configuration arguments -- GitLab From eee6a5622dca683d4d6a701daa48e09e8d17b54e Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Fri, 11 Feb 2022 05:34:27 +0000 Subject: [PATCH 030/203] 8281522: Rename ADLC classes which have the same name as hotspot variants Reviewed-by: neliasso, kvn --- .../share/adlc/{arena.cpp => adlArena.cpp} | 94 +++++++++---------- .../share/adlc/{arena.hpp => adlArena.hpp} | 56 +++++------ src/hotspot/share/adlc/adlc.hpp | 2 +- src/hotspot/share/adlc/adlparse.cpp | 16 ++-- src/hotspot/share/adlc/dfa.cpp | 6 +- src/hotspot/share/adlc/dict2.cpp | 4 +- src/hotspot/share/adlc/dict2.hpp | 6 +- src/hotspot/share/adlc/forms.cpp | 14 +-- src/hotspot/share/adlc/forms.hpp | 10 +- src/hotspot/share/adlc/formsopt.cpp | 4 +- src/hotspot/share/adlc/formssel.cpp | 6 +- 11 files changed, 109 insertions(+), 109 deletions(-) rename src/hotspot/share/adlc/{arena.cpp => adlArena.cpp} (66%) rename src/hotspot/share/adlc/{arena.hpp => adlArena.hpp} (73%) diff --git a/src/hotspot/share/adlc/arena.cpp b/src/hotspot/share/adlc/adlArena.cpp similarity index 66% rename from src/hotspot/share/adlc/arena.cpp rename to src/hotspot/share/adlc/adlArena.cpp index 60a546e7961..7c6e9419d4f 100644 --- a/src/hotspot/share/adlc/arena.cpp +++ b/src/hotspot/share/adlc/adlArena.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ #include "adlc.hpp" -void* AllocateHeap(size_t size) { +void* AdlAllocateHeap(size_t size) { unsigned char* ptr = (unsigned char*) malloc(size); if (ptr == NULL && size != 0) { fprintf(stderr, "Error: Out of memory in ADLC\n"); // logging can cause crash! @@ -34,7 +34,7 @@ void* AllocateHeap(size_t size) { return ptr; } -void* ReAllocateHeap(void* old_ptr, size_t size) { +void* AdlReAllocateHeap(void* old_ptr, size_t size) { unsigned char* ptr = (unsigned char*) realloc(old_ptr, size); if (ptr == NULL && size != 0) { fprintf(stderr, "Error: Out of memory in ADLC\n"); // logging can cause crash! @@ -44,24 +44,24 @@ void* ReAllocateHeap(void* old_ptr, size_t size) { return ptr; } -void* Chunk::operator new(size_t requested_size, size_t length) throw() { - return CHeapObj::operator new(requested_size + length); +void* AdlChunk::operator new(size_t requested_size, size_t length) throw() { + return AdlCHeapObj::operator new(requested_size + length); } -void Chunk::operator delete(void* p, size_t length) { - CHeapObj::operator delete(p); +void AdlChunk::operator delete(void* p, size_t length) { + AdlCHeapObj::operator delete(p); } -Chunk::Chunk(size_t length) { +AdlChunk::AdlChunk(size_t length) { _next = NULL; // Chain on the linked list _len = length; // Save actual size } //------------------------------chop------------------------------------------- -void Chunk::chop() { - Chunk *k = this; +void AdlChunk::chop() { + AdlChunk *k = this; while( k ) { - Chunk *tmp = k->_next; + AdlChunk *tmp = k->_next; // clear out this chunk (to detect allocation bugs) memset(k, 0xBE, k->_len); free(k); // Free chunk (was malloc'd) @@ -69,52 +69,52 @@ void Chunk::chop() { } } -void Chunk::next_chop() { +void AdlChunk::next_chop() { _next->chop(); _next = NULL; } -//------------------------------Arena------------------------------------------ -Arena::Arena( size_t init_size ) { +//------------------------------AdlArena------------------------------------------ +AdlArena::AdlArena( size_t init_size ) { init_size = (init_size+3) & ~3; - _first = _chunk = new (init_size) Chunk(init_size); + _first = _chunk = new (init_size) AdlChunk(init_size); _hwm = _chunk->bottom(); // Save the cached hwm, max _max = _chunk->top(); set_size_in_bytes(init_size); } -Arena::Arena() { - _first = _chunk = new (Chunk::init_size) Chunk(Chunk::init_size); +AdlArena::AdlArena() { + _first = _chunk = new (AdlChunk::init_size) AdlChunk(AdlChunk::init_size); _hwm = _chunk->bottom(); // Save the cached hwm, max _max = _chunk->top(); - set_size_in_bytes(Chunk::init_size); + set_size_in_bytes(AdlChunk::init_size); } -Arena::Arena( Arena *a ) +AdlArena::AdlArena( AdlArena *a ) : _chunk(a->_chunk), _hwm(a->_hwm), _max(a->_max), _first(a->_first) { set_size_in_bytes(a->size_in_bytes()); } //------------------------------used------------------------------------------- -// Total of all Chunks in arena -size_t Arena::used() const { - size_t sum = _chunk->_len - (_max-_hwm); // Size leftover in this Chunk - Chunk *k = _first; - while( k != _chunk) { // Whilst have Chunks in a row - sum += k->_len; // Total size of this Chunk - k = k->_next; // Bump along to next Chunk +// Total of all AdlChunks in arena +size_t AdlArena::used() const { + size_t sum = _chunk->_len - (_max-_hwm); // Size leftover in this AdlChunk + AdlChunk *k = _first; + while( k != _chunk) { // Whilst have AdlChunks in a row + sum += k->_len; // Total size of this AdlChunk + k = k->_next; // Bump along to next AdlChunk } return sum; // Return total consumed space. } //------------------------------grow------------------------------------------- -// Grow a new Chunk -void* Arena::grow( size_t x ) { +// Grow a new AdlChunk +void* AdlArena::grow( size_t x ) { // Get minimal required size. Either real big, or even bigger for giant objs - size_t len = max(x, Chunk::size); + size_t len = max(x, AdlChunk::size); - Chunk *k = _chunk; // Get filled-up chunk address - _chunk = new (len) Chunk(len); + AdlChunk *k = _chunk; // Get filled-up chunk address + _chunk = new (len) AdlChunk(len); if( k ) k->_next = _chunk; // Append new chunk to end of linked list else _first = _chunk; @@ -127,8 +127,8 @@ void* Arena::grow( size_t x ) { } //------------------------------calloc----------------------------------------- -// Allocate zeroed storage in Arena -void *Arena::Acalloc( size_t items, size_t x ) { +// Allocate zeroed storage in AdlArena +void *AdlArena::Acalloc( size_t items, size_t x ) { size_t z = items*x; // Total size needed void *ptr = Amalloc(z); // Get space memset( ptr, 0, z ); // Zap space @@ -136,8 +136,8 @@ void *Arena::Acalloc( size_t items, size_t x ) { } //------------------------------realloc---------------------------------------- -// Reallocate storage in Arena. -void *Arena::Arealloc( void *old_ptr, size_t old_size, size_t new_size ) { +// Reallocate storage in AdlArena. +void *AdlArena::Arealloc( void *old_ptr, size_t old_size, size_t new_size ) { char *c_old = (char*)old_ptr; // Handy name // Stupid fast special case if( new_size <= old_size ) { // Shrink in-place @@ -161,32 +161,32 @@ void *Arena::Arealloc( void *old_ptr, size_t old_size, size_t new_size ) { } //------------------------------reset------------------------------------------ -// Reset this Arena to empty, and return this Arenas guts in a new Arena. -Arena *Arena::reset(void) { - Arena *a = new Arena(this); // New empty arena +// Reset this AdlArena to empty, and return this AdlArenas guts in a new AdlArena. +AdlArena *AdlArena::reset(void) { + AdlArena *a = new AdlArena(this); // New empty arena _first = _chunk = NULL; // Normal, new-arena initialization _hwm = _max = NULL; - return a; // Return Arena with guts + return a; // Return AdlArena with guts } //------------------------------contains--------------------------------------- -// Determine if pointer belongs to this Arena or not. -bool Arena::contains( const void *ptr ) const { +// Determine if pointer belongs to this AdlArena or not. +bool AdlArena::contains( const void *ptr ) const { if( (void*)_chunk->bottom() <= ptr && ptr < (void*)_hwm ) return true; // Check for in this chunk - for( Chunk *c = _first; c; c = c->_next ) + for( AdlChunk *c = _first; c; c = c->_next ) if( (void*)c->bottom() <= ptr && ptr < (void*)c->top()) - return true; // Check for every chunk in Arena - return false; // Not in any Chunk, so not in Arena + return true; // Check for every chunk in AdlArena + return false; // Not in any AdlChunk, so not in AdlArena } //----------------------------------------------------------------------------- // CHeapObj -void* CHeapObj::operator new(size_t size) throw() { - return (void *) AllocateHeap(size); +void* AdlCHeapObj::operator new(size_t size) throw() { + return (void *) AdlAllocateHeap(size); } -void CHeapObj::operator delete(void* p){ +void AdlCHeapObj::operator delete(void* p){ free(p); } diff --git a/src/hotspot/share/adlc/arena.hpp b/src/hotspot/share/adlc/adlArena.hpp similarity index 73% rename from src/hotspot/share/adlc/arena.hpp rename to src/hotspot/share/adlc/adlArena.hpp index 1fa99ed0e24..254f414f707 100644 --- a/src/hotspot/share/adlc/arena.hpp +++ b/src/hotspot/share/adlc/adlArena.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,11 +22,11 @@ * */ -#ifndef SHARE_ADLC_ARENA_HPP -#define SHARE_ADLC_ARENA_HPP +#ifndef SHARE_ADLC_ADLARENA_HPP +#define SHARE_ADLC_ADLARENA_HPP -void* AllocateHeap(size_t size); -void* ReAllocateHeap(void* old_ptr, size_t size); +void* AdlAllocateHeap(size_t size); +void* AdlReAllocateHeap(void* old_ptr, size_t size); // All classes in adlc may be derived // from one of the following allocation classes: @@ -35,10 +35,10 @@ void* ReAllocateHeap(void* old_ptr, size_t size); // - CHeapObj // // For classes used as name spaces. -// - AllStatic +// - AdlAllStatic // -class CHeapObj { +class AdlCHeapObj { public: void* operator new(size_t size) throw(); void operator delete(void* p); @@ -47,16 +47,16 @@ class CHeapObj { // Base class for classes that constitute name spaces. -class AllStatic { +class AdlAllStatic { public: void* operator new(size_t size) throw(); void operator delete(void* p); }; -//------------------------------Chunk------------------------------------------ +//------------------------------AdlChunk------------------------------------------ // Linked list of raw memory chunks -class Chunk: public CHeapObj { +class AdlChunk: public AdlCHeapObj { private: // This ordinary operator delete is needed even though not used, so the // below two-argument operator delete will be treated as a placement @@ -65,41 +65,41 @@ class Chunk: public CHeapObj { public: void* operator new(size_t size, size_t length) throw(); void operator delete(void* p, size_t length); - Chunk(size_t length); + AdlChunk(size_t length); enum { init_size = 1*1024, // Size of first chunk - size = 32*1024 // Default size of an Arena chunk (following the first) + size = 32*1024 // Default size of an AdlArena chunk (following the first) }; - Chunk* _next; // Next Chunk in list - size_t _len; // Size of this Chunk + AdlChunk* _next; // Next AdlChunk in list + size_t _len; // Size of this AdlChunk void chop(); // Chop this chunk void next_chop(); // Chop next chunk // Boundaries of data area (possibly unused) - char* bottom() const { return ((char*) this) + sizeof(Chunk); } + char* bottom() const { return ((char*) this) + sizeof(AdlChunk); } char* top() const { return bottom() + _len; } }; -//------------------------------Arena------------------------------------------ +//------------------------------AdlArena------------------------------------------ // Fast allocation of memory -class Arena: public CHeapObj { +class AdlArena: public AdlCHeapObj { protected: friend class ResourceMark; friend class HandleMark; friend class NoHandleMark; - Chunk *_first; // First chunk - Chunk *_chunk; // current chunk + AdlChunk *_first; // First chunk + AdlChunk *_chunk; // current chunk char *_hwm, *_max; // High water mark and max in current chunk - void* grow(size_t x); // Get a new Chunk of at least size x + void* grow(size_t x); // Get a new AdlChunk of at least size x size_t _size_in_bytes; // Size of arena (used for memory usage tracing) public: - Arena(); - Arena(size_t init_size); - Arena(Arena *old); - ~Arena() { _first->chop(); } + AdlArena(); + AdlArena(size_t init_size); + AdlArena(AdlArena *old); + ~AdlArena() { _first->chop(); } char* hwm() const { return _hwm; } // Fast allocate in the arena. Common case is: pointer test + increment. @@ -137,10 +137,10 @@ public: void *Acalloc( size_t items, size_t x ); void *Arealloc( void *old_ptr, size_t old_size, size_t new_size ); - // Reset this Arena to empty, and return this Arenas guts in a new Arena. - Arena *reset(void); + // Reset this AdlArena to empty, and return this AdlArenas guts in a new AdlArena. + AdlArena *reset(void); - // Determine if pointer belongs to this Arena or not. + // Determine if pointer belongs to this AdlArena or not. bool contains( const void *ptr ) const; // Total of all chunks in use (not thread-safe) @@ -151,4 +151,4 @@ public: void set_size_in_bytes(size_t size) { _size_in_bytes = size; } }; -#endif // SHARE_ADLC_ARENA_HPP +#endif // SHARE_ADLC_ADLARENA_HPP diff --git a/src/hotspot/share/adlc/adlc.hpp b/src/hotspot/share/adlc/adlc.hpp index 297d5cb0133..19567f05d40 100644 --- a/src/hotspot/share/adlc/adlc.hpp +++ b/src/hotspot/share/adlc/adlc.hpp @@ -93,7 +93,7 @@ typedef unsigned int uintptr_t; #define max(a, b) (((a)>(b)) ? (a) : (b)) // ADLC components -#include "arena.hpp" +#include "adlArena.hpp" #include "opto/adlcVMDeps.hpp" #include "filebuff.hpp" #include "dict2.hpp" diff --git a/src/hotspot/share/adlc/adlparse.cpp b/src/hotspot/share/adlc/adlparse.cpp index ecb722c56b2..283713bb1f8 100644 --- a/src/hotspot/share/adlc/adlparse.cpp +++ b/src/hotspot/share/adlc/adlparse.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -211,7 +211,7 @@ void ADLParser::instr_parse(void) { return; } assert(match_rules_cnt < 100," too many match rule clones"); - char* buf = (char*) AllocateHeap(strlen(instr->_ident) + 4); + char* buf = (char*) AdlAllocateHeap(strlen(instr->_ident) + 4); sprintf(buf, "%s_%d", instr->_ident, match_rules_cnt++); rule->_result = buf; // Check for commutative operations with tree operands. @@ -2805,7 +2805,7 @@ void ADLParser::ins_encode_parse_block(InstructForm& inst) { // Create a new encoding name based on the name of the instruction // definition, which should be unique. const char* prefix = "__ins_encode_"; - char* ec_name = (char*) AllocateHeap(strlen(inst._ident) + strlen(prefix) + 1); + char* ec_name = (char*) AdlAllocateHeap(strlen(inst._ident) + strlen(prefix) + 1); sprintf(ec_name, "%s%s", prefix, inst._ident); assert(_AD._encode->encClass(ec_name) == NULL, "shouldn't already exist"); @@ -3276,7 +3276,7 @@ void ADLParser::constant_parse(InstructForm& inst) { // Create a new encoding name based on the name of the instruction // definition, which should be unique. const char* prefix = "__constant_"; - char* ec_name = (char*) AllocateHeap(strlen(inst._ident) + strlen(prefix) + 1); + char* ec_name = (char*) AdlAllocateHeap(strlen(inst._ident) + strlen(prefix) + 1); sprintf(ec_name, "%s%s", prefix, inst._ident); assert(_AD._encode->encClass(ec_name) == NULL, "shouldn't already exist"); @@ -4409,7 +4409,7 @@ char* ADLParser::find_cpp_block(const char* description) { if (_AD._adlocation_debug) { char* location = get_line_string(line); char* end_loc = end_line_marker(); - char* result = (char *)AllocateHeap(strlen(location) + strlen(cppBlock) + strlen(end_loc) + 1); + char* result = (char *)AdlAllocateHeap(strlen(location) + strlen(cppBlock) + strlen(end_loc) + 1); strcpy(result, location); strcat(result, cppBlock); strcat(result, end_loc); @@ -4498,7 +4498,7 @@ char *ADLParser::get_paren_expr(const char *description, bool include_location) // Prepend location descriptor, for debugging. char* location = get_line_string(line); char* end_loc = end_line_marker(); - char* result = (char *)AllocateHeap(strlen(location) + strlen(token2) + strlen(end_loc) + 1); + char* result = (char *)AdlAllocateHeap(strlen(location) + strlen(token2) + strlen(end_loc) + 1); strcpy(result, location); strcat(result, token2); strcat(result, end_loc); @@ -4596,7 +4596,7 @@ char *ADLParser::get_ident_or_literal_constant(const char* description) { // Grab a constant expression. param = get_paren_expr(description); if (param[0] != '(') { - char* buf = (char*) AllocateHeap(strlen(param) + 3); + char* buf = (char*) AdlAllocateHeap(strlen(param) + 3); sprintf(buf, "(%s)", param); param = buf; } @@ -5204,7 +5204,7 @@ void ADLParser::next_line() { char* ADLParser::get_line_string(int linenum) { const char* file = _AD._ADL_file._name; int line = linenum ? linenum : this->linenum(); - char* location = (char *)AllocateHeap(strlen(file) + 100); + char* location = (char *)AdlAllocateHeap(strlen(file) + 100); sprintf(location, "\n#line %d \"%s\"\n", line, file); return location; } diff --git a/src/hotspot/share/adlc/dfa.cpp b/src/hotspot/share/adlc/dfa.cpp index b1556ab5f5e..5abc4365297 100644 --- a/src/hotspot/share/adlc/dfa.cpp +++ b/src/hotspot/share/adlc/dfa.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -72,7 +72,7 @@ private: public: // cmpstr does string comparisions. hashstr computes a key. - ProductionState(Arena *arena) : _production(cmpstr, hashstr, arena) { initialize(); }; + ProductionState(AdlArena *arena) : _production(cmpstr, hashstr, arena) { initialize(); }; ~ProductionState() { }; void initialize(); // reset local and dictionary state @@ -817,7 +817,7 @@ bool Expr::check_buffers() { //------------------------------ExprDict--------------------------------------- // Constructor -ExprDict::ExprDict( CmpKey cmp, Hash hash, Arena *arena ) +ExprDict::ExprDict( CmpKey cmp, Hash hash, AdlArena *arena ) : _expr(cmp, hash, arena), _defines() { } ExprDict::~ExprDict() { diff --git a/src/hotspot/share/adlc/dict2.cpp b/src/hotspot/share/adlc/dict2.cpp index 4f3e33dd626..9fd22572855 100644 --- a/src/hotspot/share/adlc/dict2.cpp +++ b/src/hotspot/share/adlc/dict2.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,7 +56,7 @@ Dict::Dict(CmpKey initcmp, Hash inithash) : _hash(inithash), _cmp(initcmp), _are init(); } -Dict::Dict(CmpKey initcmp, Hash inithash, Arena *arena) : _hash(inithash), _cmp(initcmp), _arena(arena) { +Dict::Dict(CmpKey initcmp, Hash inithash, AdlArena *arena) : _hash(inithash), _cmp(initcmp), _arena(arena) { init(); } diff --git a/src/hotspot/share/adlc/dict2.hpp b/src/hotspot/share/adlc/dict2.hpp index a9790088dfb..c6b7da3368a 100644 --- a/src/hotspot/share/adlc/dict2.hpp +++ b/src/hotspot/share/adlc/dict2.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,7 @@ typedef void (*FuncDict)(const void *key, const void *val, Dict *d); class Dict { // Dictionary structure private: - class Arena *_arena; // Where to draw storage from + class AdlArena *_arena; // Where to draw storage from class bucket *_bin; // Hash table is array of buckets int _size; // Size (# of slots) in hash table int _cnt; // Number of key-value pairs in hash table @@ -56,7 +56,7 @@ class Dict { // Dictionary structure // cmp is a key comparision routine. hash is a routine to hash a key. Dict( CmpKey cmp, Hash hash ); - Dict( CmpKey cmp, Hash hash, Arena *arena ); + Dict( CmpKey cmp, Hash hash, AdlArena *arena ); void init(); ~Dict(); diff --git a/src/hotspot/share/adlc/forms.cpp b/src/hotspot/share/adlc/forms.cpp index 3a246285b3a..9580d81484d 100644 --- a/src/hotspot/share/adlc/forms.cpp +++ b/src/hotspot/share/adlc/forms.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,9 +27,9 @@ //------------------------------Static Initializers---------------------------- // allocate arena used by forms -Arena *Form::arena = Form::generate_arena(); // = Form::generate_arena(); -Arena *Form::generate_arena() { - return (new Arena); +AdlArena *Form::arena = Form::generate_arena(); // = Form::generate_arena(); +AdlArena *Form::generate_arena() { + return (new AdlArena); } //------------------------------NameList--------------------------------------- @@ -40,7 +40,7 @@ const char *NameList::_signal3 = "$$SIGNAL3$$"; // Constructor and Destructor NameList::NameList() : _cur(0), _max(4), _iter(0), _justReset(true) { - _names = (const char**) AllocateHeap(_max*sizeof(char*)); + _names = (const char**) AdlAllocateHeap(_max*sizeof(char*)); } NameList::~NameList() { // The following free is a double-free, and crashes the program: @@ -49,7 +49,7 @@ NameList::~NameList() { void NameList::addName(const char *name) { if (_cur == _max) { - _names = (const char**) ReAllocateHeap(_names, (_max *=2)*sizeof(char*)); + _names = (const char**) AdlReAllocateHeap(_names, (_max *=2)*sizeof(char*)); } _names[_cur++] = name; } @@ -312,7 +312,7 @@ FormList::~FormList() { //------------------------------FormDict--------------------------------------- // Constructor -FormDict::FormDict( CmpKey cmp, Hash hash, Arena *arena ) +FormDict::FormDict( CmpKey cmp, Hash hash, AdlArena *arena ) : _form(cmp, hash, arena) { } FormDict::~FormDict() { diff --git a/src/hotspot/share/adlc/forms.hpp b/src/hotspot/share/adlc/forms.hpp index b4e115229c3..6586ea88311 100644 --- a/src/hotspot/share/adlc/forms.hpp +++ b/src/hotspot/share/adlc/forms.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -97,7 +97,7 @@ private: public: // cmp is a key comparision routine. hash is a routine to hash a key. // FormDict( CmpKey cmp, Hash hash ); - FormDict( CmpKey cmp, Hash hash, Arena *arena ); + FormDict( CmpKey cmp, Hash hash, AdlArena *arena ); FormDict( const FormDict & fd ); // Deep-copy guts ~FormDict(); @@ -119,9 +119,9 @@ public: //------------------------------Form------------------------------------------- class Form { public: - static Arena *arena; // arena used by forms + static AdlArena *arena; // arena used by forms private: - static Arena *generate_arena(); // allocate arena used by forms + static AdlArena *generate_arena(); // allocate arena used by forms protected: int _ftype; // Indicator for derived class type @@ -573,7 +573,7 @@ private: public: // cmp is a key comparision routine. hash is a routine to hash a key. - ExprDict( CmpKey cmp, Hash hash, Arena *arena ); + ExprDict( CmpKey cmp, Hash hash, AdlArena *arena ); ~ExprDict(); // Return # of key-value pairs in dict diff --git a/src/hotspot/share/adlc/formsopt.cpp b/src/hotspot/share/adlc/formsopt.cpp index 351904bbb29..6f1a5997511 100644 --- a/src/hotspot/share/adlc/formsopt.cpp +++ b/src/hotspot/share/adlc/formsopt.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -206,7 +206,7 @@ RegDef::RegDef(char *regname, char *callconv, char *c_conv, char * idealtype, ch _concrete(concrete), _register_num(0) { - // Chunk and register mask are determined by the register number + // AdlChunk and register mask are determined by the register number // _register_num is set when registers are added to an allocation class } RegDef::~RegDef() { // Destructor diff --git a/src/hotspot/share/adlc/formssel.cpp b/src/hotspot/share/adlc/formssel.cpp index f7ff8ccf40b..67c49459db9 100644 --- a/src/hotspot/share/adlc/formssel.cpp +++ b/src/hotspot/share/adlc/formssel.cpp @@ -1366,7 +1366,7 @@ void InstructForm::set_unique_opnds() { // component back to an index and any DEF always goes at 0 so the // length of the array has to be the number of components + 1. _uniq_idx_length = _components.count() + 1; - uniq_idx = (uint*) AllocateHeap(sizeof(uint) * _uniq_idx_length); + uniq_idx = (uint*) AdlAllocateHeap(sizeof(uint) * _uniq_idx_length); for (i = 0; i < _uniq_idx_length; i++) { uniq_idx[i] = i; } @@ -3476,7 +3476,7 @@ void MatchNode::build_internalop( ) { rstr = (_rChild) ? ((_rChild->_internalop) ? _rChild->_internalop : _rChild->_opType) : ""; len += (int)strlen(lstr) + (int)strlen(rstr); - subtree = (char *)AllocateHeap(len); + subtree = (char *)AdlAllocateHeap(len); sprintf(subtree,"_%s_%s_%s", _opType, lstr, rstr); // Hash the subtree string in _internalOps; if a name exists, use it iop = (char *)_AD._internalOps[subtree]; @@ -3926,7 +3926,7 @@ void MatchRule::matchrule_swap_commutative_op(const char* instr_ident, int count MatchRule* clone = new MatchRule(_AD, this); // Swap operands of commutative operation ((MatchNode*)clone)->swap_commutative_op(true, count); - char* buf = (char*) AllocateHeap(strlen(instr_ident) + 4); + char* buf = (char*) AdlAllocateHeap(strlen(instr_ident) + 4); sprintf(buf, "%s_%d", instr_ident, match_rules_cnt++); clone->_result = buf; -- GitLab From 65831eb294b6f1f5f99988836c00005d41c27fd3 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Fri, 11 Feb 2022 06:45:13 +0000 Subject: [PATCH 031/203] 8281318: Improve jfr/event/allocation tests reliability Reviewed-by: mgronlun --- .../TestObjectAllocationInNewTLABEvent.java | 30 +++++++++++++------ .../TestObjectAllocationOutsideTLABEvent.java | 28 ++++++++++++----- ...ObjectAllocationSampleEventThrottling.java | 17 ++++++++--- 3 files changed, 54 insertions(+), 21 deletions(-) diff --git a/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationInNewTLABEvent.java b/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationInNewTLABEvent.java index d4078a65ecd..cb70c0ba324 100644 --- a/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationInNewTLABEvent.java +++ b/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationInNewTLABEvent.java @@ -30,6 +30,8 @@ import jdk.jfr.consumer.RecordedEvent; import jdk.test.lib.jfr.EventNames; import jdk.test.lib.jfr.Events; import jdk.test.lib.Asserts; +import jdk.test.lib.Platform; +import sun.hotspot.WhiteBox; /** * @test @@ -37,8 +39,16 @@ import jdk.test.lib.Asserts; * @key jfr * @requires vm.hasJFR * @library /test/lib - * @run main/othervm -XX:+UseTLAB -XX:TLABSize=100k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=1 jdk.jfr.event.allocation.TestObjectAllocationInNewTLABEvent - * @run main/othervm -XX:+UseTLAB -XX:TLABSize=100k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=1 -Xint jdk.jfr.event.allocation.TestObjectAllocationInNewTLABEvent + * @build sun.hotspot.WhiteBox + * + * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:+UseTLAB -XX:TLABSize=100k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=1 + * jdk.jfr.event.allocation.TestObjectAllocationInNewTLABEvent + * @run main/othervm -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:+UseTLAB -XX:TLABSize=100k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=1 + * -Xint + * jdk.jfr.event.allocation.TestObjectAllocationInNewTLABEvent */ /** @@ -46,17 +56,19 @@ import jdk.test.lib.Asserts; * an event will be triggered. The test is done for default and interpreted mode (-Xint). * * To force objects to be allocated in a new TLAB: - * the size of TLAB is set to 100k (-XX:TLABSize=100k); - * the size of allocated objects is set to 100k minus 16 bytes overhead; + * the initial size of TLAB is set to 100k (-XX:TLABSize=100k); + * the size of allocated objects is set to 128k; * max TLAB waste at refill is set to minimum (-XX:TLABRefillWasteFraction=1), * to provoke a new TLAB creation. */ public class TestObjectAllocationInNewTLABEvent { private final static String EVENT_NAME = EventNames.ObjectAllocationInNewTLAB; - private static final int BYTE_ARRAY_OVERHEAD = 16; // Extra bytes used by a byte array. - private static final int OBJECT_SIZE = 100 * 1024; - private static final int OBJECT_SIZE_ALT = OBJECT_SIZE + 8; // Object size in case of disabled CompressedOops. + private static final Boolean COMPRESSED_CLASS_PTRS = WhiteBox.getWhiteBox().getBooleanVMFlag("UseCompressedClassPointers"); + + private static final int BYTE_ARRAY_OVERHEAD = (Platform.is64bit() && !COMPRESSED_CLASS_PTRS) ? 24 : 16; + private static final int OBJECT_SIZE = 128 * 1024; + private static final int OBJECTS_TO_ALLOCATE = 100; private static final String BYTE_ARRAY_CLASS_NAME = new byte[0].getClass().getName(); private static final int INITIAL_TLAB_SIZE = 100 * 1024; @@ -112,9 +124,9 @@ public class TestObjectAllocationInNewTLABEvent { long allocationSize = Events.assertField(event, "allocationSize").atLeast(1L).getValue(); long tlabSize = Events.assertField(event, "tlabSize").atLeast(allocationSize).getValue(); String className = Events.assertField(event, "objectClass.name").notEmpty().getValue(); - if (className.equals(BYTE_ARRAY_CLASS_NAME) && (allocationSize == OBJECT_SIZE || allocationSize == OBJECT_SIZE_ALT)) { + if (className.equals(BYTE_ARRAY_CLASS_NAME) && (allocationSize == OBJECT_SIZE)) { countAllTlabs++; - if (tlabSize == INITIAL_TLAB_SIZE + OBJECT_SIZE || tlabSize == INITIAL_TLAB_SIZE + OBJECT_SIZE_ALT) { + if (tlabSize == INITIAL_TLAB_SIZE + OBJECT_SIZE) { countFullTlabs++; } } diff --git a/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationOutsideTLABEvent.java b/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationOutsideTLABEvent.java index 466a0062ac9..70bf4518f08 100644 --- a/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationOutsideTLABEvent.java +++ b/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationOutsideTLABEvent.java @@ -30,6 +30,8 @@ import jdk.jfr.consumer.RecordedEvent; import jdk.test.lib.jfr.EventNames; import jdk.test.lib.jfr.Events; import jdk.test.lib.Asserts; +import jdk.test.lib.Platform; +import sun.hotspot.WhiteBox; /** * @test @@ -37,8 +39,16 @@ import jdk.test.lib.Asserts; * @key jfr * @requires vm.hasJFR * @library /test/lib - * @run main/othervm -XX:+UseTLAB -XX:TLABSize=90k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=256 jdk.jfr.event.allocation.TestObjectAllocationOutsideTLABEvent - * @run main/othervm -XX:+UseTLAB -XX:TLABSize=90k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=256 -Xint jdk.jfr.event.allocation.TestObjectAllocationOutsideTLABEvent + * @build sun.hotspot.WhiteBox + * + * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:+UseTLAB -XX:TLABSize=90k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=256 + * jdk.jfr.event.allocation.TestObjectAllocationOutsideTLABEvent + * @run main/othervm -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:+UseTLAB -XX:TLABSize=90k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=256 + * -Xint + * jdk.jfr.event.allocation.TestObjectAllocationOutsideTLABEvent */ /** @@ -46,17 +56,19 @@ import jdk.test.lib.Asserts; * Thread Local Allocation Buffer (TLAB). The test is done for default interpreted mode (-Xint). * * To force objects to be allocated outside TLAB: - * the size of TLAB is set to 90k (-XX:TLABSize=90k); - * the size of allocated objects is set to 100k. + * the initial size of TLAB is set to 90k (-XX:TLABSize=90k); + * the size of allocated objects is set to 128k; * max TLAB waste at refill is set to 256 (-XX:TLABRefillWasteFraction=256), * to prevent a new TLAB creation. */ public class TestObjectAllocationOutsideTLABEvent { private static final String EVENT_NAME = EventNames.ObjectAllocationOutsideTLAB; - private static final int BYTE_ARRAY_OVERHEAD = 16; // Extra bytes used by a byte array - private static final int OBJECT_SIZE = 100 * 1024; - private static final int OBJECT_SIZE_ALT = OBJECT_SIZE + 8; // Object size in case of disabled CompressedOops + private static final Boolean COMPRESSED_CLASS_PTRS = WhiteBox.getWhiteBox().getBooleanVMFlag("UseCompressedClassPointers"); + + private static final int BYTE_ARRAY_OVERHEAD = (Platform.is64bit() && !COMPRESSED_CLASS_PTRS) ? 24 : 16; + private static final int OBJECT_SIZE = 128 * 1024; + private static final int OBJECTS_TO_ALLOCATE = 100; private static final String BYTE_ARRAY_CLASS_NAME = new byte[0].getClass().getName(); private static int eventCount; @@ -94,7 +106,7 @@ public class TestObjectAllocationOutsideTLABEvent { } long allocationSize = Events.assertField(event, "allocationSize").atLeast(1L).getValue(); String className = Events.assertField(event, "objectClass.name").notEmpty().getValue(); - if (className.equals(BYTE_ARRAY_CLASS_NAME) && (allocationSize == OBJECT_SIZE || allocationSize == OBJECT_SIZE_ALT)) { + if (className.equals(BYTE_ARRAY_CLASS_NAME) && (allocationSize == OBJECT_SIZE)) { ++eventCount; } } diff --git a/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationSampleEventThrottling.java b/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationSampleEventThrottling.java index 22d03ce57ba..a10b6e2b56a 100644 --- a/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationSampleEventThrottling.java +++ b/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationSampleEventThrottling.java @@ -32,6 +32,8 @@ import jdk.jfr.consumer.RecordedEvent; import jdk.test.lib.jfr.EventNames; import jdk.test.lib.jfr.Events; import jdk.test.lib.Asserts; +import jdk.test.lib.Platform; +import sun.hotspot.WhiteBox; /** * @test @@ -39,15 +41,22 @@ import jdk.test.lib.Asserts; * @key jfr * @requires vm.hasJFR * @library /test/lib -* @run main/othervm -XX:+UseTLAB -XX:TLABSize=2k -XX:-ResizeTLAB jdk.jfr.event.allocation.TestObjectAllocationSampleEventThrottling + * @build sun.hotspot.WhiteBox + * + * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:+UseTLAB -XX:TLABSize=2k -XX:-ResizeTLAB + * jdk.jfr.event.allocation.TestObjectAllocationSampleEventThrottling */ public class TestObjectAllocationSampleEventThrottling { private static final String EVENT_NAME = EventNames.ObjectAllocationSample; - private static final int BYTE_ARRAY_OVERHEAD = 16; // Extra bytes used by a byte array - private static final int OBJECT_SIZE = 100 * 1024; - private static final int OBJECT_SIZE_ALT = OBJECT_SIZE + 8; // Object size in case of disabled CompressedOops + private static final Boolean COMPRESSED_CLASS_PTRS = WhiteBox.getWhiteBox().getBooleanVMFlag("UseCompressedClassPointers"); + + private static final int BYTE_ARRAY_OVERHEAD = (Platform.is64bit() && !COMPRESSED_CLASS_PTRS) ? 24 : 16; + private static final int OBJECT_SIZE = 128 * 1024; + private static final int OBJECTS_TO_ALLOCATE = 100; private static final String BYTE_ARRAY_CLASS_NAME = new byte[0].getClass().getName(); private static int eventCount; -- GitLab From a037b3c35831f029d23a88bdd49e7f2c2d951631 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Fri, 11 Feb 2022 07:21:04 +0000 Subject: [PATCH 032/203] 8281460: Let ObjectMonitor have its own NMT category Reviewed-by: dholmes, dcubed, shade --- src/hotspot/share/memory/allocation.hpp | 1 + src/hotspot/share/runtime/objectMonitor.hpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/memory/allocation.hpp b/src/hotspot/share/memory/allocation.hpp index 8503942f21f..ec7f78b9fa4 100644 --- a/src/hotspot/share/memory/allocation.hpp +++ b/src/hotspot/share/memory/allocation.hpp @@ -146,6 +146,7 @@ class AllocatedObj { f(mtServiceability, "Serviceability") \ f(mtMetaspace, "Metaspace") \ f(mtStringDedup, "String Deduplication") \ + f(mtObjectMonitor, "Object Monitors") \ f(mtNone, "Unknown") \ //end diff --git a/src/hotspot/share/runtime/objectMonitor.hpp b/src/hotspot/share/runtime/objectMonitor.hpp index 4ca4cc28c86..889a844fa50 100644 --- a/src/hotspot/share/runtime/objectMonitor.hpp +++ b/src/hotspot/share/runtime/objectMonitor.hpp @@ -127,7 +127,7 @@ class ObjectWaiter : public StackObj { #define OM_CACHE_LINE_SIZE DEFAULT_CACHE_LINE_SIZE #endif -class ObjectMonitor : public CHeapObj { +class ObjectMonitor : public CHeapObj { friend class ObjectSynchronizer; friend class ObjectWaiter; friend class VMStructs; -- GitLab From 8441d51e71e143250b44eea74114a624cf00cc3e Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Fri, 11 Feb 2022 07:41:18 +0000 Subject: [PATCH 033/203] 8281419: The source data for the color conversion can be discarded Reviewed-by: prr, aivanov --- src/java.desktop/share/native/liblcms/LCMS.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/java.desktop/share/native/liblcms/LCMS.c b/src/java.desktop/share/native/liblcms/LCMS.c index 4bbd6e100c3..27c23c6d92f 100644 --- a/src/java.desktop/share/native/liblcms/LCMS.c +++ b/src/java.desktop/share/native/liblcms/LCMS.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -496,19 +496,20 @@ static void *getILData(JNIEnv *env, jobject data, jint type) { } } -static void releaseILData(JNIEnv *env, void *pData, jint type, jobject data) { +static void releaseILData(JNIEnv *env, void *pData, jint type, jobject data, + jint mode) { switch (type) { case DT_BYTE: - (*env)->ReleaseByteArrayElements(env, data, (jbyte *) pData, 0); + (*env)->ReleaseByteArrayElements(env, data, (jbyte *) pData, mode); break; case DT_SHORT: - (*env)->ReleaseShortArrayElements(env, data, (jshort *) pData, 0); + (*env)->ReleaseShortArrayElements(env, data, (jshort *) pData, mode); break; case DT_INT: - (*env)->ReleaseIntArrayElements(env, data, (jint *) pData, 0); + (*env)->ReleaseIntArrayElements(env, data, (jint *) pData, mode); break; case DT_DOUBLE: - (*env)->ReleaseDoubleArrayElements(env, data, (jdouble *) pData, 0); + (*env)->ReleaseDoubleArrayElements(env, data, (jdouble *) pData, mode); break; } } @@ -542,7 +543,7 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_colorConvert void *outputBuffer = getILData(env, dstData, dstDType); if (outputBuffer == NULL) { - releaseILData(env, inputBuffer, srcDType, srcData); + releaseILData(env, inputBuffer, srcDType, srcData, JNI_ABORT); // An exception should have already been thrown. return; } @@ -560,8 +561,8 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_colorConvert } } - releaseILData(env, inputBuffer, srcDType, srcData); - releaseILData(env, outputBuffer, dstDType, dstData); + releaseILData(env, inputBuffer, srcDType, srcData, JNI_ABORT); + releaseILData(env, outputBuffer, dstDType, dstData, 0); } /* -- GitLab From 3a13425bc9088cbb6d95e1a46248d7eba27fb1a6 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Fri, 11 Feb 2022 08:46:55 +0000 Subject: [PATCH 034/203] 8072070: Improve interpreter stack banging Reviewed-by: xliu, coleenp, mdoerr --- .../x86/templateInterpreterGenerator_x86.cpp | 56 ++++++-- src/hotspot/share/runtime/javaCalls.cpp | 4 +- src/hotspot/share/runtime/os.cpp | 6 +- src/hotspot/share/runtime/stackOverflow.hpp | 123 +++++++++++++++++- src/hotspot/share/runtime/thread.hpp | 6 + 5 files changed, 173 insertions(+), 22 deletions(-) diff --git a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp index a4e86ff4202..cc365f70426 100644 --- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -713,23 +713,59 @@ address TemplateInterpreterGenerator::generate_Reference_get_entry(void) { } void TemplateInterpreterGenerator::bang_stack_shadow_pages(bool native_call) { - // Quick & dirty stack overflow checking: bang the stack & handle trap. + // See more discussion in stackOverflow.hpp. + // Note that we do the banging after the frame is setup, since the exception // handling code expects to find a valid interpreter frame on the stack. // Doing the banging earlier fails if the caller frame is not an interpreter // frame. // (Also, the exception throwing code expects to unlock any synchronized - // method receiever, so do the banging after locking the receiver.) + // method receiver, so do the banging after locking the receiver.) - // Bang each page in the shadow zone. We can't assume it's been done for - // an interpreter frame with greater than a page of locals, so each page - // needs to be checked. Only true for non-native. + const int shadow_zone_size = checked_cast(StackOverflow::stack_shadow_zone_size()); const int page_size = os::vm_page_size(); - const int n_shadow_pages = ((int)StackOverflow::stack_shadow_zone_size()) / page_size; - const int start_page = native_call ? n_shadow_pages : 1; - for (int pages = start_page; pages <= n_shadow_pages; pages++) { - __ bang_stack_with_offset(pages*page_size); + const int n_shadow_pages = shadow_zone_size / page_size; + + const Register thread = NOT_LP64(rsi) LP64_ONLY(r15_thread); +#ifndef _LP64 + __ push(thread); + __ get_thread(thread); +#endif + +#ifdef ASSERT + Label L_good_limit; + __ cmpptr(Address(thread, JavaThread::shadow_zone_safe_limit()), (int32_t)NULL_WORD); + __ jcc(Assembler::notEqual, L_good_limit); + __ stop("shadow zone safe limit is not initialized"); + __ bind(L_good_limit); + + Label L_good_watermark; + __ cmpptr(Address(thread, JavaThread::shadow_zone_growth_watermark()), (int32_t)NULL_WORD); + __ jcc(Assembler::notEqual, L_good_watermark); + __ stop("shadow zone growth watermark is not initialized"); + __ bind(L_good_watermark); +#endif + + Label L_done; + + __ cmpptr(rsp, Address(thread, JavaThread::shadow_zone_growth_watermark())); + __ jcc(Assembler::above, L_done); + + for (int p = 1; p <= n_shadow_pages; p++) { + __ bang_stack_with_offset(p*page_size); } + + // Record a new watermark, unless the update is above the safe limit. + // Otherwise, the next time around a check above would pass the safe limit. + __ cmpptr(rsp, Address(thread, JavaThread::shadow_zone_safe_limit())); + __ jccb(Assembler::belowEqual, L_done); + __ movptr(Address(thread, JavaThread::shadow_zone_growth_watermark()), rsp); + + __ bind(L_done); + +#ifndef _LP64 + __ pop(thread); +#endif } // Interpreter stub for calling a native method. (asm interpreter) diff --git a/src/hotspot/share/runtime/javaCalls.cpp b/src/hotspot/share/runtime/javaCalls.cpp index 5390c5f6eaf..978fd20e0dd 100644 --- a/src/hotspot/share/runtime/javaCalls.cpp +++ b/src/hotspot/share/runtime/javaCalls.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -380,7 +380,7 @@ void JavaCalls::call_helper(JavaValue* result, const methodHandle& method, JavaC // Check that there are shadow pages available before changing thread state // to Java. Calculate current_stack_pointer here to make sure - // stack_shadow_pages_available() and bang_stack_shadow_pages() use the same sp. + // stack_shadow_pages_available() and map_stack_shadow_pages() use the same sp. address sp = os::current_stack_pointer(); if (!os::stack_shadow_pages_available(THREAD, method, sp)) { // Throw stack overflow exception with preinitialized exception. diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index a85be30ec48..f86396beada 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -1384,7 +1384,7 @@ char** os::split_path(const char* path, size_t* elements, size_t file_name_lengt // pages, false otherwise. bool os::stack_shadow_pages_available(Thread *thread, const methodHandle& method, address sp) { if (!thread->is_Java_thread()) return false; - // Check if we have StackShadowPages above the yellow zone. This parameter + // Check if we have StackShadowPages above the guard zone. This parameter // is dependent on the depth of the maximum VM call stack possible from // the handler for stack overflow. 'instanceof' in the stack overflow // handler or a println uses at least 8k stack of VM and native code @@ -1392,9 +1392,7 @@ bool os::stack_shadow_pages_available(Thread *thread, const methodHandle& method const int framesize_in_bytes = Interpreter::size_top_interpreter_activation(method()) * wordSize; - address limit = JavaThread::cast(thread)->stack_end() + - (StackOverflow::stack_guard_zone_size() + StackOverflow::stack_shadow_zone_size()); - + address limit = JavaThread::cast(thread)->stack_overflow_state()->shadow_zone_safe_limit(); return sp > (limit + framesize_in_bytes); } diff --git a/src/hotspot/share/runtime/stackOverflow.hpp b/src/hotspot/share/runtime/stackOverflow.hpp index c8e4249ab25..5a8a88c4fcd 100644 --- a/src/hotspot/share/runtime/stackOverflow.hpp +++ b/src/hotspot/share/runtime/stackOverflow.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,6 +51,8 @@ class StackOverflow { _stack_guard_state(stack_guard_unused), _stack_overflow_limit(nullptr), _reserved_stack_activation(nullptr), // stack base not known yet + _shadow_zone_safe_limit(nullptr), + _shadow_zone_growth_watermark(nullptr), _stack_base(nullptr), _stack_end(nullptr) {} // Initialization after thread is started. @@ -58,6 +60,7 @@ class StackOverflow { _stack_base = base; _stack_end = end; set_stack_overflow_limit(); + set_shadow_zone_limits(); set_reserved_stack_activation(base); } private: @@ -68,6 +71,8 @@ class StackOverflow { // We load it from here to simplify the stack overflow check in assembly. address _stack_overflow_limit; address _reserved_stack_activation; + address _shadow_zone_safe_limit; + address _shadow_zone_growth_watermark; // Support for stack overflow handling, copied down from thread. address _stack_base; @@ -77,6 +82,9 @@ class StackOverflow { address stack_base() const { assert(_stack_base != nullptr, "Sanity check"); return _stack_base; } // Stack overflow support + // -------------------------------------------------------------------------------- + // + // The Java thread stack is structured as follows: // // (low addresses) // @@ -95,11 +103,24 @@ class StackOverflow { // | | // | reserved zone | // | | - // -- <-- stack_reserved_zone_base() --- --- - // /|\ shadow <-- stack_overflow_limit() (somewhere in here) - // | zone - // \|/ size - // some untouched memory --- + // -- <-- stack_reserved_zone_base() --- --- + // ^ + // | <-- stack_overflow_limit() [somewhere in here] + // | shadow + // | zone + // | size + // v + // --- <-- shadow_zone_safe_limit() + // (Here and below: not yet touched stack) + // + // + // (Here and below: touched at least once) --- + // ^ + // | shadow + // | zone + // | size + // v + // --- <-- shadow_zone_growth_watermark() // // // -- @@ -120,6 +141,84 @@ class StackOverflow { // // (high addresses) // + // + // The stack overflow mechanism detects overflows by touching ("banging") the stack + // ahead of current stack pointer (SP). The entirety of guard zone is memory protected, + // therefore such access would trap when touching the guard zone, and one of the following + // things would happen. + // + // Access in the red zone: unrecoverable stack overflow. Crash the VM, generate a report, + // crash dump, and other diagnostics. + // + // Access in the yellow zone: recoverable, reportable stack overflow. Create and throw + // a StackOverflowError, remove the protection of yellow zone temporarily to let exception + // handlers run. If exception handlers themselves run out of stack, they will crash VM due + // to access to red zone. + // + // Access in the reserved zone: recoverable, reportable, transparent for privileged methods + // stack overflow. Perform a stack walk to check if there's a method annotated with + // @ReservedStackAccess on the call stack. If such method is found, remove the protection of + // reserved zone temporarily, and let the method run. If not, handle the access like a yellow + // zone trap. + // + // The banging itself happens within the "shadow zone" that extends from the current SP. + // + // The goals for properly implemented shadow zone banging are: + // + // a) Allow native/VM methods to run without stack overflow checks within some reasonable + // headroom. Default shadow zone size should accommodate the largest normally expected + // native/VM stack use. + // b) Guarantee the stack overflow checks work even if SP is dangerously close to guard zone. + // If SP is very low, banging at the edge of shadow zone (SP+shadow-zone-size) can slip + // into adjacent thread stack, or even into other readable memory. This would potentially + // pass the check by accident. + // c) Allow for incremental stack growth on some OSes. This is enabled by handling traps + // from not yet committed thread stacks, even outside the guard zone. The banging should + // not allow uncommitted "gaps" on thread stack. See for example the uses of + // os::map_stack_shadow_pages(). + // d) Make sure the stack overflow trap happens in the code that is known to runtime, so + // the traps can be reasonably handled: handling a spurious trap from executing Java code + // is hard, while properly handling the trap from VM/native code is nearly impossible. + // + // The simplest code that satisfies all these requirements is banging the shadow zone + // page by page at every Java/native method entry. + // + // While that code is sufficient, it comes with the large performance cost. This performance + // cost can be reduced by several *optional* techniques: + // + // 1. Guarantee that stack would not take another page. If so, the current bang was + // enough to verify we are not near the guard zone. This kind of insight is usually only + // available for compilers that can know the size of the frame exactly. + // + // Examples: PhaseOutput::need_stack_bang. + // + // 2. Check the current SP in relation to shadow zone safe limit. + // + // Define "safe limit" as the highest SP where banging would not touch the guard zone. + // Then, do the page-by-page bang only if current SP is above that safe limit, OR some + // OS-es need it to get the stack mapped. + // + // Examples: AbstractAssembler::generate_stack_overflow_check, JavaCalls::call_helper, + // os::stack_shadow_pages_available, os::map_stack_shadow_pages and their uses. + // + // 3. Check the current SP in relation to the shadow zone growth watermark. + // + // Define "shadow zone growth watermark" as the highest SP where we banged already. + // Invariant: growth watermark is always above the safe limit, which allows testing + // for watermark and safe limit at the same time in the most frequent case. + // + // Easy and overwhelmingly frequent case: SP is above the growth watermark, and + // by extension above the safe limit. In this case, we know that the guard zone is far away + // (safe limit), and that the stack was banged before for stack growth (growth watermark). + // Therefore, we can skip the banging altogether. + // + // Harder cases: SP is below the growth watermark. In might be due to two things: + // we have not banged the stack for growth (below growth watermark only), or we are + // close to guard zone (also below safe limit). Do the full banging. Once done, we + // can adjust the growth watermark, thus recording the bang for stack growth had + // happened. + // + // Examples: TemplateInterpreterGenerator::bang_stack_shadow_pages on x86 and others. private: // These values are derived from flags StackRedPages, StackYellowPages, @@ -189,6 +288,11 @@ class StackOverflow { return _stack_shadow_zone_size; } + address shadow_zone_safe_limit() const { + assert(_shadow_zone_safe_limit != nullptr, "Don't call this before the field is initialized."); + return _shadow_zone_safe_limit; + } + void create_stack_guard_pages(); void remove_stack_guard_pages(); @@ -242,6 +346,13 @@ class StackOverflow { _stack_overflow_limit = stack_end() + MAX2(stack_guard_zone_size(), stack_shadow_zone_size()); } + + void set_shadow_zone_limits() { + _shadow_zone_safe_limit = + stack_end() + stack_guard_zone_size() + stack_shadow_zone_size(); + _shadow_zone_growth_watermark = + stack_base(); + } }; #endif // SHARE_RUNTIME_STACKOVERFLOW_HPP diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index 9ceb17f7af1..151d487355a 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -1299,6 +1299,12 @@ class JavaThread: public Thread { static ByteSize reserved_stack_activation_offset() { return byte_offset_of(JavaThread, _stack_overflow_state._reserved_stack_activation); } + static ByteSize shadow_zone_safe_limit() { + return byte_offset_of(JavaThread, _stack_overflow_state._shadow_zone_safe_limit); + } + static ByteSize shadow_zone_growth_watermark() { + return byte_offset_of(JavaThread, _stack_overflow_state._shadow_zone_growth_watermark); + } static ByteSize suspend_flags_offset() { return byte_offset_of(JavaThread, _suspend_flags); } -- GitLab From 90939cb80193c671cae635b7a4e41bd2e6bcdbd5 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Fri, 11 Feb 2022 09:05:50 +0000 Subject: [PATCH 035/203] 8281626: NonblockingQueue should use nullptr Reviewed-by: shade, dholmes --- .../share/utilities/nonblockingQueue.hpp | 10 +-- .../utilities/nonblockingQueue.inline.hpp | 68 +++++++++---------- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/hotspot/share/utilities/nonblockingQueue.hpp b/src/hotspot/share/utilities/nonblockingQueue.hpp index a271aaa38d8..7ba4c80cfd6 100644 --- a/src/hotspot/share/utilities/nonblockingQueue.hpp +++ b/src/hotspot/share/utilities/nonblockingQueue.hpp @@ -45,7 +45,7 @@ // // A queue may temporarily appear to be empty even though elements have been // added and not removed. For example, after running the following program, -// the value of r may be NULL. +// the value of r may be nullptr. // // thread1: q.push(a); r = q.pop(); // thread2: q.push(b); @@ -105,15 +105,15 @@ public: // Thread-safe attempt to remove and return the first object in the queue. // Returns true if successful. If successful then *node_ptr is the former - // first object, or NULL if the queue was empty. If unsuccessful, because + // first object, or nullptr if the queue was empty. If unsuccessful, because // of contention with a concurrent modification, then returns false with // the value of *node_ptr unspecified. Subject to ABA behavior; callers // must ensure usage is safe. inline bool try_pop(T** node_ptr); - // Thread-safe remove and return the first object in the queue, or NULL if - // the queue was empty. This just iterates on try_pop() until it - // succeeds, returning the (possibly NULL) element obtained from that. + // Thread-safe remove and return the first object in the queue, or nullptr + // if the queue was empty. This just iterates on try_pop() until it + // succeeds, returning the (possibly nullptr) element obtained from that. // Subject to ABA behavior; callers must ensure usage is safe. inline T* pop(); diff --git a/src/hotspot/share/utilities/nonblockingQueue.inline.hpp b/src/hotspot/share/utilities/nonblockingQueue.inline.hpp index 2ecb1663e45..f4e86c6fe65 100644 --- a/src/hotspot/share/utilities/nonblockingQueue.inline.hpp +++ b/src/hotspot/share/utilities/nonblockingQueue.inline.hpp @@ -40,13 +40,13 @@ void NonblockingQueue::set_next(T& node, T* new_next) { } template -NonblockingQueue::NonblockingQueue() : _head(NULL), _tail(NULL) {} +NonblockingQueue::NonblockingQueue() : _head(nullptr), _tail(nullptr) {} #ifdef ASSERT template NonblockingQueue::~NonblockingQueue() { - assert(_head == NULL, "precondition"); - assert(_tail == NULL, "precondition"); + assert(_head == nullptr, "precondition"); + assert(_tail == nullptr, "precondition"); } #endif @@ -61,7 +61,7 @@ T* NonblockingQueue::end_marker() const { template T* NonblockingQueue::first() const { T* head = Atomic::load(&_head); - return head == NULL ? end_marker() : head; + return head == nullptr ? end_marker() : head; } template @@ -71,7 +71,7 @@ bool NonblockingQueue::is_end(const T* entry) const { template bool NonblockingQueue::empty() const { - return Atomic::load(&_head) == NULL; + return Atomic::load(&_head) == nullptr; } template @@ -85,8 +85,8 @@ size_t NonblockingQueue::length() const { // An append operation atomically exchanges the new tail with the queue tail. // It then sets the "next" value of the old tail to the head of the list being -// appended. If the old tail is NULL then the queue was empty, then the head -// of the list being appended is instead stored in the queue head. +// appended. If the old tail is nullptr then the queue was empty, then the +// head of the list being appended is instead stored in the queue head. // // This means there is a period between the exchange and the old tail update // where the queue sequence is split into two parts, the list from the queue @@ -100,17 +100,17 @@ size_t NonblockingQueue::length() const { // is both the head and the tail of the list being appended. template void NonblockingQueue::append(T& first, T& last) { - assert(next(last) == NULL, "precondition"); + assert(next(last) == nullptr, "precondition"); // Make last the new end of the queue. Any further push/appends will // extend after last. We will try to extend from the previous end of // queue. set_next(last, end_marker()); T* old_tail = Atomic::xchg(&_tail, &last); - if (old_tail == NULL) { - // If old_tail is NULL then the queue was empty, and _head must also be - // NULL. The correctness of this assertion depends on try_pop clearing + if (old_tail == nullptr) { + // If old_tail is nullptr then the queue was empty, and _head must also be + // nullptr. The correctness of this assertion depends on try_pop clearing // first _head then _tail when taking the last entry. - assert(Atomic::load(&_head) == NULL, "invariant"); + assert(Atomic::load(&_head) == nullptr, "invariant"); // Fall through to common update of _head. } else if (is_end(Atomic::cmpxchg(next_ptr(*old_tail), end_marker(), &first))) { // Successfully extended the queue list from old_tail to first. No @@ -126,10 +126,10 @@ void NonblockingQueue::append(T& first, T& last) { return; } else { // A concurrent try_pop has claimed old_tail, so it is no longer in the - // list. The queue was logically empty. _head is either NULL or + // list. The queue was logically empty. _head is either nullptr or // old_tail, depending on how far try_pop operations have progressed. DEBUG_ONLY(T* old_head = Atomic::load(&_head);) - assert((old_head == NULL) || (old_head == old_tail), "invariant"); + assert((old_head == nullptr) || (old_head == old_tail), "invariant"); // Fall through to common update of _head. } // The queue was empty, and first should become the new _head. The queue @@ -142,8 +142,8 @@ bool NonblockingQueue::try_pop(T** node_ptr) { // We only need memory_order_consume. Upgrade it to "load_acquire" // as the memory_order_consume API is not ready for use yet. T* old_head = Atomic::load_acquire(&_head); - if (old_head == NULL) { - *node_ptr = NULL; + if (old_head == nullptr) { + *node_ptr = nullptr; return true; // Queue is empty. } @@ -152,7 +152,7 @@ bool NonblockingQueue::try_pop(T** node_ptr) { // [Clause 1] // There are several cases for next_node. // (1) next_node is the extension of the queue's list. - // (2) next_node is NULL, because a competing try_pop took old_head. + // (2) next_node is nullptr, because a competing try_pop took old_head. // (3) next_node is the extension of some unrelated list, because a // competing try_pop took old_head and put it in some other list. // @@ -166,16 +166,16 @@ bool NonblockingQueue::try_pop(T** node_ptr) { // the race and claimed old_head. This can happen for any of the // next_node cases. return false; - } else if (next_node == NULL) { + } else if (next_node == nullptr) { // [Clause 1b] // The cmpxchg to advance the list succeeded, but a concurrent try_pop // has already claimed old_head (see [Clause 2] - old_head was the last // entry in the list) by nulling old_head's next field. The advance set - // _head to NULL, "helping" the competing try_pop. _head will remain - // NULL until a subsequent push/append. This is a lost race, and we + // _head to nullptr, "helping" the competing try_pop. _head will remain + // nullptr until a subsequent push/append. This is a lost race, and we // report it as such for consistency, though we could report the queue // was empty. We don't attempt to further help [Clause 2] by also - // trying to set _tail to NULL, as that would just ensure that one or + // trying to set _tail to nullptr, as that would just ensure that one or // the other cmpxchg is a wasted failure. return false; } else { @@ -183,15 +183,15 @@ bool NonblockingQueue::try_pop(T** node_ptr) { // Successfully advanced the list and claimed old_head. next_node was // in the extension of the queue's list. Return old_head after // unlinking it from next_node. - set_next(*old_head, NULL); + set_next(*old_head, nullptr); *node_ptr = old_head; return true; } - } else if (is_end(Atomic::cmpxchg(next_ptr(*old_head), next_node, (T*)NULL))) { + } else if (is_end(Atomic::cmpxchg(next_ptr(*old_head), next_node, (T*)nullptr))) { // [Clause 2] // Old_head was the last entry and we've claimed it by setting its next - // value to NULL. However, this leaves the queue in disarray. Fix up + // value to nullptr. However, this leaves the queue in disarray. Fix up // the queue, possibly in conjunction with other concurrent operations. // Any further try_pops will consider the queue empty until a // push/append completes by installing a new head. @@ -200,16 +200,16 @@ bool NonblockingQueue::try_pop(T** node_ptr) { // dealing with _head first gives a stronger invariant in append, and is // also consistent with [Clause 1b]. - // Attempt to change the queue head from old_head to NULL. Failure of the - // cmpxchg indicates a concurrent operation updated _head first. That + // Attempt to change the queue head from old_head to nullptr. Failure of + // the cmpxchg indicates a concurrent operation updated _head first. That // could be either a push/append or a try_pop in [Clause 1b]. - Atomic::cmpxchg(&_head, old_head, (T*)NULL); + Atomic::cmpxchg(&_head, old_head, (T*)nullptr); - // Attempt to change the queue tail from old_head to NULL. Failure of the - // cmpxchg indicates that a concurrent push/append updated _tail first. + // Attempt to change the queue tail from old_head to nullptr. Failure of + // the cmpxchg indicates that a concurrent push/append updated _tail first. // That operation will eventually recognize the old tail (our old_head) is // no longer in the list and update _head from the list being appended. - Atomic::cmpxchg(&_tail, old_head, (T*)NULL); + Atomic::cmpxchg(&_tail, old_head, (T*)nullptr); // The queue has been restored to order, and we can return old_head. *node_ptr = old_head; @@ -226,7 +226,7 @@ bool NonblockingQueue::try_pop(T** node_ptr) { template T* NonblockingQueue::pop() { - T* result = NULL; + T* result = nullptr; // Typically try_pop() will succeed without retrying many times, thus we // omit SpinPause in the loop body. SpinPause or yield may be worthwhile // in rare, highly contended cases, and client code could implement such @@ -238,10 +238,10 @@ T* NonblockingQueue::pop() { template Pair NonblockingQueue::take_all() { T* tail = Atomic::load(&_tail); - if (tail != NULL) set_next(*tail, NULL); // Clear end marker. + if (tail != nullptr) set_next(*tail, nullptr); // Clear end marker. Pair result(Atomic::load(&_head), tail); - Atomic::store(&_head, (T*)NULL); - Atomic::store(&_tail, (T*)NULL); + Atomic::store(&_head, (T*)nullptr); + Atomic::store(&_tail, (T*)nullptr); return result; } -- GitLab From 4d64076058a4ec5df101b06572195ed5fdee6f64 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Fri, 11 Feb 2022 09:39:10 +0000 Subject: [PATCH 036/203] 8047749: javadoc for getPathBounds() in TreeUI and BasicTreeUI is incorrect Reviewed-by: aivanov --- src/java.desktop/share/classes/javax/swing/plaf/TreeUI.java | 2 +- .../share/classes/javax/swing/plaf/basic/BasicTreeUI.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.desktop/share/classes/javax/swing/plaf/TreeUI.java b/src/java.desktop/share/classes/javax/swing/plaf/TreeUI.java index 22e8a10052b..40b575f1b2c 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/TreeUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/TreeUI.java @@ -45,7 +45,7 @@ public abstract class TreeUI extends ComponentUI /** * Returns the Rectangle enclosing the label portion that the * last item in path will be drawn into. Will return null if - * any component in path is currently valid. + * any component in path is currently invalid. * * @param tree the {@code JTree} for {@code path} * @param path the {@code TreePath} identifying the node diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTreeUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTreeUI.java index 2626b1c9585..d02a53315af 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTreeUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTreeUI.java @@ -665,7 +665,7 @@ public class BasicTreeUI extends TreeUI /** * Returns the Rectangle enclosing the label portion that the * last item in path will be drawn into. Will return null if - * any component in path is currently valid. + * any component in path is currently invalid. */ public Rectangle getPathBounds(JTree tree, TreePath path) { if(tree != null && treeState != null) { -- GitLab From d254cf28c5e72bd9b8de863b831015237640ca25 Mon Sep 17 00:00:00 2001 From: Jie Fu Date: Fri, 11 Feb 2022 11:39:54 +0000 Subject: [PATCH 037/203] 8281638: jfr/event/allocation tests fail with release VMs after JDK-8281318 due to lack of -XX:+UnlockDiagnosticVMOptions Reviewed-by: shade --- .../allocation/TestObjectAllocationInNewTLABEvent.java | 6 +++--- .../allocation/TestObjectAllocationOutsideTLABEvent.java | 6 +++--- .../TestObjectAllocationSampleEventThrottling.java | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationInNewTLABEvent.java b/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationInNewTLABEvent.java index cb70c0ba324..6dbd51b1386 100644 --- a/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationInNewTLABEvent.java +++ b/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationInNewTLABEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,10 +42,10 @@ import sun.hotspot.WhiteBox; * @build sun.hotspot.WhiteBox * * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. * -XX:+UseTLAB -XX:TLABSize=100k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=1 * jdk.jfr.event.allocation.TestObjectAllocationInNewTLABEvent - * @run main/othervm -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. * -XX:+UseTLAB -XX:TLABSize=100k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=1 * -Xint * jdk.jfr.event.allocation.TestObjectAllocationInNewTLABEvent diff --git a/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationOutsideTLABEvent.java b/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationOutsideTLABEvent.java index 70bf4518f08..87c3b29af42 100644 --- a/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationOutsideTLABEvent.java +++ b/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationOutsideTLABEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,10 +42,10 @@ import sun.hotspot.WhiteBox; * @build sun.hotspot.WhiteBox * * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. * -XX:+UseTLAB -XX:TLABSize=90k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=256 * jdk.jfr.event.allocation.TestObjectAllocationOutsideTLABEvent - * @run main/othervm -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. * -XX:+UseTLAB -XX:TLABSize=90k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=256 * -Xint * jdk.jfr.event.allocation.TestObjectAllocationOutsideTLABEvent diff --git a/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationSampleEventThrottling.java b/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationSampleEventThrottling.java index a10b6e2b56a..5049acc229c 100644 --- a/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationSampleEventThrottling.java +++ b/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationSampleEventThrottling.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,7 +44,7 @@ import sun.hotspot.WhiteBox; * @build sun.hotspot.WhiteBox * * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. * -XX:+UseTLAB -XX:TLABSize=2k -XX:-ResizeTLAB * jdk.jfr.event.allocation.TestObjectAllocationSampleEventThrottling */ -- GitLab From 4ff5824f5bc13826d2eae1c83094acfcccdb7b8f Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Fri, 11 Feb 2022 12:11:29 +0000 Subject: [PATCH 038/203] 8281100: Spurious "variable might not have been initialized" with sealed class switch Reviewed-by: vromero --- .../com/sun/tools/javac/comp/Flow.java | 32 ++++---- .../com/sun/tools/javac/tree/JCTree.java | 2 + .../com/sun/tools/javac/tree/TreeInfo.java | 6 ++ .../tools/javac/patterns/Exhaustiveness.java | 81 ++++++++++++++++++- 4 files changed, 104 insertions(+), 17 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java index 1346d141bb7..db64097c02d 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java @@ -664,10 +664,7 @@ public class Flow { ListBuffer prevPendingExits = pendingExits; pendingExits = new ListBuffer<>(); scan(tree.selector); - boolean exhaustiveSwitch = tree.patternSwitch || - tree.cases.stream() - .flatMap(c -> c.labels.stream()) - .anyMatch(l -> TreeInfo.isNull(l)); + boolean exhaustiveSwitch = TreeInfo.expectedExhaustive(tree); Set constants = exhaustiveSwitch ? new HashSet<>() : null; for (List l = tree.cases; l.nonEmpty(); l = l.tail) { alive = Liveness.ALIVE; @@ -689,10 +686,13 @@ public class Flow { l.tail.head.pos(), Warnings.PossibleFallThroughIntoCase); } - if (!tree.hasTotalPattern && exhaustiveSwitch && - !TreeInfo.isErrorEnumSwitch(tree.selector, tree.cases) && - (constants == null || !isExhaustive(tree.selector.pos(), tree.selector.type, constants))) { - log.error(tree, Errors.NotExhaustiveStatement); + tree.isExhaustive = tree.hasTotalPattern || + TreeInfo.isErrorEnumSwitch(tree.selector, tree.cases); + if (exhaustiveSwitch) { + tree.isExhaustive |= isExhaustive(tree.selector.pos(), tree.selector.type, constants); + if (!tree.isExhaustive) { + log.error(tree, Errors.NotExhaustiveStatement); + } } if (!tree.hasTotalPattern) { alive = Liveness.ALIVE; @@ -725,8 +725,10 @@ public class Flow { } } } - if (!tree.hasTotalPattern && !TreeInfo.isErrorEnumSwitch(tree.selector, tree.cases) && - !isExhaustive(tree.selector.pos(), tree.selector.type, constants)) { + tree.isExhaustive = tree.hasTotalPattern || + TreeInfo.isErrorEnumSwitch(tree.selector, tree.cases) || + isExhaustive(tree.selector.pos(), tree.selector.type, constants); + if (!tree.isExhaustive) { log.error(tree, Errors.NotExhaustive); } alive = prevAlive; @@ -2432,15 +2434,15 @@ public class Flow { } public void visitSwitch(JCSwitch tree) { - handleSwitch(tree, tree.selector, tree.cases, tree.hasTotalPattern); + handleSwitch(tree, tree.selector, tree.cases, tree.isExhaustive); } public void visitSwitchExpression(JCSwitchExpression tree) { - handleSwitch(tree, tree.selector, tree.cases, tree.hasTotalPattern); + handleSwitch(tree, tree.selector, tree.cases, tree.isExhaustive); } private void handleSwitch(JCTree tree, JCExpression selector, - List cases, boolean hasTotalPattern) { + List cases, boolean isExhaustive) { ListBuffer prevPendingExits = pendingExits; pendingExits = new ListBuffer<>(); int nextadrPrev = nextadr; @@ -2478,10 +2480,10 @@ public class Flow { addVars(c.stats, initsSwitch, uninitsSwitch); // Warn about fall-through if lint switch fallthrough enabled. } - if (!hasTotalPattern) { + if (!isExhaustive) { if (tree.hasTag(SWITCH_EXPRESSION)) { markDead(); - } else { + } else if (tree.hasTag(SWITCH) && !TreeInfo.expectedExhaustive((JCSwitch) tree)) { inits.assign(initsSwitch); uninits.assign(uninits.andSet(uninitsSwitch)); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java index a6d3de24e3c..cc66127baa4 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java @@ -1285,6 +1285,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { /** Position of closing brace, optional. */ public int endpos = Position.NOPOS; public boolean hasTotalPattern; + public boolean isExhaustive; public boolean patternSwitch; protected JCSwitch(JCExpression selector, List cases) { this.selector = selector; @@ -1371,6 +1372,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { /** Position of closing brace, optional. */ public int endpos = Position.NOPOS; public boolean hasTotalPattern; + public boolean isExhaustive; public boolean patternSwitch; protected JCSwitchExpression(JCExpression selector, List cases) { this.selector = selector; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java index ee25802ca86..355e19c8826 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java @@ -1384,4 +1384,10 @@ public class TreeInfo { public record PatternPrimaryType(Type type, boolean unconditional) {} + public static boolean expectedExhaustive(JCSwitch tree) { + return tree.patternSwitch || + tree.cases.stream() + .flatMap(c -> c.labels.stream()) + .anyMatch(l -> TreeInfo.isNull(l)); + } } diff --git a/test/langtools/tools/javac/patterns/Exhaustiveness.java b/test/langtools/tools/javac/patterns/Exhaustiveness.java index b7db66c3231..75121a97eca 100644 --- a/test/langtools/tools/javac/patterns/Exhaustiveness.java +++ b/test/langtools/tools/javac/patterns/Exhaustiveness.java @@ -23,7 +23,7 @@ /** * @test - * @bug 8262891 8268871 8274363 + * @bug 8262891 8268871 8274363 8281100 * @summary Check exhaustiveness of switches over sealed types. * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -791,6 +791,82 @@ public class Exhaustiveness extends TestRunner { } } + @Test + public void testDefiniteAssignment(Path base) throws Exception { + doTest(base, + new String[]{""" + package lib; + public sealed interface S permits A, B {} + """, + """ + package lib; + public final class A implements S {} + """, + """ + package lib; + public final class B implements S {} + """}, + """ + package test; + import lib.*; + public class Test { + private void testStatement(S obj) { + int data; + switch (obj) { + case A a -> data = 0; + case B b -> data = 0; + }; + System.err.println(data); + } + private void testExpression(S obj) { + int data; + int v = switch (obj) { + case A a -> data = 0; + case B b -> data = 0; + }; + System.err.println(data); + } + private void testStatementNotExhaustive(S obj) { + int data; + switch (obj) { + case A a -> data = 0; + }; + System.err.println(data); + } + private void testExpressionNotExhaustive(S obj) { + int data; + int v = switch (obj) { + case A a -> data = 0; + }; + System.err.println(data); + } + private void testStatementErrorEnum(E e) { //"E" is intentionally unresolvable + int data; + switch (e) { + case A -> data = 0; + case B -> data = 0; + }; + System.err.println(data); + } + private void testExpressionErrorEnum(E e) { //"E" is intentionally unresolvable + int data; + int v = switch (e) { + case A -> data = 0; + case B -> data = 0; + }; + System.err.println(data); + } + } + """, + "Test.java:34:41: compiler.err.cant.resolve.location: kindname.class, E, , , (compiler.misc.location: kindname.class, test.Test, null)", + "Test.java:42:42: compiler.err.cant.resolve.location: kindname.class, E, , , (compiler.misc.location: kindname.class, test.Test, null)", + "Test.java:22:9: compiler.err.not.exhaustive.statement", + "Test.java:29:17: compiler.err.not.exhaustive", + "- compiler.note.preview.filename: Test.java, DEFAULT", + "- compiler.note.preview.recompile", + "4 errors"); + } + private void doTest(Path base, String[] libraryCode, String testCode, String... expectedErrors) throws IOException { Path current = base.resolve("."); Path libClasses = current.resolve("libClasses"); @@ -825,7 +901,8 @@ public class Exhaustiveness extends TestRunner { "-source", JAVA_VERSION, "-XDrawDiagnostics", "-Xlint:-preview", - "--class-path", libClasses.toString()) + "--class-path", libClasses.toString(), + "-XDshould-stop.at=FLOW") .outdir(classes) .files(tb.findJavaFiles(src)) .run(expectedErrors.length > 0 ? Task.Expect.FAIL : Task.Expect.SUCCESS) -- GitLab From f399ae558eabdce8960d339ef0758c023aeb89cc Mon Sep 17 00:00:00 2001 From: "lawrence.andrews" Date: Fri, 11 Feb 2022 15:33:17 +0000 Subject: [PATCH 039/203] 8202836: [macosx] test java/awt/Graphics/TextAAHintsTest.java fails Reviewed-by: prr, aivanov --- .../java/awt/Graphics/TextAAHintsTest.java | 132 +++++++++++++++--- 1 file changed, 110 insertions(+), 22 deletions(-) diff --git a/test/jdk/java/awt/Graphics/TextAAHintsTest.java b/test/jdk/java/awt/Graphics/TextAAHintsTest.java index 46fa6c28c9b..15fd5a63464 100644 --- a/test/jdk/java/awt/Graphics/TextAAHintsTest.java +++ b/test/jdk/java/awt/Graphics/TextAAHintsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,21 +21,44 @@ * questions. */ -/** +/* * @test * @bug 6263951 * @summary Text should be B&W, grayscale, and LCD. - * @run main/manual=yesno TextAAHintsTest + * @requires (os.family != "mac") + * @run main/manual TextAAHintsTest */ -import java.awt.*; -import java.awt.geom.*; -import java.awt.image.*; + +import java.awt.AWTException; +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.ImageCapabilities; +import java.awt.Panel; +import java.awt.RenderingHints; +import java.awt.TextArea; +import java.awt.image.BufferedImage; +import java.awt.image.VolatileImage; +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; public class TextAAHintsTest extends Component { - String black = "This text should be solid black"; - String gray = "This text should be gray scale anti-aliased"; - String lcd = "This text should be LCD sub-pixel text (coloured)."; + private static final String black = "This text should be solid black"; + private static final String gray = "This text should be gray scale anti-aliased"; + private static final String lcd = "This text should be LCD sub-pixel text (coloured)."; + private static final CountDownLatch countDownLatch = new CountDownLatch(1); + private static volatile String failureReason; + private static volatile boolean testPassed = false; + private static Frame frame; public void paint(Graphics g) { @@ -63,28 +86,24 @@ public class TextAAHintsTest extends Component { RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); g2d.drawString(black, 10, 20); - g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, - RenderingHints.VALUE_TEXT_ANTIALIAS_GASP); - g2d.drawString(black, 10, 35); - g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT); - g2d.drawString(gray, 10, 50); + g2d.drawString(gray, 10, 35); g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); - g2d.drawString(gray, 10, 65); + g2d.drawString(gray, 10, 50); /* For visual comparison, render grayscale with graphics AA off */ g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); - g2d.drawString(gray, 10, 80); + g2d.drawString(gray, 10, 65); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB); - g2d.drawString(lcd, 10, 95); + g2d.drawString(lcd, 10, 80); } public void bufferedImageText(Graphics g) { @@ -139,11 +158,80 @@ public class TextAAHintsTest extends Component { return new Dimension(500,300); } - public static void main(String[] args) throws Exception { + public static void createTestUI() { + frame = new Frame("Composite and Text Test"); + TextAAHintsTest textAAHintsTestObject = new TextAAHintsTest(); + frame.add(textAAHintsTestObject, BorderLayout.NORTH); + + String instructions = """ + Note: Texts are rendered with different TEXT_ANTIALIASING & + VALUE_TEXT_ANTIALIAS. Text should be B&W, grayscale, and LCD. + Note: The results may be visually the same. + 1. Verify that first set of text are rendered correctly. + 2. Second set of text are created using BufferedImage of the first text. + 3. Third set of text are created using VolatileImage of the first text. + """; + TextArea instructionTextArea = new TextArea(instructions, 8, 50); + instructionTextArea.setEditable(false); + frame.add(instructionTextArea, BorderLayout.CENTER); + + Panel controlPanel = new Panel(); + Button passButton = new Button("Pass"); + passButton.addActionListener(e -> { + testPassed = true; + countDownLatch.countDown(); + frame.dispose(); + }); + Button failButton = new Button("Fail"); + failButton.addActionListener(e -> { + getFailureReason(); + testPassed = false; + countDownLatch.countDown(); + frame.dispose(); + }); + controlPanel.add(passButton); + controlPanel.add(failButton); + frame.add(controlPanel, BorderLayout.SOUTH); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public static void getFailureReason() { + // Show dialog to read why the testcase was failed and append the + // testcase failure reason to the output + final Dialog dialog = new Dialog(frame, "TestCase" + + " failure reason", true); + TextArea textArea = new TextArea("", 5, 60, TextArea.SCROLLBARS_BOTH); + dialog.add(textArea, BorderLayout.CENTER); + + Button okButton = new Button("OK"); + okButton.addActionListener(e1 -> { + failureReason = textArea.getText(); + dialog.dispose(); + }); + Panel ctlPanel = new Panel(); + ctlPanel.add(okButton); + dialog.add(ctlPanel, BorderLayout.SOUTH); + dialog.setLocationRelativeTo(null); + dialog.pack(); + dialog.setVisible(true); + } + + public static void main(String[] args) throws InterruptedException, InvocationTargetException { + EventQueue.invokeAndWait(TextAAHintsTest::createTestUI); + if (!countDownLatch.await(2, TimeUnit.MINUTES)) { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + throw new RuntimeException("Timeout : No action was taken on the test."); + } - Frame f = new Frame("Composite and Text Test"); - f.add(new TextAAHintsTest(), BorderLayout.CENTER); - f.pack(); - f.setVisible(true); + if (!testPassed) { + throw new RuntimeException("Test failed : Reason : " + failureReason); + } } } + -- GitLab From e73ee0ca10b644600ee3747b901e5f69104d03df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Fri, 11 Feb 2022 16:24:43 +0000 Subject: [PATCH 040/203] 8281259: MutableBigInteger subtraction could be simplified Reviewed-by: bpb --- .../share/classes/java/math/MutableBigInteger.java | 10 +++++----- .../org/openjdk/bench/java/math/BigIntegers.java | 11 +++++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/java.base/share/classes/java/math/MutableBigInteger.java b/src/java.base/share/classes/java/math/MutableBigInteger.java index 7d0ccbf1e09..91f710d67b8 100644 --- a/src/java.base/share/classes/java/math/MutableBigInteger.java +++ b/src/java.base/share/classes/java/math/MutableBigInteger.java @@ -945,13 +945,13 @@ class MutableBigInteger { x--; y--; diff = (a.value[x+a.offset] & LONG_MASK) - - (b.value[y+b.offset] & LONG_MASK) - ((int)-(diff>>32)); + (b.value[y+b.offset] & LONG_MASK) + (diff >> 32); result[rstart--] = (int)diff; } // Subtract remainder of longer number while (x > 0) { x--; - diff = (a.value[x+a.offset] & LONG_MASK) - ((int)-(diff>>32)); + diff = (a.value[x+a.offset] & LONG_MASK) + (diff >> 32); result[rstart--] = (int)diff; } @@ -986,13 +986,13 @@ class MutableBigInteger { while (y > 0) { x--; y--; diff = (a.value[a.offset+ x] & LONG_MASK) - - (b.value[b.offset+ y] & LONG_MASK) - ((int)-(diff>>32)); + (b.value[b.offset+ y] & LONG_MASK) + (diff >> 32); a.value[a.offset+x] = (int)diff; } // Subtract remainder of longer number - while (x > 0) { + while (diff < 0 && x > 0) { x--; - diff = (a.value[a.offset+ x] & LONG_MASK) - ((int)-(diff>>32)); + diff = (a.value[a.offset+ x] & LONG_MASK) + (diff >> 32); a.value[a.offset+x] = (int)diff; } diff --git a/test/micro/org/openjdk/bench/java/math/BigIntegers.java b/test/micro/org/openjdk/bench/java/math/BigIntegers.java index e2d563d8306..54056e2c5d4 100644 --- a/test/micro/org/openjdk/bench/java/math/BigIntegers.java +++ b/test/micro/org/openjdk/bench/java/math/BigIntegers.java @@ -207,4 +207,15 @@ public class BigIntegers { bh.consume(tmp); } } + + /** Invokes the gcd method of BigInteger with different values. */ + @Benchmark + @OperationsPerInvocation(TESTSIZE) + public void testGcd(Blackhole bh) { + for (int i = 0; i < TESTSIZE; i++) { + BigInteger i1 = shiftArray[TESTSIZE - i - 1]; + BigInteger i2 = shiftArray[i]; + bh.consume(i2.gcd(i1)); + } + } } -- GitLab From e75e8cd708ed478eda08c4a5c724e7e82f57d36e Mon Sep 17 00:00:00 2001 From: Yumin Qi Date: Fri, 11 Feb 2022 16:42:07 +0000 Subject: [PATCH 041/203] 8279997: check_for_dynamic_dump should not exit vm Reviewed-by: ccheung, iklam --- src/hotspot/share/cds/dynamicArchive.cpp | 5 +- src/hotspot/share/runtime/arguments.cpp | 4 ++ .../dynamicArchive/ArchiveConsistency.java | 27 ++++++++++- .../SharedArchiveFileOption.java | 48 ++++++++----------- 4 files changed, 54 insertions(+), 30 deletions(-) diff --git a/src/hotspot/share/cds/dynamicArchive.cpp b/src/hotspot/share/cds/dynamicArchive.cpp index 0ff6a017fed..00d586ffc4f 100644 --- a/src/hotspot/share/cds/dynamicArchive.cpp +++ b/src/hotspot/share/cds/dynamicArchive.cpp @@ -375,9 +375,10 @@ void DynamicArchive::check_for_dynamic_dump() { vm_exit_during_initialization("-XX:+RecordDynamicDumpInfo" __THEMSG, NULL); } else { assert(ArchiveClassesAtExit != nullptr, "sanity"); - vm_exit_during_initialization("-XX:ArchiveClassesAtExit" __THEMSG, NULL); -#undef __THEMSG + warning("-XX:ArchiveClassesAtExit" __THEMSG); } +#undef __THEMSG + DynamicDumpSharedSpaces = false; } } diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index c0f78eaaccf..7d0f1ddd4d3 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -3576,6 +3576,10 @@ void Arguments::init_shared_archive_paths() { SharedArchivePath = get_default_shared_archive_path(); SharedArchiveFile = nullptr; } else { + if (AutoCreateSharedArchive) { + warning("-XX:+AutoCreateSharedArchive is unsupported when base CDS archive is not loaded. Run with -Xlog:cds for more info."); + AutoCreateSharedArchive = false; + } no_shared_spaces("invalid archive"); } } else if (base_archive_path == NULL) { diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ArchiveConsistency.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ArchiveConsistency.java index 33bfc2ef99e..0dcc0e3d7b0 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ArchiveConsistency.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ArchiveConsistency.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -202,5 +202,30 @@ public class ArchiveConsistency extends DynamicArchiveTestBase { runTwo(nonExistBase, nonExistTop, appJar, mainClass, isAuto ? 0 : 1, "Specified shared archive not found (" + nonExistBase + ")"); + + // following two tests: + // -Xshare:auto -XX:SharedArchiveFile=top.jsa, but base does not exist. + + new File(baseArchiveName).delete(); + + startTest("10. -XX:+AutoCreateSharedArchive -XX:SharedArchiveFile=" + topArchiveName); + run(topArchiveName, + "-Xshare:auto", + "-XX:+AutoCreateSharedArchive", + "-cp", + appJar, mainClass) + .assertNormalExit(output -> { + output.shouldContain("warning: -XX:+AutoCreateSharedArchive is unsupported when base CDS archive is not loaded"); + }); + + startTest("11. -XX:SharedArchiveFile=" + topArchiveName + " -XX:ArchiveClassesAtExit=" + getNewArchiveName("top3")); + run(topArchiveName, + "-Xshare:auto", + "-XX:ArchiveClassesAtExit=" + getNewArchiveName("top3"), + "-cp", + appJar, mainClass) + .assertNormalExit(output -> { + output.shouldContain("VM warning: -XX:ArchiveClassesAtExit is unsupported when base CDS archive is not loaded"); + }); } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/SharedArchiveFileOption.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/SharedArchiveFileOption.java index 1dd12b2b55d..d06bb8ef106 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/SharedArchiveFileOption.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/SharedArchiveFileOption.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,17 +64,6 @@ public class SharedArchiveFileOption extends DynamicArchiveTestBase { public void run() throws Exception; } - private static void mustSkipWith(String expectedMsg, MyRunnable r) throws Exception { - try { - r.run(); - } catch (SkippedException e) { - System.out.println("Got SkippedException: " + e); - Asserts.assertTrue(e.getMessage().contains(expectedMsg), "SkippedException must have message " + expectedMsg); - return; - } - Asserts.fail("SkippedException should have been thrown"); - } - private static void doTest(String baseArchiveName, String topArchiveName) throws Exception { String appJar = ClassFileInstaller.getJarPath("hello.jar"); String mainClass = "Hello"; @@ -205,25 +194,30 @@ public class SharedArchiveFileOption extends DynamicArchiveTestBase { output.shouldNotMatch("\\[cds,dynamic"); }); - { + { String ERROR = "-XX:ArchiveClassesAtExit is unsupported when base CDS archive is not loaded"; testcase("-XX:ArchiveClassesAtExit with CDS disabled (-Xshare:off)"); - mustSkipWith(ERROR, () -> { - dump2(baseArchiveName, - topArchiveName, - "-Xshare:off", - "-cp", appJar, mainClass); - }); + dump2(baseArchiveName, + topArchiveName, + "-Xshare:off", + "-Xlog:cds", + "-cp", appJar, mainClass) + .assertNormalExit(output -> { + output.shouldNotMatch("\\[cds,dynamic"); + output.shouldContain(ERROR); + }); testcase("-XX:ArchiveClassesAtExit with CDS disabled (Base archive cannot be mapped -- doesn't exist"); - mustSkipWith(ERROR, () -> { - dump2(baseArchiveName + ".notExist", - topArchiveName, - "-Xlog:cds", - "-Xshare:auto", - "-cp", appJar, mainClass); - }); + dump2(baseArchiveName + ".notExist", + topArchiveName, + "-Xlog:cds", + "-Xshare:auto", + "-cp", appJar, mainClass) + .assertNormalExit(output -> { + output.shouldNotMatch("\\[cds,dynamic"); + output.shouldContain(ERROR); + }); testcase("-XX:ArchiveClassesAtExit with CDS disabled (incompatible VM options)"); dump2(baseArchiveName, @@ -233,7 +227,7 @@ public class SharedArchiveFileOption extends DynamicArchiveTestBase { "-Xshare:auto", "-Xlog:cds", "-cp", appJar, mainClass) - .assertAbnormalExit("Cannot use the following option when dumping the shared archive: --patch-module"); + .assertAbnormalExit("Cannot use the following option when dumping the shared archive: --patch-module"); } { -- GitLab From 8886839779094f8a13c16be79f88052b2c79eeea Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Fri, 11 Feb 2022 17:15:04 +0000 Subject: [PATCH 042/203] 8281622: JFR: Improve documentation of jdk.jfr.Relational Reviewed-by: jbachorik --- .../share/classes/jdk/jfr/Relational.java | 9 ++++- .../jdk/jfr/snippet-files/Snippets.java | 40 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/Relational.java b/src/jdk.jfr/share/classes/jdk/jfr/Relational.java index f195d6ac67b..153346a19ac 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/Relational.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/Relational.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,13 @@ import java.lang.annotation.Target; /** * Meta annotation for relational annotations, to be used on an annotation. + *

+ * The following example shows how a relational annotation can be created and + * used. The {@code Orderid} annotation indicates there is a relation between + * {@code OrderEvent} and {@code OrderLineEvent}. if they have the same ID, + * the order line belongs to the order. + * + * {@snippet class="Snippets" region="RelationalOverview"} * * @since 9 */ diff --git a/src/jdk.jfr/share/classes/jdk/jfr/snippet-files/Snippets.java b/src/jdk.jfr/share/classes/jdk/jfr/snippet-files/Snippets.java index ef95e2ffb35..ef2ff2f3670 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/snippet-files/Snippets.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/snippet-files/Snippets.java @@ -42,6 +42,7 @@ import jdk.jfr.consumer.RecordingFile; import jdk.jfr.Configuration; import jdk.jfr.SettingDefinition; import jdk.jfr.SettingControl; +import jdk.jfr.Timestamp; import jdk.jfr.FlightRecorder; import jdk.jfr.consumer.RecordedEvent; @@ -260,6 +261,45 @@ public class Snippets { } // @end + // @start region="RelationalOverview" + @MetadataDefinition + @Relational + @Name("com.example.OrderId") + @Label("Order ID") + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + public @interface OrderId { + } + + @Name("com.example.Order") + @Label("Order") + @Category("Orders") + class OrderEvent extends Event { + @Label("Order ID") + @OrderId + long orderId; + + @Label("Order Date") + @Timestamp + long orderDate; + } + + @Name("com.example.OrderLine") + @Label("Order Line") + @Category("Orders") + class OrderLineEvent extends Event { + @Label("Order ID") + @OrderId + long orderId; + + @Label("Quantity") + long quantity; + + @Label("Product") + String product; + } + // @end + void RecordingnOverview() throws Exception { // @start region="RecordingOverview" Configuration c = Configuration.getConfiguration("default"); -- GitLab From c5ff6e45dee41b5703138d323a04c2c7973a08b9 Mon Sep 17 00:00:00 2001 From: Calvin Cheung Date: Fri, 11 Feb 2022 17:39:20 +0000 Subject: [PATCH 043/203] 8223077: module path support for dynamic CDS archive Reviewed-by: iklam, minqi --- src/hotspot/share/cds/filemap.cpp | 19 ++- src/hotspot/share/cds/filemap.hpp | 1 + src/hotspot/share/runtime/arguments.hpp | 2 +- .../jtreg/runtime/cds/appcds/TestCommon.java | 15 +- .../cds/appcds/dynamicArchive/ModulePath.java | 131 ++++++++++++++++++ .../UnsupportedBaseArchive.java | 23 +-- 6 files changed, 175 insertions(+), 16 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ModulePath.java diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index 5128565803b..63ba7fb2893 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -963,6 +963,17 @@ void FileMapInfo::log_paths(const char* msg, int start_idx, int end_idx) { } } +bool FileMapInfo::check_module_paths() { + const char* rp = Arguments::get_property("jdk.module.path"); + int num_paths = Arguments::num_archives(rp); + if (num_paths != header()->num_module_paths()) { + return false; + } + ResourceMark rm; + GrowableArray* rp_array = create_path_array(rp); + return check_paths(header()->app_module_paths_start_index(), num_paths, rp_array); +} + bool FileMapInfo::validate_shared_path_table() { assert(UseSharedSpaces, "runtime only"); @@ -985,9 +996,11 @@ bool FileMapInfo::validate_shared_path_table() { "Dynamic archiving is disabled because base layer archive has appended boot classpath"); } if (header()->num_module_paths() > 0) { - DynamicDumpSharedSpaces = false; - warning( - "Dynamic archiving is disabled because base layer archive has module path"); + if (!check_module_paths()) { + DynamicDumpSharedSpaces = false; + warning( + "Dynamic archiving is disabled because base layer archive has a different module path"); + } } } diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp index e6655858187..f34fb4d7211 100644 --- a/src/hotspot/share/cds/filemap.hpp +++ b/src/hotspot/share/cds/filemap.hpp @@ -491,6 +491,7 @@ public: static void clone_shared_path_table(TRAPS); static int add_shared_classpaths(int i, const char* which, ClassPathEntry *cpe, TRAPS); static void check_nonempty_dir_in_shared_path_table(); + bool check_module_paths(); bool validate_shared_path_table(); void validate_non_existent_class_paths(); static void set_shared_path_table(FileMapInfo* info) { diff --git a/src/hotspot/share/runtime/arguments.hpp b/src/hotspot/share/runtime/arguments.hpp index 19bb12196e3..de6cf1a4d23 100644 --- a/src/hotspot/share/runtime/arguments.hpp +++ b/src/hotspot/share/runtime/arguments.hpp @@ -470,12 +470,12 @@ class Arguments : AllStatic { static char* SharedArchivePath; static char* SharedDynamicArchivePath; static size_t _default_SharedBaseAddress; // The default value specified in globals.hpp - static int num_archives(const char* archive_path) NOT_CDS_RETURN_(0); static void extract_shared_archive_paths(const char* archive_path, char** base_archive_path, char** top_archive_path) NOT_CDS_RETURN; public: + static int num_archives(const char* archive_path) NOT_CDS_RETURN_(0); // Parses the arguments, first phase static jint parse(const JavaVMInitArgs* args); // Parse a string for a unsigned integer. Returns true if value diff --git a/test/hotspot/jtreg/runtime/cds/appcds/TestCommon.java b/test/hotspot/jtreg/runtime/cds/appcds/TestCommon.java index a90512f73fb..959d43173d0 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/TestCommon.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/TestCommon.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -153,6 +153,19 @@ public class TestCommon extends CDSTestUtils { return out; } + public static OutputAnalyzer dumpBaseArchive(String baseArchiveName, String classList[], String ... cmdLineSuffix) + throws Exception + { + CDSOptions opts = new CDSOptions(); + opts.setArchiveName(baseArchiveName); + opts.setClassList(classList); + opts.addSuffix(cmdLineSuffix); + opts.addSuffix("-Djava.class.path="); + OutputAnalyzer out = CDSTestUtils.createArchive(opts); + CDSTestUtils.checkBaseDump(out); + return out; + } + // Create AppCDS archive using most common args - convenience method public static OutputAnalyzer createArchive(String appJar, String classList[], String... suffix) throws Exception { diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ModulePath.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ModulePath.java new file mode 100644 index 00000000000..2672225ee05 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ModulePath.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import jdk.test.lib.cds.CDSTestUtils; + +/* + * @test + * @summary Dyanmic archive with module path + * @requires vm.cds + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds /test/hotspot/jtreg/runtime/cds/appcds/test-classes + * @compile ../test-classes/Hello.java + * @build sun.hotspot.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:./WhiteBox.jar ModulePath + */ + +public class ModulePath extends DynamicArchiveTestBase { + private static final Path USER_DIR = Paths.get(CDSTestUtils.getOutputDir()); + + private static final String FS = File.separator; + private static final String TEST_SRC = System.getProperty("test.src") + + FS + ".." + FS + "jigsaw" + FS + "modulepath"; + + private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); + private static final Path MODS_DIR = Paths.get("mods"); + + // the module name of the test module + private static final String TEST_MODULE = "com.simple"; + + // the module main class + private static final String MAIN_CLASS = "com.simple.Main"; + + private static Path moduleDir = null; + private static Path srcJar = null; + + public static void buildTestModule() throws Exception { + + // javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/** + JarBuilder.compileModule(SRC_DIR.resolve(TEST_MODULE), + MODS_DIR.resolve(TEST_MODULE), + MODS_DIR.toString()); + + + moduleDir = Files.createTempDirectory(USER_DIR, "mlib"); + srcJar = moduleDir.resolve(TEST_MODULE + ".jar"); + String classes = MODS_DIR.resolve(TEST_MODULE).toString(); + JarBuilder.createModularJar(srcJar.toString(), classes, MAIN_CLASS); + } + + public static void main(String[] args) throws Exception { + runTest(ModulePath::test); + } + + static void test(String args[]) throws Exception { + String topArchiveName = getNewArchiveName("top"); + String baseArchiveName = getNewArchiveName("base"); + + String appJar = JarBuilder.getOrCreateHelloJar(); + String mainClass = "Hello"; + + // create a base archive with the --module-path option + buildTestModule(); + baseArchiveName = getNewArchiveName("base-with-module"); + String appClasses[] = {mainClass}; + TestCommon.dumpBaseArchive(baseArchiveName, + appClasses, + "-Xlog:class+load", + "-cp", appJar, + "--module-path", moduleDir.toString(), + "-m", TEST_MODULE); + + // Dumping of dynamic archive should be successful if the specified + // --module-path is the same as for the base archive. + topArchiveName = getNewArchiveName("top-with-module"); + dump2(baseArchiveName, topArchiveName, + "-Xlog:cds*", + "-Xlog:cds+dynamic=debug", + "-Xlog:class+path=info,class+load", + "-cp", appJar, + "--module-path", moduleDir.toString(), + "-m", TEST_MODULE, MAIN_CLASS) + .assertNormalExit(); + + // Load the Hello class from the base archive. + run2(baseArchiveName, topArchiveName, + "-Xlog:class+load", + "-Xlog:cds+dynamic=debug,cds=debug", + "-cp", appJar, mainClass) + .assertNormalExit(output -> { + output.shouldContain("Hello source: shared objects file") + .shouldHaveExitValue(0); + }); + + // Load the com.simple.Main class from the dynamic archive. + run2(baseArchiveName, topArchiveName, + "-Xlog:class+load", + "-Xlog:cds+dynamic=debug,cds=debug", + "-cp", appJar, + "--module-path", moduleDir.toString(), + "-m", TEST_MODULE, MAIN_CLASS) + .assertNormalExit(output -> { + output.shouldContain("com.simple.Main source: shared objects file (top)") + .shouldHaveExitValue(0); + }); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/UnsupportedBaseArchive.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/UnsupportedBaseArchive.java index a6027354e25..6a34bcc3192 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/UnsupportedBaseArchive.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/UnsupportedBaseArchive.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,7 +62,7 @@ public class UnsupportedBaseArchive extends DynamicArchiveTestBase { "Dynamic archiving is disabled because base layer archive has appended boot classpath"; private static final String warningModulePath = - "Dynamic archiving is disabled because base layer archive has module path"; + "Dynamic archiving is disabled because base layer archive has a different module path"; public static void buildTestModule() throws Exception { @@ -104,22 +104,23 @@ public class UnsupportedBaseArchive extends DynamicArchiveTestBase { // create a base archive with the --module-path option buildTestModule(); baseArchiveName = getNewArchiveName("base-with-module"); + String appClasses[] = {mainClass}; TestCommon.dumpBaseArchive(baseArchiveName, - "-cp", srcJar.toString(), + appClasses, + "-Xlog:class+load", + "-cp", appJar, "--module-path", moduleDir.toString(), "-m", TEST_MODULE); - // dumping of dynamic archive should be disabled with a warning message - // if the base archive contains --module-path entries. - topArchiveName = getNewArchiveName("top-with-module"); + // Try to create a dynamic archive without specifying module path, + // dumping should fail. + topArchiveName = getNewArchiveName("top-with-module-failed"); dump2(baseArchiveName, topArchiveName, "-Xlog:cds*", "-Xlog:cds+dynamic=debug", - "-Xlog:class+path=info", - "-cp", srcJar.toString(), - "--module-path", moduleDir.toString(), - "-m", TEST_MODULE) + "-Xlog:class+path=info,class+load", + "-cp", appJar, + mainClass) .assertNormalExit(warningModulePath); - } } -- GitLab From 0786ddb4712296c90df2c9e97c76c203a4de4612 Mon Sep 17 00:00:00 2001 From: Manukumar V S Date: Fri, 11 Feb 2022 17:40:25 +0000 Subject: [PATCH 044/203] 8281535: Create a regression test for JDK-4670051 Reviewed-by: aivanov --- .../4670051/DateFieldUnderCursorTest.java | 282 ++++++++++++++++++ 1 file changed, 282 insertions(+) create mode 100644 test/jdk/javax/swing/JSpinner/4670051/DateFieldUnderCursorTest.java diff --git a/test/jdk/javax/swing/JSpinner/4670051/DateFieldUnderCursorTest.java b/test/jdk/javax/swing/JSpinner/4670051/DateFieldUnderCursorTest.java new file mode 100644 index 00000000000..c0346700699 --- /dev/null +++ b/test/jdk/javax/swing/JSpinner/4670051/DateFieldUnderCursorTest.java @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.ComponentOrientation; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JSpinner; +import javax.swing.SpinnerDateModel; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +import static javax.swing.UIManager.getInstalledLookAndFeels; + +/* + * @test + * @key headful + * @bug 4670051 + * @summary Checks whether JSpinner with a SpinnerDateModel + * spins the field where cursor is located. + * @run main DateFieldUnderCursorTest + */ +public class DateFieldUnderCursorTest { + + private static final Calendar expected = Calendar.getInstance(); + private static final Calendar actual = Calendar.getInstance(); + private static Robot robot; + private static JSpinner spinner; + private static Date initValue; + private static Date upValue; + private static Date downValue; + private static JFrame frame; + private static boolean passed = true; + private static volatile Point spinnerUpButtonCenter; + private static volatile Point spinnerDownButtonCenter; + private static volatile Date spinnerValue; + + public static void main(String[] s) throws Exception { + runTest(); + } + + public static void runTest() throws Exception { + robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.setAutoDelay(100); + List lafs = Arrays.stream(getInstalledLookAndFeels()) + .map(UIManager.LookAndFeelInfo::getClassName) + .collect(Collectors.toList()); + for (final String laf : lafs) { + try { + SwingUtilities.invokeAndWait(() -> { + setLookAndFeel(laf); + createUI(); + }); + SwingUtilities.invokeAndWait(() -> { + Point loc = spinner.getLocationOnScreen(); + int editorWidth = spinner.getEditor().getWidth(); + int buttonWidth = spinner.getWidth() - editorWidth; + int quarterHeight = spinner.getHeight() / 4; + + spinnerUpButtonCenter = new Point(loc.x + editorWidth + + (buttonWidth / 2), + loc.y + quarterHeight); + spinnerDownButtonCenter = new Point(spinnerUpButtonCenter.x, + loc.y + (3 * quarterHeight)); + }); + + // Cursor at Day field. + // Increment Day + initValue = getSpinnerValue(); + mousePressOnUpButton(); + upValue = getSpinnerValue(); + verifyDayIncrement(); + // Decrement Day + initValue = getSpinnerValue(); + mousePressOnDownButton(); + downValue = getSpinnerValue(); + verifyDayDecrement(); + + // Cursor at Month Field + pressRightArrowKey(); + // Increment Month + initValue = getSpinnerValue(); + mousePressOnUpButton(); + upValue = getSpinnerValue(); + verifyMonthIncrement(); + // Decrement Month + initValue = getSpinnerValue(); + mousePressOnDownButton(); + downValue = getSpinnerValue(); + verifyMonthDecrement(); + + // Cursor at Year Field + pressRightArrowKey(); + // Increment Year + initValue = getSpinnerValue(); + mousePressOnUpButton(); + upValue = getSpinnerValue(); + verifyYearIncrement(); + // Decrement Year + initValue = getSpinnerValue(); + mousePressOnDownButton(); + downValue = getSpinnerValue(); + verifyYearDecrement(); + + if (passed) { + System.out.println("Test Passed"); + } else { + throw new RuntimeException("Test Failed as one or more cases failed"); + } + } finally { + SwingUtilities.invokeAndWait(DateFieldUnderCursorTest::disposeFrame); + } + } + } + + private static Date getSpinnerValue() throws Exception { + SwingUtilities.invokeAndWait(() -> spinnerValue = (Date) spinner.getValue()); + return spinnerValue; + } + + public static void pressRightArrowKey() { + robot.keyPress(KeyEvent.VK_RIGHT); + robot.keyRelease(KeyEvent.VK_RIGHT); + } + + public static void mousePressOnUpButton() { + robot.mouseMove(spinnerUpButtonCenter.x, spinnerUpButtonCenter.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + } + + public static void mousePressOnDownButton() { + robot.mouseMove(spinnerDownButtonCenter.x, spinnerDownButtonCenter.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + } + + + public static boolean compareDates() { + return (expected.get(Calendar.DATE) == actual.get(Calendar.DATE)) + && (expected.get(Calendar.MONTH) == actual.get(Calendar.MONTH)) + && (expected.get(Calendar.YEAR) == actual.get(Calendar.YEAR)); + } + + private static void checkResult() { + if (compareDates()) { + System.out.println(" Case Passed"); + } else { + passed = false; + System.out.println(" Case Failed because the expected: " + expected.getTime() + + " and actual: " + actual.getTime() + " outputs do not match."); + } + } + + private static void updateCalendarObjects(Date finalValue) { + expected.setTime(initValue); + actual.setTime(finalValue); + } + + /** + * Verifying that JSpinner increments the date field when cursor is on date field + */ + private static void verifyDayIncrement() { + System.out.print("verifyDateIncrement"); + updateCalendarObjects(upValue); + expected.add(Calendar.DATE, 1); + checkResult(); + } + + /** + * Verifying that JSpinner decrements the date field when cursor is on date field + */ + private static void verifyDayDecrement() { + System.out.print("verifyDateDecrement"); + updateCalendarObjects(downValue); + expected.add(Calendar.DATE, -1); + checkResult(); + } + + /** + * Verifying that JSpinner increments the month field when cursor is on month field + */ + private static void verifyMonthIncrement() { + System.out.print("verifyMonthIncrement"); + updateCalendarObjects(upValue); + expected.add(Calendar.MONTH, 1); + checkResult(); + } + + /** + * Verifying that JSpinner decrements the month field when cursor is on month field + */ + private static void verifyMonthDecrement() { + System.out.print("verifyMonthDecrement"); + updateCalendarObjects(downValue); + expected.add(Calendar.MONTH, -1); + checkResult(); + } + + /** + * Verifying that, JSpinner decrements the year field when the cursor is on year field. + */ + private static void verifyYearDecrement() { + System.out.print("verifyYearDecrement"); + updateCalendarObjects(downValue); + expected.add(Calendar.YEAR, -1); + checkResult(); + } + + /** + * Verifying that JSpinner increments the year field when cursor is on year field + */ + private static void verifyYearIncrement() { + System.out.print("verifyYearIncrement"); + updateCalendarObjects(upValue); + expected.add(Calendar.YEAR, 1); + checkResult(); + } + + private static void createUI() { + frame = new JFrame(); + JPanel panel = new JPanel(); + spinner = new JSpinner(new SpinnerDateModel()); + JSpinner.DateEditor editor = new JSpinner.DateEditor(spinner, " dd/MM/yy "); + spinner.setEditor(editor); + spinner.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); + panel.add(spinner); + + frame.add(panel); + frame.setUndecorated(true); + frame.pack(); + frame.setAlwaysOnTop(true); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private static void setLookAndFeel(final String laf) { + try { + UIManager.setLookAndFeel(laf); + System.out.println("LookAndFeel: " + laf); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static void disposeFrame() { + if (frame != null) { + frame.dispose(); + frame = null; + } + } + +} -- GitLab From 83ffbd2e7aed8a9c788395ccbe920ddff221ae16 Mon Sep 17 00:00:00 2001 From: "Dr Heinz M. Kabutz" Date: Fri, 11 Feb 2022 18:49:04 +0000 Subject: [PATCH 045/203] 8277175: Add a parallel multiply method to BigInteger Reviewed-by: psandoz --- .../share/classes/java/math/BigInteger.java | 155 +++++++-- .../BigIntegerParallelMultiplyTest.java | 82 +++++ .../math/BigIntegerMersennePrimeMultiply.java | 322 ++++++++++++++++++ .../java/math/BigIntegerParallelMultiply.java | 61 ++++ 4 files changed, 601 insertions(+), 19 deletions(-) create mode 100644 test/jdk/java/math/BigInteger/BigIntegerParallelMultiplyTest.java create mode 100644 test/micro/org/openjdk/bench/java/math/BigIntegerMersennePrimeMultiply.java create mode 100644 test/micro/org/openjdk/bench/java/math/BigIntegerParallelMultiply.java diff --git a/src/java.base/share/classes/java/math/BigInteger.java b/src/java.base/share/classes/java/math/BigInteger.java index 34f1953d003..81d9a9cf248 100644 --- a/src/java.base/share/classes/java/math/BigInteger.java +++ b/src/java.base/share/classes/java/math/BigInteger.java @@ -36,6 +36,9 @@ import java.io.ObjectStreamField; import java.util.Arrays; import java.util.Objects; import java.util.Random; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinWorkerThread; +import java.util.concurrent.RecursiveTask; import java.util.concurrent.ThreadLocalRandom; import jdk.internal.math.DoubleConsts; @@ -1581,7 +1584,30 @@ public class BigInteger extends Number implements Comparable { * @return {@code this * val} */ public BigInteger multiply(BigInteger val) { - return multiply(val, false); + return multiply(val, false, false, 0); + } + + /** + * Returns a BigInteger whose value is {@code (this * val)}. + * When both {@code this} and {@code val} are large, typically + * in the thousands of bits, parallel multiply might be used. + * This method returns the exact same mathematical result as + * {@link #multiply}. + * + * @implNote This implementation may offer better algorithmic + * performance when {@code val == this}. + * + * @implNote Compared to {@link #multiply}, an implementation's + * parallel multiplication algorithm would typically use more + * CPU resources to compute the result faster, and may do so + * with a slight increase in memory consumption. + * + * @param val value to be multiplied by this BigInteger. + * @return {@code this * val} + * @see #multiply + */ + public BigInteger parallelMultiply(BigInteger val) { + return multiply(val, false, true, 0); } /** @@ -1590,16 +1616,17 @@ public class BigInteger extends Number implements Comparable { * * @param val value to be multiplied by this BigInteger. * @param isRecursion whether this is a recursive invocation + * @param parallel whether the multiply should be done in parallel * @return {@code this * val} */ - private BigInteger multiply(BigInteger val, boolean isRecursion) { + private BigInteger multiply(BigInteger val, boolean isRecursion, boolean parallel, int depth) { if (val.signum == 0 || signum == 0) return ZERO; int xlen = mag.length; if (val == this && xlen > MULTIPLY_SQUARE_THRESHOLD) { - return square(); + return square(true, parallel, depth); } int ylen = val.mag.length; @@ -1677,7 +1704,7 @@ public class BigInteger extends Number implements Comparable { } } - return multiplyToomCook3(this, val); + return multiplyToomCook3(this, val, parallel, depth); } } } @@ -1844,6 +1871,88 @@ public class BigInteger extends Number implements Comparable { } } + @SuppressWarnings("serial") + private abstract static sealed class RecursiveOp extends RecursiveTask { + /** + * The threshold until when we should continue forking recursive ops + * if parallel is true. This threshold is only relevant for Toom Cook 3 + * multiply and square. + */ + private static final int PARALLEL_FORK_DEPTH_THRESHOLD = + calculateMaximumDepth(ForkJoinPool.getCommonPoolParallelism()); + + private static final int calculateMaximumDepth(int parallelism) { + return 32 - Integer.numberOfLeadingZeros(parallelism); + } + + final boolean parallel; + /** + * The current recursing depth. Since it is a logarithmic algorithm, + * we do not need an int to hold the number. + */ + final byte depth; + + private RecursiveOp(boolean parallel, int depth) { + this.parallel = parallel; + this.depth = (byte) depth; + } + + private static int getParallelForkDepthThreshold() { + if (Thread.currentThread() instanceof ForkJoinWorkerThread fjwt) { + return calculateMaximumDepth(fjwt.getPool().getParallelism()); + } + else { + return PARALLEL_FORK_DEPTH_THRESHOLD; + } + } + + protected RecursiveTask forkOrInvoke() { + if (parallel && depth <= getParallelForkDepthThreshold()) fork(); + else invoke(); + return this; + } + + @SuppressWarnings("serial") + private static final class RecursiveMultiply extends RecursiveOp { + private final BigInteger a; + private final BigInteger b; + + public RecursiveMultiply(BigInteger a, BigInteger b, boolean parallel, int depth) { + super(parallel, depth); + this.a = a; + this.b = b; + } + + @Override + public BigInteger compute() { + return a.multiply(b, true, parallel, depth); + } + } + + @SuppressWarnings("serial") + private static final class RecursiveSquare extends RecursiveOp { + private final BigInteger a; + + public RecursiveSquare(BigInteger a, boolean parallel, int depth) { + super(parallel, depth); + this.a = a; + } + + @Override + public BigInteger compute() { + return a.square(true, parallel, depth); + } + } + + private static RecursiveTask multiply(BigInteger a, BigInteger b, boolean parallel, int depth) { + return new RecursiveMultiply(a, b, parallel, depth).forkOrInvoke(); + } + + private static RecursiveTask square(BigInteger a, boolean parallel, int depth) { + return new RecursiveSquare(a, parallel, depth).forkOrInvoke(); + } + } + /** * Multiplies two BigIntegers using a 3-way Toom-Cook multiplication * algorithm. This is a recursive divide-and-conquer algorithm which is @@ -1872,7 +1981,7 @@ public class BigInteger extends Number implements Comparable { * LNCS #4547. Springer, Madrid, Spain, June 21-22, 2007. * */ - private static BigInteger multiplyToomCook3(BigInteger a, BigInteger b) { + private static BigInteger multiplyToomCook3(BigInteger a, BigInteger b, boolean parallel, int depth) { int alen = a.mag.length; int blen = b.mag.length; @@ -1896,16 +2005,20 @@ public class BigInteger extends Number implements Comparable { BigInteger v0, v1, v2, vm1, vinf, t1, t2, tm1, da1, db1; - v0 = a0.multiply(b0, true); + depth++; + var v0_task = RecursiveOp.multiply(a0, b0, parallel, depth); da1 = a2.add(a0); db1 = b2.add(b0); - vm1 = da1.subtract(a1).multiply(db1.subtract(b1), true); + var vm1_task = RecursiveOp.multiply(da1.subtract(a1), db1.subtract(b1), parallel, depth); da1 = da1.add(a1); db1 = db1.add(b1); - v1 = da1.multiply(db1, true); + var v1_task = RecursiveOp.multiply(da1, db1, parallel, depth); v2 = da1.add(a2).shiftLeft(1).subtract(a0).multiply( - db1.add(b2).shiftLeft(1).subtract(b0), true); - vinf = a2.multiply(b2, true); + db1.add(b2).shiftLeft(1).subtract(b0), true, parallel, depth); + vinf = a2.multiply(b2, true, parallel, depth); + v0 = v0_task.join(); + vm1 = vm1_task.join(); + v1 = v1_task.join(); // The algorithm requires two divisions by 2 and one by 3. // All divisions are known to be exact, that is, they do not produce @@ -2071,7 +2184,7 @@ public class BigInteger extends Number implements Comparable { * @return this2 */ private BigInteger square() { - return square(false); + return square(false, false, 0); } /** @@ -2081,7 +2194,7 @@ public class BigInteger extends Number implements Comparable { * @param isRecursion whether this is a recursive invocation * @return this2 */ - private BigInteger square(boolean isRecursion) { + private BigInteger square(boolean isRecursion, boolean parallel, int depth) { if (signum == 0) { return ZERO; } @@ -2103,7 +2216,7 @@ public class BigInteger extends Number implements Comparable { } } - return squareToomCook3(); + return squareToomCook3(parallel, depth); } } } @@ -2237,7 +2350,7 @@ public class BigInteger extends Number implements Comparable { * that has better asymptotic performance than the algorithm used in * squareToLen or squareKaratsuba. */ - private BigInteger squareToomCook3() { + private BigInteger squareToomCook3(boolean parallel, int depth) { int len = mag.length; // k is the size (in ints) of the lower-order slices. @@ -2254,13 +2367,17 @@ public class BigInteger extends Number implements Comparable { a0 = getToomSlice(k, r, 2, len); BigInteger v0, v1, v2, vm1, vinf, t1, t2, tm1, da1; - v0 = a0.square(true); + depth++; + var v0_fork = RecursiveOp.square(a0, parallel, depth); da1 = a2.add(a0); - vm1 = da1.subtract(a1).square(true); + var vm1_fork = RecursiveOp.square(da1.subtract(a1), parallel, depth); da1 = da1.add(a1); - v1 = da1.square(true); - vinf = a2.square(true); - v2 = da1.add(a2).shiftLeft(1).subtract(a0).square(true); + var v1_fork = RecursiveOp.square(da1, parallel, depth); + vinf = a2.square(true, parallel, depth); + v2 = da1.add(a2).shiftLeft(1).subtract(a0).square(true, parallel, depth); + v0 = v0_fork.join(); + vm1 = vm1_fork.join(); + v1 = v1_fork.join(); // The algorithm requires two divisions by 2 and one by 3. // All divisions are known to be exact, that is, they do not produce diff --git a/test/jdk/java/math/BigInteger/BigIntegerParallelMultiplyTest.java b/test/jdk/java/math/BigInteger/BigIntegerParallelMultiplyTest.java new file mode 100644 index 00000000000..1396ae06d96 --- /dev/null +++ b/test/jdk/java/math/BigInteger/BigIntegerParallelMultiplyTest.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 + * @run main BigIntegerParallelMultiplyTest + * @summary tests parallelMultiply() method in BigInteger + * @author Heinz Kabutz heinz@javaspecialists.eu + */ + +import java.math.BigInteger; +import java.util.function.BinaryOperator; + +/** + * This is a simple test class created to ensure that the results + * of multiply() are the same as multiplyParallel(). We calculate + * the Fibonacci numbers using Dijkstra's sum of squares to get + * very large numbers (hundreds of thousands of bits). + * + * @author Heinz Kabutz, heinz@javaspecialists.eu + */ +public class BigIntegerParallelMultiplyTest { + public static BigInteger fibonacci(int n, BinaryOperator multiplyOperator) { + if (n == 0) return BigInteger.ZERO; + if (n == 1) return BigInteger.ONE; + + int half = (n + 1) / 2; + BigInteger f0 = fibonacci(half - 1, multiplyOperator); + BigInteger f1 = fibonacci(half, multiplyOperator); + if (n % 2 == 1) { + BigInteger b0 = multiplyOperator.apply(f0, f0); + BigInteger b1 = multiplyOperator.apply(f1, f1); + return b0.add(b1); + } else { + BigInteger b0 = f0.shiftLeft(1).add(f1); + return multiplyOperator.apply(b0, f1); + } + } + + public static void main(String[] args) throws Exception { + compare(1000, 324); + compare(10_000, 3473); + compare(100_000, 34883); + compare(1_000_000, 347084); + } + + private static void compare(int n, int expectedBitCount) { + BigInteger multiplyResult = fibonacci(n, BigInteger::multiply); + BigInteger parallelMultiplyResult = fibonacci(n, BigInteger::parallelMultiply); + checkBitCount(n, expectedBitCount, multiplyResult); + checkBitCount(n, expectedBitCount, parallelMultiplyResult); + if (!multiplyResult.equals(parallelMultiplyResult)) + throw new AssertionError("multiply() and parallelMultiply() give different results"); + } + + private static void checkBitCount(int n, int expectedBitCount, BigInteger number) { + if (number.bitCount() != expectedBitCount) + throw new AssertionError( + "bitCount of fibonacci(" + n + ") was expected to be " + expectedBitCount + + " but was " + number.bitCount()); + } +} diff --git a/test/micro/org/openjdk/bench/java/math/BigIntegerMersennePrimeMultiply.java b/test/micro/org/openjdk/bench/java/math/BigIntegerMersennePrimeMultiply.java new file mode 100644 index 00000000000..7ac4cf54dc2 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/math/BigIntegerMersennePrimeMultiply.java @@ -0,0 +1,322 @@ +package org.openjdk.bench.java.math; + +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadMXBean; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.math.BigInteger; +import java.util.Arrays; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Locale; +import java.util.LongSummaryStatistics; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinWorkerThread; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.BinaryOperator; +import java.util.function.LongUnaryOperator; +import java.util.stream.Collectors; + +import static java.util.concurrent.ForkJoinPool.defaultForkJoinWorkerThreadFactory; + +/** + * Benchmark for checking performance difference between sequential and parallel + * multiply of very large Mersenne primes using BigInteger. We want to measure + * real time, user time, system time and the amount of memory allocated. To + * calculate this, we create our own thread factory for the common ForkJoinPool + * and then use that to measure user time, cpu time and bytes allocated. + *

+ * We use reflection to discover all methods that match "*ultiply", and use them + * to multiply two very large Mersenne primes together. + *

+ *

Results on a 1-6-2 machine running Ubuntu linux

+ *

+ * Memory allocation increased from 83.9GB to 84GB, for both the sequential and + * parallel versions. This is an increase of just 0.1%. On this machine, the + * parallel version was 3.8x faster in latency (real time), but it used 2.7x + * more CPU resources. + *

+ * Testing multiplying Mersenne primes of 2^57885161-1 and 2^82589933-1 + *

+ *

+ * openjdk version "18-internal" 2022-03-15
+ * BigInteger.parallelMultiply()
+ * real  0m6.288s
+ * user  1m3.010s
+ * sys   0m0.027s
+ * mem   84.0GB
+ * BigInteger.multiply()
+ * real  0m23.682s
+ * user  0m23.530s
+ * sys   0m0.004s
+ * mem   84.0GB
+ *
+ * openjdk version "1.8.0_302"
+ * BigInteger.multiply()
+ * real  0m25.657s
+ * user  0m25.390s
+ * sys   0m0.001s
+ * mem   83.9GB
+ *
+ * openjdk version "9.0.7.1"
+ * BigInteger.multiply()
+ * real  0m24.907s
+ * user  0m24.700s
+ * sys   0m0.001s
+ * mem   83.9GB
+ *
+ * openjdk version "10.0.2" 2018-07-17
+ * BigInteger.multiply()
+ * real  0m24.632s
+ * user  0m24.380s
+ * sys   0m0.004s
+ * mem   83.9GB
+ *
+ * openjdk version "11.0.12" 2021-07-20 LTS
+ * BigInteger.multiply()
+ * real  0m22.114s
+ * user  0m21.930s
+ * sys   0m0.001s
+ * mem   83.9GB
+ *
+ * openjdk version "12.0.2" 2019-07-16
+ * BigInteger.multiply()
+ * real  0m23.015s
+ * user  0m22.830s
+ * sys   0m0.000s
+ * mem   83.9GB
+ *
+ * openjdk version "13.0.9" 2021-10-19
+ * BigInteger.multiply()
+ * real  0m23.548s
+ * user  0m23.350s
+ * sys   0m0.005s
+ * mem   83.9GB
+ *
+ * openjdk version "14.0.2" 2020-07-14
+ * BigInteger.multiply()
+ * real  0m22.918s
+ * user  0m22.530s
+ * sys   0m0.131s
+ * mem   83.9GB
+ *
+ * openjdk version "15.0.5" 2021-10-19
+ * BigInteger.multiply()
+ * real  0m22.038s
+ * user  0m21.750s
+ * sys   0m0.003s
+ * mem   83.9GB
+ *
+ * openjdk version "16.0.2" 2021-07-20
+ * BigInteger.multiply()
+ * real  0m23.049s
+ * user  0m22.760s
+ * sys   0m0.006s
+ * mem   83.9GB
+ *
+ * openjdk version "17" 2021-09-14
+ * BigInteger.multiply()
+ * real  0m22.580s
+ * user  0m22.310s
+ * sys   0m0.001s
+ * mem   83.9GB
+ *
+ * + * @author Heinz Kabutz, heinz@javaspecialists.eu + */ +public class BigIntegerMersennePrimeMultiply implements ForkJoinPool.ForkJoinWorkerThreadFactory { + // Large Mersenne prime discovered by Curtis Cooper in 2013 + private static final int EXPONENT_1 = 57885161; + private static final BigInteger MERSENNE_1 = + BigInteger.ONE.shiftLeft(EXPONENT_1).subtract(BigInteger.ONE); + // Largest Mersenne prime number discovered by Patrick Laroche in 2018 + private static final int EXPONENT_2 = 82589933; + private static final BigInteger MERSENNE_2 = + BigInteger.ONE.shiftLeft(EXPONENT_2).subtract(BigInteger.ONE); + private static boolean DEBUG = false; + + public static void main(String... args) { + System.setProperty("java.util.concurrent.ForkJoinPool.common.threadFactory", + BigIntegerMersennePrimeMultiply.class.getName()); + System.out.println("Testing multiplying Mersenne primes of " + + "2^" + EXPONENT_1 + "-1 and 2^" + EXPONENT_2 + "-1"); + addCounters(Thread.currentThread()); + System.out.println("Using the following multiply methods:"); + List methods = Arrays.stream(BigInteger.class.getMethods()) + .filter(method -> method.getName().endsWith("ultiply") && + method.getParameterCount() == 1 && + method.getParameterTypes()[0] == BigInteger.class) + .peek(method -> System.out.println(" " + method)) + .collect(Collectors.toList()); + + for (int i = 0; i < 3; i++) { + System.out.println(); + methods.forEach(BigIntegerMersennePrimeMultiply::test); + } + } + + private static void test(Method method) { + BinaryOperator multiplyOperator = (a, b) -> { + try { + return (BigInteger) method.invoke(a, b); + } catch (IllegalAccessException e) { + throw new AssertionError(e); + } catch (InvocationTargetException e) { + throw new AssertionError(e.getCause()); + } + }; + test(method.getName(), multiplyOperator); + } + + private static void test(String description, + BinaryOperator multiplyOperator) { + System.out.println("BigInteger." + description + "()"); + resetAllCounters(); + long elapsedTimeInNanos = System.nanoTime(); + try { + BigInteger result1 = multiplyOperator.apply(MERSENNE_1, MERSENNE_2); + BigInteger result2 = multiplyOperator.apply(MERSENNE_2, MERSENNE_1); + if (result1.bitLength() != 140475094) + throw new AssertionError("Expected bitLength: 140475094, " + + "but was " + result1.bitLength()); + if (result2.bitLength() != 140475094) + throw new AssertionError("Expected bitLength: 140475094, " + + "but was " + result1.bitLength()); + } finally { + elapsedTimeInNanos = System.nanoTime() - elapsedTimeInNanos; + } + + LongSummaryStatistics userTimeStatistics = getStatistics(userTime); + LongSummaryStatistics cpuTimeStatistics = getStatistics(cpuTime); + LongSummaryStatistics memoryAllocationStatistics = getStatistics(bytes); + System.out.println("real " + formatTime(elapsedTimeInNanos)); + System.out.println("user " + formatTime(userTimeStatistics.getSum())); + System.out.println("sys " + + formatTime(cpuTimeStatistics.getSum() - userTimeStatistics.getSum())); + System.out.println("mem " + formatMemory(memoryAllocationStatistics.getSum(), 1)); + } + + private static LongSummaryStatistics getStatistics(Map timeMap) { + return timeMap.entrySet() + .stream() + .peek(entry -> { + long timeInMs = (counterExtractorMap.get(timeMap) + .applyAsLong(entry.getKey().getId()) + - entry.getValue().get()); + entry.getValue().set(timeInMs); + }) + .peek(BigIntegerMersennePrimeMultiply::printTime) + .map(Map.Entry::getValue) + .mapToLong(AtomicLong::get) + .summaryStatistics(); + } + + private static void printTime(Map.Entry threadCounter) { + if (DEBUG) + System.out.printf("%s %d%n", threadCounter.getKey(), threadCounter.getValue() + .get()); + } + + private static void addCounters(Thread thread) { + counterExtractorMap.forEach((map, timeExtractor) -> add(map, thread, timeExtractor)); + } + + private static void add(Map time, Thread thread, + LongUnaryOperator timeExtractor) { + time.put(thread, new AtomicLong(timeExtractor.applyAsLong(thread.getId()))); + } + + private static void resetAllCounters() { + counterExtractorMap.forEach(BigIntegerMersennePrimeMultiply::resetTimes); + } + + private static void resetTimes(Map timeMap, LongUnaryOperator timeMethod) { + timeMap.forEach((thread, time) -> + time.set(timeMethod.applyAsLong(thread.getId()))); + } + + private static final Map userTime = + new ConcurrentHashMap<>(); + private static final Map cpuTime = + new ConcurrentHashMap<>(); + private static final Map bytes = + new ConcurrentHashMap<>(); + private static final ThreadMXBean tmb = ManagementFactory.getThreadMXBean(); + + private static final Map, LongUnaryOperator> counterExtractorMap = + new IdentityHashMap<>(); + + static { + counterExtractorMap.put(userTime, tmb::getThreadUserTime); + counterExtractorMap.put(cpuTime, tmb::getThreadCpuTime); + counterExtractorMap.put(bytes, BigIntegerMersennePrimeMultiply::threadAllocatedBytes); + } + + public final ForkJoinWorkerThread newThread(ForkJoinPool pool) { + ForkJoinWorkerThread thread = defaultForkJoinWorkerThreadFactory.newThread(pool); + addCounters(thread); + return thread; + } + + private static final String[] SIGNATURE = new String[]{long.class.getName()}; + private static final MBeanServer mBeanServer; + private static final ObjectName name; + + static { + try { + name = new ObjectName(ManagementFactory.THREAD_MXBEAN_NAME); + mBeanServer = ManagementFactory.getPlatformMBeanServer(); + } catch (MalformedObjectNameException e) { + throw new ExceptionInInitializerError(e); + } + } + + public static long threadAllocatedBytes(long threadId) { + try { + return (long) mBeanServer.invoke( + name, + "getThreadAllocatedBytes", + new Object[]{threadId}, + SIGNATURE + ); + } catch (Exception e) { + throw new IllegalArgumentException(e); + } + } + + public static String formatMemory(double bytes, int decimals) { + double val; + String unitStr; + if (bytes < 1024) { + val = bytes; + unitStr = "B"; + } else if (bytes < 1024 * 1024) { + val = bytes / 1024; + unitStr = "KB"; + } else if (bytes < 1024 * 1024 * 1024) { + val = bytes / (1024 * 1024); + unitStr = "MB"; + } else if (bytes < 1024 * 1024 * 1024 * 1024L) { + val = bytes / (1024 * 1024 * 1024L); + unitStr = "GB"; + } else { + val = bytes / (1024 * 1024 * 1024 * 1024L); + unitStr = "TB"; + } + return String.format(Locale.US, "%." + decimals + "f%s", val, unitStr); + } + + public static String formatTime(long nanos) { + if (nanos < 0) nanos = 0; + long timeInMs = TimeUnit.NANOSECONDS.toMillis(nanos); + long minutes = timeInMs / 60_000; + double remainingMs = (timeInMs % 60_000) / 1000.0; + return String.format(Locale.US, "%dm%.3fs", minutes, remainingMs); + } +} \ No newline at end of file diff --git a/test/micro/org/openjdk/bench/java/math/BigIntegerParallelMultiply.java b/test/micro/org/openjdk/bench/java/math/BigIntegerParallelMultiply.java new file mode 100644 index 00000000000..92a1c5a8237 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/math/BigIntegerParallelMultiply.java @@ -0,0 +1,61 @@ +package org.openjdk.bench.java.math; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +import java.math.BigInteger; +import java.util.concurrent.TimeUnit; +import java.util.function.BinaryOperator; + +/** + * Benchmark for checking performance difference between + * sequential and parallel multiply methods in BigInteger, + * using a large Fibonacci calculation of up to n = 100 million. + * + * @author Heinz Kabutz, heinz@javaspecialists.eu + */ +@BenchmarkMode(Mode.SingleShotTime) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@Fork(value = 2) +@Warmup(iterations = 2) +@Measurement(iterations = 2) // only 2 iterations because each one takes very long +@State(Scope.Thread) +public class BigIntegerParallelMultiply { + private static BigInteger fibonacci(int n, BinaryOperator multiplyOperator) { + if (n == 0) return BigInteger.ZERO; + if (n == 1) return BigInteger.ONE; + + int half = (n + 1) / 2; + BigInteger f0 = fibonacci(half - 1, multiplyOperator); + BigInteger f1 = fibonacci(half, multiplyOperator); + if (n % 2 == 1) { + BigInteger b0 = multiplyOperator.apply(f0, f0); + BigInteger b1 = multiplyOperator.apply(f1, f1); + return b0.add(b1); + } else { + BigInteger b0 = f0.shiftLeft(1).add(f1); + return multiplyOperator.apply(b0, f1); + } + } + + @Param({"1000000", "10000000", "100000000"}) + private int n; + + @Benchmark + public void multiply() { + fibonacci(n, BigInteger::multiply); + } + + @Benchmark + public void parallelMultiply() { + fibonacci(n, BigInteger::parallelMultiply); + } +} \ No newline at end of file -- GitLab From 4032fe76dccb6da85927361aee7ceedcdb758e89 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Fri, 11 Feb 2022 21:52:16 +0000 Subject: [PATCH 046/203] 8281238: TYPE_USE annotations not printed in correct position in toString output Reviewed-by: vromero --- .../share/classes/com/sun/tools/javac/code/Type.java | 12 ++++++++++-- test/langtools/tools/javac/patterns/Annotations.java | 10 +++++----- .../tools/javac/tree/ArrayTypeToString.java | 6 +++--- .../langtools/tools/javac/tree/ArrayTypeToString.out | 2 +- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java index 3cf34052300..86851fa8cb6 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java @@ -1038,8 +1038,16 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons appendAnnotationsString(buf); buf.append(className(tsym, false)); } else { - appendAnnotationsString(buf); - buf.append(className(tsym, true)); + if (isAnnotated()) { + if (!tsym.packge().isUnnamed()) { + buf.append(tsym.packge()); + buf.append("."); + } + appendAnnotationsString(buf); + buf.append(tsym.name); + } else { + buf.append(className(tsym, true)); + } } if (getTypeArguments().nonEmpty()) { diff --git a/test/langtools/tools/javac/patterns/Annotations.java b/test/langtools/tools/javac/patterns/Annotations.java index 8c9062fa427..324f07945dd 100644 --- a/test/langtools/tools/javac/patterns/Annotations.java +++ b/test/langtools/tools/javac/patterns/Annotations.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8256266 + * @bug 8256266 8281238 * @summary Verify annotations work correctly on binding variables * @library /tools/javac/lib * @modules java.compiler @@ -114,11 +114,11 @@ public class Annotations extends JavacTestingAbstractProcessor { } case "dta" -> { expectedDeclAnnos = "@Annotations.DTA"; - expectedType = "@Annotations.DTA java.lang.String"; + expectedType = "java.lang.@Annotations.DTA String"; } case "ta" -> { expectedDeclAnnos = ""; - expectedType = "@Annotations.TA java.lang.String"; + expectedType = "java.lang.@Annotations.TA String"; } default -> { throw new AssertionError("Unexpected variable: " + var); @@ -133,7 +133,7 @@ public class Annotations extends JavacTestingAbstractProcessor { String type = varType.toString(); if (!expectedType.equals(type)) { throw new AssertionError("Unexpected type: " + type + - " for: " + var.getName()); + " for: " + var.getName() + " expected " + expectedType); } return super.visitInstanceOf(node, p); } diff --git a/test/langtools/tools/javac/tree/ArrayTypeToString.java b/test/langtools/tools/javac/tree/ArrayTypeToString.java index 9d2275ab26f..eac8f345bef 100644 --- a/test/langtools/tools/javac/tree/ArrayTypeToString.java +++ b/test/langtools/tools/javac/tree/ArrayTypeToString.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8068737 + * @bug 8068737 8281238 * @summary Tests ArrayType.toString with type annotations present * @modules jdk.compiler/com.sun.tools.javac.code * @library /tools/javac/lib @@ -66,7 +66,7 @@ public class ArrayTypeToString extends JavacTestingAbstractProcessor { // Normalize output by removing whitespace s = s.replaceAll("\\s", ""); - // Expected: "@Foo(0)java.lang.String@Foo(3)[]@Foo(2)[]@Foo(1)[]" + // Expected: "java.lang.@Foo(0)String@Foo(1)[]@Foo(2)[]@Foo(3)[]" processingEnv.getMessager().printNote(s); } } diff --git a/test/langtools/tools/javac/tree/ArrayTypeToString.out b/test/langtools/tools/javac/tree/ArrayTypeToString.out index 375a6f28949..ca3db541c2d 100644 --- a/test/langtools/tools/javac/tree/ArrayTypeToString.out +++ b/test/langtools/tools/javac/tree/ArrayTypeToString.out @@ -1 +1 @@ -- compiler.note.proc.messager: @Foo(0)java.lang.String@Foo(1)[]@Foo(2)[]@Foo(3)[] +- compiler.note.proc.messager: java.lang.@Foo(0)String@Foo(1)[]@Foo(2)[]@Foo(3)[] -- GitLab From c3179a8760019b5954e344bf0d2775e1e1968f32 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Fri, 11 Feb 2022 23:24:08 +0000 Subject: [PATCH 047/203] 8281462: Annotation toString output for enum not reusable for source input Reviewed-by: mchung --- .../AnnotationInvocationHandler.java | 30 ++++++++++------ .../annotation/AnnotationToStringTest.java | 21 +++++++++--- .../EnumTypeMismatchTest.java | 4 +-- .../TestConstructorParameterAnnotations.java | 34 +++++++++---------- .../GetAnnotatedNestedSuperclass.java | 12 +++---- ...stConstructorParameterTypeAnnotations.java | 18 +++++----- .../typeAnnotations/TestObjectMethods.java | 4 +-- .../reflect/records/RecordReflectionTest.java | 6 ++-- 8 files changed, 74 insertions(+), 55 deletions(-) diff --git a/src/java.base/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java b/src/java.base/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java index c4cc4ccdec7..74eec629b3e 100644 --- a/src/java.base/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java +++ b/src/java.base/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -145,7 +145,9 @@ class AnnotationInvocationHandler implements InvocationHandler, Serializable { private String toStringImpl() { StringBuilder result = new StringBuilder(128); result.append('@'); - result.append(type.getName()); + // Guard against null canonical name; shouldn't happen + result.append(Objects.toString(type.getCanonicalName(), + "")); result.append('('); boolean firstMember = true; Set> entries = memberValues.entrySet(); @@ -189,6 +191,10 @@ class AnnotationInvocationHandler implements InvocationHandler, Serializable { return toSourceString((long) value); else if (type == Byte.class) return toSourceString((byte) value); + else if (value instanceof Enum v) + // Predicate above covers enum constants, including + // those with specialized class bodies. + return toSourceString(v); else return value.toString(); } else { @@ -219,6 +225,10 @@ class AnnotationInvocationHandler implements InvocationHandler, Serializable { stringStream = Arrays.stream((String[])value). map(AnnotationInvocationHandler::toSourceString); + else if (type.getComponentType().isEnum()) + stringStream = + Arrays.stream((Enum[])value). + map(AnnotationInvocationHandler::toSourceString); else stringStream = Arrays.stream((Object[])value).map(Objects::toString); @@ -231,15 +241,9 @@ class AnnotationInvocationHandler implements InvocationHandler, Serializable { * string representation of an annotation. */ private static String toSourceString(Class clazz) { - Class finalComponent = clazz; - StringBuilder arrayBrackets = new StringBuilder(); - - while(finalComponent.isArray()) { - finalComponent = finalComponent.getComponentType(); - arrayBrackets.append("[]"); - } - - return finalComponent.getName() + arrayBrackets.toString() + ".class"; + // Guard against null canonical name; shouldn't happen + return Objects.toString(clazz.getCanonicalName(), + "") + ".class"; } private static String toSourceString(float f) { @@ -307,6 +311,10 @@ class AnnotationInvocationHandler implements InvocationHandler, Serializable { return String.valueOf(ell) + "L"; } + private static String toSourceString(Enum enumConstant) { + return enumConstant.name(); + } + /** * Return a string suitable for use in the string representation * of an annotation. diff --git a/test/jdk/java/lang/annotation/AnnotationToStringTest.java b/test/jdk/java/lang/annotation/AnnotationToStringTest.java index e9fcf57014e..71551193a3f 100644 --- a/test/jdk/java/lang/annotation/AnnotationToStringTest.java +++ b/test/jdk/java/lang/annotation/AnnotationToStringTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,8 @@ // test/langtools/tools/javac/processing/model/element/AnnotationToStringTest.java import java.lang.annotation.*; -import java.lang.reflect.*; +import java.lang.reflect.Field; +import javax.lang.model.element.Modifier; import java.util.*; /** @@ -160,6 +161,11 @@ public class AnnotationToStringTest { } static class ArrayAnnotationHost { + @ExpectedString( + "@EnumValue(NON_SEALED)") // toString and name differ + @EnumValue(Modifier.NON_SEALED) + public int f00; + @ExpectedString( "@BooleanArray({true, false, true})") @BooleanArray({true, false, true}) @@ -213,8 +219,8 @@ public class AnnotationToStringTest { public Class[] f9; @ExpectedString( - "@EnumArray({SOURCE})") - @EnumArray({RetentionPolicy.SOURCE}) + "@EnumArray({SEALED, NON_SEALED, PUBLIC})") + @EnumArray({Modifier.SEALED, Modifier.NON_SEALED, Modifier.PUBLIC}) public RetentionPolicy[] f10; } } @@ -223,6 +229,11 @@ public class AnnotationToStringTest { class Obj {} +@Retention(RetentionPolicy.RUNTIME) +@interface EnumValue { + Modifier value(); +} + @Retention(RetentionPolicy.RUNTIME) @interface ExpectedString { String value(); @@ -285,7 +296,7 @@ class Obj {} @Retention(RetentionPolicy.RUNTIME) @interface EnumArray { - RetentionPolicy[] value(); + Modifier[] value(); } @Retention(RetentionPolicy.RUNTIME) diff --git a/test/jdk/java/lang/annotation/AnnotationTypeMismatchException/EnumTypeMismatchTest.java b/test/jdk/java/lang/annotation/AnnotationTypeMismatchException/EnumTypeMismatchTest.java index dd787e727b4..5000aa0ee65 100644 --- a/test/jdk/java/lang/annotation/AnnotationTypeMismatchException/EnumTypeMismatchTest.java +++ b/test/jdk/java/lang/annotation/AnnotationTypeMismatchException/EnumTypeMismatchTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,7 +61,7 @@ public class EnumTypeMismatchTest { } catch (AnnotationTypeMismatchException e) { if (!e.element().getName().equals("value")) { throw new IllegalStateException("Unexpected element: " + e.element()); - } else if (!e.foundType().equals("@" + AnAnnotation.class.getName() + "(" + AnEnum.VALUE.name() + ")")) { + } else if (!e.foundType().equals("@" + AnAnnotation.class.getCanonicalName() + "(" + AnEnum.VALUE.name() + ")")) { throw new IllegalStateException("Unexpected type: " + e.foundType()); } } diff --git a/test/jdk/java/lang/annotation/TestConstructorParameterAnnotations.java b/test/jdk/java/lang/annotation/TestConstructorParameterAnnotations.java index f36474ef3b7..3e39cdb6e8d 100644 --- a/test/jdk/java/lang/annotation/TestConstructorParameterAnnotations.java +++ b/test/jdk/java/lang/annotation/TestConstructorParameterAnnotations.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -129,21 +129,21 @@ public class TestConstructorParameterAnnotations { @ExpectedGetParameterAnnotations( "[[], " + - "[@TestConstructorParameterAnnotations$MarkerAnnotation(1)]]") + "[@TestConstructorParameterAnnotations.MarkerAnnotation(1)]]") @ExpectedParameterAnnotations({ "null", - "@TestConstructorParameterAnnotations$MarkerAnnotation(1)"}) + "@TestConstructorParameterAnnotations.MarkerAnnotation(1)"}) public class NestedClass1 { public NestedClass1(@MarkerAnnotation(1) int parameter) {} } @ExpectedGetParameterAnnotations( "[[], " + - "[@TestConstructorParameterAnnotations$MarkerAnnotation(2)], " + + "[@TestConstructorParameterAnnotations.MarkerAnnotation(2)], " + "[]]") @ExpectedParameterAnnotations({ "null", - "@TestConstructorParameterAnnotations$MarkerAnnotation(2)", + "@TestConstructorParameterAnnotations.MarkerAnnotation(2)", "null"}) public class NestedClass2 { public NestedClass2(@MarkerAnnotation(2) int parameter1, @@ -152,11 +152,11 @@ public class TestConstructorParameterAnnotations { @ExpectedGetParameterAnnotations( "[[], " + - "[@TestConstructorParameterAnnotations$MarkerAnnotation(3)], " + + "[@TestConstructorParameterAnnotations.MarkerAnnotation(3)], " + "[]]") @ExpectedParameterAnnotations({ "null", - "@TestConstructorParameterAnnotations$MarkerAnnotation(3)", + "@TestConstructorParameterAnnotations.MarkerAnnotation(3)", "null"}) public class NestedClass3 { public

NestedClass3(@MarkerAnnotation(3) P parameter1, @@ -165,11 +165,11 @@ public class TestConstructorParameterAnnotations { @ExpectedGetParameterAnnotations( "[[], " + - "[@TestConstructorParameterAnnotations$MarkerAnnotation(4)], " + + "[@TestConstructorParameterAnnotations.MarkerAnnotation(4)], " + "[]]") @ExpectedParameterAnnotations({ "null", - "@TestConstructorParameterAnnotations$MarkerAnnotation(4)", + "@TestConstructorParameterAnnotations.MarkerAnnotation(4)", "null"}) public class NestedClass4 { public NestedClass4(@MarkerAnnotation(4) P parameter1, @@ -183,18 +183,18 @@ public class TestConstructorParameterAnnotations { } @ExpectedGetParameterAnnotations( - "[[@TestConstructorParameterAnnotations$MarkerAnnotation(1)]]") + "[[@TestConstructorParameterAnnotations.MarkerAnnotation(1)]]") @ExpectedParameterAnnotations({ - "@TestConstructorParameterAnnotations$MarkerAnnotation(1)"}) + "@TestConstructorParameterAnnotations.MarkerAnnotation(1)"}) public static class StaticNestedClass1 { public StaticNestedClass1(@MarkerAnnotation(1) int parameter) {} } @ExpectedGetParameterAnnotations( - "[[@TestConstructorParameterAnnotations$MarkerAnnotation(2)], " + + "[[@TestConstructorParameterAnnotations.MarkerAnnotation(2)], " + "[]]") @ExpectedParameterAnnotations({ - "@TestConstructorParameterAnnotations$MarkerAnnotation(2)", + "@TestConstructorParameterAnnotations.MarkerAnnotation(2)", "null"}) public static class StaticNestedClass2 { public StaticNestedClass2(@MarkerAnnotation(2) int parameter1, @@ -202,10 +202,10 @@ public class TestConstructorParameterAnnotations { } @ExpectedGetParameterAnnotations( - "[[@TestConstructorParameterAnnotations$MarkerAnnotation(3)], " + + "[[@TestConstructorParameterAnnotations.MarkerAnnotation(3)], " + "[]]") @ExpectedParameterAnnotations({ - "@TestConstructorParameterAnnotations$MarkerAnnotation(3)", + "@TestConstructorParameterAnnotations.MarkerAnnotation(3)", "null"}) public static class StaticNestedClass3 { public

StaticNestedClass3(@MarkerAnnotation(3) P parameter1, @@ -213,10 +213,10 @@ public class TestConstructorParameterAnnotations { } @ExpectedGetParameterAnnotations( - "[[@TestConstructorParameterAnnotations$MarkerAnnotation(4)], " + + "[[@TestConstructorParameterAnnotations.MarkerAnnotation(4)], " + "[]]") @ExpectedParameterAnnotations({ - "@TestConstructorParameterAnnotations$MarkerAnnotation(4)", + "@TestConstructorParameterAnnotations.MarkerAnnotation(4)", "null"}) public static class StaticNestedClass4 { public StaticNestedClass4(@MarkerAnnotation(4) P parameter1, diff --git a/test/jdk/java/lang/annotation/typeAnnotations/GetAnnotatedNestedSuperclass.java b/test/jdk/java/lang/annotation/typeAnnotations/GetAnnotatedNestedSuperclass.java index a667a2e2c23..8603b7f9f19 100644 --- a/test/jdk/java/lang/annotation/typeAnnotations/GetAnnotatedNestedSuperclass.java +++ b/test/jdk/java/lang/annotation/typeAnnotations/GetAnnotatedNestedSuperclass.java @@ -64,31 +64,31 @@ public class GetAnnotatedNestedSuperclass { public static void main(String[] args) throws Exception { AnnotatedType x = Y.class.getAnnotatedSuperclass(); - assertEquals(Arrays.toString(x.getAnnotations()), "[@GetAnnotatedNestedSuperclass$A()]"); + assertEquals(Arrays.toString(x.getAnnotations()), "[@GetAnnotatedNestedSuperclass.A()]"); AnnotatedParameterizedType xpt = (AnnotatedParameterizedType) x; { AnnotatedType arg = xpt.getAnnotatedActualTypeArguments()[0]; assertEquals( - Arrays.toString(arg.getAnnotations()), "[@GetAnnotatedNestedSuperclass$B()]"); + Arrays.toString(arg.getAnnotations()), "[@GetAnnotatedNestedSuperclass.B()]"); } { AnnotatedType arg = xpt.getAnnotatedActualTypeArguments()[1]; assertEquals( - Arrays.toString(arg.getAnnotations()), "[@GetAnnotatedNestedSuperclass$C()]"); + Arrays.toString(arg.getAnnotations()), "[@GetAnnotatedNestedSuperclass.C()]"); } { AnnotatedType arg = xpt.getAnnotatedActualTypeArguments()[2]; assertEquals( - Arrays.toString(arg.getAnnotations()), "[@GetAnnotatedNestedSuperclass$D()]"); + Arrays.toString(arg.getAnnotations()), "[@GetAnnotatedNestedSuperclass.D()]"); AnnotatedType nestedArg = ((AnnotatedParameterizedType) arg).getAnnotatedActualTypeArguments()[0]; assertEquals( Arrays.toString(nestedArg.getAnnotations()), - "[@GetAnnotatedNestedSuperclass$E()]"); + "[@GetAnnotatedNestedSuperclass.E()]"); } } - private static void assertEquals(Object expected, Object actual) { + private static void assertEquals(Object actual, Object expected) { if (!Objects.equals(expected, actual)) { throw new AssertionError("expected: " + expected + "; actual=" + actual); } diff --git a/test/jdk/java/lang/annotation/typeAnnotations/TestConstructorParameterTypeAnnotations.java b/test/jdk/java/lang/annotation/typeAnnotations/TestConstructorParameterTypeAnnotations.java index 21934b3247d..a90aa36ba09 100644 --- a/test/jdk/java/lang/annotation/typeAnnotations/TestConstructorParameterTypeAnnotations.java +++ b/test/jdk/java/lang/annotation/typeAnnotations/TestConstructorParameterTypeAnnotations.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -128,7 +128,7 @@ public class TestConstructorParameterTypeAnnotations { @ExpectedGetParameterAnnotations("[[], []]") @ExpectedParameterTypeAnnotations({ "null", - "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(1)"}) + "@TestConstructorParameterTypeAnnotations.MarkerTypeAnnotation(1)"}) public class NestedClass1 { public NestedClass1(@MarkerTypeAnnotation(1) int parameter) {} } @@ -136,7 +136,7 @@ public class TestConstructorParameterTypeAnnotations { @ExpectedGetParameterAnnotations("[[], [], []]") @ExpectedParameterTypeAnnotations({ "null", - "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(2)", + "@TestConstructorParameterTypeAnnotations.MarkerTypeAnnotation(2)", "null"}) public class NestedClass2 { public NestedClass2(@MarkerTypeAnnotation(2) int parameter1, @@ -146,7 +146,7 @@ public class TestConstructorParameterTypeAnnotations { @ExpectedGetParameterAnnotations("[[], [], []]") @ExpectedParameterTypeAnnotations({ "null", - "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(3)", + "@TestConstructorParameterTypeAnnotations.MarkerTypeAnnotation(3)", "null"}) public class NestedClass3 { public

NestedClass3(@MarkerTypeAnnotation(3) P parameter1, @@ -156,7 +156,7 @@ public class TestConstructorParameterTypeAnnotations { @ExpectedGetParameterAnnotations("[[], [], []]") @ExpectedParameterTypeAnnotations({ "null", - "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(4)", + "@TestConstructorParameterTypeAnnotations.MarkerTypeAnnotation(4)", "null"}) public class NestedClass4 { public NestedClass4(@MarkerTypeAnnotation(4) P parameter1, @@ -171,14 +171,14 @@ public class TestConstructorParameterTypeAnnotations { @ExpectedGetParameterAnnotations("[[]]") @ExpectedParameterTypeAnnotations({ - "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(1)"}) + "@TestConstructorParameterTypeAnnotations.MarkerTypeAnnotation(1)"}) public static class StaticNestedClass1 { public StaticNestedClass1(@MarkerTypeAnnotation(1) int parameter) {} } @ExpectedGetParameterAnnotations("[[], []]") @ExpectedParameterTypeAnnotations({ - "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(2)", + "@TestConstructorParameterTypeAnnotations.MarkerTypeAnnotation(2)", "null"}) public static class StaticNestedClass2 { public StaticNestedClass2(@MarkerTypeAnnotation(2) int parameter1, @@ -187,7 +187,7 @@ public class TestConstructorParameterTypeAnnotations { @ExpectedGetParameterAnnotations("[[], []]") @ExpectedParameterTypeAnnotations({ - "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(3)", + "@TestConstructorParameterTypeAnnotations.MarkerTypeAnnotation(3)", "null"}) public static class StaticNestedClass3 { public

StaticNestedClass3(@MarkerTypeAnnotation(3) P parameter1, @@ -196,7 +196,7 @@ public class TestConstructorParameterTypeAnnotations { @ExpectedGetParameterAnnotations("[[], []]") @ExpectedParameterTypeAnnotations({ - "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(4)", + "@TestConstructorParameterTypeAnnotations.MarkerTypeAnnotation(4)", "null"}) public static class StaticNestedClass4 { public StaticNestedClass4(@MarkerTypeAnnotation(4) P parameter1, diff --git a/test/jdk/java/lang/annotation/typeAnnotations/TestObjectMethods.java b/test/jdk/java/lang/annotation/typeAnnotations/TestObjectMethods.java index dea8f42db6a..8349d48af72 100644 --- a/test/jdk/java/lang/annotation/typeAnnotations/TestObjectMethods.java +++ b/test/jdk/java/lang/annotation/typeAnnotations/TestObjectMethods.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -177,7 +177,7 @@ public class TestObjectMethods { } } - private static final Pattern annotationRegex = Pattern.compile("@TestObjectMethods\\$AnnotType\\((\\p{Digit})+\\)"); + private static final Pattern annotationRegex = Pattern.compile("@TestObjectMethods\\.AnnotType\\((\\p{Digit})+\\)"); static void testGetAnnotations(Class clazz, boolean annotationsExpectedOnMethods) { System.err.println("Testing getAnnotations on methods of class " + clazz.getName()); diff --git a/test/jdk/java/lang/reflect/records/RecordReflectionTest.java b/test/jdk/java/lang/reflect/records/RecordReflectionTest.java index 5968b4813ea..23b707663a9 100644 --- a/test/jdk/java/lang/reflect/records/RecordReflectionTest.java +++ b/test/jdk/java/lang/reflect/records/RecordReflectionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -162,7 +162,7 @@ public class RecordReflectionTest { RecordComponent rc = recordClass.getRecordComponents()[0]; Annotation[] annos = rc.getAnnotations(); assertEquals(annos.length, 1); - assertEquals(annos[0].toString(), "@RecordReflectionTest$RCA()"); + assertEquals(annos[0].toString(), "@RecordReflectionTest.RCA()"); Field f = recordClass.getDeclaredField("i"); assertEquals(f.getAnnotations().length, 1); @@ -181,7 +181,7 @@ public class RecordReflectionTest { AnnotatedType at = rc.getAnnotatedType(); Annotation[] annos = at.getAnnotations(); assertEquals(annos.length, 1); - assertEquals(annos[0].toString(), "@RecordReflectionTest$TYPE_USE()"); + assertEquals(annos[0].toString(), "@RecordReflectionTest.TYPE_USE()"); Field f = recordClass.getDeclaredField("i"); assertEquals(f.getAnnotatedType().getAnnotations().length, 1); -- GitLab From 6fdfe0458df989a7946b4f52a3023e8a39fb3bbb Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Sat, 12 Feb 2022 01:33:41 +0000 Subject: [PATCH 048/203] 8281674: tools/javac/annotations/typeAnnotations/classfile/AnonymousExtendsTest.java fails with AssertionError Reviewed-by: vromero --- .../typeAnnotations/classfile/AnonymousExtendsTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousExtendsTest.java b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousExtendsTest.java index 063afbf43f3..0a99008c643 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousExtendsTest.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousExtendsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8146167 + * @bug 8146167 8281674 * @summary Anonymous type declarations drop supertype type parameter annotations * @run main AnonymousExtendsTest */ @@ -52,10 +52,10 @@ public class AnonymousExtendsTest { public void testIt() { checkAnnotations(TestClass.class.getAnnotatedSuperclass(), - "[@AnonymousExtendsTest$TA(1)],[@AnonymousExtendsTest$TA(2)]"); + "[@AnonymousExtendsTest.TA(1)],[@AnonymousExtendsTest.TA(2)]"); checkAnnotations(new @TA(3) ArrayList<@TA(4) List>() { }.getClass().getAnnotatedSuperclass(), - "[@AnonymousExtendsTest$TA(3)],[@AnonymousExtendsTest$TA(4)]"); + "[@AnonymousExtendsTest.TA(3)],[@AnonymousExtendsTest.TA(4)]"); } public void checkAnnotations(AnnotatedType type, String expected) { -- GitLab From aa918a6ec4cd1356efd481c6f6fa94959f94f7b3 Mon Sep 17 00:00:00 2001 From: Alexander Zuev Date: Sat, 12 Feb 2022 09:26:47 +0000 Subject: [PATCH 049/203] 8281033: Improve ImageCheckboxTest to test all available LaF Reviewed-by: serb --- .../ImageCheckboxFocus/ImageCheckboxTest.java | 59 +++++++++++++++---- 1 file changed, 48 insertions(+), 11 deletions(-) diff --git a/test/jdk/javax/swing/JCheckBox/ImageCheckboxFocus/ImageCheckboxTest.java b/test/jdk/javax/swing/JCheckBox/ImageCheckboxFocus/ImageCheckboxTest.java index c93715d8087..844692bf454 100644 --- a/test/jdk/javax/swing/JCheckBox/ImageCheckboxFocus/ImageCheckboxTest.java +++ b/test/jdk/javax/swing/JCheckBox/ImageCheckboxFocus/ImageCheckboxTest.java @@ -23,13 +23,14 @@ import java.awt.Color; import java.awt.Component; -import java.awt.Dimension; import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.File; import javax.imageio.ImageIO; import javax.swing.Icon; import javax.swing.JCheckBox; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; /* * @test @@ -43,18 +44,43 @@ import javax.swing.JCheckBox; public class ImageCheckboxTest { public static void main(String[] args) throws Exception { - new ImageCheckboxTest().performTest(); + ImageCheckboxTest test = new ImageCheckboxTest(); + boolean passed = true; + // There are bugs found in various LaFs that needs to be fixed + // to enable testing there + String[] skip = { + "GTK+", // JDK-8281580 + "Nimbus" // JDK-8281581 + }; + testloop: + for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) { + for (String s : skip) { + if (s.equals(laf.getName())) { + continue testloop; + } + } + passed = passed && test.performTest(laf); + } + + if(!passed) { + throw new RuntimeException("Test failed"); + } } - public void performTest() throws Exception { + public boolean performTest(UIManager.LookAndFeelInfo laf) throws Exception { BufferedImage imageNoFocus = new BufferedImage(100, 50, BufferedImage.TYPE_INT_ARGB); BufferedImage imageFocus = new BufferedImage(100, 50, BufferedImage.TYPE_INT_ARGB); BufferedImage imageFocusNotPainted = new BufferedImage(100, 50, BufferedImage.TYPE_INT_ARGB); + boolean success = true; - + try { + UIManager.setLookAndFeel(laf.getClassName()); + } catch (UnsupportedLookAndFeelException ulaf) { + return true; + } CustomCheckBox checkbox = new CustomCheckBox("Test", new MyIcon(Color.GREEN)); checkbox.setFocusPainted(true); checkbox.setSize(100, 50); @@ -64,21 +90,32 @@ public class ImageCheckboxTest { checkbox.paint(imageFocus.createGraphics()); if (Util.compareBufferedImages(imageFocus, imageNoFocus)) { - ImageIO.write(imageFocus, "png", new File("imageFocus.png")); - ImageIO.write(imageNoFocus, "png", new File("imageNoFocus.png")); - throw new Exception("Changing focus is not visualized"); + File folder = new File(laf.getName()); + if (!folder.exists()) { + folder.mkdir(); + } + ImageIO.write(imageFocus, "png", new File(folder, "/imageFocus.png")); + ImageIO.write(imageNoFocus, "png", new File(folder, "/imageNoFocus.png")); + System.err.println(laf.getName() + ": Changing of focus is not visualized"); + success = false; } checkbox.setFocusPainted(false); checkbox.paint(imageFocusNotPainted.createGraphics()); if (!Util.compareBufferedImages(imageFocusNotPainted, imageNoFocus)) { + File folder = new File(laf.getName()); + if (!folder.exists()) { + folder.mkdir(); + } ImageIO.write(imageFocusNotPainted, "png", - new File("imageFocusNotPainted.png")); - ImageIO.write(imageFocus, "png", new File("imageFocus.png")); - ImageIO.write(imageNoFocus, "png", new File("imageNoFocus.png")); - throw new Exception("setFocusPainted(false) is ignored"); + new File(folder,"imageFocusNotPainted.png")); + ImageIO.write(imageFocus, "png", new File(folder, "imageFocus.png")); + ImageIO.write(imageNoFocus, "png", new File(folder, "imageNoFocus.png")); + System.err.println(laf.getName() + ": setFocusPainted(false) is ignored"); + success = false; } + return success; } class MyIcon implements Icon { -- GitLab From 58dae60da0711c4ae0cb23f8ce2328e051d603b2 Mon Sep 17 00:00:00 2001 From: Alexey Bakhtin Date: Sat, 12 Feb 2022 11:54:22 +0000 Subject: [PATCH 050/203] 8274524: SSLSocket.close() hangs if it is called during the ssl handshake Reviewed-by: xuelei --- .../sun/security/ssl/SSLSocketImpl.java | 17 +++ .../SSLSocketImpl/ClientSocketCloseHang.java | 134 ++++++++++++++++++ 2 files changed, 151 insertions(+) create mode 100644 test/jdk/sun/security/ssl/SSLSocketImpl/ClientSocketCloseHang.java diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java index e55419d70ee..842cef11911 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java @@ -107,6 +107,11 @@ public final class SSLSocketImpl private static final boolean trustNameService = Utilities.getBooleanProperty("jdk.tls.trustNameService", false); + /* + * Default timeout to skip bytes from the open socket + */ + private static final int DEFAULT_SKIP_TIMEOUT = 1; + /** * Package-private constructor used to instantiate an unconnected * socket. @@ -1781,9 +1786,21 @@ public final class SSLSocketImpl if (conContext.inputRecord instanceof SSLSocketInputRecord inputRecord && isConnected) { if (appInput.readLock.tryLock()) { + int soTimeout = getSoTimeout(); try { + // deplete could hang on the skip operation + // in case of infinite socket read timeout. + // Change read timeout to avoid deadlock. + // This workaround could be replaced later + // with the right synchronization + if (soTimeout == 0) + setSoTimeout(DEFAULT_SKIP_TIMEOUT); inputRecord.deplete(false); + } catch (java.net.SocketTimeoutException stEx) { + // skip timeout exception during deplete } finally { + if (soTimeout == 0) + setSoTimeout(soTimeout); appInput.readLock.unlock(); } } diff --git a/test/jdk/sun/security/ssl/SSLSocketImpl/ClientSocketCloseHang.java b/test/jdk/sun/security/ssl/SSLSocketImpl/ClientSocketCloseHang.java new file mode 100644 index 00000000000..249aab13291 --- /dev/null +++ b/test/jdk/sun/security/ssl/SSLSocketImpl/ClientSocketCloseHang.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8274524 + * @summary 8274524: SSLSocket.close() hangs if it is called during the ssl handshake + * @library /javax/net/ssl/templates + * @run main/othervm ClientSocketCloseHang TLSv1.2 + * @run main/othervm ClientSocketCloseHang TLSv1.3 + */ + + +import javax.net.ssl.*; +import java.net.InetAddress; + +public class ClientSocketCloseHang implements SSLContextTemplate { + + public static void main(String[] args) throws Exception { + System.setProperty("jdk.tls.client.protocols", args[0]); + for (int i = 0; i<= 20; i++) { + System.err.println("==================================="); + System.err.println("loop " + i); + System.err.println("==================================="); + new ClientSocketCloseHang().test(); + } + } + + private void test() throws Exception { + SSLServerSocket listenSocket = null; + SSLSocket serverSocket = null; + ClientSocket clientSocket = null; + try { + SSLServerSocketFactory serversocketfactory = + createServerSSLContext().getServerSocketFactory(); + listenSocket = + (SSLServerSocket)serversocketfactory.createServerSocket(0); + listenSocket.setNeedClientAuth(false); + listenSocket.setEnableSessionCreation(true); + listenSocket.setUseClientMode(false); + + + System.err.println("Starting client"); + clientSocket = new ClientSocket(listenSocket.getLocalPort()); + clientSocket.start(); + + System.err.println("Accepting client requests"); + serverSocket = (SSLSocket) listenSocket.accept(); + + serverSocket.startHandshake(); + } finally { + if (clientSocket != null) { + clientSocket.close(); + } + if (listenSocket != null) { + listenSocket.close(); + } + + if (serverSocket != null) { + serverSocket.close(); + } + } + } + + private class ClientSocket extends Thread{ + int serverPort = 0; + SSLSocket clientSocket = null; + + public ClientSocket(int serverPort) { + this.serverPort = serverPort; + } + + @Override + public void run() { + try { + System.err.println( + "Connecting to server at port " + serverPort); + SSLSocketFactory sslSocketFactory = + createClientSSLContext().getSocketFactory(); + clientSocket = (SSLSocket)sslSocketFactory.createSocket( + InetAddress.getLocalHost(), serverPort); + clientSocket.setSoLinger(true, 3); + clientSocket.startHandshake(); + } catch (Exception e) { + } + } + + public void close() { + Thread t = new Thread() { + @Override + public void run() { + try { + if (clientSocket != null) { + clientSocket.close(); + } + } catch (Exception ex) { + } + } + }; + try { + // Close client connection + t.start(); + t.join(2000); // 2 sec + } catch (InterruptedException ex) { + return; + } + + if (t.isAlive()) { + throw new RuntimeException("SSL Client hangs on close"); + } + } + } +} + -- GitLab From 67077a04307b512219a46b6c4c274ce308ee46de Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Sat, 12 Feb 2022 13:08:39 +0000 Subject: [PATCH 051/203] 8278423: ExtendedDTraceProbes should be deprecated Reviewed-by: dholmes, hseigel, kvn, thartmann --- src/hotspot/share/runtime/arguments.cpp | 3 ++ src/hotspot/share/runtime/globals.hpp | 10 ++++--- src/java.base/share/man/java.1 | 28 +++++++++++++++---- .../CommandLine/VMDeprecatedOptions.java | 1 + .../7170638/SDTProbesGNULinuxTest.java | 4 ++- 5 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 7d0f1ddd4d3..952b96f537e 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -537,6 +537,7 @@ static SpecialFlag const special_jvm_flags[] = { #ifdef PRODUCT { "UseHeavyMonitors", JDK_Version::jdk(18), JDK_Version::jdk(19), JDK_Version::jdk(20) }, #endif + { "ExtendedDTraceProbes", JDK_Version::jdk(19), JDK_Version::jdk(20), JDK_Version::jdk(21) }, // --- Deprecated alias flags (see also aliased_jvm_flags) - sorted by obsolete_in then expired_in: { "DefaultMaxRAMFraction", JDK_Version::jdk(8), JDK_Version::undefined(), JDK_Version::undefined() }, @@ -2886,6 +2887,8 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m } } else if (match_option(option, "-XX:+ExtendedDTraceProbes")) { #if defined(DTRACE_ENABLED) + warning("Option ExtendedDTraceProbes was deprecated in version 19 and will likely be removed in a future release."); + warning("Use the combination of -XX:+DTraceMethodProbes, -XX:+DTraceAllocProbes and -XX:+DTraceMonitorProbes instead."); if (FLAG_SET_CMDLINE(ExtendedDTraceProbes, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index bc80a2eb45f..f45d259fd21 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1858,16 +1858,18 @@ const intx ObjectAlignmentInBytes = 8; "Pause and wait for keypress on exit if a debugger is attached") \ \ product(bool, ExtendedDTraceProbes, false, \ - "Enable performance-impacting dtrace probes") \ + "(Deprecated) Enable performance-impacting dtrace probes. " \ + "Use the combination of -XX:+DTraceMethodProbes, " \ + "-XX:+DTraceAllocProbes and -XX:+DTraceMonitorProbes instead.") \ \ product(bool, DTraceMethodProbes, false, \ - "Enable dtrace probes for method-entry and method-exit") \ + "Enable dtrace tool probes for method-entry and method-exit") \ \ product(bool, DTraceAllocProbes, false, \ - "Enable dtrace probes for object allocation") \ + "Enable dtrace tool probes for object allocation") \ \ product(bool, DTraceMonitorProbes, false, \ - "Enable dtrace probes for monitor events") \ + "Enable dtrace tool probes for monitor events") \ \ product(bool, RelaxAccessControlCheck, false, \ "Relax the access control checks in the verifier") \ diff --git a/src/java.base/share/man/java.1 b/src/java.base/share/man/java.1 index 6a1532a8981..ea7edb8ef99 100644 --- a/src/java.base/share/man/java.1 +++ b/src/java.base/share/man/java.1 @@ -2977,11 +2977,19 @@ different JDK version. .RE .RE .TP -.B \f[CB]\-XX:+ExtendedDTraceProbes\f[R] -\f[B]Linux and macOS:\f[R] Enables additional \f[CB]dtrace\f[R] tool probes -that affect the performance. -By default, this option is disabled and \f[CB]dtrace\f[R] performs only -standard probes. +.B \f[CB]\-XX:+DTraceAllocProbes\f[R] +\f[B]Linux and macOS:\f[R] Enable \f[CB]dtrace\f[R] tool probes for object allocation. +.RS +.RE +.TP +.B \f[CB]\-XX:+DTraceMethodProbes\f[R] +\f[B]Linux and macOS:\f[R] Enable \f[CB]dtrace\f[R] tool probes for method-entry +and method-exit. +.RS +.RE +.TP +.B \f[CB]\-XX:+DTraceMonitorProbes\f[R] +\f[B]Linux and macOS:\f[R] Enable \f[CB]dtrace\f[R] tool probes for monitor events. .RS .RE .TP @@ -4008,6 +4016,16 @@ Example: \f[CB]\-Xlog:gc:garbage\-collection.log\f[R] .RE .TP +.B \f[CB]\-XX:+ExtendedDTraceProbes\f[R] +\f[B]Linux and macOS:\f[R] Enables additional \f[CB]dtrace\f[R] tool probes +that affect performance. +By default, this option is disabled and \f[CB]dtrace\f[R] performs only +standard probes. +Use the combination of these flags instead: \f[CB]\-XX:+DTraceMethodProbes\f[R], +\f[CB]\-XX:+DTraceAllocProbes\f[R], \f[CB]\-XX:+DTraceMonitorProbes\f[R]. +.RS +.RE +.TP .B \f[CB]\-XX:+FlightRecorder\f[R] Enables the use of Java Flight Recorder (JFR) during the runtime of the application. diff --git a/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java b/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java index e9ccac08793..86bd3e9d2e2 100644 --- a/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java +++ b/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java @@ -54,6 +54,7 @@ public class VMDeprecatedOptions { {"InitialRAMFraction", "64"}, {"TLABStats", "false"}, {"AllowRedefinitionToAddDeleteMethods", "true"}, + {"ExtendedDTraceProbes", "true"}, // deprecated alias flags (see also aliased_jvm_flags): {"DefaultMaxRAMFraction", "4"}, diff --git a/test/hotspot/jtreg/serviceability/7170638/SDTProbesGNULinuxTest.java b/test/hotspot/jtreg/serviceability/7170638/SDTProbesGNULinuxTest.java index 9ad10282d1b..36759433112 100644 --- a/test/hotspot/jtreg/serviceability/7170638/SDTProbesGNULinuxTest.java +++ b/test/hotspot/jtreg/serviceability/7170638/SDTProbesGNULinuxTest.java @@ -46,7 +46,9 @@ public class SDTProbesGNULinuxTest { public static void main(String[] args) throws Throwable { { var pb = ProcessTools.createJavaProcessBuilder( - "-XX:+ExtendedDTraceProbes", + "-XX:+DTraceMethodProbes", + "-XX:+DTraceAllocProbes", + "-XX:+DTraceMonitorProbes", "-version"); var oa = new OutputAnalyzer(pb.start()); // This test only matters when build with DTRACE_ENABLED. -- GitLab From 8acfbc2e21063c3dc088c25c1574bcefa94e5a24 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Sat, 12 Feb 2022 14:12:42 +0000 Subject: [PATCH 052/203] 8281675: VMDeprecatedOptions test fails after JDK-8278423 Reviewed-by: dcubed --- .../hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java b/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java index 86bd3e9d2e2..a8b5bb31194 100644 --- a/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java +++ b/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,7 +54,6 @@ public class VMDeprecatedOptions { {"InitialRAMFraction", "64"}, {"TLABStats", "false"}, {"AllowRedefinitionToAddDeleteMethods", "true"}, - {"ExtendedDTraceProbes", "true"}, // deprecated alias flags (see also aliased_jvm_flags): {"DefaultMaxRAMFraction", "4"}, -- GitLab From eff5dafba9f72bd0612357712ffa472ce1c9166a Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Sat, 12 Feb 2022 22:10:11 +0000 Subject: [PATCH 053/203] 8274939: Incorrect size of the pixel storage is used by the robot on macOS Reviewed-by: aivanov, prr --- .../macosx/classes/sun/lwawt/macosx/CRobot.java | 8 ++++---- src/java.desktop/macosx/native/libawt_lwawt/awt/CRobot.m | 7 ++++++- .../awt/Robot/CheckCommonColors/CheckCommonColors.java | 2 ++ 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CRobot.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CRobot.java index 49125443b2e..5dba06cb612 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CRobot.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CRobot.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -168,9 +168,9 @@ final class CRobot implements RobotPeer { */ @Override public int getRGBPixel(int x, int y) { - int[] c = new int[1]; - double scale = fDevice.getScaleFactor(); - getScreenPixels(new Rectangle(x, y, (int) scale, (int) scale), c); + int scale = fDevice.getScaleFactor(); + int[] c = new int[scale * scale]; + getScreenPixels(new Rectangle(x, y, scale, scale), c); return c[0]; } diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobot.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobot.m index 9d90086677d..55df129960f 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobot.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobot.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -321,6 +321,11 @@ Java_sun_lwawt_macosx_CRobot_nativeGetScreenPixels jint picY = y; jint picWidth = width; jint picHeight = height; + jsize size = (*env)->GetArrayLength(env, pixels); + if (size < (long) picWidth * picHeight || picWidth < 0 || picHeight < 0) { + JNU_ThrowInternalError(env, "Invalid arguments to get screen pixels"); + return; + } CGRect screenRect = CGRectMake(picX / scale, picY / scale, picWidth / scale, picHeight / scale); diff --git a/test/jdk/java/awt/Robot/CheckCommonColors/CheckCommonColors.java b/test/jdk/java/awt/Robot/CheckCommonColors/CheckCommonColors.java index 57419b0ac5a..55d9b4358af 100644 --- a/test/jdk/java/awt/Robot/CheckCommonColors/CheckCommonColors.java +++ b/test/jdk/java/awt/Robot/CheckCommonColors/CheckCommonColors.java @@ -42,6 +42,8 @@ import javax.imageio.ImageIO; * @key headful * @bug 8215105 8211999 * @summary tests that Robot can capture the common colors without artifacts + * @run main/othervm CheckCommonColors + * @run main/othervm -Xcheck:jni CheckCommonColors */ public final class CheckCommonColors { -- GitLab From adbe0661029f12a36a44af52b83b189384d33a27 Mon Sep 17 00:00:00 2001 From: Bhavana Kilambi Date: Mon, 14 Feb 2022 01:33:20 +0000 Subject: [PATCH 054/203] 8239927: Product variable PrefetchFieldsAhead is unused and should be removed Reviewed-by: njian, dholmes --- src/hotspot/cpu/x86/vm_version_x86.cpp | 8 +------- src/hotspot/share/gc/shared/gc_globals.hpp | 6 +----- src/hotspot/share/runtime/arguments.cpp | 1 + 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index 93613850a5e..c09785b969a 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1818,9 +1818,6 @@ void VM_Version::get_processor_features() { if (FLAG_IS_DEFAULT(PrefetchScanIntervalInBytes)) { FLAG_SET_DEFAULT(PrefetchScanIntervalInBytes, 576); } - if (FLAG_IS_DEFAULT(PrefetchFieldsAhead)) { - FLAG_SET_DEFAULT(PrefetchFieldsAhead, 1); - } #endif if (FLAG_IS_DEFAULT(ContendedPaddingWidth) && @@ -1883,9 +1880,6 @@ void VM_Version::get_processor_features() { if (PrefetchScanIntervalInBytes > 0) { log->print_cr("PrefetchScanIntervalInBytes %d", (int) PrefetchScanIntervalInBytes); } - if (PrefetchFieldsAhead > 0) { - log->print_cr("PrefetchFieldsAhead %d", (int) PrefetchFieldsAhead); - } if (ContendedPaddingWidth > 0) { log->print_cr("ContendedPaddingWidth %d", (int) ContendedPaddingWidth); } diff --git a/src/hotspot/share/gc/shared/gc_globals.hpp b/src/hotspot/share/gc/shared/gc_globals.hpp index 555170a091a..d9380b2af71 100644 --- a/src/hotspot/share/gc/shared/gc_globals.hpp +++ b/src/hotspot/share/gc/shared/gc_globals.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -503,10 +503,6 @@ "How far ahead to prefetch scan area (<= 0 means off)") \ range(-1, max_jint) \ \ - product(intx, PrefetchFieldsAhead, -1, \ - "How many fields ahead to prefetch in oop scan (<= 0 means off)") \ - range(-1, max_jint) \ - \ product(bool, VerifyDuringStartup, false, DIAGNOSTIC, \ "Verify memory system before executing any Java code " \ "during VM initialization") \ diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 952b96f537e..fed6faa0ccd 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -548,6 +548,7 @@ static SpecialFlag const special_jvm_flags[] = { { "FilterSpuriousWakeups", JDK_Version::jdk(18), JDK_Version::jdk(19), JDK_Version::jdk(20) }, { "MinInliningThreshold", JDK_Version::jdk(18), JDK_Version::jdk(19), JDK_Version::jdk(20) }, + { "PrefetchFieldsAhead", JDK_Version::undefined(), JDK_Version::jdk(19), JDK_Version::jdk(20) }, #ifdef ASSERT { "DummyObsoleteTestFlag", JDK_Version::undefined(), JDK_Version::jdk(18), JDK_Version::undefined() }, #endif -- GitLab From 483d4b97e0ae4ab7b0d87058901f57688a0f0811 Mon Sep 17 00:00:00 2001 From: Nils Eliasson Date: Mon, 14 Feb 2022 08:27:21 +0000 Subject: [PATCH 055/203] 8281505: Add CompileCommand PrintIdealPhase Reviewed-by: kvn, thartmann, chagedorn --- src/hotspot/share/compiler/compileBroker.cpp | 3 +- .../share/compiler/compilerDirectives.cpp | 20 ++ .../share/compiler/compilerDirectives.hpp | 6 +- src/hotspot/share/compiler/compilerOracle.cpp | 16 ++ src/hotspot/share/compiler/compilerOracle.hpp | 7 +- .../share/compiler/directivesParser.cpp | 10 + src/hotspot/share/opto/compile.cpp | 15 +- src/hotspot/share/opto/compile.hpp | 1 + src/hotspot/share/opto/phasetype.hpp | 248 +++++++++++------- .../compiler/oracle/PrintIdealPhaseTest.java | 153 +++++++++++ 10 files changed, 377 insertions(+), 102 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/oracle/PrintIdealPhaseTest.java diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index 4ae7bc21ce6..1c8656044b5 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -614,9 +614,8 @@ void register_jfr_phasetype_serializer(CompilerType compiler_type) { #ifdef COMPILER2 } else if (compiler_type == compiler_c2) { assert(first_registration, "invariant"); // c2 must be registered first. - GrowableArray* c2_phase_names = new GrowableArray(PHASE_NUM_TYPES); for (int i = 0; i < PHASE_NUM_TYPES; i++) { - const char* phase_name = CompilerPhaseTypeHelper::to_string((CompilerPhaseType) i); + const char* phase_name = CompilerPhaseTypeHelper::to_description((CompilerPhaseType) i); CompilerEvent::PhaseEvent::get_phase_id(phase_name, false, false, false); } first_registration = false; diff --git a/src/hotspot/share/compiler/compilerDirectives.cpp b/src/hotspot/share/compiler/compilerDirectives.cpp index 6d864072d1b..5fe84827195 100644 --- a/src/hotspot/share/compiler/compilerDirectives.cpp +++ b/src/hotspot/share/compiler/compilerDirectives.cpp @@ -30,6 +30,7 @@ #include "compiler/compilerOracle.hpp" #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" +#include "opto/phasetype.hpp" #include "runtime/globals_extension.hpp" CompilerDirectives::CompilerDirectives() : _next(NULL), _match(NULL), _ref_count(0) { @@ -262,6 +263,7 @@ void DirectiveSet::init_control_intrinsic() { DirectiveSet::DirectiveSet(CompilerDirectives* d) :_inlinematchers(NULL), _directive(d) { #define init_defaults_definition(name, type, dvalue, compiler) this->name##Option = dvalue; + _ideal_phase_name_mask = 0; compilerdirectives_common_flags(init_defaults_definition) compilerdirectives_c2_flags(init_defaults_definition) compilerdirectives_c1_flags(init_defaults_definition) @@ -381,6 +383,24 @@ DirectiveSet* DirectiveSet::compilecommand_compatibility_init(const methodHandle compilerdirectives_c2_flags(init_default_cc) compilerdirectives_c1_flags(init_default_cc) + // Parse PrintIdealPhaseName and create an efficient lookup mask +#ifndef PRODUCT +#ifdef COMPILER2 + if (!_modified[PrintIdealPhaseIndex]) { + // Parse ccstr and create mask + ccstrlist option; + if (CompilerOracle::has_option_value(method, CompileCommand::PrintIdealPhase, option)) { + uint64_t mask = 0; + PhaseNameValidator validator(option, mask); + if (validator.is_valid()) { + assert(mask != 0, "Must be set"); + set.cloned()->_ideal_phase_name_mask = mask; + } + } + } +#endif +#endif + // Canonicalize DisableIntrinsic to contain only ',' as a separator. ccstrlist option_value; bool need_reset = true; // if Control/DisableIntrinsic redefined, only need to reset control_words once diff --git a/src/hotspot/share/compiler/compilerDirectives.hpp b/src/hotspot/share/compiler/compilerDirectives.hpp index 7daa034a8d0..8e3ba2db005 100644 --- a/src/hotspot/share/compiler/compilerDirectives.hpp +++ b/src/hotspot/share/compiler/compilerDirectives.hpp @@ -67,6 +67,7 @@ NOT_PRODUCT(cflags(TraceOptoPipelining, bool, TraceOptoPipelining, TraceOptoPipelining)) \ NOT_PRODUCT(cflags(TraceOptoOutput, bool, TraceOptoOutput, TraceOptoOutput)) \ NOT_PRODUCT(cflags(PrintIdeal, bool, PrintIdeal, PrintIdeal)) \ +NOT_PRODUCT(cflags(PrintIdealPhase, ccstrlist, "", PrintIdealPhase)) \ NOT_PRODUCT(cflags(PrintIdealLevel, uintx, PrintIdealLevel, PrintIdealLevel)) \ cflags(TraceSpilling, bool, TraceSpilling, TraceSpilling) \ cflags(Vectorize, bool, false, Vectorize) \ @@ -108,6 +109,7 @@ private: InlineMatcher* _inlinematchers; CompilerDirectives* _directive; TriBoolArray<(size_t)vmIntrinsics::number_of_intrinsics(), int> _intrinsic_control_words; + uint64_t _ideal_phase_name_mask; public: DirectiveSet(CompilerDirectives* directive); @@ -137,7 +139,6 @@ public: private: bool _modified[number_of_flags]; // Records what options where set by a directive - public: #define flag_store_definition(name, type, dvalue, cc_flag) type name##Option; compilerdirectives_common_flags(flag_store_definition) @@ -150,6 +151,9 @@ public: compilerdirectives_c2_flags(set_function_definition) compilerdirectives_c1_flags(set_function_definition) + void set_ideal_phase_mask(uint64_t mask) { _ideal_phase_name_mask = mask; }; + uint64_t ideal_phase_mask() { return _ideal_phase_name_mask; }; + void print_intx(outputStream* st, ccstr n, intx v, bool mod) { if (mod) { st->print("%s:" INTX_FORMAT " ", n, v); } } void print_uintx(outputStream* st, ccstr n, intx v, bool mod) { if (mod) { st->print("%s:" UINTX_FORMAT " ", n, v); } } void print_bool(outputStream* st, ccstr n, bool v, bool mod) { if (mod) { st->print("%s:%s ", n, v ? "true" : "false"); } } diff --git a/src/hotspot/share/compiler/compilerOracle.cpp b/src/hotspot/share/compiler/compilerOracle.cpp index 7d58a28d272..7d8b7179d0c 100644 --- a/src/hotspot/share/compiler/compilerOracle.cpp +++ b/src/hotspot/share/compiler/compilerOracle.cpp @@ -34,6 +34,7 @@ #include "oops/klass.hpp" #include "oops/method.inline.hpp" #include "oops/symbol.hpp" +#include "opto/phasetype.hpp" #include "runtime/globals_extension.hpp" #include "runtime/handles.inline.hpp" #include "runtime/jniHandles.hpp" @@ -683,6 +684,21 @@ static void scan_value(enum OptionType type, char* line, int& total_bytes_read, jio_snprintf(errorbuf, buf_size, "Unrecognized intrinsic detected in %s: %s", option2name(option), validator.what()); } } +#ifndef PRODUCT + else if (option == CompileCommand::PrintIdealPhase) { + uint64_t mask = 0; + PhaseNameValidator validator(value, mask); + + if (!validator.is_valid()) { + jio_snprintf(errorbuf, buf_size, "Unrecognized phase name in %s: %s", option2name(option), validator.what()); + } + } else if (option == CompileCommand::TestOptionList) { + // all values are ok + } +#endif + else { + assert(false, "Ccstrlist type option missing validator"); + } register_command(matcher, option, (ccstr) value); return; diff --git a/src/hotspot/share/compiler/compilerOracle.hpp b/src/hotspot/share/compiler/compilerOracle.hpp index f2fc0e8251d..24ed40b7ef2 100644 --- a/src/hotspot/share/compiler/compilerOracle.hpp +++ b/src/hotspot/share/compiler/compilerOracle.hpp @@ -79,9 +79,10 @@ class methodHandle; option(TraceOptoPipelining, "TraceOptoPipelining", Bool) \ option(TraceOptoOutput, "TraceOptoOutput", Bool) \ option(TraceSpilling, "TraceSpilling", Bool) \ - option(PrintIdeal, "PrintIdeal", Bool) \ - option(PrintIdealLevel, "PrintIdealLevel", Uintx) \ - option(IGVPrintLevel, "IGVPrintLevel", Intx) \ +NOT_PRODUCT(option(PrintIdeal, "PrintIdeal", Bool)) \ +NOT_PRODUCT(option(PrintIdealLevel, "PrintIdealLevel", Uintx)) \ +NOT_PRODUCT(option(PrintIdealPhase, "PrintIdealPhase", Ccstrlist)) \ +NOT_PRODUCT(option(IGVPrintLevel, "IGVPrintLevel", Intx)) \ option(Vectorize, "Vectorize", Bool) \ option(VectorizeDebug, "VectorizeDebug", Uintx) \ option(CloneMapDebug, "CloneMapDebug", Bool) \ diff --git a/src/hotspot/share/compiler/directivesParser.cpp b/src/hotspot/share/compiler/directivesParser.cpp index b4ce9a3877c..e48ac58b31c 100644 --- a/src/hotspot/share/compiler/directivesParser.cpp +++ b/src/hotspot/share/compiler/directivesParser.cpp @@ -27,6 +27,7 @@ #include "compiler/directivesParser.hpp" #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" +#include "opto/phasetype.hpp" #include "runtime/os.hpp" #include @@ -334,6 +335,15 @@ bool DirectivesParser::set_option_flag(JSON_TYPE t, JSON_VAL* v, const key* opti error(VALUE_ERROR, "Unrecognized intrinsic detected in DisableIntrinsic: %s", validator.what()); return false; } + } else if (strncmp(option_key->name, "PrintIdealPhase", 15) == 0) { + uint64_t mask = 0; + PhaseNameValidator validator(s, mask); + + if (!validator.is_valid()) { + error(VALUE_ERROR, "Unrecognized phase name detected in PrintIdealPhase: %s", validator.what()); + return false; + } + set->set_ideal_phase_mask(mask); } } break; diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 1296a3ff8b8..44456772321 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -4833,7 +4833,7 @@ void Compile::print_method(CompilerPhaseType cpt, int level, Node* n) { #ifndef PRODUCT ResourceMark rm; stringStream ss; - ss.print_raw(CompilerPhaseTypeHelper::to_string(cpt)); + ss.print_raw(CompilerPhaseTypeHelper::to_name(cpt)); if (n != nullptr) { ss.print(": %d %s ", n->_idx, NodeClassNames[n->Opcode()]); } @@ -4842,8 +4842,8 @@ void Compile::print_method(CompilerPhaseType cpt, int level, Node* n) { if (should_print_igv(level)) { _igv_printer->print_method(name, level); } - if (should_print_ideal(level)) { - print_ideal_ir(name); + if (should_print_ideal(level) || should_print_phase(cpt)) { + print_ideal_ir(CompilerPhaseTypeHelper::to_name(cpt)); } #endif C->_latest_stage_start_counter.stamp(); @@ -4873,6 +4873,15 @@ void Compile::end_method() { #endif } +bool Compile::should_print_phase(CompilerPhaseType cpt) { +#ifndef PRODUCT + if ((_directive->ideal_phase_mask() & CompilerPhaseTypeHelper::to_bitmask(cpt)) != 0) { + return true; + } +#endif + return false; +} + bool Compile::should_print_igv(int level) { #ifndef PRODUCT if (PrintIdealGraphLevel < 0) { // disabled by the user diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index 70480b0d06e..0d74c9e5f9a 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -654,6 +654,7 @@ class Compile : public Phase { void begin_method(); void end_method(); bool should_print_igv(int level); + bool should_print_phase(CompilerPhaseType cpt); void print_method(CompilerPhaseType cpt, int level, Node* n = nullptr); diff --git a/src/hotspot/share/opto/phasetype.hpp b/src/hotspot/share/opto/phasetype.hpp index 2aa55a65553..d56a7b13197 100644 --- a/src/hotspot/share/opto/phasetype.hpp +++ b/src/hotspot/share/opto/phasetype.hpp @@ -25,105 +25,167 @@ #ifndef SHARE_OPTO_PHASETYPE_HPP #define SHARE_OPTO_PHASETYPE_HPP +#define COMPILER_PHASES(flags) \ + flags(BEFORE_STRINGOPTS, "Before StringOpts") \ + flags(AFTER_STRINGOPTS, "After StringOpts") \ + flags(BEFORE_REMOVEUSELESS, "Before RemoveUseless") \ + flags(AFTER_PARSING, "After Parsing") \ + flags(ITER_GVN1, "Iter GVN 1") \ + flags(EXPAND_VUNBOX, "Expand VectorUnbox") \ + flags(SCALARIZE_VBOX, "Scalarize VectorBox") \ + flags(INLINE_VECTOR_REBOX, "Inline Vector Rebox Calls") \ + flags(EXPAND_VBOX, "Expand VectorBox") \ + flags(ELIMINATE_VBOX_ALLOC, "Eliminate VectorBoxAllocate") \ + flags(PHASEIDEAL_BEFORE_EA, "PhaseIdealLoop before EA") \ + flags(ITER_GVN_AFTER_VECTOR, "Iter GVN after vector box elimination") \ + flags(ITER_GVN_BEFORE_EA, "Iter GVN before EA") \ + flags(ITER_GVN_AFTER_EA, "Iter GVN after EA") \ + flags(ITER_GVN_AFTER_ELIMINATION, "Iter GVN after eliminating allocations and locks") \ + flags(PHASEIDEALLOOP1, "PhaseIdealLoop 1") \ + flags(PHASEIDEALLOOP2, "PhaseIdealLoop 2") \ + flags(PHASEIDEALLOOP3, "PhaseIdealLoop 3") \ + flags(CCP1, "PhaseCCP 1") \ + flags(ITER_GVN2, "Iter GVN 2") \ + flags(PHASEIDEALLOOP_ITERATIONS, "PhaseIdealLoop iterations") \ + flags(OPTIMIZE_FINISHED, "Optimize finished") \ + flags(GLOBAL_CODE_MOTION, "Global code motion") \ + flags(FINAL_CODE, "Final Code") \ + flags(AFTER_EA, "After Escape Analysis") \ + flags(BEFORE_CLOOPS, "Before CountedLoop") \ + flags(AFTER_CLOOPS, "After CountedLoop") \ + flags(BEFORE_BEAUTIFY_LOOPS, "Before beautify loops") \ + flags(AFTER_BEAUTIFY_LOOPS, "After beautify loops") \ + flags(BEFORE_MATCHING, "Before matching") \ + flags(MATCHING, "After matching") \ + flags(INCREMENTAL_INLINE, "Incremental Inline") \ + flags(INCREMENTAL_INLINE_STEP, "Incremental Inline Step") \ + flags(INCREMENTAL_INLINE_CLEANUP, "Incremental Inline Cleanup") \ + flags(INCREMENTAL_BOXING_INLINE, "Incremental Boxing Inline") \ + flags(CALL_CATCH_CLEANUP, "Call catch cleanup") \ + flags(MACRO_EXPANSION, "Macro expand") \ + flags(BARRIER_EXPANSION, "Barrier expand") \ + flags(END, "End") \ + flags(FAILURE, "Failure") \ + flags(DEBUG, "Debug") + +#define table_entry(name, description) PHASE_##name, enum CompilerPhaseType { - PHASE_BEFORE_STRINGOPTS, - PHASE_AFTER_STRINGOPTS, - PHASE_BEFORE_REMOVEUSELESS, - PHASE_AFTER_PARSING, - PHASE_ITER_GVN1, - PHASE_EXPAND_VUNBOX, - PHASE_SCALARIZE_VBOX, - PHASE_INLINE_VECTOR_REBOX, - PHASE_EXPAND_VBOX, - PHASE_ELIMINATE_VBOX_ALLOC, - PHASE_PHASEIDEAL_BEFORE_EA, - PHASE_ITER_GVN_AFTER_VECTOR, - PHASE_ITER_GVN_BEFORE_EA, - PHASE_ITER_GVN_AFTER_EA, - PHASE_ITER_GVN_AFTER_ELIMINATION, - PHASE_PHASEIDEALLOOP1, - PHASE_PHASEIDEALLOOP2, - PHASE_PHASEIDEALLOOP3, - PHASE_CCP1, - PHASE_ITER_GVN2, - PHASE_PHASEIDEALLOOP_ITERATIONS, - PHASE_OPTIMIZE_FINISHED, - PHASE_GLOBAL_CODE_MOTION, - PHASE_FINAL_CODE, - PHASE_AFTER_EA, - PHASE_BEFORE_CLOOPS, - PHASE_AFTER_CLOOPS, - PHASE_BEFORE_BEAUTIFY_LOOPS, - PHASE_AFTER_BEAUTIFY_LOOPS, - PHASE_BEFORE_MATCHING, - PHASE_MATCHING, - PHASE_INCREMENTAL_INLINE, - PHASE_INCREMENTAL_INLINE_STEP, - PHASE_INCREMENTAL_INLINE_CLEANUP, - PHASE_INCREMENTAL_BOXING_INLINE, - PHASE_CALL_CATCH_CLEANUP, - PHASE_INSERT_BARRIER, - PHASE_MACRO_EXPANSION, - PHASE_BARRIER_EXPANSION, - PHASE_ADD_UNSAFE_BARRIER, - PHASE_END, - PHASE_FAILURE, - PHASE_DEBUG, - - PHASE_NUM_TYPES + COMPILER_PHASES(table_entry) + PHASE_NUM_TYPES, + PHASE_NONE +}; +#undef table_entry + +static const char* phase_descriptions[] = { +#define array_of_labels(name, description) description, + COMPILER_PHASES(array_of_labels) +#undef array_of_labels +}; + +static const char* phase_names[] = { +#define array_of_labels(name, description) #name, + COMPILER_PHASES(array_of_labels) +#undef array_of_labels }; class CompilerPhaseTypeHelper { public: - static const char* to_string(CompilerPhaseType cpt) { - switch (cpt) { - case PHASE_BEFORE_STRINGOPTS: return "Before StringOpts"; - case PHASE_AFTER_STRINGOPTS: return "After StringOpts"; - case PHASE_BEFORE_REMOVEUSELESS: return "Before RemoveUseless"; - case PHASE_AFTER_PARSING: return "After Parsing"; - case PHASE_ITER_GVN1: return "Iter GVN 1"; - case PHASE_EXPAND_VUNBOX: return "Expand VectorUnbox"; - case PHASE_SCALARIZE_VBOX: return "Scalarize VectorBox"; - case PHASE_INLINE_VECTOR_REBOX: return "Inline Vector Rebox Calls"; - case PHASE_EXPAND_VBOX: return "Expand VectorBox"; - case PHASE_ELIMINATE_VBOX_ALLOC: return "Eliminate VectorBoxAllocate"; - case PHASE_PHASEIDEAL_BEFORE_EA: return "PhaseIdealLoop before EA"; - case PHASE_ITER_GVN_AFTER_VECTOR: return "Iter GVN after vector box elimination"; - case PHASE_ITER_GVN_BEFORE_EA: return "Iter GVN before EA"; - case PHASE_ITER_GVN_AFTER_EA: return "Iter GVN after EA"; - case PHASE_ITER_GVN_AFTER_ELIMINATION: return "Iter GVN after eliminating allocations and locks"; - case PHASE_PHASEIDEALLOOP1: return "PhaseIdealLoop 1"; - case PHASE_PHASEIDEALLOOP2: return "PhaseIdealLoop 2"; - case PHASE_PHASEIDEALLOOP3: return "PhaseIdealLoop 3"; - case PHASE_CCP1: return "PhaseCCP 1"; - case PHASE_ITER_GVN2: return "Iter GVN 2"; - case PHASE_PHASEIDEALLOOP_ITERATIONS: return "PhaseIdealLoop iterations"; - case PHASE_OPTIMIZE_FINISHED: return "Optimize finished"; - case PHASE_GLOBAL_CODE_MOTION: return "Global code motion"; - case PHASE_FINAL_CODE: return "Final Code"; - case PHASE_AFTER_EA: return "After Escape Analysis"; - case PHASE_BEFORE_CLOOPS: return "Before CountedLoop"; - case PHASE_AFTER_CLOOPS: return "After CountedLoop"; - case PHASE_BEFORE_BEAUTIFY_LOOPS: return "Before beautify loops"; - case PHASE_AFTER_BEAUTIFY_LOOPS: return "After beautify loops"; - case PHASE_BEFORE_MATCHING: return "Before matching"; - case PHASE_MATCHING: return "After matching"; - case PHASE_INCREMENTAL_INLINE: return "Incremental Inline"; - case PHASE_INCREMENTAL_INLINE_STEP: return "Incremental Inline Step"; - case PHASE_INCREMENTAL_INLINE_CLEANUP: return "Incremental Inline Cleanup"; - case PHASE_INCREMENTAL_BOXING_INLINE: return "Incremental Boxing Inline"; - case PHASE_CALL_CATCH_CLEANUP: return "Call catch cleanup"; - case PHASE_INSERT_BARRIER: return "Insert barrier"; - case PHASE_MACRO_EXPANSION: return "Macro expand"; - case PHASE_BARRIER_EXPANSION: return "Barrier expand"; - case PHASE_ADD_UNSAFE_BARRIER: return "Add barrier to unsafe op"; - case PHASE_END: return "End"; - case PHASE_FAILURE: return "Failure"; - case PHASE_DEBUG: return "Debug"; - default: - ShouldNotReachHere(); - return NULL; + static const char* to_name(CompilerPhaseType cpt) { + return phase_names[cpt]; + } + static const char* to_description(CompilerPhaseType cpt) { + return phase_descriptions[cpt]; + } + static int to_bitmask(CompilerPhaseType cpt) { + return (1 << cpt); + } +}; + +static CompilerPhaseType find_phase(const char* str) { + for (int i = 0; i < PHASE_NUM_TYPES; i++) { + if (strcmp(phase_names[i], str) == 0) { + return (CompilerPhaseType)i; + } + } + return PHASE_NONE; +} + +class PhaseNameIter { + private: + char* _token; + char* _saved_ptr; + char* _list; + + public: + PhaseNameIter(ccstrlist option) { + _list = (char*) canonicalize(option); + _saved_ptr = _list; + _token = strtok_r(_saved_ptr, ",", &_saved_ptr); + } + + ~PhaseNameIter() { + FREE_C_HEAP_ARRAY(char, _list); + } + + const char* operator*() const { return _token; } + + PhaseNameIter& operator++() { + _token = strtok_r(NULL, ",", &_saved_ptr); + return *this; + } + + ccstrlist canonicalize(ccstrlist option_value) { + char* canonicalized_list = NEW_C_HEAP_ARRAY(char, strlen(option_value) + 1, mtCompiler); + int i = 0; + char current; + while ((current = option_value[i]) != '\0') { + if (current == '\n' || current == ' ') { + canonicalized_list[i] = ','; + } else { + canonicalized_list[i] = current; + } + i++; } + canonicalized_list[i] = '\0'; + return canonicalized_list; + } +}; + +class PhaseNameValidator { + private: + bool _valid; + char* _bad; + + public: + PhaseNameValidator(ccstrlist option, uint64_t& mask) : _valid(true), _bad(nullptr) { + for (PhaseNameIter iter(option); *iter != NULL && _valid; ++iter) { + + CompilerPhaseType cpt = find_phase(*iter); + if (PHASE_NONE == cpt) { + const size_t len = MIN2(strlen(*iter), 63) + 1; // cap len to a value we know is enough for all phase descriptions + _bad = NEW_C_HEAP_ARRAY(char, len, mtCompiler); + // strncpy always writes len characters. If the source string is shorter, the function fills the remaining bytes with NULLs. + strncpy(_bad, *iter, len); + _valid = false; + } else { + assert(cpt < 64, "out of bounds"); + mask |= CompilerPhaseTypeHelper::to_bitmask(cpt); + } + } + } + + ~PhaseNameValidator() { + if (_bad != NULL) { + FREE_C_HEAP_ARRAY(char, _bad); + } + } + + bool is_valid() const { + return _valid; + } + + const char* what() const { + return _bad; } }; diff --git a/test/hotspot/jtreg/compiler/oracle/PrintIdealPhaseTest.java b/test/hotspot/jtreg/compiler/oracle/PrintIdealPhaseTest.java new file mode 100644 index 00000000000..f07d7264482 --- /dev/null +++ b/test/hotspot/jtreg/compiler/oracle/PrintIdealPhaseTest.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test PrintIdealPhaseTest + * @summary Checks that -XX:CompileCommand=PrintIdealPhase,... works + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.management + * @requires vm.debug == true & vm.compiler2.enabled + * @run driver compiler.oracle.PrintIdealPhaseTest + */ + +package compiler.oracle; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import jdk.test.lib.Asserts; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class PrintIdealPhaseTest { + + public static void main(String[] args) throws Exception { + new PrintIdealPhaseTest(); + } + + PrintIdealPhaseTest() throws Exception { + // The Phases specified here will be exchanged for the enum Phase in compiler.lib.ir_framework when it's done + + // Test -XX:CompileCommand=PrintIdealPhase,*::test,CCP1 + List expectedPhases = new ArrayList(); + expectedPhases.add("CCP1"); + runTest("CCP1", expectedPhases, "hotspot_log_1.log", true); + runTest("FISH", expectedPhases, "hotspot_log_1f.log", false); + + // Test -XX:CompileCommand=PrintIdealPhase,*::test,MATCHING + expectedPhases.clear(); + expectedPhases.add("MATCHING"); + runTest("MATCHING", expectedPhases, "hotspot_log_2.log", true); + + // Test -XX:CompileCommand=PrintIdealPhase,*::test,CCP_1,AFTER_MATCHING + expectedPhases.add("CCP1"); + runTest("MATCHING,CCP1", expectedPhases, "hotspot_log_3.log", true); + } + + private void runTest(String cmdPhases, List expectedPhases, String logFile, boolean valid) throws Exception { + List options = new ArrayList(); + options.add("-Xbatch"); + options.add("-XX:+PrintCompilation"); + options.add("-XX:LogFile="+logFile); + options.add("-XX:+IgnoreUnrecognizedVMOptions"); + options.add("-XX:CompileCommand=PrintIdealPhase," + getTestClass() + "::test," + cmdPhases); + options.add(getTestClass()); + + OutputAnalyzer oa = ProcessTools.executeTestJvm(options); + if (valid) { + oa.shouldHaveExitValue(0) + .shouldContain("CompileCommand: PrintIdealPhase compiler/oracle/PrintIdealPhaseTest$TestMain.test const char* PrintIdealPhase = '"+cmdPhases.replace(',', ' ')+"'") + .shouldNotContain("CompileCommand: An error occurred during parsing") + .shouldNotContain("Error: Unrecognized phase name in PrintIdealPhase:") + .shouldNotContain("# A fatal error has been detected by the Java Runtime Environment"); + + // Check that all the expected phases matches what can be found in the compilation log file + HashSet loggedPhases = parseLogFile(logFile); + System.out.println("Logged phases:"); + for (String loggedPhase : loggedPhases) { + System.out.println("loggedPhase: "+ loggedPhase); + } + for (String expectedPhase : expectedPhases) { + System.out.println("Looking for phase: " + expectedPhase); + + Asserts.assertTrue(loggedPhases.contains(expectedPhase), "Must find specified phase: " + expectedPhase); + loggedPhases.remove(expectedPhase); + } + Asserts.assertTrue(loggedPhases.isEmpty(), "Expect no other phases"); + } else { + // Check that we don't pass even though bad phase names where given + oa.shouldHaveExitValue(0) + .shouldContain("CompileCommand: An error occurred during parsing") + .shouldContain("Error: Unrecognized phase name in PrintIdealPhase:"); + } + } + + private HashSet parseLogFile(String logFile) { + String printIdealTag = " phasesFound = new HashSet<>(); + + try (var br = Files.newBufferedReader(Paths.get(logFile))) { + String line; + while ((line = br.readLine()) != null) { + if (line.startsWith(printIdealTag)) { + Matcher matcher = compilePhasePattern.matcher(line); + if (matcher.find()) { + phasesFound.add(matcher.group(1)); + } else { + throw new Error("Failed to match compile_phase in file: " + logFile); + } + } + } + } catch (IOException e) { + throw new Error("Failed to read " + logFile + " data: " + e, e); + } + return phasesFound; + } + + // Test class that is invoked by the sub process + public String getTestClass() { + return TestMain.class.getName(); + } + + public static class TestMain { + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + test(i); + } + } + + static void test(int i) { + if ((i % 1000) == 0) { + System.out.println("Hello World!"); + } + } + } +} -- GitLab From 1ef45c5bbdeb4e1ca65c6d8f3ac1568a6951f3a7 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Mon, 14 Feb 2022 08:35:53 +0000 Subject: [PATCH 056/203] =?UTF-8?q?8280799:=20=D0=A12:=20assert(false)=20f?= =?UTF-8?q?ailed:=20cyclic=20dependency=20prevents=20range=20check=20elimi?= =?UTF-8?q?nation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: thartmann, kvn --- src/hotspot/share/opto/loopnode.cpp | 59 ++-- src/hotspot/share/opto/split_if.cpp | 18 ++ .../TestPredicateInputBelowLoopPredicate.java | 268 ++++++++++++++++++ 3 files changed, 319 insertions(+), 26 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/loopopts/TestPredicateInputBelowLoopPredicate.java diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index e2b01f61d49..ceb2327edb5 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -5725,38 +5725,45 @@ void PhaseIdealLoop::build_loop_late_post_work(Node *n, bool pinned) { } assert(early == legal || legal != C->root(), "bad dominance of inputs"); + if (least != early) { + // Move the node above predicates as far up as possible so a + // following pass of loop predication doesn't hoist a predicate + // that depends on it above that node. + Node* new_ctrl = least; + for (;;) { + if (!new_ctrl->is_Proj()) { + break; + } + CallStaticJavaNode* call = new_ctrl->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none); + if (call == NULL) { + break; + } + int req = call->uncommon_trap_request(); + Deoptimization::DeoptReason trap_reason = Deoptimization::trap_request_reason(req); + if (trap_reason != Deoptimization::Reason_loop_limit_check && + trap_reason != Deoptimization::Reason_predicate && + trap_reason != Deoptimization::Reason_profile_predicate) { + break; + } + Node* c = new_ctrl->in(0)->in(0); + if (is_dominator(c, early) && c != early) { + break; + } + new_ctrl = c; + } + least = new_ctrl; + } // Try not to place code on a loop entry projection // which can inhibit range check elimination. if (least != early) { Node* ctrl_out = least->unique_ctrl_out(); if (ctrl_out && ctrl_out->is_Loop() && - least == ctrl_out->in(LoopNode::EntryControl)) { - // Move the node above predicates as far up as possible so a - // following pass of loop predication doesn't hoist a predicate - // that depends on it above that node. - Node* new_ctrl = least; - for (;;) { - if (!new_ctrl->is_Proj()) { - break; - } - CallStaticJavaNode* call = new_ctrl->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none); - if (call == NULL) { - break; - } - int req = call->uncommon_trap_request(); - Deoptimization::DeoptReason trap_reason = Deoptimization::trap_request_reason(req); - if (trap_reason != Deoptimization::Reason_loop_limit_check && - trap_reason != Deoptimization::Reason_predicate && - trap_reason != Deoptimization::Reason_profile_predicate) { - break; - } - Node* c = new_ctrl->in(0)->in(0); - if (is_dominator(c, early) && c != early) { - break; - } - new_ctrl = c; + least == ctrl_out->in(LoopNode::EntryControl) && + (ctrl_out->is_CountedLoop() || ctrl_out->is_OuterStripMinedLoop())) { + Node* least_dom = idom(least); + if (get_loop(least_dom)->is_member(get_loop(least))) { + least = least_dom; } - least = new_ctrl; } } diff --git a/src/hotspot/share/opto/split_if.cpp b/src/hotspot/share/opto/split_if.cpp index 05babc625c6..f85f3996ca5 100644 --- a/src/hotspot/share/opto/split_if.cpp +++ b/src/hotspot/share/opto/split_if.cpp @@ -201,6 +201,24 @@ bool PhaseIdealLoop::split_up( Node *n, Node *blk1, Node *blk2 ) { return true; } } + if (n->Opcode() == Op_OpaqueLoopStride || n->Opcode() == Op_OpaqueLoopInit) { + Unique_Node_List wq; + wq.push(n); + for (uint i = 0; i < wq.size(); i++) { + Node* m = wq.at(i); + if (m->is_If()) { + assert(skeleton_predicate_has_opaque(m->as_If()), "opaque node not reachable from if?"); + Node* bol = clone_skeleton_predicate_bool(m, NULL, NULL, m->in(0)); + _igvn.replace_input_of(m, 1, bol); + } else { + assert(!m->is_CFG(), "not CFG expected"); + for (DUIterator_Fast jmax, j = m->fast_outs(jmax); j < jmax; j++) { + Node* u = m->fast_out(j); + wq.push(u); + } + } + } + } // See if splitting-up a Store. Any anti-dep loads must go up as // well. An anti-dep load might be in the wrong block, because in diff --git a/test/hotspot/jtreg/compiler/loopopts/TestPredicateInputBelowLoopPredicate.java b/test/hotspot/jtreg/compiler/loopopts/TestPredicateInputBelowLoopPredicate.java new file mode 100644 index 00000000000..8ffa476ff26 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestPredicateInputBelowLoopPredicate.java @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * bug 8280799 + * @summary С2: assert(false) failed: cyclic dependency prevents range check elimination + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseCountedLoopSafepoints TestPredicateInputBelowLoopPredicate + */ + +public class TestPredicateInputBelowLoopPredicate { + private static final Object object = new Object(); + private static int fieldStop = 100; + private static int[] array = new int[200]; + private static int[] array2 = new int[200]; + private static int fieldStart = 0; + + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + test(true); + test(false); + } + } + + private static void test(boolean flag) { + if (array == null) { + } + int start = fieldStart; + int i = start; + for(;;) { + int j; + for (j = -10; j < 0; j++) { + } + int stop = fieldStop; + // bound check becomes candidate for predication once + // loop above is optimized out + array[stop - i + j] = 0; + + // A bunch of stuff to grow loop body size and prevent peeling: + array2[0] = 0; + array2[1] = 0; + array2[2] = 0; + array2[3] = 0; + array2[4] = 0; + array2[5] = 0; + array2[6] = 0; + array2[7] = 0; + array2[8] = 0; + array2[9] = 0; + array2[10] = 0; + array2[11] = 0; + array2[12] = 0; + array2[13] = 0; + array2[14] = 0; + array2[15] = 0; + array2[16] = 0; + array2[17] = 0; + array2[18] = 0; + array2[19] = 0; + array2[20] = 0; + array2[21] = 0; + array2[22] = 0; + array2[23] = 0; + array2[24] = 0; + array2[25] = 0; + array2[26] = 0; + array2[27] = 0; + array2[28] = 0; + array2[29] = 0; + array2[30] = 0; + array2[31] = 0; + array2[32] = 0; + array2[33] = 0; + array2[34] = 0; + array2[35] = 0; + array2[36] = 0; + array2[37] = 0; + array2[38] = 0; + array2[39] = 0; + array2[40] = 0; + array2[41] = 0; + array2[42] = 0; + array2[43] = 0; + array2[44] = 0; + array2[45] = 0; + array2[46] = 0; + array2[47] = 0; + array2[48] = 0; + array2[49] = 0; + array2[50] = 0; + array2[51] = 0; + array2[52] = 0; + array2[53] = 0; + array2[54] = 0; + array2[55] = 0; + array2[56] = 0; + array2[57] = 0; + array2[58] = 0; + array2[59] = 0; + array2[60] = 0; + array2[61] = 0; + array2[62] = 0; + array2[63] = 0; + array2[64] = 0; + array2[65] = 0; + array2[66] = 0; + array2[67] = 0; + array2[68] = 0; + array2[69] = 0; + array2[70] = 0; + array2[71] = 0; + array2[72] = 0; + array2[73] = 0; + array2[74] = 0; + array2[75] = 0; + array2[76] = 0; + array2[77] = 0; + array2[78] = 0; + array2[79] = 0; + array2[80] = 0; + array2[81] = 0; + array2[82] = 0; + array2[83] = 0; + array2[84] = 0; + array2[85] = 0; + array2[86] = 0; + array2[87] = 0; + array2[88] = 0; + array2[89] = 0; + array2[90] = 0; + array2[91] = 0; + array2[92] = 0; + array2[93] = 0; + array2[94] = 0; + array2[95] = 0; + array2[96] = 0; + array2[97] = 0; + array2[98] = 0; + array2[99] = 0; + + array2[100] = 0; + array2[101] = 0; + array2[102] = 0; + array2[103] = 0; + array2[104] = 0; + array2[105] = 0; + array2[106] = 0; + array2[107] = 0; + array2[108] = 0; + array2[109] = 0; + array2[110] = 0; + array2[111] = 0; + array2[112] = 0; + array2[113] = 0; + array2[114] = 0; + array2[115] = 0; + array2[116] = 0; + array2[117] = 0; + array2[118] = 0; + array2[119] = 0; + array2[120] = 0; + array2[121] = 0; + array2[122] = 0; + array2[123] = 0; + array2[124] = 0; + array2[125] = 0; + array2[126] = 0; + array2[127] = 0; + array2[128] = 0; + array2[129] = 0; + array2[130] = 0; + array2[131] = 0; + array2[132] = 0; + array2[133] = 0; + array2[134] = 0; + array2[135] = 0; + array2[136] = 0; + array2[137] = 0; + array2[138] = 0; + array2[139] = 0; + array2[140] = 0; + array2[141] = 0; + array2[142] = 0; + array2[143] = 0; + array2[144] = 0; + array2[145] = 0; + array2[146] = 0; + array2[147] = 0; + array2[148] = 0; + array2[149] = 0; + array2[150] = 0; + array2[151] = 0; + array2[152] = 0; + array2[153] = 0; + array2[154] = 0; + array2[155] = 0; + array2[156] = 0; + array2[157] = 0; + array2[158] = 0; + array2[159] = 0; + array2[160] = 0; + array2[161] = 0; + array2[162] = 0; + array2[163] = 0; + array2[164] = 0; + array2[165] = 0; + array2[166] = 0; + array2[167] = 0; + array2[168] = 0; + array2[169] = 0; + array2[170] = 0; + array2[171] = 0; + array2[172] = 0; + array2[173] = 0; + array2[174] = 0; + array2[175] = 0; + array2[176] = 0; + array2[177] = 0; + array2[178] = 0; + array2[179] = 0; + array2[180] = 0; + array2[181] = 0; + array2[182] = 0; + array2[183] = 0; + array2[184] = 0; + array2[185] = 0; + array2[186] = 0; + array2[187] = 0; + array2[188] = 0; + array2[189] = 0; + array2[190] = 0; + array2[191] = 0; + array2[192] = 0; + array2[193] = 0; + array2[194] = 0; + array2[195] = 0; + array2[196] = 0; + array2[197] = 0; + array2[198] = 0; + array2[199] = 0; + i++; + + if (i == stop) { // requires a loop limit predicate + break; + } + } + } +} -- GitLab From 46f522962f1b2bbb2513823821e332db1093994b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Casta=C3=B1eda=20Lozano?= Date: Mon, 14 Feb 2022 08:37:31 +0000 Subject: [PATCH 057/203] 8281539: IGV: schedule approximation computes immediate dominators wrongly Replace custom dominator computation with one from the WALA libraries. Reviewed-by: neliasso, chagedorn --- .../ServerCompiler/pom.xml | 7 +- .../ServerCompilerScheduler.java | 173 ++---------------- src/utils/IdealGraphVisualizer/pom.xml | 3 +- 3 files changed, 26 insertions(+), 157 deletions(-) diff --git a/src/utils/IdealGraphVisualizer/ServerCompiler/pom.xml b/src/utils/IdealGraphVisualizer/ServerCompiler/pom.xml index b43145fa974..79209514ebc 100644 --- a/src/utils/IdealGraphVisualizer/ServerCompiler/pom.xml +++ b/src/utils/IdealGraphVisualizer/ServerCompiler/pom.xml @@ -1,6 +1,6 @@ server // client <--- 401 ---- server try (Socket s = ss.accept()) { - new MessageHeader().parseHeader(s.getInputStream()); + new HttpHeaderParser().parse(s.getInputStream()); s.getOutputStream().write(reply.getBytes("US-ASCII")); } @@ -171,10 +171,10 @@ public class NoNTLM { // client <--- 200 ---- server String auth; try (Socket s = ss.accept()) { - MessageHeader mh = new MessageHeader(); - mh.parseHeader(s.getInputStream()); + HttpHeaderParser mh = new HttpHeaderParser(); + mh.parse(s.getInputStream()); s.getOutputStream().write(OKAY.getBytes("US-ASCII")); - auth = mh.findValue("Authorization"); + auth = mh.getHeaderValue("Authorization").get(0); } // check Authorization header @@ -208,7 +208,7 @@ public class NoNTLM { // client ---- GET ---> server // client <--- 401 ---- client try (Socket s = ss.accept()) { - new MessageHeader().parseHeader(s.getInputStream()); + new HttpHeaderParser().parse(s.getInputStream()); s.getOutputStream().write(reply.getBytes("US-ASCII")); } diff --git a/test/jdk/sun/net/www/protocol/http/RetryUponTimeout.java b/test/jdk/sun/net/www/protocol/http/RetryUponTimeout.java index bfda1663259..b2214780c2e 100644 --- a/test/jdk/sun/net/www/protocol/http/RetryUponTimeout.java +++ b/test/jdk/sun/net/www/protocol/http/RetryUponTimeout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,13 +26,13 @@ * @bug 4772077 * @library /test/lib * @summary using defaultReadTimeout appear to retry request upon timeout - * @modules java.base/sun.net.www */ import java.net.*; import java.io.*; + +import jdk.test.lib.net.HttpHeaderParser; import jdk.test.lib.net.URIBuilder; -import sun.net.www.*; public class RetryUponTimeout implements Runnable { // run server @@ -42,7 +42,7 @@ public class RetryUponTimeout implements Runnable { for (int i = 0; i < 2; i++) { socket = server.accept(); InputStream is = socket.getInputStream (); - MessageHeader header = new MessageHeader (is); + HttpHeaderParser header = new HttpHeaderParser (is); count++; } } catch (Exception ex) { diff --git a/test/jdk/sun/net/www/protocol/http/UserAgent.java b/test/jdk/sun/net/www/protocol/http/UserAgent.java index 7db84882488..40ff5d3106f 100644 --- a/test/jdk/sun/net/www/protocol/http/UserAgent.java +++ b/test/jdk/sun/net/www/protocol/http/UserAgent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ * @test * @bug 4512200 * @library /test/lib - * @modules java.base/sun.net.www * @run main/othervm -Dhttp.agent=foo UserAgent * @run main/othervm -Dhttp.agent=foo -Djava.net.preferIPv6Addresses=true UserAgent * @summary HTTP header "User-Agent" format incorrect @@ -34,8 +33,9 @@ import java.io.*; import java.util.*; import java.net.*; + +import jdk.test.lib.net.HttpHeaderParser; import jdk.test.lib.net.URIBuilder; -import sun.net.www.MessageHeader; class Server extends Thread { Server (ServerSocket server) { @@ -46,8 +46,8 @@ class Server extends Thread { String version = System.getProperty ("java.version"); String expected = "foo Java/"+version; Socket s = server.accept (); - MessageHeader header = new MessageHeader (s.getInputStream()); - String v = header.findValue ("User-Agent"); + HttpHeaderParser header = new HttpHeaderParser (s.getInputStream()); + String v = header.getHeaderValue ("User-Agent").get(0); if (!expected.equals (v)) { error ("Got unexpected User-Agent: " + v); } else { diff --git a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/B6226610.java b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/B6226610.java index ec75bcc3e11..9fca12c9958 100644 --- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/B6226610.java +++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/B6226610.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @bug 6226610 6973030 * @summary HTTP tunnel connections send user headers to proxy - * @modules java.base/sun.net.www + * @library /test/lib * @run main/othervm B6226610 */ @@ -37,7 +37,9 @@ import java.io.*; import java.net.*; -import sun.net.www.MessageHeader; + +import jdk.test.lib.net.HttpHeaderParser; + public class B6226610 { static HeaderCheckerProxyTunnelServer proxy; @@ -138,21 +140,21 @@ class HeaderCheckerProxyTunnelServer extends Thread private void processRequests() throws IOException { InputStream in = clientSocket.getInputStream(); - MessageHeader mheader = new MessageHeader(in); - String statusLine = mheader.getValue(0); + HttpHeaderParser mheader = new HttpHeaderParser(in); + String statusLine = mheader.getRequestDetails(); if (statusLine.startsWith("CONNECT")) { // retrieve the host and port info from the status-line retrieveConnectInfo(statusLine); - if (mheader.findValue("X-TestHeader") != null) { + if (mheader.getHeaderValue("X-TestHeader") != null) { System.out.println("Proxy should not receive user defined headers for tunneled requests"); failed = true; } // 6973030 String value; - if ((value = mheader.findValue("Proxy-Connection")) == null || + if ((value = mheader.getHeaderValue("Proxy-Connection").get(0)) == null || !value.equals("keep-alive")) { System.out.println("Proxy-Connection:keep-alive not being sent"); failed = true; diff --git a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/TunnelProxy.java b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/TunnelProxy.java index 9573543fde1..979e8be9acd 100644 --- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/TunnelProxy.java +++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/TunnelProxy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,7 +45,8 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Set; -import sun.net.www.MessageHeader; +import jdk.test.lib.net.HttpHeaderParser; + public class TunnelProxy { @@ -261,7 +262,7 @@ public class TunnelProxy { try { InputStream is = new BufferedInputStream (new NioInputStream (chan)); String requestline = readLine (is); - MessageHeader mhead = new MessageHeader (is); + HttpHeaderParser mhead = new HttpHeaderParser (is); String[] req = requestline.split (" "); if (req.length < 2) { /* invalid request line */ diff --git a/test/lib/jdk/test/lib/net/HttpHeaderParser.java b/test/lib/jdk/test/lib/net/HttpHeaderParser.java new file mode 100644 index 00000000000..71b3a84fdaa --- /dev/null +++ b/test/lib/jdk/test/lib/net/HttpHeaderParser.java @@ -0,0 +1,390 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.lib.net; + +import java.io.IOException; +import java.io.InputStream; +import java.net.ProtocolException; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import static java.util.Objects.requireNonNull; + +public class HttpHeaderParser { + private static final char CR = '\r'; + private static final char LF = '\n'; + private static final char HT = '\t'; + private static final char SP = ' '; + // ABNF primitives defined in RFC 7230 + private static boolean[] tchar = new boolean[256]; + private static boolean[] fieldvchar = new boolean[256]; + + static { + char[] allowedTokenChars = + ("!#$%&'*+-.^_`|~0123456789" + + "abcdefghijklmnopqrstuvwxyz" + + "ABCDEFGHIJKLMNOPQRSTUVWXYZ").toCharArray(); + for (char c : allowedTokenChars) { + tchar[c] = true; + } + for (char c = 0x21; c <= 0xFF; c++) { + fieldvchar[c] = true; + } + fieldvchar[0x7F] = false; // a little hole (DEL) in the range + } + + private StringBuilder sb = new StringBuilder(); + + private Map > headerMap = new LinkedHashMap<>(); + private List keyList = new ArrayList<>(); + private String requestOrStatusLine; + private int responseCode; + private boolean eof; + + + + enum State { INITIAL, + STATUS_OR_REQUEST_LINE, + STATUS_OR_REQUEST_LINE_FOUND_CR, + STATUS_OR_REQUEST_LINE_FOUND_LF, + STATUS_OR_REQUEST_LINE_END, + STATUS_OR_REQUEST_LINE_END_CR, + STATUS_OR_REQUEST_LINE_END_LF, + HEADER, + HEADER_FOUND_CR, + HEADER_FOUND_LF, + HEADER_FOUND_CR_LF, + HEADER_FOUND_CR_LF_CR, + FINISHED } + + private HttpHeaderParser.State state = HttpHeaderParser.State.INITIAL; + + public HttpHeaderParser() { + } + + + public HttpHeaderParser(InputStream is) throws IOException, ProtocolException { + parse(is); + } + + public Map> getHeaderMap() { + return headerMap; + } + + public List getHeaderValue(String key) { + if(headerMap.containsKey(key.toLowerCase(Locale.ROOT))) { + return headerMap.get(key.toLowerCase(Locale.ROOT)); + } + return null; + } + public List getValue(int id) { + String key = keyList.get(id); + return headerMap.get(key); + } + + public String getRequestDetails() { + return requestOrStatusLine; + } + + /** + * Parses HTTP/1.X status-line or request-line and headers from the given input stream. + * @param input Containing the input stream of bytes representing request or response header data + * @return true if the end of the headers block has been reached + */ + public boolean parse(InputStream input) throws IOException { + requireNonNull(input, "null input"); + while (canContinueParsing()) { + switch (state) { + case INITIAL -> state = HttpHeaderParser.State.STATUS_OR_REQUEST_LINE; + case STATUS_OR_REQUEST_LINE -> readResumeStatusLine(input); + case STATUS_OR_REQUEST_LINE_FOUND_CR, STATUS_OR_REQUEST_LINE_FOUND_LF -> readStatusLineFeed(input); + case STATUS_OR_REQUEST_LINE_END -> maybeStartHeaders(input); + case STATUS_OR_REQUEST_LINE_END_CR, STATUS_OR_REQUEST_LINE_END_LF -> maybeEndHeaders(input); + case HEADER -> readResumeHeader(input); + case HEADER_FOUND_CR, HEADER_FOUND_LF -> resumeOrLF(input); + case HEADER_FOUND_CR_LF -> resumeOrSecondCR(input); + case HEADER_FOUND_CR_LF_CR -> resumeOrEndHeaders(input); + default -> throw new InternalError("Unexpected state: " + state); + } + } + return state == HttpHeaderParser.State.FINISHED; + } + + private boolean canContinueParsing() { + // some states don't require any input to transition + // to the next state. + return switch (state) { + case FINISHED -> false; + case STATUS_OR_REQUEST_LINE_FOUND_LF, STATUS_OR_REQUEST_LINE_END_LF, HEADER_FOUND_LF -> true; + default -> !eof; + }; + } + + /** + * Returns a character (char) corresponding to the next byte in the + * input, interpreted as an ISO-8859-1 encoded character. + *

+ * The ISO-8859-1 encoding is a 8-bit character coding that + * corresponds to the first 256 Unicode characters - from U+0000 to + * U+00FF. UTF-16 is backward compatible with ISO-8859-1 - which + * means each byte in the input should be interpreted as an unsigned + * value from [0, 255] representing the character code. + * + * @param input a {@code InputStream} containing input stream of Bytes. + * @return the next byte in the input, interpreted as an ISO-8859-1 + * encoded char + * @throws IOException + * if an I/O error occurs. + */ + private char get(InputStream input) throws IOException { + int c = input.read(); + if(c < 0) + eof = true; + return (char)(c & 0xFF); + } + + private void readResumeStatusLine(InputStream input) throws IOException { + char c; + while ((c = get(input)) != CR && !eof) { + if (c == LF) break; + sb.append(c); + } + if (c == CR) { + state = HttpHeaderParser.State.STATUS_OR_REQUEST_LINE_FOUND_CR; + } else if (c == LF) { + state = HttpHeaderParser.State.STATUS_OR_REQUEST_LINE_FOUND_LF; + } + } + + private void readStatusLineFeed(InputStream input) throws IOException { + char c = state == HttpHeaderParser.State.STATUS_OR_REQUEST_LINE_FOUND_LF ? LF : get(input); + if (c != LF) { + throw protocolException("Bad trailing char, \"%s\", when parsing status line, \"%s\"", + c, sb.toString()); + } + requestOrStatusLine = sb.toString(); + sb = new StringBuilder(); + if (!requestOrStatusLine.startsWith("HTTP/1.")) { + if(!requestOrStatusLine.startsWith("GET") && !requestOrStatusLine.startsWith("POST") && + !requestOrStatusLine.startsWith("PUT") && !requestOrStatusLine.startsWith("DELETE") && + !requestOrStatusLine.startsWith("OPTIONS") && !requestOrStatusLine.startsWith("HEAD") && + !requestOrStatusLine.startsWith("PATCH") && !requestOrStatusLine.startsWith("CONNECT")) { + throw protocolException("Invalid request Or Status line: \"%s\"", requestOrStatusLine); + } else { //This is request + System.out.println("Request is :"+requestOrStatusLine); + } + } else { //This is response + if (requestOrStatusLine.length() < 12) { + throw protocolException("Invalid status line: \"%s\"", requestOrStatusLine); + } + try { + responseCode = Integer.parseInt(requestOrStatusLine.substring(9, 12)); + } catch (NumberFormatException nfe) { + throw protocolException("Invalid status line: \"%s\"", requestOrStatusLine); + } + // response code expected to be a 3-digit integer (RFC-2616, section 6.1.1) + if (responseCode < 100) { + throw protocolException("Invalid status line: \"%s\"", requestOrStatusLine); + } + } + state = HttpHeaderParser.State.STATUS_OR_REQUEST_LINE_END; + } + + private void maybeStartHeaders(InputStream input) throws IOException { + assert state == HttpHeaderParser.State.STATUS_OR_REQUEST_LINE_END; + assert sb.length() == 0; + char c = get(input); + if(!eof) { + if (c == CR) { + state = HttpHeaderParser.State.STATUS_OR_REQUEST_LINE_END_CR; + } else if (c == LF) { + state = HttpHeaderParser.State.STATUS_OR_REQUEST_LINE_END_LF; + } else { + sb.append(c); + state = HttpHeaderParser.State.HEADER; + } + } + } + + private void maybeEndHeaders(InputStream input) throws IOException { + assert state == HttpHeaderParser.State.STATUS_OR_REQUEST_LINE_END_CR || state == HttpHeaderParser.State.STATUS_OR_REQUEST_LINE_END_LF; + assert sb.length() == 0; + char c = state == HttpHeaderParser.State.STATUS_OR_REQUEST_LINE_END_LF ? LF : get(input); + if (c == LF) { + state = HttpHeaderParser.State.FINISHED; // no headers + } else { + throw protocolException("Unexpected \"%s\", after status line CR", c); + } + } + + private void readResumeHeader(InputStream input) throws IOException { + assert state == HttpHeaderParser.State.HEADER; + assert !eof; + char c = get(input); + while (!eof) { + if (c == CR) { + state = HttpHeaderParser.State.HEADER_FOUND_CR; + break; + } else if (c == LF) { + state = HttpHeaderParser.State.HEADER_FOUND_LF; + break; + } + if (c == HT) + c = SP; + sb.append(c); + c = get(input); + } + } + + private void addHeaderFromString(String headerString) throws ProtocolException { + assert sb.length() == 0; + int idx = headerString.indexOf(':'); + if (idx == -1) + return; + String name = headerString.substring(0, idx); + + // compatibility with HttpURLConnection; + if (name.isEmpty()) return; + + if (!isValidName(name)) { + throw protocolException("Invalid header name \"%s\"", name); + } + String value = headerString.substring(idx + 1).trim(); + if (!isValidValue(value)) { + throw protocolException("Invalid header value \"%s: %s\"", name, value); + } + + keyList.add(name); + headerMap.computeIfAbsent(name.toLowerCase(Locale.US), + k -> new ArrayList<>()).add(value); + } + + private void resumeOrLF(InputStream input) throws IOException { + assert state == HttpHeaderParser.State.HEADER_FOUND_CR || state == HttpHeaderParser.State.HEADER_FOUND_LF; + char c = state == HttpHeaderParser.State.HEADER_FOUND_LF ? LF : get(input); + if (!eof) { + if (c == LF) { + state = HttpHeaderParser.State.HEADER_FOUND_CR_LF; + } else if (c == SP || c == HT) { + sb.append(SP); // parity with MessageHeaders + state = HttpHeaderParser.State.HEADER; + } else { + sb = new StringBuilder(); + sb.append(c); + state = HttpHeaderParser.State.HEADER; + } + } + } + + private void resumeOrSecondCR(InputStream input) throws IOException { + assert state == HttpHeaderParser.State.HEADER_FOUND_CR_LF; + char c = get(input); + if (!eof) { + if (c == CR || c == LF) { + if (sb.length() > 0) { + // no continuation line - flush + // previous header value. + String headerString = sb.toString(); + sb = new StringBuilder(); + addHeaderFromString(headerString); + } + if (c == CR) { + state = HttpHeaderParser.State.HEADER_FOUND_CR_LF_CR; + } else { + state = HttpHeaderParser.State.FINISHED; + } + } else if (c == SP || c == HT) { + assert sb.length() != 0; + sb.append(SP); // continuation line + state = HttpHeaderParser.State.HEADER; + } else { + if (sb.length() > 0) { + // no continuation line - flush + // previous header value. + String headerString = sb.toString(); + sb = new StringBuilder(); + addHeaderFromString(headerString); + } + sb.append(c); + state = HttpHeaderParser.State.HEADER; + } + } + } + + private void resumeOrEndHeaders(InputStream input) throws IOException { + assert state == HttpHeaderParser.State.HEADER_FOUND_CR_LF_CR; + char c = get(input); + if (!eof) { + if (c == LF) { + state = HttpHeaderParser.State.FINISHED; + } else { + throw protocolException("Unexpected \"%s\", after CR LF CR", c); + } + } + } + + private ProtocolException protocolException(String format, Object ... args) { + return new ProtocolException(String.format(format, args)); + } + + /* + * Validates a RFC 7230 field-name. + */ + public boolean isValidName(String token) { + for (int i = 0; i < token.length(); i++) { + char c = token.charAt(i); + if (c > 255 || !tchar[c]) { + return false; + } + } + return !token.isEmpty(); + } + + /* + * Validates a RFC 7230 field-value. + * + * "Obsolete line folding" rule + * + * obs-fold = CRLF 1*( SP / HTAB ) + * + * is not permitted! + */ + public boolean isValidValue(String token) { + for (int i = 0; i < token.length(); i++) { + char c = token.charAt(i); + if (c > 255) { + return false; + } + if (c == ' ' || c == '\t') { + continue; + } else if (!fieldvchar[c]) { + return false; // forbidden byte + } + } + return true; + } +} -- GitLab From 9b74c3f2e74a4efdec1c1488e96ab5939a408df0 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Wed, 16 Feb 2022 16:54:53 +0000 Subject: [PATCH 095/203] 8176706: Additional Date-Time Formats Reviewed-by: joehw, rriggs --- .../build/tools/cldrconverter/Bundle.java | 82 ++++-- .../tools/cldrconverter/CLDRConverter.java | 20 +- .../tools/cldrconverter/LDMLParseHandler.java | 12 +- .../SupplementDataParseHandler.java | 52 ++-- .../java/time/format/DateTimeFormatter.java | 54 +++- .../time/format/DateTimeFormatterBuilder.java | 204 ++++++++++++--- .../spi/JavaTimeDateTimePatternProvider.java | 27 +- .../provider/JavaTimeDateTimePatternImpl.java | 22 +- .../util/locale/provider/LocaleResources.java | 233 +++++++++++++++++- .../time/format/Skeletons_en_US.properties | 51 ++++ .../java/time/format/Skeletons_ja.properties | 43 ++++ .../time/format/TestLocalizedPattern.java | 105 ++++++++ 12 files changed, 809 insertions(+), 96 deletions(-) create mode 100644 test/jdk/java/time/test/java/time/format/Skeletons_en_US.properties create mode 100644 test/jdk/java/time/test/java/time/format/Skeletons_ja.properties create mode 100644 test/jdk/java/time/test/java/time/format/TestLocalizedPattern.java diff --git a/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java b/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java index 9f262fa0106..952e28fd43b 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,9 @@ package build.tools.cldrconverter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; @@ -34,6 +37,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.stream.Collectors; import java.util.stream.IntStream; class Bundle { @@ -47,21 +51,21 @@ class Bundle { FORMATDATA); } - private final static Map bundles = new HashMap<>(); + private static final Map bundles = new HashMap<>(); - private final static String[] NUMBER_PATTERN_KEYS = { + private static final String[] NUMBER_PATTERN_KEYS = { "NumberPatterns/decimal", "NumberPatterns/currency", "NumberPatterns/percent", "NumberPatterns/accounting" }; - private final static String[] COMPACT_NUMBER_PATTERN_KEYS = { - "short.CompactNumberPatterns", - "long.CompactNumberPatterns" + private static final String[] COMPACT_NUMBER_PATTERN_KEYS = { + "short.CompactNumberPatterns", + "long.CompactNumberPatterns" }; - private final static String[] NUMBER_ELEMENT_KEYS = { + private static final String[] NUMBER_ELEMENT_KEYS = { "NumberElements/decimal", "NumberElements/group", "NumberElements/list", @@ -77,41 +81,45 @@ class Bundle { "NumberElements/currencyGroup", }; - private final static String[] TIME_PATTERN_KEYS = { + private static final String[] TIME_PATTERN_KEYS = { "DateTimePatterns/full-time", "DateTimePatterns/long-time", "DateTimePatterns/medium-time", "DateTimePatterns/short-time", }; - private final static String[] DATE_PATTERN_KEYS = { + private static final String[] DATE_PATTERN_KEYS = { "DateTimePatterns/full-date", "DateTimePatterns/long-date", "DateTimePatterns/medium-date", "DateTimePatterns/short-date", }; - private final static String[] DATETIME_PATTERN_KEYS = { + private static final String[] DATETIME_PATTERN_KEYS = { "DateTimePatterns/full-dateTime", "DateTimePatterns/long-dateTime", "DateTimePatterns/medium-dateTime", "DateTimePatterns/short-dateTime", }; - private final static String[] ERA_KEYS = { + private static final String[] ERA_KEYS = { "long.Eras", "Eras", "narrow.Eras" }; + // DateFormatItem prefix + static final String DATEFORMATITEM_KEY_PREFIX = "DateFormatItem."; + static final String DATEFORMATITEM_INPUT_REGIONS_PREFIX = "DateFormatItemInputRegions."; + // Keys for individual time zone names - private final static String TZ_GEN_LONG_KEY = "timezone.displayname.generic.long"; - private final static String TZ_GEN_SHORT_KEY = "timezone.displayname.generic.short"; - private final static String TZ_STD_LONG_KEY = "timezone.displayname.standard.long"; - private final static String TZ_STD_SHORT_KEY = "timezone.displayname.standard.short"; - private final static String TZ_DST_LONG_KEY = "timezone.displayname.daylight.long"; - private final static String TZ_DST_SHORT_KEY = "timezone.displayname.daylight.short"; - private final static String[] ZONE_NAME_KEYS = { + private static final String TZ_GEN_LONG_KEY = "timezone.displayname.generic.long"; + private static final String TZ_GEN_SHORT_KEY = "timezone.displayname.generic.short"; + private static final String TZ_STD_LONG_KEY = "timezone.displayname.standard.long"; + private static final String TZ_STD_SHORT_KEY = "timezone.displayname.standard.short"; + private static final String TZ_DST_LONG_KEY = "timezone.displayname.daylight.long"; + private static final String TZ_DST_SHORT_KEY = "timezone.displayname.daylight.short"; + private static final String[] ZONE_NAME_KEYS = { TZ_STD_LONG_KEY, TZ_STD_SHORT_KEY, TZ_DST_LONG_KEY, @@ -262,7 +270,7 @@ class Bundle { CLDRConverter.handleAliases(myMap); // another hack: parentsMap is not used for date-time resources. - if ("root".equals(id)) { + if (isRoot()) { parentsMap = null; } @@ -287,6 +295,14 @@ class Bundle { handleDateTimeFormatPatterns(TIME_PATTERN_KEYS, myMap, parentsMap, calendarType, "TimePatterns"); handleDateTimeFormatPatterns(DATE_PATTERN_KEYS, myMap, parentsMap, calendarType, "DatePatterns"); handleDateTimeFormatPatterns(DATETIME_PATTERN_KEYS, myMap, parentsMap, calendarType, "DateTimePatterns"); + + // Skeleton + handleSkeletonPatterns(myMap, calendarType); + } + + // Skeleton input regions + if (isRoot()) { + skeletonInputRegions(myMap); } // First, weed out any empty timezone or metazone names from myMap. @@ -647,8 +663,9 @@ class Bundle { private void convertDateTimePatternLetter(CalendarType calendarType, char cldrLetter, int count, StringBuilder sb) { switch (cldrLetter) { case 'u': - // Change cldr letter 'u' to 'y', as 'u' is interpreted as - // "Extended year (numeric)" in CLDR/LDML, + case 'U': + // Change cldr letter 'u'/'U' to 'y', as 'u' is interpreted as + // "Extended year (numeric)", and 'U' as "Cyclic year" in CLDR/LDML, // which is not supported in SimpleDateFormat and // j.t.f.DateTimeFormatter, so it is replaced with 'y' // as the best approximation @@ -742,6 +759,19 @@ class Bundle { return false; } + private void handleSkeletonPatterns(Map myMap, CalendarType calendarType) { + String calendarPrefix = calendarType.keyElementName(); + myMap.putAll(myMap.entrySet().stream() + .filter(e -> e.getKey().startsWith(Bundle.DATEFORMATITEM_KEY_PREFIX)) + .collect(Collectors.toMap( + e -> calendarPrefix + e.getKey(), + e -> translateDateFormatLetters(calendarType, + (String)e.getValue(), + this::convertDateTimePatternLetter) + )) + ); + } + @FunctionalInterface private interface ConvertDateTimeLetters { void convert(CalendarType calendarType, char cldrLetter, int count, StringBuilder sb); @@ -790,4 +820,14 @@ class Bundle { } return numArray; } + + private static void skeletonInputRegions(Map myMap) { + myMap.putAll(myMap.entrySet().stream() + .filter(e -> e.getKey().startsWith(Bundle.DATEFORMATITEM_INPUT_REGIONS_PREFIX)) + .collect(Collectors.toMap( + e -> e.getKey(), + e -> ((String)e.getValue()).trim() + )) + ); + } } diff --git a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java index 267f93e733b..abf1be64306 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -847,20 +847,19 @@ public class CLDRConverter { "DateTimePatternChars", "PluralRules", "DayPeriodRules", + "DateFormatItem", }; private static Map extractFormatData(Map map, String id) { Map formatData = new LinkedHashMap<>(); for (CalendarType calendarType : CalendarType.values()) { - if (calendarType == CalendarType.GENERIC) { - continue; - } String prefix = calendarType.keyElementName(); - for (String element : FORMAT_DATA_ELEMENTS) { - String key = prefix + element; - copyIfPresent(map, "java.time." + key, formatData); - copyIfPresent(map, key, formatData); - } + Arrays.stream(FORMAT_DATA_ELEMENTS) + .flatMap(elem -> map.keySet().stream().filter(k -> k.startsWith(prefix + elem))) + .forEach(key -> { + copyIfPresent(map, "java.time." + key, formatData); + copyIfPresent(map, key, formatData); + }); } for (String key : map.keySet()) { @@ -868,9 +867,6 @@ public class CLDRConverter { if (key.startsWith(CLDRConverter.LOCALE_TYPE_PREFIX_CA)) { String type = key.substring(CLDRConverter.LOCALE_TYPE_PREFIX_CA.length()); for (CalendarType calendarType : CalendarType.values()) { - if (calendarType == CalendarType.GENERIC) { - continue; - } if (type.equals(calendarType.lname())) { Object value = map.get(key); String dataKey = key.replace(LOCALE_TYPE_PREFIX_CA, diff --git a/make/jdk/src/classes/build/tools/cldrconverter/LDMLParseHandler.java b/make/jdk/src/classes/build/tools/cldrconverter/LDMLParseHandler.java index 745796d96cf..668c187c383 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/LDMLParseHandler.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/LDMLParseHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -756,6 +756,14 @@ class LDMLParseHandler extends AbstractLDMLHandler { pushStringEntry(qName, attributes, prefix + "DateTimePatterns/" + attributes.getValue("type") + "-dateTime"); } break; + case "dateFormatItem": + { + // for FormatData + String prefix = (currentCalendarType == null) ? "" : currentCalendarType.keyElementName(); + pushStringEntry(qName, attributes, + prefix + Bundle.DATEFORMATITEM_KEY_PREFIX + attributes.getValue("id")); + } + break; case "localizedPatternChars": { // for FormatData @@ -1113,7 +1121,7 @@ class LDMLParseHandler extends AbstractLDMLHandler { if (id.equals("root") && key.startsWith("MonthNames")) { value = new DateFormatSymbols(Locale.US).getShortMonths(); } - return put(entry.getKey(), value); + return put(key, value); } } return null; diff --git a/make/jdk/src/classes/build/tools/cldrconverter/SupplementDataParseHandler.java b/make/jdk/src/classes/build/tools/cldrconverter/SupplementDataParseHandler.java index fdc8a977766..11547ccb38e 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/SupplementDataParseHandler.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/SupplementDataParseHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,8 +27,12 @@ package build.tools.cldrconverter; import java.io.File; import java.io.IOException; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.stream.Collectors; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; @@ -62,10 +66,15 @@ class SupplementDataParseHandler extends AbstractLDMLHandler { // parentLocale.=(" ")+ private final Map parentLocalesMap; + // Input Skeleton map for "preferred" and "allowed" + // Map<"preferred"/"allowed", Map<"skeleton", SortedSet<"regions">>> + private final Map>> inputSkeletonMap; + SupplementDataParseHandler() { firstDayMap = new HashMap<>(); minDaysMap = new HashMap<>(); parentLocalesMap = new HashMap<>(); + inputSkeletonMap = new HashMap<>(); } /** @@ -76,22 +85,25 @@ class SupplementDataParseHandler extends AbstractLDMLHandler { * It returns null when there is no firstDay and minDays for the country * although this should not happen because supplementalData.xml includes * default value for the world ("001") for firstDay and minDays. + * + * This method also returns Maps for "preferred" and "allowed" skeletons, + * which are grouped by regions. E.g, "h:XX YY ZZ;" which means 'h' pattern + * is "preferred"/"allowed" in "XX", "YY", and "ZZ" regions. */ Map getData(String id) { Map values = new HashMap<>(); if ("root".equals(id)) { - parentLocalesMap.keySet().forEach(key -> { - values.put(CLDRConverter.PARENT_LOCALE_PREFIX+key, - parentLocalesMap.get(key)); - }); - firstDayMap.keySet().forEach(key -> { - values.put(CLDRConverter.CALENDAR_FIRSTDAY_PREFIX+firstDayMap.get(key), - key); - }); - minDaysMap.keySet().forEach(key -> { - values.put(CLDRConverter.CALENDAR_MINDAYS_PREFIX+minDaysMap.get(key), - key); - }); + parentLocalesMap.forEach((k, v) -> values.put(CLDRConverter.PARENT_LOCALE_PREFIX + k, v)); + firstDayMap.forEach((k, v) -> values.put(CLDRConverter.CALENDAR_FIRSTDAY_PREFIX + v, k)); + minDaysMap.forEach((k, v) -> values.put(CLDRConverter.CALENDAR_MINDAYS_PREFIX + v, k)); + inputSkeletonMap.get("preferred").forEach((k, v) -> + values.merge(Bundle.DATEFORMATITEM_INPUT_REGIONS_PREFIX + "preferred", + k + ":" + v.stream().collect(Collectors.joining(" ")) + ";", + (old, newVal) -> old + (String)newVal)); + inputSkeletonMap.get("allowed").forEach((k, v) -> + values.merge(Bundle.DATEFORMATITEM_INPUT_REGIONS_PREFIX + "allowed", + k + ":" + v.stream().collect(Collectors.joining(" ")) + ";", + (old, newVal) -> old + (String)newVal)); } return values.isEmpty() ? null : values; } @@ -158,11 +170,23 @@ class SupplementDataParseHandler extends AbstractLDMLHandler { attributes.getValue("locales").replaceAll("_", "-")); } break; + case "hours": + if (!isIgnored(attributes)) { + var preferred = attributes.getValue("preferred"); + var allowed = attributes.getValue("allowed").replaceFirst(" .*", "").replaceFirst("b", "B"); // take only the first one, "b" -> "B" + var regions = Arrays.stream(attributes.getValue("regions").split(" ")) + .map(r -> r.replaceAll("_", "-")) + .collect(Collectors.toSet()); + var pmap = inputSkeletonMap.computeIfAbsent("preferred", k -> new HashMap<>()); + var amap = inputSkeletonMap.computeIfAbsent("allowed", k -> new HashMap<>()); + pmap.computeIfAbsent(preferred, k -> new TreeSet<>()).addAll(regions); + amap.computeIfAbsent(allowed, k -> new TreeSet<>()).addAll(regions); + } + break; default: // treat anything else as a container pushContainer(qName, attributes); break; } } - } diff --git a/src/java.base/share/classes/java/time/format/DateTimeFormatter.java b/src/java.base/share/classes/java/time/format/DateTimeFormatter.java index 063b6e14a00..0a67e22c0f3 100644 --- a/src/java.base/share/classes/java/time/format/DateTimeFormatter.java +++ b/src/java.base/share/classes/java/time/format/DateTimeFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,7 +81,6 @@ import java.time.Period; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.chrono.ChronoLocalDateTime; -import java.time.chrono.ChronoZonedDateTime; import java.time.chrono.Chronology; import java.time.chrono.IsoChronology; import java.time.format.DateTimeFormatterBuilder.CompositePrinterParser; @@ -718,6 +717,57 @@ public final class DateTimeFormatter { .toFormatter(ResolverStyle.SMART, IsoChronology.INSTANCE); } + //----------------------------------------------------------------------- + /** + * Creates a locale specific formatter derived from the requested template for + * the ISO chronology. The requested template is a series of typical pattern + * symbols in canonical order from the largest date or time unit to the smallest, + * which can be expressed with the following regular expression: + * {@snippet : + * "G{0,5}" + // Era + * "y*" + // Year + * "Q{0,5}" + // Quarter + * "M{0,5}" + // Month + * "w*" + // Week of Week Based Year + * "E{0,5}" + // Day of Week + * "d{0,2}" + // Day of Month + * "B{0,5}" + // Period/AmPm of Day + * "[hHjC]{0,2}" + // Hour of Day/AmPm (refer to LDML for 'j' and 'C') + * "m{0,2}" + // Minute of Hour + * "s{0,2}" + // Second of Minute + * "[vz]{0,4}" // Zone + * } + * All pattern symbols are optional, and each pattern symbol represents a field, + * for example, 'M' represents the Month field. The number of the pattern symbol letters follows the + * same presentation, such as "number" or "text" as in the Patterns for + * Formatting and Parsing section. Other pattern symbols in the requested template are + * invalid. + *

+ * The mapping of the requested template to the closest of the available localized formats + * is defined by the + * + * Unicode LDML specification. For example, the formatter created from the requested template + * {@code yMMM} will format the date '2020-06-16' to 'Jun 2020' in the {@link Locale#US US locale}. + *

+ * The locale is determined from the formatter. The formatter returned directly by + * this method uses the {@link Locale#getDefault() default FORMAT locale}. + * The locale can be controlled using {@link DateTimeFormatter#withLocale(Locale) withLocale(Locale)} + * on the result of this method. + *

+ * The returned formatter has no override zone. + * It uses {@link ResolverStyle#SMART SMART} resolver style. + * + * @param requestedTemplate the requested template, not null + * @return the formatter based on the {@code requestedTemplate} pattern, not null + * @throws IllegalArgumentException if {@code requestedTemplate} is invalid + * @see #ofPattern(String) + * @since 19 + */ + public static DateTimeFormatter ofLocalizedPattern(String requestedTemplate) { + return new DateTimeFormatterBuilder().appendLocalized(requestedTemplate) + .toFormatter(ResolverStyle.SMART, IsoChronology.INSTANCE); + } + //----------------------------------------------------------------------- /** * The ISO date formatter that formats or parses a date without an diff --git a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java index 40c0de53d3f..62ea488ede7 100644 --- a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java +++ b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -227,6 +227,42 @@ public final class DateTimeFormatterBuilder { CalendarDataUtility.findRegionOverride(locale)); } + /** + * Returns the formatting pattern for the requested template for a locale and chronology. + * The locale and chronology are used to lookup the locale specific format + * for the requested template. + *

+ * If the locale contains the "rg" (region override) + * Unicode extensions, + * the formatting pattern is overridden with the one appropriate for the region. + *

+ * Refer to {@link #appendLocalized(String)} for the detail of {@code requestedTemplate} + * argument. + * + * @param requestedTemplate the requested template, not null + * @param chrono the Chronology, non-null + * @param locale the locale, non-null + * @return the locale and Chronology specific formatting pattern + * @throws IllegalArgumentException if {@code requestedTemplate} does not match + * the regular expression syntax described in {@link #appendLocalized(String)}. + * @throws DateTimeException if a match for the localized pattern for + * {@code requestedTemplate} is not available + * @see #appendLocalized(String) + * @since 19 + */ + public static String getLocalizedDateTimePattern(String requestedTemplate, + Chronology chrono, Locale locale) { + Objects.requireNonNull(requestedTemplate, "requestedTemplate"); + Objects.requireNonNull(chrono, "chrono"); + Objects.requireNonNull(locale, "locale"); + Locale override = CalendarDataUtility.findRegionOverride(locale); + LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(JavaTimeDateTimePatternProvider.class, override); + JavaTimeDateTimePatternProvider provider = adapter.getJavaTimeDateTimePatternProvider(); + return provider.getJavaTimeDateTimePattern(requestedTemplate, + chrono.getCalendarType(), + override); + } + /** * Converts the given FormatStyle to the java.text.DateFormat style. * @@ -1423,6 +1459,84 @@ public final class DateTimeFormatterBuilder { return this; } + //----------------------------------------------------------------------- + // RegEx pattern for skeleton validity checking + private static final Pattern VALID_TEMPLATE_PATTERN = Pattern.compile( + "G{0,5}" + // Era + "y*" + // Year + "Q{0,5}" + // Quarter + "M{0,5}" + // Month + "w*" + // Week of Week Based Year + "E{0,5}" + // Day of Week + "d{0,2}" + // Day of Month + "B{0,5}" + // Period/AmPm of Day + "[hHjC]{0,2}" + // Hour of Day/AmPm + "m{0,2}" + // Minute of Hour + "s{0,2}" + // Second of Minute + "[vz]{0,4}"); // Zone + /** + * Appends a localized pattern to the formatter using the requested template. + *

+ * This appends a localized section to the builder, suitable for outputting + * a date, time or date-time combination. The format of the localized + * section is lazily looked up based on three items: + *

    + *
  • the {@code requestedTemplate} specified to this method + *
  • the {@code Locale} of the {@code DateTimeFormatter} + *
  • the {@code Chronology} of the {@code DateTimeFormatter} unless overridden + *
+ * During formatting, the chronology is obtained from the temporal object + * being formatted, which may have been overridden by + * {@link DateTimeFormatter#withChronology(Chronology)}. + *

+ * During parsing, if a chronology has already been parsed, then it is used. + * Otherwise the default from {@code DateTimeFormatter.withChronology(Chronology)} + * is used, with {@code IsoChronology} as the fallback. + *

+ * The requested template is a series of typical pattern + * symbols in canonical order from the largest date or time unit to the smallest, + * which can be expressed with the following regular expression: + * {@snippet : + * "G{0,5}" + // Era + * "y*" + // Year + * "Q{0,5}" + // Quarter + * "M{0,5}" + // Month + * "w*" + // Week of Week Based Year + * "E{0,5}" + // Day of Week + * "d{0,2}" + // Day of Month + * "B{0,5}" + // Period/AmPm of Day + * "[hHjC]{0,2}" + // Hour of Day/AmPm (refer to LDML for 'j' and 'C') + * "m{0,2}" + // Minute of Hour + * "s{0,2}" + // Second of Minute + * "[vz]{0,4}" // Zone + * } + * All pattern symbols are optional, and each pattern symbol represents a field, + * for example, 'M' represents the Month field. The number of the pattern symbol letters follows the + * same presentation, such as "number" or "text" as in the + * Patterns for Formatting and Parsing section. + * Other pattern symbols in the requested template are invalid. + *

+ * The mapping of the requested template to the closest of the available localized formats + * is defined by the + * + * Unicode LDML specification. For example, the formatter created from the requested template + * {@code yMMM} will format the date '2020-06-16' to 'Jun 2020' in the {@link Locale#US US locale}. + * + * @param requestedTemplate the requested template to use, not null + * @return this, for chaining, not null + * @throws IllegalArgumentException if {@code requestedTemplate} is invalid + * @see #appendPattern(String) + * @since 19 + */ + public DateTimeFormatterBuilder appendLocalized(String requestedTemplate) { + Objects.requireNonNull(requestedTemplate, "requestedTemplate"); + if (!VALID_TEMPLATE_PATTERN.matcher(requestedTemplate).matches()) { + throw new IllegalArgumentException("Requested template is invalid: " + requestedTemplate); + } + appendInternal(new LocalizedPrinterParser(requestedTemplate)); + return this; + } + //----------------------------------------------------------------------- /** * Appends a character literal to the formatter. @@ -2378,11 +2492,11 @@ public final class DateTimeFormatterBuilder { private final DateTimePrinterParser[] printerParsers; private final boolean optional; - CompositePrinterParser(List printerParsers, boolean optional) { + private CompositePrinterParser(List printerParsers, boolean optional) { this(printerParsers.toArray(new DateTimePrinterParser[0]), optional); } - CompositePrinterParser(DateTimePrinterParser[] printerParsers, boolean optional) { + private CompositePrinterParser(DateTimePrinterParser[] printerParsers, boolean optional) { this.printerParsers = printerParsers; this.optional = optional; } @@ -2476,7 +2590,7 @@ public final class DateTimeFormatterBuilder { * @param padWidth the width to pad to, 1 or greater * @param padChar the pad character */ - PadPrinterParserDecorator(DateTimePrinterParser printerParser, int padWidth, char padChar) { + private PadPrinterParserDecorator(DateTimePrinterParser printerParser, int padWidth, char padChar) { // input checked by DateTimeFormatterBuilder this.printerParser = printerParser; this.padWidth = padWidth; @@ -2584,7 +2698,7 @@ public final class DateTimeFormatterBuilder { private final TemporalField field; private final long value; - DefaultValueParser(TemporalField field, long value) { + private DefaultValueParser(TemporalField field, long value) { this.field = field; this.value = value; } @@ -2608,7 +2722,7 @@ public final class DateTimeFormatterBuilder { static final class CharLiteralPrinterParser implements DateTimePrinterParser { private final char literal; - CharLiteralPrinterParser(char literal) { + private CharLiteralPrinterParser(char literal) { this.literal = literal; } @@ -2651,7 +2765,7 @@ public final class DateTimeFormatterBuilder { static final class StringLiteralPrinterParser implements DateTimePrinterParser { private final String literal; - StringLiteralPrinterParser(String literal) { + private StringLiteralPrinterParser(String literal) { this.literal = literal; // validated by caller } @@ -2717,7 +2831,7 @@ public final class DateTimeFormatterBuilder { * @param maxWidth the maximum field width, from minWidth to 19 * @param signStyle the positive/negative sign style, not null */ - NumberPrinterParser(TemporalField field, int minWidth, int maxWidth, SignStyle signStyle) { + private NumberPrinterParser(TemporalField field, int minWidth, int maxWidth, SignStyle signStyle) { // validated by caller this.field = field; this.minWidth = minWidth; @@ -3008,7 +3122,7 @@ public final class DateTimeFormatterBuilder { * @param baseValue the base value * @param baseDate the base date */ - ReducedPrinterParser(TemporalField field, int minWidth, int maxWidth, + private ReducedPrinterParser(TemporalField field, int minWidth, int maxWidth, int baseValue, ChronoLocalDate baseDate) { this(field, minWidth, maxWidth, baseValue, baseDate, 0); if (minWidth < 1 || minWidth > 10) { @@ -3161,7 +3275,7 @@ public final class DateTimeFormatterBuilder { * @param maxWidth the maximum width to output, from 0 to 9 * @param decimalPoint whether to output the localized decimal point symbol */ - NanosPrinterParser(int minWidth, int maxWidth, boolean decimalPoint) { + private NanosPrinterParser(int minWidth, int maxWidth, boolean decimalPoint) { this(minWidth, maxWidth, decimalPoint, 0); if (minWidth < 0 || minWidth > 9) { throw new IllegalArgumentException("Minimum width must be from 0 to 9 inclusive but was " + minWidth); @@ -3183,7 +3297,7 @@ public final class DateTimeFormatterBuilder { * @param decimalPoint whether to output the localized decimal point symbol * @param subsequentWidth the subsequentWidth for this instance */ - NanosPrinterParser(int minWidth, int maxWidth, boolean decimalPoint, int subsequentWidth) { + private NanosPrinterParser(int minWidth, int maxWidth, boolean decimalPoint, int subsequentWidth) { super(NANO_OF_SECOND, minWidth, maxWidth, SignStyle.NOT_NEGATIVE, subsequentWidth); this.decimalPoint = decimalPoint; } @@ -3366,7 +3480,7 @@ public final class DateTimeFormatterBuilder { * @param maxWidth the maximum width to output, from 0 to 9 * @param decimalPoint whether to output the localized decimal point symbol */ - FractionPrinterParser(TemporalField field, int minWidth, int maxWidth, boolean decimalPoint) { + private FractionPrinterParser(TemporalField field, int minWidth, int maxWidth, boolean decimalPoint) { this(field, minWidth, maxWidth, decimalPoint, 0); Objects.requireNonNull(field, "field"); if (field.range().isFixed() == false) { @@ -3393,7 +3507,7 @@ public final class DateTimeFormatterBuilder { * @param decimalPoint whether to output the localized decimal point symbol * @param subsequentWidth the subsequentWidth for this instance */ - FractionPrinterParser(TemporalField field, int minWidth, int maxWidth, boolean decimalPoint, int subsequentWidth) { + private FractionPrinterParser(TemporalField field, int minWidth, int maxWidth, boolean decimalPoint, int subsequentWidth) { super(field, minWidth, maxWidth, SignStyle.NOT_NEGATIVE, subsequentWidth); this.decimalPoint = decimalPoint; ValueRange range = field.range(); @@ -3583,7 +3697,7 @@ public final class DateTimeFormatterBuilder { * @param textStyle the text style, not null * @param provider the text provider, not null */ - TextPrinterParser(TemporalField field, TextStyle textStyle, DateTimeTextProvider provider) { + private TextPrinterParser(TemporalField field, TextStyle textStyle, DateTimeTextProvider provider) { // validated by caller this.field = field; this.textStyle = textStyle; @@ -3681,7 +3795,7 @@ public final class DateTimeFormatterBuilder { private static final long SECONDS_0000_TO_1970 = ((146097L * 5L) - (30L * 365L + 7L)) * 86400L; private final int fractionalDigits; - InstantPrinterParser(int fractionalDigits) { + private InstantPrinterParser(int fractionalDigits) { this.fractionalDigits = fractionalDigits; } @@ -3830,7 +3944,7 @@ public final class DateTimeFormatterBuilder { * @param pattern the pattern * @param noOffsetText the text to use for UTC, not null */ - OffsetIdPrinterParser(String pattern, String noOffsetText) { + private OffsetIdPrinterParser(String pattern, String noOffsetText) { Objects.requireNonNull(pattern, "pattern"); Objects.requireNonNull(noOffsetText, "noOffsetText"); this.type = checkPattern(pattern); @@ -4312,7 +4426,7 @@ public final class DateTimeFormatterBuilder { /** Display in generic time-zone format. True in case of pattern letter 'v' */ private final boolean isGeneric; - ZoneTextPrinterParser(TextStyle textStyle, Set preferredZones, boolean isGeneric) { + private ZoneTextPrinterParser(TextStyle textStyle, Set preferredZones, boolean isGeneric) { super(TemporalQueries.zone(), "ZoneText(" + textStyle + ")"); this.textStyle = Objects.requireNonNull(textStyle, "textStyle"); this.isGeneric = isGeneric; @@ -4484,7 +4598,7 @@ public final class DateTimeFormatterBuilder { private final TemporalQuery query; private final String description; - ZoneIdPrinterParser(TemporalQuery query, String description) { + private ZoneIdPrinterParser(TemporalQuery query, String description) { this.query = query; this.description = description; } @@ -4903,7 +5017,7 @@ public final class DateTimeFormatterBuilder { /** The text style to output, null means the ID. */ private final TextStyle textStyle; - ChronoPrinterParser(TextStyle textStyle) { + private ChronoPrinterParser(TextStyle textStyle) { // validated by caller this.textStyle = textStyle; } @@ -4978,6 +5092,7 @@ public final class DateTimeFormatterBuilder { private final FormatStyle dateStyle; private final FormatStyle timeStyle; + private final String requestedTemplate; /** * Constructor. @@ -4985,10 +5100,23 @@ public final class DateTimeFormatterBuilder { * @param dateStyle the date style to use, may be null * @param timeStyle the time style to use, may be null */ - LocalizedPrinterParser(FormatStyle dateStyle, FormatStyle timeStyle) { - // validated by caller + private LocalizedPrinterParser(FormatStyle dateStyle, FormatStyle timeStyle) { + // params validated by caller this.dateStyle = dateStyle; this.timeStyle = timeStyle; + this.requestedTemplate = null; + } + + /** + * Constructor. + * + * @param requestedTemplate the requested template to use, not null + */ + private LocalizedPrinterParser(String requestedTemplate) { + // param validated by caller + this.dateStyle = null; + this.timeStyle = null; + this.requestedTemplate = requestedTemplate; } @Override @@ -5006,7 +5134,8 @@ public final class DateTimeFormatterBuilder { /** * Gets the formatter to use. *

- * The formatter will be the most appropriate to use for the date and time style in the locale. + * The formatter will be the most appropriate to use for the date and time style, or + * the requested template for the locale. * For example, some locales will use the month name while others will use the number. * * @param locale the locale to use, not null @@ -5015,23 +5144,22 @@ public final class DateTimeFormatterBuilder { * @throws IllegalArgumentException if the formatter cannot be found */ private DateTimeFormatter formatter(Locale locale, Chronology chrono) { - String key = chrono.getId() + '|' + locale.toString() + '|' + dateStyle + timeStyle; - DateTimeFormatter formatter = FORMATTER_CACHE.get(key); - if (formatter == null) { - String pattern = getLocalizedDateTimePattern(dateStyle, timeStyle, chrono, locale); - formatter = new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter(locale); - DateTimeFormatter old = FORMATTER_CACHE.putIfAbsent(key, formatter); - if (old != null) { - formatter = old; - } - } - return formatter; + String key = chrono.getId() + '|' + locale.toString() + '|' + + (requestedTemplate != null ? requestedTemplate : Objects.toString(dateStyle) + timeStyle); + + return FORMATTER_CACHE.computeIfAbsent(key, k -> + new DateTimeFormatterBuilder() + .appendPattern(requestedTemplate != null ? + getLocalizedDateTimePattern(requestedTemplate, chrono, locale) : + getLocalizedDateTimePattern(dateStyle, timeStyle, chrono, locale)) + .toFormatter(locale)); } @Override public String toString() { - return "Localized(" + (dateStyle != null ? dateStyle : "") + "," + - (timeStyle != null ? timeStyle : "") + ")"; + return "Localized(" + (requestedTemplate != null ? requestedTemplate : + (dateStyle != null ? dateStyle : "") + "," + + (timeStyle != null ? timeStyle : "")) + ")"; } } @@ -5056,7 +5184,7 @@ public final class DateTimeFormatterBuilder { * @param minWidth the minimum field width, from 1 to 19 * @param maxWidth the maximum field width, from minWidth to 19 */ - WeekBasedFieldPrinterParser(char chr, int count, int minWidth, int maxWidth) { + private WeekBasedFieldPrinterParser(char chr, int count, int minWidth, int maxWidth) { this(chr, count, minWidth, maxWidth, 0); } @@ -5070,7 +5198,7 @@ public final class DateTimeFormatterBuilder { * @param subsequentWidth the width of subsequent non-negative numbers, 0 or greater, * -1 if fixed width due to active adjacent parsing */ - WeekBasedFieldPrinterParser(char chr, int count, int minWidth, int maxWidth, + private WeekBasedFieldPrinterParser(char chr, int count, int minWidth, int maxWidth, int subsequentWidth) { super(null, minWidth, maxWidth, SignStyle.NOT_NEGATIVE, subsequentWidth); this.chr = chr; @@ -5201,7 +5329,7 @@ public final class DateTimeFormatterBuilder { * * @param textStyle the text style, not null */ - DayPeriodPrinterParser(TextStyle textStyle) { + private DayPeriodPrinterParser(TextStyle textStyle) { // validated by caller this.textStyle = textStyle; } diff --git a/src/java.base/share/classes/sun/text/spi/JavaTimeDateTimePatternProvider.java b/src/java.base/share/classes/sun/text/spi/JavaTimeDateTimePatternProvider.java index a3835c6ac82..58235c9dff0 100644 --- a/src/java.base/share/classes/sun/text/spi/JavaTimeDateTimePatternProvider.java +++ b/src/java.base/share/classes/sun/text/spi/JavaTimeDateTimePatternProvider.java @@ -27,6 +27,7 @@ package sun.text.spi; +import java.time.DateTimeException; import java.util.Locale; import java.util.spi.LocaleServiceProvider; @@ -41,10 +42,10 @@ public abstract class JavaTimeDateTimePatternProvider extends LocaleServiceProvi } /** - * Gets the formatting pattern for a timeStyle + * Returns the formatting pattern for a timeStyle * dateStyle, calendarType and locale. * Concrete implementation of this method will retrieve - * a java.time specific dateTime Pattern from selected Locale Provider. + * a java.time specific dateTime Pattern from the selected Locale Provider. * * @param timeStyle an {@code int} value, representing FormatStyle constant, -1 * for date-only pattern @@ -58,4 +59,26 @@ public abstract class JavaTimeDateTimePatternProvider extends LocaleServiceProvi * @since 9 */ public abstract String getJavaTimeDateTimePattern(int timeStyle, int dateStyle, String calType, Locale locale); + + /** + * Returns the formatting pattern for the requested template, calendarType, and locale. + * Concrete implementation of this method will retrieve + * a java.time specific pattern from selected Locale Provider. + * + * @param requestedTemplate the requested template, not null + * @param calType a {@code String}, non-null representing CalendarType such as "japanese", + * "iso8601" + * @param locale {@code locale}, non-null + * @throws IllegalArgumentException if {@code requestedTemplate} does not match + * the regular expression syntax described in + * {@link java.time.format.DateTimeFormatterBuilder#appendLocalized(String)}. + * @throws DateTimeException if a match for the formatting pattern for + * {@code requestedTemplate} is not available + * @return formatting pattern {@code String} + * @since 19 + */ + public String getJavaTimeDateTimePattern(String requestedTemplate, String calType, Locale locale) { + // default implementation throws exception + throw new DateTimeException("Formatting pattern is not available for the requested template: " + requestedTemplate); + } } diff --git a/src/java.base/share/classes/sun/util/locale/provider/JavaTimeDateTimePatternImpl.java b/src/java.base/share/classes/sun/util/locale/provider/JavaTimeDateTimePatternImpl.java index 41de2dd7f65..c39cea799b3 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/JavaTimeDateTimePatternImpl.java +++ b/src/java.base/share/classes/sun/util/locale/provider/JavaTimeDateTimePatternImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,10 @@ */ package sun.util.locale.provider; +import java.time.DateTimeException; import java.util.Locale; +import java.util.Objects; +import java.util.Optional; import java.util.Set; import sun.text.spi.JavaTimeDateTimePatternProvider; @@ -63,10 +66,21 @@ public class JavaTimeDateTimePatternImpl extends JavaTimeDateTimePatternProvider @Override public String getJavaTimeDateTimePattern(int timeStyle, int dateStyle, String calType, Locale locale) { LocaleResources lr = LocaleProviderAdapter.getResourceBundleBased().getLocaleResources(locale); - String pattern = lr.getJavaTimeDateTimePattern( - timeStyle, dateStyle, calType); - return pattern; + return lr.getJavaTimeDateTimePattern(timeStyle, dateStyle, calType); + } + @Override + public String getJavaTimeDateTimePattern(String requestedTemplate, String calType, Locale locale) { + LocaleProviderAdapter lpa = LocaleProviderAdapter.getResourceBundleBased(); + return ((ResourceBundleBasedAdapter)lpa).getCandidateLocales("", locale).stream() + .map(lpa::getLocaleResources) + .map(lr -> lr.getLocalizedPattern(requestedTemplate, calType)) + .filter(Objects::nonNull) + .findFirst() + .or(() -> calType.equals("generic") ? Optional.empty(): + Optional.of(getJavaTimeDateTimePattern(requestedTemplate, "generic", locale))) + .orElseThrow(() -> new DateTimeException("Requested template \"" + requestedTemplate + + "\" cannot be resolved in the locale \"" + locale + "\"")); } @Override diff --git a/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java b/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java index fe84b66b167..aa991359c68 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java +++ b/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,15 +46,21 @@ import java.text.MessageFormat; import java.text.NumberFormat; import java.util.Arrays; import java.util.Calendar; +import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; +import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Objects; import java.util.ResourceBundle; import java.util.Set; import java.util.TimeZone; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.regex.Pattern; +import java.util.stream.Stream; + import sun.security.action.GetPropertyAction; import sun.util.resources.LocaleData; import sun.util.resources.OpenListResourceBundle; @@ -91,6 +97,10 @@ public class LocaleResources { private static final String COMPACT_NUMBER_PATTERNS_CACHEKEY = "CNP"; private static final String DATE_TIME_PATTERN = "DTP."; private static final String RULES_CACHEKEY = "RULE"; + private static final String SKELETON_PATTERN = "SP."; + + // ResourceBundle key names for skeletons + private static final String SKELETON_INPUT_REGIONS_KEY = "DateFormatItemInputRegions"; // TimeZoneNamesBundle exemplar city prefix private static final String TZNB_EXCITY_PREFIX = "timezone.excity."; @@ -98,6 +108,31 @@ public class LocaleResources { // null singleton cache value private static final Object NULLOBJECT = new Object(); + // RegEx pattern for skeleton validity checking + private static final Pattern VALID_SKELETON_PATTERN = Pattern.compile( + "(?" + + "G{0,5}" + // Era + "y*" + // Year + "Q{0,5}" + // Quarter + "M{0,5}" + // Month + "w*" + // Week of Week Based Year + "E{0,5}" + // Day of Week + "d{0,2})" + // Day of Month + "(?

* This method is caller sensitive, which means that it may return different * values to different callers. + * In cases where {@code MethodHandles.lookup} is called from a context where + * there is no caller frame on the stack (e.g. when called directly + * from a JNI attached thread), {@code IllegalCallerException} is thrown. + * To obtain a {@link Lookup lookup object} in such a context, use an auxiliary class that will + * implicitly be identified as the caller, or use {@link MethodHandles#publicLookup()} + * to obtain a low-privileged lookup instead. * @return a lookup object for the caller of this method, with * {@linkplain Lookup#ORIGINAL original} and * {@linkplain Lookup#hasFullPrivilegeAccess() full privilege access}. + * @throws IllegalCallerException if there is no caller frame on the stack. */ @CallerSensitive @ForceInline // to ensure Reflection.getCallerClass optimization public static Lookup lookup() { - return new Lookup(Reflection.getCallerClass()); + final Class c = Reflection.getCallerClass(); + if (c == null) { + throw new IllegalCallerException("no caller frame"); + } + return new Lookup(c); } /** diff --git a/test/jdk/java/lang/invoke/MethodHandles/exeNullCallerLookup/NullCallerLookupTest.java b/test/jdk/java/lang/invoke/MethodHandles/exeNullCallerLookup/NullCallerLookupTest.java new file mode 100644 index 00000000000..cda0b2bc7af --- /dev/null +++ b/test/jdk/java/lang/invoke/MethodHandles/exeNullCallerLookup/NullCallerLookupTest.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8281003 + * @summary Test uses custom launcher that starts VM using JNI that verifies + * MethodHandles::lookup with null caller class throws an IllegalCallerException. + * @library /test/lib + * @requires os.family != "aix" + * @run main/native NullCallerLookupTest + */ + +// Test disabled on AIX since we cannot invoke the JVM on the primordial thread. + +import java.io.File; +import java.util.Map; +import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; + +import java.io.IOException; +import java.nio.file.Path; + +public class NullCallerLookupTest { + public static void main(String[] args) throws IOException { + Path launcher = Path.of(System.getProperty("test.nativepath"), "NullCallerLookupTest"); + ProcessBuilder pb = new ProcessBuilder(launcher.toString()); + Map env = pb.environment(); + + String libDir = Platform.libDir().toString(); + String vmDir = Platform.jvmLibDir().toString(); + + // set up shared library path + String sharedLibraryPathEnvName = Platform.sharedLibraryPathVariableName(); + env.compute(sharedLibraryPathEnvName, + (k, v) -> (v == null) ? libDir : v + File.pathSeparator + libDir); + env.compute(sharedLibraryPathEnvName, + (k, v) -> (v == null) ? vmDir : v + File.pathSeparator + vmDir); + + System.out.println("Launching: " + launcher + " shared library path: " + + env.get(sharedLibraryPathEnvName)); + new OutputAnalyzer(pb.start()) + .outputTo(System.out) + .errorTo(System.err) + .shouldHaveExitValue(0); + } +} + diff --git a/test/jdk/java/lang/invoke/MethodHandles/exeNullCallerLookup/exeNullCallerLookupTest.c b/test/jdk/java/lang/invoke/MethodHandles/exeNullCallerLookup/exeNullCallerLookupTest.c new file mode 100644 index 00000000000..3abe15ce96c --- /dev/null +++ b/test/jdk/java/lang/invoke/MethodHandles/exeNullCallerLookup/exeNullCallerLookupTest.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include + +#include "jni.h" +#include "assert.h" + +static jclass class_IllegalCallerException; + +int checkAndClearIllegalCallerExceptionThrown(JNIEnv *env) { + jthrowable t = (*env)->ExceptionOccurred(env); + if ((*env)->IsInstanceOf(env, t, class_IllegalCallerException) == JNI_TRUE) { + (*env)->ExceptionClear(env); + return JNI_TRUE; + } + return JNI_FALSE; +} + +int main(int argc, char** args) { + JavaVM *jvm; + JNIEnv *env; + JavaVMInitArgs vm_args; + JavaVMOption options[1]; + jint rc; + + + vm_args.version = JNI_VERSION_1_2; + vm_args.nOptions = 0; + vm_args.options = options; + + if ((rc = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args)) != JNI_OK) { + printf("ERROR: cannot create VM.\n"); + exit(-1); + } + class_IllegalCallerException = (*env)->FindClass(env, "java/lang/IllegalCallerException"); + assert (class_IllegalCallerException != NULL); + + // call MethodHandles.lookup() + jclass methodHandlesClass = (*env)->FindClass(env, "java/lang/invoke/MethodHandles"); + assert(methodHandlesClass != NULL); + jmethodID mid_MethodHandles_lookup = (*env)->GetStaticMethodID(env, methodHandlesClass, "lookup", "()Ljava/lang/invoke/MethodHandles$Lookup;" ); + assert(mid_MethodHandles_lookup != NULL); + jobject l = (*env)->CallStaticObjectMethod(env, methodHandlesClass, mid_MethodHandles_lookup ); + if ((rc = checkAndClearIllegalCallerExceptionThrown(env)) != JNI_TRUE) { + printf("ERROR: Didn't get the expected IllegalCallerException.\n"); + exit(-1); + } + + printf("Expected IllegalCallerException was thrown\n"); + + (*jvm)->DestroyJavaVM(jvm); + return 0; +} + -- GitLab From 48f6e93079f377a621ca769b820fa221062ceab1 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Wed, 16 Feb 2022 21:38:48 +0000 Subject: [PATCH 101/203] 8282020: ProblemList sun/net/www/protocol/https/HttpsURLConnection/B6216082.java until JDK-8282017 is fixed Reviewed-by: michaelm, naoto --- test/jdk/ProblemList.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 6b54c726277..8e00e12f1ba 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -597,6 +597,7 @@ java/net/MulticastSocket/SetGetNetworkInterfaceTest.java 8219083 windows- java/net/ServerSocket/AcceptInheritHandle.java 8211854 aix-ppc64 +sun/net/www/protocol/https/HttpsURLConnection/B6216082.java 8282017 generic-all ############################################################################ -- GitLab From 9ba0760cf85f9e843f3383b725017c9ffac350df Mon Sep 17 00:00:00 2001 From: Martin Desruisseaux Date: Wed, 16 Feb 2022 22:01:01 +0000 Subject: [PATCH 102/203] 8275345: RasterFormatException when drawing a tiled image made of non-writable rasters Reviewed-by: prr, aivanov --- .../classes/sun/java2d/SunGraphics2D.java | 18 +- .../java/awt/image/DrawImage/TiledImage.java | 225 ++++++++++++++++++ 2 files changed, 234 insertions(+), 9 deletions(-) create mode 100644 test/jdk/java/awt/image/DrawImage/TiledImage.java diff --git a/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java b/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java index b5b5225938b..193a8a38587 100644 --- a/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java +++ b/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java @@ -2838,23 +2838,23 @@ public final class SunGraphics2D WritableRaster wRaster = null; if (raster instanceof WritableRaster) { wRaster = (WritableRaster)raster; + + // Translate wRaster to start at (0, 0) and to contain + // only the relevent portion of the tile + wRaster = wRaster.createWritableChild(tileRect.x, tileRect.y, + tileRect.width, + tileRect.height, + 0, 0, + null); } else { // Create a WritableRaster in the same coordinate system - // as the original raster. + // as the original raster, except origin which is (0,0). wRaster = Raster.createWritableRaster(raster.getSampleModel(), raster.getDataBuffer(), null); } - // Translate wRaster to start at (0, 0) and to contain - // only the relevent portion of the tile - wRaster = wRaster.createWritableChild(tileRect.x, tileRect.y, - tileRect.width, - tileRect.height, - 0, 0, - null); - // Wrap wRaster in a BufferedImage BufferedImage bufImg = new BufferedImage(colorModel, diff --git a/test/jdk/java/awt/image/DrawImage/TiledImage.java b/test/jdk/java/awt/image/DrawImage/TiledImage.java new file mode 100644 index 00000000000..8faca3aec6a --- /dev/null +++ b/test/jdk/java/awt/image/DrawImage/TiledImage.java @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.geom.AffineTransform; +import java.awt.image.BandedSampleModel; +import java.awt.image.BufferedImage; +import java.awt.image.Raster; +import java.awt.image.ColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.RenderedImage; +import java.awt.image.SampleModel; +import java.awt.image.WritableRaster; +import java.util.Objects; +import java.util.Vector; + + +/** + * @test + * @bug 8275345 + * @summary RasterFormatException when drawing a tiled image made of non-writable rasters. + * + * Test drawing a tiled image made of non-writable {@link Raster} tiles. + * Drawing works when tiles are instances of {@link WritableRaster}. + * But if tiles are instances of {@link Raster} only, then the following + * exception is thrown: + * + * Exception in thread "main" java.awt.image.RasterFormatException: (parentX + width) is outside raster + * at java.desktop/java.awt.image.WritableRaster.createWritableChild(WritableRaster.java:228) + * at java.desktop/sun.java2d.SunGraphics2D.drawTranslatedRenderedImage(SunGraphics2D.java:2852) + * at java.desktop/sun.java2d.SunGraphics2D.drawRenderedImage(SunGraphics2D.java:2711) + * + * The bug is demonstrated by drawing the same image twice: + * once with {@link WritableRaster} tiles (which succeed), + * then the same operation but with {@link Raster} tiles. + * + * The bug is caused by the following code in {@code SunGraphics2D}: + * + * // Create a WritableRaster containing the tile + * WritableRaster wRaster = null; + * if (raster instanceof WritableRaster) { + * wRaster = (WritableRaster)raster; + * } else { + * // Create a WritableRaster in the same coordinate system + * // as the original raster. + * wRaster = + * Raster.createWritableRaster(raster.getSampleModel(), + * raster.getDataBuffer(), + * null); + * } + * // Translate wRaster to start at (0, 0) and to contain + * // only the relevant portion of the tile + * wRaster = wRaster.createWritableChild(tileRect.x, tileRect.y, + * tileRect.width, + * tileRect.height, + * 0, 0, + * null); + * + * If {@code raster} is not an instance of {@link WritableRaster}, + * then a new {@link WritableRaster} is created wrapping the same + * buffer but with a location of (0,0), because + * the {@code location} argument of {@code createWritableRaster} + * is null. Consequently the call to {@code createWritableChild} + * shall not be done in that case, because the raster is already + * translated. The current code applies translation twice. + * + * This bug is largely unnoticed because most {@code Raster.create} + * methods actually create {@link WritableRaster} instances, even + * when the user did not asked for writable raster. To make this + * bug apparent, we need to invoke {@code Raster.createRaster(…)} + * with a sample model for which no optimization is provided. + */ +public class TiledImage implements RenderedImage { + /** + * Run the test using writable tiles first, then read-only tiles. + */ + public static void main(String[] args) { + draw(true); // Pass. + draw(false); // Fail if 8275345 is not fixed. + } + + private static final int NUM_X_TILES = 2, NUM_Y_TILES = 3; + + private static final int TILE_WIDTH = 16, TILE_HEIGHT = 12; + + /** + * Tests rendering a tiled image. + * + * @param writable whether the image shall use writable raster. + */ + private static void draw(final boolean writable) { + final BufferedImage target = new BufferedImage( + TILE_WIDTH * NUM_X_TILES, + TILE_HEIGHT * NUM_Y_TILES, + BufferedImage.TYPE_BYTE_GRAY); + + final RenderedImage source = new TiledImage(writable, + target.getColorModel()); + + Graphics2D g = target.createGraphics(); + g.drawRenderedImage(source, new AffineTransform()); + g.dispose(); + } + + private final ColorModel colorModel; + + private final Raster[] tiles; + + /** + * Creates a tiled image. The image is empty, + * but pixel values are not the purpose of this test. + * + * @param writable whether the image shall use writable raster. + */ + private TiledImage(boolean writable, ColorModel cm) { + /* + * We need a sample model class for which Raster.createRaster + * do not provide a special case. That method has optimizations + * for most SampleModel sub-types, except BandedSampleModel. + */ + SampleModel sm = new BandedSampleModel(DataBuffer.TYPE_BYTE, TILE_WIDTH, TILE_HEIGHT, 1); + tiles = new Raster[NUM_X_TILES * NUM_Y_TILES]; + final Point location = new Point(); + for (int tileY = 0; tileY < NUM_Y_TILES; tileY++) { + for (int tileX = 0; tileX < NUM_X_TILES; tileX++) { + location.x = tileX * TILE_WIDTH; + location.y = tileY * TILE_HEIGHT; + DataBufferByte db = new DataBufferByte(TILE_WIDTH * TILE_HEIGHT); + Raster r; + if (writable) { + r = Raster.createWritableRaster(sm, db, location); + } else { + // Case causing RasterFormatException later. + r = Raster.createRaster(sm, db, location); + } + tiles[tileX + tileY * NUM_X_TILES] = r; + } + } + colorModel = cm; + } + + @Override + public ColorModel getColorModel() { + return colorModel; + } + + @Override + public SampleModel getSampleModel() { + return tiles[0].getSampleModel(); + } + + @Override + public Vector getSources() { + return new Vector<>(); + } + + @Override + public Object getProperty(String key) { + return Image.UndefinedProperty; + } + + @Override + public String[] getPropertyNames() { + return null; + } + + @Override public int getMinX() {return 0;} + @Override public int getMinY() {return 0;} + @Override public int getMinTileX() {return 0;} + @Override public int getMinTileY() {return 0;} + @Override public int getTileGridXOffset() {return 0;} + @Override public int getTileGridYOffset() {return 0;} + @Override public int getNumXTiles() {return NUM_X_TILES;} + @Override public int getNumYTiles() {return NUM_Y_TILES;} + @Override public int getTileWidth() {return TILE_WIDTH;} + @Override public int getTileHeight() {return TILE_HEIGHT;} + @Override public int getWidth() {return TILE_WIDTH * NUM_X_TILES;} + @Override public int getHeight() {return TILE_HEIGHT * NUM_Y_TILES;} + + @Override + public Raster getTile(final int tileX, final int tileY) { + Objects.checkIndex(tileX, NUM_X_TILES); + Objects.checkIndex(tileY, NUM_Y_TILES); + return tiles[tileX + tileY * NUM_X_TILES]; + } + + @Override + public Raster getData() { + throw new UnsupportedOperationException("Not needed for this test."); + } + + @Override + public Raster getData(Rectangle rect) { + throw new UnsupportedOperationException("Not needed for this test."); + } + + @Override + public WritableRaster copyData(WritableRaster raster) { + throw new UnsupportedOperationException("Not needed for this test."); + } +} -- GitLab From 5ec7898dbf1ebe261e5e25939cad42134611ff12 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Wed, 16 Feb 2022 22:02:55 +0000 Subject: [PATCH 103/203] 8281671: Class.getCanonicalName spec should explicitly cover array classes Reviewed-by: mchung --- .../share/classes/java/lang/Class.java | 10 ++ test/jdk/java/lang/Class/NameTest.java | 101 ++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 test/jdk/java/lang/Class/NameTest.java diff --git a/src/java.base/share/classes/java/lang/Class.java b/src/java.base/share/classes/java/lang/Class.java index fb936b14989..fce7793fbcf 100644 --- a/src/java.base/share/classes/java/lang/Class.java +++ b/src/java.base/share/classes/java/lang/Class.java @@ -1732,8 +1732,18 @@ public final class Class implements java.io.Serializable, *

  • an array whose component type does not have a canonical name
  • * * + * The canonical name for a primitive class is the keyword for the + * corresponding primitive type ({@code byte}, {@code short}, + * {@code char}, {@code int}, and so on). + * + *

    An array type has a canonical name if and only if its + * component type has a canonical name. When an array type has a + * canonical name, it is equal to the canonical name of the + * component type followed by "{@code []}". + * * @return the canonical name of the underlying class if it exists, and * {@code null} otherwise. + * @jls 6.7 Fully Qualified Names and Canonical Names * @since 1.5 */ public String getCanonicalName() { diff --git a/test/jdk/java/lang/Class/NameTest.java b/test/jdk/java/lang/Class/NameTest.java new file mode 100644 index 00000000000..b8d6e2125b8 --- /dev/null +++ b/test/jdk/java/lang/Class/NameTest.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8281671 + * @summary Checks on various "getFooName" methods of java.lang.Class + */ + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +public class NameTest { + public static void main(String... args) { + testCanonicalName(); + testSimpleName(); + } + + private static void testCanonicalName() { + class LocalClass {} // Local class; no canonical name + Object o = new Object() {}; // Anonymous class; no canonical name + Object[] objectArray = {}; + + Map, String> expectedCanonicalName = new HashMap<>(); + + expectedCanonicalName.put(LocalClass.class, null); + expectedCanonicalName.put(o.getClass(), null); + + // If a component type doesn't have a canonical name, neither + // does an array of that type. + expectedCanonicalName.put(LocalClass.class.arrayType(), null); + expectedCanonicalName.put(o.getClass().arrayType(), null); + + expectedCanonicalName.put(int.class, "int"); + expectedCanonicalName.put(Object.class, "java.lang.Object"); + expectedCanonicalName.put(objectArray.getClass(), "java.lang.Object[]"); + + for (var entry : expectedCanonicalName.entrySet()) { + var key = entry.getKey(); + var expectedName = entry.getValue(); + String canonicalName = key.getCanonicalName(); + if (!Objects.equals(canonicalName, expectedName)) { + System.err.println("Unexpected canonical name '" + + canonicalName + "' found for " + + key + ", expected " + expectedName); + throw new RuntimeException(); + } + } + } + + private static void testSimpleName() { + class ALocalClass {} // Local class + Object o = new Object() {}; // Anonymous class, empty simple name + Object[] objectArray = {}; + + Map, String> expectedSimpleName = new HashMap<>(); + + expectedSimpleName.put(ALocalClass.class, "ALocalClass"); + expectedSimpleName.put(o.getClass(), ""); + + expectedSimpleName.put(ALocalClass.class.arrayType(), "ALocalClass[]"); + expectedSimpleName.put(o.getClass().arrayType(), "[]"); + + expectedSimpleName.put(int.class, "int"); + expectedSimpleName.put(Object.class, "Object"); + expectedSimpleName.put(objectArray.getClass(), "Object[]"); + + for (var entry : expectedSimpleName.entrySet()) { + var key = entry.getKey(); + var expectedName = entry.getValue(); + String simpleName = key.getSimpleName(); + if (!Objects.equals(simpleName, expectedName)) { + System.err.println("Unexpected simple name '" + + simpleName + "' found for " + + key + ", expected " + expectedName); + throw new RuntimeException(); + } + } + } +} -- GitLab From 0b00ce17cd6b530d9394e79ac8b07208cd4b92f5 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 16 Feb 2022 23:23:57 +0000 Subject: [PATCH 104/203] 8282011: test/jdk/tools/jpackage/windows/WinL10nTest.java test fails if light.exe is not in %PATH% Reviewed-by: almatvee --- test/jdk/tools/jpackage/windows/WinL10nTest.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/jdk/tools/jpackage/windows/WinL10nTest.java b/test/jdk/tools/jpackage/windows/WinL10nTest.java index 4171da208a4..4f7e726a3af 100644 --- a/test/jdk/tools/jpackage/windows/WinL10nTest.java +++ b/test/jdk/tools/jpackage/windows/WinL10nTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -94,8 +94,11 @@ public class WinL10nTest { private final static Stream getLightCommandLine( Executor.Result result) { - return result.getOutput().stream() - .filter(s -> s.trim().startsWith("light.exe")); + return result.getOutput().stream().filter(s -> { + s = s.trim(); + return s.startsWith("light.exe") || ((s.contains("\\light.exe ") + && s.contains(" -out "))); + }); } @Test -- GitLab From cd234f5dbebd18ebf0c78dfdf533318cdc627971 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 17 Feb 2022 05:27:41 +0000 Subject: [PATCH 105/203] 8282007: Assorted enhancements to jpackage testing framework Reviewed-by: almatvee --- test/jdk/tools/jpackage/apps/Hello.java | 19 +- .../jdk/jpackage/test/AdditionalLauncher.java | 137 ++++++++++--- .../helpers/jdk/jpackage/test/CfgFile.java | 6 +- .../helpers/jdk/jpackage/test/Executor.java | 8 +- .../helpers/jdk/jpackage/test/HelloApp.java | 21 +- .../jdk/jpackage/test/JPackageCommand.java | 67 +++++- .../helpers/jdk/jpackage/test/JavaTool.java | 6 +- .../jdk/jpackage/test/LinuxHelper.java | 44 ++-- .../helpers/jdk/jpackage/test/MacHelper.java | 93 +++++---- .../jdk/jpackage/test/PackageTest.java | 190 ++++++++++++------ .../jpackage/test/RunnablePackageTest.java | 16 +- .../helpers/jdk/jpackage/test/TKit.java | 2 +- .../jdk/jpackage/test/WindowsHelper.java | 109 ++++++---- test/jdk/tools/jpackage/run_tests.sh | 62 ++++-- .../share/MultiLauncherTwoPhaseTest.java | 4 +- test/jdk/tools/jpackage/test_jpackage.sh | 100 --------- .../jpackage/windows/WinUpgradeUUIDTest.java | 4 +- 17 files changed, 562 insertions(+), 326 deletions(-) delete mode 100644 test/jdk/tools/jpackage/test_jpackage.sh diff --git a/test/jdk/tools/jpackage/apps/Hello.java b/test/jdk/tools/jpackage/apps/Hello.java index dd6f114a421..000573c933f 100644 --- a/test/jdk/tools/jpackage/apps/Hello.java +++ b/test/jdk/tools/jpackage/apps/Hello.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,7 @@ import java.util.List; import java.util.ArrayList; import java.util.stream.Stream; import java.util.Collections; +import java.util.Optional; public class Hello implements OpenFilesHandler { @@ -60,6 +61,15 @@ public class Hello implements OpenFilesHandler { var outputFile = getOutputFile(args); trace(String.format("Output file: [%s]", outputFile)); Files.write(outputFile, lines); + + if (Optional.ofNullable(System.getProperty("jpackage.test.noexit")).map( + Boolean::parseBoolean).orElse(false)) { + trace("noexit"); + var lock = new Object(); + synchronized (lock) { + lock.wait(); + } + } } private static List printArgs(String[] args) { @@ -87,7 +97,8 @@ public class Hello implements OpenFilesHandler { } private static Path getOutputFile(String[] args) { - Path outputFilePath = Path.of("appOutput.txt"); + Path outputFilePath = Path.of(Optional.ofNullable(System.getProperty( + "jpackage.test.appOutput")).orElse("appOutput.txt")); // If first arg is a file (most likely from fa), then put output in the same folder as // the file from fa. @@ -101,7 +112,7 @@ public class Hello implements OpenFilesHandler { try { // Try writing in the default output file. Files.write(outputFilePath, Collections.emptyList()); - return outputFilePath; + return outputFilePath.toAbsolutePath(); } catch (IOException ex) { // Log reason of a failure. StringWriter errors = new StringWriter(); @@ -109,7 +120,7 @@ public class Hello implements OpenFilesHandler { Stream.of(errors.toString().split("\\R")).forEachOrdered(Hello::trace); } - return Path.of(System.getProperty("user.home")).resolve(outputFilePath); + return Path.of(System.getProperty("user.home")).resolve(outputFilePath).toAbsolutePath(); } @Override diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java index 10033db4802..44d75d98ec9 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,13 +29,17 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.function.BiConsumer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.jpackage.internal.ApplicationLayout; import jdk.jpackage.test.Functional.ThrowingBiConsumer; +import static jdk.jpackage.test.Functional.ThrowingFunction.toFunction; -public final class AdditionalLauncher { +public class AdditionalLauncher { public AdditionalLauncher(String name) { this.name = name; @@ -43,12 +47,12 @@ public final class AdditionalLauncher { setPersistenceHandler(null); } - public AdditionalLauncher setDefaultArguments(String... v) { + final public AdditionalLauncher setDefaultArguments(String... v) { defaultArguments = new ArrayList<>(List.of(v)); return this; } - public AdditionalLauncher addDefaultArguments(String... v) { + final public AdditionalLauncher addDefaultArguments(String... v) { if (defaultArguments == null) { return setDefaultArguments(v); } @@ -57,12 +61,12 @@ public final class AdditionalLauncher { return this; } - public AdditionalLauncher setJavaOptions(String... v) { + final public AdditionalLauncher setJavaOptions(String... v) { javaOptions = new ArrayList<>(List.of(v)); return this; } - public AdditionalLauncher addJavaOptions(String... v) { + final public AdditionalLauncher addJavaOptions(String... v) { if (javaOptions == null) { return setJavaOptions(v); } @@ -71,23 +75,24 @@ public final class AdditionalLauncher { return this; } - public AdditionalLauncher addRawProperties(Map.Entry... v) { + final public AdditionalLauncher addRawProperties( + Map.Entry... v) { return addRawProperties(List.of(v)); } - public AdditionalLauncher addRawProperties( + final public AdditionalLauncher addRawProperties( Collection> v) { rawProperties.addAll(v); return this; } - public AdditionalLauncher setShortcuts(boolean menu, boolean shortcut) { + final public AdditionalLauncher setShortcuts(boolean menu, boolean shortcut) { withMenuShortcut = menu; withShortcut = shortcut; return this; } - public AdditionalLauncher setIcon(Path iconPath) { + final public AdditionalLauncher setIcon(Path iconPath) { if (iconPath == NO_ICON) { throw new IllegalArgumentException(); } @@ -96,12 +101,12 @@ public final class AdditionalLauncher { return this; } - public AdditionalLauncher setNoIcon() { + final public AdditionalLauncher setNoIcon() { icon = NO_ICON; return this; } - public AdditionalLauncher setPersistenceHandler( + final public AdditionalLauncher setPersistenceHandler( ThrowingBiConsumer>> handler) { if (handler != null) { createFileHandler = ThrowingBiConsumer.toBiConsumer(handler); @@ -111,19 +116,53 @@ public final class AdditionalLauncher { return this; } - public void applyTo(JPackageCommand cmd) { + final public void applyTo(JPackageCommand cmd) { cmd.addPrerequisiteAction(this::initialize); cmd.addVerifyAction(this::verify); } - public void applyTo(PackageTest test) { - test.addLauncherName(name); + final public void applyTo(PackageTest test) { test.addInitializer(this::initialize); test.addInstallVerifier(this::verify); } + static void forEachAdditionalLauncher(JPackageCommand cmd, + BiConsumer consumer) { + var argIt = cmd.getAllArguments().iterator(); + while (argIt.hasNext()) { + if ("--add-launcher".equals(argIt.next())) { + // = + var arg = argIt.next(); + var items = arg.split("=", 2); + consumer.accept(items[0], Path.of(items[1])); + } + } + } + + static PropertyFile getAdditionalLauncherProperties( + JPackageCommand cmd, String launcherName) { + PropertyFile shell[] = new PropertyFile[1]; + forEachAdditionalLauncher(cmd, (name, propertiesFilePath) -> { + if (name.equals(launcherName)) { + shell[0] = toFunction(PropertyFile::new).apply( + propertiesFilePath); + } + }); + return Optional.of(shell[0]).get(); + } + private void initialize(JPackageCommand cmd) { - final Path propsFile = TKit.workDir().resolve(name + ".properties"); + Path propsFile = TKit.workDir().resolve(name + ".properties"); + if (Files.exists(propsFile)) { + // File with the given name exists, pick another name that + // will not reference existing file. + try { + propsFile = TKit.createTempFile(propsFile); + TKit.deleteIfExists(propsFile); + } catch (IOException ex) { + Functional.rethrowUnchecked(ex); + } + } cmd.addArguments("--add-launcher", String.format("%s=%s", name, propsFile)); @@ -242,7 +281,7 @@ public final class AdditionalLauncher { } } - private void verify(JPackageCommand cmd) throws IOException { + protected void verify(JPackageCommand cmd) throws IOException { verifyIcon(cmd); verifyShortcuts(cmd); @@ -255,14 +294,60 @@ public final class AdditionalLauncher { return; } - HelloApp.assertApp(launcherPath) - .addDefaultArguments(Optional - .ofNullable(defaultArguments) - .orElseGet(() -> List.of(cmd.getAllArgumentValues("--arguments")))) - .addJavaOptions(Optional - .ofNullable(javaOptions) - .orElseGet(() -> List.of(cmd.getAllArgumentValues("--java-options")))) - .executeAndVerifyOutput(); + var appVerifier = HelloApp.assertApp(launcherPath) + .addDefaultArguments(Optional + .ofNullable(defaultArguments) + .orElseGet(() -> List.of(cmd.getAllArgumentValues("--arguments")))) + .addJavaOptions(Optional + .ofNullable(javaOptions) + .orElseGet(() -> List.of(cmd.getAllArgumentValues( + "--java-options"))).stream().map( + str -> resolveVariables(cmd, str)).toList()); + + appVerifier.executeAndVerifyOutput(); + } + + public static final class PropertyFile { + + PropertyFile(Path path) throws IOException { + data = Files.readAllLines(path).stream().map(str -> { + return str.split("=", 2); + }).collect( + Collectors.toMap(tokens -> tokens[0], tokens -> tokens[1], + (oldValue, newValue) -> { + return newValue; + })); + } + + public boolean isPropertySet(String name) { + Objects.requireNonNull(name); + return data.containsKey(name); + } + + public Optional getPropertyValue(String name) { + Objects.requireNonNull(name); + return Optional.of(data.get(name)); + } + + public Optional getPropertyBooleanValue(String name) { + Objects.requireNonNull(name); + return Optional.ofNullable(data.get(name)).map(Boolean::parseBoolean); + } + + private final Map data; + } + + private static String resolveVariables(JPackageCommand cmd, String str) { + var map = Map.of( + "$APPDIR", cmd.appLayout().appDirectory(), + "$ROOTDIR", + cmd.isImagePackageType() ? cmd.outputBundle() : cmd.appInstallationDirectory(), + "$BINDIR", cmd.appLayout().launchersDirectory()); + for (var e : map.entrySet()) { + str = str.replaceAll(Pattern.quote(e.getKey()), + Matcher.quoteReplacement(e.getValue().toString())); + } + return str; } private List javaOptions; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/CfgFile.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/CfgFile.java index e2a380366e8..31bf0520a31 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/CfgFile.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/CfgFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -85,7 +86,8 @@ public final class CfgFile { } if (!currentSection.isEmpty()) { - result.put("", Collections.unmodifiableMap(currentSection)); + result.put(Optional.ofNullable(currentSectionName).orElse(""), + Collections.unmodifiableMap(currentSection)); } return new CfgFile(Collections.unmodifiableMap(result), path.toString()); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java index d65fe4e667b..3fed83ddb36 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -90,8 +90,10 @@ public final class Executor extends CommandArguments { } public Executor setWindowsTmpDir(String tmp) { - TKit.assertTrue(TKit.isWindows(), - "setWindowsTmpDir is only valid on Windows platform"); + if (!TKit.isWindows()) { + throw new UnsupportedOperationException( + "setWindowsTmpDir is only valid on Windows platform"); + } winTmpDir = tmp; return this; } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java index 71561a51cf3..2d0d23dae26 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -351,6 +351,7 @@ public final class HelloApp { public final static class AppOutputVerifier { AppOutputVerifier(Path helloAppLauncher) { this.launcherPath = helloAppLauncher; + this.outputFilePath = TKit.workDir().resolve(OUTPUT_FILENAME); this.params = new HashMap<>(); this.defaultLauncherArgs = new ArrayList<>(); } @@ -367,6 +368,8 @@ public final class HelloApp { public AppOutputVerifier addParam(String name, String value) { if (name.startsWith("param")) { params.put(name, value); + } else if ("jpackage.test.appOutput".equals(name)) { + outputFilePath = Path.of(value); } return this; } @@ -397,6 +400,18 @@ public final class HelloApp { .collect(Collectors.toList())); } + public void verifyOutput(String... args) { + final List launcherArgs = List.of(args); + final List appArgs; + if (launcherArgs.isEmpty()) { + appArgs = defaultLauncherArgs; + } else { + appArgs = launcherArgs; + } + + verifyOutputFile(outputFilePath, appArgs, params); + } + public void executeAndVerifyOutput(String... args) { executeAndVerifyOutput(false, args); } @@ -408,8 +423,7 @@ public final class HelloApp { getExecutor(launcherArgs.toArray(new String[0])).dumpOutput().setRemovePath( removePath).executeAndRepeatUntilExitCode(0, attempts, waitBetweenAttemptsSeconds); - Path outputFile = TKit.workDir().resolve(OUTPUT_FILENAME); - verifyOutputFile(outputFile, appArgs, params); + verifyOutputFile(outputFilePath, appArgs, params); } public void executeAndVerifyOutput(boolean removePath, String... args) { @@ -453,6 +467,7 @@ public final class HelloApp { } private final Path launcherPath; + private Path outputFilePath; private final List defaultLauncherArgs; private final Map params; } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index b68fe08bd1e..d30f96ff786 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,6 +47,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.jpackage.internal.AppImageFile; import jdk.jpackage.internal.ApplicationLayout; +import static jdk.jpackage.test.AdditionalLauncher.forEachAdditionalLauncher; import jdk.jpackage.test.Functional.ThrowingConsumer; import jdk.jpackage.test.Functional.ThrowingFunction; import jdk.jpackage.test.Functional.ThrowingSupplier; @@ -242,6 +243,17 @@ public final class JPackageCommand extends CommandArguments { return this; } + public JPackageCommand setInputToEmptyDirectory() { + if (Files.exists(inputDir())) { + try { + setArgumentValue("--input", TKit.createTempDirectory("input")); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + return this; + } + public JPackageCommand setFakeRuntime() { verifyMutable(); @@ -414,6 +426,28 @@ public final class JPackageCommand extends CommandArguments { return unpackDir.resolve(TKit.removeRootFromAbsolutePath(path)); } + /** + * Returns path to package file from the path in unpacked package directory + * or the given path if the package is not unpacked. + */ + public Path pathToPackageFile(Path path) { + Path unpackDir = unpackedPackageDirectory(); + if (unpackDir == null) { + if (!path.isAbsolute()) { + throw new IllegalArgumentException(String.format( + "Path [%s] is not absolute", path)); + } + return path; + } + + if (!path.startsWith(unpackDir)) { + throw new IllegalArgumentException(String.format( + "Path [%s] doesn't start with [%s] path", path, unpackDir)); + } + + return Path.of("/").resolve(unpackDir.relativize(path)); + } + Path unpackedPackageDirectory() { verifyIsOfType(PackageType.NATIVE); return getArgumentValue(UNPACKED_PATH_ARGNAME, () -> null, Path::of); @@ -497,6 +531,18 @@ public final class JPackageCommand extends CommandArguments { return appLauncherPath(null); } + /** + * Returns names of all additional launchers or empty list if none + * configured. + */ + public List addLauncherNames() { + List names = new ArrayList<>(); + forEachAdditionalLauncher(this, (launcherName, propFile) -> { + names.add(launcherName); + }); + return names; + } + private void verifyNotRuntime() { if (isRuntime()) { throw new IllegalArgumentException("Java runtime packaging"); @@ -537,9 +583,9 @@ public final class JPackageCommand extends CommandArguments { throw TKit.throwUnknownPlatformError(); } - if (criticalRuntimeFiles.stream().filter( - v -> runtimeDir.resolve(v).toFile().exists()).findFirst().orElse( - null) == null) { + if (!criticalRuntimeFiles.stream().anyMatch(v -> { + return runtimeDir.resolve(v).toFile().exists(); + })) { // Fake runtime TKit.trace(String.format( "%s because application runtime directory [%s] is incomplete", @@ -738,7 +784,7 @@ public final class JPackageCommand extends CommandArguments { appImageFileName)); } } - } else if (TKit.isOSX()) { + } else if (TKit.isOSX() && !isRuntime()) { TKit.assertFileExists(AppImageFile.getPathInAppImage( appInstallationDirectory())); } else { @@ -763,7 +809,11 @@ public final class JPackageCommand extends CommandArguments { JPackageCommand setUnpackedPackageLocation(Path path) { verifyIsOfType(PackageType.NATIVE); - setArgumentValue(UNPACKED_PATH_ARGNAME, path); + if (path != null) { + setArgumentValue(UNPACKED_PATH_ARGNAME, path); + } else { + removeArgumentWithValue(UNPACKED_PATH_ARGNAME); + } return this; } @@ -788,6 +838,11 @@ public final class JPackageCommand extends CommandArguments { return createExecutor().getPrintableCommandLine(); } + @Override + public String toString() { + return getPrintableCommandLine(); + } + public void verifyIsOfType(Collection types) { verifyIsOfType(types.toArray(PackageType[]::new)); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaTool.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaTool.java index de5a4e4d8e4..7b217b2431c 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaTool.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaTool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ public enum JavaTool { } } - Path getPath() { + public Path getPath() { return path; } @@ -48,7 +48,7 @@ public enum JavaTool { return ToolProvider.findFirst(toolName()).orElse(null); } - Path relativePathInJavaHome() { + private Path relativePathInJavaHome() { Path path = Path.of("bin", toolName()); if (TKit.isWindows()) { path = path.getParent().resolve(path.getFileName().toString() + ".exe"); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java index 5b91b829457..4d096198c9d 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,8 +42,7 @@ import jdk.jpackage.internal.IOUtils; import jdk.jpackage.test.PackageTest.PackageHandlers; - -public class LinuxHelper { +public final class LinuxHelper { private static String getReleaseSuffix(JPackageCommand cmd) { String value = null; final PackageType packageType = cmd.packageType(); @@ -183,7 +182,10 @@ public class LinuxHelper { }; deb.uninstallHandler = cmd -> { cmd.verifyIsOfType(PackageType.LINUX_DEB); - Executor.of("sudo", "dpkg", "-r", getPackageName(cmd)).execute(); + var packageName = getPackageName(cmd); + String script = String.format("! dpkg -s %s || sudo dpkg -r %s", + packageName, packageName); + Executor.of("sh", "-c", script).execute(); }; deb.unpackHandler = (cmd, destinationDir) -> { cmd.verifyIsOfType(PackageType.LINUX_DEB); @@ -200,13 +202,16 @@ public class LinuxHelper { PackageHandlers rpm = new PackageHandlers(); rpm.installHandler = cmd -> { cmd.verifyIsOfType(PackageType.LINUX_RPM); - Executor.of("sudo", "rpm", "-i") + Executor.of("sudo", "rpm", "-U") .addArgument(cmd.outputBundle()) .execute(); }; rpm.uninstallHandler = cmd -> { cmd.verifyIsOfType(PackageType.LINUX_RPM); - Executor.of("sudo", "rpm", "-e", getPackageName(cmd)).execute(); + var packageName = getPackageName(cmd); + String script = String.format("! rpm -q %s || sudo rpm -e %s", + packageName, packageName); + Executor.of("sh", "-c", script).execute(); }; rpm.unpackHandler = (cmd, destinationDir) -> { cmd.verifyIsOfType(PackageType.LINUX_RPM); @@ -363,10 +368,10 @@ public class LinuxHelper { test.addInstallVerifier(cmd -> { // Verify .desktop files. - try (var files = Files.walk(cmd.appLayout().destktopIntegrationDirectory(), 1)) { + try (var files = Files.list(cmd.appLayout().destktopIntegrationDirectory())) { List desktopFiles = files .filter(path -> path.getFileName().toString().endsWith(".desktop")) - .collect(Collectors.toList()); + .toList(); if (!integrated) { TKit.assertStringListEquals(List.of(), desktopFiles.stream().map(Path::toString).collect( @@ -470,23 +475,18 @@ public class LinuxHelper { String desktopFileName = queryMimeTypeDefaultHandler(mimeType); - Path desktopFile = getSystemDesktopFilesFolder().resolve( + Path systemDesktopFile = getSystemDesktopFilesFolder().resolve( + desktopFileName); + Path appDesktopFile = cmd.appLayout().destktopIntegrationDirectory().resolve( desktopFileName); - TKit.assertFileExists(desktopFile); - - TKit.trace(String.format("Reading [%s] file...", desktopFile)); - String mimeHandler = Files.readAllLines(desktopFile).stream().peek( - v -> TKit.trace(v)).filter( - v -> v.startsWith("Exec=")).map( - v -> v.split("=", 2)[1]).findFirst().orElseThrow(); - - TKit.trace(String.format("Done")); - - TKit.assertEquals(cmd.appLauncherPath().toString(), - mimeHandler, String.format( - "Check mime type handler is the main application launcher")); + TKit.assertFileExists(systemDesktopFile); + TKit.assertFileExists(appDesktopFile); + TKit.assertStringListEquals(Files.readAllLines(appDesktopFile), + Files.readAllLines(systemDesktopFile), String.format( + "Check [%s] file is a copy of [%s] file", + systemDesktopFile, appDesktopFile)); }); }); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java index 9b6457ccc58..7f5887f0ac3 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,6 +39,7 @@ import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; +import jdk.jpackage.internal.IOUtils; import jdk.jpackage.test.Functional.ThrowingConsumer; import jdk.jpackage.test.Functional.ThrowingSupplier; import jdk.jpackage.test.PackageTest.PackageHandlers; @@ -46,7 +47,7 @@ import jdk.jpackage.internal.RetryExecutor; import org.xml.sax.SAXException; import org.w3c.dom.NodeList; -public class MacHelper { +public final class MacHelper { public static void withExplodedDmg(JPackageCommand cmd, ThrowingConsumer consumer) { @@ -172,41 +173,62 @@ public class MacHelper { pkg.installHandler = cmd -> { cmd.verifyIsOfType(PackageType.MAC_PKG); Executor.of("sudo", "/usr/sbin/installer", "-allowUntrusted", "-pkg") - .addArgument(cmd.outputBundle()) - .addArguments("-target", "/") - .execute(); + .addArgument(cmd.outputBundle()) + .addArguments("-target", "/") + .execute(); }; pkg.unpackHandler = (cmd, destinationDir) -> { cmd.verifyIsOfType(PackageType.MAC_PKG); + + var dataDir = destinationDir.resolve("data"); + Executor.of("pkgutil", "--expand") - .addArgument(cmd.outputBundle()) - .addArgument(destinationDir.resolve("data")) // We need non-existing folder - .execute(); + .addArgument(cmd.outputBundle()) + .addArgument(dataDir) // We need non-existing folder + .execute(); final Path unpackRoot = destinationDir.resolve("unpacked"); - Path installDir = TKit.removeRootFromAbsolutePath( - getInstallationDirectory(cmd)).getParent(); - final Path unpackDir = unpackRoot.resolve(installDir); - try { - Files.createDirectories(unpackDir); + // Unpack all ".pkg" files from $dataDir folder in $unpackDir folder + try (var dataListing = Files.list(dataDir)) { + dataListing.filter(file -> { + return ".pkg".equals(IOUtils.getSuffix(file.getFileName())); + }).forEach(ThrowingConsumer.toConsumer(pkgDir -> { + // Installation root of the package is stored in + // /pkg-info@install-location attribute in $pkgDir/PackageInfo xml file + var doc = createDocumentBuilder().parse( + new ByteArrayInputStream(Files.readAllBytes( + pkgDir.resolve("PackageInfo")))); + var xPath = XPathFactory.newInstance().newXPath(); + + final String installRoot = (String) xPath.evaluate( + "/pkg-info/@install-location", doc, + XPathConstants.STRING); + + final Path unpackDir = unpackRoot.resolve( + TKit.removeRootFromAbsolutePath(Path.of(installRoot))); + + Files.createDirectories(unpackDir); + + Executor.of("tar", "-C") + .addArgument(unpackDir) + .addArgument("-xvf") + .addArgument(pkgDir.resolve("Payload")) + .execute(); + })); } catch (IOException ex) { throw new RuntimeException(ex); } - Executor.of("tar", "-C") - .addArgument(unpackDir) - .addArgument("-xvf") - .addArgument(Path.of(destinationDir.toString(), "data", - cmd.name() + "-app.pkg", "Payload")) - .execute(); return unpackRoot; }; pkg.uninstallHandler = cmd -> { cmd.verifyIsOfType(PackageType.MAC_PKG); + Executor.of("sudo", "rm", "-rf") - .addArgument(cmd.appInstallationDirectory()) - .execute(); + .addArgument(cmd.appInstallationDirectory()) + .execute(); + }; return pkg; @@ -220,13 +242,13 @@ public class MacHelper { static Path getInstallationDirectory(JPackageCommand cmd) { cmd.verifyIsOfType(PackageType.MAC); - return Path.of(cmd.getArgumentValue("--install-dir", () -> "/Applications")) - .resolve(cmd.name() + (cmd.isRuntime() ? "" : ".app")); + return Path.of(cmd.getArgumentValue("--install-dir", + () -> cmd.isRuntime() ? "/Library/Java/JavaVirtualMachines" : "/Applications")).resolve( + cmd.name() + (cmd.isRuntime() ? "" : ".app")); } private static String getPackageName(JPackageCommand cmd) { - return cmd.getArgumentValue("--mac-package-name", - () -> cmd.installerName()); + return cmd.getArgumentValue("--mac-package-name", cmd::installerName); } public static final class PListWrapper { @@ -274,25 +296,24 @@ public class MacHelper { return values; } - PListWrapper(String xml) throws ParserConfigurationException, + private PListWrapper(String xml) throws ParserConfigurationException, SAXException, IOException { doc = createDocumentBuilder().parse(new ByteArrayInputStream( xml.getBytes(StandardCharsets.UTF_8))); } - private static DocumentBuilder createDocumentBuilder() throws - ParserConfigurationException { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newDefaultInstance(); - dbf.setFeature( - "http://apache.org/xml/features/nonvalidating/load-external-dtd", - false); - return dbf.newDocumentBuilder(); - } - private final org.w3c.dom.Document doc; } + private static DocumentBuilder createDocumentBuilder() throws + ParserConfigurationException { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newDefaultInstance(); + dbf.setFeature( + "http://apache.org/xml/features/nonvalidating/load-external-dtd", + false); + return dbf.newDocumentBuilder(); + } + static final Set CRITICAL_RUNTIME_FILES = Set.of(Path.of( "Contents/Home/lib/server/libjvm.dylib")); - } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java index f81fb1c170c..0884b41dc55 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package jdk.jpackage.test; import java.awt.Desktop; import java.awt.GraphicsEnvironment; import java.io.File; +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -36,19 +37,32 @@ import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Predicate; +import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.jpackage.internal.AppImageFile; import jdk.jpackage.internal.ApplicationLayout; import jdk.jpackage.test.Functional.ThrowingBiConsumer; +import static jdk.jpackage.test.Functional.ThrowingBiConsumer.toBiConsumer; import jdk.jpackage.test.Functional.ThrowingConsumer; +import static jdk.jpackage.test.Functional.ThrowingConsumer.toConsumer; import jdk.jpackage.test.Functional.ThrowingRunnable; - +import static jdk.jpackage.test.Functional.ThrowingSupplier.toSupplier; +import static jdk.jpackage.test.Functional.rethrowUnchecked; +import static jdk.jpackage.test.PackageType.LINUX; +import static jdk.jpackage.test.PackageType.LINUX_DEB; +import static jdk.jpackage.test.PackageType.LINUX_RPM; +import static jdk.jpackage.test.PackageType.MAC_DMG; +import static jdk.jpackage.test.PackageType.MAC_PKG; +import static jdk.jpackage.test.PackageType.NATIVE; +import static jdk.jpackage.test.PackageType.WINDOWS; +import static jdk.jpackage.test.PackageType.WIN_EXE; +import static jdk.jpackage.test.PackageType.WIN_MSI; /** @@ -82,7 +96,7 @@ public final class PackageTest extends RunnablePackageTest { public PackageTest forTypes(PackageType... types) { Collection newTypes; if (types == null || types.length == 0) { - newTypes = PackageType.NATIVE; + newTypes = NATIVE; } else { newTypes = Stream.of(types).collect(Collectors.toSet()); } @@ -122,7 +136,7 @@ public final class PackageTest extends RunnablePackageTest { namedInitializers.add(id); } currentTypes.forEach(type -> handlers.get(type).addInitializer( - ThrowingConsumer.toConsumer(v))); + toConsumer(v))); return this; } @@ -151,13 +165,12 @@ public final class PackageTest extends RunnablePackageTest { public PackageTest addBundleVerifier( ThrowingBiConsumer v) { currentTypes.forEach(type -> handlers.get(type).addBundleVerifier( - ThrowingBiConsumer.toBiConsumer(v))); + toBiConsumer(v))); return this; } public PackageTest addBundleVerifier(ThrowingConsumer v) { - return addBundleVerifier( - (cmd, unused) -> ThrowingConsumer.toConsumer(v).accept(cmd)); + return addBundleVerifier((cmd, unused) -> toConsumer(v).accept(cmd)); } public PackageTest addBundlePropertyVerifier(String propertyName, @@ -184,7 +197,7 @@ public final class PackageTest extends RunnablePackageTest { } public PackageTest addBundleDesktopIntegrationVerifier(boolean integrated) { - forTypes(PackageType.LINUX, () -> { + forTypes(LINUX, () -> { LinuxHelper.addBundleDesktopIntegrationVerifier(this, integrated); }); return this; @@ -192,31 +205,25 @@ public final class PackageTest extends RunnablePackageTest { public PackageTest addInstallVerifier(ThrowingConsumer v) { currentTypes.forEach(type -> handlers.get(type).addInstallVerifier( - ThrowingConsumer.toConsumer(v))); + toConsumer(v))); return this; } public PackageTest addUninstallVerifier(ThrowingConsumer v) { currentTypes.forEach(type -> handlers.get(type).addUninstallVerifier( - ThrowingConsumer.toConsumer(v))); + toConsumer(v))); return this; } - public PackageTest setPackageInstaller(Consumer v) { + public PackageTest disablePackageInstaller() { currentTypes.forEach( - type -> packageHandlers.get(type).installHandler = v); - return this; - } - - public PackageTest setPackageUnpacker( - BiFunction v) { - currentTypes.forEach(type -> packageHandlers.get(type).unpackHandler = v); + type -> packageHandlers.get(type).installHandler = cmd -> {}); return this; } - public PackageTest setPackageUninstaller(Consumer v) { + public PackageTest disablePackageUninstaller() { currentTypes.forEach( - type -> packageHandlers.get(type).uninstallHandler = v); + type -> packageHandlers.get(type).uninstallHandler = cmd -> {}); return this; } @@ -238,7 +245,7 @@ public final class PackageTest extends RunnablePackageTest { // running check of type of environment. addHelloAppInitializer(null); - forTypes(PackageType.LINUX, () -> { + forTypes(LINUX, () -> { LinuxHelper.addFileAssociationsVerifier(this, fa); }); @@ -317,11 +324,6 @@ public final class PackageTest extends RunnablePackageTest { return this; } - public PackageTest addLauncherName(String name) { - launcherNames.add(name); - return this; - } - public final static class Group extends RunnablePackageTest { public Group(PackageTest... tests) { handlers = Stream.of(tests) @@ -372,7 +374,7 @@ public final class PackageTest extends RunnablePackageTest { } private List> createPackageTypeHandlers() { - return PackageType.NATIVE.stream() + return NATIVE.stream() .map(type -> { Handler handler = handlers.entrySet().stream() .filter(entry -> !entry.getValue().isVoid()) @@ -393,29 +395,39 @@ public final class PackageTest extends RunnablePackageTest { private Consumer createPackageTypeHandler( PackageType type, Handler handler) { - return ThrowingConsumer.toConsumer(new ThrowingConsumer() { + return toConsumer(new ThrowingConsumer() { @Override public void accept(Action action) throws Throwable { + if (terminated) { + throw new IllegalStateException(); + } + if (action == Action.FINALIZE) { - if (unpackDir != null && Files.isDirectory(unpackDir) - && !unpackDir.startsWith(TKit.workDir())) { - TKit.deleteDirectoryRecursive(unpackDir); + if (unpackDir != null) { + if (Files.isDirectory(unpackDir) + && !unpackDir.startsWith(TKit.workDir())) { + TKit.deleteDirectoryRecursive(unpackDir); + } + unpackDir = null; } + terminated = true; } if (aborted) { return; } - final JPackageCommand curCmd; - if (Set.of(Action.INITIALIZE, Action.CREATE).contains(action)) { - curCmd = cmd; - } else { - curCmd = cmd.createImmutableCopy(); - } + final Supplier curCmd = () -> { + if (Set.of(Action.INITIALIZE, Action.CREATE).contains(action)) { + return cmd; + } else { + return cmd.createImmutableCopy(); + } + }; switch (action) { case UNPACK: { + cmd.setUnpackedPackageLocation(null); var handler = packageHandlers.get(type).unpackHandler; if (!(aborted = (handler == null))) { unpackDir = TKit.createTempDirectory( @@ -428,9 +440,10 @@ public final class PackageTest extends RunnablePackageTest { } case INSTALL: { + cmd.setUnpackedPackageLocation(null); var handler = packageHandlers.get(type).installHandler; if (!(aborted = (handler == null))) { - handler.accept(curCmd); + handler.accept(curCmd.get()); } break; } @@ -438,18 +451,19 @@ public final class PackageTest extends RunnablePackageTest { case UNINSTALL: { var handler = packageHandlers.get(type).uninstallHandler; if (!(aborted = (handler == null))) { - handler.accept(curCmd); + handler.accept(curCmd.get()); } break; } case CREATE: - handler.accept(action, curCmd); + cmd.setUnpackedPackageLocation(null); + handler.accept(action, curCmd.get()); aborted = (expectedJPackageExitCode != 0); return; default: - handler.accept(action, curCmd); + handler.accept(action, curCmd.get()); break; } @@ -462,6 +476,7 @@ public final class PackageTest extends RunnablePackageTest { private Path unpackDir; private boolean aborted; + private boolean terminated; private final JPackageCommand cmd = Functional.identity(() -> { JPackageCommand result = new JPackageCommand(); result.setDefaultInputOutput().setDefaultAppName(); @@ -535,13 +550,23 @@ public final class PackageTest extends RunnablePackageTest { verifyPackageUninstalled(cmd); } break; + + case PURGE: + if (expectedJPackageExitCode == 0) { + var bundle = cmd.outputBundle(); + if (toSupplier(() -> TKit.deleteIfExists(bundle)).get()) { + TKit.trace(String.format("Deleted [%s] package", + bundle)); + } + } + break; } } private void verifyPackageBundle(JPackageCommand cmd, Executor.Result result) { if (expectedJPackageExitCode == 0) { - if (PackageType.LINUX.contains(cmd.packageType())) { + if (LINUX.contains(cmd.packageType())) { LinuxHelper.verifyPackageBundleEssential(cmd); } } @@ -557,35 +582,85 @@ public final class PackageTest extends RunnablePackageTest { } TKit.trace(String.format(formatString, cmd.getPrintableCommandLine())); + Optional.ofNullable(cmd.unpackedPackageDirectory()).ifPresent( + unpackedDir -> { + verifyRootCountInUnpackedPackage(cmd, unpackedDir); + }); + if (!cmd.isRuntime()) { - if (PackageType.WINDOWS.contains(cmd.packageType()) + if (WINDOWS.contains(cmd.packageType()) && !cmd.isPackageUnpacked( "Not verifying desktop integration")) { // Check main launcher - new WindowsHelper.DesktopIntegrationVerifier(cmd, null); + WindowsHelper.verifyDesktopIntegration(cmd, null); // Check additional launchers - launcherNames.forEach(name -> { - new WindowsHelper.DesktopIntegrationVerifier(cmd, name); + cmd.addLauncherNames().forEach(name -> { + WindowsHelper.verifyDesktopIntegration(cmd, name); }); } } + cmd.assertAppLayout(); installVerifiers.forEach(v -> v.accept(cmd)); } + private void verifyRootCountInUnpackedPackage(JPackageCommand cmd, + Path unpackedDir) { + + final long expectedRootCount; + if (WINDOWS.contains(cmd.packageType())) { + // On Windows it is always two entries: + // installation home directory and MSI file + expectedRootCount = 2; + } else if (LINUX.contains(cmd.packageType())) { + Set roots = new HashSet<>(); + roots.add(Path.of("/").resolve(Path.of(cmd.getArgumentValue( + "--install-dir", () -> "/opt")).getName(0))); + if (cmd.hasArgument("--license-file")) { + switch (cmd.packageType()) { + case LINUX_RPM -> { + // License file is in /usr/share/licenses subtree + roots.add(Path.of("/usr")); + } + + case LINUX_DEB -> { + Path installDir = cmd.appInstallationDirectory(); + if (installDir.equals(Path.of("/")) + || installDir.startsWith("/usr")) { + // License file is in /usr/share/doc subtree + roots.add(Path.of("/usr")); + } + } + } + } + expectedRootCount = roots.size(); + } else { + expectedRootCount = 1; + } + + try ( var files = Files.list(unpackedDir)) { + TKit.assertEquals(expectedRootCount, files.count(), + String.format( + "Check the package has %d top installation directories", + expectedRootCount)); + } catch (IOException ex) { + rethrowUnchecked(ex); + } + } + private void verifyPackageUninstalled(JPackageCommand cmd) { TKit.trace(String.format("Verify uninstalled: %s", cmd.getPrintableCommandLine())); if (!cmd.isRuntime()) { TKit.assertPathExists(cmd.appLauncherPath(), false); - if (PackageType.WINDOWS.contains(cmd.packageType())) { + if (WINDOWS.contains(cmd.packageType())) { // Check main launcher - new WindowsHelper.DesktopIntegrationVerifier(cmd, null); + WindowsHelper.verifyDesktopIntegration(cmd, null); // Check additional launchers - launcherNames.forEach(name -> { - new WindowsHelper.DesktopIntegrationVerifier(cmd, name); + cmd.addLauncherNames().forEach(name -> { + WindowsHelper.verifyDesktopIntegration(cmd, name); }); } } @@ -610,18 +685,18 @@ public final class PackageTest extends RunnablePackageTest { private static Map createDefaultPackageHandlers() { HashMap handlers = new HashMap<>(); if (TKit.isLinux()) { - handlers.put(PackageType.LINUX_DEB, LinuxHelper.createDebPackageHandlers()); - handlers.put(PackageType.LINUX_RPM, LinuxHelper.createRpmPackageHandlers()); + handlers.put(LINUX_DEB, LinuxHelper.createDebPackageHandlers()); + handlers.put(LINUX_RPM, LinuxHelper.createRpmPackageHandlers()); } if (TKit.isWindows()) { - handlers.put(PackageType.WIN_MSI, WindowsHelper.createMsiPackageHandlers()); - handlers.put(PackageType.WIN_EXE, WindowsHelper.createExePackageHandlers()); + handlers.put(WIN_MSI, WindowsHelper.createMsiPackageHandlers()); + handlers.put(WIN_EXE, WindowsHelper.createExePackageHandlers()); } if (TKit.isOSX()) { - handlers.put(PackageType.MAC_DMG, MacHelper.createDmgPackageHandlers()); - handlers.put(PackageType.MAC_PKG, MacHelper.createPkgPackageHandlers()); + handlers.put(MAC_DMG, MacHelper.createDmgPackageHandlers()); + handlers.put(MAC_PKG, MacHelper.createPkgPackageHandlers()); } return handlers; @@ -633,7 +708,6 @@ public final class PackageTest extends RunnablePackageTest { private Map handlers; private Set namedInitializers; private Map packageHandlers; - private final List launcherNames = new ArrayList(); private final static File BUNDLE_OUTPUT_DIR; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/RunnablePackageTest.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/RunnablePackageTest.java index 6f98cfc234d..a5cedc5c34e 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/RunnablePackageTest.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/RunnablePackageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,12 @@ public abstract class RunnablePackageTest { .filter(Predicate.not(Action.INITIALIZE::equals)) .filter(Predicate.not(Action.FINALIZE::equals)) .collect(Collectors.toList())); + if (hasAction(Action.PURGE) && !actionList.contains(Action.PURGE)) { + // Default action list contains "purge" action meaning + // packages are not needed for further processing. + // Copy this behavior in custom action list. + actionList.add(Action.PURGE); + } } actionList.add(Action.FINALIZE); @@ -51,6 +57,10 @@ public abstract class RunnablePackageTest { runActions(actionGroups); } + public static boolean hasAction(Action a) { + return DEFAULT_ACTIONS.contains(a); + } + protected void runActions(List actions) { actions.forEach(this::runAction); } @@ -89,6 +99,10 @@ public abstract class RunnablePackageTest { * Uninstall package. */ UNINSTALL, + /** + * Purge package. + */ + PURGE, /** * Finalize test. */ diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java index fb88d4cd21d..1907c074504 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java index 528973bea22..a3f67e01d46 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,7 +58,7 @@ public class WindowsHelper { private static Path getInstallationSubDirectory(JPackageCommand cmd) { cmd.verifyIsOfType(PackageType.WINDOWS); - return Path.of(cmd.getArgumentValue("--install-dir", () -> cmd.name())); + return Path.of(cmd.getArgumentValue("--install-dir", cmd::name)); } private static void runMsiexecWithRetries(Executor misexec) { @@ -66,7 +66,13 @@ public class WindowsHelper { for (int attempt = 0; attempt < 8; ++attempt) { result = misexec.executeWithoutExitCodeCheck(); - // The given Executor may either be of an msiexe command or an + if (result.exitCode == 1605) { + // ERROR_UNKNOWN_PRODUCT, attempt to uninstall not installed + // package + return; + } + + // The given Executor may either be of an msiexec command or an // unpack.bat script containing the msiexec command. In the later // case, when misexec returns 1618, the unpack.bat may return 1603 if ((result.exitCode == 1618) || (result.exitCode == 1603)) { @@ -91,16 +97,25 @@ public class WindowsHelper { PackageHandlers msi = new PackageHandlers(); msi.installHandler = cmd -> installMsi.accept(cmd, true); - msi.uninstallHandler = cmd -> installMsi.accept(cmd, false); + msi.uninstallHandler = cmd -> { + if (Files.exists(cmd.outputBundle())) { + installMsi.accept(cmd, false); + } + }; msi.unpackHandler = (cmd, destinationDir) -> { cmd.verifyIsOfType(PackageType.WIN_MSI); final Path unpackBat = destinationDir.resolve("unpack.bat"); final Path unpackDir = destinationDir.resolve( TKit.removeRootFromAbsolutePath( getInstallationRootDirectory(cmd))); + // Put msiexec in .bat file because can't pass value of TARGETDIR // property containing spaces through ProcessBuilder properly. - TKit.createTextFile(unpackBat, List.of(String.join(" ", List.of( + // Set folder permissions to allow msiexec unpack msi bundle. + TKit.createTextFile(unpackBat, List.of( + String.format("icacls \"%s\" /inheritance:e /grant Users:M", + destinationDir), + String.join(" ", List.of( "msiexec", "/a", String.format("\"%s\"", cmd.outputBundle().normalize()), @@ -125,10 +140,19 @@ public class WindowsHelper { PackageHandlers exe = new PackageHandlers(); exe.installHandler = cmd -> installExe.accept(cmd, true); - exe.uninstallHandler = cmd -> installExe.accept(cmd, false); + exe.uninstallHandler = cmd -> { + if (Files.exists(cmd.outputBundle())) { + installExe.accept(cmd, false); + } + }; return exe; } + static void verifyDesktopIntegration(JPackageCommand cmd, + String launcherName) { + new DesktopIntegrationVerifier(cmd, launcherName); + } + public static String getMsiProperty(JPackageCommand cmd, String propertyName) { cmd.verifyIsOfType(PackageType.WIN_MSI); return Executor.of("cscript.exe", "//Nologo") @@ -143,21 +167,45 @@ public class WindowsHelper { return cmd.hasArgument("--win-per-user-install"); } - static class DesktopIntegrationVerifier { + private static class DesktopIntegrationVerifier { - DesktopIntegrationVerifier(JPackageCommand cmd, String name) { + DesktopIntegrationVerifier(JPackageCommand cmd, String launcherName) { cmd.verifyIsOfType(PackageType.WINDOWS); - this.cmd = cmd; - this.name = (name == null ? cmd.name() : name); + + name = Optional.ofNullable(launcherName).orElseGet(cmd::name); + + isUserLocalInstall = isUserLocalInstall(cmd); + + appInstalled = cmd.appLauncherPath(launcherName).toFile().exists(); + + desktopShortcutPath = Path.of(name + ".lnk"); + + startMenuShortcutPath = Path.of(cmd.getArgumentValue( + "--win-menu-group", () -> "Unknown"), name + ".lnk"); + + if (name.equals(cmd.name())) { + isWinMenu = cmd.hasArgument("--win-menu"); + isDesktop = cmd.hasArgument("--win-shortcut"); + } else { + var props = AdditionalLauncher.getAdditionalLauncherProperties(cmd, + launcherName); + isWinMenu = props.getPropertyBooleanValue("win-menu").orElseGet( + () -> cmd.hasArgument("--win-menu")); + isDesktop = props.getPropertyBooleanValue("win-shortcut").orElseGet( + () -> cmd.hasArgument("--win-shortcut")); + } + verifyStartMenuShortcut(); + verifyDesktopShortcut(); - verifyFileAssociationsRegistry(); + + Stream.of(cmd.getAllArgumentValues("--file-associations")).map( + Path::of).forEach(this::verifyFileAssociationsRegistry); } private void verifyDesktopShortcut() { - boolean appInstalled = cmd.appLauncherPath(name).toFile().exists(); - if (cmd.hasArgument("--win-shortcut")) { - if (isUserLocalInstall(cmd)) { + if (isDesktop) { + if (isUserLocalInstall) { verifyUserLocalDesktopShortcut(appInstalled); verifySystemDesktopShortcut(false); } else { @@ -170,10 +218,6 @@ public class WindowsHelper { } } - private Path desktopShortcutPath() { - return Path.of(name + ".lnk"); - } - private void verifyShortcut(Path path, boolean exists) { if (exists) { TKit.assertFileExists(path); @@ -185,19 +229,18 @@ public class WindowsHelper { private void verifySystemDesktopShortcut(boolean exists) { Path dir = Path.of(queryRegistryValueCache( SYSTEM_SHELL_FOLDERS_REGKEY, "Common Desktop")); - verifyShortcut(dir.resolve(desktopShortcutPath()), exists); + verifyShortcut(dir.resolve(desktopShortcutPath), exists); } private void verifyUserLocalDesktopShortcut(boolean exists) { Path dir = Path.of( queryRegistryValueCache(USER_SHELL_FOLDERS_REGKEY, "Desktop")); - verifyShortcut(dir.resolve(desktopShortcutPath()), exists); + verifyShortcut(dir.resolve(desktopShortcutPath), exists); } private void verifyStartMenuShortcut() { - boolean appInstalled = cmd.appLauncherPath(name).toFile().exists(); - if (cmd.hasArgument("--win-menu")) { - if (isUserLocalInstall(cmd)) { + if (isWinMenu) { + if (isUserLocalInstall) { verifyUserLocalStartMenuShortcut(appInstalled); verifySystemStartMenuShortcut(false); } else { @@ -210,13 +253,8 @@ public class WindowsHelper { } } - private Path startMenuShortcutPath() { - return Path.of(cmd.getArgumentValue("--win-menu-group", - () -> "Unknown"), name + ".lnk"); - } - private void verifyStartMenuShortcut(Path shortcutsRoot, boolean exists) { - Path shortcutPath = shortcutsRoot.resolve(startMenuShortcutPath()); + Path shortcutPath = shortcutsRoot.resolve(startMenuShortcutPath); verifyShortcut(shortcutPath, exists); if (!exists) { TKit.assertPathNotEmptyDirectory(shortcutPath.getParent()); @@ -234,13 +272,7 @@ public class WindowsHelper { USER_SHELL_FOLDERS_REGKEY, "Programs")), exists); } - private void verifyFileAssociationsRegistry() { - Stream.of(cmd.getAllArgumentValues("--file-associations")).map( - Path::of).forEach(this::verifyFileAssociationsRegistry); - } - private void verifyFileAssociationsRegistry(Path faFile) { - boolean appInstalled = cmd.appLauncherPath(name).toFile().exists(); try { TKit.trace(String.format( "Get file association properties from [%s] file", @@ -290,7 +322,12 @@ public class WindowsHelper { } } - private final JPackageCommand cmd; + private final Path desktopShortcutPath; + private final Path startMenuShortcutPath; + private final boolean isUserLocalInstall; + private final boolean appInstalled; + private final boolean isWinMenu; + private final boolean isDesktop; private final String name; } diff --git a/test/jdk/tools/jpackage/run_tests.sh b/test/jdk/tools/jpackage/run_tests.sh index a5cb03fc3aa..2639f38cd68 100644 --- a/test/jdk/tools/jpackage/run_tests.sh +++ b/test/jdk/tools/jpackage/run_tests.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -78,15 +78,25 @@ help_usage () echo " Optional, for jtreg tests debug purposes only." echo ' -l - value for `jpackage.test.logfile` property.' echo " Optional, for jtreg tests debug purposes only." - echo " -m - mode to run jtreg tests." - echo ' Should be one of `create`, `update` or `print-default-tests`.' - echo ' Optional, default mode is `update`.' + echo " -m - mode to run jtreg tests. Supported values:" echo ' - `create`' echo ' Remove all package bundles from the output directory before running jtreg tests.' echo ' - `update`' echo ' Run jtreg tests and overrite existing package bundles in the output directory.' echo ' - `print-default-tests`' echo ' Print default list of packaging tests and exit.' + echo ' - `create-small-runtime`' + echo ' Create small Java runtime using /bin/jlink command in the output directory.' + echo ' - `create-packages`' + echo ' Create packages.' + echo ' The script will set `jpackage.test.action` property.' + echo ' - `test-packages`' + echo ' Create and fully test packages. Will create, unpack, install, and uninstall packages.' + echo ' The script will set `jpackage.test.action` property.' + echo ' - `do-packages`' + echo " Create, unpack and verify packages." + echo ' The script will not set `jpackage.test.action` property.' + echo ' Optional, defaults are `update` and `create-packages`.' } error () @@ -133,8 +143,6 @@ exec_command () test_jdk= # Path to local copy of open jdk repo with jpackage jtreg tests -# hg clone http://hg.openjdk.java.net/jdk/sandbox -# cd sandbox; hg update -r JDK-8200758-branch open_jdk_with_jpackage_jtreg_tests=$(dirname $0)/../../../../ # Directory where to save artifacts for testing. @@ -152,12 +160,27 @@ mode=update # jtreg extra arguments declare -a jtreg_args -# Create packages only -jtreg_args+=("-Djpackage.test.action=create") - # run all tests run_all_tests= +test_actions= + +set_mode () +{ + case "$1" in + create-packages) test_actions='-Djpackage.test.action=create';; + test-packages) test_actions='-Djpackage.test.action=uninstall,create,unpack,verify-install,install,verify-install,uninstall,verify-uninstall,purge';; + do-packages) test_actions=;; + create-small-runtime) mode=$1;; + print-default-tests) mode=$1;; + create) mode=$1;; + update) mode=$1;; + *) fatal_with_help_usage 'Invalid value of -m option:' [$1];; + esac +} + +set_mode 'create-packages' + mapfile -t tests < <(find_all_packaging_tests) while getopts "vahdct:j:o:r:m:l:" argname; do @@ -171,7 +194,7 @@ while getopts "vahdct:j:o:r:m:l:" argname; do o) output_dir="$OPTARG";; r) runtime_dir="$OPTARG";; l) logfile="$OPTARG";; - m) mode="$OPTARG";; + m) set_mode "$OPTARG";; h) help_usage; exit 0;; ?) help_usage; exit 1;; esac @@ -201,6 +224,11 @@ if [ ! -e "$JAVA_HOME/bin/java" ]; then fatal JAVA_HOME variable is set to [$JAVA_HOME] value, but $JAVA_HOME/bin/java not found. fi +if [ "$mode" = "create-small-runtime" ]; then + exec_command "$test_jdk/bin/jlink" --add-modules java.base,java.datatransfer,java.xml,java.prefs,java.desktop --compress=2 --no-header-files --no-man-pages --strip-debug --output "$output_dir" + exit +fi + if [ -z "$JT_HOME" ]; then if [ -z "$JT_BUNDLE_URL" ]; then fatal 'JT_HOME or JT_BUNDLE_URL environment variable is not set. Link to JTREG bundle can be found at https://openjdk.java.net/jtreg/'. @@ -222,18 +250,12 @@ if [ -n "$logfile" ]; then jtreg_args+=("-Djpackage.test.logfile=$(to_native_path "$logfile")") fi -if [ "$mode" = create ]; then - true -elif [ "$mode" = update ]; then - true -else - fatal_with_help_usage 'Invalid value of -m option:' [$mode] -fi - if [ -z "$run_all_tests" ]; then jtreg_args+=(-Djpackage.test.SQETest=yes) fi +jtreg_args+=("$test_actions") + # Drop arguments separator [ "$1" != "--" ] || shift @@ -249,10 +271,10 @@ installJtreg () if [ ! -f "$jtreg_jar" ]; then exec_command mkdir -p "$workdir" if [[ ${jtreg_bundle: -7} == ".tar.gz" ]]; then - exec_command "(" cd "$workdir" "&&" wget "$jtreg_bundle" "&&" tar -xzf "$(basename $jtreg_bundle)" ";" rm -f "$(basename $jtreg_bundle)" ")" + exec_command "(" cd "$workdir" "&&" wget --no-check-certificate "$jtreg_bundle" "&&" tar -xzf "$(basename $jtreg_bundle)" ";" rm -f "$(basename $jtreg_bundle)" ")" else if [[ ${jtreg_bundle: -4} == ".zip" ]]; then - exec_command "(" cd "$workdir" "&&" wget "$jtreg_bundle" "&&" unzip "$(basename $jtreg_bundle)" ";" rm -f "$(basename $jtreg_bundle)" ")" + exec_command "(" cd "$workdir" "&&" wget --no-check-certificate "$jtreg_bundle" "&&" unzip "$(basename $jtreg_bundle)" ";" rm -f "$(basename $jtreg_bundle)" ")" else fatal 'Unsupported extension of JREG bundle ['$JT_BUNDLE_URL']. Only *.zip or *.tar.gz is supported.' fi diff --git a/test/jdk/tools/jpackage/share/MultiLauncherTwoPhaseTest.java b/test/jdk/tools/jpackage/share/MultiLauncherTwoPhaseTest.java index 5df3609e3ba..b048d6db335 100644 --- a/test/jdk/tools/jpackage/share/MultiLauncherTwoPhaseTest.java +++ b/test/jdk/tools/jpackage/share/MultiLauncherTwoPhaseTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,8 +69,6 @@ public class MultiLauncherTwoPhaseTest { launcher2.applyTo(appImageCmd); PackageTest packageTest = new PackageTest() - .addLauncherName("bar") // Add launchers name for verification - .addLauncherName("foo") .addRunOnceInitializer(() -> appImageCmd.execute()) .addBundleDesktopIntegrationVerifier(true) .addInitializer(cmd -> { diff --git a/test/jdk/tools/jpackage/test_jpackage.sh b/test/jdk/tools/jpackage/test_jpackage.sh deleted file mode 100644 index c4b28020bc0..00000000000 --- a/test/jdk/tools/jpackage/test_jpackage.sh +++ /dev/null @@ -1,100 +0,0 @@ -#!/bin/bash - -# Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. - - -# -# Complete testing of jpackage platform-specific packaging. -# -# The script does the following: -# 1. Create packages. -# 2. Install created packages. -# 3. Verifies packages are installed. -# 4. Uninstall created packages. -# 5. Verifies packages are uninstalled. -# -# For the list of accepted command line arguments see `run_tests.sh` script. -# - -# Fail fast -set -e; set -o pipefail; - -# Script debug -dry_run=${JPACKAGE_TEST_DRY_RUN} - -# Default directory where jpackage should write bundle files -output_dir=~/jpackage_bundles - - -set_args () -{ - args=() - local arg_is_output_dir= - local arg_is_mode= - local output_dir_set= - local with_append_actions=yes - for arg in "$@"; do - if [ "$arg" == "-o" ]; then - arg_is_output_dir=yes - output_dir_set=yes - elif [ "$arg" == "-m" ]; then - arg_is_mode=yes - continue - elif [ "$arg" == '--' ]; then - append_actions - with_append_actions= - continue - elif ! case "$arg" in -Djpackage.test.action=*) false;; esac; then - continue - elif [ -n "$arg_is_output_dir" ]; then - arg_is_output_dir= - output_dir="$arg" - elif [ -n "$arg_is_mode" ]; then - arg_is_mode= - continue - fi - - args+=( "$arg" ) - done - [ -n "$output_dir_set" ] || args=( -o "$output_dir" "${args[@]}" ) - [ -z "$with_append_actions" ] || append_actions -} - - -append_actions () -{ - args+=( '--' '-Djpackage.test.action=create,install,verify-install,uninstall,verify-uninstall' ) -} - - -exec_command () -{ - if [ -n "$dry_run" ]; then - echo "$@" - else - eval "$@" - fi -} - -set_args "$@" -basedir="$(dirname $0)" -exec_command ${SHELL} "$basedir/run_tests.sh" -m create "${args[@]}" diff --git a/test/jdk/tools/jpackage/windows/WinUpgradeUUIDTest.java b/test/jdk/tools/jpackage/windows/WinUpgradeUUIDTest.java index 0c233b0e652..968ed94b345 100644 --- a/test/jdk/tools/jpackage/windows/WinUpgradeUUIDTest.java +++ b/test/jdk/tools/jpackage/windows/WinUpgradeUUIDTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -100,7 +100,7 @@ public class WinUpgradeUUIDTest { // It will be uninstalled automatically when the second // package will be installed. // However uninstall verification for the first package will be executed. - PackageTest test1 = init.get().setPackageUninstaller(cmd -> {}); + PackageTest test1 = init.get().disablePackageUninstaller(); PackageTest test2 = init.get().addInitializer(cmd -> { cmd.setArgumentValue("--app-version", "2.0"); -- GitLab From 1eec16b47be300e1462528bddf5d0686df3f042c Mon Sep 17 00:00:00 2001 From: Xiaohong Gong Date: Thu, 17 Feb 2022 05:44:12 +0000 Subject: [PATCH 106/203] 8281803: AArch64: Optimize masked vector NOT/AND_NOT for SVE Reviewed-by: aph, njian --- src/hotspot/cpu/aarch64/aarch64_sve.ad | 64 ++++++- src/hotspot/cpu/aarch64/aarch64_sve_ad.m4 | 56 ++++++- src/hotspot/cpu/aarch64/assembler_aarch64.hpp | 1 + test/hotspot/gtest/aarch64/aarch64-asmtest.py | 1 + test/hotspot/gtest/aarch64/asmtest.out.h | 158 +++++++++--------- 5 files changed, 198 insertions(+), 82 deletions(-) diff --git a/src/hotspot/cpu/aarch64/aarch64_sve.ad b/src/hotspot/cpu/aarch64/aarch64_sve.ad index bf00892b936..c048a463c1a 100644 --- a/src/hotspot/cpu/aarch64/aarch64_sve.ad +++ b/src/hotspot/cpu/aarch64/aarch64_sve.ad @@ -1,6 +1,6 @@ // -// Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. -// Copyright (c) 2020, 2021, Arm Limited. All rights reserved. +// Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2020, 2022, Arm Limited. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -1288,6 +1288,36 @@ instruct vnotL(vReg dst, vReg src, immL_M1 m1) %{ ins_pipe(pipe_slow); %} +// vector not - predicated + +instruct vnotI_masked(vReg dst, vReg src, immI_M1 m1, pRegGov pg) %{ + predicate(UseSVE > 0); + match(Set dst (XorV (Binary src (ReplicateB m1)) pg)); + match(Set dst (XorV (Binary src (ReplicateS m1)) pg)); + match(Set dst (XorV (Binary src (ReplicateI m1)) pg)); + ins_cost(SVE_COST); + format %{ "sve_not $dst, $pg, $src\t# vector (sve) B/H/S" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ sve_not(as_FloatRegister($dst$$reg), __ elemType_to_regVariant(bt), + as_PRegister($pg$$reg), as_FloatRegister($src$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vnotL_masked(vReg dst, vReg src, immL_M1 m1, pRegGov pg) %{ + predicate(UseSVE > 0); + match(Set dst (XorV (Binary src (ReplicateL m1)) pg)); + ins_cost(SVE_COST); + format %{ "sve_not $dst, $pg, $src\t# vector (sve) D" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ sve_not(as_FloatRegister($dst$$reg), __ elemType_to_regVariant(bt), + as_PRegister($pg$$reg), as_FloatRegister($src$$reg)); + %} + ins_pipe(pipe_slow); +%} + // vector and_not instruct vand_notI(vReg dst, vReg src1, vReg src2, immI_M1 m1) %{ @@ -1318,6 +1348,36 @@ instruct vand_notL(vReg dst, vReg src1, vReg src2, immL_M1 m1) %{ ins_pipe(pipe_slow); %} +// vector and_not - predicated + +instruct vand_notI_masked(vReg dst_src1, vReg src2, immI_M1 m1, pRegGov pg) %{ + predicate(UseSVE > 0); + match(Set dst_src1 (AndV (Binary dst_src1 (XorV src2 (ReplicateB m1))) pg)); + match(Set dst_src1 (AndV (Binary dst_src1 (XorV src2 (ReplicateS m1))) pg)); + match(Set dst_src1 (AndV (Binary dst_src1 (XorV src2 (ReplicateI m1))) pg)); + ins_cost(SVE_COST); + format %{ "sve_bic $dst_src1, $pg, $dst_src1, $src2\t# vector (sve) B/H/S" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ sve_bic(as_FloatRegister($dst_src1$$reg), __ elemType_to_regVariant(bt), + as_PRegister($pg$$reg), as_FloatRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vand_notL_masked(vReg dst_src1, vReg src2, immL_M1 m1, pRegGov pg) %{ + predicate(UseSVE > 0); + match(Set dst_src1 (AndV (Binary dst_src1 (XorV src2 (ReplicateL m1))) pg)); + ins_cost(SVE_COST); + format %{ "sve_bic $dst_src1, $pg, $dst_src1, $src2\t# vector (sve) D" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ sve_bic(as_FloatRegister($dst_src1$$reg), __ elemType_to_regVariant(bt), + as_PRegister($pg$$reg), as_FloatRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + // vector float div instruct vdivF(vReg dst_src1, vReg src2) %{ diff --git a/src/hotspot/cpu/aarch64/aarch64_sve_ad.m4 b/src/hotspot/cpu/aarch64/aarch64_sve_ad.m4 index 7e0acdc52c2..874cdf6e4e0 100644 --- a/src/hotspot/cpu/aarch64/aarch64_sve_ad.m4 +++ b/src/hotspot/cpu/aarch64/aarch64_sve_ad.m4 @@ -1,6 +1,6 @@ // -// Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. -// Copyright (c) 2020, 2021, Arm Limited. All rights reserved. +// Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2020, 2022, Arm Limited. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -745,6 +745,32 @@ VECTOR_NOT(I, B/H/S) VECTOR_NOT(L, D) undefine(MATCH_RULE) dnl +// vector not - predicated +dnl +define(`MATCH_RULE', `ifelse($1, I, +`match(Set dst (XorV (Binary src (ReplicateB m1)) pg)); + match(Set dst (XorV (Binary src (ReplicateS m1)) pg)); + match(Set dst (XorV (Binary src (ReplicateI m1)) pg));', +`match(Set dst (XorV (Binary src (ReplicateL m1)) pg));')')dnl +dnl +define(`VECTOR_NOT_PREDICATE', ` +instruct vnot$1_masked`'(vReg dst, vReg src, imm$1_M1 m1, pRegGov pg) %{ + predicate(UseSVE > 0); + MATCH_RULE($1) + ins_cost(SVE_COST); + format %{ "sve_not $dst, $pg, $src\t# vector (sve) $2" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ sve_not(as_FloatRegister($dst$$reg), __ elemType_to_regVariant(bt), + as_PRegister($pg$$reg), as_FloatRegister($src$$reg)); + %} + ins_pipe(pipe_slow); +%}')dnl +dnl $1, $2 +VECTOR_NOT_PREDICATE(I, B/H/S) +VECTOR_NOT_PREDICATE(L, D) +undefine(MATCH_RULE) +dnl // vector and_not dnl define(`MATCH_RULE', `ifelse($1, I, @@ -771,6 +797,32 @@ VECTOR_AND_NOT(I, B/H/S) VECTOR_AND_NOT(L, D) undefine(MATCH_RULE) dnl +// vector and_not - predicated +dnl +define(`MATCH_RULE', `ifelse($1, I, +`match(Set dst_src1 (AndV (Binary dst_src1 (XorV src2 (ReplicateB m1))) pg)); + match(Set dst_src1 (AndV (Binary dst_src1 (XorV src2 (ReplicateS m1))) pg)); + match(Set dst_src1 (AndV (Binary dst_src1 (XorV src2 (ReplicateI m1))) pg));', +`match(Set dst_src1 (AndV (Binary dst_src1 (XorV src2 (ReplicateL m1))) pg));')')dnl +dnl +define(`VECTOR_AND_NOT_PREDICATE', ` +instruct vand_not$1_masked`'(vReg dst_src1, vReg src2, imm$1_M1 m1, pRegGov pg) %{ + predicate(UseSVE > 0); + MATCH_RULE($1) + ins_cost(SVE_COST); + format %{ "sve_bic $dst_src1, $pg, $dst_src1, $src2\t# vector (sve) $2" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ sve_bic(as_FloatRegister($dst_src1$$reg), __ elemType_to_regVariant(bt), + as_PRegister($pg$$reg), as_FloatRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%}')dnl +dnl $1, $2 +VECTOR_AND_NOT_PREDICATE(I, B/H/S) +VECTOR_AND_NOT_PREDICATE(L, D) +undefine(MATCH_RULE) +dnl dnl VDIVF($1, $2 , $3 ) dnl VDIVF(name_suffix, size, min_vec_len) define(`VDIVF', ` diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp index 3717756d9d9..9482c3a65c2 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp @@ -3045,6 +3045,7 @@ public: INSN(sve_and, 0b00000100, 0b011010000); // vector and INSN(sve_andv, 0b00000100, 0b011010001); // bitwise and reduction to scalar INSN(sve_asr, 0b00000100, 0b010000100); // vector arithmetic shift right + INSN(sve_bic, 0b00000100, 0b011011000); // vector bitwise clear INSN(sve_cnt, 0b00000100, 0b011010101); // count non-zero bits INSN(sve_cpy, 0b00000101, 0b100000100); // copy scalar to each active vector element INSN(sve_eor, 0b00000100, 0b011001000); // vector eor diff --git a/test/hotspot/gtest/aarch64/aarch64-asmtest.py b/test/hotspot/gtest/aarch64/aarch64-asmtest.py index d43733535ae..1bbcdbb103a 100644 --- a/test/hotspot/gtest/aarch64/aarch64-asmtest.py +++ b/test/hotspot/gtest/aarch64/aarch64-asmtest.py @@ -1792,6 +1792,7 @@ generate(SVEVectorOp, [["add", "ZZZ"], ["add", "ZPZ", "m", "dn"], ["and", "ZPZ", "m", "dn"], ["asr", "ZPZ", "m", "dn"], + ["bic", "ZPZ", "m", "dn"], ["cnt", "ZPZ", "m"], ["eor", "ZPZ", "m", "dn"], ["lsl", "ZPZ", "m", "dn"], diff --git a/test/hotspot/gtest/aarch64/asmtest.out.h b/test/hotspot/gtest/aarch64/asmtest.out.h index 4975cce511d..2dbb48d3d01 100644 --- a/test/hotspot/gtest/aarch64/asmtest.out.h +++ b/test/hotspot/gtest/aarch64/asmtest.out.h @@ -1078,53 +1078,54 @@ __ sve_add(z8, __ D, p5, z16); // add z8.d, p5/m, z8.d, z16.d __ sve_and(z15, __ S, p1, z4); // and z15.s, p1/m, z15.s, z4.s __ sve_asr(z8, __ B, p1, z29); // asr z8.b, p1/m, z8.b, z29.b - __ sve_cnt(z28, __ D, p4, z29); // cnt z28.d, p4/m, z29.d - __ sve_eor(z9, __ H, p3, z2); // eor z9.h, p3/m, z9.h, z2.h - __ sve_lsl(z28, __ B, p0, z7); // lsl z28.b, p0/m, z28.b, z7.b - __ sve_lsr(z26, __ H, p5, z17); // lsr z26.h, p5/m, z26.h, z17.h - __ sve_mul(z8, __ D, p4, z21); // mul z8.d, p4/m, z8.d, z21.d - __ sve_neg(z5, __ S, p5, z21); // neg z5.s, p5/m, z21.s - __ sve_not(z22, __ S, p4, z29); // not z22.s, p4/m, z29.s - __ sve_orr(z19, __ S, p0, z4); // orr z19.s, p0/m, z19.s, z4.s - __ sve_smax(z23, __ B, p1, z19); // smax z23.b, p1/m, z23.b, z19.b - __ sve_smin(z23, __ B, p6, z19); // smin z23.b, p6/m, z23.b, z19.b - __ sve_sub(z8, __ D, p2, z14); // sub z8.d, p2/m, z8.d, z14.d - __ sve_fabs(z17, __ S, p7, z21); // fabs z17.s, p7/m, z21.s - __ sve_fadd(z30, __ D, p0, z10); // fadd z30.d, p0/m, z30.d, z10.d - __ sve_fdiv(z12, __ S, p0, z9); // fdiv z12.s, p0/m, z12.s, z9.s - __ sve_fmax(z24, __ D, p4, z4); // fmax z24.d, p4/m, z24.d, z4.d - __ sve_fmin(z6, __ D, p2, z27); // fmin z6.d, p2/m, z6.d, z27.d - __ sve_fmul(z13, __ D, p4, z30); // fmul z13.d, p4/m, z13.d, z30.d - __ sve_fneg(z22, __ D, p5, z30); // fneg z22.d, p5/m, z30.d - __ sve_frintm(z9, __ S, p3, z19); // frintm z9.s, p3/m, z19.s - __ sve_frintn(z20, __ S, p7, z9); // frintn z20.s, p7/m, z9.s - __ sve_frintp(z13, __ S, p3, z19); // frintp z13.s, p3/m, z19.s - __ sve_fsqrt(z24, __ S, p2, z19); // fsqrt z24.s, p2/m, z19.s - __ sve_fsub(z17, __ S, p4, z16); // fsub z17.s, p4/m, z17.s, z16.s - __ sve_fmad(z0, __ S, p0, z11, z7); // fmad z0.s, p0/m, z11.s, z7.s - __ sve_fmla(z14, __ D, p4, z4, z15); // fmla z14.d, p4/m, z4.d, z15.d - __ sve_fmls(z5, __ D, p0, z10, z21); // fmls z5.d, p0/m, z10.d, z21.d - __ sve_fnmla(z3, __ D, p0, z9, z19); // fnmla z3.d, p0/m, z9.d, z19.d - __ sve_fnmls(z10, __ S, p6, z3, z19); // fnmls z10.s, p6/m, z3.s, z19.s - __ sve_mla(z23, __ H, p7, z13, z21); // mla z23.h, p7/m, z13.h, z21.h - __ sve_mls(z26, __ S, p3, z17, z30); // mls z26.s, p3/m, z17.s, z30.s - __ sve_and(z14, z2, z29); // and z14.d, z2.d, z29.d - __ sve_eor(z21, z20, z7); // eor z21.d, z20.d, z7.d - __ sve_orr(z2, z1, z26); // orr z2.d, z1.d, z26.d - __ sve_bic(z9, z16, z17); // bic z9.d, z16.d, z17.d - __ sve_uzp1(z0, __ D, z4, z2); // uzp1 z0.d, z4.d, z2.d - __ sve_uzp2(z14, __ S, z6, z11); // uzp2 z14.s, z6.s, z11.s + __ sve_bic(z28, __ D, p4, z29); // bic z28.d, p4/m, z28.d, z29.d + __ sve_cnt(z9, __ H, p3, z2); // cnt z9.h, p3/m, z2.h + __ sve_eor(z28, __ B, p0, z7); // eor z28.b, p0/m, z28.b, z7.b + __ sve_lsl(z26, __ H, p5, z17); // lsl z26.h, p5/m, z26.h, z17.h + __ sve_lsr(z8, __ D, p4, z21); // lsr z8.d, p4/m, z8.d, z21.d + __ sve_mul(z5, __ S, p5, z21); // mul z5.s, p5/m, z5.s, z21.s + __ sve_neg(z22, __ S, p4, z29); // neg z22.s, p4/m, z29.s + __ sve_not(z19, __ S, p0, z4); // not z19.s, p0/m, z4.s + __ sve_orr(z23, __ B, p1, z19); // orr z23.b, p1/m, z23.b, z19.b + __ sve_smax(z23, __ B, p6, z19); // smax z23.b, p6/m, z23.b, z19.b + __ sve_smin(z8, __ D, p2, z14); // smin z8.d, p2/m, z8.d, z14.d + __ sve_sub(z17, __ B, p7, z21); // sub z17.b, p7/m, z17.b, z21.b + __ sve_fabs(z30, __ D, p0, z10); // fabs z30.d, p0/m, z10.d + __ sve_fadd(z12, __ S, p0, z9); // fadd z12.s, p0/m, z12.s, z9.s + __ sve_fdiv(z24, __ D, p4, z4); // fdiv z24.d, p4/m, z24.d, z4.d + __ sve_fmax(z6, __ D, p2, z27); // fmax z6.d, p2/m, z6.d, z27.d + __ sve_fmin(z13, __ D, p4, z30); // fmin z13.d, p4/m, z13.d, z30.d + __ sve_fmul(z22, __ D, p5, z30); // fmul z22.d, p5/m, z22.d, z30.d + __ sve_fneg(z9, __ S, p3, z19); // fneg z9.s, p3/m, z19.s + __ sve_frintm(z20, __ S, p7, z9); // frintm z20.s, p7/m, z9.s + __ sve_frintn(z13, __ S, p3, z19); // frintn z13.s, p3/m, z19.s + __ sve_frintp(z24, __ S, p2, z19); // frintp z24.s, p2/m, z19.s + __ sve_fsqrt(z17, __ S, p4, z16); // fsqrt z17.s, p4/m, z16.s + __ sve_fsub(z0, __ S, p0, z11); // fsub z0.s, p0/m, z0.s, z11.s + __ sve_fmad(z15, __ S, p3, z15, z4); // fmad z15.s, p3/m, z15.s, z4.s + __ sve_fmla(z29, __ D, p1, z0, z10); // fmla z29.d, p1/m, z0.d, z10.d + __ sve_fmls(z26, __ D, p0, z0, z9); // fmls z26.d, p0/m, z0.d, z9.d + __ sve_fnmla(z28, __ D, p2, z24, z3); // fnmla z28.d, p2/m, z24.d, z3.d + __ sve_fnmls(z7, __ D, p6, z28, z13); // fnmls z7.d, p6/m, z28.d, z13.d + __ sve_mla(z10, __ D, p6, z12, z17); // mla z10.d, p6/m, z12.d, z17.d + __ sve_mls(z17, __ S, p3, z2, z29); // mls z17.s, p3/m, z2.s, z29.s + __ sve_and(z21, z20, z7); // and z21.d, z20.d, z7.d + __ sve_eor(z2, z1, z26); // eor z2.d, z1.d, z26.d + __ sve_orr(z9, z16, z17); // orr z9.d, z16.d, z17.d + __ sve_bic(z0, z4, z2); // bic z0.d, z4.d, z2.d + __ sve_uzp1(z14, __ S, z6, z11); // uzp1 z14.s, z6.s, z11.s + __ sve_uzp2(z14, __ H, z16, z29); // uzp2 z14.h, z16.h, z29.h // SVEReductionOp - __ sve_andv(v14, __ H, p4, z29); // andv h14, p4, z29.h - __ sve_orv(v3, __ H, p0, z22); // orv h3, p0, z22.h - __ sve_eorv(v3, __ B, p6, z27); // eorv b3, p6, z27.b - __ sve_smaxv(v19, __ D, p5, z7); // smaxv d19, p5, z7.d - __ sve_sminv(v21, __ H, p3, z5); // sminv h21, p3, z5.h - __ sve_fminv(v25, __ D, p1, z21); // fminv d25, p1, z21.d - __ sve_fmaxv(v17, __ S, p0, z3); // fmaxv s17, p0, z3.s - __ sve_fadda(v19, __ S, p3, z7); // fadda s19, p3, s19, z7.s - __ sve_uaddv(v14, __ H, p4, z17); // uaddv d14, p4, z17.h + __ sve_andv(v3, __ H, p0, z22); // andv h3, p0, z22.h + __ sve_orv(v3, __ B, p6, z27); // orv b3, p6, z27.b + __ sve_eorv(v19, __ D, p5, z7); // eorv d19, p5, z7.d + __ sve_smaxv(v21, __ H, p3, z5); // smaxv h21, p3, z5.h + __ sve_sminv(v25, __ S, p1, z21); // sminv s25, p1, z21.s + __ sve_fminv(v17, __ S, p0, z3); // fminv s17, p0, z3.s + __ sve_fmaxv(v19, __ S, p3, z7); // fmaxv s19, p3, z7.s + __ sve_fadda(v14, __ S, p4, z17); // fadda s14, p4, s14, z17.s + __ sve_uaddv(v13, __ D, p6, z17); // uaddv d13, p6, z17.d __ bind(forth); @@ -1143,30 +1144,30 @@ 0x9101a1a0, 0xb10a5cc8, 0xd10810aa, 0xf10fd061, 0x120cb166, 0x321764bc, 0x52174681, 0x720c0227, 0x9241018e, 0xb25a2969, 0xd278b411, 0xf26aad01, - 0x14000000, 0x17ffffd7, 0x140003a5, 0x94000000, - 0x97ffffd4, 0x940003a2, 0x3400000a, 0x34fffa2a, - 0x340073ea, 0x35000008, 0x35fff9c8, 0x35007388, - 0xb400000b, 0xb4fff96b, 0xb400732b, 0xb500001d, - 0xb5fff91d, 0xb50072dd, 0x10000013, 0x10fff8b3, - 0x10007273, 0x90000013, 0x36300016, 0x3637f836, - 0x363071f6, 0x3758000c, 0x375ff7cc, 0x3758718c, + 0x14000000, 0x17ffffd7, 0x140003a6, 0x94000000, + 0x97ffffd4, 0x940003a3, 0x3400000a, 0x34fffa2a, + 0x3400740a, 0x35000008, 0x35fff9c8, 0x350073a8, + 0xb400000b, 0xb4fff96b, 0xb400734b, 0xb500001d, + 0xb5fff91d, 0xb50072fd, 0x10000013, 0x10fff8b3, + 0x10007293, 0x90000013, 0x36300016, 0x3637f836, + 0x36307216, 0x3758000c, 0x375ff7cc, 0x375871ac, 0x128313a0, 0x528a32c7, 0x7289173b, 0x92ab3acc, 0xd2a0bf94, 0xf2c285e8, 0x9358722f, 0x330e652f, 0x53067f3b, 0x93577c53, 0xb34a1aac, 0xd35a4016, 0x13946c63, 0x93c3dbc8, 0x54000000, 0x54fff5a0, - 0x54006f60, 0x54000001, 0x54fff541, 0x54006f01, - 0x54000002, 0x54fff4e2, 0x54006ea2, 0x54000002, - 0x54fff482, 0x54006e42, 0x54000003, 0x54fff423, - 0x54006de3, 0x54000003, 0x54fff3c3, 0x54006d83, - 0x54000004, 0x54fff364, 0x54006d24, 0x54000005, - 0x54fff305, 0x54006cc5, 0x54000006, 0x54fff2a6, - 0x54006c66, 0x54000007, 0x54fff247, 0x54006c07, - 0x54000008, 0x54fff1e8, 0x54006ba8, 0x54000009, - 0x54fff189, 0x54006b49, 0x5400000a, 0x54fff12a, - 0x54006aea, 0x5400000b, 0x54fff0cb, 0x54006a8b, - 0x5400000c, 0x54fff06c, 0x54006a2c, 0x5400000d, - 0x54fff00d, 0x540069cd, 0x5400000e, 0x54ffefae, - 0x5400696e, 0x5400000f, 0x54ffef4f, 0x5400690f, + 0x54006f80, 0x54000001, 0x54fff541, 0x54006f21, + 0x54000002, 0x54fff4e2, 0x54006ec2, 0x54000002, + 0x54fff482, 0x54006e62, 0x54000003, 0x54fff423, + 0x54006e03, 0x54000003, 0x54fff3c3, 0x54006da3, + 0x54000004, 0x54fff364, 0x54006d44, 0x54000005, + 0x54fff305, 0x54006ce5, 0x54000006, 0x54fff2a6, + 0x54006c86, 0x54000007, 0x54fff247, 0x54006c27, + 0x54000008, 0x54fff1e8, 0x54006bc8, 0x54000009, + 0x54fff189, 0x54006b69, 0x5400000a, 0x54fff12a, + 0x54006b0a, 0x5400000b, 0x54fff0cb, 0x54006aab, + 0x5400000c, 0x54fff06c, 0x54006a4c, 0x5400000d, + 0x54fff00d, 0x540069ed, 0x5400000e, 0x54ffefae, + 0x5400698e, 0x5400000f, 0x54ffef4f, 0x5400692f, 0xd40658e1, 0xd4014d22, 0xd4046543, 0xd4273f60, 0xd44cad80, 0xd503201f, 0xd69f03e0, 0xd6bf03e0, 0xd5033fdf, 0xd5033e9f, 0xd50332bf, 0xd61f0200, @@ -1198,7 +1199,7 @@ 0x791f226d, 0xf95aa2f3, 0xb9587bb7, 0x395f7176, 0x795d9143, 0x399e7e08, 0x799a2697, 0x79df3422, 0xb99c2624, 0xfd5c2374, 0xbd5fa1d9, 0xfd1d595a, - 0xbd1b1869, 0x5800595b, 0x1800000b, 0xf8945060, + 0xbd1b1869, 0x5800597b, 0x1800000b, 0xf8945060, 0xd8000000, 0xf8ae6ba0, 0xf99a0080, 0x1a070035, 0x3a0700a8, 0x5a0e0367, 0x7a11009b, 0x9a000380, 0xba1e030c, 0xda0f0320, 0xfa030301, 0x0b340b11, @@ -1365,17 +1366,18 @@ 0x25a0c6cd, 0x2521cf00, 0x0583c5b1, 0x05407336, 0x05001e62, 0x04e400f4, 0x04a80407, 0x65c402d3, 0x65cb0ac9, 0x659007c5, 0x0456ac36, 0x04c01608, - 0x049a048f, 0x041087a8, 0x04dab3bc, 0x04590c49, - 0x041380fc, 0x0451963a, 0x04d012a8, 0x0497b6a5, - 0x049eb3b6, 0x04980093, 0x04080677, 0x040a1a77, - 0x04c109c8, 0x049cbeb1, 0x65c0815e, 0x658d812c, - 0x65c69098, 0x65c78b66, 0x65c293cd, 0x04ddb7d6, - 0x6582ae69, 0x6580bd34, 0x6581ae6d, 0x658daa78, - 0x65819211, 0x65a78160, 0x65ef108e, 0x65f52145, - 0x65f34123, 0x65b3786a, 0x04555db7, 0x049e6e3a, - 0x043d304e, 0x04a73295, 0x047a3022, 0x04f13209, - 0x05e26880, 0x05ab6cce, 0x045a33ae, 0x045822c3, - 0x04193b63, 0x04c834f3, 0x044a2cb5, 0x65c726b9, - 0x65862071, 0x65982cf3, 0x0441322e, + 0x049a048f, 0x041087a8, 0x04db13bc, 0x045aac49, + 0x041900fc, 0x0453963a, 0x04d192a8, 0x049016a5, + 0x0497b3b6, 0x049ea093, 0x04180677, 0x04081a77, + 0x04ca09c8, 0x04011eb1, 0x04dca15e, 0x6580812c, + 0x65cd9098, 0x65c68b66, 0x65c793cd, 0x65c297d6, + 0x049dae69, 0x6582bd34, 0x6580ae6d, 0x6581aa78, + 0x658db211, 0x65818160, 0x65a48def, 0x65ea041d, + 0x65e9201a, 0x65e34b1c, 0x65ed7b87, 0x04d1598a, + 0x049d6c51, 0x04273295, 0x04ba3022, 0x04713209, + 0x04e23080, 0x05ab68ce, 0x057d6e0e, 0x045a22c3, + 0x04183b63, 0x04d934f3, 0x04482cb5, 0x048a26b9, + 0x65872071, 0x65862cf3, 0x6598322e, 0x04c13a2d, + }; // END Generated code -- do not edit -- GitLab From 1864481df10d2f616cbfdecebf3bebbae04de5e1 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Thu, 17 Feb 2022 06:40:46 +0000 Subject: [PATCH 107/203] 8279969: NULL return from map_bitmap_region() needs to be checked Reviewed-by: ccheung, coleenp --- src/hotspot/share/cds/filemap.cpp | 13 ++++++++++--- src/hotspot/share/cds/heapShared.cpp | 4 ++++ .../cds/appcds/SharedArchiveConsistency.java | 8 ++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index 63ba7fb2893..69ab7430e16 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -2168,6 +2168,15 @@ void FileMapInfo::map_heap_regions_impl() { assert(is_aligned(relocated_closed_heap_region_bottom, HeapRegion::GrainBytes), "must be"); + if (_heap_pointers_need_patching) { + char* bitmap_base = map_bitmap_region(); + if (bitmap_base == NULL) { + log_info(cds)("CDS heap cannot be used because bitmap region cannot be mapped"); + _heap_pointers_need_patching = false; + return; + } + } + // Map the closed heap regions: GC does not write into these regions. if (map_heap_regions(MetaspaceShared::first_closed_heap_region, MetaspaceShared::max_num_closed_heap_regions, @@ -2297,9 +2306,7 @@ void FileMapInfo::patch_heap_embedded_pointers() { void FileMapInfo::patch_heap_embedded_pointers(MemRegion* regions, int num_regions, int first_region_idx) { char* bitmap_base = map_bitmap_region(); - if (bitmap_base == NULL) { - return; - } + assert(bitmap_base != NULL, "must have already been mapped"); for (int i=0; imap_bitmap_region(); + if (bitmap_base == 0) { + _loading_failed = true; + return false; // OOM or CRC error + } uintptr_t load_address = buffer; for (int i = 0; i < num_loaded_regions; i++) { LoadedArchiveHeapRegion* ri = &loaded_regions[i]; diff --git a/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java b/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java index fd0291f06e0..cec5b66a12f 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java @@ -80,6 +80,14 @@ public class SharedArchiveConsistency { OutputAnalyzer output = shareAuto ? TestCommon.execAuto(execArgs) : TestCommon.execCommon(execArgs); String stdtxt = output.getOutput(); System.out.println("Note: this test may fail in very rare occasions due to CRC32 checksum collision"); + for (String opt : execArgs) { + if (opt.equals("-XX:+VerifySharedSpaces")) { + // If VerifySharedSpaces is enabled, the VM should never crash even if the archive + // is corrupted (unless if we are so lucky that the corrupted archive ends up + // have the same checksum as recoreded in the header) + output.shouldNotContain("A fatal error has been detected by the Java Runtime Environment"); + } + } for (String message : matchMessages) { if (stdtxt.contains(message)) { // match any to return -- GitLab From c0275e18b7cb4a01385b79ced46560322aeacc97 Mon Sep 17 00:00:00 2001 From: Tyler Steele Date: Thu, 17 Feb 2022 08:49:22 +0000 Subject: [PATCH 108/203] 8203290: [AIX] Check functionality of JDK-8199712 (Flight Recorder) Implements JFR for AIX Reviewed-by: erikj, mdoerr, mgronlun, stuefe, ihse --- make/autoconf/jvm-features.m4 | 23 - src/hotspot/os/aix/libperfstat_aix.cpp | 61 +- src/hotspot/os/aix/libperfstat_aix.hpp | 153 ++- src/hotspot/os/aix/loadlib_aix.cpp | 178 ++-- src/hotspot/os/aix/loadlib_aix.hpp | 12 + src/hotspot/os/aix/os_aix.cpp | 8 +- src/hotspot/os/aix/os_perf_aix.cpp | 982 ++++++------------ src/hotspot/os_cpu/aix_ppc/thread_aix_ppc.cpp | 73 +- test/jdk/ProblemList.txt | 2 +- .../runtime/TestNativeLibrariesEvent.java | 5 +- 10 files changed, 728 insertions(+), 769 deletions(-) diff --git a/make/autoconf/jvm-features.m4 b/make/autoconf/jvm-features.m4 index 70457149edc..8dfc0d362b9 100644 --- a/make/autoconf/jvm-features.m4 +++ b/make/autoconf/jvm-features.m4 @@ -264,22 +264,6 @@ AC_DEFUN_ONCE([JVM_FEATURES_CHECK_DTRACE], ]) ]) -############################################################################### -# Check if the feature 'jfr' is available on this platform. -# -AC_DEFUN_ONCE([JVM_FEATURES_CHECK_JFR], -[ - JVM_FEATURES_CHECK_AVAILABILITY(jfr, [ - AC_MSG_CHECKING([if platform is supported by JFR]) - if test "x$OPENJDK_TARGET_OS" = xaix; then - AC_MSG_RESULT([no, $OPENJDK_TARGET_OS-$OPENJDK_TARGET_CPU]) - AVAILABLE=false - else - AC_MSG_RESULT([yes]) - fi - ]) -]) - ############################################################################### # Check if the feature 'jvmci' is available on this platform. # @@ -399,18 +383,11 @@ AC_DEFUN_ONCE([JVM_FEATURES_PREPARE_PLATFORM], JVM_FEATURES_CHECK_CDS JVM_FEATURES_CHECK_DTRACE - JVM_FEATURES_CHECK_JFR JVM_FEATURES_CHECK_JVMCI JVM_FEATURES_CHECK_SHENANDOAHGC JVM_FEATURES_CHECK_STATIC_BUILD JVM_FEATURES_CHECK_ZGC - # Filter out features by default for all variants on certain platforms. - # Make sure to just add to JVM_FEATURES_PLATFORM_FILTER, since it could - # have a value already from custom extensions. - if test "x$OPENJDK_TARGET_OS" = xaix; then - JVM_FEATURES_PLATFORM_FILTER="$JVM_FEATURES_PLATFORM_FILTER jfr" - fi ]) ############################################################################### diff --git a/src/hotspot/os/aix/libperfstat_aix.cpp b/src/hotspot/os/aix/libperfstat_aix.cpp index 65a937ef261..cec0ac1d287 100644 --- a/src/hotspot/os/aix/libperfstat_aix.cpp +++ b/src/hotspot/os/aix/libperfstat_aix.cpp @@ -1,5 +1,7 @@ /* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2018 SAP SE. All rights reserved. + * Copyright (c) 2022, IBM Corp. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,12 +32,22 @@ // Handle to the libperfstat. static void* g_libhandle = NULL; +typedef int (*fun_perfstat_cpu_t) (perfstat_id_t *name, PERFSTAT_CPU_T_LATEST* userbuff, + int sizeof_userbuff, int desired_number); + typedef int (*fun_perfstat_cpu_total_t) (perfstat_id_t *name, PERFSTAT_CPU_TOTAL_T_LATEST* userbuff, int sizeof_userbuff, int desired_number); typedef int (*fun_perfstat_memory_total_t) (perfstat_id_t *name, perfstat_memory_total_t* userbuff, int sizeof_userbuff, int desired_number); +typedef int (*fun_perfstat_netinterface_t) (perfstat_id_t *name, perfstat_netinterface_t* userbuff, + int sizeof_userbuff, int desired_number); + +typedef int (*fun_perfstat_process_t) (perfstat_id_t *name, + PERFSTAT_PROCESS_T_LATEST* userbuff, int sizeof_userbuff, + int desired_number); + typedef int (*fun_perfstat_partition_total_t) (perfstat_id_t *name, PERFSTAT_PARTITON_TOTAL_T_LATEST* userbuff, int sizeof_userbuff, int desired_number); @@ -48,12 +60,15 @@ typedef void (*fun_perfstat_reset_t) (); typedef cid_t (*fun_wpar_getcid_t) (); -static fun_perfstat_cpu_total_t g_fun_perfstat_cpu_total = NULL; -static fun_perfstat_memory_total_t g_fun_perfstat_memory_total = NULL; +static fun_perfstat_cpu_total_t g_fun_perfstat_cpu_total = NULL; +static fun_perfstat_cpu_t g_fun_perfstat_cpu = NULL; +static fun_perfstat_memory_total_t g_fun_perfstat_memory_total = NULL; +static fun_perfstat_netinterface_t g_fun_perfstat_netinterface = NULL; static fun_perfstat_partition_total_t g_fun_perfstat_partition_total = NULL; -static fun_perfstat_wpar_total_t g_fun_perfstat_wpar_total = NULL; -static fun_perfstat_reset_t g_fun_perfstat_reset = NULL; -static fun_wpar_getcid_t g_fun_wpar_getcid = NULL; +static fun_perfstat_process_t g_fun_perfstat_process = NULL; +static fun_perfstat_wpar_total_t g_fun_perfstat_wpar_total = NULL; +static fun_perfstat_reset_t g_fun_perfstat_reset = NULL; +static fun_wpar_getcid_t g_fun_wpar_getcid = NULL; bool libperfstat::init() { @@ -84,7 +99,10 @@ bool libperfstat::init() { // These functions are required for every release. RESOLVE_FUN(perfstat_cpu_total); + RESOLVE_FUN(perfstat_cpu); RESOLVE_FUN(perfstat_memory_total); + RESOLVE_FUN(perfstat_netinterface); + RESOLVE_FUN(perfstat_process); RESOLVE_FUN(perfstat_reset); trcVerbose("libperfstat loaded."); @@ -108,6 +126,22 @@ void libperfstat::cleanup() { } +int libperfstat::perfstat_cpu_total(perfstat_id_t *name, PERFSTAT_CPU_TOTAL_T_LATEST* userbuff, + int sizeof_userbuff, int desired_number) { + if (g_fun_perfstat_cpu_total == NULL) { + return -1; + } + return g_fun_perfstat_cpu_total(name, userbuff, sizeof_userbuff, desired_number); +} + +int libperfstat::perfstat_cpu(perfstat_id_t *name, PERFSTAT_CPU_T_LATEST* userbuff, + int sizeof_userbuff, int desired_number) { + if (g_fun_perfstat_cpu == NULL) { + return -1; + } + return g_fun_perfstat_cpu(name, userbuff, sizeof_userbuff, desired_number); +} + int libperfstat::perfstat_memory_total(perfstat_id_t *name, perfstat_memory_total_t* userbuff, int sizeof_userbuff, int desired_number) { @@ -117,12 +151,13 @@ int libperfstat::perfstat_memory_total(perfstat_id_t *name, return g_fun_perfstat_memory_total(name, userbuff, sizeof_userbuff, desired_number); } -int libperfstat::perfstat_cpu_total(perfstat_id_t *name, PERFSTAT_CPU_TOTAL_T_LATEST* userbuff, - int sizeof_userbuff, int desired_number) { - if (g_fun_perfstat_cpu_total == NULL) { +int libperfstat::perfstat_netinterface(perfstat_id_t *name, + perfstat_netinterface_t* userbuff, + int sizeof_userbuff, int desired_number) { + if (g_fun_perfstat_netinterface == NULL) { return -1; } - return g_fun_perfstat_cpu_total(name, userbuff, sizeof_userbuff, desired_number); + return g_fun_perfstat_netinterface(name, userbuff, sizeof_userbuff, desired_number); } int libperfstat::perfstat_partition_total(perfstat_id_t *name, PERFSTAT_PARTITON_TOTAL_T_LATEST* userbuff, @@ -133,6 +168,14 @@ int libperfstat::perfstat_partition_total(perfstat_id_t *name, PERFSTAT_PARTITON return g_fun_perfstat_partition_total(name, userbuff, sizeof_userbuff, desired_number); } +int libperfstat::perfstat_process(perfstat_id_t *name, perfstat_process_t* userbuff, + int sizeof_userbuff, int desired_number) { + if (g_fun_perfstat_process == NULL) { + return -1; + } + return g_fun_perfstat_process(name, userbuff, sizeof_userbuff, desired_number); +} + int libperfstat::perfstat_wpar_total(perfstat_id_wpar_t *name, PERFSTAT_WPAR_TOTAL_T_LATEST* userbuff, int sizeof_userbuff, int desired_number) { if (g_fun_perfstat_wpar_total == NULL) { diff --git a/src/hotspot/os/aix/libperfstat_aix.hpp b/src/hotspot/os/aix/libperfstat_aix.hpp index d323b8e8bbc..30f08c57a03 100644 --- a/src/hotspot/os/aix/libperfstat_aix.hpp +++ b/src/hotspot/os/aix/libperfstat_aix.hpp @@ -1,5 +1,7 @@ /* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2018 SAP SE. All rights reserved. + * Copyright (c) 2022, IBM Corp. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +49,9 @@ // work without recompilation on all newer AIX versions. // -#define IDENTIFIER_LENGTH 64 /* length of strings included in the structures */ +#define IDENTIFIER_LENGTH 64 /* length of strings included in the structures */ +#define FIRST_CPU "" /* pseudo-name for fist CPU */ +#define FIRST_NETINTERFACE "" /* pseudo-name for first NETINTERFACE */ typedef struct { /* structure element identifier */ @@ -439,6 +443,102 @@ typedef struct { /* global cpu information AIX 7.2 / 6.1 TL6 (see oslevel -r) * * of perfstat_cpu_total_t data structure */ } perfstat_cpu_total_t_72; +typedef struct { /* component perfstat_cpu_t from AIX 7.2 documentation */ + char name [IDENTIFIER_LENGTH]; /* Logical processor name (processor0, processor1,.). */ + ulong_t state; /* Specifies whether the CPU is offline or online. + * (NOTE: The type of 'state' is not specified in the documentation, but + * ulong_t is the correct length) */ + u_longlong_t user; /* Raw number of clock ticks spent in user mode. */ + u_longlong_t sys; /* Raw number of clock ticks spent in system mode. */ + u_longlong_t idle; /* Raw number of clock ticks spent idle. */ + u_longlong_t wait; /* Raw number of clock ticks spent waiting for I/O. */ + u_longlong_t pswitch; /* Number of context switches (changes of currently running process). */ + u_longlong_t syscall; /* Number of system calls executed. */ + u_longlong_t sysread; /* Number of read system calls executed. */ + u_longlong_t syswrite; /* Number of write system calls executed. */ + u_longlong_t sysfork; /* Number of fork system call executed. */ + u_longlong_t sysexec; /* Number of exec system call executed. */ + u_longlong_t readch; /* Number of characters transferred with read system call. */ + u_longlong_t writech; /* Number of characters transferred with write system call. */ + u_longlong_t bread; /* Number of block reads. */ + u_longlong_t bwrite; /* Number of block writes. */ + u_longlong_t lread; /* Number of logical read requests. */ + u_longlong_t lwrite; /* Number of logical write requests. */ + u_longlong_t phread; /* Number of physical reads (reads on raw device). */ + u_longlong_t phwrite; /* Number of physical writes (writes on raw device). */ + u_longlong_t iget; /* Number of inode lookups. */ + u_longlong_t namei; /* Number of vnode lookup from a path name. */ + u_longlong_t dirblk; /* Number of 512-byte blocks reads by the directory search routine to locate an entry for a file. */ + u_longlong_t msg; /* Number of interprocess communication (IPC) message operations. */ + u_longlong_t sema; /* Number of IPC semaphore operations. */ + u_longlong_t minfaults; /* Number of page faults with no I/O. */ + u_longlong_t majfaults; /* Number of page faults with disk I/O. */ + u_longlong_t puser; /* Raw number of physical processor ticks in user mode. */ + u_longlong_t psys; /* Raw number of physical processor ticks in system mode. */ + u_longlong_t pidle; /* Raw number of physical processor ticks idle. */ + u_longlong_t pwait; /* Raw number of physical processor ticks waiting for I/O. */ + u_longlong_t redisp_sd0; /* Number of thread redispatches within the scheduler affinity domain 0. */ + u_longlong_t redisp_sd1; /* Number of thread redispatches within the scheduler affinity domain 1. */ + u_longlong_t redisp_sd2; /* Number of thread redispatches within the scheduler affinity domain 2. */ + u_longlong_t redisp_sd3; /* Number of thread redispatches within the scheduler affinity domain 3. */ + u_longlong_t redisp_sd4; /* Number of thread redispatches within the scheduler affinity domain 4. */ + u_longlong_t redisp_sd5; /* Number of thread redispatches within the scheduler affinity domain 5. */ + u_longlong_t migration_push; /* Number of thread migrations from the local runque to another queue due to starvation load balancing. */ + u_longlong_t migration_S3grq; /* Number of thread migrations from the global runque to the local runque resulting in a move across scheduling domain 3. */ + u_longlong_t migration_S3pull; /* Number of thread migrations from another processor's runque resulting in a move across scheduling domain 3. */ + u_longlong_t invol_cswitch; /* Number of involuntary thread context switches. */ + u_longlong_t vol_cswitch; /* Number of voluntary thread context switches. */ + u_longlong_t runque; /* Number of threads on the runque. */ + u_longlong_t bound; /* Number of bound threads. */ + u_longlong_t decrintrs; /* Number of decrementer interrupts. */ + u_longlong_t mpcrintrs; /* Number of received interrupts for MPC. */ + u_longlong_t mpcsintrs; /* Number of sent interrupts for MPC. */ + u_longlong_t devintrs; /* Number of device interrupts. */ + u_longlong_t softintrs; /* Number of offlevel handlers called. */ + u_longlong_t phantintrs; /* Number of phantom interrupts. */ + u_longlong_t idle_donated_purr; /* Number of idle cycles donated by a dedicated partition enabled for donation. */ + u_longlong_t idle_donated_spurr; /* Number of idle spurr cycles donated by a dedicated partition enabled for donation. */ + u_longlong_t busy_donated_purr; /* Number of busy cycles donated by a dedicated partition enabled for donation. */ + u_longlong_t busy_donated_spurr; /* Number of busy spurr cycles donated by a dedicated partition enabled for donation. */ + u_longlong_t idle_stolen_purr; /* Number of idle cycles stolen by the hypervisor from a dedicated partition. */ + u_longlong_t idle_stolen_spurr; /* Number of idle spurr cycles stolen by the hypervisor from a dedicated partition. */ + u_longlong_t busy_stolen_purr; /* Number of busy cycles stolen by the hypervisor from a dedicated partition. */ + u_longlong_t busy_stolen_spurr; /* Number of busy spurr cycles stolen by the hypervisor from a dedicated partition.*/ + u_longlong_t shcpus_in_sys; /* Number of physical processors allocated for shared processor use, across all shared processors pools. */ + u_longlong_t entitled_pool_capacity; /* Entitled processor capacity of partition’s pool. */ + u_longlong_t pool_max_time; /* Summation of maximum time that can be consumed by the pool (nanoseconds). */ + u_longlong_t pool_busy_time; /* Summation of busy (nonidle) time accumulated across all partitions in the pool (nanoseconds). */ + u_longlong_t pool_scaled_busy_time; /* Scaled summation of busy (nonidle) time accumulated across all partitions in the pool (nanoseconds). */ + u_longlong_t shcpu_tot_time; /* Summation of total time across all physical processors allocated for shared processor use (nanoseconds). */ + u_longlong_t shcpu_busy_time; /* Summation of busy (nonidle) time accumulated across all shared processor partitions (nanoseconds). */ + u_longlong_t shcpu_scaled_busy_time; /* Scaled summation of busy time accumulated across all shared processor partitions (nanoseconds). */ + int ams_pool_id; /* AMS pool ID of the pool the LPAR belongs to. */ + int var_mem_weight; /* Variable memory capacity weight. */ + u_longlong_t iome; /* I/O memory entitlement of the partition in bytes. */ + u_longlong_t pmem; /* Physical memory currently backing the partition's logical memory in bytes. */ + u_longlong_t hpi; /* Number of hypervisor page-ins. */ + u_longlong_t hpit; /* Time spent in hypervisor page-ins (in nanoseconds). */ + u_longlong_t hypv_pagesize; /* Hypervisor page size in KB. */ + uint online_lcpus; /* Number of online logical processors. */ + uint smt_thrds; /* Number of SMT threads. */ +} perfstat_cpu_t; + +typedef struct { + char name[IDENTIFIER_LENGTH]; /* Name of the interface. */ + char description[IDENTIFIER_LENGTH]; /* Interface description (from ODM, similar to lscfg output). */ + uchar type; /* Ethernet, token ring, and so on. Interpretation can be done using the /usr/include/net/if_types.h file. */ + u_longlong_t mtu; /* Network frame size. */ + u_longlong_t ipacets; /* Number of packets received on interface. */ + u_longlong_t ibytes; /* Number of bytes received on interface. */ + u_longlong_t ierrors; /* Number of input errors on interface. */ + u_longlong_t opackets; /* Number of packets sent on interface. */ + u_longlong_t obytes; /* Number of bytes sent on interface. */ + u_longlong_t oerrors; /* Number of output errors on interface. */ + u_longlong_t collisions; /* Number of collisions on csma interface. */ + u_longlong_t bitrate; /* Adapter rating in bit per second. */ + u_longlong_t if_iqdrops; /* Dropped on input, this interface. */ + u_longlong_t if_arpdrops; /* Dropped because no arp response. */ +} perfstat_netinterface_t; typedef union { uint w; @@ -797,6 +897,38 @@ typedef struct { /* partition total information AIX 7.1 >= TL1*/ * of perfstat_partition_total_t data structure */ } perfstat_partition_total_t_71_1; +typedef struct { + u_longlong_t version; /* Version number of the data structure. */ + u_longlong_t pid; /* Process ID. */ + char proc_name[64]; /* Name of the process. */ + int proc_priority; /* Process priority. */ + u_longlong_t num_threads; /* Thread count. */ + u_longlong_t proc_uid; /* Owner information. */ + u_longlong_t proc_classid; /* WLM class name. */ + u_longlong_t proc_size; /* Virtual size of the process (exclusive usage, leaving all shared library text & shared file pages, shared memory, and memory mapped). */ + u_longlong_t proc_real_mem_data; /* Real memory used for data in KB. */ + u_longlong_t proc_real_mem_text; /* Real memory used for text in KB. */ + u_longlong_t proc_virt_mem_data; /* Virtual memory used for data in KB. */ + u_longlong_t proc_virt_mem_text; /* Virtual memory used for text in KB. */ + u_longlong_t shared_lib_data_size; /* Data size from shared library in KB. */ + u_longlong_t heap_size; /* Heap size in KB. */ + u_longlong_t real_inuse; /* The Real memory (in KB) in use by the process including all kind of segments (excluding system segments). This includes text, data, shared library text, shared library data, file pages, shared memory, and memory mapped. */ + u_longlong_t virt_inuse; /* The virtual memory (in KB) in use by the process including all kind of segments (excluding system segments). This includes text, data, shared library text, shared library data, file pages, shared memory, and memory mapped. */ + u_longlong_t pinned; /* Pinned memory (in KB) for this process inclusive of all segments. */ + u_longlong_t pgsp_inuse; /* Paging space used (in KB) inclusive of all segments. */ + u_longlong_t filepages; /* File pages used (in KB) including shared pages. */ + u_longlong_t real_inuse_map; /* Real memory used (in KB) for shared memory and memory mapped regions */ + u_longlong_t virt_inuse_map; /* Virtual memory used (in KB) for shared memory and memory mapped regions. */ + u_longlong_t pinned_inuse_map; /* Pinned memory used (in KB) for shared memory and memory mapped regions. */ + double ucpu_time; /* User mode CPU time is in percentage or milliseconds, which is based on, whether it is filled by perfstat_process_util or perfstat_process respectively. */ + double scpu_time; /* System mode CPU time is in percentage or milliseconds, which is based on whether it is filled by perfstat_process_util or perfstat_process respectively. */ + u_longlong_t last_timebase; /* Timebase counter. */ + u_longlong_t inBytes; /* Bytes written to disk. */ + u_longlong_t outBytes; /* Bytes read from disk. */ + u_longlong_t inOps; /* In operations from disk. */ + u_longlong_t outOps; /* Out operations from disk */ +} perfstat_process_t; + typedef union { /* WPAR Type & Flags */ uint w; struct { @@ -854,9 +986,14 @@ typedef struct { /* WPAR identifier */ // end: libperfstat.h (AIX 5.2, 5.3, 6.1, 7.1) ////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#define PERFSTAT_PARTITON_TOTAL_T_LATEST perfstat_partition_total_t_71_1/* latest perfstat_partition_total_t structure */ -#define PERFSTAT_CPU_TOTAL_T_LATEST perfstat_cpu_total_t_72 /* latest perfstat_cpu_total_t structure */ -#define PERFSTAT_WPAR_TOTAL_T_LATEST perfstat_wpar_total_t_71 /* latest perfstat_wpar_total_t structure */ +#define PERFSTAT_PARTITON_TOTAL_T_LATEST perfstat_partition_total_t_71_1 /* latest perfstat_partition_total_t structure */ +#define PERFSTAT_PROCESS_T_LATEST perfstat_process_t /* latest perfstat_process_t structure */ +#define PERFSTAT_CPU_TOTAL_T_LATEST perfstat_cpu_total_t_72 /* latest perfstat_cpu_total_t structure */ +#define PERFSTAT_CPU_T_LATEST perfstat_cpu_t /* latest perfstat_cpu_t structure */ +#define PERFSTAT_NETINTERFACE_T_LATEST perfstat_netinterface_t /* latest perfstat_netinterface_t structure */ +#define PERFSTAT_WPAR_TOTAL_T_LATEST perfstat_wpar_total_t_71 /* latest perfstat_wpar_total_t structure */ + +typedef PERFSTAT_CPU_TOTAL_T_LATEST perfstat_cpu_total_t; class libperfstat { @@ -886,6 +1023,14 @@ public: static cid_t wpar_getcid(); + static int perfstat_cpu(perfstat_id_t *name, PERFSTAT_CPU_T_LATEST* userbuff, + int sizeof_userbuff, int desired_number); + + static int perfstat_process(perfstat_id_t *name, PERFSTAT_PROCESS_T_LATEST* userbuff, + int sizeof_userbuff, int desired_number); + + static int perfstat_netinterface(perfstat_id_t *name, PERFSTAT_NETINTERFACE_T_LATEST* userbuff, + int sizeof_userbuff, int desired_number); //////////////////////////////////////////////////////////////// // The convenience functions get_partitioninfo(), get_cpuinfo(), get_wparinfo() return diff --git a/src/hotspot/os/aix/loadlib_aix.cpp b/src/hotspot/os/aix/loadlib_aix.cpp index 9ac761f6212..a111e0199fa 100644 --- a/src/hotspot/os/aix/loadlib_aix.cpp +++ b/src/hotspot/os/aix/loadlib_aix.cpp @@ -1,6 +1,7 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2019 SAP SE. All rights reserved. + * Copyright (c) 2022, IBM Corp. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -110,13 +111,7 @@ static StringList g_stringlist; // eternal - this list is rebuilt on every reload. // Note that we do not hand out those entries, but copies of them. -struct entry_t { - entry_t* next; - loaded_module_t info; -}; - -static void print_entry(const entry_t* e, outputStream* os) { - const loaded_module_t* const lm = &(e->info); +static void print_entry(const loaded_module_t* lm, outputStream* os) { os->print(" %c text: " INTPTR_FORMAT " - " INTPTR_FORMAT ", data: " INTPTR_FORMAT " - " INTPTR_FORMAT " " "%s", @@ -129,50 +124,50 @@ static void print_entry(const entry_t* e, outputStream* os) { } } -static entry_t* g_first = NULL; +static loaded_module_t* g_first = NULL; -static entry_t* find_entry_for_text_address(const void* p) { - for (entry_t* e = g_first; e; e = e->next) { - if ((uintptr_t)p >= (uintptr_t)e->info.text && - (uintptr_t)p < ((uintptr_t)e->info.text + e->info.text_len)) { - return e; +static loaded_module_t* find_entry_for_text_address(const void* p) { + for (loaded_module_t* lm = g_first; lm; lm = lm->next) { + if ((uintptr_t)p >= (uintptr_t)lm->text && + (uintptr_t)p < ((uintptr_t)lm->text + lm->text_len)) { + return lm; } } return NULL; } -static entry_t* find_entry_for_data_address(const void* p) { - for (entry_t* e = g_first; e; e = e->next) { - if ((uintptr_t)p >= (uintptr_t)e->info.data && - (uintptr_t)p < ((uintptr_t)e->info.data + e->info.data_len)) { - return e; +static loaded_module_t* find_entry_for_data_address(const void* p) { + for (loaded_module_t* lm = g_first; lm; lm = lm->next) { + if ((uintptr_t)p >= (uintptr_t)lm->data && + (uintptr_t)p < ((uintptr_t)lm->data + lm->data_len)) { + return lm; } } return NULL; } // Adds a new entry to the list (ordered by text address ascending). -static void add_entry_to_list(entry_t* e, entry_t** start) { - entry_t* last = NULL; - entry_t* e2 = *start; - while (e2 && e2->info.text < e->info.text) { - last = e2; - e2 = e2->next; +static void add_entry_to_list(loaded_module_t* lm, loaded_module_t** start) { + loaded_module_t* last = NULL; + loaded_module_t* lm2 = *start; + while (lm2 && lm2->text < lm->text) { + last = lm2; + lm2 = lm2->next; } if (last) { - last->next = e; + last->next = lm; } else { - *start = e; + *start = lm; } - e->next = e2; + lm->next = lm2; } -static void free_entry_list(entry_t** start) { - entry_t* e = *start; - while (e) { - entry_t* const e2 = e->next; - ::free(e); - e = e2; +static void free_entry_list(loaded_module_t** start) { + loaded_module_t* lm = *start; + while (lm) { + loaded_module_t* const lm2 = lm->next; + ::free(lm); + lm = lm2; } *start = NULL; } @@ -186,7 +181,7 @@ static bool reload_table() { trcVerbose("reload module table..."); - entry_t* new_list = NULL; + loaded_module_t* new_list = NULL; const struct ld_info* ldi = NULL; // Call loadquery(L_GETINFO..) to get a list of all loaded Dlls from AIX. loadquery @@ -214,33 +209,33 @@ static bool reload_table() { for (;;) { - entry_t* e = (entry_t*) ::malloc(sizeof(entry_t)); - if (!e) { + loaded_module_t* lm = (loaded_module_t*) ::malloc(sizeof(loaded_module_t)); + if (!lm) { trcVerbose("OOM."); goto cleanup; } - memset(e, 0, sizeof(entry_t)); + memset(lm, 0, sizeof(loaded_module_t)); - e->info.text = ldi->ldinfo_textorg; - e->info.text_len = ldi->ldinfo_textsize; - e->info.data = ldi->ldinfo_dataorg; - e->info.data_len = ldi->ldinfo_datasize; + lm->text = ldi->ldinfo_textorg; + lm->text_len = ldi->ldinfo_textsize; + lm->data = ldi->ldinfo_dataorg; + lm->data_len = ldi->ldinfo_datasize; - e->info.path = g_stringlist.add(ldi->ldinfo_filename); - if (!e->info.path) { + lm->path = g_stringlist.add(ldi->ldinfo_filename); + if (!lm->path) { trcVerbose("OOM."); goto cleanup; } // Extract short name { - const char* p = strrchr(e->info.path, '/'); + const char* p = strrchr(lm->path, '/'); if (p) { p ++; - e->info.shortname = p; + lm->shortname = p; } else { - e->info.shortname = e->info.path; + lm->shortname = lm->path; } } @@ -248,32 +243,32 @@ static bool reload_table() { const char* p_mbr_name = ldi->ldinfo_filename + strlen(ldi->ldinfo_filename) + 1; if (*p_mbr_name) { - e->info.member = g_stringlist.add(p_mbr_name); - if (!e->info.member) { + lm->member = g_stringlist.add(p_mbr_name); + if (!lm->member) { trcVerbose("OOM."); goto cleanup; } } else { - e->info.member = NULL; + lm->member = NULL; } - if (strcmp(e->info.shortname, "libjvm.so") == 0) { + if (strcmp(lm->shortname, "libjvm.so") == 0) { // Note that this, theoretically, is fuzzy. We may accidentally contain // more than one libjvm.so. But that is improbable, so lets go with this // solution. - e->info.is_in_vm = true; + lm->is_in_vm = true; } trcVerbose("entry: %p " SIZE_FORMAT ", %p " SIZE_FORMAT ", %s %s %s, %d", - e->info.text, e->info.text_len, - e->info.data, e->info.data_len, - e->info.path, e->info.shortname, - (e->info.member ? e->info.member : "NULL"), - e->info.is_in_vm + lm->text, lm->text_len, + lm->data, lm->data_len, + lm->path, lm->shortname, + (lm->member ? lm->member : "NULL"), + lm->is_in_vm ); // Add to list. - add_entry_to_list(e, &new_list); + add_entry_to_list(lm, &new_list); // Next entry... if (ldi->ldinfo_next) { @@ -304,6 +299,23 @@ cleanup: } // end LoadedLibraries::reload() +// Callback for loaded module information (from os.hpp) +// Input parameters: +// char* module_file_name, +// address module_base_addr, +// address module_top_addr, +// void* param +static bool for_each_internal(os::LoadedModulesCallbackFunc cb, void* param) { + + for (const loaded_module_t* lm = g_first; lm; lm = lm->next) { + (*cb)(lm->shortname, + (address) lm->text, + (address) lm->text + lm->text_len, + param); + } + + return true; +} /////////////////////////////////////////////////////////////////////////////// // Externals @@ -322,8 +334,8 @@ void LoadedLibraries::print(outputStream* os) { if (!g_first) { reload_table(); } - for (entry_t* e = g_first; e; e = e->next) { - print_entry(e, os); + for (loaded_module_t* lm = g_first; lm; lm = lm->next) { + print_entry(lm, os); os->cr(); } } @@ -334,14 +346,17 @@ bool LoadedLibraries::find_for_text_address(const void* p, if (!g_first) { reload_table(); } - const entry_t* const e = find_entry_for_text_address(p); - if (e) { - if (info) { - *info = e->info; - } - return true; + + const loaded_module_t* const lm = find_entry_for_text_address(p); + if (!lm) { + return false; } - return false; + + if (info) { + memcpy(info, lm, sizeof(loaded_module_t)); + info->next = nullptr; + } + return true; } @@ -353,13 +368,30 @@ bool LoadedLibraries::find_for_data_address ( if (!g_first) { reload_table(); } - const entry_t* const e = find_entry_for_data_address(p); - if (e) { - if (info) { - *info = e->info; + + const loaded_module_t* const lm = find_entry_for_data_address(p); + if (!lm) { + return false; + } + + if (info) { + memcpy(info, lm, sizeof(loaded_module_t)); + info->next = nullptr; + } + return true; +} + +bool LoadedLibraries::for_each(os::LoadedModulesCallbackFunc cb, void* param) { + MiscUtils::AutoCritSect lck(&g_cs); + + if (!g_first) { + if (!reload_table()) { + // If the table is not loaded and cannot be initialized, + // then we must quit. + return false; } - return true; } - return false; + + return for_each_internal(cb, param); } diff --git a/src/hotspot/os/aix/loadlib_aix.hpp b/src/hotspot/os/aix/loadlib_aix.hpp index 354dccf4c7b..18cd6e59864 100644 --- a/src/hotspot/os/aix/loadlib_aix.hpp +++ b/src/hotspot/os/aix/loadlib_aix.hpp @@ -1,4 +1,5 @@ /* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2013 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -32,6 +33,9 @@ #ifndef OS_AIX_LOADLIB_AIX_HPP #define OS_AIX_LOADLIB_AIX_HPP +#include "misc_aix.hpp" +#include "runtime/os.hpp" + #include class outputStream; @@ -66,6 +70,9 @@ struct loaded_module_t { // True if this module is part of the vm. bool is_in_vm; + // Next item in the list, or NULL if no such item exits + loaded_module_t* next; + }; // This class is a singleton holding a map of all loaded binaries @@ -99,6 +106,11 @@ class LoadedLibraries // Output debug info static void print(outputStream* os); + // Apply the callback to each loaded_module_t in the list + // Return false if module table is empty and cannot be loaded. + static bool for_each(os::LoadedModulesCallbackFunc cb, void* param); + }; + #endif // OS_AIX_LOADLIB_AIX_HPP diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index 419e2ce92fd..b586da9a78d 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2021 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -1131,7 +1131,11 @@ void os::get_summary_os_info(char* buf, size_t buflen) { } int os::get_loaded_modules_info(os::LoadedModulesCallbackFunc callback, void *param) { - // Not yet implemented. + + if (!LoadedLibraries::for_each(callback, param)) { + return -1; + } + return 0; } diff --git a/src/hotspot/os/aix/os_perf_aix.cpp b/src/hotspot/os/aix/os_perf_aix.cpp index bdccca0c1c5..ad031de3cdc 100644 --- a/src/hotspot/os/aix/os_perf_aix.cpp +++ b/src/hotspot/os/aix/os_perf_aix.cpp @@ -1,5 +1,6 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, IBM Corp. * 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,197 +25,42 @@ #include "precompiled.hpp" #include "jvm.h" +#include "libperfstat_aix.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "os_aix.inline.hpp" #include "runtime/os.hpp" #include "runtime/os_perf.hpp" #include "runtime/vm_version.hpp" +#include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" -#include -#include -#include +#include +#include #include +#include +#include +#include +#include #include +#include #include -#include #include -#include +#include #include -#include -#include -#include - -/** - /proc/[number]/stat - Status information about the process. This is used by ps(1). It is defined in /usr/src/linux/fs/proc/array.c. - - The fields, in order, with their proper scanf(3) format specifiers, are: - - 1. pid %d The process id. - - 2. comm %s - The filename of the executable, in parentheses. This is visible whether or not the executable is swapped out. - - 3. state %c - One character from the string "RSDZTW" where R is running, S is sleeping in an interruptible wait, D is waiting in uninterruptible disk - sleep, Z is zombie, T is traced or stopped (on a signal), and W is paging. - - 4. ppid %d - The PID of the parent. - - 5. pgrp %d - The process group ID of the process. - - 6. session %d - The session ID of the process. - - 7. tty_nr %d - The tty the process uses. - - 8. tpgid %d - The process group ID of the process which currently owns the tty that the process is connected to. - - 9. flags %lu - The flags of the process. The math bit is decimal 4, and the traced bit is decimal 10. - - 10. minflt %lu - The number of minor faults the process has made which have not required loading a memory page from disk. - - 11. cminflt %lu - The number of minor faults that the process's waited-for children have made. - - 12. majflt %lu - The number of major faults the process has made which have required loading a memory page from disk. - - 13. cmajflt %lu - The number of major faults that the process's waited-for children have made. - - 14. utime %lu - The number of jiffies that this process has been scheduled in user mode. - - 15. stime %lu - The number of jiffies that this process has been scheduled in kernel mode. - - 16. cutime %ld - The number of jiffies that this process's waited-for children have been scheduled in user mode. (See also times(2).) - - 17. cstime %ld - The number of jiffies that this process' waited-for children have been scheduled in kernel mode. - - 18. priority %ld - The standard nice value, plus fifteen. The value is never negative in the kernel. - - 19. nice %ld - The nice value ranges from 19 (nicest) to -19 (not nice to others). - - 20. 0 %ld This value is hard coded to 0 as a placeholder for a removed field. - - 21. itrealvalue %ld - The time in jiffies before the next SIGALRM is sent to the process due to an interval timer. - - 22. starttime %lu - The time in jiffies the process started after system boot. - - 23. vsize %lu - Virtual memory size in bytes. - - 24. rss %ld - Resident Set Size: number of pages the process has in real memory, minus 3 for administrative purposes. This is just the pages which count - towards text, data, or stack space. This does not include pages which have not been demand-loaded in, or which are swapped out. - - 25. rlim %lu - Current limit in bytes on the rss of the process (usually 4294967295 on i386). - - 26. startcode %lu - The address above which program text can run. - - 27. endcode %lu - The address below which program text can run. - - 28. startstack %lu - The address of the start of the stack. - - 29. kstkesp %lu - The current value of esp (stack pointer), as found in the kernel stack page for the process. - - 30. kstkeip %lu - The current EIP (instruction pointer). - - 31. signal %lu - The bitmap of pending signals (usually 0). - - 32. blocked %lu - The bitmap of blocked signals (usually 0, 2 for shells). - - 33. sigignore %lu - The bitmap of ignored signals. - - 34. sigcatch %lu - The bitmap of catched signals. - - 35. wchan %lu - This is the "channel" in which the process is waiting. It is the address of a system call, and can be looked up in a namelist if you need - a textual name. (If you have an up-to-date /etc/psdatabase, then try ps -l to see the WCHAN field in action.) - - 36. nswap %lu - Number of pages swapped - not maintained. - - 37. cnswap %lu - Cumulative nswap for child processes. - - 38. exit_signal %d - Signal to be sent to parent when we die. - - 39. processor %d - CPU number last executed on. - - - - ///// SSCANF FORMAT STRING. Copy and use. - -field: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 -format: %d %s %c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %d %d - - -*/ - -/** - * For platforms that have them, when declaring - * a printf-style function, - * formatSpec is the parameter number (starting at 1) - * that is the format argument ("%d pid %s") - * params is the parameter number where the actual args to - * the format starts. If the args are in a va_list, this - * should be 0. - */ -#ifndef PRINTF_ARGS -# define PRINTF_ARGS(formatSpec, params) ATTRIBUTE_PRINTF(formatSpec, params) -#endif - -#ifndef SCANF_ARGS -# define SCANF_ARGS(formatSpec, params) ATTRIBUTE_SCANF(formatSpec, params) -#endif - -#ifndef _PRINTFMT_ -# define _PRINTFMT_ -#endif - -#ifndef _SCANFMT_ -# define _SCANFMT_ -#endif - +#include -struct CPUPerfTicks { - uint64_t used; - uint64_t usedKernel; - uint64_t total; -}; +typedef struct { + u_longlong_t user; + u_longlong_t sys; + u_longlong_t idle; + u_longlong_t wait; +} cpu_tick_store_t; -typedef enum { - CPU_LOAD_VM_ONLY, - CPU_LOAD_GLOBAL, -} CpuLoadTarget; +typedef struct { + double utime; + double stime; +} jvm_time_store_t; enum { UNDETECTED, @@ -223,318 +69,299 @@ enum { BAREMETAL }; -struct CPUPerfCounters { - int nProcs; - CPUPerfTicks jvmTicks; - CPUPerfTicks* cpus; -}; - -static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters, double* pkernelLoad, CpuLoadTarget target); - -/** reads /proc//stat data, with some checks and some skips. - * Ensure that 'fmt' does _NOT_ contain the first two "%d %s" +/** + * Get info for requested PID from /proc//psinfo file */ -static int SCANF_ARGS(2, 0) vread_statdata(const char* procfile, _SCANFMT_ const char* fmt, va_list args) { - FILE*f; - int n; - char buf[2048]; - - if ((f = os::fopen(procfile, "r")) == NULL) { - return -1; - } - - if ((n = fread(buf, 1, sizeof(buf), f)) != -1) { - char *tmp; - - buf[n-1] = '\0'; - /** skip through pid and exec name. */ - if ((tmp = strrchr(buf, ')')) != NULL) { - // skip the ')' and the following space - // but check that buffer is long enough - tmp += 2; - if (tmp < buf + n) { - n = vsscanf(tmp, fmt, args); - } - } - } +static bool read_psinfo(const u_longlong_t& pid, psinfo_t& psinfo) { + static size_t BUF_LENGTH = 32 + sizeof(u_longlong_t); - fclose(f); + FILE* fp; + char buf[BUF_LENGTH]; + int len; - return n; -} + jio_snprintf(buf, BUF_LENGTH, "/proc/%llu/psinfo", pid); + fp = fopen(buf, "r"); -static int SCANF_ARGS(2, 3) read_statdata(const char* procfile, _SCANFMT_ const char* fmt, ...) { - int n; - va_list args; + if (!fp) { + return false; + } - va_start(args, fmt); - n = vread_statdata(procfile, fmt, args); - va_end(args); - return n; + len = fread(&psinfo, 1, sizeof(psinfo_t), fp); + return len == sizeof(psinfo_t); } /** - * on Linux we got the ticks related information from /proc/stat - * this does not work on AIX, libperfstat might be an alternative + * Get and set ticks for the specified lcpu */ -static OSReturn get_total_ticks(int which_logical_cpu, CPUPerfTicks* pticks) { - return OS_ERR; -} +static OSReturn get_lcpu_ticks(perfstat_id_t* lcpu_name, cpu_tick_store_t* pticks) { + perfstat_cpu_t lcpu_stats; -/** read user and system ticks from a named procfile, assumed to be in 'stat' format then. */ -static int read_ticks(const char* procfile, uint64_t* userTicks, uint64_t* systemTicks) { - return read_statdata(procfile, "%*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u " UINT64_FORMAT " " UINT64_FORMAT, - userTicks, systemTicks); -} + if (!pticks) { + return OS_ERR; + } -/** - * Return the number of ticks spent in any of the processes belonging - * to the JVM on any CPU. - */ -static OSReturn get_jvm_ticks(CPUPerfTicks* pticks) { - return OS_ERR; + // populate cpu_stats + if (libperfstat::perfstat_cpu(lcpu_name, &lcpu_stats, sizeof(perfstat_cpu_t), 1) < 1) { + memset(pticks, 0, sizeof(cpu_tick_store_t)); + return OS_ERR; + } + + pticks->user = lcpu_stats.user; + pticks->sys = lcpu_stats.sys; + pticks->idle = lcpu_stats.idle; + pticks->wait = lcpu_stats.wait; + + return OS_OK; } /** - * Return the load of the CPU as a double. 1.0 means the CPU process uses all - * available time for user or system processes, 0.0 means the CPU uses all time - * being idle. - * - * Returns a negative value if there is a problem in determining the CPU load. + * Return CPU load caused by the currently executing process (the jvm). */ -static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters, double* pkernelLoad, CpuLoadTarget target) { - uint64_t udiff, kdiff, tdiff; - CPUPerfTicks* pticks; - CPUPerfTicks tmp; - double user_load; +static OSReturn get_jvm_load(double* jvm_uload, double* jvm_sload) { + static clock_t ticks_per_sec = sysconf(_SC_CLK_TCK); + static u_longlong_t last_timebase = 0; - *pkernelLoad = 0.0; + perfstat_process_t jvm_stats; + perfstat_id_t name_holder; + u_longlong_t timebase_diff; - if (target == CPU_LOAD_VM_ONLY) { - pticks = &counters->jvmTicks; - } else if (-1 == which_logical_cpu) { - pticks = &counters->cpus[counters->nProcs]; - } else { - pticks = &counters->cpus[which_logical_cpu]; + jio_snprintf(name_holder.name, IDENTIFIER_LENGTH, "%d", getpid()); + if (libperfstat::perfstat_process(&name_holder, &jvm_stats, sizeof(perfstat_process_t), 1) < 1) { + return OS_ERR; } - tmp = *pticks; + // Update timebase + timebase_diff = jvm_stats.last_timebase - last_timebase; + last_timebase = jvm_stats.last_timebase; - if (target == CPU_LOAD_VM_ONLY) { - if (get_jvm_ticks(pticks) != OS_OK) { - return -1.0; - } - } else if (get_total_ticks(which_logical_cpu, pticks) != OS_OK) { - return -1.0; + if (jvm_uload) { + *jvm_uload = jvm_stats.ucpu_time / timebase_diff; + } + if (jvm_sload) { + *jvm_sload = jvm_stats.scpu_time / timebase_diff; } - // seems like we sometimes end up with less kernel ticks when - // reading /proc/self/stat a second time, timing issue between cpus? - if (pticks->usedKernel < tmp.usedKernel) { - kdiff = 0; - } else { - kdiff = pticks->usedKernel - tmp.usedKernel; + return OS_OK; +} + +static void update_prev_time(jvm_time_store_t* from, jvm_time_store_t* to) { + if (from && to) { + memcpy(to, from, sizeof(jvm_time_store_t)); } - tdiff = pticks->total - tmp.total; - udiff = pticks->used - tmp.used; +} - if (tdiff == 0) { - return 0.0; - } else if (tdiff < (udiff + kdiff)) { - tdiff = udiff + kdiff; +static void update_prev_ticks(cpu_tick_store_t* from, cpu_tick_store_t* to) { + if (from && to) { + memcpy(to, from, sizeof(cpu_tick_store_t)); } - *pkernelLoad = (kdiff / (double)tdiff); - // BUG9044876, normalize return values to sane values - *pkernelLoad = MAX2(*pkernelLoad, 0.0); - *pkernelLoad = MIN2(*pkernelLoad, 1.0); +} - user_load = (udiff / (double)tdiff); - user_load = MAX2(user_load, 0.0); - user_load = MIN2(user_load, 1.0); +/** + * Calculate the current system load from current ticks using previous ticks as a starting point. + */ +static void calculate_updated_load(cpu_tick_store_t* update, cpu_tick_store_t* prev, double* load) { + cpu_tick_store_t diff; - return user_load; -} + if (update && prev && load) { + diff.user = update->user - prev->user; + diff.sys = update->sys - prev->sys; + diff.idle = update->idle - prev->idle; + diff.wait = update->wait - prev->wait; -static int SCANF_ARGS(1, 2) parse_stat(_SCANFMT_ const char* fmt, ...) { - return OS_ERR; + *load = 1.0 - diff.idle/(diff.sys + diff.user + diff.idle + diff.wait); + } } -static int get_noof_context_switches(uint64_t* switches) { - return parse_stat("ctxt " UINT64_FORMAT "\n", switches); -} +/** + * Look up lcpu names for later re-use. + */ +static bool populate_lcpu_names(int ncpus, perfstat_id_t* lcpu_names) { + ResourceMark rm; + perfstat_cpu_t* all_lcpu_stats; + perfstat_cpu_t* lcpu_stats; + perfstat_id_t name_holder; -/** returns boot time in _seconds_ since epoch */ -static int get_boot_time(uint64_t* time) { - return parse_stat("btime " UINT64_FORMAT "\n", time); -} + assert(lcpu_names, "Names pointer NULL"); -static int perf_context_switch_rate(double* rate) { - static pthread_mutex_t contextSwitchLock = PTHREAD_MUTEX_INITIALIZER; - static uint64_t bootTime; - static uint64_t lastTimeNanos; - static uint64_t lastSwitches; - static double lastRate; + strncpy(name_holder.name, FIRST_CPU, IDENTIFIER_LENGTH); - uint64_t bt = 0; - int res = 0; + all_lcpu_stats = NEW_RESOURCE_ARRAY(perfstat_cpu_t, ncpus); - // First time through bootTime will be zero. - if (bootTime == 0) { - uint64_t tmp; - if (get_boot_time(&tmp) < 0) { - return OS_ERR; - } - bt = tmp * 1000; + // If perfstat_cpu does not return the expected number of names, signal error to caller + if (ncpus != libperfstat::perfstat_cpu(&name_holder, all_lcpu_stats, sizeof(perfstat_cpu_t), ncpus)) { + return false; } - res = OS_OK; + for (int n = 0; n < ncpus; n++) { + strncpy(lcpu_names[n].name, all_lcpu_stats[n].name, IDENTIFIER_LENGTH); + } - pthread_mutex_lock(&contextSwitchLock); - { + return true; +} - uint64_t sw; - s8 t, d; +/** + * Calculates the context switch rate. + * (Context Switches / Tick) * (Tick / s) = Context Switches per second + */ +static OSReturn perf_context_switch_rate(double* rate) { + static clock_t ticks_per_sec = sysconf(_SC_CLK_TCK); - if (bootTime == 0) { - // First interval is measured from boot time which is - // seconds since the epoch. Thereafter we measure the - // elapsed time using javaTimeNanos as it is monotonic- - // non-decreasing. - lastTimeNanos = os::javaTimeNanos(); - t = os::javaTimeMillis(); - d = t - bt; - // keep bootTime zero for now to use as a first-time-through flag - } else { - t = os::javaTimeNanos(); - d = nanos_to_millis(t - lastTimeNanos); - } + u_longlong_t ticks; + perfstat_cpu_total_t cpu_stats; - if (d == 0) { - *rate = lastRate; - } else if (get_noof_context_switches(&sw) == 0) { - *rate = ( (double)(sw - lastSwitches) / d ) * 1000; - lastRate = *rate; - lastSwitches = sw; - if (bootTime != 0) { - lastTimeNanos = t; - } - } else { - *rate = 0; - res = OS_ERR; - } - if (*rate <= 0) { - *rate = 0; - lastRate = 0; - } + if (libperfstat::perfstat_cpu_total(NULL, &cpu_stats, sizeof(perfstat_cpu_total_t), 1) < 0) { + return OS_ERR; + } - if (bootTime == 0) { - bootTime = bt; - } - } - pthread_mutex_unlock(&contextSwitchLock); + ticks = cpu_stats.user + cpu_stats.sys + cpu_stats.idle + cpu_stats.wait; + *rate = (cpu_stats.pswitch / ticks) * ticks_per_sec; - return res; + return OS_OK; } class CPUPerformanceInterface::CPUPerformance : public CHeapObj { - friend class CPUPerformanceInterface; private: - CPUPerfCounters _counters; - - int cpu_load(int which_logical_cpu, double* cpu_load); - int context_switch_rate(double* rate); - int cpu_load_total_process(double* cpu_load); - int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad); + int _ncpus; + perfstat_id_t* _lcpu_names; + cpu_tick_store_t* _prev_ticks; public: CPUPerformance(); bool initialize(); ~CPUPerformance(); + + int cpu_load(int which_logical_cpu, double* cpu_load); + int context_switch_rate(double* rate); + int cpu_load_total_process(double* cpu_load); + int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad); }; -CPUPerformanceInterface::CPUPerformance::CPUPerformance() { - _counters.nProcs = os::active_processor_count(); - _counters.cpus = NULL; -} +CPUPerformanceInterface::CPUPerformance::CPUPerformance(): + _ncpus(0), + _lcpu_names(NULL), + _prev_ticks(NULL) {} bool CPUPerformanceInterface::CPUPerformance::initialize() { - size_t array_entry_count = _counters.nProcs + 1; - _counters.cpus = NEW_C_HEAP_ARRAY(CPUPerfTicks, array_entry_count, mtInternal); - memset(_counters.cpus, 0, array_entry_count * sizeof(*_counters.cpus)); + perfstat_cpu_total_t cpu_stats; - // For the CPU load total - get_total_ticks(-1, &_counters.cpus[_counters.nProcs]); - - // For each CPU - for (int i = 0; i < _counters.nProcs; i++) { - get_total_ticks(i, &_counters.cpus[i]); + if (libperfstat::perfstat_cpu_total(NULL, &cpu_stats, sizeof(perfstat_cpu_total_t), 1) < 0) { + return false; + } + if (cpu_stats.ncpus <= 0) { + return false; } - // For JVM load - get_jvm_ticks(&_counters.jvmTicks); - // initialize context switch system - // the double is only for init - double init_ctx_switch_rate; - perf_context_switch_rate(&init_ctx_switch_rate); + _ncpus = cpu_stats.ncpus; + _lcpu_names = NEW_C_HEAP_ARRAY(perfstat_id_t, _ncpus, mtInternal); + + _prev_ticks = NEW_C_HEAP_ARRAY(cpu_tick_store_t, _ncpus, mtInternal); + // Set all prev-tick values to 0 + memset(_prev_ticks, 0, _ncpus*sizeof(cpu_tick_store_t)); + + if (!populate_lcpu_names(_ncpus, _lcpu_names)) { + return false; + } return true; } CPUPerformanceInterface::CPUPerformance::~CPUPerformance() { - if (_counters.cpus != NULL) { - FREE_C_HEAP_ARRAY(char, _counters.cpus); + if (_lcpu_names) { + FREE_C_HEAP_ARRAY(perfstat_id_t, _lcpu_names); + } + if (_prev_ticks) { + FREE_C_HEAP_ARRAY(cpu_tick_store_t, _prev_ticks); } } -int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) { - double u, s; - u = get_cpu_load(which_logical_cpu, &_counters, &s, CPU_LOAD_GLOBAL); - if (u < 0) { - *cpu_load = 0.0; +/** + * Get CPU load for all processes on specified logical CPU. + */ +int CPUPerformanceInterface::CPUPerformance::cpu_load(int lcpu_number, double* lcpu_load) { + cpu_tick_store_t ticks; + + assert(lcpu_load != NULL, "NULL pointer passed to cpu_load"); + assert(lcpu_number < _ncpus, "Invalid lcpu passed to cpu_load"); + + if (get_lcpu_ticks(&_lcpu_names[lcpu_number], &ticks) == OS_ERR) { + *lcpu_load = -1.0; return OS_ERR; } - // Cap total systemload to 1.0 - *cpu_load = MIN2((u + s), 1.0); + + calculate_updated_load(&ticks, &_prev_ticks[lcpu_number], lcpu_load); + update_prev_ticks(&ticks, &_prev_ticks[lcpu_number]); + return OS_OK; } -int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) { - double u, s; - u = get_cpu_load(-1, &_counters, &s, CPU_LOAD_VM_ONLY); - if (u < 0) { - *cpu_load = 0.0; - return OS_ERR; +/** + * Get CPU load for all processes on all CPUs. + */ +int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* total_load) { + cpu_tick_store_t total_ticks; + cpu_tick_store_t prev_total_ticks; + + assert(total_load != NULL, "NULL pointer passed to cpu_load_total_process"); + + memset(&total_ticks, 0, sizeof(cpu_tick_store_t)); + memset(&prev_total_ticks, 0, sizeof(cpu_tick_store_t)); + + for (int lcpu = 0; lcpu < _ncpus; lcpu++) { + cpu_tick_store_t lcpu_ticks; + + if (get_lcpu_ticks(&_lcpu_names[lcpu], &lcpu_ticks) == OS_ERR) { + *total_load = -1.0; + return OS_ERR; + } + + total_ticks.user = lcpu_ticks.user; + total_ticks.sys = lcpu_ticks.sys; + total_ticks.idle = lcpu_ticks.idle; + total_ticks.wait = lcpu_ticks.wait; + + prev_total_ticks.user += _prev_ticks[lcpu].user; + prev_total_ticks.sys += _prev_ticks[lcpu].sys; + prev_total_ticks.idle += _prev_ticks[lcpu].idle; + prev_total_ticks.wait += _prev_ticks[lcpu].wait; + + update_prev_ticks(&lcpu_ticks, &_prev_ticks[lcpu]); } - *cpu_load = u + s; + + calculate_updated_load(&total_ticks, &prev_total_ticks, total_load); + return OS_OK; } +/** + * Get CPU load for all CPUs. + * + * Set values for: + * - pjvmUserLoad: CPU load due to jvm process in user mode. Jvm process assumed to be self process + * - pjvmKernelLoad: CPU load due to jvm process in kernel mode. Jvm process assumed to be self process + * - psystemTotalLoad: Total CPU load from all process on all logical CPUs + * + * Note: If any of the above loads cannot be calculated, this procedure returns OS_ERR and any load that could not be calculated is set to -1 + * + */ int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) { - double u, s, t; + double u, k, t; - assert(pjvmUserLoad != NULL, "pjvmUserLoad not inited"); - assert(pjvmKernelLoad != NULL, "pjvmKernelLoad not inited"); - assert(psystemTotalLoad != NULL, "psystemTotalLoad not inited"); - - u = get_cpu_load(-1, &_counters, &s, CPU_LOAD_VM_ONLY); - if (u < 0) { - *pjvmUserLoad = 0.0; - *pjvmKernelLoad = 0.0; - *psystemTotalLoad = 0.0; - return OS_ERR; + int retval = OS_OK; + if (get_jvm_load(&u, &k) == OS_ERR || cpu_load_total_process(&t) == OS_ERR) { + retval = OS_ERR; } - cpu_load(-1, &t); - // clamp at user+system and 1.0 - if (u + s > t) { - t = MIN2(u + s, 1.0); + if (pjvmUserLoad) { + *pjvmUserLoad = u; + } + if (pjvmKernelLoad) { + *pjvmKernelLoad = k; + } + if (psystemTotalLoad) { + *psystemTotalLoad = t; } - *pjvmUserLoad = u; - *pjvmKernelLoad = s; - *psystemTotalLoad = t; - - return OS_OK; + return retval; } int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) { @@ -573,267 +400,85 @@ int CPUPerformanceInterface::context_switch_rate(double* rate) const { } class SystemProcessInterface::SystemProcesses : public CHeapObj { - friend class SystemProcessInterface; - private: - class ProcessIterator : public CHeapObj { - friend class SystemProcessInterface::SystemProcesses; - private: - DIR* _dir; - struct dirent* _entry; - bool _valid; - char _exeName[PATH_MAX]; - char _exePath[PATH_MAX]; - - ProcessIterator(); - ~ProcessIterator(); - bool initialize(); - - bool is_valid() const { return _valid; } - bool is_valid_entry(struct dirent* entry) const; - bool is_dir(const char* name) const; - int fsize(const char* name, uint64_t& size) const; - - char* allocate_string(const char* str) const; - void get_exe_name(); - char* get_exe_path(); - char* get_cmdline(); - - int current(SystemProcess* process_info); - int next_process(); - }; - - ProcessIterator* _iterator; + private: + char* allocate_string(const char* str) const; + + public: SystemProcesses(); bool initialize(); ~SystemProcesses(); - - //information about system processes int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const; }; -bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_dir(const char* name) const { - struct stat mystat; - int ret_val = 0; - - ret_val = stat(name, &mystat); - if (ret_val < 0) { - return false; - } - ret_val = S_ISDIR(mystat.st_mode); - return ret_val > 0; -} - -int SystemProcessInterface::SystemProcesses::ProcessIterator::fsize(const char* name, uint64_t& size) const { - assert(name != NULL, "name pointer is NULL!"); - size = 0; - struct stat fbuf; - - if (stat(name, &fbuf) < 0) { - return OS_ERR; - } - size = fbuf.st_size; - return OS_OK; -} - -// if it has a numeric name, is a directory and has a 'stat' file in it -bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_valid_entry(struct dirent* entry) const { - char buffer[PATH_MAX]; - uint64_t size = 0; - - if (atoi(entry->d_name) != 0) { - jio_snprintf(buffer, PATH_MAX, "/proc/%s", entry->d_name); - buffer[PATH_MAX - 1] = '\0'; - - if (is_dir(buffer)) { - jio_snprintf(buffer, PATH_MAX, "/proc/%s/stat", entry->d_name); - buffer[PATH_MAX - 1] = '\0'; - if (fsize(buffer, size) != OS_ERR) { - return true; - } - } - } - return false; -} - -// get exe-name from /proc//stat -void SystemProcessInterface::SystemProcesses::ProcessIterator::get_exe_name() { - FILE* fp; - char buffer[PATH_MAX]; - - jio_snprintf(buffer, PATH_MAX, "/proc/%s/stat", _entry->d_name); - buffer[PATH_MAX - 1] = '\0'; - if ((fp = os::fopen(buffer, "r")) != NULL) { - if (fgets(buffer, PATH_MAX, fp) != NULL) { - char* start, *end; - // exe-name is between the first pair of ( and ) - start = strchr(buffer, '('); - if (start != NULL && start[1] != '\0') { - start++; - end = strrchr(start, ')'); - if (end != NULL) { - size_t len; - len = MIN2(end - start, sizeof(_exeName) - 1); - memcpy(_exeName, start, len); - _exeName[len] = '\0'; - } - } - } - fclose(fp); - } +SystemProcessInterface::SystemProcesses::SystemProcesses() { } -// get command line from /proc//cmdline -char* SystemProcessInterface::SystemProcesses::ProcessIterator::get_cmdline() { - FILE* fp; - char buffer[PATH_MAX]; - char* cmdline = NULL; - - jio_snprintf(buffer, PATH_MAX, "/proc/%s/cmdline", _entry->d_name); - buffer[PATH_MAX - 1] = '\0'; - if ((fp = os::fopen(buffer, "r")) != NULL) { - size_t size = 0; - char dummy; - - // find out how long the file is (stat always returns 0) - while (fread(&dummy, 1, 1, fp) == 1) { - size++; - } - if (size > 0) { - cmdline = NEW_C_HEAP_ARRAY(char, size + 1, mtInternal); - cmdline[0] = '\0'; - if (fseek(fp, 0, SEEK_SET) == 0) { - if (fread(cmdline, 1, size, fp) == size) { - // the file has the arguments separated by '\0', - // so we translate '\0' to ' ' - for (size_t i = 0; i < size; i++) { - if (cmdline[i] == '\0') { - cmdline[i] = ' '; - } - } - cmdline[size] = '\0'; - } - } - } - fclose(fp); - } - return cmdline; +bool SystemProcessInterface::SystemProcesses::initialize() { + return true; } -// get full path to exe from /proc//exe symlink -char* SystemProcessInterface::SystemProcesses::ProcessIterator::get_exe_path() { - char buffer[PATH_MAX]; - - jio_snprintf(buffer, PATH_MAX, "/proc/%s/exe", _entry->d_name); - buffer[PATH_MAX - 1] = '\0'; - return realpath(buffer, _exePath); +SystemProcessInterface::SystemProcesses::~SystemProcesses() { } -char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const { +char* SystemProcessInterface::SystemProcesses::allocate_string(const char* str) const { if (str != NULL) { return os::strdup_check_oom(str, mtInternal); } return NULL; } -int SystemProcessInterface::SystemProcesses::ProcessIterator::current(SystemProcess* process_info) { - if (!is_valid()) { - return OS_ERR; - } - - process_info->set_pid(atoi(_entry->d_name)); - - get_exe_name(); - process_info->set_name(allocate_string(_exeName)); +int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes, int* nprocs) const { + ResourceMark rm; + perfstat_process_t* proc_stats; + SystemProcess* head; + perfstat_id_t name_holder; + int records_allocated = 0; - if (get_exe_path() != NULL) { - process_info->set_path(allocate_string(_exePath)); - } - - char* cmdline = NULL; - cmdline = get_cmdline(); - if (cmdline != NULL) { - process_info->set_command_line(allocate_string(cmdline)); - FREE_C_HEAP_ARRAY(char, cmdline); - } + assert(nprocs != NULL, "system_processes counter pointers is NULL!"); - return OS_OK; -} + head = NULL; + *nprocs = 0; + strncpy(name_holder.name, "", IDENTIFIER_LENGTH); -int SystemProcessInterface::SystemProcesses::ProcessIterator::next_process() { - if (!is_valid()) { + // calling perfstat_(NULL, NULL, _, 0) returns number of available records + *nprocs = libperfstat::perfstat_process(NULL, NULL, sizeof(perfstat_process_t), 0); + if(*nprocs < 1) { + // expect at least 1 process return OS_ERR; } - do { - _entry = os::readdir(_dir); - if (_entry == NULL) { - // Error or reached end. Could use errno to distinguish those cases. - _valid = false; - return OS_ERR; - } - } while(!is_valid_entry(_entry)); - - _valid = true; - return OS_OK; -} - -SystemProcessInterface::SystemProcesses::ProcessIterator::ProcessIterator() { - _dir = NULL; - _entry = NULL; - _valid = false; -} + records_allocated = *nprocs; + proc_stats = NEW_RESOURCE_ARRAY(perfstat_process_t, records_allocated); -bool SystemProcessInterface::SystemProcesses::ProcessIterator::initialize() { - // Not yet implemented. - return false; -} + // populate stats && set the actual number of procs that have been populated + // should never be higher than requested, but may be lower due to process death + *nprocs = libperfstat::perfstat_process(&name_holder, proc_stats, sizeof(perfstat_process_t), records_allocated); -SystemProcessInterface::SystemProcesses::ProcessIterator::~ProcessIterator() { - if (_dir != NULL) { - os::closedir(_dir); - } -} + for (int n = 0; n < *nprocs; n++) { + psinfo_t psinfo; + // Note: SystemProcess with free these in its dtor. + char* name = NEW_C_HEAP_ARRAY(char, IDENTIFIER_LENGTH, mtInternal); + char* exe_name = NEW_C_HEAP_ARRAY(char, PRFNSZ, mtInternal); + char* cmd_line = NEW_C_HEAP_ARRAY(char, PRARGSZ, mtInternal); -SystemProcessInterface::SystemProcesses::SystemProcesses() { - _iterator = NULL; -} + strncpy(name, proc_stats[n].proc_name, IDENTIFIER_LENGTH); -bool SystemProcessInterface::SystemProcesses::initialize() { - _iterator = new SystemProcessInterface::SystemProcesses::ProcessIterator(); - return _iterator->initialize(); -} + if (read_psinfo(proc_stats[n].pid, psinfo)) { + strncpy(exe_name, psinfo.pr_fname, PRFNSZ); + strncpy(cmd_line, psinfo.pr_psargs, PRARGSZ); + } -SystemProcessInterface::SystemProcesses::~SystemProcesses() { - if (_iterator != NULL) { - delete _iterator; + // create a new SystemProcess with next pointing to current head. + SystemProcess* sp = new SystemProcess(proc_stats[n].pid, + name, + exe_name, + cmd_line, + head); + // update head. + head = sp; } -} - -int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const { - assert(system_processes != NULL, "system_processes pointer is NULL!"); - assert(no_of_sys_processes != NULL, "system_processes counter pointers is NULL!"); - assert(_iterator != NULL, "iterator is NULL!"); - - // initialize pointers - *no_of_sys_processes = 0; - *system_processes = NULL; - while (_iterator->is_valid()) { - SystemProcess* tmp = new SystemProcess(); - _iterator->current(tmp); - - //if already existing head - if (*system_processes != NULL) { - //move "first to second" - tmp->set_next(*system_processes); - } - // new head - *system_processes = tmp; - // increment - (*no_of_sys_processes)++; - // step forward - _iterator->next_process(); - } + *system_processes = head; return OS_OK; } @@ -897,29 +542,68 @@ int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) { } class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj { - friend class NetworkPerformanceInterface; + NONCOPYABLE(NetworkPerformance); + private: + char* allocate_string(const char* str) const; + + public: NetworkPerformance(); - NONCOPYABLE(NetworkPerformance); bool initialize(); ~NetworkPerformance(); int network_utilization(NetworkInterface** network_interfaces) const; }; -NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() { - -} +NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() {} bool NetworkPerformanceInterface::NetworkPerformance::initialize() { return true; } -NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() { -} +NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() {} + +int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const { + int n_records = 0; + perfstat_netinterface_t* net_stats; + perfstat_id_t name_holder; + int records_allocated = 0; + + assert(network_interfaces != NULL, "network_interfaces is NULL"); + + *network_interfaces = NULL; + strncpy(name_holder.name , FIRST_NETINTERFACE, IDENTIFIER_LENGTH); + + // calling perfstat_(NULL, NULL, _, 0) returns number of available records + if ((n_records = libperfstat::perfstat_netinterface(NULL, NULL, sizeof(perfstat_netinterface_t), 0)) < 0) { + return OS_ERR; + } -int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const -{ - return FUNCTIONALITY_NOT_IMPLEMENTED; + records_allocated = n_records; + net_stats = NEW_C_HEAP_ARRAY(perfstat_netinterface_t, records_allocated, mtInternal); + + n_records = libperfstat::perfstat_netinterface(&name_holder, net_stats, sizeof(perfstat_netinterface_t), n_records); + + // check for error + if (n_records < 0) { + FREE_C_HEAP_ARRAY(perfstat_netinterface_t, net_stats); + return OS_ERR; + } + + for (int i = 0; i < n_records; i++) { + // Create new Network interface *with current head as next node* + // Note: NetworkInterface makes copies of these string values into RA memory + // this means: + // (1) we are free to clean our values upon exiting this proc + // (2) we avoid using RA-alloced memory here (ie. do not use NEW_RESOURCE_ARRAY) + NetworkInterface* new_interface = new NetworkInterface(net_stats[i].name, + net_stats[i].ibytes, + net_stats[i].obytes, + *network_interfaces); + *network_interfaces = new_interface; + } + + FREE_C_HEAP_ARRAY(perfstat_netinterface_t, net_stats); + return OS_OK; } NetworkPerformanceInterface::NetworkPerformanceInterface() { diff --git a/src/hotspot/os_cpu/aix_ppc/thread_aix_ppc.cpp b/src/hotspot/os_cpu/aix_ppc/thread_aix_ppc.cpp index 6b810bd3918..44c7baebd79 100644 --- a/src/hotspot/os_cpu/aix_ppc/thread_aix_ppc.cpp +++ b/src/hotspot/os_cpu/aix_ppc/thread_aix_ppc.cpp @@ -1,6 +1,7 @@ /* * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2014 SAP SE. All rights reserved. + * Copyright (c) 2022, IBM Corp. * 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,6 +25,7 @@ */ #include "precompiled.hpp" +#include "memory/metaspace.hpp" #include "runtime/frame.inline.hpp" #include "runtime/thread.hpp" @@ -34,6 +36,8 @@ frame JavaThread::pd_last_frame() { address pc = _anchor.last_Java_pc(); // Last_Java_pc ist not set, if we come here from compiled code. + // Assume spill slot for link register contains a suitable pc. + // Should have been filled by method entry code. if (pc == NULL) pc = (address) *(sp + 2); @@ -41,16 +45,71 @@ frame JavaThread::pd_last_frame() { } bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, bool isInJava) { - ucontext_t* uc = (ucontext_t*) ucontext; - *fr_addr = frame((intptr_t*)uc->uc_mcontext.jmp_context.gpr[1/*REG_SP*/], - (address)uc->uc_mcontext.jmp_context.iar); - return true; + + // If we have a last_Java_frame, then we should use it even if + // isInJava == true. It should be more reliable than ucontext info. + if (has_last_Java_frame() && frame_anchor()->walkable()) { + *fr_addr = pd_last_frame(); + return true; + } + + // At this point, we don't have a last_Java_frame, so + // we try to glean some information out of the ucontext + // if we were running Java code when SIGPROF came in. + if (isInJava) { + ucontext_t* uc = (ucontext_t*) ucontext; + address pc = (address)uc->uc_mcontext.jmp_context.iar; + + if (pc == NULL) { + // ucontext wasn't useful + return false; + } + + frame ret_frame((intptr_t*)uc->uc_mcontext.jmp_context.gpr[1/*REG_SP*/], pc); + + if (ret_frame.fp() == NULL) { + // The found frame does not have a valid frame pointer. + // Bail out because this will create big trouble later on, either + // - when using istate, calculated as (NULL - ijava_state_size) or + // - when using fp() directly in safe_for_sender() + // + // There is no conclusive description (yet) how this could happen, but it does. + // For more details on what was observed, see thread_linux_s390.cpp + return false; + } + + if (ret_frame.is_interpreted_frame()) { + frame::ijava_state *istate = ret_frame.get_ijava_state(); + const Method *m = (const Method*)(istate->method); + if (!Method::is_valid_method(m)) return false; + if (!Metaspace::contains(m->constMethod())) return false; + + uint64_t reg_bcp = uc->uc_mcontext.jmp_context.gpr[14/*R14_bcp*/]; + uint64_t istate_bcp = istate->bcp; + uint64_t code_start = (uint64_t)(m->code_base()); + uint64_t code_end = (uint64_t)(m->code_base() + m->code_size()); + if (istate_bcp >= code_start && istate_bcp < code_end) { + // we have a valid bcp, don't touch it, do nothing + } else if (reg_bcp >= code_start && reg_bcp < code_end) { + istate->bcp = reg_bcp; + } else { + return false; + } + } + if (!ret_frame.safe_for_sender(this)) { + // nothing else to try if the frame isn't good + return false; + } + *fr_addr = ret_frame; + return true; + } + // nothing else to try + return false; } -// Forte Analyzer AsyncGetCallTrace profiling support is not implemented on Aix/PPC. +// Forte Analyzer AsyncGetCallTrace profiling support. bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, bool isInJava) { - Unimplemented(); - return false; + return pd_get_top_frame_for_profiling(fr_addr, ucontext, isInJava); } void JavaThread::cache_global_variables() { } diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 8e00e12f1ba..81c2dffe2d1 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -821,7 +821,7 @@ javax/script/Test7.java 8239361 generic- # jdk_jfr -jdk/jfr/event/runtime/TestNetworkUtilizationEvent.java 8228990 generic-all +jdk/jfr/event/runtime/TestNetworkUtilizationEvent.java 8228990 macosx-all,linux-all,windows-all jdk/jfr/event/compiler/TestCodeSweeper.java 8225209 generic-all jdk/jfr/event/os/TestThreadContextSwitches.java 8247776 windows-all jdk/jfr/startupargs/TestStartName.java 8214685 windows-x64 diff --git a/test/jdk/jdk/jfr/event/runtime/TestNativeLibrariesEvent.java b/test/jdk/jdk/jfr/event/runtime/TestNativeLibrariesEvent.java index f3299820925..77eb0362841 100644 --- a/test/jdk/jdk/jfr/event/runtime/TestNativeLibrariesEvent.java +++ b/test/jdk/jdk/jfr/event/runtime/TestNativeLibrariesEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -77,7 +77,10 @@ public class TestNativeLibrariesEvent { libTemplate = "lib%s.dylib"; } else if (Platform.isLinux()) { libTemplate = "lib%s.so"; + } else if (Platform.isAix()) { + libTemplate = "lib%s.so"; } + if (libTemplate == null) { throw new Exception("Unsupported OS"); } -- GitLab From b4900b1298e536c0ceaa77bc0ac0e8e6ccba6400 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Thu, 17 Feb 2022 09:36:05 +0000 Subject: [PATCH 109/203] 8264743: Add forRemoval for deprecated classes and method in javax/swing/plaf/basic Reviewed-by: trebari, prr --- .../javax/swing/plaf/basic/BasicDirectoryModel.java | 6 +++--- .../classes/javax/swing/plaf/basic/BasicMenuItemUI.java | 2 +- .../classes/javax/swing/plaf/basic/BasicScrollPaneUI.java | 8 ++++---- .../classes/javax/swing/plaf/basic/BasicToolBarUI.java | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java index 34c53ca915f..63e8309fda2 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java @@ -228,7 +228,7 @@ public class BasicDirectoryModel extends AbstractListModel implements Pr * @param e list data event * @deprecated Obsolete method, not used anymore. */ - @Deprecated(since = "17") + @Deprecated(since = "17", forRemoval = true) public void intervalAdded(ListDataEvent e) { } @@ -237,7 +237,7 @@ public class BasicDirectoryModel extends AbstractListModel implements Pr * @param e list data event * @deprecated Obsolete method, not used anymore. */ - @Deprecated(since = "17") + @Deprecated(since = "17", forRemoval = true) public void intervalRemoved(ListDataEvent e) { } @@ -257,7 +257,7 @@ public class BasicDirectoryModel extends AbstractListModel implements Pr * @param b another file * @deprecated Obsolete method, not used anymore. */ - @Deprecated(since = "17") + @Deprecated(since = "17", forRemoval = true) protected boolean lt(File a, File b) { // First ignore case when comparing int diff = a.getName().toLowerCase().compareTo(b.getName().toLowerCase()); diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicMenuItemUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicMenuItemUI.java index db9eee52f1f..cbe840c1ad6 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicMenuItemUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicMenuItemUI.java @@ -928,7 +928,7 @@ public class BasicMenuItemUI extends MenuItemUI * All its functionality has been moved into Handler. * @deprecated */ - @Deprecated(since = "17") + @Deprecated(since = "17", forRemoval = true) protected class MouseInputHandler implements MouseInputListener { // NOTE: This class exists only for backward compatibility. All // its functionality has been moved into Handler. If you need to add diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicScrollPaneUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicScrollPaneUI.java index 714199af15b..e017ac6722b 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicScrollPaneUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicScrollPaneUI.java @@ -500,7 +500,7 @@ public class BasicScrollPaneUI * All its functionality has been moved into Handler. * @deprecated */ - @Deprecated(since = "17") + @Deprecated(since = "17", forRemoval = true) public class ViewportChangeHandler implements ChangeListener { /** @@ -534,7 +534,7 @@ public class BasicScrollPaneUI * All its functionality has been moved into Handler. * @deprecated */ - @Deprecated(since = "17") + @Deprecated(since = "17", forRemoval = true) public class HSBChangeListener implements ChangeListener { /** @@ -577,7 +577,7 @@ public class BasicScrollPaneUI * All its functionality has been moved into Handler. * @deprecated */ - @Deprecated(since = "17") + @Deprecated(since = "17", forRemoval = true) public class VSBChangeListener implements ChangeListener { /** @@ -786,7 +786,7 @@ public class BasicScrollPaneUI * All its functionality has been moved into Handler. * @deprecated */ - @Deprecated(since = "17") + @Deprecated(since = "17", forRemoval = true) public class PropertyChangeHandler implements PropertyChangeListener { /** diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicToolBarUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicToolBarUI.java index 8a13bf119a5..975272a03b7 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicToolBarUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicToolBarUI.java @@ -551,7 +551,7 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants * @deprecated It is recommended that {@link BasicToolBarUI#createFloatingWindow(JToolBar)} * be used instead */ - @Deprecated(since = "17") + @Deprecated(since = "17", forRemoval = true) protected JFrame createFloatingFrame(JToolBar toolbar) { Window window = SwingUtilities.getWindowAncestor(toolbar); @SuppressWarnings("serial") // anonymous class -- GitLab From 9ca435b4c03f9741709bbfab22fb006de8c8c9d3 Mon Sep 17 00:00:00 2001 From: Julia Boes Date: Thu, 17 Feb 2022 10:35:05 +0000 Subject: [PATCH 110/203] 8281305: Test com/sun/net/httpserver/simpleserver/MapToPathTest.java fails on Windows 11 Reviewed-by: dfuchs --- .../simpleserver/FileServerHandler.java | 5 +- .../simpleserver/URIPathSegment.java | 44 +++++++++++++++ .../simpleserver/URIPathSegment.java | 53 +++++++++++++++++++ .../simpleserver/MapToPathTest.java | 43 ++++++++++++--- 4 files changed, 138 insertions(+), 7 deletions(-) create mode 100644 src/jdk.httpserver/unix/classes/sun/net/httpserver/simpleserver/URIPathSegment.java create mode 100644 src/jdk.httpserver/windows/classes/sun/net/httpserver/simpleserver/URIPathSegment.java diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/FileServerHandler.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/FileServerHandler.java index e0e9736cad4..b3dc1ff5f4a 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/FileServerHandler.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/FileServerHandler.java @@ -227,9 +227,12 @@ public final class FileServerHandler implements HttpHandler { // resolve each path segment against the root Path path = root; for (var segment : pathSegment) { + if (!URIPathSegment.isSupported(segment)) { + return null; // stop resolution, null results in 404 response + } path = path.resolve(segment); if (!Files.isReadable(path) || isHiddenOrSymLink(path)) { - return null; // stop resolution, null results in 404 response + return null; // stop resolution } } path = path.normalize(); diff --git a/src/jdk.httpserver/unix/classes/sun/net/httpserver/simpleserver/URIPathSegment.java b/src/jdk.httpserver/unix/classes/sun/net/httpserver/simpleserver/URIPathSegment.java new file mode 100644 index 00000000000..497ccd7a850 --- /dev/null +++ b/src/jdk.httpserver/unix/classes/sun/net/httpserver/simpleserver/URIPathSegment.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.net.httpserver.simpleserver; + +/** + * A class that represents a URI path segment. + */ +final class URIPathSegment { + + private URIPathSegment() { throw new AssertionError(); } + + /** + * Checks if the segment of a URI path is supported. + * + * @param segment the segment string + * @return true + */ + static boolean isSupported(String segment) { + return true; + } +} diff --git a/src/jdk.httpserver/windows/classes/sun/net/httpserver/simpleserver/URIPathSegment.java b/src/jdk.httpserver/windows/classes/sun/net/httpserver/simpleserver/URIPathSegment.java new file mode 100644 index 00000000000..0de28f188dc --- /dev/null +++ b/src/jdk.httpserver/windows/classes/sun/net/httpserver/simpleserver/URIPathSegment.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.net.httpserver.simpleserver; + +/** + * A class that represents a URI path segment. + */ +final class URIPathSegment { + + private URIPathSegment() { throw new AssertionError(); } + + /** + * Checks if the segment of a URI path is supported. For example, + * "C:" is supported as a drive on Windows only. + * + * @param segment the segment string + * @return true if the segment is supported + */ + static boolean isSupported(String segment) { + // apply same logic as WindowsPathParser + if (segment.length() >= 2 && isLetter(segment.charAt(0)) && segment.charAt(1) == ':') { + return false; + } + return true; + } + + private static boolean isLetter(char c) { + return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')); + } +} diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/MapToPathTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/MapToPathTest.java index d6e61da4073..aa8f37acc1b 100644 --- a/test/jdk/com/sun/net/httpserver/simpleserver/MapToPathTest.java +++ b/test/jdk/com/sun/net/httpserver/simpleserver/MapToPathTest.java @@ -137,19 +137,27 @@ public class MapToPathTest { var res3 = client.send(req3, BodyHandlers.ofString()); assertEquals(res3.statusCode(), 404); // not found - var req4 = HttpRequest.newBuilder(uri(server, "/foo/file:" + TEST_DIR.getParent())).build(); + var req4 = HttpRequest.newBuilder(uri(server, "/foo/bar/baz/c:.//")).build(); var res4 = client.send(req4, BodyHandlers.ofString()); assertEquals(res4.statusCode(), 404); // not found - var req5 = HttpRequest.newBuilder(uri(server, "/foo/bar/\\..\\../")).build(); + var req5 = HttpRequest.newBuilder(uri(server, "/foo/bar/baz/c:..//")).build(); var res5 = client.send(req5, BodyHandlers.ofString()); assertEquals(res5.statusCode(), 404); // not found - var req6 = HttpRequest.newBuilder(uri(server, "/foo")).build(); + var req6 = HttpRequest.newBuilder(uri(server, "/foo/file:" + TEST_DIR.getParent())).build(); var res6 = client.send(req6, BodyHandlers.ofString()); - assertEquals(res6.statusCode(), 301); // redirect - assertEquals(res6.headers().firstValue("content-length").get(), "0"); - assertEquals(res6.headers().firstValue("location").get(), "/foo/"); + assertEquals(res6.statusCode(), 404); // not found + + var req7 = HttpRequest.newBuilder(uri(server, "/foo/bar/\\..\\../")).build(); + var res7 = client.send(req7, BodyHandlers.ofString()); + assertEquals(res7.statusCode(), 404); // not found + + var req8 = HttpRequest.newBuilder(uri(server, "/foo")).build(); + var res8 = client.send(req8, BodyHandlers.ofString()); + assertEquals(res8.statusCode(), 301); // redirect + assertEquals(res8.headers().firstValue("content-length").get(), "0"); + assertEquals(res8.headers().firstValue("location").get(), "/foo/"); } finally { server.stop(0); } @@ -250,6 +258,29 @@ public class MapToPathTest { server.stop(0); } } + { + // Test that a request path segment that is a Windows root drive + // does not circumvent access restrictions. + // + // For example, given the test directory tree: + // + // |-- TEST_DIR + // |-- foo + // |-- bar ----->>> if hidden, itself and any of its subdirectories are not accessible + // |-- baz + // |-- file.txt + // ... + var handler = SimpleFileServer.createFileHandler(TEST_DIR); + var server = HttpServer.create(LOOPBACK_ADDR, 10, "/", handler, OUTPUT_FILTER); + server.start(); + try { + var req1 = HttpRequest.newBuilder(uri(server, "/foo/bar/c:/baz/")).build(); + var res1 = client.send(req1, BodyHandlers.ofString()); + assertEquals(res1.statusCode(), 404); // not found + } finally { + server.stop(0); + } + } } // Tests with a mixture of in-memory and file handlers. -- GitLab From 3b7a3cfce345cc900e042c5378d35d1237bdcd78 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Thu, 17 Feb 2022 11:40:43 +0000 Subject: [PATCH 111/203] 8281971: Remove unimplemented InstanceRefKlass::do_next Reviewed-by: dholmes --- src/hotspot/share/oops/instanceRefKlass.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/hotspot/share/oops/instanceRefKlass.hpp b/src/hotspot/share/oops/instanceRefKlass.hpp index 4156559df05..16a9bb53c3a 100644 --- a/src/hotspot/share/oops/instanceRefKlass.hpp +++ b/src/hotspot/share/oops/instanceRefKlass.hpp @@ -97,9 +97,6 @@ class InstanceRefKlass: public InstanceKlass { template static void do_referent(oop obj, OopClosureType* closure, Contains& contains); - template - static void do_next(oop obj, OopClosureType* closure, Contains& contains); - template static void do_discovered(oop obj, OopClosureType* closure, Contains& contains); -- GitLab From d0e11808fd688d96e5cfeb586d1de277f26da5ad Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Thu, 17 Feb 2022 12:31:37 +0000 Subject: [PATCH 112/203] 8282019: Unused static fields DEGREES_TO_RADIANS, RADIANS_TO_DEGREES in StrictMath Reviewed-by: bpb, darcy --- .../share/classes/java/lang/StrictMath.java | 21 ++++--------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/src/java.base/share/classes/java/lang/StrictMath.java b/src/java.base/share/classes/java/lang/StrictMath.java index b5e3541c85c..53b25fedebb 100644 --- a/src/java.base/share/classes/java/lang/StrictMath.java +++ b/src/java.base/share/classes/java/lang/StrictMath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -101,19 +101,6 @@ public final class StrictMath { */ public static final double PI = 3.14159265358979323846; - /** - * Constant by which to multiply an angular value in degrees to obtain an - * angular value in radians. - */ - private static final double DEGREES_TO_RADIANS = 0.017453292519943295; - - /** - * Constant by which to multiply an angular value in radians to obtain an - * angular value in degrees. - */ - - private static final double RADIANS_TO_DEGREES = 57.29577951308232; - /** * Returns the trigonometric sine of an angle. Special cases: *
    • If the argument is NaN or an infinity, then the @@ -397,7 +384,7 @@ public final class StrictMath { * @param a the value to be floored or ceiled * @param negativeBoundary result for values in (-1, 0) * @param positiveBoundary result for values in (0, 1) - * @param increment value to add when the argument is non-integral + * @param sign the sign of the result */ private static double floorOrCeil(double a, double negativeBoundary, @@ -408,8 +395,8 @@ public final class StrictMath { if (exponent < 0) { /* * Absolute value of argument is less than 1. - * floorOrceil(-0.0) => -0.0 - * floorOrceil(+0.0) => +0.0 + * floorOrCeil(-0.0) => -0.0 + * floorOrCeil(+0.0) => +0.0 */ return ((a == 0.0) ? a : ( (a < 0.0) ? negativeBoundary : positiveBoundary) ); -- GitLab From 4c7f8b49a4845acf58272c42327328d6d2837cea Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Thu, 17 Feb 2022 17:12:40 +0000 Subject: [PATCH 113/203] 8268250: Class.arrayType() for a 255-d array throws undocumented IllegalArgumentException Reviewed-by: sundar, alanb --- .../share/classes/java/lang/Class.java | 11 ++++- test/jdk/java/lang/Class/ArrayType.java | 49 +++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 test/jdk/java/lang/Class/ArrayType.java diff --git a/src/java.base/share/classes/java/lang/Class.java b/src/java.base/share/classes/java/lang/Class.java index fce7793fbcf..840abc63aaf 100644 --- a/src/java.base/share/classes/java/lang/Class.java +++ b/src/java.base/share/classes/java/lang/Class.java @@ -4485,12 +4485,21 @@ public final class Class implements java.io.Serializable, * Returns a {@code Class} for an array type whose component type * is described by this {@linkplain Class}. * + * @throws UnsupportedOperationException if this component type is {@linkplain + * Void#TYPE void} or if the number of dimensions of the resulting array + * type would exceed 255. * @return a {@code Class} describing the array type + * @jvms 4.3.2 Field Descriptors + * @jvms 4.4.1 The {@code CONSTANT_Class_info} Structure * @since 12 */ @Override public Class arrayType() { - return Array.newInstance(this, 0).getClass(); + try { + return Array.newInstance(this, 0).getClass(); + } catch (IllegalArgumentException iae) { + throw new UnsupportedOperationException(iae); + } } /** diff --git a/test/jdk/java/lang/Class/ArrayType.java b/test/jdk/java/lang/Class/ArrayType.java new file mode 100644 index 00000000000..9764dd0b366 --- /dev/null +++ b/test/jdk/java/lang/Class/ArrayType.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8268250 + * @summary Check exceptional behavior of Class.arrayType + */ + +import java.lang.reflect.*; +import java.util.function.*; + +public class ArrayType { + public static void main(String... args) { + expectException(() -> Void.TYPE); + expectException(() -> Array.newInstance(int.class, new int[255]) + .getClass()); + } + + private static void expectException(Supplier> arrayTypeArg) { + try { + Class arrayClazz = arrayTypeArg.get().arrayType(); + throw new RuntimeException("Expected exception not thrown: " + + arrayClazz); + } catch (UnsupportedOperationException uoe) { + ; // Expected + } + } +} -- GitLab From a6f8a386efa7af162f4b815951287f0a9bc1f396 Mon Sep 17 00:00:00 2001 From: Tim Prinzing Date: Thu, 17 Feb 2022 17:34:39 +0000 Subject: [PATCH 114/203] 8281000: ClassLoader::registerAsParallelCapable throws NPE if caller is null Reviewed-by: erikj, ihse, mchung, bchristi --- make/test/JtregNativeJdk.gmk | 2 + .../share/classes/java/lang/ClassLoader.java | 10 +++ .../BadRegisterAsParallelCapableCaller.java | 57 ++++++++++++++ .../NullCallerClassLoaderTest.java | 71 +++++++++++++++++ .../exeNullCallerClassLoaderTest.c | 76 +++++++++++++++++++ 5 files changed, 216 insertions(+) create mode 100644 test/jdk/java/lang/ClassLoader/BadRegisterAsParallelCapableCaller.java create mode 100644 test/jdk/java/lang/ClassLoader/exeNullCallerClassLoaderTest/NullCallerClassLoaderTest.java create mode 100644 test/jdk/java/lang/ClassLoader/exeNullCallerClassLoaderTest/exeNullCallerClassLoaderTest.c diff --git a/make/test/JtregNativeJdk.gmk b/make/test/JtregNativeJdk.gmk index 974ab77cb7b..6797952bc05 100644 --- a/make/test/JtregNativeJdk.gmk +++ b/make/test/JtregNativeJdk.gmk @@ -62,6 +62,7 @@ ifeq ($(call isTargetOs, windows), true) WIN_LIB_JLI := $(SUPPORT_OUTPUTDIR)/native/java.base/libjli/jli.lib BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeJliLaunchTest := $(WIN_LIB_JLI) BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeCallerAccessTest := jvm.lib + BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeNullCallerClassLoaderTest := jvm.lib BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeNullCallerLookupTest := jvm.lib BUILD_JDK_JTREG_EXECUTABLES_LIBS_exerevokeall := advapi32.lib BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libAsyncStackWalk := /EHsc @@ -81,6 +82,7 @@ else endif BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeJliLaunchTest := -ljli BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeCallerAccessTest := -ljvm + BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeNullCallerClassLoaderTest := -ljvm BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeNullCallerLookupTest := -ljvm endif diff --git a/src/java.base/share/classes/java/lang/ClassLoader.java b/src/java.base/share/classes/java/lang/ClassLoader.java index ed5ad09da44..0aeb7620189 100644 --- a/src/java.base/share/classes/java/lang/ClassLoader.java +++ b/src/java.base/share/classes/java/lang/ClassLoader.java @@ -1606,9 +1606,16 @@ public abstract class ClassLoader { * *

      Note that once a class loader is registered as parallel capable, there * is no way to change it back.

      + *

      + * In cases where this method is called from a context where the caller is + * not a subclass of {@code ClassLoader} or there is no caller frame on the + * stack (e.g. when called directly from a JNI attached thread), + * {@code IllegalCallerException} is thrown. + *

      * * @return {@code true} if the caller is successfully registered as * parallel capable and {@code false} if otherwise. + * @throws IllegalCallerException if the caller is not a subclass of {@code ClassLoader} * * @see #isRegisteredAsParallelCapable() * @@ -1622,6 +1629,9 @@ public abstract class ClassLoader { // Caller-sensitive adapter method for reflective invocation @CallerSensitiveAdapter private static boolean registerAsParallelCapable(Class caller) { + if ((caller == null) || !ClassLoader.class.isAssignableFrom(caller)) { + throw new IllegalCallerException(caller + " not a subclass of ClassLoader"); + } return ParallelLoaders.register(caller.asSubclass(ClassLoader.class)); } diff --git a/test/jdk/java/lang/ClassLoader/BadRegisterAsParallelCapableCaller.java b/test/jdk/java/lang/ClassLoader/BadRegisterAsParallelCapableCaller.java new file mode 100644 index 00000000000..8b1c8d24d5e --- /dev/null +++ b/test/jdk/java/lang/ClassLoader/BadRegisterAsParallelCapableCaller.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8281000 + * @summary Test ClassLoader.isRegisteredAsParallelCapable() method with an + * invalid caller (non-JNI cases). This test uses reflection and opens + * the java.base module so it runs separate from behavior tests of + * isRegisteredParallelCapable to avoid side effects. + * @modules java.base/java.lang:open + * @run main/othervm BadRegisterAsParallelCapableCaller + */ + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class BadRegisterAsParallelCapableCaller { + + public static void main(String[] args) throws Exception { + + Throwable thrown = null; + final Method m = ClassLoader.class.getDeclaredMethod("registerAsParallelCapable"); + m.setAccessible(true); + try { + m.invoke(null); + } catch (InvocationTargetException ite) { + thrown = ite.getCause(); + } + if (! (thrown instanceof IllegalCallerException)) { + throw new RuntimeException("Didn't get expected IllegalCallerException, got "+ thrown); + } else { + System.out.println("Invalid caller threw IllegalCallerException as expected"); + } + } + +} diff --git a/test/jdk/java/lang/ClassLoader/exeNullCallerClassLoaderTest/NullCallerClassLoaderTest.java b/test/jdk/java/lang/ClassLoader/exeNullCallerClassLoaderTest/NullCallerClassLoaderTest.java new file mode 100644 index 00000000000..52427f01e6e --- /dev/null +++ b/test/jdk/java/lang/ClassLoader/exeNullCallerClassLoaderTest/NullCallerClassLoaderTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8281000 + * @summary Test uses custom launcher that starts VM using JNI that verifies + * ClassLoader.registerAsParallelCapable with null caller class + * throws an IllegalCallerException. + * @library /test/lib + * @requires os.family != "aix" + * @run main/native NullCallerClassLoaderTest + */ + +// Test disabled on AIX since we cannot invoke the JVM on the primordial thread. + +import java.io.File; +import java.util.Map; +import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class NullCallerClassLoaderTest { + public static void main(String[] args) throws IOException { + Path launcher = Path.of(System.getProperty("test.nativepath"), "NullCallerClassLoaderTest"); + ProcessBuilder pb = new ProcessBuilder(launcher.toString()); + Map env = pb.environment(); + + String libDir = Platform.libDir().toString(); + String vmDir = Platform.jvmLibDir().toString(); + + // set up shared library path + String sharedLibraryPathEnvName = Platform.sharedLibraryPathVariableName(); + env.compute(sharedLibraryPathEnvName, + (k, v) -> (v == null) ? libDir : v + File.pathSeparator + libDir); + env.compute(sharedLibraryPathEnvName, + (k, v) -> (v == null) ? vmDir : v + File.pathSeparator + vmDir); + + System.out.println("Launching: " + launcher + " shared library path: " + + env.get(sharedLibraryPathEnvName)); + new OutputAnalyzer(pb.start()) + .outputTo(System.out) + .errorTo(System.err) + .shouldHaveExitValue(0); + } +} + diff --git a/test/jdk/java/lang/ClassLoader/exeNullCallerClassLoaderTest/exeNullCallerClassLoaderTest.c b/test/jdk/java/lang/ClassLoader/exeNullCallerClassLoaderTest/exeNullCallerClassLoaderTest.c new file mode 100644 index 00000000000..d488c74bf6c --- /dev/null +++ b/test/jdk/java/lang/ClassLoader/exeNullCallerClassLoaderTest/exeNullCallerClassLoaderTest.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include + +#include "jni.h" +#include "assert.h" + +static jclass class_IllegalCallerException; + +int checkAndClearIllegalCallerExceptionThrown(JNIEnv *env) { + jthrowable t = (*env)->ExceptionOccurred(env); + if ((*env)->IsInstanceOf(env, t, class_IllegalCallerException) == JNI_TRUE) { + (*env)->ExceptionClear(env); + return JNI_TRUE; + } + return JNI_FALSE; +} + +int main(int argc, char** args) { + JavaVM *jvm; + JNIEnv *env; + JavaVMInitArgs vm_args; + JavaVMOption options[1]; + jint rc; + + + vm_args.version = JNI_VERSION_1_2; + vm_args.nOptions = 0; + vm_args.options = options; + + if ((rc = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args)) != JNI_OK) { + printf("ERROR: cannot create VM.\n"); + exit(-1); + } + class_IllegalCallerException = (*env)->FindClass(env, "java/lang/IllegalCallerException"); + assert (class_IllegalCallerException != NULL); + + // call ClassLoader.registerAsParallelCapable() + jclass class_ClassLoader = (*env)->FindClass(env, "java/lang/ClassLoader"); + assert(class_ClassLoader != NULL); + jmethodID mid_ClassLoader_registerAsParallelCapable = (*env)->GetStaticMethodID(env, class_ClassLoader, "registerAsParallelCapable", "()Z" ); + assert(mid_ClassLoader_registerAsParallelCapable != NULL); + jboolean b = (*env)->CallStaticBooleanMethod(env, class_ClassLoader, mid_ClassLoader_registerAsParallelCapable ); + if ((rc = checkAndClearIllegalCallerExceptionThrown(env)) != JNI_TRUE) { + printf("ERROR: Didn't get the expected IllegalCallerException.\n"); + exit(-1); + } + + printf("Expected IllegalCallerException was thrown\n"); + + (*jvm)->DestroyJavaVM(jvm); + return 0; +} + -- GitLab From cd9a3cf05b2c200709103e2e8596414a62a1c441 Mon Sep 17 00:00:00 2001 From: Mahendra Chhipa Date: Thu, 17 Feb 2022 17:45:06 +0000 Subject: [PATCH 115/203] 8282017: sun/net/www/protocol/https/HttpsURLConnection/B6216082.java fails with "SocketException: Unexpected end of file from server" Reviewed-by: dfuchs --- test/jdk/ProblemList.txt | 2 -- .../www/protocol/https/HttpsURLConnection/TunnelProxy.java | 6 +++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 81c2dffe2d1..7e19b4bd713 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -597,8 +597,6 @@ java/net/MulticastSocket/SetGetNetworkInterfaceTest.java 8219083 windows- java/net/ServerSocket/AcceptInheritHandle.java 8211854 aix-ppc64 -sun/net/www/protocol/https/HttpsURLConnection/B6216082.java 8282017 generic-all - ############################################################################ # jdk_nio diff --git a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/TunnelProxy.java b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/TunnelProxy.java index 979e8be9acd..9cec3987d9e 100644 --- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/TunnelProxy.java +++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/TunnelProxy.java @@ -261,9 +261,9 @@ public class TunnelProxy { boolean res; try { InputStream is = new BufferedInputStream (new NioInputStream (chan)); - String requestline = readLine (is); - HttpHeaderParser mhead = new HttpHeaderParser (is); - String[] req = requestline.split (" "); + HttpHeaderParser mHead = new HttpHeaderParser (is); + String requestLine = mHead.getRequestDetails(); + String[] req = requestLine.split (" "); if (req.length < 2) { /* invalid request line */ return false; -- GitLab From 129277653e51e9b1387ecee279a6ccee9199c8ff Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Thu, 17 Feb 2022 19:03:08 +0000 Subject: [PATCH 116/203] 8281317: CompactNumberFormat displays 4-digit values when rounding to a new range Reviewed-by: joehw --- .../java/text/CompactNumberFormat.java | 41 ++++++++++++++++--- .../TestCompactPatternsValidity.java | 12 +++--- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/src/java.base/share/classes/java/text/CompactNumberFormat.java b/src/java.base/share/classes/java/text/CompactNumberFormat.java index 0449133d5b8..551945cc832 100644 --- a/src/java.base/share/classes/java/text/CompactNumberFormat.java +++ b/src/java.base/share/classes/java/text/CompactNumberFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -589,6 +589,10 @@ public final class CompactNumberFormat extends NumberFormat { if (compactDataIndex != -1) { long divisor = (Long) divisors.get(compactDataIndex); int iPart = getIntegerPart(number, divisor); + if (checkIncrement(iPart, compactDataIndex, divisor)) { + divisor = (Long) divisors.get(++compactDataIndex); + iPart = getIntegerPart(number, divisor); + } String prefix = getAffix(false, true, isNegative, compactDataIndex, iPart); String suffix = getAffix(false, false, isNegative, compactDataIndex, iPart); @@ -658,6 +662,10 @@ public final class CompactNumberFormat extends NumberFormat { if (compactDataIndex != -1) { long divisor = (Long) divisors.get(compactDataIndex); int iPart = getIntegerPart(number, divisor); + if (checkIncrement(iPart, compactDataIndex, divisor)) { + divisor = (Long) divisors.get(++compactDataIndex); + iPart = getIntegerPart(number, divisor); + } String prefix = getAffix(false, true, isNegative, compactDataIndex, iPart); String suffix = getAffix(false, false, isNegative, compactDataIndex, iPart); if (!prefix.isEmpty() || !suffix.isEmpty()) { @@ -753,6 +761,10 @@ public final class CompactNumberFormat extends NumberFormat { if (compactDataIndex != -1) { Number divisor = divisors.get(compactDataIndex); int iPart = getIntegerPart(number.doubleValue(), divisor.doubleValue()); + if (checkIncrement(iPart, compactDataIndex, divisor.doubleValue())) { + divisor = divisors.get(++compactDataIndex); + iPart = getIntegerPart(number.doubleValue(), divisor.doubleValue()); + } String prefix = getAffix(false, true, isNegative, compactDataIndex, iPart); String suffix = getAffix(false, false, isNegative, compactDataIndex, iPart); if (!prefix.isEmpty() || !suffix.isEmpty()) { @@ -820,6 +832,10 @@ public final class CompactNumberFormat extends NumberFormat { if (compactDataIndex != -1) { Number divisor = divisors.get(compactDataIndex); int iPart = getIntegerPart(number.doubleValue(), divisor.doubleValue()); + if (checkIncrement(iPart, compactDataIndex, divisor.doubleValue())) { + divisor = divisors.get(++compactDataIndex); + iPart = getIntegerPart(number.doubleValue(), divisor.doubleValue()); + } String prefix = getAffix(false, true, isNegative, compactDataIndex, iPart); String suffix = getAffix(false, false, isNegative, compactDataIndex, iPart); if (!prefix.isEmpty() || !suffix.isEmpty()) { @@ -875,7 +891,7 @@ public final class CompactNumberFormat extends NumberFormat { * Appends the {@code prefix} to the {@code result} and also set the * {@code NumberFormat.Field.SIGN} and {@code NumberFormat.Field.PREFIX} * field positions. - * @param result the resulting string, where the pefix is to be appended + * @param result the resulting string, where the prefix is to be appended * @param prefix prefix to append * @param delegate notified of the locations of * {@code NumberFormat.Field.SIGN} and @@ -910,7 +926,7 @@ public final class CompactNumberFormat extends NumberFormat { * @param result the resulting string, where the text is to be appended * @param string the text to append * @param delegate notified of the locations of sub fields - * @param positions a list of {@code FieldPostion} in the given + * @param positions a list of {@code FieldPosition} in the given * string */ private void append(StringBuffer result, String string, @@ -956,10 +972,10 @@ public final class CompactNumberFormat extends NumberFormat { } /** - * Returns a list of {@code FieldPostion} in the given {@code pattern}. + * Returns a list of {@code FieldPosition} in the given {@code pattern}. * @param pattern the pattern to be parsed for {@code FieldPosition} * @param field whether a PREFIX or SUFFIX field - * @return a list of {@code FieldPostion} + * @return a list of {@code FieldPosition} */ private List getFieldPositions(String pattern, Field field) { List positions = new ArrayList<>(); @@ -1769,7 +1785,7 @@ public final class CompactNumberFormat extends NumberFormat { if (cnfMultiplier.longValue() != 1L) { double doubleResult = number.doubleValue() * cnfMultiplier.doubleValue(); doubleResult = (double) convertIfNegative(doubleResult, status, gotLongMin); - // Check if a double can be represeneted as a long + // Check if a double can be represented as a long long longResult = (long) doubleResult; gotDouble = ((doubleResult != (double) longResult) || (doubleResult == 0.0 && 1 / doubleResult < 0.0)); @@ -2396,6 +2412,19 @@ public final class CompactNumberFormat extends NumberFormat { .divide(BigDecimal.valueOf(divisor), roundingMode).intValue(); } + // Checks whether the iPart is incremented by the BigDecimal division in + // getIntegerPart(), and affects the compact number index. + private boolean checkIncrement(int iPart, int index, double divisor) { + if (index < compactPatterns.length - 1 && + !"".equals(compactPatterns[index])) { // ignore empty pattern + var nextDiv = divisors.get(index + 1).doubleValue(); + if (divisor != nextDiv) { + return Math.log10(iPart) == Math.log10(nextDiv) - Math.log10(divisor); + } + } + return false; + } + /** * Returns LDML's tag from the plurals rules * diff --git a/test/jdk/java/text/Format/CompactNumberFormat/TestCompactPatternsValidity.java b/test/jdk/java/text/Format/CompactNumberFormat/TestCompactPatternsValidity.java index 6ca1f25ea90..8476b568ba0 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/TestCompactPatternsValidity.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/TestCompactPatternsValidity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,7 @@ */ /* * @test - * @bug 8177552 8217254 8251499 + * @bug 8177552 8217254 8251499 8281317 * @summary Checks the validity of compact number patterns specified through * CompactNumberFormat constructor * @run testng/othervm TestCompactPatternsValidity @@ -101,8 +101,9 @@ public class TestCompactPatternsValidity { {COMPACT_PATTERN5, List.of(100, 1000, 30000), List.of("100", "1K", "K3")}, {COMPACT_PATTERN6, List.of(20.99, 1000, 30000), List.of("21", ".1K", ".30K")}, {COMPACT_PATTERN7, List.of(100, 1000, new BigInteger("12345678987654321")), List.of("100", "1K,", "12345678987654K,")}, - {COMPACT_PATTERN8, List.of(new BigInteger("223565686837667632"), new BigDecimal("12322456774334.89766"), 30000, 3456.78), - List.of("223566T", "12T", "30K", "3K")}, + {COMPACT_PATTERN8, List.of(new BigInteger("223565686837667632"), new BigDecimal("12322456774334.89766"), 30000, 3456.78, + new BigInteger("999999999999"), new BigDecimal("999999999999.0"), 999_999, 999_999_999), + List.of("223566T", "12T", "30K", "3K", "1T", "1T", "1M", "1B")}, {COMPACT_PATTERN9, List.of(new BigInteger("223566000000000000"), new BigDecimal("12345678987654567"), 30000, 3000), List.of("223,566,000,000,000,000", "12,345,678,987,654,567", "30,000", "3,000")}, {COMPACT_PATTERN10, List.of(new BigInteger("100000000000000000"), new BigInteger("10000000000000000000"), new BigDecimal("555555555555555555555.89766"), 30000), @@ -110,7 +111,8 @@ public class TestCompactPatternsValidity { {COMPACT_PATTERN11, List.of(20.99, -20.99, 1000, -1000, 30000, -30000, new BigInteger("12345678987654321"), new BigInteger("-12345678987654321")), List.of("21", "-21", "elfu 1", "elfu -1", "elfu 30", "elfu -30", "milioni 12345678988", "milioni -12345678988")}, {COMPACT_PATTERN12, List.of(0, 500, -500, 30000, -3000, 5000000), List.of("0", "H5H", "H-5H", "30K", "3K-", "H50G")}, - {COMPACT_PATTERN13, List.of(1000, new BigInteger("10000000000000000000")), List.of("Thousand", "BeyondLong")}, + {COMPACT_PATTERN13, List.of(1000, new BigInteger("10000000000000000000"), new BigDecimal("9999999999999999999.9")), + List.of("Thousand", "BeyondLong", "BeyondLong")}, }; } -- GitLab From 69fc273f202352f74a313c37db0198be2be08616 Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Thu, 17 Feb 2022 20:56:46 +0000 Subject: [PATCH 117/203] 8282075: ProblemList 3 compiler/whitebox tests on macosx-x64 Reviewed-by: mikael, bpb --- test/hotspot/jtreg/ProblemList.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index a09185a4b19..9c9b1b0b3c5 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -67,9 +67,9 @@ compiler/rtm/print/TestPrintPreciseRTMLockingStatistics.java 8183263 generic-x64 compiler/c2/Test8004741.java 8235801 generic-all -compiler/whitebox/ClearMethodStateTest.java 8265360 macosx-aarch64 -compiler/whitebox/EnqueueMethodForCompilationTest.java 8265360 macosx-aarch64 -compiler/whitebox/MakeMethodNotCompilableTest.java 8265360 macosx-aarch64 +compiler/whitebox/ClearMethodStateTest.java 8265360 macosx-generic +compiler/whitebox/EnqueueMethodForCompilationTest.java 8265360 macosx-generic +compiler/whitebox/MakeMethodNotCompilableTest.java 8265360 macosx-generic compiler/codecache/jmx/PoolsIndependenceTest.java 8264632 macosx-generic compiler/codecache/TestStressCodeBuffers.java 8272094 generic-aarch64 -- GitLab From f830cbec909b91ad0f00f46a3496d83ecb5912ed Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Thu, 17 Feb 2022 21:18:15 +0000 Subject: [PATCH 118/203] 8188073: Add Capstone as backend for hsdis Co-authored-by: Magnus Ihse Bursie Co-authored-by: Jorn Vernee Reviewed-by: erikj --- make/Hsdis.gmk | 151 +++++++++++------- make/autoconf/help.m4 | 4 + make/autoconf/jdk-options.m4 | 42 ++++- make/autoconf/spec.gmk.in | 3 +- src/utils/hsdis/README | 102 ------------ src/utils/hsdis/README.md | 133 +++++++++++++++ .../{hsdis.c => binutils/hsdis-binutils.c} | 0 src/utils/hsdis/capstone/hsdis-capstone.c | 97 +++++++++++ src/utils/hsdis/hsdis.h | 20 ++- 9 files changed, 381 insertions(+), 171 deletions(-) delete mode 100644 src/utils/hsdis/README create mode 100644 src/utils/hsdis/README.md rename src/utils/hsdis/{hsdis.c => binutils/hsdis-binutils.c} (100%) create mode 100644 src/utils/hsdis/capstone/hsdis-capstone.c diff --git a/make/Hsdis.gmk b/make/Hsdis.gmk index 02f09b320f0..fa5238c80f6 100644 --- a/make/Hsdis.gmk +++ b/make/Hsdis.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -36,89 +36,111 @@ include JdkNativeCompilation.gmk HSDIS_OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/hsdis +HSDIS_TOOLCHAIN := TOOLCHAIN_DEFAULT +HSDIS_TOOLCHAIN_CFLAGS := $(CFLAGS_JDKLIB) +HSDIS_TOOLCHAIN_LDFLAGS := $(LDFLAGS_JDKLIB) + ifeq ($(call isTargetOs, windows), true) INSTALLED_HSDIS_DIR := $(JDK_OUTPUTDIR)/bin + IMAGE_HSDIS_DIR := $(JDK_IMAGE_DIR)/bin +else + INSTALLED_HSDIS_DIR := $(JDK_OUTPUTDIR)/lib + IMAGE_HSDIS_DIR := $(JDK_IMAGE_DIR)/lib +endif - # On windows, we need to "fake" a completely different toolchain using gcc - # instead of the normal microsoft toolchain. This is quite hacky... +ifeq ($(HSDIS_BACKEND), capstone) + ifeq ($(call isTargetCpuArch, x86), true) + CAPSTONE_ARCH := CS_ARCH_X86 + CAPSTONE_MODE := CS_MODE_$(OPENJDK_TARGET_CPU_BITS) + else ifeq ($(call isTargetCpuArch, aarch64), true) + CAPSTONE_ARCH := CS_ARCH_ARM64 + CAPSTONE_MODE := CS_MODE_ARM + else + $(error No support for Capstone on this platform) + endif - MINGW_BASE := x86_64-w64-mingw32 + HSDIS_CFLAGS += -DCAPSTONE_ARCH=$(CAPSTONE_ARCH) \ + -DCAPSTONE_MODE=$(CAPSTONE_MODE) +endif + +ifeq ($(HSDIS_BACKEND), binutils) + ifeq ($(call isTargetOs, windows), true) + # On windows, we need to "fake" a completely different toolchain using gcc + # instead of the normal microsoft toolchain. This is quite hacky... - MINGW_SYSROOT = $(shell $(MINGW_BASE)-gcc -print-sysroot) - ifeq ($(wildcard $(MINGW_SYSROOT)), ) - # Use fallback path - MINGW_SYSROOT := /usr/$(MINGW_BASE) + MINGW_BASE := x86_64-w64-mingw32 + + MINGW_SYSROOT = $(shell $(MINGW_BASE)-gcc -print-sysroot) ifeq ($(wildcard $(MINGW_SYSROOT)), ) - $(error mingw sysroot not found) + # Use fallback path + MINGW_SYSROOT := /usr/$(MINGW_BASE) + ifeq ($(wildcard $(MINGW_SYSROOT)), ) + $(error mingw sysroot not found) + endif endif - endif - $(eval $(call DefineNativeToolchain, TOOLCHAIN_MINGW, \ - CC := $(MINGW_BASE)-gcc, \ - LD := $(MINGW_BASE)-ld, \ - OBJCOPY := $(MINGW_BASE)-objcopy, \ - RC := $(RC), \ - SYSROOT_CFLAGS := --sysroot=$(MINGW_SYSROOT), \ - SYSROOT_LDFLAGS := --sysroot=$(MINGW_SYSROOT), \ - )) - - MINGW_SYSROOT_LIB_PATH := $(MINGW_SYSROOT)/mingw/lib - ifeq ($(wildcard $(MINGW_SYSROOT_LIB_PATH)), ) - # Try without mingw - MINGW_SYSROOT_LIB_PATH := $(MINGW_SYSROOT)/lib + $(eval $(call DefineNativeToolchain, TOOLCHAIN_MINGW, \ + CC := $(MINGW_BASE)-gcc, \ + LD := $(MINGW_BASE)-ld, \ + OBJCOPY := $(MINGW_BASE)-objcopy, \ + RC := $(RC), \ + SYSROOT_CFLAGS := --sysroot=$(MINGW_SYSROOT), \ + SYSROOT_LDFLAGS := --sysroot=$(MINGW_SYSROOT), \ + )) + + MINGW_SYSROOT_LIB_PATH := $(MINGW_SYSROOT)/mingw/lib ifeq ($(wildcard $(MINGW_SYSROOT_LIB_PATH)), ) - $(error mingw sysroot lib path not found) + # Try without mingw + MINGW_SYSROOT_LIB_PATH := $(MINGW_SYSROOT)/lib + ifeq ($(wildcard $(MINGW_SYSROOT_LIB_PATH)), ) + $(error mingw sysroot lib path not found) + endif endif - endif - MINGW_VERSION = $(shell $(MINGW_BASE)-gcc -v 2>&1 | $(GREP) "gcc version" | $(CUT) -d " " -f 3) - MINGW_GCC_LIB_PATH := /usr/lib/gcc/$(MINGW_BASE)/$(MINGW_VERSION) - ifeq ($(wildcard $(MINGW_GCC_LIB_PATH)), ) - # Try using only major version number - MINGW_VERSION_MAJOR := $(firstword $(subst ., , $(MINGW_VERSION))) - MINGW_GCC_LIB_PATH := /usr/lib/gcc/$(MINGW_BASE)/$(MINGW_VERSION_MAJOR) + MINGW_VERSION = $(shell $(MINGW_BASE)-gcc -v 2>&1 | $(GREP) "gcc version" | $(CUT) -d " " -f 3) + MINGW_GCC_LIB_PATH := /usr/lib/gcc/$(MINGW_BASE)/$(MINGW_VERSION) ifeq ($(wildcard $(MINGW_GCC_LIB_PATH)), ) - $(error mingw gcc lib path not found) + # Try using only major version number + MINGW_VERSION_MAJOR := $(firstword $(subst ., , $(MINGW_VERSION))) + MINGW_GCC_LIB_PATH := /usr/lib/gcc/$(MINGW_BASE)/$(MINGW_VERSION_MAJOR) + ifeq ($(wildcard $(MINGW_GCC_LIB_PATH)), ) + $(error mingw gcc lib path not found) + endif endif - endif - TOOLCHAIN_TYPE := gcc - OPENJDK_TARGET_OS := linux - CC_OUT_OPTION := -o$(SPACE) - LD_OUT_OPTION := -o$(SPACE) - GENDEPS_FLAGS := -MMD -MF - CFLAGS_DEBUG_SYMBOLS := -g - DISABLED_WARNINGS := - DISABLE_WARNING_PREFIX := -Wno- - CFLAGS_WARNINGS_ARE_ERRORS := -Werror - SHARED_LIBRARY_FLAGS := -shared - - HSDIS_TOOLCHAIN := TOOLCHAIN_MINGW - HSDIS_TOOLCHAIN_CFLAGS := - HSDIS_TOOLCHAIN_LDFLAGS := -L$(MINGW_GCC_LIB_PATH) -L$(MINGW_SYSROOT_LIB_PATH) - MINGW_DLLCRT := $(MINGW_SYSROOT_LIB_PATH)/dllcrt2.o - HSDIS_TOOLCHAIN_LIBS := $(MINGW_DLLCRT) -lmingw32 -lgcc -lgcc_eh -lmoldname \ - -lmingwex -lmsvcrt -lpthread -ladvapi32 -lshell32 -luser32 -lkernel32 -else - INSTALLED_HSDIS_DIR := $(JDK_OUTPUTDIR)/lib - - HSDIS_TOOLCHAIN := TOOLCHAIN_DEFAULT - HSDIS_TOOLCHAIN_CFLAGS := $(CFLAGS_JDKLIB) - HSDIS_TOOLCHAIN_LDFLAGS := $(LDFLAGS_JDKLIB) - HSDIS_TOOLCHAIN_LIBS := -ldl + TOOLCHAIN_TYPE := gcc + OPENJDK_TARGET_OS := linux + CC_OUT_OPTION := -o$(SPACE) + LD_OUT_OPTION := -o$(SPACE) + GENDEPS_FLAGS := -MMD -MF + CFLAGS_DEBUG_SYMBOLS := -g + DISABLED_WARNINGS := + DISABLE_WARNING_PREFIX := -Wno- + CFLAGS_WARNINGS_ARE_ERRORS := -Werror + SHARED_LIBRARY_FLAGS := -shared + + HSDIS_TOOLCHAIN := TOOLCHAIN_MINGW + HSDIS_TOOLCHAIN_CFLAGS := + HSDIS_TOOLCHAIN_LDFLAGS := -L$(MINGW_GCC_LIB_PATH) -L$(MINGW_SYSROOT_LIB_PATH) + MINGW_DLLCRT := $(MINGW_SYSROOT_LIB_PATH)/dllcrt2.o + HSDIS_TOOLCHAIN_LIBS := $(MINGW_DLLCRT) -lmingw32 -lgcc -lgcc_eh -lmoldname \ + -lmingwex -lmsvcrt -lpthread -ladvapi32 -lshell32 -luser32 -lkernel32 + else + HSDIS_TOOLCHAIN_LIBS := -ldl + endif endif - $(eval $(call SetupJdkLibrary, BUILD_HSDIS, \ NAME := hsdis, \ - SRC := $(TOPDIR)/src/utils/hsdis, \ + SRC := $(TOPDIR)/src/utils/hsdis/$(HSDIS_BACKEND), \ + EXTRA_HEADER_DIRS := $(TOPDIR)/src/utils/hsdis, \ TOOLCHAIN := $(HSDIS_TOOLCHAIN), \ OUTPUT_DIR := $(HSDIS_OUTPUT_DIR), \ OBJECT_DIR := $(HSDIS_OUTPUT_DIR), \ DISABLED_WARNINGS_gcc := undef format-nonliteral sign-compare, \ DISABLED_WARNINGS_clang := undef format-nonliteral, \ CFLAGS := $(HSDIS_TOOLCHAIN_CFLAGS) $(HSDIS_CFLAGS), \ - LDFLAGS := $(HSDIS_TOOLCHAIN_LDFLAGS) $(SHARED_LIBRARY_FLAGS), \ + LDFLAGS := $(HSDIS_TOOLCHAIN_LDFLAGS) $(HSDIS_LDFLAGS) $(SHARED_LIBRARY_FLAGS), \ LIBS := $(HSDIS_LIBS) $(HSDIS_TOOLCHAIN_LIBS), \ )) @@ -129,13 +151,18 @@ TARGETS += build INSTALLED_HSDIS_NAME := hsdis-$(OPENJDK_TARGET_CPU_LEGACY_LIB)$(SHARED_LIBRARY_SUFFIX) INSTALLED_HSDIS := $(INSTALLED_HSDIS_DIR)/$(INSTALLED_HSDIS_NAME) +INSTALLED_HSDIS_IMAGE := $(IMAGE_HSDIS_DIR)/$(INSTALLED_HSDIS_NAME) $(INSTALLED_HSDIS): $(BUILD_HSDIS_TARGET) - $(call LogWarn, NOTE: The resulting build might not be redistributable. Seek legal advice before distibuting.) + ifeq ($(HSDIS_BACKEND), binutils) + $(call LogWarn, NOTE: The resulting build might not be redistributable. Seek legal advice before distributing.) + endif $(install-file) +$(INSTALLED_HSDIS_IMAGE): $(INSTALLED_HSDIS) + $(install-file) -install: $(INSTALLED_HSDIS) +install: $(INSTALLED_HSDIS_IMAGE) TARGETS += install diff --git a/make/autoconf/help.m4 b/make/autoconf/help.m4 index 09e82e36c94..486e78d4fcf 100644 --- a/make/autoconf/help.m4 +++ b/make/autoconf/help.m4 @@ -117,6 +117,8 @@ apt_help() { PKGHANDLER_COMMAND="sudo apt-get install ccache" ;; dtrace) PKGHANDLER_COMMAND="sudo apt-get install systemtap-sdt-dev" ;; + capstone) + PKGHANDLER_COMMAND="sudo apt-get install libcapstone-dev" ;; esac } @@ -168,6 +170,8 @@ brew_help() { PKGHANDLER_COMMAND="brew install freetype" ;; ccache) PKGHANDLER_COMMAND="brew install ccache" ;; + capstone) + PKGHANDLER_COMMAND="brew install capstone" ;; esac } diff --git a/make/autoconf/jdk-options.m4 b/make/autoconf/jdk-options.m4 index 0a7145c9116..7692407316a 100644 --- a/make/autoconf/jdk-options.m4 +++ b/make/autoconf/jdk-options.m4 @@ -811,7 +811,10 @@ AC_DEFUN([JDKOPT_BUILD_BINUTILS], AC_DEFUN_ONCE([JDKOPT_SETUP_HSDIS], [ AC_ARG_WITH([hsdis], [AS_HELP_STRING([--with-hsdis], - [what hsdis backend to use ('none', 'binutils') @<:@none@:>@])]) + [what hsdis backend to use ('none', 'capstone', 'binutils') @<:@none@:>@])]) + + AC_ARG_WITH(capstone, [AS_HELP_STRING([--with-capstone], + [where to find the Capstone files needed for hsdis/capstone])]) AC_ARG_WITH([binutils], [AS_HELP_STRING([--with-binutils], [where to find the binutils files needed for hsdis/binutils])]) @@ -826,6 +829,41 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_HSDIS], elif test "x$with_hsdis" = xnone || test "x$with_hsdis" = xno || test "x$with_hsdis" = x; then HSDIS_BACKEND=none AC_MSG_RESULT(['none', hsdis will not be built]) + elif test "x$with_hsdis" = xcapstone; then + HSDIS_BACKEND=capstone + AC_MSG_RESULT(['capstone']) + + if test "x$with_capstone" != x; then + AC_MSG_CHECKING([for capstone]) + CAPSTONE="$with_capstone" + AC_MSG_RESULT([$CAPSTONE]) + + HSDIS_CFLAGS="-I${CAPSTONE}/include/capstone" + if test "x$OPENJDK_TARGET_OS" != xwindows; then + HSDIS_LDFLAGS="-L${CAPSTONE}/lib" + HSDIS_LIBS="-lcapstone" + else + HSDIS_LDFLAGS="-nodefaultlib:libcmt.lib" + HSDIS_LIBS="${CAPSTONE}/capstone.lib" + fi + else + if test "x$OPENJDK_TARGET_OS" = xwindows; then + # There is no way to auto-detect capstone on Windowos + AC_MSG_NOTICE([You must specify capstone location using --with-capstone=]) + AC_MSG_ERROR([Cannot continue]) + fi + + PKG_CHECK_MODULES(CAPSTONE, capstone, [CAPSTONE_FOUND=yes], [CAPSTONE_FOUND=no]) + if test "x$CAPSTONE_FOUND" = xyes; then + HSDIS_CFLAGS="$CAPSTONE_CFLAGS" + HSDIS_LDFLAGS="$CAPSTONE_LDFLAGS" + HSDIS_LIBS="$CAPSTONE_LIBS" + else + HELP_MSG_MISSING_DEPENDENCY([capstone]) + AC_MSG_NOTICE([Cannot locate capstone which is needed for hsdis/capstone. Try using --with-capstone=. $HELP_MSG]) + AC_MSG_ERROR([Cannot continue]) + fi + fi elif test "x$with_hsdis" = xbinutils; then HSDIS_BACKEND=binutils AC_MSG_RESULT(['binutils']) @@ -853,6 +891,7 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_HSDIS], test -e $BINUTILS_DIR/opcodes/libopcodes.a && \ test -e $BINUTILS_DIR/libiberty/libiberty.a; then HSDIS_CFLAGS="-I$BINUTILS_DIR/include -I$BINUTILS_DIR/bfd -DLIBARCH_$OPENJDK_TARGET_CPU_LEGACY_LIB" + HSDIS_LDFLAGS="" HSDIS_LIBS="$BINUTILS_DIR/bfd/libbfd.a $BINUTILS_DIR/opcodes/libopcodes.a $BINUTILS_DIR/libiberty/libiberty.a $BINUTILS_DIR/zlib/libz.a" fi fi @@ -895,5 +934,6 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_HSDIS], AC_SUBST(HSDIS_BACKEND) AC_SUBST(HSDIS_CFLAGS) + AC_SUBST(HSDIS_LDFLAGS) AC_SUBST(HSDIS_LIBS) ]) diff --git a/make/autoconf/spec.gmk.in b/make/autoconf/spec.gmk.in index 3dce730970e..d286d5cc2cc 100644 --- a/make/autoconf/spec.gmk.in +++ b/make/autoconf/spec.gmk.in @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -361,6 +361,7 @@ ALLOW_ABSOLUTE_PATHS_IN_OUTPUT := @ALLOW_ABSOLUTE_PATHS_IN_OUTPUT@ HSDIS_BACKEND := @HSDIS_BACKEND@ HSDIS_CFLAGS := @HSDIS_CFLAGS@ +HSDIS_LDFLAGS := @HSDIS_LDFLAGS@ HSDIS_LIBS := @HSDIS_LIBS@ # The boot jdk to use. This is overridden in bootcycle-spec.gmk. Make sure to keep diff --git a/src/utils/hsdis/README b/src/utils/hsdis/README deleted file mode 100644 index 64a8ab61a7c..00000000000 --- a/src/utils/hsdis/README +++ /dev/null @@ -1,102 +0,0 @@ -Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. -DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - -The Universal Permissive License (UPL), Version 1.0 - -Subject to the condition set forth below, permission is hereby granted to -any person obtaining a copy of this software, associated documentation -and/or data (collectively the "Software"), free of charge and under any -and all copyright rights in the Software, and any and all patent rights -owned or freely licensable by each licensor hereunder covering either (i) -the unmodified Software as contributed to or provided by such licensor, -or (ii) the Larger Works (as defined below), to deal in both - -(a) the Software, and - -(b) any piece of software and/or hardware listed in the lrgrwrks.txt file -if one is included with the Software (each a "Larger Work" to which the -Software is contributed by such licensors), - -without restriction, including without limitation the rights to copy, -create derivative works of, display, perform, and distribute the Software -and make, use, sell, offer for sale, import, export, have made, and have -sold the Software and the Larger Work(s), and to sublicense the foregoing -rights on either these or other terms. - -This license is subject to the following condition: - -The above copyright notice and either this complete permission notice or -at a minimum a reference to the UPL must be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -USE OR OTHER DEALINGS IN THE SOFTWARE. - -Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -or visit www.oracle.com if you need additional information or have any -questions. - -________________________________________________________________________ - -'hsdis': A HotSpot plugin for disassembling dynamically generated code. - -The files in this directory are built independently of the HotSpot JVM. - -* Building - -To build this project you need a copy of GNU binutils to build against. It is -known to work with binutils 2.37. Building against versions older than 2.29 is -not supported. Download a copy of the software from -http://directory.fsf.org/project/binutils or one of its mirrors. - -To build this library, you must enable building in configure by "bash configure ---with-hsdis=binutils". - -You must also specify where binutils is located. To facilitate building, you can -point to a place where the (unpacked) binutils sources are located using -"--with-binutils-src=", and configure will build binutils for you. On -repeated runs, you can keep this command line option, since configure will -figure out that the binutils binaries are already present and skip building, or -you can replace it with "--with-binutils=". - -If you have pre-built binutils binaries, you can point to them directly using -"--with-binutils=". - -If you want to build hsdis with binutils provided by system -(e.g. binutils-devel from Fedora, binutils-dev from Ubuntu), you can pass -"--with-binutils=system". "system" is available on Linux only. - -When you have created a proper configuration, you can then build the hsdis -library using "make build-hsdis". - -* Building on Windows - -On Windows, the normal Microsoft Visual Studio toolchain cannot build binutils. -Instead we need to use the mingw compiler. This is available as a cygwin -package. You need to install the "gcc-core" and "mingw64-x86_64-gcc-core" -packages (or "mingw64-i686-gcc-core", if you want the 32-bit version) and -"mingw64-x86_64-glib2.0". - -* Installing - -To build the hsdis library, run "make build-hsdis". This will build the library -in a separate directory, but not make it available to the JDK in the -configuration. To actually install it in the JDK, run "make install-hsdis". - -Note: The resulting build may not be distributable. Please get legal advice if -you intend to distribute the result of your build. - -* Using the library - -The hsdis library will be automatically loaded by Hotspot when you use the -diagnostic option "-XX:+PrintAssembly". Note that since this is a diagnostic -option, you need to unlock these first, so in practice you activate it using -"-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly". - -More information is available at the wiki -[https://wiki.openjdk.java.net/display/HotSpot/PrintAssembly]. diff --git a/src/utils/hsdis/README.md b/src/utils/hsdis/README.md new file mode 100644 index 00000000000..bc8bdb767b7 --- /dev/null +++ b/src/utils/hsdis/README.md @@ -0,0 +1,133 @@ +``` +Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to +any person obtaining a copy of this software, associated documentation +and/or data (collectively the "Software"), free of charge and under any +and all copyright rights in the Software, and any and all patent rights +owned or freely licensable by each licensor hereunder covering either (i) +the unmodified Software as contributed to or provided by such licensor, +or (ii) the Larger Works (as defined below), to deal in both + +(a) the Software, and + +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file +if one is included with the Software (each a "Larger Work" to which the +Software is contributed by such licensors), + +without restriction, including without limitation the rights to copy, +create derivative works of, display, perform, and distribute the Software +and make, use, sell, offer for sale, import, export, have made, and have +sold the Software and the Larger Work(s), and to sublicense the foregoing +rights on either these or other terms. + +This license is subject to the following condition: + +The above copyright notice and either this complete permission notice or +at a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. + +Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +or visit www.oracle.com if you need additional information or have any +questions. +``` + +--- + +# hsdis - a HotSpot plugin for disassembling dynamically generated code + +The files in this directory are built independently of the HotSpot JVM. + +hsdis is an interface exposed by Hotspot. There are several backends that +implement this interface, using different disassembly engines. Included in the +JDK is support for building hsdis with Capstone or GNU binutils. The interface +is fairly straightforward and easy to implement using other backends. + +## Building and installing + +To compile hsdis, you need to activate hsdis support, and select the proper +backend to use. This is done with the configure switch `--with-hsdis=`, +where `` is either `capstone` or `binutils`. For details, see the +sections on the respective backends below. + +To build the hsdis library, run `make build-hsdis`. This will build the library +in a separate directory, but not make it available to the JDK in the +configuration. To actually install it in the JDK, run `make install-hsdis`. + +**NOTE:** If you do this using the binutils backend, the resulting build may not +be distributable. Please get legal advice if you intend to distribute the result +of your build. + +## Using the library + +The hsdis library will be automatically loaded by Hotspot when you use the +diagnostic option `-XX:+PrintAssembly`. Note that since this is a diagnostic +option, you need to unlock these first, so in practice you activate it using +`-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly`. + +More information is available at the [HotSpot +wiki](https://wiki.openjdk.java.net/display/HotSpot/PrintAssembly). + +## Building with Capstone + +To build this project using Capstone you need to have Capstone installed. +Typical ways of installation can be `sudo apt install libcapstone-dev` (on +Debian and derivatives), or `brew install capstone` (on macOS with Homebrew). +For Windows, you need to download the "Core Engine", and unzip it. See the +[Capstone Download +page](https://www.capstone-engine.org/download.html#windows---core-engine-) for +up-to-date download links. + +This has been tested with Capstone v4.0.2, but earlier (and later) versions are +also likely to work. + +To build hsdis using Capstone, you must enable it in configure by `bash +configure --with-hsdis=capstone`. + +On Linux and macOS, the location Capstone can most often be auto-detected. If +this fails, or if you are building on Windows, you need to specify where +Capstone is located using `--with-capstone=`. This path should point to +where you have extracted the Core Engine zip file. + +## Building with binutils + +To build this project using binutils you need a copy of GNU binutils to build +against. It is known to work with binutils 2.37. Building against versions older +than 2.29 is not supported. Download a copy of the software from [FSF binutils +page](http://directory.fsf.org/project/binutils) or one of its mirrors. + +To build this library, you must enable building in configure by `bash configure +--with-hsdis=binutils`. + +You must also specify where binutils is located. To facilitate building, you can +point to a place where the (unpacked) binutils sources are located using +`--with-binutils-src=`, and configure will build binutils for you. On +repeated runs, you can keep this command line option, since configure will +figure out that the binutils binaries are already present and skip building, or +you can replace it with `--with-binutils=`. + +If you have pre-built binutils binaries, you can point to them directly using +`--with-binutils=`. + +If you want to build hsdis with binutils provided by system (e.g. binutils-devel +from Fedora, binutils-dev from Ubuntu), you can pass `--with-binutils=system`. +`system` is available on Linux only. + +### Building with binutils on Windows + +On Windows, the normal Microsoft Visual Studio toolchain cannot build binutils. +Instead we need to use the mingw compiler. This is available as a cygwin +package. You need to install the `gcc-core` and `mingw64-x86_64-gcc-core` +packages (or `mingw64-i686-gcc-core`, if you want the 32-bit version) and +`mingw64-x86_64-glib2.0`. diff --git a/src/utils/hsdis/hsdis.c b/src/utils/hsdis/binutils/hsdis-binutils.c similarity index 100% rename from src/utils/hsdis/hsdis.c rename to src/utils/hsdis/binutils/hsdis-binutils.c diff --git a/src/utils/hsdis/capstone/hsdis-capstone.c b/src/utils/hsdis/capstone/hsdis-capstone.c new file mode 100644 index 00000000000..d71330ee6a7 --- /dev/null +++ b/src/utils/hsdis/capstone/hsdis-capstone.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to + * any person obtaining a copy of this software, associated documentation + * and/or data (collectively the "Software"), free of charge and under any + * and all copyright rights in the Software, and any and all patent rights + * owned or freely licensable by each licensor hereunder covering either (i) + * the unmodified Software as contributed to or provided by such licensor, + * or (ii) the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file + * if one is included with the Software (each a "Larger Work" to which the + * Software is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, + * create derivative works of, display, perform, and distribute the Software + * and make, use, sell, offer for sale, import, export, have made, and have + * sold the Software and the Larger Work(s), and to sublicense the foregoing + * rights on either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or + * at a minimum a reference to the UPL must be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* hsdis.c -- dump a range of addresses as native instructions + This implements the plugin protocol required by the + HotSpot PrintAssembly option. +*/ + +#include + +#include + +#include "hsdis.h" + +/* short names for stuff in hsdis.h */ +typedef decode_instructions_event_callback_ftype event_callback_t; +typedef decode_instructions_printf_callback_ftype printf_callback_t; + +#define print(...) (*printf_callback) (printf_stream, __VA_ARGS__) + +#ifdef _WIN32 +__declspec(dllexport) +#endif +void* decode_instructions_virtual(uintptr_t start_va, uintptr_t end_va, + unsigned char* buffer, uintptr_t length, + void* (*event_callback)(void*, const char*, void*), + void* event_stream, + int (*printf_callback)(void*, const char*, ...), + void* printf_stream, + const char* options, + int newline /* bool value for nice new line */) { + csh cs_handle; + + if (cs_open(CAPSTONE_ARCH, CAPSTONE_MODE, &cs_handle) != CS_ERR_OK) { + print("Could not open cs_handle"); + return NULL; + } + + // TODO: Support intel syntax + cs_option(cs_handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT); + + cs_insn *insn; + size_t count = cs_disasm(cs_handle, buffer, length, (uintptr_t) buffer, 0 , &insn); + if (count) { + for (unsigned int j = 0; j < count; j++) { + print(" 0x%" PRIx64 ":\t%s\t\t%s\n", insn[j].address, insn[j].mnemonic, insn[j].op_str); + } + cs_free(insn, count); + } + + cs_close(&cs_handle); + + return NULL; +} diff --git a/src/utils/hsdis/hsdis.h b/src/utils/hsdis/hsdis.h index a6b45a57ba8..7e3b8e397af 100644 --- a/src/utils/hsdis/hsdis.h +++ b/src/utils/hsdis/hsdis.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -72,9 +72,14 @@ #ifndef SHARED_TOOLS_HSDIS_H #define SHARED_TOOLS_HSDIS_H +#ifdef __cplusplus +extern "C" +{ +#endif + extern -#ifdef DLL_EXPORT - DLL_EXPORT +#ifdef _WIN32 +__declspec(dllexport) #endif void* decode_instructions_virtual(uintptr_t start_va, uintptr_t end_va, unsigned char* buffer, uintptr_t length, @@ -87,8 +92,8 @@ void* decode_instructions_virtual(uintptr_t start_va, uintptr_t end_va, /* This is the compatability interface for older versions of hotspot */ extern -#ifdef DLL_ENTRY - DLL_ENTRY +#ifdef _WIN32 +__declspec(dllexport) #endif void* decode_instructions(void* start_pv, void* end_pv, void* (*event_callback)(void*, const char*, void*), @@ -115,4 +120,9 @@ typedef void* (*decode_func_stype) (void* start_pv, void* end_pv, decode_instructions_printf_callback_ftype printf_callback, void* printf_stream, const char* options); + +#ifdef __cplusplus +} +#endif + #endif /* SHARED_TOOLS_HSDIS_H */ -- GitLab From fdce35f3a1c12a64238d0c76c02451a25b0b4abb Mon Sep 17 00:00:00 2001 From: Jie Fu Date: Thu, 17 Feb 2022 22:53:53 +0000 Subject: [PATCH 119/203] 8282025: assert(ctrl != __null) failed: control out is assumed to be unique after JDK-8281732 Reviewed-by: kvn, thartmann, chagedorn --- src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp index f46d9436316..849b40f3d79 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2015, 2021, Red Hat, Inc. All rights reserved. + * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -706,7 +707,7 @@ Node* ShenandoahBarrierC2Support::no_branches(Node* c, Node* dom, bool allow_one Node* iffproj = NULL; while (c != dom) { Node* next = phase->idom(c); - assert(next->unique_ctrl_out() == c || c->is_Proj() || c->is_Region(), "multiple control flow out but no proj or region?"); + assert(next->unique_ctrl_out_or_null() == c || c->is_Proj() || c->is_Region(), "multiple control flow out but no proj or region?"); if (c->is_Region()) { ResourceMark rm; Unique_Node_List wq; -- GitLab From a22f422b7f18dc134e48c6193bf690004635bf7d Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Fri, 18 Feb 2022 04:56:05 +0000 Subject: [PATCH 120/203] 8037573: Typo in DefaultTreeModel docs: askAllowsChildren instead of asksAllowsChildren Reviewed-by: prr, jdv, azvegint --- .../share/classes/javax/swing/tree/DefaultTreeModel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java.desktop/share/classes/javax/swing/tree/DefaultTreeModel.java b/src/java.desktop/share/classes/javax/swing/tree/DefaultTreeModel.java index 6d2a692c043..4cdec3f6b38 100644 --- a/src/java.desktop/share/classes/javax/swing/tree/DefaultTreeModel.java +++ b/src/java.desktop/share/classes/javax/swing/tree/DefaultTreeModel.java @@ -204,7 +204,7 @@ public class DefaultTreeModel implements Serializable, TreeModel { /** * Returns whether the specified node is a leaf node. * The way the test is performed depends on the - * askAllowsChildren setting. + * asksAllowsChildren setting. * * @param node the node to check * @return true if the node is a leaf node -- GitLab From c9289583eb6919ced3b4115cf981180f6a957fbf Mon Sep 17 00:00:00 2001 From: Jie Fu Date: Fri, 18 Feb 2022 05:02:19 +0000 Subject: [PATCH 121/203] 8281936: compiler/arguments/TestCodeEntryAlignment.java fails on AVX512 machines Reviewed-by: shade, kvn --- src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index 6597c91bb42..8bfbe3303da 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -3002,7 +3002,7 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha // allocate space for the code ResourceMark rm; - CodeBuffer buffer(name, 1000, 512); + CodeBuffer buffer(name, 1200, 512); MacroAssembler* masm = new MacroAssembler(&buffer); int frame_size_in_words; -- GitLab From 7bcca7692b62a37f70c757694f6acff0295371cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Casta=C3=B1eda=20Lozano?= Date: Fri, 18 Feb 2022 08:35:52 +0000 Subject: [PATCH 122/203] 8279068: IGV: Update to work with JDK 16 and 17 Reviewed-by: kvn, neliasso, chagedorn --- .../IdealGraphVisualizer/Bytecodes/pom.xml | 6 ++++- .../IdealGraphVisualizer/ControlFlow/pom.xml | 6 ++++- .../IdealGraphVisualizer/Coordinator/pom.xml | 6 ++++- src/utils/IdealGraphVisualizer/Data/pom.xml | 6 ++++- .../IdealGraphVisualizer/Difference/pom.xml | 6 ++++- src/utils/IdealGraphVisualizer/Filter/pom.xml | 8 +++++-- .../IdealGraphVisualizer/FilterWindow/pom.xml | 6 ++++- src/utils/IdealGraphVisualizer/Graal/pom.xml | 6 ++++- src/utils/IdealGraphVisualizer/Graph/pom.xml | 6 ++++- .../HierarchicalLayout/pom.xml | 6 ++++- src/utils/IdealGraphVisualizer/Layout/pom.xml | 6 ++++- .../NetworkConnection/pom.xml | 6 ++++- src/utils/IdealGraphVisualizer/README.md | 2 +- .../SelectionCoordinator/pom.xml | 6 ++++- .../ServerCompiler/pom.xml | 4 ++++ .../IdealGraphVisualizer/Settings/pom.xml | 6 ++++- src/utils/IdealGraphVisualizer/Util/pom.xml | 6 ++++- src/utils/IdealGraphVisualizer/View/pom.xml | 6 ++++- .../IdealGraphVisualizer/application/pom.xml | 5 +++- .../main/resources/idealgraphvisualizer.conf | 24 +++++++++++++++++++ .../IdealGraphVisualizer/branding/pom.xml | 6 ++++- src/utils/IdealGraphVisualizer/pom.xml | 24 ++++++++++++++++++- 22 files changed, 142 insertions(+), 21 deletions(-) create mode 100644 src/utils/IdealGraphVisualizer/application/src/main/resources/idealgraphvisualizer.conf diff --git a/src/utils/IdealGraphVisualizer/Bytecodes/pom.xml b/src/utils/IdealGraphVisualizer/Bytecodes/pom.xml index 188537f81d6..e87ad7fb509 100644 --- a/src/utils/IdealGraphVisualizer/Bytecodes/pom.xml +++ b/src/utils/IdealGraphVisualizer/Bytecodes/pom.xml @@ -1,6 +1,6 @@ diff --git a/src/utils/IdealGraphVisualizer/application/src/main/resources/idealgraphvisualizer.conf b/src/utils/IdealGraphVisualizer/application/src/main/resources/idealgraphvisualizer.conf new file mode 100644 index 00000000000..500ed32f280 --- /dev/null +++ b/src/utils/IdealGraphVisualizer/application/src/main/resources/idealgraphvisualizer.conf @@ -0,0 +1,24 @@ +# Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. + +# Open/export modules still accessed by the NetBeans Platform. +# All options must be passed in a single line for multi-platform support. +default_options="-J--add-opens=java.base/java.net=ALL-UNNAMED -J--add-opens=java.desktop/javax.swing.plaf.synth=ALL-UNNAMED -J--add-opens=java.desktop/com.sun.java.swing.plaf.gtk=ALL-UNNAMED -J--add-opens=java.desktop/javax.swing=ALL-UNNAMED -J--add-exports=java.desktop/sun.awt=ALL-UNNAMED" \ No newline at end of file diff --git a/src/utils/IdealGraphVisualizer/branding/pom.xml b/src/utils/IdealGraphVisualizer/branding/pom.xml index 67821ff4621..ed33298d3e4 100644 --- a/src/utils/IdealGraphVisualizer/branding/pom.xml +++ b/src/utils/IdealGraphVisualizer/branding/pom.xml @@ -1,6 +1,6 @@