diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 98ede25b88df5..2d5cef8fd6dee 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,3 @@ # Contributing to the JDK - +... Please see the [OpenJDK Developers' Guide](https://openjdk.org/guide/). diff --git a/make/modules/jdk.jcmd/Copy.gmk b/make/modules/jdk.jcmd/Copy.gmk new file mode 100644 index 0000000000000..f3240f9f61db7 --- /dev/null +++ b/make/modules/jdk.jcmd/Copy.gmk @@ -0,0 +1,42 @@ +# +# Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. +# 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. +# + +################################################################################ + +include CopyCommon.gmk + +# the autocompletion script is Bash-only +ifneq ($(call isTargetOsType, windows), true) + JCMD_CONF_DIR := $(TOPDIR)/src/jdk.jcmd/share/conf + $(eval $(call SetupCopyFiles, COPY_JCMD_BASH_COMPLETION, \ + DEST := $(CONF_DST_DIR)/bash-completion, \ + SRC := $(JCMD_CONF_DIR)/bash-completion, \ + FILES := jcmd, \ + )) +endif + +TARGETS += $(COPY_JCMD_BASH_COMPLETION) + +################################################################################ diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 7487de2d57759..c6dc1bdfed2a4 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -2647,19 +2647,45 @@ static bool is_valid_sve_arith_imm_pattern(Node* n, Node* m) { } // (XorV src (Replicate m1)) -// (XorVMask src (MaskAll m1)) static bool is_vector_bitwise_not_pattern(Node* n, Node* m) { if (n != nullptr && m != nullptr) { - return (n->Opcode() == Op_XorV || n->Opcode() == Op_XorVMask) && + return n->Opcode() == Op_XorV && VectorNode::is_all_ones_vector(m); } return false; } +// Returns true if (n, m) matches "(XorVMask vm2 (MaskAll m1))" and that XorVMask +// is used only by an AndVMask. In that case, cloning m (the MaskAll) lets the +// matcher avoid sharing the MaskAll node and subsume the pattern into rule: +// "(AndVMask vm1 (XorVMask vm2 (MaskAll m1)))". +// +// Limitation: the "andNot" rule still cannot be matched if "m" has other +// uses outside this pattern. +static bool is_vector_mask_not_operand_in_andnot_pattern(Node* n, Node* m) { + if (n == nullptr || m == nullptr) { + return false; + } + + if (VectorNode::is_all_ones_vector(m) && + n->Opcode() == Op_XorVMask && + n->outcnt() == 1 && + n->unique_out()->Opcode() == Op_AndVMask) { + // If another input of the AndVMask is also a mask-not pattern that would + // qualify for the `maskAll` cloning, do not clone the "maskAll" here, + // because the match rule can only consume one such pattern. + Node* use = n->unique_out(); + Node* other_input = use->in(1) == n ? use->in(2) : use->in(1); + return !VectorNode::is_vectormask_bitwise_not_pattern(other_input); + } + return false; +} + // Should the matcher clone input 'm' of node 'n'? bool Matcher::pd_clone_node(Node* n, Node* m, Matcher::MStack& mstack) { if (is_vshift_con_pattern(n, m) || is_vector_bitwise_not_pattern(n, m) || + is_vector_mask_not_operand_in_andnot_pattern(n, m) || is_valid_sve_arith_imm_pattern(n, m) || is_encode_and_store_pattern(n, m)) { mstack.push(m, Visit); diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index f385a3d2eff39..7d920704131ba 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -2667,7 +2667,7 @@ int MacroAssembler::corrected_idivq(Register result, Register ra, Register rb, void MacroAssembler::membar(Membar_mask_bits order_constraint) { address prev = pc() - NativeMembar::instruction_size; - address last = code()->last_insn(); + address last = code()->last_merge_candidate(); if (last != nullptr && nativeInstruction_at(last)->is_Membar() && prev == last) { NativeMembar *bar = NativeMembar_at(prev); if (AlwaysMergeDMB) { @@ -2699,21 +2699,21 @@ void MacroAssembler::membar(Membar_mask_bits order_constraint) { } } } - code()->set_last_insn(pc()); + code()->set_last_merge_candidate(pc()); dmb(Assembler::barrier(order_constraint)); } bool MacroAssembler::try_merge_ldst(Register rt, const Address &adr, size_t size_in_bytes, bool is_store) { if (ldst_can_merge(rt, adr, size_in_bytes, is_store)) { merge_ldst(rt, adr, size_in_bytes, is_store); - code()->clear_last_insn(); + code()->clear_last_merge_candidate(); return true; } else { assert(size_in_bytes == 8 || size_in_bytes == 4, "only 8 bytes or 4 bytes load/store is supported."); const uint64_t mask = size_in_bytes - 1; if (adr.getMode() == Address::base_plus_offset && (adr.offset() & mask) == 0) { // only supports base_plus_offset. - code()->set_last_insn(pc()); + code()->set_last_merge_candidate(pc()); } return false; } @@ -3876,7 +3876,7 @@ bool MacroAssembler::ldst_can_merge(Register rt, size_t cur_size_in_bytes, bool is_store) const { address prev = pc() - NativeInstruction::instruction_size; - address last = code()->last_insn(); + address last = code()->last_merge_candidate(); if (last == nullptr || !nativeInstruction_at(last)->is_Imm_LdSt()) { return false; diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index c02df666a87f6..a338098cb53fe 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -168,7 +168,7 @@ class MacroAssembler: public Assembler { void bind(Label& L) { Assembler::bind(L); - code()->clear_last_insn(); + code()->clear_last_merge_candidate(); code()->set_last_label(pc()); } diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 0e32c602d953e..02798d5204aae 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -4117,7 +4117,7 @@ void MacroAssembler::membar(uint32_t order_constraint) { } address prev = pc() - MacroAssembler::instruction_size; - address last = code()->last_insn(); + address last = code()->last_merge_candidate(); if (last != nullptr && is_membar(last) && prev == last) { // We are merging two memory barrier instructions. On RISCV we @@ -4127,7 +4127,7 @@ void MacroAssembler::membar(uint32_t order_constraint) { return; } - code()->set_last_insn(pc()); + code()->set_last_merge_candidate(pc()); uint32_t predecessor = 0; uint32_t successor = 0; membar_mask_to_pred_succ(order_constraint, predecessor, successor); diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index 4cc55e7ae23b6..6e592b5c8529d 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -876,7 +876,7 @@ class MacroAssembler: public Assembler { void bind(Label& L) { Assembler::bind(L); // fences across basic blocks should not be merged - code()->clear_last_insn(); + code()->clear_last_merge_candidate(); } typedef void (MacroAssembler::* compare_and_branch_insn)(Register Rs1, Register Rs2, const address dest); diff --git a/src/hotspot/share/adlc/formssel.cpp b/src/hotspot/share/adlc/formssel.cpp index 5802217c1c1c8..392ef78a71d52 100644 --- a/src/hotspot/share/adlc/formssel.cpp +++ b/src/hotspot/share/adlc/formssel.cpp @@ -3967,7 +3967,7 @@ void MatchNode::count_commutative_op(int& count) { static const char *commut_vector_op_list[] = { "AddVB", "AddVS", "AddVI", "AddVL", "AddVHF", "AddVF", "AddVD", "MulVB", "MulVS", "MulVI", "MulVL", "MulVHF", "MulVF", "MulVD", - "AndV", "OrV", "XorV", + "AndV", "OrV", "XorV", "AndVMask", "OrVMask", "XorVMask", "MaxVHF", "MinVHF", "MaxV", "MinV", "UMax","UMin" }; diff --git a/src/hotspot/share/asm/codeBuffer.cpp b/src/hotspot/share/asm/codeBuffer.cpp index c647505059279..55ba27fcbe1da 100644 --- a/src/hotspot/share/asm/codeBuffer.cpp +++ b/src/hotspot/share/asm/codeBuffer.cpp @@ -937,8 +937,8 @@ void CodeBuffer::expand(CodeSection* which_cs, csize_t amount) { // Move all the code and relocations to the new blob: relocate_code_to(&cb); - // some internal addresses, _last_insn _last_label, are used during code emission, - // adjust them in expansion + // some internal addresses, _last_merge_candidate and _last_label, are used during + // code emission, adjust them in expansion adjust_internal_address(insts_begin(), cb.insts_begin()); // Copy the temporary code buffer into the current code buffer. @@ -966,8 +966,8 @@ void CodeBuffer::expand(CodeSection* which_cs, csize_t amount) { } void CodeBuffer::adjust_internal_address(address from, address to) { - if (_last_insn != nullptr) { - _last_insn += to - from; + if (_last_merge_candidate != nullptr) { + _last_merge_candidate += to - from; } if (_last_label != nullptr) { _last_label += to - from; diff --git a/src/hotspot/share/asm/codeBuffer.hpp b/src/hotspot/share/asm/codeBuffer.hpp index 38e151273da95..ea0237f140184 100644 --- a/src/hotspot/share/asm/codeBuffer.hpp +++ b/src/hotspot/share/asm/codeBuffer.hpp @@ -561,11 +561,11 @@ class CodeBuffer: public StackObj DEBUG_ONLY(COMMA private Scrubber) { OopRecorder* _oop_recorder; - OopRecorder _default_oop_recorder; // override with initialize_oop_recorder + OopRecorder _default_oop_recorder; // override with initialize_oop_recorder Arena* _overflow_arena; - address _last_insn; // used to merge consecutive memory barriers, loads or stores. - address _last_label; // record last bind label address, it's also the start of current bb. + address _last_label; // record last bind label address, it's also the start of current bb. + address _last_merge_candidate; // used to merge consecutive memory barriers, loads or stores. SharedStubToInterpRequests* _shared_stub_to_interp_requests; // used to collect requests for shared iterpreter stubs SharedTrampolineRequests* _shared_trampoline_requests; // used to collect requests for shared trampolines @@ -591,11 +591,11 @@ class CodeBuffer: public StackObj DEBUG_ONLY(COMMA private Scrubber) { _total_size = 0; _oop_recorder = nullptr; _overflow_arena = nullptr; - _last_insn = nullptr; _last_label = nullptr; - _finalize_stubs = false; + _last_merge_candidate = nullptr; _shared_stub_to_interp_requests = nullptr; _shared_trampoline_requests = nullptr; + _finalize_stubs = false; _consts.initialize_outer(this, SECT_CONSTS); _insts.initialize_outer(this, SECT_INSTS); @@ -812,9 +812,9 @@ class CodeBuffer: public StackObj DEBUG_ONLY(COMMA private Scrubber) { OopRecorder* oop_recorder() const { return _oop_recorder; } - address last_insn() const { return _last_insn; } - void set_last_insn(address a) { _last_insn = a; } - void clear_last_insn() { set_last_insn(nullptr); } + address last_merge_candidate() const { return _last_merge_candidate; } + void set_last_merge_candidate(address a) { _last_merge_candidate = a; } + void clear_last_merge_candidate() { set_last_merge_candidate(nullptr); } address last_label() const { return _last_label; } void set_last_label(address a) { _last_label = a; } diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 3bb4030afdeda..540b24f5c78ec 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -268,26 +268,36 @@ class nmethod : public CodeBlob { volatile signed char _state; // {not_installed, in_use, not_entrant} public: - union Flags { - uint8_t _raw; - struct { - bool _has_unsafe_access:1; // May fault due to unsafe access. - bool _has_wide_vectors:1; // Preserve wide vectors at safepoints - bool _has_monitors:1; // Fastpath monitor detection for continuations - bool _has_scoped_access:1; // Used by shared scope closure (scopedMemoryAccess.cpp) + struct Flags { + uint8_t const _bits; + + enum : uint8_t { + UNSAFE_ACCESS = 1 << 0, + WIDE_VECTORS = 1 << 1, + MONITORS = 1 << 2, + SCOPED_ACCESS = 1 << 3 }; - Flags() { - _raw = 0; - } - Flags(bool has_unsafe_access, bool has_wide_vectors, bool has_monitors, bool has_scoped_access) : Flags() { - _has_unsafe_access = has_unsafe_access; - _has_wide_vectors = has_wide_vectors; - _has_monitors = has_monitors; - _has_scoped_access = has_scoped_access; - } - }; - static_assert(sizeof(Flags) == sizeof(uint8_t), "Must fit exactly"); + Flags() : _bits(0) {} + Flags(bool has_unsafe_access, bool has_wide_vectors, bool has_monitors, bool has_scoped_access) : + _bits((has_unsafe_access ? UNSAFE_ACCESS : 0) | + (has_wide_vectors ? WIDE_VECTORS : 0) | + (has_monitors ? MONITORS : 0) | + (has_scoped_access ? SCOPED_ACCESS : 0)) + {} + + // May fault due to unsafe access + bool has_unsafe_access() const { return (_bits & UNSAFE_ACCESS) != 0; } + + // Preserve wide vectors at safepoints + bool has_wide_vectors() const { return (_bits & WIDE_VECTORS) != 0; } + + // Fastpath monitor detection for continuations + bool has_monitors() const { return (_bits & MONITORS) != 0; } + + // Used by shared scope closure (scopedMemoryAccess.cpp) + bool has_scoped_access() const { return (_bits & SCOPED_ACCESS) != 0; } + }; private: // Persistent bits, set once during construction. @@ -779,10 +789,10 @@ class nmethod : public CodeBlob { template void set_gc_data(T* gc_data) { _gc_data = reinterpret_cast(gc_data); } - bool has_unsafe_access() const { return _flags._has_unsafe_access; } - bool has_monitors() const { return _flags._has_monitors; } - bool has_scoped_access() const { return _flags._has_scoped_access; } - bool has_wide_vectors() const { return _flags._has_wide_vectors; } + bool has_unsafe_access() const { return _flags.has_unsafe_access(); } + bool has_monitors() const { return _flags.has_monitors(); } + bool has_scoped_access() const { return _flags.has_scoped_access(); } + bool has_wide_vectors() const { return _flags.has_wide_vectors(); } bool has_flushed_dependencies() const { return _has_flushed_dependencies; } void set_has_flushed_dependencies(bool z) { diff --git a/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp b/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp index a486a88c48fbc..0a03ce52e238b 100644 --- a/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp +++ b/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp @@ -324,6 +324,8 @@ class BarrierSetC2: public CHeapObj { virtual bool is_gc_pre_barrier_node(Node* node) const { return false; } virtual bool is_gc_barrier_node(Node* node) const { return false; } virtual Node* step_over_gc_barrier(Node* c) const { return c; } + // Allow barriers that depend on transitive inputs to be re-evaluated. + virtual void enqueue_dependent_gc_barriers(Unique_Node_List& worklist, Node* use) const {} // Support for macro expanded GC barriers virtual void register_potential_barrier_node(Node* node) const { } diff --git a/src/hotspot/share/gc/shared/gcConfig.cpp b/src/hotspot/share/gc/shared/gcConfig.cpp index 402bd0caacddc..c31bce353541d 100644 --- a/src/hotspot/share/gc/shared/gcConfig.cpp +++ b/src/hotspot/share/gc/shared/gcConfig.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -95,10 +95,11 @@ void GCConfig::fail_if_non_included_gc_is_selected() { } void GCConfig::select_gc_ergonomically() { - if (os::is_server_class_machine()) { #if INCLUDE_G1GC - FLAG_SET_ERGO_IF_DEFAULT(UseG1GC, true); -#elif INCLUDE_PARALLELGC + FLAG_SET_ERGO_IF_DEFAULT(UseG1GC, true); +#else + if (os::is_server_class_machine()) { +#if INCLUDE_PARALLELGC FLAG_SET_ERGO_IF_DEFAULT(UseParallelGC, true); #elif INCLUDE_SERIALGC FLAG_SET_ERGO_IF_DEFAULT(UseSerialGC, true); @@ -108,6 +109,7 @@ void GCConfig::select_gc_ergonomically() { FLAG_SET_ERGO_IF_DEFAULT(UseSerialGC, true); #endif } +#endif } bool GCConfig::is_no_gc_selected() { diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp index deab648a108ec..f786702a29190 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp @@ -843,6 +843,36 @@ Node* ShenandoahBarrierSetC2::step_over_gc_barrier(Node* c) const { return c; } +static bool is_barrier_traversal_node(int op) { + // Node types that ShenandoahLoadReferenceBarrierNode::Identity traverses via needs_barrier_impl. + return op == Op_Phi || op == Op_DecodeN || op == Op_EncodeP || op == Op_CastPP || + op == Op_CheckCastPP || op == Op_CMoveN || op == Op_CMoveP || op == Op_Proj; +} + +void ShenandoahBarrierSetC2::enqueue_dependent_gc_barriers(Unique_Node_List& worklist, Node* n) const { + if (!is_barrier_traversal_node(n->Opcode())) { + return; + } + Unique_Node_List visited; + Unique_Node_List stack; + stack.push(n); + while (stack.size() > 0) { + Node* cur = stack.pop(); + if (visited.member(cur)) { + continue; + } + visited.push(cur); + for (DUIterator_Fast imax, i = cur->fast_outs(imax); i < imax; i++) { + Node* u = cur->fast_out(i); + if (u->Opcode() == Op_ShenandoahLoadReferenceBarrier) { + worklist.push(u); + } else if (is_barrier_traversal_node(u->Opcode())) { + stack.push(u); + } + } + } +} + bool ShenandoahBarrierSetC2::expand_barriers(Compile* C, PhaseIterGVN& igvn) const { return !ShenandoahBarrierC2Support::expand(C, igvn); } diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp index c77a9da63fc1b..63244ee7751ea 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp @@ -127,6 +127,7 @@ class ShenandoahBarrierSetC2 : public BarrierSetC2 { virtual bool is_gc_pre_barrier_node(Node* node) const; virtual bool is_gc_barrier_node(Node* node) const; virtual Node* step_over_gc_barrier(Node* c) const; + virtual void enqueue_dependent_gc_barriers(Unique_Node_List& worklist, Node* use) const; virtual bool expand_barriers(Compile* C, PhaseIterGVN& igvn) const; virtual bool optimize_loops(PhaseIdealLoop* phase, LoopOptsMode mode, VectorSet& visited, Node_Stack& nstack, Node_List& worklist) const; virtual bool strip_mined_loops_expanded(LoopOptsMode mode) const { return mode == LoopOptsShenandoahExpand; } diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index a4d6a6c33d081..c166a3f05f79d 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -2797,6 +2797,11 @@ void PhaseIterGVN::add_users_of_use_to_worklist(Node* n, Node* use, Unique_Node_ add_users_to_worklist_if(worklist, use, [](Node* u) { return u->Opcode() == Op_VectorMaskToLong; }); } + // Allow GC to enqueue barriers that depend on transitive inputs + if (has_load_barrier_nodes) { + bs->enqueue_dependent_gc_barriers(worklist, use); + } + // From CastX2PNode::Ideal // CastX2P(AddX(x, y)) // CastX2P(SubX(x, y)) diff --git a/src/hotspot/share/opto/vectornode.cpp b/src/hotspot/share/opto/vectornode.cpp index a54fe6e3a7333..1059bfe20e584 100644 --- a/src/hotspot/share/opto/vectornode.cpp +++ b/src/hotspot/share/opto/vectornode.cpp @@ -1017,6 +1017,13 @@ bool VectorNode::is_vector_bitwise_not_pattern(Node* n) { return false; } +bool VectorNode::is_vectormask_bitwise_not_pattern(Node* n) { + if (n->Opcode() == Op_XorVMask) { + return is_all_ones_vector(n->in(1)) || + is_all_ones_vector(n->in(2)); + } + return false; +} bool VectorNode::is_reinterpret_opcode(int opc) { switch (opc) { diff --git a/src/hotspot/share/opto/vectornode.hpp b/src/hotspot/share/opto/vectornode.hpp index 6bcb7702d13a0..de077015bca14 100644 --- a/src/hotspot/share/opto/vectornode.hpp +++ b/src/hotspot/share/opto/vectornode.hpp @@ -182,6 +182,7 @@ class VectorNode : public TypeNode { // Return true if every bit in this vector is 0. static bool is_all_zeros_vector(Node* n); static bool is_vector_bitwise_not_pattern(Node* n); + static bool is_vectormask_bitwise_not_pattern(Node* n); static Node* degenerate_vector_rotate(Node* n1, Node* n2, bool is_rotate_left, int vlen, BasicType bt, PhaseGVN* phase); diff --git a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java index 1ccffaa61bbc6..d15e701b94d17 100644 --- a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java +++ b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java @@ -180,7 +180,7 @@ private static class StaticHolders { * * @throws NullPointerException if any argument is {@code null}, unless noted otherwise * @throws IllegalArgumentException if any element in the labels array is null - * @throws IllegalArgumentException if the invocation type is not a method type of first parameter of a reference type, + * @throws IllegalArgumentException if the invocation type is not a method type of first parameter of a target type, * second parameter of type {@code int} and with {@code int} as its return type * @throws IllegalArgumentException if {@code labels} contains an element that is not of type {@code String}, * {@code Integer}, {@code Long}, {@code Float}, {@code Double}, {@code Boolean}, diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsConstants.java b/src/java.base/windows/classes/sun/nio/fs/WindowsConstants.java index 0c09a80e99e73..8e713464f199d 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsConstants.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsConstants.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -115,6 +115,12 @@ private WindowsConstants() { } public static final int ERROR_NOT_A_REPARSE_POINT = 4390; public static final int ERROR_INVALID_REPARSE_DATA = 4392; + // FILE_INFO_BY_NAME_CLASS enum values for GetFileInformationByName() + public static final int FileStatByNameInfo = 0; + public static final int FileStatLxByNameInfo = 1; + public static final int FileCaseSensitiveByNameInfo = 2; + public static final int FileStatBasicByNameInfo = 3; + // notify filters public static final int FILE_NOTIFY_CHANGE_FILE_NAME = 0x00000001; public static final int FILE_NOTIFY_CHANGE_DIR_NAME = 0x00000002; diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsFileAttributes.java b/src/java.base/windows/classes/sun/nio/fs/WindowsFileAttributes.java index 3c94e8bc4a2a2..76422c9ecc9ae 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsFileAttributes.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsFileAttributes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -107,6 +107,35 @@ class WindowsFileAttributes private static final short OFFSETOF_FIND_DATA_SIZELOW = 32; private static final short OFFSETOF_FIND_DATA_RESERVED0 = 36; + /* + * typedef struct _FILE_STAT_BASIC_INFORMATION { + * LARGE_INTEGER FileId; // offset = 0 + * LARGE_INTEGER CreationTime; // offset = 8 + * LARGE_INTEGER LastAccessTime; // offset = 16 + * LARGE_INTEGER LastWriteTime; // offset = 24 + * LARGE_INTEGER ChangeTime; // offset = 32 + * LARGE_INTEGER AllocationSize; // offset = 40 + * LARGE_INTEGER EndOfFile; // offset = 48 + * ULONG FileAttributes; // offset = 56 + * ULONG ReparseTag; // offset = 60 + * ULONG NumberOfLinks; // offset = 64 + * ULONG DeviceType; // offset = 68 + * ULONG DeviceCharacteristics; // offset = 72 + * ULONG Reserved; // offset = 76 + * LARGE_INTEGER VolumeSerialNumber; // offset = 80 + * FILE_ID_128 FileId128; // offset = 88 + * } FILE_STAT_BASIC_INFORMATION; + */ + private static final short SIZEOF_STAT_BASIC_INFO = 104; + private static final short OFFSETOF_STAT_BASIC_INFO_FILEID = 0; + private static final short OFFSETOF_STAT_BASIC_INFO_CREATETIME = 8; + private static final short OFFSETOF_STAT_BASIC_INFO_LASTACCESSTIME = 16; + private static final short OFFSETOF_STAT_BASIC_INFO_LASTWRITETIME = 24; + private static final short OFFSETOF_STAT_BASIC_INFO_ENDOFFILE = 48; + private static final short OFFSETOF_STAT_BASIC_INFO_ATTRIBUTES = 56; + private static final short OFFSETOF_STAT_BASIC_INFO_REPARSETAG = 60; + private static final short OFFSETOF_STAT_BASIC_INFO_VOLSERIAL = 80; + // used to adjust values between Windows and java epochs private static final long WINDOWS_EPOCH_IN_MICROS = -11644473600000000L; private static final long WINDOWS_EPOCH_IN_100NS = -116444736000000000L; @@ -226,6 +255,32 @@ private static WindowsFileAttributes fromFileAttributeData(long address, int rep } + /** + * Create a WindowsFileAttributes from a FILE_STAT_BASIC_INFORMATION structure + */ + static WindowsFileAttributes fromStatBasicInfo(long address) { + int fileAttrs = unsafe.getInt(address + OFFSETOF_STAT_BASIC_INFO_ATTRIBUTES); + long creationTime = unsafe.getLong(address + OFFSETOF_STAT_BASIC_INFO_CREATETIME); + long lastAccessTime = unsafe.getLong(address + OFFSETOF_STAT_BASIC_INFO_LASTACCESSTIME); + long lastWriteTime = unsafe.getLong(address + OFFSETOF_STAT_BASIC_INFO_LASTWRITETIME); + long size = unsafe.getLong(address + OFFSETOF_STAT_BASIC_INFO_ENDOFFILE); + int reparseTag = isReparsePoint(fileAttrs) ? + unsafe.getInt(address + OFFSETOF_STAT_BASIC_INFO_REPARSETAG) : 0; + int volSerialNumber = unsafe.getInt(address + OFFSETOF_STAT_BASIC_INFO_VOLSERIAL); + int fileIndexLow = unsafe.getInt(address + OFFSETOF_STAT_BASIC_INFO_FILEID); + int fileIndexHigh = unsafe.getInt(address + OFFSETOF_STAT_BASIC_INFO_FILEID + 4); + + return new WindowsFileAttributes(fileAttrs, + creationTime, + lastAccessTime, + lastWriteTime, + size, + reparseTag, + volSerialNumber, + fileIndexHigh, + fileIndexLow); + } + /** * Allocates a native buffer for a WIN32_FIND_DATA structure */ @@ -332,6 +387,23 @@ static WindowsFileAttributes get(WindowsPath path, boolean followLinks) } } + if (supportsGetFileInformationByName()) { + try (NativeBuffer buffer = NativeBuffers.getNativeBuffer(SIZEOF_STAT_BASIC_INFO)) { + long addr = buffer.address(); + GetFileInformationByName(path.getPathForWin32Calls(), + FileStatBasicByNameInfo, addr, + SIZEOF_STAT_BASIC_INFO); + + // GetFileInformationByName() doesn't follow reparse points so if + // we discover that this is a reparse point and if we're being asked + // to follow links, then drop to the slow path. + int fileAttrs = unsafe.getInt(addr + OFFSETOF_STAT_BASIC_INFO_ATTRIBUTES); + if (!isReparsePoint(fileAttrs) || !followLinks) { + return fromStatBasicInfo(addr); + } + } + } + // file is reparse point so need to open file to get attributes long handle = path.openForReadAttributeAccess(followLinks); try { diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java b/src/java.base/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java index ba1b7b1aa9f3e..d6f68b72ed39b 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java @@ -367,6 +367,24 @@ static void GetFileAttributesEx(String path, long address) throws WindowsExcepti private static native void GetFileAttributesEx0(long lpFileName, long address) throws WindowsException; + /** + * GetFileInformationByName( + * PCWSTR FileName, + * FILE_INFO_BY_NAME_CLASS FileInformationClass, + * PVOID FileInfoBuffer, + * ULONG FileInfoBufferSize + * ) + */ + static void GetFileInformationByName(String path, int infoClass, long address, int size) + throws WindowsException + { + try (NativeBuffer buffer = asNativeBuffer(path)) { + GetFileInformationByName0(buffer.address(), infoClass, address, size); + } + } + private static native void GetFileInformationByName0(long pathAddress, + int infoClass, long infoAddress, int infoSize) throws WindowsException; + /** * SetFileTime( * HANDLE hFile, @@ -1090,15 +1108,23 @@ static NativeBuffer asNativeBuffer(String s) throws WindowsException { return buffer; } + // -- capabilities -- + private static final int SUPPORTS_GETFILEINFORMATIONBYNAME = 1 << 1; + private static final int capabilities; + + static boolean supportsGetFileInformationByName() { + return (capabilities & SUPPORTS_GETFILEINFORMATIONBYNAME) != 0; + } + // -- native library initialization -- - private static native void initIDs(); + private static native int init(); static { // nio.dll has dependency on net.dll jdk.internal.loader.BootLoader.loadLibrary("net"); jdk.internal.loader.BootLoader.loadLibrary("nio"); - initIDs(); + capabilities = init(); } } diff --git a/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c b/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c index b6e6a9751c019..07452cbef0a0f 100644 --- a/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c +++ b/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -79,75 +79,122 @@ static void throwWindowsException(JNIEnv* env, DWORD lastError) { } } +#if !defined(NTDDI_WIN10_NI) || !(NTDDI_VERSION >= NTDDI_WIN10_NI) + +typedef struct _FILE_STAT_BASIC_INFORMATION { + LARGE_INTEGER FileId; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG FileAttributes; + ULONG ReparseTag; + ULONG NumberOfLinks; + ULONG DeviceType; + ULONG DeviceCharacteristics; + ULONG Reserved; + LARGE_INTEGER VolumeSerialNumber; + FILE_ID_128 FileId128; +} FILE_STAT_BASIC_INFORMATION; + +typedef enum _FILE_INFO_BY_NAME_CLASS { + FileStatByNameInfo, + FileStatLxByNameInfo, + FileCaseSensitiveByNameInfo, + FileStatBasicByNameInfo, + MaximumFileInfoByNameClass +} FILE_INFO_BY_NAME_CLASS; + +#endif /* !defined(NTDDI_WIN10_NI) || !(NTDDI_VERSION >= NTDDI_WIN10_NI) */ + +typedef BOOL (WINAPI *PGetFileInformationByName)( + PCWSTR, FILE_INFO_BY_NAME_CLASS, PVOID, ULONG); + +static PGetFileInformationByName pGetFileInformationByName = NULL; + /** * Initializes jfieldIDs and get address of Win32 calls that are located * at runtime. */ -JNIEXPORT void JNICALL -Java_sun_nio_fs_WindowsNativeDispatcher_initIDs(JNIEnv* env, jclass this) +JNIEXPORT jint JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_init(JNIEnv* env, jclass this) { jclass clazz; + jint capabilities = 0; clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$FirstFile"); - CHECK_NULL(clazz); + CHECK_NULL_RETURN(clazz, 0); findFirst_handle = (*env)->GetFieldID(env, clazz, "handle", "J"); - CHECK_NULL(findFirst_handle); + CHECK_NULL_RETURN(findFirst_handle, 0); findFirst_name = (*env)->GetFieldID(env, clazz, "name", "Ljava/lang/String;"); - CHECK_NULL(findFirst_name); + CHECK_NULL_RETURN(findFirst_name, 0); findFirst_attributes = (*env)->GetFieldID(env, clazz, "attributes", "I"); - CHECK_NULL(findFirst_attributes); + CHECK_NULL_RETURN(findFirst_attributes, 0); clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$FirstStream"); - CHECK_NULL(clazz); + CHECK_NULL_RETURN(clazz, 0); findStream_handle = (*env)->GetFieldID(env, clazz, "handle", "J"); - CHECK_NULL(findStream_handle); + CHECK_NULL_RETURN(findStream_handle, 0); findStream_name = (*env)->GetFieldID(env, clazz, "name", "Ljava/lang/String;"); - CHECK_NULL(findStream_name); + CHECK_NULL_RETURN(findStream_name, 0); clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$VolumeInformation"); - CHECK_NULL(clazz); + CHECK_NULL_RETURN(clazz, 0); volumeInfo_fsName = (*env)->GetFieldID(env, clazz, "fileSystemName", "Ljava/lang/String;"); - CHECK_NULL(volumeInfo_fsName); + CHECK_NULL_RETURN(volumeInfo_fsName, 0); volumeInfo_volName = (*env)->GetFieldID(env, clazz, "volumeName", "Ljava/lang/String;"); - CHECK_NULL(volumeInfo_volName); + CHECK_NULL_RETURN(volumeInfo_volName, 0); volumeInfo_volSN = (*env)->GetFieldID(env, clazz, "volumeSerialNumber", "I"); - CHECK_NULL(volumeInfo_volSN); + CHECK_NULL_RETURN(volumeInfo_volSN, 0); volumeInfo_flags = (*env)->GetFieldID(env, clazz, "flags", "I"); - CHECK_NULL(volumeInfo_flags); + CHECK_NULL_RETURN(volumeInfo_flags, 0); clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$DiskFreeSpace"); - CHECK_NULL(clazz); + CHECK_NULL_RETURN(clazz, 0); diskSpace_bytesAvailable = (*env)->GetFieldID(env, clazz, "freeBytesAvailable", "J"); - CHECK_NULL(diskSpace_bytesAvailable); + CHECK_NULL_RETURN(diskSpace_bytesAvailable, 0); diskSpace_totalBytes = (*env)->GetFieldID(env, clazz, "totalNumberOfBytes", "J"); - CHECK_NULL(diskSpace_totalBytes); + CHECK_NULL_RETURN(diskSpace_totalBytes, 0); diskSpace_totalFree = (*env)->GetFieldID(env, clazz, "totalNumberOfFreeBytes", "J"); - CHECK_NULL(diskSpace_totalFree); + CHECK_NULL_RETURN(diskSpace_totalFree, 0); diskSpace_bytesPerSector = (*env)->GetFieldID(env, clazz, "bytesPerSector", "J"); - CHECK_NULL(diskSpace_bytesPerSector); + CHECK_NULL_RETURN(diskSpace_bytesPerSector, 0); clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$Account"); - CHECK_NULL(clazz); + CHECK_NULL_RETURN(clazz, 0); account_domain = (*env)->GetFieldID(env, clazz, "domain", "Ljava/lang/String;"); - CHECK_NULL(account_domain); + CHECK_NULL_RETURN(account_domain, 0); account_name = (*env)->GetFieldID(env, clazz, "name", "Ljava/lang/String;"); - CHECK_NULL(account_name); + CHECK_NULL_RETURN(account_name, 0); account_use = (*env)->GetFieldID(env, clazz, "use", "I"); - CHECK_NULL(account_use); + CHECK_NULL_RETURN(account_use, 0); clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$AclInformation"); - CHECK_NULL(clazz); + CHECK_NULL_RETURN(clazz, 0); aclInfo_aceCount = (*env)->GetFieldID(env, clazz, "aceCount", "I"); - CHECK_NULL(aclInfo_aceCount); + CHECK_NULL_RETURN(aclInfo_aceCount, 0); clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$CompletionStatus"); - CHECK_NULL(clazz); + CHECK_NULL_RETURN(clazz, 0); completionStatus_error = (*env)->GetFieldID(env, clazz, "error", "I"); - CHECK_NULL(completionStatus_error); + CHECK_NULL_RETURN(completionStatus_error, 0); completionStatus_bytesTransferred = (*env)->GetFieldID(env, clazz, "bytesTransferred", "I"); - CHECK_NULL(completionStatus_bytesTransferred); + CHECK_NULL_RETURN(completionStatus_bytesTransferred, 0); completionStatus_completionKey = (*env)->GetFieldID(env, clazz, "completionKey", "J"); - CHECK_NULL(completionStatus_completionKey); + CHECK_NULL_RETURN(completionStatus_completionKey, 0); + + HMODULE hMod = GetModuleHandleW(L"kernel32.dll"); + if (hMod != NULL) { + pGetFileInformationByName = + (PGetFileInformationByName)GetProcAddress(hMod, "GetFileInformationByName"); + if (pGetFileInformationByName != NULL) { + capabilities |= sun_nio_fs_WindowsNativeDispatcher_SUPPORTS_GETFILEINFORMATIONBYNAME; + } + } + + return capabilities; } JNIEXPORT jlong JNICALL @@ -510,6 +557,23 @@ Java_sun_nio_fs_WindowsNativeDispatcher_GetFileAttributesEx0(JNIEnv* env, jclass throwWindowsException(env, GetLastError()); } +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_GetFileInformationByName0(JNIEnv* env, + jclass this, jlong pathAddress, jint infoClass, jlong infoAddress, jint infoSize) +{ + LPCWSTR lpFileName = jlong_to_ptr(pathAddress); + PVOID pInfo = jlong_to_ptr(infoAddress); + + if (pGetFileInformationByName == NULL) { + JNU_ThrowInternalError(env, "should not reach here"); + return; + } + + if (!pGetFileInformationByName(lpFileName, (FILE_INFO_BY_NAME_CLASS)infoClass, + pInfo, (ULONG)infoSize)) { + throwWindowsException(env, GetLastError()); + } +} JNIEXPORT void JNICALL Java_sun_nio_fs_WindowsNativeDispatcher_SetFileTime0(JNIEnv* env, jclass this, diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java index 692ccefa69e02..27d6e73fa45ab 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java @@ -2358,8 +2358,9 @@ Symbol findGlobalType(Env env, Scope scope, Name name, RecoveryLoad bestSoFar != sym) { return new AmbiguityError(bestSoFar, sym); } else if (env.toplevel.namedImportScope == scope && - (sym == typeNotFound || (sym.kind == ERR && s.kind == ERR))) { - bestSoFar = bestOf(bestSoFar, new UnresolvableGobalSymbolError(s)); + ((sym == typeNotFound && s.kind.matches(KindSelector.TYP)) || + (sym.kind == ERR && s.kind == ERR))) { + bestSoFar = bestOf(bestSoFar, new UnresolvableGlobalSymbolError(s)); } else bestSoFar = bestOf(bestSoFar, sym); } @@ -4157,9 +4158,9 @@ abstract JCDiagnostic getDiagnostic(JCDiagnostic.DiagnosticType dkind, List typeargtypes); } - class UnresolvableGobalSymbolError extends InvalidSymbolError { + class UnresolvableGlobalSymbolError extends InvalidSymbolError { - UnresolvableGobalSymbolError(Symbol sym) { + UnresolvableGlobalSymbolError(Symbol sym) { super(HIDDEN, sym, "unresolvable class error"); this.name = sym.name; } diff --git a/src/jdk.jcmd/share/conf/bash-completion/jcmd b/src/jdk.jcmd/share/conf/bash-completion/jcmd new file mode 100644 index 0000000000000..c1aca269e721d --- /dev/null +++ b/src/jdk.jcmd/share/conf/bash-completion/jcmd @@ -0,0 +1,157 @@ +# +# Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. +# 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. +# + +# Bash completion for jcmd tool. +# +# Source this file from an interactive shell: +# source /path/to/bash-completion/jcmd +# + +# 'complete' is a Bash builtin from Programmable Completion framework +if ! builtin complete &>/dev/null; then + return 0 2>/dev/null || exit 0 +fi + +function _jcmd__dedupe_words() { + awk '!seen[$0]++' +} + +# list JVM processes on the local machine, except `jcmd` itself. +# Output format: " \n" +function _jcmd__list_processes() { + jcmd -l 2>/dev/null | awk ' + $1 ~ /^[0-9]+$/ && $2 != "jdk.jcmd/sun.tools.jcmd.JCmd" { + print $1, $2 + } + ' +} + +# query the list of commands known by the target JVM +function _jcmd__list_commands_for_jvm() { + local -r jvm_identifier=$1 # can also be a main class name + + jcmd "${jvm_identifier}" help 2>/dev/null | awk ' + /^The following commands are available:/ { in_block=1; next } + /^For more information/ { in_block=0 } + in_block && $1 != "" { print $1 } + ' +} + + +function _jcmd__complete_first_arg() { + local -r cur=$1 + + # include generic options as well + local -a candidates=("-l" "--help") + + local pid main_class _rest + while read -r pid main_class _rest; do + candidates+=("${pid}" "${main_class}") + done < <(_jcmd__list_processes) + + local -r wordlist=$(printf '%s\n' "${candidates[@]}" | _jcmd__dedupe_words | tr '\n' ' ') + COMPREPLY=( $(compgen -W "${wordlist}" -- "${cur}") ) +} + + +function _jcmd__complete_command() { + local -r jvm_identifier=$1 + local -r cur=$2 + + # include "read commands from file" -f flag + local -a commands=("-f") + + local cmd + while read -r cmd; do + [[ -z $cmd ]] && continue + commands+=("$cmd") + done < <(_jcmd__list_commands_for_jvm "${jvm_identifier}") + + printf -v wordlist '%s ' "${commands[@]}" + COMPREPLY=( $(compgen -W "${wordlist}" -- "${cur}") ) +} + + +function _jcmd__complete_help_command() { + local -r jvm_identifier=$1 + local -r cur=$2 + + local -a commands=() + + local cmd + while read -r cmd; do + [[ -z ${cmd} || ${cmd} == help ]] && continue + commands+=("${cmd}") + done < <(_jcmd__list_commands_for_jvm "${jvm_identifier}") + + printf -v wordlist '%s ' "${commands[@]}" + COMPREPLY=( $(compgen -W "${wordlist}" -- "${cur}") ) +} + + +function _jcmd_completion() { + COMPREPLY=() + + # current word, possibly incomplete + local -r cur=${COMP_WORDS[COMP_CWORD]} + + # COMP_WORDS + # An array variable consisting of the individual words in the current command line. + # The line is split into words as `readline` would split it, using COMP_WORDBREAKS. + # A word is considered complete once it is followed by a space. + # COMP_CWORD + # An index into ${COMP_WORDS} of the word containing the current cursor position. + # Examples: + # "jcmd " -> COMP_CWORD = 1, cur = "" + # "jcmd MyA" -> COMP_CWORD = 1, cur = "MyA" + # "jcmd MyApp" -> COMP_CWORD = 1, cur = "MyApp" + # "jcmd MyApp " -> COMP_CWORD = 2, cur = "" + + if [[ ${COMP_CWORD} -eq 1 ]]; then + _jcmd__complete_first_arg "$cur" + return 0 + fi + + local -r jvm_identifier=${COMP_WORDS[1]} + + # 2nd argument: diagnostic command. + if [[ ${COMP_CWORD} -eq 2 ]]; then + _jcmd__complete_command "${jvm_identifier}" "${cur}" + return 0 + fi + + if [[ ${COMP_CWORD} -eq 3 ]]; then + if [[ ${COMP_WORDS[2]} == help ]]; then + _jcmd__complete_help_command "${jvm_identifier}" "${cur}" + elif [[ ${COMP_WORDS[2]} == "-f" ]]; then + # autocomplete filename + compopt -o filenames 2>/dev/null + COMPREPLY=( $(compgen -f -- "${cur}") ) + fi + return 0 + fi +} + +# Avoid alphabetical sorting of completion candidates on double-TAB. This +# keeps each JVM identifier (main class or JAR path) next to its PID. +complete -o nosort -F _jcmd_completion jcmd diff --git a/src/jdk.sctp/unix/native/libsctp/SctpChannelImpl.c b/src/jdk.sctp/unix/native/libsctp/SctpChannelImpl.c index 83f3519fbe222..e25da7993ec99 100644 --- a/src/jdk.sctp/unix/native/libsctp/SctpChannelImpl.c +++ b/src/jdk.sctp/unix/native/libsctp/SctpChannelImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -389,7 +389,7 @@ void handleMessage (JNIEnv* env, jobject resultContainerObj, struct msghdr* msg,int read, jboolean isEOR, struct sockaddr* sap) { jobject isa, resultObj; - struct controlData cdata[1]; + struct controlData cdata[1] = {0}; if (read == 0) { /* we reached EOF */ diff --git a/test/hotspot/jtreg/compiler/arguments/TestCompilerCounts.java b/test/hotspot/jtreg/compiler/arguments/TestCompilerCounts.java index 870daa7f0a56b..e3f1d59d67c6b 100644 --- a/test/hotspot/jtreg/compiler/arguments/TestCompilerCounts.java +++ b/test/hotspot/jtreg/compiler/arguments/TestCompilerCounts.java @@ -1,6 +1,6 @@ /* * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,8 +23,8 @@ */ /* - * @test - * @library /test/lib / + * @test id=debug + * @library /test/lib * @bug 8356000 * @requires vm.flagless * @requires vm.bits == "64" @@ -33,8 +33,8 @@ */ /* - * @test - * @library /test/lib / + * @test id=product + * @library /test/lib * @bug 8356000 * @requires vm.flagless * @requires vm.bits == "64" @@ -44,15 +44,10 @@ package compiler.arguments; -import java.io.IOException; -import java.util.List; -import java.util.Arrays; -import java.util.ArrayList; -import java.util.function.Function; import jdk.test.lib.Asserts; -import jdk.test.lib.process.ProcessTools; -import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.cli.CommandLineOptionTest; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; public class TestCompilerCounts { diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 4f7869f444a26..cd4f62825e858 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -1489,6 +1489,16 @@ public class IRNode { beforeMatchingNameRegex(MASK_ALL, "MaskAll"); } + public static final String AARCH64_VMASK_ALL_IMM_I = PREFIX + "AARCH64_VMASK_ALL_IMM_I" + POSTFIX; + static { + machOnlyNameRegex(AARCH64_VMASK_ALL_IMM_I, "vmaskAll_immI"); + } + + public static final String AARCH64_VMASK_ALL_IMM_L = PREFIX + "AARCH64_VMASK_ALL_IMM_L" + POSTFIX; + static { + machOnlyNameRegex(AARCH64_VMASK_ALL_IMM_L, "vmaskAll_immL"); + } + public static final String VECTOR_LONG_TO_MASK = PREFIX + "VECTOR_LONG_TO_MASK" + POSTFIX; static { beforeMatchingNameRegex(VECTOR_LONG_TO_MASK, "VectorLongToMask"); @@ -2718,6 +2728,11 @@ public class IRNode { machOnlyNameRegex(RISCV_VFMADD_MASKED, "vfmadd_masked"); } + public static final String VMASK_AND_NOT_I = PREFIX + "VMASK_AND_NOT_I" + POSTFIX; + static { + machOnlyNameRegex(VMASK_AND_NOT_I, "vmask_and_notI"); + } + public static final String VMASK_AND_NOT_L = PREFIX + "VMASK_AND_NOT_L" + POSTFIX; static { machOnlyNameRegex(VMASK_AND_NOT_L, "vmask_and_notL"); diff --git a/test/hotspot/jtreg/compiler/vectorapi/AllBitsSetVectorMatchRuleTest.java b/test/hotspot/jtreg/compiler/vectorapi/AllBitsSetVectorMatchRuleTest.java index bb88f60dd21d9..2c5b74a078ea4 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/AllBitsSetVectorMatchRuleTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/AllBitsSetVectorMatchRuleTest.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2022, Arm Limited. All rights reserved. + * Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. * 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,7 +39,7 @@ /** * @test - * @bug 8287984 + * @bug 8287984 8378737 * @key randomness * @library /test/lib / * @requires vm.compiler2.enabled @@ -90,8 +91,9 @@ public class AllBitsSetVectorMatchRuleTest { } } + // Tests of C2 match rules for vector ops containing an all-bits-set vector operand. + @Test - @Warmup(10000) @IR(counts = { IRNode.VAND_NOT_I, " >= 1" }) public static void testAllBitsSetVector() { IntVector av = IntVector.fromArray(I_SPECIES, ia, 0); @@ -105,7 +107,6 @@ public static void testAllBitsSetVector() { } @Test - @Warmup(10000) @IR(counts = { IRNode.VAND_NOT_L, " >= 1" }) public static void testVectorVAndNotL() { LongVector av = LongVector.fromArray(L_SPECIES, la, 0); @@ -119,8 +120,7 @@ public static void testVectorVAndNotL() { } @Test - @Warmup(10000) - @IR(counts = { IRNode.VAND_NOT_I_MASKED, " >= 1" }, applyIfPlatform = {"aarch64", "true"}, applyIf = {"UseSVE", "> 0"}) + @IR(counts = { IRNode.VAND_NOT_I_MASKED, " >= 1" }, applyIfCPUFeature = {"sve", "true"}) @IR(counts = { IRNode.VAND_NOT_I_MASKED, " >= 1" }, applyIfPlatform = {"riscv64", "true"}) public static void testVectorVAndNotIMasked() { VectorMask avm = VectorMask.fromArray(I_SPECIES, ma, 0); @@ -137,8 +137,7 @@ public static void testVectorVAndNotIMasked() { } @Test - @Warmup(10000) - @IR(counts = { IRNode.VAND_NOT_L_MASKED, " >= 1" }, applyIfPlatform = {"aarch64", "true"}, applyIf = {"UseSVE", "> 0"}) + @IR(counts = { IRNode.VAND_NOT_L_MASKED, " >= 1" }, applyIfCPUFeature = {"sve", "true"}) @IR(counts = { IRNode.VAND_NOT_L_MASKED, " >= 1" }, applyIfPlatform = {"riscv64", "true"}) public static void testVectorVAndNotLMasked() { VectorMask avm = VectorMask.fromArray(L_SPECIES, ma, 0); @@ -155,7 +154,6 @@ public static void testVectorVAndNotLMasked() { } @Test - @Warmup(10000) @IR(counts = { IRNode.RISCV_VAND_NOTI_VX, " >= 1" }, applyIfPlatform = {"riscv64", "true"}) public static void testAllBitsSetVectorRegI() { IntVector av = IntVector.fromArray(I_SPECIES, ia, 0); @@ -169,7 +167,6 @@ public static void testAllBitsSetVectorRegI() { } @Test - @Warmup(10000) @IR(counts = { IRNode.RISCV_VAND_NOTL_VX, " >= 1" }, applyIfPlatform = {"riscv64", "true"}) public static void testAllBitsSetVectorRegL() { LongVector av = LongVector.fromArray(L_SPECIES, la, 0); @@ -183,7 +180,6 @@ public static void testAllBitsSetVectorRegL() { } @Test - @Warmup(10000) @IR(counts = { IRNode.RISCV_VAND_NOTI_VX_MASKED, " >= 1" }, applyIfPlatform = {"riscv64", "true"}) public static void testAllBitsSetVectorRegIMask() { VectorMask avm = VectorMask.fromArray(I_SPECIES, ma, 0); @@ -200,7 +196,6 @@ public static void testAllBitsSetVectorRegIMask() { } @Test - @Warmup(10000) @IR(counts = { IRNode.RISCV_VAND_NOTL_VX_MASKED, " >= 1" }, applyIfPlatform = {"riscv64", "true"}) public static void testAllBitsSetVectorRegLMask() { VectorMask avm = VectorMask.fromArray(L_SPECIES, ma, 0); @@ -216,11 +211,26 @@ public static void testAllBitsSetVectorRegLMask() { } } + // Tests that VectorMask.andNot() chains match to VMASK_AND_NOT / VAND_NOT (two andNot ops). + @Test + @IR(counts = { IRNode.VAND_NOT_I, "2" }, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + @IR(counts = { IRNode.VMASK_AND_NOT_I, "2" }, applyIfCPUFeature = {"sve", "true"}) + public static void testMaskAndNotI() { + VectorMask avm = VectorMask.fromArray(I_SPECIES, ma, 0); + VectorMask bvm = VectorMask.fromArray(I_SPECIES, mb, 0); + VectorMask cvm = VectorMask.fromArray(I_SPECIES, mc, 0); + avm.andNot(bvm).andNot(cvm).intoArray(mr, 0); + + // Verify results + for (int i = 0; i < I_SPECIES.length(); i++) { + Asserts.assertEquals((ma[i] & (!mb[i])) & (!mc[i]), mr[i]); + } + } + @Test - @Warmup(10000) - @IR(counts = { IRNode.VAND_NOT_L, " >= 1" }, applyIfPlatform = {"aarch64", "true"}, applyIf = {"UseSVE", "0"}) - @IR(counts = { IRNode.VMASK_AND_NOT_L, " >= 1" }, applyIfPlatform = {"aarch64", "true"}, applyIf = {"UseSVE", "> 0"}) - public static void testAllBitsSetMask() { + @IR(counts = { IRNode.VAND_NOT_L, "2" }, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + @IR(counts = { IRNode.VMASK_AND_NOT_L, "2" }, applyIfCPUFeature = {"sve", "true"}) + public static void testMaskAndNotL() { VectorMask avm = VectorMask.fromArray(L_SPECIES, ma, 0); VectorMask bvm = VectorMask.fromArray(L_SPECIES, mb, 0); VectorMask cvm = VectorMask.fromArray(L_SPECIES, mc, 0); @@ -232,7 +242,123 @@ public static void testAllBitsSetMask() { } } + // Tests that mask.not().and(other) matches to VMASK_AND_NOT (AndVMask commutative rule). + @Test + @IR(counts = { IRNode.VMASK_AND_NOT_I, "1" }, applyIfCPUFeature = {"sve", "true"}) + public static void testCommutativeAndVMaskI() { + VectorMask avm = VectorMask.fromArray(I_SPECIES, ma, 0); + VectorMask bvm = VectorMask.fromArray(I_SPECIES, mb, 0); + avm.not().and(bvm).intoArray(mr, 0); + + // Verify results + for (int i = 0; i < I_SPECIES.length(); i++) { + Asserts.assertEquals((!ma[i]) & (mb[i]), mr[i]); + } + } + + @Test + @IR(counts = { IRNode.VMASK_AND_NOT_L, "1" }, applyIfCPUFeature = {"sve", "true"}) + public static void testCommutativeAndVMaskL() { + VectorMask avm = VectorMask.fromArray(L_SPECIES, ma, 0); + VectorMask bvm = VectorMask.fromArray(L_SPECIES, mb, 0); + avm.not().and(bvm).intoArray(mr, 0); + + // Verify results + for (int i = 0; i < L_SPECIES.length(); i++) { + Asserts.assertEquals((!ma[i]) & (mb[i]), mr[i]); + } + } + + // Tests that mask.and(allTrue.xor(other)) matches to VMASK_AND_NOT (XorVMask commutative rule). + @Test + @IR(counts = { IRNode.VMASK_AND_NOT_I, "1" }, applyIfCPUFeature = {"sve", "true"}) + public static void testCommutativeXorVMaskI() { + VectorMask avm = VectorMask.fromArray(I_SPECIES, ma, 0); + VectorMask bvm = VectorMask.fromArray(I_SPECIES, mb, 0); + VectorMask alltrue = I_SPECIES.maskAll(true); + bvm.and(alltrue.xor(avm)).intoArray(mr, 0); + + // Verify results + for (int i = 0; i < I_SPECIES.length(); i++) { + Asserts.assertEquals((mb[i]) & (!ma[i]), mr[i]); + } + } + + @Test + @IR(counts = { IRNode.VMASK_AND_NOT_L, "1" }, applyIfCPUFeature = {"sve", "true"}) + public static void testCommutativeXorVMaskL() { + VectorMask avm = VectorMask.fromArray(L_SPECIES, ma, 0); + VectorMask bvm = VectorMask.fromArray(L_SPECIES, mb, 0); + VectorMask alltrue = L_SPECIES.maskAll(true); + bvm.and(alltrue.xor(avm)).intoArray(mr, 0); + + // Verify results + for (int i = 0; i < L_SPECIES.length(); i++) { + Asserts.assertEquals((mb[i]) & (!ma[i]), mr[i]); + } + } + + // Tests that only one MaskAll machine node is generated (no duplicate "maskall" nodes). + @Test + @IR(counts = { IRNode.AARCH64_VMASK_ALL_IMM_I, "1" }, applyIfCPUFeature = {"sve", "true"}) + public static void testSingleMaskAllI() { + VectorMask avm = VectorMask.fromArray(I_SPECIES, ma, 0); + VectorMask bvm = VectorMask.fromArray(I_SPECIES, mb, 0); + avm.not().or(bvm.not()).intoArray(mr, 0); + + // Verify results + for (int i = 0; i < I_SPECIES.length(); i++) { + Asserts.assertEquals(!ma[i] | !mb[i], mr[i]); + } + } + + @Test + @IR(counts = { IRNode.AARCH64_VMASK_ALL_IMM_L, "1" }, applyIfCPUFeature = {"sve", "true"}) + public static void testSingleMaskAllL() { + VectorMask avm = VectorMask.fromArray(L_SPECIES, ma, 0); + VectorMask bvm = VectorMask.fromArray(L_SPECIES, mb, 0); + avm.not().or(bvm.not()).intoArray(mr, 0); + + // Verify results + for (int i = 0; i < L_SPECIES.length(); i++) { + Asserts.assertEquals(!ma[i] | !mb[i], mr[i]); + } + } + + // Tests that mask.not().andNot(other) doesn't match to VMASK_AND_NOT rule on SVE, + // and only one MaskAll machine node is generated. + @Test + @IR(counts = { IRNode.AARCH64_VMASK_ALL_IMM_I, "1", IRNode.VMASK_AND_NOT_I, "0" }, + applyIfCPUFeature = {"sve", "true"}) + public static void testSingleMaskAllWithAndNotI() { + VectorMask avm = VectorMask.fromArray(I_SPECIES, ma, 0); + VectorMask bvm = VectorMask.fromArray(I_SPECIES, mb, 0); + avm.not().andNot(bvm).intoArray(mr, 0); + + // Verify results + for (int i = 0; i < I_SPECIES.length(); i++) { + Asserts.assertEquals((!ma[i]) & (!mb[i]), mr[i]); + } + } + + @Test + @IR(counts = { IRNode.AARCH64_VMASK_ALL_IMM_L, "1", IRNode.VMASK_AND_NOT_L, "0" }, + applyIfCPUFeature = {"sve", "true"}) + public static void testSingleMaskAllWithAndNotL() { + VectorMask avm = VectorMask.fromArray(L_SPECIES, ma, 0); + VectorMask bvm = VectorMask.fromArray(L_SPECIES, mb, 0); + avm.not().andNot(bvm).intoArray(mr, 0); + + // Verify results + for (int i = 0; i < L_SPECIES.length(); i++) { + Asserts.assertEquals((!ma[i]) & (!mb[i]), mr[i]); + } + } + public static void main(String[] args) { - TestFramework.runWithFlags("--add-modules=jdk.incubator.vector"); + TestFramework testFramework = new TestFramework(); + testFramework.setDefaultWarmup(10000) + .addFlags("--add-modules=jdk.incubator.vector") + .start(); } } diff --git a/test/langtools/tools/javac/recovery/AttrRecovery.java b/test/langtools/tools/javac/recovery/AttrRecovery.java index bd74eb6c3f039..64aaad2a184c3 100644 --- a/test/langtools/tools/javac/recovery/AttrRecovery.java +++ b/test/langtools/tools/javac/recovery/AttrRecovery.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8301580 8322159 8333107 8332230 8338678 8351260 8366196 8372336 8373094 + * @bug 8301580 8322159 8333107 8332230 8338678 8351260 8366196 8372336 8373094 8384229 * @summary Verify error recovery w.r.t. Attr * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -800,6 +800,66 @@ public Void visitVariable(VariableTree tree, Void p) { assertEquals(expected, actual); } + @Test //JDK-8384229 + public void testStaticFieldTypeLookup() throws Exception { + Path out = base.resolve("out"); + + Files.createDirectories(out); + + new JavacTask(tb) + .options("-XDrawDiagnostics", + "-XDdev") + .sources(""" + package test; + import static test.A.Object; + enum A { + Object; + } + class Test { + void foo() { + Object f = ""; + } + } + """) + .outdir(out) + .run() + .writeAll(); + + new JavacTask(tb) + .options("-XDrawDiagnostics", + "-XDdev") + .sources(""" + package test; + import static test.A.Object; + enum A { + Object; + } + class Test { + private static final Object f = ""; + } + """) + .outdir(out) + .run() + .writeAll(); + + new JavacTask(tb) + .options("-XDrawDiagnostics", + "-XDdev") + .sources(""" + package test; + import static test.A.Object; + class A { + public static java.lang.Object Object() { return null; } + } + class Test { + private static final Object f = Object(); + } + """) + .outdir(out) + .run() + .writeAll(); + } + @BeforeEach public void setUp(TestInfo info) throws IOException { base = Path.of(info.getTestMethod().orElseThrow().getName()); diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskLogicOperationsBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskLogicOperationsBenchmark.java new file mode 100644 index 0000000000000..b70588906af99 --- /dev/null +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskLogicOperationsBenchmark.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.jdk.incubator.vector; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.*; + +import jdk.incubator.vector.*; +import java.util.concurrent.TimeUnit; +import java.util.Random; + +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@State(Scope.Thread) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 1) +@Fork(value = 2, jvmArgs = { "--add-modules=jdk.incubator.vector" }) +public class MaskLogicOperationsBenchmark { + @Param({"256", "512", "1024"}) + private int size; + + private static final VectorSpecies B_SPECIES = VectorSpecies.ofLargestShape(byte.class); + private static final VectorSpecies S_SPECIES = VectorSpecies.ofLargestShape(short.class); + private static final VectorSpecies I_SPECIES = VectorSpecies.ofLargestShape(int.class); + private static final VectorSpecies L_SPECIES = VectorSpecies.ofLargestShape(long.class); + + private Random r = new Random(); + private boolean[] ma; + private boolean[] mb; + private boolean[] mc; + + @Setup + public void init() { + ma = new boolean[size]; + mb = new boolean[size]; + mc = new boolean[size]; + + for (int i = 0; i < size; i++) { + ma[i] = r.nextInt() % 2 == 0; + mb[i] = r.nextInt() % 2 == 0; + } + } + + @Benchmark + public void byteMaskAndNot() { + VectorMask vm1 = VectorMask.fromArray(B_SPECIES, ma, 0); + for (int i = 0; i < B_SPECIES.loopBound(size); i += B_SPECIES.length()) { + VectorMask vm2 = VectorMask.fromArray(B_SPECIES, mb, i); + vm1.andNot(vm2).intoArray(mc, i); + } + } + + @Benchmark + public void shortMaskAndNot() { + VectorMask vm1 = VectorMask.fromArray(S_SPECIES, ma, 0); + for (int i = 0; i < S_SPECIES.loopBound(size); i += S_SPECIES.length()) { + VectorMask vm2 = VectorMask.fromArray(S_SPECIES, mb, i); + vm1.andNot(vm2).intoArray(mc, i); + } + } + + @Benchmark + public void intMaskAndNot() { + VectorMask vm1 = VectorMask.fromArray(I_SPECIES, ma, 0); + for (int i = 0; i < I_SPECIES.loopBound(size); i += I_SPECIES.length()) { + VectorMask vm2 = VectorMask.fromArray(I_SPECIES, mb, i); + vm1.andNot(vm2).intoArray(mc, i); + } + } + + @Benchmark + public void longMaskAndNot() { + VectorMask vm1 = VectorMask.fromArray(L_SPECIES, ma, 0); + for (int i = 0; i < L_SPECIES.loopBound(size); i += L_SPECIES.length()) { + VectorMask vm2 = VectorMask.fromArray(L_SPECIES, mb, i); + vm1.andNot(vm2).intoArray(mc, i); + } + } + + @Benchmark + public int highMaskRegisterPressureWithNots() { + int res = 0; + VectorMask vm1 = VectorMask.fromArray(B_SPECIES, ma, 0); + for (int i = 0; i < B_SPECIES.loopBound(size); i += B_SPECIES.length()) { + VectorMask vm2 = VectorMask.fromArray(B_SPECIES, mb, i).not(); + VectorMask vm3 = vm1.or(vm2).not(); + VectorMask vm4 = vm1.xor(vm3).not(); + VectorMask vm5 = vm1.or(vm4).not(); + res += vm2.trueCount(); + res += vm3.trueCount(); + res += vm4.trueCount(); + res += vm5.trueCount(); + } + return res; + } +} \ No newline at end of file