Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Contributing to the JDK

...
Please see the [OpenJDK Developers' Guide](https://openjdk.org/guide/).
42 changes: 42 additions & 0 deletions make/modules/jdk.jcmd/Copy.gmk
Original file line number Diff line number Diff line change
@@ -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)

################################################################################
30 changes: 28 additions & 2 deletions src/hotspot/cpu/aarch64/aarch64.ad
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
10 changes: 5 additions & 5 deletions src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}

Expand Down
4 changes: 2 additions & 2 deletions src/hotspot/cpu/riscv/macroAssembler_riscv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/cpu/riscv/macroAssembler_riscv.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/adlc/formssel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
};

Expand Down
8 changes: 4 additions & 4 deletions src/hotspot/share/asm/codeBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand Down
16 changes: 8 additions & 8 deletions src/hotspot/share/asm/codeBuffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
Expand Down Expand Up @@ -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; }
Expand Down
54 changes: 32 additions & 22 deletions src/hotspot/share/code/nmethod.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -779,10 +789,10 @@ class nmethod : public CodeBlob {
template<typename T>
void set_gc_data(T* gc_data) { _gc_data = reinterpret_cast<void*>(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) {
Expand Down
2 changes: 2 additions & 0 deletions src/hotspot/share/gc/shared/c2/barrierSetC2.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,8 @@ class BarrierSetC2: public CHeapObj<mtGC> {
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 { }
Expand Down
10 changes: 6 additions & 4 deletions src/hotspot/share/gc/shared/gcConfig.cpp
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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);
Expand All @@ -108,6 +109,7 @@ void GCConfig::select_gc_ergonomically() {
FLAG_SET_ERGO_IF_DEFAULT(UseSerialGC, true);
#endif
}
#endif
}

bool GCConfig::is_no_gc_selected() {
Expand Down
30 changes: 30 additions & 0 deletions src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
Loading
Loading