From 3f37c5718d676b7001e6a084aed3ba645745a144 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Mon, 8 Jul 2024 01:19:36 +0000 Subject: [PATCH 001/460] 8335806: RISC-V: Corrected typos Bizarrely Reviewed-by: aph, amitkumar --- src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp | 2 +- src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp index 7e3ceb1f020..251ea3813ff 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp @@ -1154,7 +1154,7 @@ void C2_MacroAssembler::string_compare(Register str1, Register str2, BLOCK_COMMENT("string_compare {"); - // Bizzarely, the counts are passed in bytes, regardless of whether they + // Bizarrely, the counts are passed in bytes, regardless of whether they // are L or U strings, however the result is always in characters. if (!str1_isL) asrw(cnt1, cnt1, 1); if (!str2_isL) asrw(cnt2, cnt2, 1); diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index 887baa4a506..3cb2e52c8cb 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -1322,7 +1322,7 @@ void C2_MacroAssembler::string_compare(Register str1, Register str2, BLOCK_COMMENT("string_compare {"); - // Bizzarely, the counts are passed in bytes, regardless of whether they + // Bizarrely, the counts are passed in bytes, regardless of whether they // are L or U strings, however the result is always in characters. if (!str1_isL) { sraiw(cnt1, cnt1, 1); From 02956ab6e161ca8556a73f328f79bcbfba997cbc Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Mon, 8 Jul 2024 06:23:03 +0000 Subject: [PATCH 002/460] 8332163: C2 SuperWord: refactor PacksetGraph and SuperWord::output into VTransformGraph Reviewed-by: chagedorn, kvn --- src/hotspot/share/opto/superword.cpp | 816 +++--------------- src/hotspot/share/opto/superword.hpp | 18 +- .../share/opto/superwordVTransformBuilder.cpp | 308 +++++++ .../share/opto/superwordVTransformBuilder.hpp | 87 ++ .../share/opto/traceAutoVectorizationTag.hpp | 1 + src/hotspot/share/opto/vectorization.cpp | 1 - src/hotspot/share/opto/vectorization.hpp | 16 +- src/hotspot/share/opto/vtransform.cpp | 450 ++++++++++ src/hotspot/share/opto/vtransform.hpp | 515 +++++++++++ 9 files changed, 1489 insertions(+), 723 deletions(-) create mode 100644 src/hotspot/share/opto/superwordVTransformBuilder.cpp create mode 100644 src/hotspot/share/opto/superwordVTransformBuilder.hpp create mode 100644 src/hotspot/share/opto/vtransform.cpp create mode 100644 src/hotspot/share/opto/vtransform.hpp diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index f78a9b63926..ba2dd423bf5 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -22,22 +22,13 @@ */ #include "precompiled.hpp" -#include "libadt/vectset.hpp" -#include "memory/allocation.inline.hpp" -#include "memory/resourceArea.hpp" #include "opto/addnode.hpp" -#include "opto/c2compiler.hpp" #include "opto/castnode.hpp" #include "opto/convertnode.hpp" -#include "opto/matcher.hpp" -#include "opto/memnode.hpp" -#include "opto/opcodes.hpp" -#include "opto/opaquenode.hpp" -#include "opto/rootnode.hpp" #include "opto/superword.hpp" +#include "opto/superwordVTransformBuilder.hpp" #include "opto/vectornode.hpp" #include "opto/movenode.hpp" -#include "utilities/powerOfTwo.hpp" SuperWord::SuperWord(const VLoopAnalyzer &vloop_analyzer) : _vloop_analyzer(vloop_analyzer), @@ -707,7 +698,7 @@ bool SuperWord::can_pack_into_pair(Node* s1, Node* s2) { } // Forbid anything that looks like a PopulateIndex to be packed. It does not need to be packed, - // and will still be vectorized by SuperWord::vector_opd. + // and will still be vectorized by SuperWordVTransformBuilder::get_or_make_vtnode_vector_input_at_index. if (isomorphic(s1, s2) && !is_populate_index(s1, s2)) { if ((independent(s1, s2) && have_similar_inputs(s1, s2)) || reduction(s1, s2)) { if (!_pairset.is_left(s1) && !_pairset.is_right(s2)) { @@ -769,8 +760,9 @@ bool SuperWord::isomorphic(Node* s1, Node* s2) { } } -// Look for pattern n1 = (iv + c) and n2 = (iv + c + 1), which may lead to PopulateIndex vector node. -// We skip the pack creation of these nodes. They will be vectorized by SuperWord::vector_opd. +// Look for pattern n1 = (iv + c) and n2 = (iv + c + 1), which may lead to +// PopulateIndex vector node. We skip the pack creation of these nodes. They +// will be vectorized by SuperWordVTransformBuilder::get_or_make_vtnode_vector_input_at_index. bool SuperWord::is_populate_index(const Node* n1, const Node* n2) const { return n1->is_Add() && n2->is_Add() && @@ -1858,307 +1850,74 @@ void PackSet::verify() const { } #endif -// The PacksetGraph combines the dependency graph with the packset. In the PackSet -// graph, we have two kinds of nodes: -// (1) pack-node: Represents all nodes of some pack p in a single node, which -// shall later become a vector node. -// (2) scalar-node: Represents a node that is not in any pack. -// For any edge (n1, n2) in the dependency graph, we add an edge to the PacksetGraph for -// the PacksetGraph nodes corresponding to n1 and n2. -// We work from the dependency graph, because it gives us all the data-dependencies, -// as well as more refined memory-dependencies than the C2 graph. The dependency graph -// does not have cycles. But packing nodes can introduce cyclic dependencies. Example: -// -// +--------+ -// A -> X | v -// Pack [A,B] and [X,Y] [A,B] [X,Y] -// Y -> B ^ | -// +--------+ -// -class PacksetGraph { -private: - // pid: packset graph node id. - GrowableArray _pid; // bb_idx(n) -> pid - GrowableArray _pid_to_node; // one node per pid, find rest via _packset.pack - GrowableArray> _out; // out-edges - GrowableArray _incnt; // number of (implicit) in-edges - int _max_pid = 0; - - bool _schedule_success; - - SuperWord* _slp; -public: - PacksetGraph(SuperWord* slp) - : _pid(8, 0, /* default */ 0), _slp(slp) { - } - // Get pid, if there is a packset node that n belongs to. Else return 0. - int get_pid_or_zero(const Node* n) const { - if (!_slp->in_bb(n)) { - return 0; - } - int idx = _slp->bb_idx(n); - if (idx >= _pid.length()) { - return 0; - } else { - return _pid.at(idx); - } - } - int get_pid(const Node* n) { - int poz = get_pid_or_zero(n); - assert(poz != 0, "pid should not be zero"); - return poz; - } - void set_pid(Node* n, int pid) { - assert(n != nullptr && pid > 0, "sane inputs"); - assert(_slp->in_bb(n), "must be"); - int idx = _slp->bb_idx(n); - _pid.at_put_grow(idx, pid); - _pid_to_node.at_put_grow(pid - 1, n, nullptr); - } - Node* get_node(int pid) { - assert(pid > 0 && pid <= _pid_to_node.length(), "pid must be mapped"); - Node* n = _pid_to_node.at(pid - 1); - assert(n != nullptr, "sanity"); - return n; - } - int new_pid() { - _incnt.push(0); - _out.push(GrowableArray()); - return ++_max_pid; - } - int incnt(int pid) { return _incnt.at(pid - 1); } - void incnt_set(int pid, int cnt) { return _incnt.at_put(pid - 1, cnt); } - GrowableArray& out(int pid) { return _out.at(pid - 1); } - bool schedule_success() const { return _schedule_success; } - - // Create nodes (from packs and scalar-nodes), and add edges, based on the dependency graph. - void build() { - const PackSet& packset = _slp->packset(); - const GrowableArray& body = _slp->body(); - // Map nodes in packsets - for (int i = 0; i < packset.length(); i++) { - Node_List* p = packset.at(i); - int pid = new_pid(); - for (uint k = 0; k < p->size(); k++) { - Node* n = p->at(k); - set_pid(n, pid); - assert(packset.get_pack(n) == p, "matching packset"); - } - } - - int max_pid_packset = _max_pid; - - // Map nodes not in packset - for (int i = 0; i < body.length(); i++) { - Node* n = body.at(i); - if (n->is_Phi() || n->is_CFG()) { - continue; // ignore control flow - } - int pid = get_pid_or_zero(n); - if (pid == 0) { - pid = new_pid(); - set_pid(n, pid); - assert(packset.get_pack(n) == nullptr, "no packset"); - } - } - - // Map edges for packset nodes - VectorSet set; - for (int i = 0; i < packset.length(); i++) { - Node_List* p = packset.at(i); - set.clear(); - int pid = get_pid(p->at(0)); - for (uint k = 0; k < p->size(); k++) { - Node* n = p->at(k); - assert(pid == get_pid(n), "all nodes in pack have same pid"); - for (VLoopDependencyGraph::PredsIterator preds(_slp->dependency_graph(), n); !preds.done(); preds.next()) { - Node* pred = preds.current(); - int pred_pid = get_pid_or_zero(pred); - if (pred_pid == pid && _slp->is_marked_reduction(n)) { - continue; // reduction -> self-cycle is not a cyclic dependency - } - // Only add edges once, and only for mapped nodes (in body) - if (pred_pid > 0 && !set.test_set(pred_pid)) { - incnt_set(pid, incnt(pid) + 1); // increment - out(pred_pid).push(pid); - } - } - } - } - - // Map edges for nodes not in packset - for (int i = 0; i < body.length(); i++) { - Node* n = body.at(i); - int pid = get_pid_or_zero(n); // zero for Phi or CFG - if (pid <= max_pid_packset) { - continue; // Only scalar-nodes - } - for (VLoopDependencyGraph::PredsIterator preds(_slp->dependency_graph(), n); !preds.done(); preds.next()) { - Node* pred = preds.current(); - int pred_pid = get_pid_or_zero(pred); - // Only add edges for mapped nodes (in body) - if (pred_pid > 0) { - incnt_set(pid, incnt(pid) + 1); // increment - out(pred_pid).push(pid); - } - } - } - } - - // Schedule nodes of PacksetGraph to worklist, using topsort: schedule a node - // that has zero incnt. If a PacksetGraph node corresponds to memops, then add - // those to the memops_schedule. At the end, we return the memops_schedule, and - // note if topsort was successful. - Node_List schedule() { - Node_List memops_schedule; - GrowableArray worklist; - // Directly schedule all nodes without precedence - for (int pid = 1; pid <= _max_pid; pid++) { - if (incnt(pid) == 0) { - worklist.push(pid); - } - } - // Continue scheduling via topological sort - for (int i = 0; i < worklist.length(); i++) { - int pid = worklist.at(i); - - // Add memops to memops_schedule - Node* n = get_node(pid); - Node_List* p = _slp->packset().get_pack(n); - if (n->is_Mem()) { - if (p == nullptr) { - memops_schedule.push(n); - } else { - for (uint k = 0; k < p->size(); k++) { - memops_schedule.push(p->at(k)); - assert(p->at(k)->is_Mem(), "only schedule memops"); - } - } - } +bool SuperWord::schedule_and_apply() const { + if (_packset.is_empty()) { return false; } - // Decrement incnt for all successors - for (int j = 0; j < out(pid).length(); j++){ - int pid_use = out(pid).at(j); - int incnt_use = incnt(pid_use) - 1; - incnt_set(pid_use, incnt_use); - // Did use lose its last input? - if (incnt_use == 0) { - worklist.push(pid_use); - } - } - } - - // Was every pid scheduled? If not, we found some cycles in the PacksetGraph. - _schedule_success = (worklist.length() == _max_pid); - return memops_schedule; - } - - // Print the PacksetGraph. - // print_nodes = true: print all C2 nodes beloning to PacksetGrahp node. - // print_zero_incnt = false: do not print nodes that have no in-edges (any more). - void print(bool print_nodes, bool print_zero_incnt) { - const GrowableArray &body = _slp->body(); - tty->print_cr("PacksetGraph"); - for (int pid = 1; pid <= _max_pid; pid++) { - if (incnt(pid) == 0 && !print_zero_incnt) { - continue; - } - tty->print("Node %d. incnt %d [", pid, incnt(pid)); - for (int j = 0; j < out(pid).length(); j++) { - tty->print("%d ", out(pid).at(j)); - } - tty->print_cr("]"); + // Make an empty transform. #ifndef PRODUCT - if (print_nodes) { - for (int i = 0; i < body.length(); i++) { - Node* n = body.at(i); - if (get_pid_or_zero(n) == pid) { - tty->print(" "); - n->dump(); - } - } - } + VTransformTrace trace(_vloop.vtrace(), + is_trace_superword_rejections(), + is_trace_align_vector(), + is_trace_superword_info()); #endif - } - } -}; - -// We want to replace the packed scalars from the PackSet and replace them -// with vector operations. This requires scheduling and re-ordering the memory -// graph. We take these steps: -// (1) Build the PacksetGraph. It combines the dependency graph with the -// packset. The PacksetGraph gives us the dependencies that must be -// respected after scheduling. -// (2) Schedule the PacksetGraph to the memops_schedule, which represents -// a linear order of all memops in the body. The order respects the -// dependencies of the PacksetGraph. -// (3) If the PacksetGraph has cycles, we cannot schedule. Abort. -// (4) Apply the vectorization, including re-ordering the memops and replacing -// packed scalars with vector operations. -bool SuperWord::schedule_and_apply() { - if (_packset.is_empty()) { - return false; - } - ResourceMark rm; + VTransform vtransform(_vloop_analyzer, + _mem_ref_for_main_loop_alignment, + _aw_for_main_loop_alignment + NOT_PRODUCT(COMMA trace) + ); - // (1) Build the PacksetGraph. - PacksetGraph graph(this); - graph.build(); + // Build the transform from the packset. + { + ResourceMark rm; + SuperWordVTransformBuilder builder(_packset, vtransform); + } - // (2) Schedule the PacksetGraph. - Node_List memops_schedule = graph.schedule(); + if (!vtransform.schedule()) { return false; } + vtransform.apply(); + return true; +} - // (3) Check if the PacksetGraph schedule succeeded (had no cycles). - // We now know that we only have independent packs, see verify_packs. - // This is a necessary but not a sufficient condition for an acyclic - // graph (DAG) after scheduling. Thus, we must check if the packs have - // introduced a cycle. The SuperWord paper mentions the need for this - // in "3.7 Scheduling". - if (!graph.schedule_success()) { +// Apply the vectorization, i.e. we irreversibly edit the C2 graph. At this point, all +// correctness and profitability checks have passed, and the graph was successfully scheduled. +void VTransform::apply() { #ifndef PRODUCT - if (is_trace_superword_rejections()) { - tty->print_cr("SuperWord::schedule found cycle in PacksetGraph:"); - graph.print(true, false); - tty->print_cr("removing all packs from packset."); - } -#endif - _packset.clear(); - return false; + if (_trace._info || TraceLoopOpts) { + tty->print_cr("\nVTransform::apply:"); + lpt()->dump_head(); + lpt()->head()->dump(); } + assert(cl()->is_main_loop(), "auto vectorization only for main loops"); + assert(_graph.is_scheduled(), "must already be scheduled"); +#endif - // (4) Apply the vectorization, including re-ordering the memops. - return apply(memops_schedule); -} - -bool SuperWord::apply(Node_List& memops_schedule) { Compile* C = phase()->C; - CountedLoopNode* cl = lpt()->_head->as_CountedLoop(); - C->print_method(PHASE_AUTO_VECTORIZATION1_BEFORE_APPLY, 4, cl); + C->print_method(PHASE_AUTO_VECTORIZATION1_BEFORE_APPLY, 4, cl()); - apply_memops_reordering_with_schedule(memops_schedule); - C->print_method(PHASE_AUTO_VECTORIZATION2_AFTER_REORDER, 4, cl); + _graph.apply_memops_reordering_with_schedule(); + C->print_method(PHASE_AUTO_VECTORIZATION2_AFTER_REORDER, 4, cl()); adjust_pre_loop_limit_to_align_main_loop_vectors(); - C->print_method(PHASE_AUTO_VECTORIZATION3_AFTER_ADJUST_LIMIT, 4, cl); - - bool is_success = apply_vectorization(); - C->print_method(PHASE_AUTO_VECTORIZATION4_AFTER_APPLY, 4, cl); + C->print_method(PHASE_AUTO_VECTORIZATION3_AFTER_ADJUST_LIMIT, 4, cl()); - return is_success; + apply_vectorization(); + C->print_method(PHASE_AUTO_VECTORIZATION4_AFTER_APPLY, 4, cl()); } -// Reorder the memory graph for all slices in parallel. We walk over the schedule once, -// and track the current memory state of each slice. -void SuperWord::apply_memops_reordering_with_schedule(Node_List& memops_schedule) { +// We prepare the memory graph for the replacement of scalar memops with vector memops. +// We reorder all slices in parallel, ensuring that the memops inside each slice are +// ordered according to the _schedule. This means that all packed memops are consecutive +// in the memory graph after the reordering. +void VTransformGraph::apply_memops_reordering_with_schedule() const { #ifndef PRODUCT - if (is_trace_superword_info()) { - tty->print_cr("\nSuperWord::apply_memops_reordering_with_schedule:"); - memops_schedule.dump(); + assert(is_scheduled(), "must be already scheduled"); + if (_trace._info) { + print_memops_schedule(); } #endif + ResourceMark rm; int max_slices = phase()->C->num_alias_types(); - // When iterating over the memops_schedule, we keep track of the current memory state, + // When iterating over the schedule, we keep track of the current memory state, // which is the Phi or a store in the loop. GrowableArray current_state_in_slice(max_slices, max_slices, nullptr); // The memory state after the loop is the last store inside the loop. If we reorder the @@ -2179,10 +1938,9 @@ void SuperWord::apply_memops_reordering_with_schedule(Node_List& memops_schedule old_last_store_in_slice.at_put(alias_idx, last_store); } - // (2) Walk over memops_schedule, append memops to the current state + // (2) Walk over schedule, append memops to the current state // of that slice. If it is a Store, we take it as the new state. - for (uint i = 0; i < memops_schedule.size(); i++) { - MemNode* n = memops_schedule.at(i)->as_Mem(); + for_each_memop_in_schedule([&] (MemNode* n) { assert(n->is_Load() || n->is_Store(), "only loads or stores"); int alias_idx = phase()->C->get_alias_index(n->adr_type()); Node* current_state = current_state_in_slice.at(alias_idx); @@ -2198,12 +1956,12 @@ void SuperWord::apply_memops_reordering_with_schedule(Node_List& memops_schedule current_state_in_slice.at_put(alias_idx, n); } } - } + }); // (3) For each slice, we add the current state to the backedge // in the Phi. Further, we replace uses of the old last store // with uses of the new last store (current_state). - Node_List uses_after_loop; + GrowableArray uses_after_loop; for (int i = 0; i < mem_slice_head.length(); i++) { Node* phi = mem_slice_head.at(i); int alias_idx = phase()->C->get_alias_index(phi->adr_type()); @@ -2225,7 +1983,7 @@ void SuperWord::apply_memops_reordering_with_schedule(Node_List& memops_schedule uses_after_loop.push(use); } } - for (uint k = 0; k < uses_after_loop.size(); k++) { + for (int k = 0; k < uses_after_loop.length(); k++) { Node* use = uses_after_loop.at(k); for (uint j = 0; j < use->req(); j++) { Node* def = use->in(j); @@ -2237,396 +1995,65 @@ void SuperWord::apply_memops_reordering_with_schedule(Node_List& memops_schedule } } -// Convert packs into vector node operations -// At this point, all correctness and profitability checks have passed. -// We start the irreversible process of editing the C2 graph. Should -// there be an unexpected situation (assert fails), then we can only -// bail out of the compilation, as the graph has already been partially -// modified. We bail out, and retry without SuperWord. -bool SuperWord::apply_vectorization() { - CountedLoopNode *cl = lpt()->_head->as_CountedLoop(); - assert(cl->is_main_loop(), "SLP should only work on main loops"); - Compile* C = phase()->C; - assert(!_packset.is_empty(), "vectorization requires non-empty packset"); - -#ifndef PRODUCT - if (TraceLoopOpts) { - tty->print("SuperWord::apply_vectorization "); - lpt()->dump_head(); - } -#endif - - uint max_vlen_in_bytes = 0; - uint max_vlen = 0; - - for (int i = 0; i < body().length(); i++) { - Node* n = body().at(i); - Node_List* p = get_pack(n); - if (p != nullptr && n == p->at(p->size()-1)) { - // After apply_memops_reordering_with_schedule, we know that the memops have the same order in the pack - // as in the memory slice. Hence, "first" is the first memop in the slice from the pack, - // and "n" is the last node in the slice from the pack. - Node* first = p->at(0); - uint vlen = p->size(); - uint vlen_in_bytes = 0; - Node* vn = nullptr; - int opc = n->Opcode(); - if (n->is_Load()) { - Node* ctl = n->in(MemNode::Control); - Node* mem = first->in(MemNode::Memory); - // Set the memory dependency of the LoadVector as early as possible. - // Walk up the memory chain, and ignore any StoreVector that provably - // does not have any memory dependency. - while (mem->is_StoreVector()) { - VPointer p_store(mem->as_Mem(), _vloop); - if (p_store.overlap_possible_with_any_in(p)) { - break; - } else { - mem = mem->in(MemNode::Memory); - } - } - Node* adr = first->in(MemNode::Address); - const TypePtr* atyp = n->adr_type(); - vn = LoadVectorNode::make(opc, ctl, mem, adr, atyp, vlen, velt_basic_type(n), control_dependency(p)); - vlen_in_bytes = vn->as_LoadVector()->memory_size(); - } else if (n->is_Store()) { - // Promote value to be stored to vector - Node* val = vector_opd(p, MemNode::ValueIn); - if (val == nullptr) { - assert(false, "input to vector store was not created"); - C->record_failure(C2Compiler::retry_no_superword()); - return false; // bailout - } +void VTransformGraph::apply_vectorization_for_each_vtnode(uint& max_vector_length, uint& max_vector_width) const { + ResourceMark rm; + // We keep track of the resulting Nodes from every "VTransformNode::apply" call. + // Since "apply" is called on defs before uses, this allows us to find the + // generated def (input) nodes when we are generating the use nodes in "apply". + int length = _vtnodes.length(); + GrowableArray vtnode_idx_to_transformed_node(length, length, nullptr); - Node* ctl = n->in(MemNode::Control); - Node* mem = first->in(MemNode::Memory); - Node* adr = first->in(MemNode::Address); - const TypePtr* atyp = n->adr_type(); - vn = StoreVectorNode::make(opc, ctl, mem, adr, atyp, val, vlen); - vlen_in_bytes = vn->as_StoreVector()->memory_size(); - } else if (VectorNode::is_scalar_rotate(n)) { - Node* in1 = vector_opd(p, 1); - Node* in2 = first->in(2); - // If rotation count is non-constant or greater than 8bit value create a vector. - if (!in2->is_Con() || !Matcher::supports_vector_constant_rotates(in2->get_int())) { - in2 = vector_opd(p, 2); - } - vn = VectorNode::make(opc, in1, in2, vlen, velt_basic_type(n)); - vlen_in_bytes = vn->as_Vector()->length_in_bytes(); - } else if (VectorNode::is_roundopD(n)) { - Node* in1 = vector_opd(p, 1); - Node* in2 = first->in(2); - assert(in2->is_Con(), "Constant rounding mode expected."); - vn = VectorNode::make(opc, in1, in2, vlen, velt_basic_type(n)); - vlen_in_bytes = vn->as_Vector()->length_in_bytes(); - } else if (VectorNode::is_muladds2i(n)) { - assert(n->req() == 5u, "MulAddS2I should have 4 operands."); - Node* in1 = vector_opd(p, 1); - Node* in2 = vector_opd(p, 2); - vn = VectorNode::make(opc, in1, in2, vlen, velt_basic_type(n)); - vlen_in_bytes = vn->as_Vector()->length_in_bytes(); - } else if (opc == Op_SignumF || opc == Op_SignumD) { - assert(n->req() == 4, "four inputs expected"); - Node* in = vector_opd(p, 1); - Node* zero = vector_opd(p, 2); - Node* one = vector_opd(p, 3); - vn = VectorNode::make(opc, in, zero, one, vlen, velt_basic_type(n)); - vlen_in_bytes = vn->as_Vector()->length_in_bytes(); - } else if (n->is_Cmp()) { - // Bool + Cmp + CMove -> VectorMaskCmp + VectorBlend - continue; - } else if (n->is_Bool()) { - // Bool + Cmp + CMove -> VectorMaskCmp + VectorBlend - continue; - } else if (n->is_CMove()) { - // Bool + Cmp + CMove -> VectorMaskCmp + VectorBlend - - BoolNode* bol = n->in(1)->as_Bool(); - assert(bol != nullptr, "must have Bool above CMove"); - Node_List* bool_pack = get_pack(bol); - assert(bool_pack != nullptr, "CMove must have matching Bool pack"); - - CmpNode* cmp = bol->in(1)->as_Cmp(); - assert(cmp != nullptr, "must have cmp above CMove"); - Node_List* cmp_pack = get_pack(cmp); - assert(cmp_pack != nullptr, "Bool must have matching Cmp pack"); - - Node* cmp_in1 = vector_opd(cmp_pack, 1); - Node* cmp_in2 = vector_opd(cmp_pack, 2); - - Node* blend_in1 = vector_opd(p, 2); - Node* blend_in2 = vector_opd(p, 3); - - VTransformBoolTest bool_test = _packset.get_bool_test(bool_pack); - BoolTest::mask test_mask = bool_test._mask; - if (bool_test._is_negated) { - // We can cancel out the negation by swapping the blend inputs. - swap(blend_in1, blend_in2); - } + for (int i = 0; i < _schedule.length(); i++) { + VTransformNode* vtn = _schedule.at(i); + VTransformApplyResult result = vtn->apply(_vloop_analyzer, + vtnode_idx_to_transformed_node); + NOT_PRODUCT( if (_trace._verbose) { result.trace(vtn); } ) - // VectorMaskCmp - ConINode* test_mask_node = igvn().intcon((int)test_mask); - BasicType bt = velt_basic_type(cmp); - const TypeVect* vt = TypeVect::make(bt, vlen); - VectorNode* mask = new VectorMaskCmpNode(test_mask, cmp_in1, cmp_in2, test_mask_node, vt); - phase()->register_new_node_with_ctrl_of(mask, p->at(0)); - igvn()._worklist.push(mask); - - // VectorBlend - vn = new VectorBlendNode(blend_in1, blend_in2, mask); - } else if (n->req() == 3) { - // Promote operands to vector - Node* in1 = nullptr; - bool node_isa_reduction = is_marked_reduction(n); - if (node_isa_reduction) { - // the input to the first reduction operation is retained - in1 = first->in(1); - } else { - in1 = vector_opd(p, 1); - if (in1 == nullptr) { - assert(false, "input in1 to vector operand was not created"); - C->record_failure(C2Compiler::retry_no_superword()); - return false; // bailout - } - } - Node* in2 = vector_opd(p, 2); - if (in2 == nullptr) { - assert(false, "input in2 to vector operand was not created"); - C->record_failure(C2Compiler::retry_no_superword()); - return false; // bailout - } - if (in1->Opcode() == Op_Replicate && (node_isa_reduction == false) && (n->is_Add() || n->is_Mul())) { - // Move invariant vector input into second position to avoid register spilling. - Node* tmp = in1; - in1 = in2; - in2 = tmp; - } - if (node_isa_reduction) { - const Type *arith_type = n->bottom_type(); - vn = ReductionNode::make(opc, nullptr, in1, in2, arith_type->basic_type()); - if (in2->is_Load()) { - vlen_in_bytes = in2->as_LoadVector()->memory_size(); - } else { - vlen_in_bytes = in2->as_Vector()->length_in_bytes(); - } - } else { - if (VectorNode::can_use_RShiftI_instead_of_URShiftI(n, velt_basic_type(n))) { - opc = Op_RShiftI; - } - vn = VectorNode::make(opc, in1, in2, vlen, velt_basic_type(n)); - vlen_in_bytes = vn->as_Vector()->length_in_bytes(); - } - } else if (VectorNode::is_scalar_unary_op_with_equal_input_and_output_types(opc)) { - assert(n->req() == 2, "only one input expected"); - Node* in = vector_opd(p, 1); - vn = VectorNode::make(opc, in, nullptr, vlen, velt_basic_type(n)); - vlen_in_bytes = vn->as_Vector()->length_in_bytes(); - } else if (VectorNode::is_scalar_op_that_returns_int_but_vector_op_returns_long(opc)) { - assert(n->req() == 2, "only one input expected"); - Node* in = vector_opd(p, 1); - Node* longval = VectorNode::make(opc, in, nullptr, vlen, T_LONG); - phase()->register_new_node_with_ctrl_of(longval, first); - // Requires extra vector long -> int conversion. - vn = VectorCastNode::make(Op_VectorCastL2X, longval, T_INT, vlen); - vlen_in_bytes = vn->as_Vector()->length_in_bytes(); - } else if (VectorNode::is_convert_opcode(opc)) { - assert(n->req() == 2, "only one input expected"); - BasicType bt = velt_basic_type(n); - Node* in = vector_opd(p, 1); - int vopc = VectorCastNode::opcode(opc, in->bottom_type()->is_vect()->element_basic_type()); - vn = VectorCastNode::make(vopc, in, bt, vlen); - vlen_in_bytes = vn->as_Vector()->length_in_bytes(); - } else if (opc == Op_FmaD || opc == Op_FmaF) { - // Promote operands to vector - Node* in1 = vector_opd(p, 1); - Node* in2 = vector_opd(p, 2); - Node* in3 = vector_opd(p, 3); - vn = VectorNode::make(opc, in1, in2, in3, vlen, velt_basic_type(n)); - vlen_in_bytes = vn->as_Vector()->length_in_bytes(); - } else { - assert(false, "Unhandled scalar opcode (%s)", NodeClassNames[opc]); - C->record_failure(C2Compiler::retry_no_superword()); - return false; // bailout - } - - if (vn == nullptr) { - assert(false, "got null node instead of vector node"); - C->record_failure(C2Compiler::retry_no_superword()); - return false; // bailout - } + vtnode_idx_to_transformed_node.at_put(vtn->_idx, result.node()); + max_vector_length = MAX2(max_vector_length, result.vector_length()); + max_vector_width = MAX2(max_vector_width, result.vector_width()); + } +} -#ifdef ASSERT - // Mark Load/Store Vector for alignment verification - if (VerifyAlignVector) { - if (vn->Opcode() == Op_LoadVector) { - vn->as_LoadVector()->set_must_verify_alignment(); - } else if (vn->Opcode() == Op_StoreVector) { - vn->as_StoreVector()->set_must_verify_alignment(); - } - } +// We call "apply" on every VTransformNode, which replaces the packed scalar nodes with vector nodes. +void VTransform::apply_vectorization() const { + Compile* C = phase()->C; +#ifndef PRODUCT + if (_trace._verbose) { + tty->print_cr("\nVTransform::apply_vectorization:"); + } #endif - phase()->register_new_node_with_ctrl_of(vn, first); - for (uint j = 0; j < p->size(); j++) { - Node* pm = p->at(j); - igvn().replace_node(pm, vn); - } - igvn()._worklist.push(vn); + uint max_vector_length = 0; // number of elements + uint max_vector_width = 0; // total width in bytes + _graph.apply_vectorization_for_each_vtnode(max_vector_length, max_vector_width); - if (vlen > max_vlen) { - max_vlen = vlen; - } - if (vlen_in_bytes > max_vlen_in_bytes) { - max_vlen_in_bytes = vlen_in_bytes; - } - VectorNode::trace_new_vector(vn, "SuperWord"); - } - }//for (int i = 0; i < body().length(); i++) + assert(max_vector_length > 0 && max_vector_width > 0, "must have vectorized"); + cl()->mark_loop_vectorized(); - if (max_vlen_in_bytes > C->max_vector_size()) { - C->set_max_vector_size(max_vlen_in_bytes); - } - if (max_vlen_in_bytes > 0) { - cl->mark_loop_vectorized(); + if (max_vector_width > C->max_vector_size()) { + C->set_max_vector_size(max_vector_width); } if (SuperWordLoopUnrollAnalysis) { - if (cl->has_passed_slp()) { - uint slp_max_unroll_factor = cl->slp_max_unroll(); - if (slp_max_unroll_factor == max_vlen) { + if (cl()->has_passed_slp()) { + uint slp_max_unroll_factor = cl()->slp_max_unroll(); + if (slp_max_unroll_factor == max_vector_length) { #ifndef PRODUCT if (TraceSuperWordLoopUnrollAnalysis) { - tty->print_cr("vector loop(unroll=%d, len=%d)\n", max_vlen, max_vlen_in_bytes*BitsPerByte); + tty->print_cr("vector loop(unroll=%d, len=%d)\n", max_vector_length, max_vector_width * BitsPerByte); } #endif // For atomic unrolled loops which are vector mapped, instigate more unrolling - cl->set_notpassed_slp(); + cl()->set_notpassed_slp(); // if vector resources are limited, do not allow additional unrolling if (Matcher::float_pressure_limit() > 8) { C->set_major_progress(); - cl->mark_do_unroll_only(); + cl()->mark_do_unroll_only(); } } } } - - return true; -} - -//------------------------------vector_opd--------------------------- -// Create a vector operand for the nodes in pack p for operand: in(opd_idx) -Node* SuperWord::vector_opd(Node_List* p, int opd_idx) { - Node* p0 = p->at(0); - uint vlen = p->size(); - Node* opd = p0->in(opd_idx); - CountedLoopNode *cl = lpt()->_head->as_CountedLoop(); - Node* same_input = _packset.same_inputs_at_index_or_null(p, opd_idx); - - // Insert index population operation to create a vector of increasing - // indices starting from the iv value. In some special unrolled loops - // (see JDK-8286125), we need scalar replications of the iv value if - // all inputs are the same iv, so we do a same inputs check here. - if (opd == iv() && same_input == nullptr) { - BasicType p0_bt = velt_basic_type(p0); - BasicType iv_bt = is_subword_type(p0_bt) ? p0_bt : T_INT; - assert(VectorNode::is_populate_index_supported(iv_bt), "Should support"); - const TypeVect* vt = TypeVect::make(iv_bt, vlen); - Node* vn = new PopulateIndexNode(iv(), igvn().intcon(1), vt); - VectorNode::trace_new_vector(vn, "SuperWord"); - phase()->register_new_node_with_ctrl_of(vn, opd); - return vn; - } - - if (same_input != nullptr) { - if (opd->is_Vector() || opd->is_LoadVector()) { - if (opd_idx == 2 && VectorNode::is_shift(p0)) { - assert(false, "shift's count can't be vector"); - return nullptr; - } - return opd; // input is matching vector - } - if ((opd_idx == 2) && VectorNode::is_shift(p0)) { - Node* cnt = opd; - // Vector instructions do not mask shift count, do it here. - juint mask = (p0->bottom_type() == TypeInt::INT) ? (BitsPerInt - 1) : (BitsPerLong - 1); - const TypeInt* t = opd->find_int_type(); - if (t != nullptr && t->is_con()) { - juint shift = t->get_con(); - if (shift > mask) { // Unsigned cmp - cnt = igvn().intcon(shift & mask); - phase()->set_ctrl(cnt, phase()->C->root()); - } - } else { - if (t == nullptr || t->_lo < 0 || t->_hi > (int)mask) { - cnt = igvn().intcon(mask); - cnt = new AndINode(opd, cnt); - phase()->register_new_node_with_ctrl_of(cnt, opd); - } - if (!opd->bottom_type()->isa_int()) { - assert(false, "int type only"); - return nullptr; - } - } - // Move shift count into vector register. - cnt = VectorNode::shift_count(p0->Opcode(), cnt, vlen, velt_basic_type(p0)); - phase()->register_new_node_with_ctrl_of(cnt, opd); - return cnt; - } - if (opd->is_StoreVector()) { - assert(false, "StoreVector is not expected here"); - return nullptr; - } - // Convert scalar input to vector with the same number of elements as - // p0's vector. Use p0's type because size of operand's container in - // vector should match p0's size regardless operand's size. - const Type* p0_t = nullptr; - VectorNode* vn = nullptr; - if (opd_idx == 2 && VectorNode::is_scalar_rotate(p0)) { - Node* conv = opd; - p0_t = TypeInt::INT; - if (p0->bottom_type()->isa_long()) { - p0_t = TypeLong::LONG; - conv = new ConvI2LNode(opd); - phase()->register_new_node_with_ctrl_of(conv, opd); - } - vn = VectorNode::scalar2vector(conv, vlen, p0_t); - } else { - p0_t = velt_type(p0); - vn = VectorNode::scalar2vector(opd, vlen, p0_t); - } - - phase()->register_new_node_with_ctrl_of(vn, opd); - VectorNode::trace_new_vector(vn, "SuperWord"); - return vn; - } - - // Insert pack operation - BasicType bt = velt_basic_type(p0); - PackNode* pk = PackNode::make(opd, vlen, bt); - DEBUG_ONLY( const BasicType opd_bt = opd->bottom_type()->basic_type(); ) - - for (uint i = 1; i < vlen; i++) { - Node* pi = p->at(i); - Node* in = pi->in(opd_idx); - if (get_pack(in) != nullptr) { - assert(false, "Should already have been unpacked"); - return nullptr; - } - assert(opd_bt == in->bottom_type()->basic_type(), "all same type"); - pk->add_opd(in); - if (VectorNode::is_muladds2i(pi)) { - Node* in2 = pi->in(opd_idx + 2); - if (get_pack(in2) != nullptr) { - assert(false, "Should already have been unpacked"); - return nullptr; - } - assert(opd_bt == in2->bottom_type()->basic_type(), "all same type"); - pk->add_opd(in2); - } - } - phase()->register_new_node_with_ctrl_of(pk, opd); - VectorNode::trace_new_vector(pk, "SuperWord"); - return pk; } #ifdef ASSERT @@ -2797,18 +2224,7 @@ bool SuperWord::is_vector_use(Node* use, int u_idx) const { return _packset.is_muladds2i_pack_with_pack_inputs(u_pk); } - if (u_pk->size() != d_pk->size()) { - return false; - } - - for (uint i = 0; i < u_pk->size(); i++) { - Node* ui = u_pk->at(i); - Node* di = d_pk->at(i); - if (ui->in(u_idx) != di) { - return false; - } - } - return true; + return _packset.pack_input_at_index_or_null(u_pk, u_idx) != nullptr; } // MulAddS2I takes 4 shorts and produces an int. We can reinterpret @@ -3182,10 +2598,10 @@ bool VLoopMemorySlices::same_memory_slice(MemNode* m1, MemNode* m2) const { _vloop.phase()->C->get_alias_index(m2->adr_type()); } -LoadNode::ControlDependency SuperWord::control_dependency(Node_List* p) { +LoadNode::ControlDependency VTransformLoadVectorNode::control_dependency() const { LoadNode::ControlDependency dep = LoadNode::DependsOnlyOnTest; - for (uint i = 0; i < p->size(); i++) { - Node* n = p->at(i); + for (int i = 0; i < nodes().length(); i++) { + Node* n = nodes().at(i); assert(n->is_Load(), "only meaningful for loads"); if (!n->depends_only_on_test()) { if (n->as_Load()->has_unknown_control_dependency() && @@ -3202,8 +2618,8 @@ LoadNode::ControlDependency SuperWord::control_dependency(Node_List* p) { } // Find the memop pack with the maximum vector width, unless they were already -// determined by SuperWord::filter_packs_for_alignment(). -void SuperWord::determine_mem_ref_and_aw_for_main_loop_alignment() { +// determined (e.g. by SuperWord::filter_packs_for_alignment()). +void VTransform::determine_mem_ref_and_aw_for_main_loop_alignment() { if (_mem_ref_for_main_loop_alignment != nullptr) { assert(VLoop::vectors_should_be_aligned(), "mem_ref only set if filtered for alignment"); return; @@ -3211,15 +2627,18 @@ void SuperWord::determine_mem_ref_and_aw_for_main_loop_alignment() { MemNode const* mem_ref = nullptr; int max_aw = 0; - for (int i = 0; i < _packset.length(); i++) { - Node_List* pack = _packset.at(i); - MemNode* first = pack->at(0)->isa_Mem(); - if (first == nullptr) { continue; } - int vw = first->memory_size() * pack->size(); + const GrowableArray& vtnodes = _graph.vtnodes(); + for (int i = 0; i < vtnodes.length(); i++) { + VTransformVectorNode* vtn = vtnodes.at(i)->isa_Vector(); + if (vtn == nullptr) { continue; } + MemNode* p0 = vtn->nodes().at(0)->isa_Mem(); + if (p0 == nullptr) { continue; } + + int vw = p0->memory_size() * vtn->nodes().length(); if (vw > max_aw) { max_aw = vw; - mem_ref = first; + mem_ref = p0; } } assert(mem_ref != nullptr && max_aw > 0, "found mem_ref and aw"); @@ -3229,7 +2648,7 @@ void SuperWord::determine_mem_ref_and_aw_for_main_loop_alignment() { #define TRACE_ALIGN_VECTOR_NODE(node) { \ DEBUG_ONLY( \ - if (is_trace_align_vector()) { \ + if (_trace._align_vector) { \ tty->print(" " #node ": "); \ node->dump(); \ } \ @@ -3240,7 +2659,7 @@ void SuperWord::determine_mem_ref_and_aw_for_main_loop_alignment() { // the address of "_mem_ref_for_main_loop_alignment" to "_aw_for_main_loop_alignment", which is a // sufficiently large alignment width. We adjust the pre-loop iteration count by adjusting the // pre-loop limit. -void SuperWord::adjust_pre_loop_limit_to_align_main_loop_vectors() { +void VTransform::adjust_pre_loop_limit_to_align_main_loop_vectors() { determine_mem_ref_and_aw_for_main_loop_alignment(); const MemNode* align_to_ref = _mem_ref_for_main_loop_alignment; const int aw = _aw_for_main_loop_alignment; @@ -3397,8 +2816,8 @@ void SuperWord::adjust_pre_loop_limit_to_align_main_loop_vectors() { Node* invar = align_to_ref_p.invar(); #ifdef ASSERT - if (is_trace_align_vector()) { - tty->print_cr("\nadjust_pre_loop_limit_to_align_main_loop_vectors:"); + if (_trace._align_vector) { + tty->print_cr("\nVTransform::adjust_pre_loop_limit_to_align_main_loop_vectors:"); tty->print(" align_to_ref:"); align_to_ref->dump(); tty->print_cr(" aw: %d", aw); @@ -3424,7 +2843,7 @@ void SuperWord::adjust_pre_loop_limit_to_align_main_loop_vectors() { scale == 0 || !is_power_of_2(abs(scale)) || abs(scale) >= aw) { #ifdef ASSERT - if (is_trace_align_vector()) { + if (_trace._align_vector) { tty->print_cr(" Alignment cannot be affected by changing pre-loop limit because"); tty->print_cr(" stride or scale are not power of 2, or abs(scale) >= aw."); } @@ -3440,7 +2859,7 @@ void SuperWord::adjust_pre_loop_limit_to_align_main_loop_vectors() { const int AW = aw / abs(scale); #ifdef ASSERT - if (is_trace_align_vector()) { + if (_trace._align_vector) { tty->print_cr(" AW = aw(%d) / abs(scale(%d)) = %d", aw, scale, AW); } #endif @@ -3595,10 +3014,10 @@ void PackSet::print_pack(Node_List* pack) { #ifndef PRODUCT void VLoopBody::print() const { - tty->print_cr("\nBlock"); + tty->print_cr("\nVLoopBody::print"); for (int i = 0; i < body().length(); i++) { Node* n = body().at(i); - tty->print("%d ", i); + tty->print("%4d ", i); if (n != nullptr) { n->dump(); } @@ -3615,3 +3034,4 @@ bool SuperWord::same_origin_idx(Node* a, Node* b) const { bool SuperWord::same_generation(Node* a, Node* b) const { return a != nullptr && b != nullptr && _clone_map.same_gen(a->_idx, b->_idx); } + diff --git a/src/hotspot/share/opto/superword.hpp b/src/hotspot/share/opto/superword.hpp index fb91d014fae..65f87082525 100644 --- a/src/hotspot/share/opto/superword.hpp +++ b/src/hotspot/share/opto/superword.hpp @@ -25,6 +25,7 @@ #define SHARE_OPTO_SUPERWORD_HPP #include "opto/vectorization.hpp" +#include "opto/vtransform.hpp" #include "utilities/growableArray.hpp" // @@ -367,6 +368,10 @@ class PackSet : public StackObj { Node* same_inputs_at_index_or_null(const Node_List* pack, const int index) const; VTransformBoolTest get_bool_test(const Node_List* bool_pack) const; + Node_List* pack_input_at_index_or_null(const Node_List* pack, const int index) const { + return strided_pack_input_at_index_or_null(pack, index, 1, 0); + } + private: SplitStatus split_pack(const char* split_name, Node_List* pack, SplitTask task); public: @@ -599,13 +604,6 @@ class SuperWord : public ResourceObj { DEBUG_ONLY(void verify_packs() const;) - bool schedule_and_apply(); - bool apply(Node_List& memops_schedule); - void apply_memops_reordering_with_schedule(Node_List& memops_schedule); - bool apply_vectorization(); - // Create a vector operand for the nodes in pack p for operand: in(opd_idx) - Node* vector_opd(Node_List* p, int opd_idx); - // Can code be generated for the pack, restricted to size nodes? bool implemented(const Node_List* pack, const uint size) const; // Find the maximal implemented size smaller or equal to the packs size @@ -630,11 +628,7 @@ class SuperWord : public ResourceObj { bool is_velt_basic_type_compatible_use_def(Node* use, Node* def) const; - static LoadNode::ControlDependency control_dependency(Node_List* p); - - // Ensure that the main loop vectors are aligned by adjusting the pre loop limit. - void determine_mem_ref_and_aw_for_main_loop_alignment(); - void adjust_pre_loop_limit_to_align_main_loop_vectors(); + bool schedule_and_apply() const; }; #endif // SHARE_OPTO_SUPERWORD_HPP diff --git a/src/hotspot/share/opto/superwordVTransformBuilder.cpp b/src/hotspot/share/opto/superwordVTransformBuilder.cpp new file mode 100644 index 00000000000..b0a0c97cb16 --- /dev/null +++ b/src/hotspot/share/opto/superwordVTransformBuilder.cpp @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "opto/superwordVTransformBuilder.hpp" +#include "opto/vectornode.hpp" + +void SuperWordVTransformBuilder::build() { + assert(!_packset.is_empty(), "must have non-empty packset"); + assert(!_vtransform.has_graph(), "start with empty vtransform"); + + // Create vtnodes for all nodes in the loop. + build_vector_vtnodes_for_packed_nodes(); + build_scalar_vtnodes_for_non_packed_nodes(); + + // Connect all vtnodes with their inputs. Possibly create vtnodes for input + // nodes that are outside the loop. + VectorSet vtn_dependencies; // Shared, but cleared for every vtnode. + build_inputs_for_vector_vtnodes(vtn_dependencies); + build_inputs_for_scalar_vtnodes(vtn_dependencies); +} + +void SuperWordVTransformBuilder::build_vector_vtnodes_for_packed_nodes() { + for (int i = 0; i < _packset.length(); i++) { + Node_List* pack = _packset.at(i); + VTransformVectorNode* vtn = make_vector_vtnode_for_pack(pack); + for (uint k = 0; k < pack->size(); k++) { + map_node_to_vtnode(pack->at(k), vtn); + } + } +} + +void SuperWordVTransformBuilder::build_scalar_vtnodes_for_non_packed_nodes() { + for (int i = 0; i < _vloop_analyzer.body().body().length(); i++) { + Node* n = _vloop_analyzer.body().body().at(i); + if (_packset.get_pack(n) != nullptr) { continue; } + VTransformScalarNode* vtn = new (_vtransform.arena()) VTransformScalarNode(_vtransform, n); + map_node_to_vtnode(n, vtn); + } +} + +void SuperWordVTransformBuilder::build_inputs_for_vector_vtnodes(VectorSet& vtn_dependencies) { + for (int i = 0; i < _packset.length(); i++) { + Node_List* pack = _packset.at(i); + Node* p0 = pack->at(0); + + VTransformVectorNode* vtn = get_vtnode(p0)->isa_Vector(); + assert(vtn != nullptr, "all packs must have vector vtnodes"); + vtn_dependencies.clear(); // Add every dependency only once per vtn. + + if (p0->is_Load()) { + set_req_with_scalar(p0, vtn, vtn_dependencies, MemNode::Address); + } else if (p0->is_Store()) { + set_req_with_scalar(p0, vtn, vtn_dependencies, MemNode::Address); + set_req_with_vector(pack, vtn, vtn_dependencies, MemNode::ValueIn); + } else if (vtn->isa_ReductionVector() != nullptr) { + set_req_with_scalar(p0, vtn, vtn_dependencies, 1); // scalar init + set_req_with_vector(pack, vtn, vtn_dependencies, 2); // vector + } else { + assert(vtn->isa_ElementWiseVector() != nullptr, "all other vtnodes are handled above"); + if (VectorNode::is_scalar_rotate(p0) && + p0->in(2)->is_Con() && + Matcher::supports_vector_constant_rotates(p0->in(2)->get_int())) { + set_req_with_vector(pack, vtn, vtn_dependencies, 1); + set_req_with_scalar(p0, vtn, vtn_dependencies, 2); // constant rotation + } else if (VectorNode::is_roundopD(p0)) { + set_req_with_vector(pack, vtn, vtn_dependencies, 1); + set_req_with_scalar(p0, vtn, vtn_dependencies, 2); // constant rounding mode + } else if (p0->is_CMove()) { + // Cmp + Bool + CMove -> VectorMaskCmp + VectorBlend. + set_all_req_with_vectors(pack, vtn, vtn_dependencies); + VTransformBoolVectorNode* vtn_mask_cmp = vtn->in(1)->isa_BoolVector(); + if (vtn_mask_cmp->test()._is_negated) { + vtn->swap_req(2, 3); // swap if test was negated. + } + } else { + set_all_req_with_vectors(pack, vtn, vtn_dependencies); + } + } + + for (uint k = 0; k < pack->size(); k++) { + add_dependencies_of_node_to_vtnode(pack->at(k), vtn, vtn_dependencies); + } + } +} + +void SuperWordVTransformBuilder::build_inputs_for_scalar_vtnodes(VectorSet& vtn_dependencies) { + for (int i = 0; i < _vloop_analyzer.body().body().length(); i++) { + Node* n = _vloop_analyzer.body().body().at(i); + VTransformScalarNode* vtn = get_vtnode(n)->isa_Scalar(); + if (vtn == nullptr) { continue; } + vtn_dependencies.clear(); // Add every dependency only once per vtn. + + if (n->is_Load()) { + set_req_with_scalar(n, vtn, vtn_dependencies, MemNode::Address); + } else if (n->is_Store()) { + set_req_with_scalar(n, vtn, vtn_dependencies, MemNode::Address); + set_req_with_scalar(n, vtn, vtn_dependencies, MemNode::ValueIn); + } else if (n->is_CountedLoop()) { + continue; // Is "root", has no dependency. + } else if (n->is_Phi()) { + // CountedLoop Phi's: ignore backedge (and entry value). + assert(n->in(0) == _vloop.cl(), "only Phi's from the CountedLoop allowed"); + set_req_with_scalar(n, vtn, vtn_dependencies, 0); + continue; + } else { + set_all_req_with_scalars(n, vtn, vtn_dependencies); + } + + add_dependencies_of_node_to_vtnode(n, vtn, vtn_dependencies); + } +} + +// Create a vtnode for each pack. No in/out edges set yet. +VTransformVectorNode* SuperWordVTransformBuilder::make_vector_vtnode_for_pack(const Node_List* pack) const { + uint pack_size = pack->size(); + Node* p0 = pack->at(0); + int opc = p0->Opcode(); + VTransformVectorNode* vtn = nullptr; + + if (p0->is_Load()) { + vtn = new (_vtransform.arena()) VTransformLoadVectorNode(_vtransform, pack_size); + } else if (p0->is_Store()) { + vtn = new (_vtransform.arena()) VTransformStoreVectorNode(_vtransform, pack_size); + } else if (p0->is_Bool()) { + VTransformBoolTest kind = _packset.get_bool_test(pack); + vtn = new (_vtransform.arena()) VTransformBoolVectorNode(_vtransform, pack_size, kind); + } else if (_vloop_analyzer.reductions().is_marked_reduction(p0)) { + vtn = new (_vtransform.arena()) VTransformReductionVectorNode(_vtransform, pack_size); + } else if (VectorNode::is_muladds2i(p0)) { + // A special kind of binary element-wise vector op: the inputs are "ints" a and b, + // but reinterpreted as two "shorts" [a0, a1] and [b0, b1]: + // v = MulAddS2I(a, b) = a0 * b0 + a1 + b1 + assert(p0->req() == 5, "MulAddS2I should have 4 operands"); + vtn = new (_vtransform.arena()) VTransformElementWiseVectorNode(_vtransform, 3, pack_size); + } else { + assert(p0->req() == 3 || + p0->is_CMove() || + VectorNode::is_scalar_op_that_returns_int_but_vector_op_returns_long(opc) || + VectorNode::is_convert_opcode(opc) || + VectorNode::is_scalar_unary_op_with_equal_input_and_output_types(opc) || + opc == Op_FmaD || + opc == Op_FmaF || + opc == Op_SignumF || + opc == Op_SignumD, + "pack type must be in this list"); + vtn = new (_vtransform.arena()) VTransformElementWiseVectorNode(_vtransform, p0->req(), pack_size); + } + vtn->set_nodes(pack); + return vtn; +} + +void SuperWordVTransformBuilder::set_req_with_scalar(Node* n, VTransformNode* vtn, VectorSet& vtn_dependencies, const int index) { + VTransformNode* req = get_vtnode_or_wrap_as_input_scalar(n->in(index)); + vtn->set_req(index, req); + vtn_dependencies.set(req->_idx); +} + +// Either get the existing vtnode vector input (when input is a pack), or else make a +// new vector vtnode for the input (e.g. for Replicate or PopulateIndex). +VTransformNode* SuperWordVTransformBuilder::get_or_make_vtnode_vector_input_at_index(const Node_List* pack, const int index) { + Node* p0 = pack->at(0); + + Node_List* pack_in = _packset.pack_input_at_index_or_null(pack, index); + if (pack_in != nullptr) { + // Input is a matching pack -> vtnode already exists. + assert(index != 2 || !VectorNode::is_shift(p0), "shift's count cannot be vector"); + return get_vtnode(pack_in->at(0)); + } + + if (VectorNode::is_muladds2i(p0)) { + assert(_packset.is_muladds2i_pack_with_pack_inputs(pack), "inputs must all be packs"); + // All inputs are strided (stride = 2), either with offset 0 or 1. + Node_List* pack_in0 = _packset.strided_pack_input_at_index_or_null(pack, index, 2, 0); + if (pack_in0 != nullptr) { + return get_vtnode(pack_in0->at(0)); + } + Node_List* pack_in1 = _packset.strided_pack_input_at_index_or_null(pack, index, 2, 1); + if (pack_in1 != nullptr) { + return get_vtnode(pack_in1->at(0)); + } + } + + Node* same_input = _packset.same_inputs_at_index_or_null(pack, index); + if (same_input == nullptr && p0->in(index) == _vloop.iv()) { + // PopulateIndex: [iv+0, iv+1, iv+2, ...] + VTransformNode* iv_vtn = get_vtnode_or_wrap_as_input_scalar(_vloop.iv()); + BasicType p0_bt = _vloop_analyzer.types().velt_basic_type(p0); + // If we have subword type, take that type directly. If p0 is some ConvI2L/F/D, + // then the p0_bt can also be L/F/D but we need to produce ints for the input of + // the ConvI2L/F/D. + BasicType element_bt = is_subword_type(p0_bt) ? p0_bt : T_INT; + VTransformNode* populate_index = new (_vtransform.arena()) VTransformPopulateIndexNode(_vtransform, pack->size(), element_bt); + populate_index->set_req(1, iv_vtn); + return populate_index; + } + + if (same_input != nullptr) { + VTransformNode* same_input_vtn = get_vtnode_or_wrap_as_input_scalar(same_input); + if (index == 2 && VectorNode::is_shift(p0)) { + // Scalar shift count for vector shift operation: vec2 = shiftV(vec1, scalar_count) + // Scalar shift operations masks the shift count, but the vector shift does not, so + // create a special ShiftCount node. + BasicType element_bt = _vloop_analyzer.types().velt_basic_type(p0); + juint mask = (p0->bottom_type() == TypeInt::INT) ? (BitsPerInt - 1) : (BitsPerLong - 1); + VTransformNode* shift_count = new (_vtransform.arena()) VTransformShiftCountNode(_vtransform, pack->size(), element_bt, mask, p0->Opcode()); + shift_count->set_req(1, same_input_vtn); + return shift_count; + } else { + // Replicate the scalar same_input to every vector element. + const Type* element_type = _vloop_analyzer.types().velt_type(p0); + if (index == 2 && VectorNode::is_scalar_rotate(p0) && element_type->isa_long()) { + // Scalar rotate has int rotation value, but the scalar rotate expects longs. + assert(same_input->bottom_type()->isa_int(), "scalar rotate expects int rotation"); + VTransformNode* conv = new (_vtransform.arena()) VTransformConvI2LNode(_vtransform); + conv->set_req(1, same_input_vtn); + same_input_vtn = conv; + } + VTransformNode* replicate = new (_vtransform.arena()) VTransformReplicateNode(_vtransform, pack->size(), element_type); + replicate->set_req(1, same_input_vtn); + return replicate; + } + } + + // The input is neither a pack not a same_input node. SuperWord::profitable does not allow + // any other case. In the future, we could insert a PackNode. +#ifdef ASSERT + tty->print_cr("\nSuperWordVTransformBuilder::get_or_make_vtnode_vector_input_at_index: index=%d", index); + pack->dump(); + assert(false, "Pack input was neither a pack nor a same_input node"); +#endif + ShouldNotReachHere(); +} + +VTransformNode* SuperWordVTransformBuilder::get_vtnode_or_wrap_as_input_scalar(Node* n) { + VTransformNode* vtn = get_vtnode_or_null(n); + if (vtn != nullptr) { return vtn; } + + assert(!_vloop.in_bb(n), "only nodes outside the loop can be input nodes to the loop"); + vtn = new (_vtransform.arena()) VTransformInputScalarNode(_vtransform, n); + map_node_to_vtnode(n, vtn); + return vtn; +} + +void SuperWordVTransformBuilder::set_req_with_vector(const Node_List* pack, VTransformNode* vtn, VectorSet& vtn_dependencies, int j) { + VTransformNode* req = get_or_make_vtnode_vector_input_at_index(pack, j); + vtn->set_req(j, req); + vtn_dependencies.set(req->_idx); +} + +void SuperWordVTransformBuilder::set_all_req_with_scalars(Node* n, VTransformNode* vtn, VectorSet& vtn_dependencies) { + assert(vtn->req() == n->req(), "scalars must have same number of reqs"); + for (uint j = 0; j < n->req(); j++) { + Node* def = n->in(j); + if (def == nullptr) { continue; } + set_req_with_scalar(n, vtn, vtn_dependencies, j); + } +} + +void SuperWordVTransformBuilder::set_all_req_with_vectors(const Node_List* pack, VTransformNode* vtn, VectorSet& vtn_dependencies) { + Node* p0 = pack->at(0); + assert(vtn->req() <= p0->req(), "must have at at most as many reqs"); + // Vectors have no ctrl, so ignore it. + for (uint j = 1; j < vtn->req(); j++) { + Node* def = p0->in(j); + if (def == nullptr) { continue; } + set_req_with_vector(pack, vtn, vtn_dependencies, j); + } +} + +void SuperWordVTransformBuilder::add_dependencies_of_node_to_vtnode(Node*n, VTransformNode* vtn, VectorSet& vtn_dependencies) { + for (VLoopDependencyGraph::PredsIterator preds(_vloop_analyzer.dependency_graph(), n); !preds.done(); preds.next()) { + Node* pred = preds.current(); + if (!_vloop.in_bb(pred)) { continue; } + + // Only add memory dependencies to memory nodes. All others are taken care of with the req. + if (n->is_Mem() && !pred->is_Mem()) { continue; } + + VTransformNode* dependency = get_vtnode(pred); + + // Reduction self-cycle? + if (vtn == dependency && _vloop_analyzer.reductions().is_marked_reduction(n)) { continue; } + + if (vtn_dependencies.test_set(dependency->_idx)) { continue; } + vtn->add_dependency(dependency); // Add every dependency only once per vtn. + } +} + diff --git a/src/hotspot/share/opto/superwordVTransformBuilder.hpp b/src/hotspot/share/opto/superwordVTransformBuilder.hpp new file mode 100644 index 00000000000..847f870bef6 --- /dev/null +++ b/src/hotspot/share/opto/superwordVTransformBuilder.hpp @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "opto/vtransform.hpp" +#include "opto/superword.hpp" + +#ifndef SHARE_OPTO_SUPERWORD_VTRANSFORM_BUILDER_HPP +#define SHARE_OPTO_SUPERWORD_VTRANSFORM_BUILDER_HPP + +// Facility class that builds a VTransform from a SuperWord PackSet. +class SuperWordVTransformBuilder : public StackObj { +private: + const VLoopAnalyzer& _vloop_analyzer; + const VLoop& _vloop; + const PackSet& _packset; + VTransform& _vtransform; + + ResourceHashtable _idx_to_vtnode; + +public: + SuperWordVTransformBuilder(const PackSet& packset, + VTransform& vtransform) : + _vloop_analyzer(vtransform.vloop_analyzer()), + _vloop(_vloop_analyzer.vloop()), + _packset(packset), + _vtransform(vtransform) + { + assert(!_vtransform.has_graph(), "constructor is passed an empty vtransform"); + build(); + assert(_vtransform.has_graph(), "vtransform must contain some vtnodes now"); + } + +private: + void build(); + void build_vector_vtnodes_for_packed_nodes(); + void build_scalar_vtnodes_for_non_packed_nodes(); + void build_inputs_for_vector_vtnodes(VectorSet& vtn_dependencies); + void build_inputs_for_scalar_vtnodes(VectorSet& vtn_dependencies); + + // Helper methods for building VTransform. + VTransformNode* get_vtnode_or_null(Node* n) const { + VTransformNode** ptr = _idx_to_vtnode.get(n->_idx); + return (ptr == nullptr) ? nullptr : *ptr; + } + + VTransformNode* get_vtnode(Node* n) const { + VTransformNode* vtn = get_vtnode_or_null(n); + assert(vtn != nullptr, "expect non-null vtnode"); + return vtn; + } + + void map_node_to_vtnode(Node* n, VTransformNode* vtn) { + assert(vtn != nullptr, "only set non-null vtnodes"); + _idx_to_vtnode.put_when_absent(n->_idx, vtn); + } + + VTransformVectorNode* make_vector_vtnode_for_pack(const Node_List* pack) const; + VTransformNode* get_or_make_vtnode_vector_input_at_index(const Node_List* pack, const int index); + VTransformNode* get_vtnode_or_wrap_as_input_scalar(Node* n); + void set_req_with_scalar(Node* n, VTransformNode* vtn, VectorSet& vtn_dependencies, const int index); + void set_req_with_vector(const Node_List* pack, VTransformNode* vtn, VectorSet& vtn_dependencies, const int index); + void set_all_req_with_scalars(Node* n, VTransformNode* vtn, VectorSet& vtn_dependencies); + void set_all_req_with_vectors(const Node_List* pack, VTransformNode* vtn, VectorSet& vtn_dependencies); + void add_dependencies_of_node_to_vtnode(Node* n, VTransformNode* vtn, VectorSet& vtn_dependencies); +}; + +#endif // SHARE_OPTO_SUPERWORD_VTRANSFORM_BUILDER_HPP diff --git a/src/hotspot/share/opto/traceAutoVectorizationTag.hpp b/src/hotspot/share/opto/traceAutoVectorizationTag.hpp index 3aae04c9453..038e04fe0c5 100644 --- a/src/hotspot/share/opto/traceAutoVectorizationTag.hpp +++ b/src/hotspot/share/opto/traceAutoVectorizationTag.hpp @@ -43,6 +43,7 @@ flags(SW_INFO, "Trace SuperWord info (equivalent to TraceSuperWord)") \ flags(SW_VERBOSE, "Trace SuperWord verbose (all SW tags enabled)") \ flags(ALIGN_VECTOR, "Trace AlignVector") \ + flags(VTRANSFORM, "Trace VTransform Graph") \ flags(ALL, "Trace everything (very verbose)") #define table_entry(name, description) name, diff --git a/src/hotspot/share/opto/vectorization.cpp b/src/hotspot/share/opto/vectorization.cpp index 01b235e8b27..8d2d3868fe6 100644 --- a/src/hotspot/share/opto/vectorization.cpp +++ b/src/hotspot/share/opto/vectorization.cpp @@ -26,7 +26,6 @@ #include "opto/addnode.hpp" #include "opto/connode.hpp" #include "opto/convertnode.hpp" -#include "opto/matcher.hpp" #include "opto/mulnode.hpp" #include "opto/rootnode.hpp" #include "opto/vectorization.hpp" diff --git a/src/hotspot/share/opto/vectorization.hpp b/src/hotspot/share/opto/vectorization.hpp index c9f54594910..3984407c565 100644 --- a/src/hotspot/share/opto/vectorization.hpp +++ b/src/hotspot/share/opto/vectorization.hpp @@ -25,7 +25,7 @@ #ifndef SHARE_OPTO_VECTORIZATION_HPP #define SHARE_OPTO_VECTORIZATION_HPP -#include "opto/node.hpp" +#include "opto/matcher.hpp" #include "opto/loopnode.hpp" #include "opto/traceAutoVectorizationTag.hpp" #include "utilities/pair.hpp" @@ -763,9 +763,9 @@ class VPointer : public ArenaObj { } } - bool overlap_possible_with_any_in(const Node_List* p) const { - for (uint k = 0; k < p->size(); k++) { - MemNode* mem = p->at(k)->as_Mem(); + bool overlap_possible_with_any_in(const GrowableArray& nodes) const { + for (int i = 0; i < nodes.length(); i++) { + MemNode* mem = nodes.at(i)->as_Mem(); VPointer p_mem(mem, _vloop); // Only if we know that we have Less or Greater can we // be sure that there can never be an overlap between @@ -1323,12 +1323,4 @@ class AlignmentSolver { #endif }; -struct VTransformBoolTest { - const BoolTest::mask _mask; - const bool _is_negated; - - VTransformBoolTest(const BoolTest::mask mask, bool is_negated) : - _mask(mask), _is_negated(is_negated) {} -}; - #endif // SHARE_OPTO_VECTORIZATION_HPP diff --git a/src/hotspot/share/opto/vtransform.cpp b/src/hotspot/share/opto/vtransform.cpp new file mode 100644 index 00000000000..e40157caa36 --- /dev/null +++ b/src/hotspot/share/opto/vtransform.cpp @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "opto/vtransform.hpp" +#include "opto/vectornode.hpp" +#include "opto/convertnode.hpp" + +void VTransformGraph::add_vtnode(VTransformNode* vtnode) { + assert(vtnode->_idx == _vtnodes.length(), "position must match idx"); + _vtnodes.push(vtnode); +} + +// Compute a linearization of the graph. We do this with a reverse-post-order of a DFS. +// This only works if the graph is a directed acyclic graph (DAG). The C2 graph, and +// the VLoopDependencyGraph are both DAGs, but after introduction of vectors/packs, the +// graph has additional constraints which can introduce cycles. Example: +// +// +--------+ +// A -> X | v +// Pack [A,B] and [X,Y] [A,B] [X,Y] +// Y -> B ^ | +// +--------+ +// +// We return "true" IFF we find no cycle, i.e. if the linearization succeeds. +bool VTransformGraph::schedule() { + assert(!is_scheduled(), "not yet scheduled"); + +#ifndef PRODUCT + if (_trace._verbose) { + print_vtnodes(); + } +#endif + + ResourceMark rm; + GrowableArray stack; + VectorSet pre_visited; + VectorSet post_visited; + + collect_nodes_without_req_or_dependency(stack); + + // We create a reverse-post-visit order. This gives us a linearization, if there are + // no cycles. Then, we simply reverse the order, and we have a schedule. + int rpo_idx = _vtnodes.length() - 1; + while (!stack.is_empty()) { + VTransformNode* vtn = stack.top(); + if (!pre_visited.test_set(vtn->_idx)) { + // Forward arc in graph (pre-visit). + } else if (!post_visited.test(vtn->_idx)) { + // Forward arc in graph. Check if all uses were already visited: + // Yes -> post-visit. + // No -> we are mid-visit. + bool all_uses_already_visited = true; + + for (int i = 0; i < vtn->outs(); i++) { + VTransformNode* use = vtn->out(i); + if (post_visited.test(use->_idx)) { continue; } + if (pre_visited.test(use->_idx)) { + // Cycle detected! + // The nodes that are pre_visited but not yet post_visited form a path from + // the "root" to the current vtn. Now, we are looking at an edge (vtn, use), + // and discover that use is also pre_visited but not post_visited. Thus, use + // lies on that path from "root" to vtn, and the edge (vtn, use) closes a + // cycle. + NOT_PRODUCT(if (_trace._rejections) { trace_schedule_cycle(stack, pre_visited, post_visited); } ) + return false; + } + stack.push(use); + all_uses_already_visited = false; + } + + if (all_uses_already_visited) { + stack.pop(); + post_visited.set(vtn->_idx); // post-visit + _schedule.at_put_grow(rpo_idx--, vtn); // assign rpo_idx + } + } else { + stack.pop(); // Already post-visited. Ignore secondary edge. + } + } + +#ifndef PRODUCT + if (_trace._verbose) { + print_schedule(); + } +#endif + + assert(rpo_idx == -1, "used up all rpo_idx, rpo_idx=%d", rpo_idx); + return true; +} + +// Push all "root" nodes, i.e. those that have no inputs (req or dependency): +void VTransformGraph::collect_nodes_without_req_or_dependency(GrowableArray& stack) const { + for (int i = 0; i < _vtnodes.length(); i++) { + VTransformNode* vtn = _vtnodes.at(i); + if (!vtn->has_req_or_dependency()) { + stack.push(vtn); + } + } +} + +#ifndef PRODUCT +void VTransformGraph::trace_schedule_cycle(const GrowableArray& stack, + const VectorSet& pre_visited, + const VectorSet& post_visited) const { + tty->print_cr("\nVTransform::schedule found a cycle on path (P), vectorization attempt fails."); + for (int j = 0; j < stack.length(); j++) { + VTransformNode* n = stack.at(j); + bool on_path = pre_visited.test(n->_idx) && !post_visited.test(n->_idx); + tty->print(" %s ", on_path ? "P" : "_"); + n->print(); + } +} + +void VTransformApplyResult::trace(VTransformNode* vtnode) const { + tty->print(" apply: "); + vtnode->print(); + tty->print(" -> "); + if (_node == nullptr) { + tty->print_cr("nullptr"); + } else { + _node->dump(); + } +} +#endif + +Node* VTransformNode::find_transformed_input(int i, const GrowableArray& vnode_idx_to_transformed_node) const { + Node* n = vnode_idx_to_transformed_node.at(in(i)->_idx); + assert(n != nullptr, "must find input IR node"); + return n; +} + +VTransformApplyResult VTransformScalarNode::apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const { + // This was just wrapped. Now we simply unwap without touching the inputs. + return VTransformApplyResult::make_scalar(_node); +} + +VTransformApplyResult VTransformReplicateNode::apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const { + Node* val = find_transformed_input(1, vnode_idx_to_transformed_node); + VectorNode* vn = VectorNode::scalar2vector(val, _vlen, _element_type); + register_new_node_from_vectorization(vloop_analyzer, vn, val); + return VTransformApplyResult::make_vector(vn, _vlen, vn->length_in_bytes()); +} + +VTransformApplyResult VTransformConvI2LNode::apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const { + Node* val = find_transformed_input(1, vnode_idx_to_transformed_node); + Node* n = new ConvI2LNode(val); + register_new_node_from_vectorization(vloop_analyzer, n, val); + return VTransformApplyResult::make_scalar(n); +} + +VTransformApplyResult VTransformShiftCountNode::apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const { + PhaseIdealLoop* phase = vloop_analyzer.vloop().phase(); + Node* shift_count_in = find_transformed_input(1, vnode_idx_to_transformed_node); + assert(shift_count_in->bottom_type()->isa_int(), "int type only for shift count"); + // The shift_count_in would be automatically truncated to the lowest _mask + // bits in a scalar shift operation. But vector shift does not truncate, so + // we must apply the mask now. + Node* shift_count_masked = new AndINode(shift_count_in, phase->igvn().intcon(_mask)); + register_new_node_from_vectorization(vloop_analyzer, shift_count_masked, shift_count_in); + // Now that masked value is "boadcast" (some platforms only set the lowest element). + VectorNode* vn = VectorNode::shift_count(_shift_opcode, shift_count_masked, _vlen, _element_bt); + register_new_node_from_vectorization(vloop_analyzer, vn, shift_count_in); + return VTransformApplyResult::make_vector(vn, _vlen, vn->length_in_bytes()); +} + + +VTransformApplyResult VTransformPopulateIndexNode::apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const { + PhaseIdealLoop* phase = vloop_analyzer.vloop().phase(); + Node* val = find_transformed_input(1, vnode_idx_to_transformed_node); + assert(val->is_Phi(), "expected to be iv"); + assert(VectorNode::is_populate_index_supported(_element_bt), "should support"); + const TypeVect* vt = TypeVect::make(_element_bt, _vlen); + VectorNode* vn = new PopulateIndexNode(val, phase->igvn().intcon(1), vt); + register_new_node_from_vectorization(vloop_analyzer, vn, val); + return VTransformApplyResult::make_vector(vn, _vlen, vn->length_in_bytes()); +} + +VTransformApplyResult VTransformElementWiseVectorNode::apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const { + Node* first = nodes().at(0); + uint vlen = nodes().length(); + int opc = first->Opcode(); + BasicType bt = vloop_analyzer.types().velt_basic_type(first); + + if (first->is_Cmp()) { + // Cmp + Bool -> VectorMaskCmp + // Handled by Bool / VTransformBoolVectorNode, so we do not generate any nodes here. + return VTransformApplyResult::make_empty(); + } + + assert(2 <= req() && req() <= 4, "Must have 1-3 inputs"); + VectorNode* vn = nullptr; + Node* in1 = find_transformed_input(1, vnode_idx_to_transformed_node); + Node* in2 = (req() >= 3) ? find_transformed_input(2, vnode_idx_to_transformed_node) : nullptr; + Node* in3 = (req() >= 4) ? find_transformed_input(3, vnode_idx_to_transformed_node) : nullptr; + + if (first->is_CMove()) { + assert(req() == 4, "three inputs expected: mask, blend1, blend2"); + vn = new VectorBlendNode(/* blend1 */ in2, /* blend2 */ in3, /* mask */ in1); + } else if (VectorNode::is_convert_opcode(opc)) { + assert(first->req() == 2 && req() == 2, "only one input expected"); + int vopc = VectorCastNode::opcode(opc, in1->bottom_type()->is_vect()->element_basic_type()); + vn = VectorCastNode::make(vopc, in1, bt, vlen); + } else if (VectorNode::can_use_RShiftI_instead_of_URShiftI(first, bt)) { + opc = Op_RShiftI; + vn = VectorNode::make(opc, in1, in2, vlen, bt); + } else if (VectorNode::is_scalar_op_that_returns_int_but_vector_op_returns_long(opc)) { + // The scalar operation was a long -> int operation. + // However, the vector operation is long -> long. + VectorNode* long_vn = VectorNode::make(opc, in1, nullptr, vlen, T_LONG); + register_new_node_from_vectorization(vloop_analyzer, long_vn, first); + // Cast long -> int, to mimic the scalar long -> int operation. + vn = VectorCastNode::make(Op_VectorCastL2X, long_vn, T_INT, vlen); + } else if (req() == 3 || + VectorNode::is_scalar_unary_op_with_equal_input_and_output_types(opc)) { + assert(!VectorNode::is_roundopD(first) || in2->is_Con(), "rounding mode must be constant"); + vn = VectorNode::make(opc, in1, in2, vlen, bt); // unary and binary + } else { + assert(req() == 4, "three inputs expected"); + assert(opc == Op_FmaD || + opc == Op_FmaF || + opc == Op_SignumF || + opc == Op_SignumD, + "element wise operation must be from this list"); + vn = VectorNode::make(opc, in1, in2, in3, vlen, bt); // ternary + } + + register_new_node_from_vectorization_and_replace_scalar_nodes(vloop_analyzer, vn); + return VTransformApplyResult::make_vector(vn, vlen, vn->length_in_bytes()); +} + +VTransformApplyResult VTransformBoolVectorNode::apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const { + BoolNode* first = nodes().at(0)->as_Bool(); + uint vlen = nodes().length(); + BasicType bt = vloop_analyzer.types().velt_basic_type(first); + + // Cmp + Bool -> VectorMaskCmp + VTransformElementWiseVectorNode* vtn_cmp = in(1)->isa_ElementWiseVector(); + assert(vtn_cmp != nullptr && vtn_cmp->nodes().at(0)->is_Cmp(), + "bool vtn expects cmp vtn as input"); + + Node* cmp_in1 = vtn_cmp->find_transformed_input(1, vnode_idx_to_transformed_node); + Node* cmp_in2 = vtn_cmp->find_transformed_input(2, vnode_idx_to_transformed_node); + BoolTest::mask mask = test()._mask; + + PhaseIdealLoop* phase = vloop_analyzer.vloop().phase(); + ConINode* mask_node = phase->igvn().intcon((int)mask); + const TypeVect* vt = TypeVect::make(bt, vlen); + VectorNode* vn = new VectorMaskCmpNode(mask, cmp_in1, cmp_in2, mask_node, vt); + register_new_node_from_vectorization_and_replace_scalar_nodes(vloop_analyzer, vn); + return VTransformApplyResult::make_vector(vn, vlen, vn->vect_type()->length_in_bytes()); +} + +VTransformApplyResult VTransformReductionVectorNode::apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const { + Node* first = nodes().at(0); + uint vlen = nodes().length(); + int opc = first->Opcode(); + BasicType bt = first->bottom_type()->basic_type(); + + Node* init = find_transformed_input(1, vnode_idx_to_transformed_node); + Node* vec = find_transformed_input(2, vnode_idx_to_transformed_node); + + ReductionNode* vn = ReductionNode::make(opc, nullptr, init, vec, bt); + register_new_node_from_vectorization_and_replace_scalar_nodes(vloop_analyzer, vn); + return VTransformApplyResult::make_vector(vn, vlen, vn->vect_type()->length_in_bytes()); +} + +VTransformApplyResult VTransformLoadVectorNode::apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const { + LoadNode* first = nodes().at(0)->as_Load(); + uint vlen = nodes().length(); + Node* ctrl = first->in(MemNode::Control); + Node* mem = first->in(MemNode::Memory); + Node* adr = first->in(MemNode::Address); + int opc = first->Opcode(); + const TypePtr* adr_type = first->adr_type(); + BasicType bt = vloop_analyzer.types().velt_basic_type(first); + + // Set the memory dependency of the LoadVector as early as possible. + // Walk up the memory chain, and ignore any StoreVector that provably + // does not have any memory dependency. + while (mem->is_StoreVector()) { + VPointer p_store(mem->as_Mem(), vloop_analyzer.vloop()); + if (p_store.overlap_possible_with_any_in(nodes())) { + break; + } else { + mem = mem->in(MemNode::Memory); + } + } + + LoadVectorNode* vn = LoadVectorNode::make(opc, ctrl, mem, adr, adr_type, vlen, bt, + control_dependency()); + DEBUG_ONLY( if (VerifyAlignVector) { vn->set_must_verify_alignment(); } ) + register_new_node_from_vectorization_and_replace_scalar_nodes(vloop_analyzer, vn); + return VTransformApplyResult::make_vector(vn, vlen, vn->memory_size()); +} + +VTransformApplyResult VTransformStoreVectorNode::apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const { + StoreNode* first = nodes().at(0)->as_Store(); + uint vlen = nodes().length(); + Node* ctrl = first->in(MemNode::Control); + Node* mem = first->in(MemNode::Memory); + Node* adr = first->in(MemNode::Address); + int opc = first->Opcode(); + const TypePtr* adr_type = first->adr_type(); + + Node* value = find_transformed_input(MemNode::ValueIn, vnode_idx_to_transformed_node); + StoreVectorNode* vn = StoreVectorNode::make(opc, ctrl, mem, adr, adr_type, value, vlen); + DEBUG_ONLY( if (VerifyAlignVector) { vn->set_must_verify_alignment(); } ) + register_new_node_from_vectorization_and_replace_scalar_nodes(vloop_analyzer, vn); + return VTransformApplyResult::make_vector(vn, vlen, vn->memory_size()); +} + +void VTransformVectorNode::register_new_node_from_vectorization_and_replace_scalar_nodes(const VLoopAnalyzer& vloop_analyzer, Node* vn) const { + PhaseIdealLoop* phase = vloop_analyzer.vloop().phase(); + Node* first = nodes().at(0); + + register_new_node_from_vectorization(vloop_analyzer, vn, first); + + for (int i = 0; i < _nodes.length(); i++) { + Node* n = _nodes.at(i); + phase->igvn().replace_node(n, vn); + } +} + +void VTransformNode::register_new_node_from_vectorization(const VLoopAnalyzer& vloop_analyzer, Node* vn, Node* old_node) const { + PhaseIdealLoop* phase = vloop_analyzer.vloop().phase(); + phase->register_new_node_with_ctrl_of(vn, old_node); + phase->igvn()._worklist.push(vn); + VectorNode::trace_new_vector(vn, "AutoVectorization"); +} + +#ifndef PRODUCT +void VTransformGraph::print_vtnodes() const { + tty->print_cr("\nVTransformGraph::print_vtnodes:"); + for (int i = 0; i < _vtnodes.length(); i++) { + _vtnodes.at(i)->print(); + } +} + +void VTransformGraph::print_schedule() const { + tty->print_cr("\nVTransformGraph::print_schedule:"); + for (int i = 0; i < _schedule.length(); i++) { + tty->print(" %3d: ", i); + VTransformNode* vtn = _schedule.at(i); + if (vtn == nullptr) { + tty->print_cr("nullptr"); + } else { + vtn->print(); + } + } +} + +void VTransformGraph::print_memops_schedule() const { + tty->print_cr("\nVTransformGraph::print_memops_schedule:"); + int i = 0; + for_each_memop_in_schedule([&] (MemNode* mem) { + tty->print(" %3d: ", i++); + mem->dump(); + }); +} + +void VTransformNode::print() const { + tty->print("%3d %s (", _idx, name()); + for (uint i = 0; i < _req; i++) { + print_node_idx(_in.at(i)); + } + if ((uint)_in.length() > _req) { + tty->print(" |"); + for (int i = _req; i < _in.length(); i++) { + print_node_idx(_in.at(i)); + } + } + tty->print(") ["); + for (int i = 0; i < _out.length(); i++) { + print_node_idx(_out.at(i)); + } + tty->print("] "); + print_spec(); + tty->cr(); +} + +void VTransformNode::print_node_idx(const VTransformNode* vtn) { + if (vtn == nullptr) { + tty->print(" _"); + } else { + tty->print(" %d", vtn->_idx); + } +} + +void VTransformScalarNode::print_spec() const { + tty->print("node[%d %s]", _node->_idx, _node->Name()); +} + +void VTransformReplicateNode::print_spec() const { + tty->print("vlen=%d element_type=", _vlen); + _element_type->dump(); +} + +void VTransformShiftCountNode::print_spec() const { + tty->print("vlen=%d element_bt=%s mask=%d shift_opcode=%s", + _vlen, type2name(_element_bt), _mask, + NodeClassNames[_shift_opcode]); +} + +void VTransformPopulateIndexNode::print_spec() const { + tty->print("vlen=%d element_bt=%s", _vlen, type2name(_element_bt)); +} + +void VTransformVectorNode::print_spec() const { + tty->print("%d-pack[", _nodes.length()); + for (int i = 0; i < _nodes.length(); i++) { + Node* n = _nodes.at(i); + if (i > 0) { + tty->print(", "); + } + tty->print("%d %s", n->_idx, n->Name()); + } + tty->print("]"); +} +#endif diff --git a/src/hotspot/share/opto/vtransform.hpp b/src/hotspot/share/opto/vtransform.hpp new file mode 100644 index 00000000000..071674533a7 --- /dev/null +++ b/src/hotspot/share/opto/vtransform.hpp @@ -0,0 +1,515 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_OPTO_VTRANSFORM_HPP +#define SHARE_OPTO_VTRANSFORM_HPP + +#include "opto/node.hpp" +#include "opto/vectorization.hpp" + +// VTransform: +// - Models the transformation of the scalar loop to vectorized loop: +// It is a "C2 subgraph" -> "C2 subgraph" mapping. +// - The VTransform contains a graph (VTransformGraph), which consists of +// many vtnodes (VTransformNode). +// - Each vtnode models a part of the transformation, and is supposed +// to represent the output C2 nodes after the vectorization as closely +// as possible. +// +// This is the life-cycle of a VTransform: +// - Construction: +// - From SuperWord, with the SuperWordVTransformBuilder. +// +// - Future Plans: optimize, if-conversion, etc. +// +// - Schedule: +// - Compute linearization of the VTransformGraph, into an order that respects +// all edges in the graph (bailout if cycle detected). +// +// - Apply: +// - Changes to the C2 IR are only made once the "apply" method is called. +// - Each vtnode generates its corresponding scalar and vector C2 nodes, +// possibly replacing old scalar C2 nodes. +// +// Future Plans with VTransform: +// - Cost model: estimate if vectorization is profitable. +// - Optimizations: moving unordered reductions out of the loop, whih decreases cost. +// - Pack/Unpack/Shuffle: introduce additional nodes not present in the scalar loop. +// This is difficult to do with the SuperWord packset approach. +// - If-conversion: convert predicated nodes into CFG. + +typedef int VTransformNodeIDX; +class VTransformNode; +class VTransformScalarNode; +class VTransformInputScalarNode; +class VTransformVectorNode; +class VTransformElementWiseVectorNode; +class VTransformBoolVectorNode; +class VTransformReductionVectorNode; + +// Result from VTransformNode::apply +class VTransformApplyResult { +private: + Node* const _node; + const uint _vector_length; // number of elements + const uint _vector_width; // total width in bytes + + VTransformApplyResult(Node* n, uint vector_length, uint vector_width) : + _node(n), + _vector_length(vector_length), + _vector_width(vector_width) {} + +public: + static VTransformApplyResult make_scalar(Node* n) { + return VTransformApplyResult(n, 0, 0); + } + + static VTransformApplyResult make_vector(Node* n, uint vector_length, uint vector_width) { + assert(vector_length > 0 && vector_width > 0, "must have nonzero size"); + return VTransformApplyResult(n, vector_length, vector_width); + } + + static VTransformApplyResult make_empty() { + return VTransformApplyResult(nullptr, 0, 0); + } + + Node* node() const { return _node; } + uint vector_length() const { return _vector_length; } + uint vector_width() const { return _vector_width; } + NOT_PRODUCT( void trace(VTransformNode* vtnode) const; ) +}; + +#ifndef PRODUCT +// Convenience class for tracing flags. +class VTransformTrace { +public: + const bool _verbose; + const bool _rejections; + const bool _align_vector; + const bool _info; + + VTransformTrace(const VTrace& vtrace, + const bool is_trace_rejections, + const bool is_trace_align_vector, + const bool is_trace_info) : + _verbose (vtrace.is_trace(TraceAutoVectorizationTag::ALL)), + _rejections (_verbose | is_trace_vtransform(vtrace) | is_trace_rejections), + _align_vector(_verbose | is_trace_vtransform(vtrace) | is_trace_align_vector), + _info (_verbose | is_trace_vtransform(vtrace) | is_trace_info) {} + + static bool is_trace_vtransform(const VTrace& vtrace) { + return vtrace.is_trace(TraceAutoVectorizationTag::VTRANSFORM); + } +}; +#endif + +// VTransformGraph: component of VTransform +// See description at top of this file. +class VTransformGraph : public StackObj { +private: + const VLoopAnalyzer& _vloop_analyzer; + const VLoop& _vloop; + + NOT_PRODUCT(const VTransformTrace _trace;) + + VTransformNodeIDX _next_idx; + GrowableArray _vtnodes; + + // Schedule (linearization) of the graph. We use this to reorder the memory graph + // before inserting vector operations. + GrowableArray _schedule; + +public: + VTransformGraph(const VLoopAnalyzer& vloop_analyzer, + Arena& arena + NOT_PRODUCT( COMMA const VTransformTrace trace)) : + _vloop_analyzer(vloop_analyzer), + _vloop(vloop_analyzer.vloop()), + NOT_PRODUCT(_trace(trace) COMMA) + _next_idx(0), + _vtnodes(&arena, _vloop.estimated_body_length(), 0, nullptr), + _schedule(&arena, _vloop.estimated_body_length(), 0, nullptr) {} + + VTransformNodeIDX new_idx() { return _next_idx++; } + void add_vtnode(VTransformNode* vtnode); + DEBUG_ONLY( bool is_empty() const { return _vtnodes.is_empty(); } ) + DEBUG_ONLY( bool is_scheduled() const { return _schedule.is_nonempty(); } ) + const GrowableArray& vtnodes() const { return _vtnodes; } + + bool schedule(); + void apply_memops_reordering_with_schedule() const; + void apply_vectorization_for_each_vtnode(uint& max_vector_length, uint& max_vector_width) const; + +private: + // VLoop accessors + PhaseIdealLoop* phase() const { return _vloop.phase(); } + PhaseIterGVN& igvn() const { return _vloop.phase()->igvn(); } + bool in_bb(const Node* n) const { return _vloop.in_bb(n); } + + void collect_nodes_without_req_or_dependency(GrowableArray& stack) const; + + template + void for_each_memop_in_schedule(Callback callback) const; + +#ifndef PRODUCT + void print_vtnodes() const; + void print_schedule() const; + void print_memops_schedule() const; + void trace_schedule_cycle(const GrowableArray& stack, + const VectorSet& pre_visited, + const VectorSet& post_visited) const; +#endif +}; + +// VTransform: models the transformation of the scalar loop to vectorized loop. +// It is a "C2 subgraph" to "C2 subgraph" mapping. +// See description at top of this file. +class VTransform : public StackObj { +private: + const VLoopAnalyzer& _vloop_analyzer; + const VLoop& _vloop; + + NOT_PRODUCT(const VTransformTrace _trace;) + + // Everything in the vtransform is allocated from this arena, including all vtnodes. + Arena _arena; + + VTransformGraph _graph; + + // Memory reference, and the alignment width (aw) for which we align the main-loop, + // by adjusting the pre-loop limit. + MemNode const* _mem_ref_for_main_loop_alignment; + int _aw_for_main_loop_alignment; + +public: + VTransform(const VLoopAnalyzer& vloop_analyzer, + MemNode const* mem_ref_for_main_loop_alignment, + int aw_for_main_loop_alignment + NOT_PRODUCT( COMMA const VTransformTrace trace) + ) : + _vloop_analyzer(vloop_analyzer), + _vloop(vloop_analyzer.vloop()), + NOT_PRODUCT(_trace(trace) COMMA) + _arena(mtCompiler), + _graph(_vloop_analyzer, _arena NOT_PRODUCT(COMMA _trace)), + _mem_ref_for_main_loop_alignment(mem_ref_for_main_loop_alignment), + _aw_for_main_loop_alignment(aw_for_main_loop_alignment) {} + + const VLoopAnalyzer& vloop_analyzer() const { return _vloop_analyzer; } + Arena* arena() { return &_arena; } + DEBUG_ONLY( bool has_graph() const { return !_graph.is_empty(); } ) + VTransformGraph& graph() { return _graph; } + + bool schedule() { return _graph.schedule(); } + void apply(); + +private: + // VLoop accessors + PhaseIdealLoop* phase() const { return _vloop.phase(); } + PhaseIterGVN& igvn() const { return _vloop.phase()->igvn(); } + IdealLoopTree* lpt() const { return _vloop.lpt(); } + CountedLoopNode* cl() const { return _vloop.cl(); } + int iv_stride() const { return cl()->stride_con(); } + + // VLoopVPointers accessors + const VPointer& vpointer(const MemNode* mem) const { + return _vloop_analyzer.vpointers().vpointer(mem); + } + + // Ensure that the main loop vectors are aligned by adjusting the pre loop limit. + void determine_mem_ref_and_aw_for_main_loop_alignment(); + void adjust_pre_loop_limit_to_align_main_loop_vectors(); + + void apply_vectorization() const; +}; + +// The vtnodes (VTransformNode) resemble the C2 IR Nodes, and model a part of the +// VTransform. Many such vtnodes make up the VTransformGraph. The vtnodes represent +// the resulting scalar and vector nodes as closely as possible. +// See description at top of this file. +class VTransformNode : public ArenaObj { +public: + const VTransformNodeIDX _idx; + +private: + // _in is split into required inputs (_req), and additional dependencies. + const uint _req; + GrowableArray _in; + GrowableArray _out; + +public: + VTransformNode(VTransform& vtransform, const uint req) : + _idx(vtransform.graph().new_idx()), + _req(req), + _in(vtransform.arena(), req, req, nullptr), + _out(vtransform.arena(), 4, 0, nullptr) + { + vtransform.graph().add_vtnode(this); + } + + void set_req(uint i, VTransformNode* n) { + assert(i < _req, "must be a req"); + assert(_in.at(i) == nullptr && n != nullptr, "only set once"); + _in.at_put(i, n); + n->add_out(this); + } + + void swap_req(uint i, uint j) { + assert(i < _req, "must be a req"); + assert(j < _req, "must be a req"); + VTransformNode* tmp = _in.at(i); + _in.at_put(i, _in.at(j)); + _in.at_put(j, tmp); + } + + void add_dependency(VTransformNode* n) { + assert(n != nullptr, "no need to add nullptr"); + _in.push(n); + n->add_out(this); + } + + void add_out(VTransformNode* n) { + _out.push(n); + } + + uint req() const { return _req; } + VTransformNode* in(int i) const { return _in.at(i); } + int outs() const { return _out.length(); } + VTransformNode* out(int i) const { return _out.at(i); } + + bool has_req_or_dependency() const { + for (int i = 0; i < _in.length(); i++) { + if (_in.at(i) != nullptr) { return true; } + } + return false; + } + + virtual VTransformScalarNode* isa_Scalar() { return nullptr; } + virtual VTransformInputScalarNode* isa_InputScalar() { return nullptr; } + virtual VTransformVectorNode* isa_Vector() { return nullptr; } + virtual VTransformElementWiseVectorNode* isa_ElementWiseVector() { return nullptr; } + virtual VTransformBoolVectorNode* isa_BoolVector() { return nullptr; } + virtual VTransformReductionVectorNode* isa_ReductionVector() { return nullptr; } + + virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const = 0; + + Node* find_transformed_input(int i, const GrowableArray& vnode_idx_to_transformed_node) const; + + void register_new_node_from_vectorization(const VLoopAnalyzer& vloop_analyzer, Node* vn, Node* old_node) const; + + NOT_PRODUCT(virtual const char* name() const = 0;) + NOT_PRODUCT(void print() const;) + NOT_PRODUCT(virtual void print_spec() const {};) + NOT_PRODUCT(static void print_node_idx(const VTransformNode* vtn);) +}; + +// Identity transform for scalar nodes. +class VTransformScalarNode : public VTransformNode { +private: + Node* _node; +public: + VTransformScalarNode(VTransform& vtransform, Node* n) : + VTransformNode(vtransform, n->req()), _node(n) {} + Node* node() const { return _node; } + virtual VTransformScalarNode* isa_Scalar() override { return this; } + virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const override; + NOT_PRODUCT(virtual const char* name() const override { return "Scalar"; };) + NOT_PRODUCT(virtual void print_spec() const override;) +}; + +// Wrapper node for nodes outside the loop that are inputs to nodes in the loop. +// Since we want the loop-internal nodes to be able to reference all inputs as vtnodes, +// we must wrap the inputs that are outside the loop into special vtnodes, too. +class VTransformInputScalarNode : public VTransformScalarNode { +public: + VTransformInputScalarNode(VTransform& vtransform, Node* n) : + VTransformScalarNode(vtransform, n) {} + virtual VTransformInputScalarNode* isa_InputScalar() override { return this; } + NOT_PRODUCT(virtual const char* name() const override { return "InputScalar"; };) +}; + +// Transform produces a ReplicateNode, replicating the input to all vector lanes. +class VTransformReplicateNode : public VTransformNode { +private: + int _vlen; + const Type* _element_type; +public: + VTransformReplicateNode(VTransform& vtransform, int vlen, const Type* element_type) : + VTransformNode(vtransform, 2), _vlen(vlen), _element_type(element_type) {} + virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const override; + NOT_PRODUCT(virtual const char* name() const override { return "Replicate"; };) + NOT_PRODUCT(virtual void print_spec() const override;) +}; + +// Transform introduces a scalar ConvI2LNode that was not previously in the C2 graph. +class VTransformConvI2LNode : public VTransformNode { +public: + VTransformConvI2LNode(VTransform& vtransform) : VTransformNode(vtransform, 2) {} + virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const override; + NOT_PRODUCT(virtual const char* name() const override { return "ConvI2L"; };) +}; + +// Transform introduces a shift-count node that truncates the shift count for a vector shift. +class VTransformShiftCountNode : public VTransformNode { +private: + int _vlen; + const BasicType _element_bt; + juint _mask; + int _shift_opcode; +public: + VTransformShiftCountNode(VTransform& vtransform, int vlen, BasicType element_bt, juint mask, int shift_opcode) : + VTransformNode(vtransform, 2), _vlen(vlen), _element_bt(element_bt), _mask(mask), _shift_opcode(shift_opcode) {} + virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const override; + NOT_PRODUCT(virtual const char* name() const override { return "ShiftCount"; };) + NOT_PRODUCT(virtual void print_spec() const override;) +}; + +// Transform introduces a PopulateIndex node: [phi, phi+1, phi+2, phi+3, ...]. +class VTransformPopulateIndexNode : public VTransformNode { +private: + int _vlen; + const BasicType _element_bt; +public: + VTransformPopulateIndexNode(VTransform& vtransform, int vlen, const BasicType element_bt) : + VTransformNode(vtransform, 2), _vlen(vlen), _element_bt(element_bt) {} + virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const override; + NOT_PRODUCT(virtual const char* name() const override { return "PopulateIndex"; };) + NOT_PRODUCT(virtual void print_spec() const override;) +}; + +// Base class for all vector vtnodes. +class VTransformVectorNode : public VTransformNode { +private: + GrowableArray _nodes; +public: + VTransformVectorNode(VTransform& vtransform, const uint req, const uint number_of_nodes) : + VTransformNode(vtransform, req), _nodes(vtransform.arena(), number_of_nodes, number_of_nodes, nullptr) {} + + void set_nodes(const Node_List* pack) { + for (uint k = 0; k < pack->size(); k++) { + _nodes.at_put(k, pack->at(k)); + } + } + + const GrowableArray& nodes() const { return _nodes; } + virtual VTransformVectorNode* isa_Vector() override { return this; } + void register_new_node_from_vectorization_and_replace_scalar_nodes(const VLoopAnalyzer& vloop_analyzer, Node* vn) const; + NOT_PRODUCT(virtual void print_spec() const override;) +}; + +// Catch all for all element-wise vector operations. +class VTransformElementWiseVectorNode : public VTransformVectorNode { +public: + VTransformElementWiseVectorNode(VTransform& vtransform, uint req, uint number_of_nodes) : + VTransformVectorNode(vtransform, req, number_of_nodes) {} + virtual VTransformElementWiseVectorNode* isa_ElementWiseVector() override { return this; } + virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const override; + NOT_PRODUCT(virtual const char* name() const override { return "ElementWiseVector"; };) +}; + +struct VTransformBoolTest { + const BoolTest::mask _mask; + const bool _is_negated; + + VTransformBoolTest(const BoolTest::mask mask, bool is_negated) : + _mask(mask), _is_negated(is_negated) {} +}; + +class VTransformBoolVectorNode : public VTransformElementWiseVectorNode { +private: + const VTransformBoolTest _test; +public: + VTransformBoolVectorNode(VTransform& vtransform, uint number_of_nodes, VTransformBoolTest test) : + VTransformElementWiseVectorNode(vtransform, 2, number_of_nodes), _test(test) {} + VTransformBoolTest test() const { return _test; } + virtual VTransformBoolVectorNode* isa_BoolVector() override { return this; } + virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const override; + NOT_PRODUCT(virtual const char* name() const override { return "BoolVector"; };) +}; + +class VTransformReductionVectorNode : public VTransformVectorNode { +public: + // req = 3 -> [ctrl, scalar init, vector] + VTransformReductionVectorNode(VTransform& vtransform, uint number_of_nodes) : + VTransformVectorNode(vtransform, 3, number_of_nodes) {} + virtual VTransformReductionVectorNode* isa_ReductionVector() override { return this; } + virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const override; + NOT_PRODUCT(virtual const char* name() const override { return "ReductionVector"; };) +}; + +class VTransformLoadVectorNode : public VTransformVectorNode { +public: + // req = 3 -> [ctrl, mem, adr] + VTransformLoadVectorNode(VTransform& vtransform, uint number_of_nodes) : + VTransformVectorNode(vtransform, 3, number_of_nodes) {} + LoadNode::ControlDependency control_dependency() const; + virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const override; + NOT_PRODUCT(virtual const char* name() const override { return "LoadVector"; };) +}; + +class VTransformStoreVectorNode : public VTransformVectorNode { +public: + // req = 4 -> [ctrl, mem, adr, val] + VTransformStoreVectorNode(VTransform& vtransform, uint number_of_nodes) : + VTransformVectorNode(vtransform, 4, number_of_nodes) {} + virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const override; + NOT_PRODUCT(virtual const char* name() const override { return "StoreVector"; };) +}; + +// Invoke callback on all memops, in the order of the schedule. +template +void VTransformGraph::for_each_memop_in_schedule(Callback callback) const { + assert(_schedule.length() == _vtnodes.length(), "schedule was computed"); + + for (int i = 0; i < _schedule.length(); i++) { + VTransformNode* vtn = _schedule.at(i); + + // We can ignore input nodes, they are outside the loop. + if (vtn->isa_InputScalar() != nullptr) { continue; } + + VTransformScalarNode* scalar = vtn->isa_Scalar(); + if (scalar != nullptr && scalar->node()->is_Mem()) { + callback(scalar->node()->as_Mem()); + } + + VTransformVectorNode* vector = vtn->isa_Vector(); + if (vector != nullptr && vector->nodes().at(0)->is_Mem()) { + for (int j = 0; j < vector->nodes().length(); j++) { + callback(vector->nodes().at(j)->as_Mem()); + } + } + } +} + +#endif // SHARE_OPTO_VTRANSFORM_HPP From 55fd1ed228ea3c42aaf92579e5dcb818fe14351d Mon Sep 17 00:00:00 2001 From: Jatin Bhateja Date: Mon, 8 Jul 2024 06:42:46 +0000 Subject: [PATCH 003/460] 8333890: Fatal error in auto-vectorizer with float16 kernel. Reviewed-by: kvn --- src/hotspot/share/opto/superword.cpp | 6 ++ .../TestFloat16VectorConvChain.java | 65 +++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorConvChain.java diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index ba2dd423bf5..5721f7bcd54 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -2586,6 +2586,12 @@ const Type* VLoopTypes::container_type(Node* n) const { } const Type* t = _vloop.phase()->igvn().type(n); if (t->basic_type() == T_INT) { + // Float to half float conversion may be succeeded by a conversion from + // half float to float, in such a case back propagation of narrow type (SHORT) + // may not be possible. + if (n->Opcode() == Op_ConvF2HF) { + return TypeInt::SHORT; + } // A narrow type of arithmetic operations will be determined by // propagating the type of memory operations. return TypeInt::INT; diff --git a/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorConvChain.java b/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorConvChain.java new file mode 100644 index 00000000000..6b090c965bb --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorConvChain.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** +* @test +* @summary Test Float16 vector conversion chain. +* @requires vm.compiler2.enabled +* @library /test/lib / +* @run driver compiler.vectorization.TestFloat16VectorConvChain +*/ + +package compiler.vectorization; + +import compiler.lib.ir_framework.*; +import java.util.Random; +import java.util.Arrays; + + +public class TestFloat16VectorConvChain { + + @Test + @IR(counts = {IRNode.VECTOR_CAST_HF2F, IRNode.VECTOR_SIZE_ANY, ">= 1", IRNode.VECTOR_CAST_F2HF, IRNode.VECTOR_SIZE_ANY, " >= 1"}) + public static void test(short [] res, short [] src1, short [] src2) { + for (int i = 0; i < res.length; i++) { + res[i] = (short)Float.float16ToFloat(Float.floatToFloat16(Float.float16ToFloat(src1[i]) + Float.float16ToFloat(src2[i]))); + } + } + + @Run(test = {"test"}) + @Warmup(1000) + public static void micro() { + short [] res = new short[1024]; + short [] src1 = new short[1024]; + short [] src2 = new short[1024]; + Arrays.fill(src1, (short)Float.floatToFloat16(1.0f)); + Arrays.fill(src2, (short)Float.floatToFloat16(2.0f)); + for (int i = 0; i < 1000; i++) { + test(res, src1, src2); + } + } + + public static void main(String [] args) { + TestFramework.run(TestFloat16VectorConvChain.class); + } +} From 3cce31ad8877ec62429981871bcb0067770f9ccb Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Mon, 8 Jul 2024 08:06:56 +0000 Subject: [PATCH 004/460] 8335643: serviceability/dcmd/vm tests fail for ZGC after JDK-8322475 Reviewed-by: sgehwolf, dholmes --- test/hotspot/jtreg/ProblemList-generational-zgc.txt | 3 --- test/hotspot/jtreg/ProblemList-zgc.txt | 3 --- .../jtreg/serviceability/dcmd/vm/SystemMapTestBase.java | 4 +++- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList-generational-zgc.txt b/test/hotspot/jtreg/ProblemList-generational-zgc.txt index bdeed9947c5..db8182641ac 100644 --- a/test/hotspot/jtreg/ProblemList-generational-zgc.txt +++ b/test/hotspot/jtreg/ProblemList-generational-zgc.txt @@ -114,7 +114,4 @@ serviceability/sa/sadebugd/PmapOnDebugdTest.java 8307393 generic- serviceability/sa/sadebugd/RunCommandOnServerTest.java 8307393 generic-all serviceability/sa/sadebugd/SADebugDTest.java 8307393 generic-all -serviceability/dcmd/vm/SystemMapTest.java 8335643 generic-all -serviceability/dcmd/vm/SystemDumpMapTest.java 8335643 generic-all - vmTestbase/gc/gctests/MemoryEaterMT/MemoryEaterMT.java 8289582 windows-x64 diff --git a/test/hotspot/jtreg/ProblemList-zgc.txt b/test/hotspot/jtreg/ProblemList-zgc.txt index 892c980b069..1afe56c99f8 100644 --- a/test/hotspot/jtreg/ProblemList-zgc.txt +++ b/test/hotspot/jtreg/ProblemList-zgc.txt @@ -45,7 +45,4 @@ serviceability/sa/TestSysProps.java 8302055 generic- serviceability/sa/TestHeapDumpForInvokeDynamic.java 8315646 generic-all -serviceability/dcmd/vm/SystemMapTest.java 8335643 generic-all -serviceability/dcmd/vm/SystemDumpMapTest.java 8335643 generic-all - vmTestbase/gc/gctests/MemoryEaterMT/MemoryEaterMT.java 8289582 windows-x64 diff --git a/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTestBase.java b/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTestBase.java index 20dc8d70d7a..000e977a590 100644 --- a/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTestBase.java +++ b/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTestBase.java @@ -42,6 +42,8 @@ public class SystemMapTestBase { private static final String regexBase_committed = regexBase + "com.*"; private static final String regexBase_shared_and_committed = regexBase + "shrd,com.*"; + // java heap is either committed, non-shared, or - in case of ZGC - committed and shared. + private static final String regexBase_java_heap = regexBase + "(shrd,)?com.*"; protected static final String shouldMatchUnconditionally[] = { // java launcher regexBase_committed + "/bin/java", @@ -54,7 +56,7 @@ public class SystemMapTestBase { }; protected static final String shouldMatchIfNMTIsEnabled[] = { - regexBase_committed + "JAVAHEAP.*", + regexBase_java_heap + "JAVAHEAP.*", // metaspace regexBase_committed + "META.*", // parts of metaspace should be uncommitted From 540188fdebd089d4145eca18c0f95bf338cbcefc Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 8 Jul 2024 10:03:39 +0000 Subject: [PATCH 005/460] 8334445: Parallel: Decouple maximum compaction from SoftReference clearing Reviewed-by: zgu, lmao --- .../gc/parallel/parallelScavengeHeap.cpp | 6 +-- .../share/gc/parallel/psParallelCompact.cpp | 50 +++++++++---------- .../share/gc/parallel/psParallelCompact.hpp | 9 ++-- src/hotspot/share/gc/parallel/psScavenge.cpp | 4 +- 4 files changed, 31 insertions(+), 38 deletions(-) diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index 665b14bb1ea..33a499ce471 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -441,11 +441,7 @@ HeapWord* ParallelScavengeHeap::mem_allocate_old_gen(size_t size) { } void ParallelScavengeHeap::do_full_collection(bool clear_all_soft_refs) { - // The do_full_collection() parameter clear_all_soft_refs - // is interpreted here as maximum_compaction which will - // cause SoftRefs to be cleared. - bool maximum_compaction = clear_all_soft_refs; - PSParallelCompact::invoke(maximum_compaction); + PSParallelCompact::invoke(clear_all_soft_refs); } // Failed allocation policy. Must be called from the VM thread, and diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index b4fe706d1e4..d4a24b710cf 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -826,15 +826,21 @@ void PSParallelCompact::fill_dense_prefix_end(SpaceId id) { } } -bool PSParallelCompact::reassess_maximum_compaction(bool maximum_compaction, - size_t total_live_words, - MutableSpace* const old_space, - HeapWord* full_region_prefix_end) { +bool PSParallelCompact::check_maximum_compaction(size_t total_live_words, + MutableSpace* const old_space, + HeapWord* full_region_prefix_end) { + + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); + + // Check System.GC + bool is_max_on_system_gc = UseMaximumCompactionOnSystemGC + && GCCause::is_user_requested_gc(heap->gc_cause()); + // Check if all live objs are larger than old-gen. const bool is_old_gen_overflowing = (total_live_words > old_space->capacity_in_words()); // JVM flags - const uint total_invocations = ParallelScavengeHeap::heap()->total_full_collections(); + const uint total_invocations = heap->total_full_collections(); assert(total_invocations >= _maximum_compaction_gc_num, "sanity"); const size_t gcs_since_max = total_invocations - _maximum_compaction_gc_num; const bool is_interval_ended = gcs_since_max > HeapMaximumCompactionInterval; @@ -843,7 +849,7 @@ bool PSParallelCompact::reassess_maximum_compaction(bool maximum_compaction, const bool is_region_full = full_region_prefix_end >= _summary_data.region_align_down(old_space->top()); - if (maximum_compaction || is_old_gen_overflowing || is_interval_ended || is_region_full) { + if (is_max_on_system_gc || is_old_gen_overflowing || is_interval_ended || is_region_full) { _maximum_compaction_gc_num = total_invocations; return true; } @@ -851,7 +857,7 @@ bool PSParallelCompact::reassess_maximum_compaction(bool maximum_compaction, return false; } -void PSParallelCompact::summary_phase(bool maximum_compaction) +void PSParallelCompact::summary_phase() { GCTraceTime(Info, gc, phases) tm("Summary Phase", &_gc_timer); @@ -874,10 +880,9 @@ void PSParallelCompact::summary_phase(bool maximum_compaction) _space_info[i].set_dense_prefix(space->bottom()); } - maximum_compaction = reassess_maximum_compaction(maximum_compaction, - total_live_words, - old_space, - full_region_prefix_end); + bool maximum_compaction = check_maximum_compaction(total_live_words, + old_space, + full_region_prefix_end); HeapWord* dense_prefix_end = maximum_compaction ? full_region_prefix_end : compute_dense_prefix_for_old_space(old_space, @@ -958,26 +963,23 @@ void PSParallelCompact::summary_phase(bool maximum_compaction) // may be true because this method can be called without intervening // activity. For example when the heap space is tight and full measure // are being taken to free space. -bool PSParallelCompact::invoke(bool maximum_heap_compaction) { +bool PSParallelCompact::invoke(bool clear_all_soft_refs) { assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint"); assert(Thread::current() == (Thread*)VMThread::vm_thread(), "should be in vm thread"); - ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); - assert(!heap->is_stw_gc_active(), "not reentrant"); - IsSTWGCActiveMark mark; - const bool clear_all_soft_refs = - heap->soft_ref_policy()->should_clear_all_soft_refs(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); + clear_all_soft_refs = clear_all_soft_refs + || heap->soft_ref_policy()->should_clear_all_soft_refs(); - return PSParallelCompact::invoke_no_policy(clear_all_soft_refs || - maximum_heap_compaction); + return PSParallelCompact::invoke_no_policy(clear_all_soft_refs); } // This method contains no policy. You should probably // be calling invoke() instead. -bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { +bool PSParallelCompact::invoke_no_policy(bool clear_all_soft_refs) { assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint"); assert(ref_processor() != nullptr, "Sanity"); @@ -998,7 +1000,7 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { // The scope of casr should end after code that can change // SoftRefPolicy::_should_clear_all_soft_refs. - ClearedAllSoftRefs casr(maximum_heap_compaction, + ClearedAllSoftRefs casr(clear_all_soft_refs, heap->soft_ref_policy()); // Make sure data structures are sane, make the heap parsable, and do other @@ -1033,7 +1035,7 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { DerivedPointerTable::clear(); #endif - ref_processor()->start_discovery(maximum_heap_compaction); + ref_processor()->start_discovery(clear_all_soft_refs); ClassUnloadingContext ctx(1 /* num_nmethod_unlink_workers */, false /* unregister_nmethods_during_purge */, @@ -1041,9 +1043,7 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { marking_phase(&_gc_tracer); - bool max_on_system_gc = UseMaximumCompactionOnSystemGC - && GCCause::is_user_requested_gc(gc_cause); - summary_phase(maximum_heap_compaction || max_on_system_gc); + summary_phase(); #if COMPILER2_OR_JVMCI assert(DerivedPointerTable::is_active(), "Sanity"); diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.hpp index 93ea7aed78e..1e04beb8c66 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp @@ -723,10 +723,9 @@ class PSParallelCompact : AllStatic { static void pre_compact(); static void post_compact(); - static bool reassess_maximum_compaction(bool maximum_compaction, - size_t total_live_words, - MutableSpace* const old_space, - HeapWord* full_region_prefix_end); + static bool check_maximum_compaction(size_t total_live_words, + MutableSpace* const old_space, + HeapWord* full_region_prefix_end); // Mark live objects static void marking_phase(ParallelOldTracer *gc_tracer); @@ -739,7 +738,7 @@ class PSParallelCompact : AllStatic { // make the heap parsable. static void fill_dense_prefix_end(SpaceId id); - static void summary_phase(bool maximum_compaction); + static void summary_phase(); static void adjust_pointers(); static void forward_to_new_addr(); diff --git a/src/hotspot/share/gc/parallel/psScavenge.cpp b/src/hotspot/share/gc/parallel/psScavenge.cpp index 865bbd17099..708bb9da48a 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.cpp +++ b/src/hotspot/share/gc/parallel/psScavenge.cpp @@ -235,7 +235,6 @@ bool PSScavenge::invoke() { assert(!ParallelScavengeHeap::heap()->is_stw_gc_active(), "not reentrant"); ParallelScavengeHeap* const heap = ParallelScavengeHeap::heap(); - PSAdaptiveSizePolicy* policy = heap->size_policy(); IsSTWGCActiveMark mark; const bool scavenge_done = PSScavenge::invoke_no_policy(); @@ -250,8 +249,7 @@ bool PSScavenge::invoke() { if (need_full_gc) { GCCauseSetter gccs(heap, GCCause::_adaptive_size_policy); - SoftRefPolicy* srp = heap->soft_ref_policy(); - const bool clear_all_softrefs = srp->should_clear_all_soft_refs(); + const bool clear_all_softrefs = heap->soft_ref_policy()->should_clear_all_soft_refs(); full_gc_done = PSParallelCompact::invoke_no_policy(clear_all_softrefs); } From c5a668bb653feb3408a9efa3274ceabf9f01a2c7 Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Mon, 8 Jul 2024 10:33:08 +0000 Subject: [PATCH 006/460] 8334231: Optimize MethodData layout Reviewed-by: dholmes, chagedorn, shade --- src/hotspot/share/oops/methodData.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/hotspot/share/oops/methodData.hpp b/src/hotspot/share/oops/methodData.hpp index b6e2a1c9652..5071c29f1d7 100644 --- a/src/hotspot/share/oops/methodData.hpp +++ b/src/hotspot/share/oops/methodData.hpp @@ -1946,7 +1946,6 @@ class ciMethodData; class MethodData : public Metadata { friend class VMStructs; friend class JVMCIVMStructs; -private: friend class ProfileData; friend class TypeEntriesAtCall; friend class ciMethodData; @@ -2080,8 +2079,8 @@ class MethodData : public Metadata { #if INCLUDE_JVMCI // Support for HotSpotMethodData.setCompiledIRSize(int) - int _jvmci_ir_size; FailedSpeculation* _failed_speculations; + int _jvmci_ir_size; #endif // Size of _data array in bytes. (Excludes header and extra_data fields.) From c34a1b7013b27a8a214f63387bd528a90342a416 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Mon, 8 Jul 2024 10:53:03 +0000 Subject: [PATCH 007/460] 8335861: Problem list compiler/vectorization/TestFloat16VectorConvChain.java Reviewed-by: epeter --- test/hotspot/jtreg/ProblemList.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index d7088408ab8..76dc9f6f033 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -69,6 +69,8 @@ compiler/startup/StartupOutput.java 8326615 generic-x64 compiler/codecache/CodeCacheFullCountTest.java 8332954 generic-all +compiler/vectorization/TestFloat16VectorConvChain.java 8335860 generic-all + ############################################################################# # :hotspot_gc From 953c35eb5bff49ec5f7dbb25edd8a324b94318eb Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 8 Jul 2024 11:44:04 +0000 Subject: [PATCH 008/460] 8335824: Test gc/arguments/TestMinInitialErgonomics.java is timing out Reviewed-by: ayang, kbarrett --- test/hotspot/jtreg/gc/arguments/TestMinInitialErgonomics.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/gc/arguments/TestMinInitialErgonomics.java b/test/hotspot/jtreg/gc/arguments/TestMinInitialErgonomics.java index 6b03401a563..6912499e53f 100644 --- a/test/hotspot/jtreg/gc/arguments/TestMinInitialErgonomics.java +++ b/test/hotspot/jtreg/gc/arguments/TestMinInitialErgonomics.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ * @test TestMinInitialErgonomics * @bug 8006088 * @requires vm.gc.Parallel + * @requires vm.compMode != "Xcomp" * @summary Test Parallel GC ergonomics decisions related to minimum and initial heap size. * @library /test/lib * @library / From cec222e46065fc15db3f2eb241d3607d605ab580 Mon Sep 17 00:00:00 2001 From: Jorn Vernee Date: Mon, 8 Jul 2024 12:39:33 +0000 Subject: [PATCH 009/460] 8317611: Add a tool like jdeprscan to find usage of restricted methods Reviewed-by: alanb, ihse, mcimadamore, jlahoda, jwaters --- make/modules/jdk.jdeps/Launcher.gmk | 9 + .../javac/platform/JDKPlatformProvider.java | 11 +- .../share/classes/module-info.java | 8 +- .../classes/com/sun/tools/jdeprscan/Main.java | 4 +- .../tools/jnativescan/ClassFileSource.java | 124 +++++++++ .../sun/tools/jnativescan/ClassResolver.java | 163 +++++++++++ .../jnativescan/JNativeScanFatalError.java | 45 ++++ .../tools/jnativescan/JNativeScanTask.java | 195 ++++++++++++++ .../com/sun/tools/jnativescan/Main.java | 234 ++++++++++++++++ .../com/sun/tools/jnativescan/MethodRef.java | 48 ++++ .../tools/jnativescan/NativeMethodFinder.java | 141 ++++++++++ .../sun/tools/jnativescan/RestrictedUse.java | 32 +++ src/jdk.jdeps/share/classes/module-info.java | 23 +- src/jdk.jdeps/share/man/jnativescan.1 | 220 +++++++++++++++ test/jdk/tools/launcher/HelpFlagsTest.java | 1 + test/langtools/TEST.groups | 4 + .../jnativescan/JNativeScanTestBase.java | 86 ++++++ .../tools/jnativescan/TestArrayTypeRefs.java | 56 ++++ .../tools/jnativescan/TestJNativeScan.java | 252 ++++++++++++++++++ .../jnativescan/TestMissingSystemClass.java | 60 +++++ .../tools/jnativescan/TestSubclassRefs.java | 56 ++++ .../jnativescan/cases/classpath/app/App.java | 31 +++ .../cases/classpath/arrayref/App.java | 32 +++ .../jnativescan/cases/classpath/lib/Lib.java | 33 +++ .../cases/classpath/missingsystem/App.java | 32 +++ .../cases/classpath/singlejar/main/Main.java | 34 +++ .../cases/classpath/subclassref/App.java | 32 +++ .../unnamed_package/UnnamedPackage.java | 32 +++ .../cases/modules/org.lib/module-info.java | 26 ++ .../cases/modules/org.lib/org/lib/Lib.java | 34 +++ .../modules/org.lib/org/lib/Service.java | 26 ++ .../cases/modules/org.myapp/module-info.java | 28 ++ .../org.myapp/org/myapp/main/Main.java | 32 +++ .../modules/org.service/module-info.java | 27 ++ .../org.service/org/service/ServiceImpl.java | 35 +++ .../modules/org.singlejar/module-info.java | 25 ++ .../org/singlejar/main/Main.java | 34 +++ 37 files changed, 2250 insertions(+), 15 deletions(-) create mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/ClassFileSource.java create mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/ClassResolver.java create mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/JNativeScanFatalError.java create mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/JNativeScanTask.java create mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/Main.java create mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/MethodRef.java create mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/NativeMethodFinder.java create mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/RestrictedUse.java create mode 100644 src/jdk.jdeps/share/man/jnativescan.1 create mode 100644 test/langtools/tools/jnativescan/JNativeScanTestBase.java create mode 100644 test/langtools/tools/jnativescan/TestArrayTypeRefs.java create mode 100644 test/langtools/tools/jnativescan/TestJNativeScan.java create mode 100644 test/langtools/tools/jnativescan/TestMissingSystemClass.java create mode 100644 test/langtools/tools/jnativescan/TestSubclassRefs.java create mode 100644 test/langtools/tools/jnativescan/cases/classpath/app/App.java create mode 100644 test/langtools/tools/jnativescan/cases/classpath/arrayref/App.java create mode 100644 test/langtools/tools/jnativescan/cases/classpath/lib/Lib.java create mode 100644 test/langtools/tools/jnativescan/cases/classpath/missingsystem/App.java create mode 100644 test/langtools/tools/jnativescan/cases/classpath/singlejar/main/Main.java create mode 100644 test/langtools/tools/jnativescan/cases/classpath/subclassref/App.java create mode 100644 test/langtools/tools/jnativescan/cases/classpath/unnamed_package/UnnamedPackage.java create mode 100644 test/langtools/tools/jnativescan/cases/modules/org.lib/module-info.java create mode 100644 test/langtools/tools/jnativescan/cases/modules/org.lib/org/lib/Lib.java create mode 100644 test/langtools/tools/jnativescan/cases/modules/org.lib/org/lib/Service.java create mode 100644 test/langtools/tools/jnativescan/cases/modules/org.myapp/module-info.java create mode 100644 test/langtools/tools/jnativescan/cases/modules/org.myapp/org/myapp/main/Main.java create mode 100644 test/langtools/tools/jnativescan/cases/modules/org.service/module-info.java create mode 100644 test/langtools/tools/jnativescan/cases/modules/org.service/org/service/ServiceImpl.java create mode 100644 test/langtools/tools/jnativescan/cases/modules/org.singlejar/module-info.java create mode 100644 test/langtools/tools/jnativescan/cases/modules/org.singlejar/org/singlejar/main/Main.java diff --git a/make/modules/jdk.jdeps/Launcher.gmk b/make/modules/jdk.jdeps/Launcher.gmk index ceab7931245..1aa54e16f45 100644 --- a/make/modules/jdk.jdeps/Launcher.gmk +++ b/make/modules/jdk.jdeps/Launcher.gmk @@ -51,3 +51,12 @@ $(eval $(call SetupBuildLauncher, jdeprscan, \ MAIN_CLASS := com.sun.tools.jdeprscan.Main, \ CFLAGS := -DEXPAND_CLASSPATH_WILDCARDS, \ )) + +################################################################################ +## Build jnativescan +################################################################################ + +$(eval $(call SetupBuildLauncher, jnativescan, \ + MAIN_CLASS := com.sun.tools.jnativescan.Main, \ + CFLAGS := -DEXPAND_CLASSPATH_WILDCARDS, \ +)) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/platform/JDKPlatformProvider.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/platform/JDKPlatformProvider.java index 487fe969f97..4c24f9892a6 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/platform/JDKPlatformProvider.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/platform/JDKPlatformProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -83,7 +83,14 @@ public Iterable getSupportedPlatformNames() { } @Override - public PlatformDescription getPlatform(String platformName, String options) { + public PlatformDescription getPlatform(String platformName, String options) throws PlatformNotSupported { + if (!SUPPORTED_JAVA_PLATFORM_VERSIONS.contains(platformName)) { + throw new PlatformNotSupported(); + } + return getPlatformTrusted(platformName); + } + + public PlatformDescription getPlatformTrusted(String platformName) { return new PlatformDescriptionImpl(platformName); } diff --git a/src/jdk.internal.opt/share/classes/module-info.java b/src/jdk.internal.opt/share/classes/module-info.java index 67ed1410560..ba6987f1ea9 100644 --- a/src/jdk.internal.opt/share/classes/module-info.java +++ b/src/jdk.internal.opt/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,11 +31,13 @@ module jdk.internal.opt { exports jdk.internal.joptsimple to jdk.jlink, - jdk.jshell; + jdk.jshell, + jdk.jdeps; exports jdk.internal.opt to jdk.compiler, jdk.jartool, jdk.javadoc, jdk.jlink, - jdk.jpackage; + jdk.jpackage, + jdk.jdeps; } diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java b/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java index c67510de441..f77d29a8bfa 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -414,7 +414,7 @@ boolean processRelease(String release, Collection classes) throws IOExce .noneMatch(n -> n.equals(release))) { return false; } - JavaFileManager fm = pp.getPlatform(release, "").getFileManager(); + JavaFileManager fm = pp.getPlatformTrusted(release).getFileManager(); List classNames = new ArrayList<>(); for (JavaFileObject fo : fm.list(StandardLocation.PLATFORM_CLASS_PATH, "", diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/ClassFileSource.java b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/ClassFileSource.java new file mode 100644 index 00000000000..754904c9c7f --- /dev/null +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/ClassFileSource.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.tools.jnativescan; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.lang.module.ModuleReader; +import java.lang.module.ModuleReference; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.jar.JarFile; +import java.util.stream.Stream; +import java.util.zip.ZipFile; + +sealed interface ClassFileSource { + String moduleName(); + Path path(); + + Stream classFiles(Runtime.Version version) throws IOException; + + record Module(ModuleReference reference) implements ClassFileSource { + @Override + public String moduleName() { + return reference.descriptor().name(); + } + + @Override + public Path path() { + URI location = reference.location().orElseThrow(); + return Path.of(location); + } + + @Override + public Stream classFiles(Runtime.Version version) throws IOException { + ModuleReader reader = reference().open(); + return reader.list() + .filter(resourceName -> resourceName.endsWith(".class")) + .map(resourceName -> { + try (InputStream stream = reader.open(resourceName).orElseThrow()) { + return stream.readAllBytes(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }).onClose(() -> { + try { + reader.close(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); + } + } + + record ClassPathJar(Path path) implements ClassFileSource { + @Override + public String moduleName() { + return "ALL-UNNAMED"; + } + + @Override + public Stream classFiles(Runtime.Version version) throws IOException { + JarFile jf = new JarFile(path().toFile(), false, ZipFile.OPEN_READ, version); + return jf.versionedStream() + .filter(je -> je.getName().endsWith(".class")) + .map(je -> { + try (InputStream stream = jf.getInputStream(je)){ + return stream.readAllBytes(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }).onClose(() -> { + try { + jf.close(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); + } + } + + record ClassPathDirectory(Path path) implements ClassFileSource { + @Override + public String moduleName() { + return "ALL-UNNAMED"; + } + + @Override + public Stream classFiles(Runtime.Version version) throws IOException { + return Files.walk(path) + .filter(file -> Files.isRegularFile(file) && file.toString().endsWith(".class")) + .map(file -> { + try (InputStream stream = Files.newInputStream(file)){ + return stream.readAllBytes(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); + } + } +} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/ClassResolver.java b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/ClassResolver.java new file mode 100644 index 00000000000..7a267a58aa5 --- /dev/null +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/ClassResolver.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.tools.jnativescan; + +import com.sun.tools.javac.platform.PlatformDescription; +import com.sun.tools.javac.platform.PlatformProvider; + +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.StandardLocation; +import java.io.IOException; +import java.lang.classfile.ClassFile; +import java.lang.classfile.ClassModel; +import java.lang.constant.ClassDesc; +import java.lang.module.ModuleDescriptor; +import java.util.*; +import java.util.function.BiConsumer; +import java.util.stream.Stream; + +abstract class ClassResolver implements AutoCloseable { + + static ClassResolver forClassFileSources(List sources, Runtime.Version version) throws IOException { + Map classMap = new HashMap<>(); + for (ClassFileSource source : sources) { + try (Stream classFiles = source.classFiles(version)) { + classFiles.forEach(bytes -> { + ClassModel model = ClassFile.of().parse(bytes); + ClassDesc desc = model.thisClass().asSymbol(); + classMap.put(desc, new Info(source, model)); + }); + } + } + return new SimpleClassResolver(classMap); + } + + static ClassResolver forSystemModules(Runtime.Version version) { + String platformName = String.valueOf(version.feature()); + PlatformProvider platformProvider = ServiceLoader.load(PlatformProvider.class).findFirst().orElseThrow(); + PlatformDescription platform; + try { + platform = platformProvider.getPlatform(platformName, null); + } catch (PlatformProvider.PlatformNotSupported e) { + throw new JNativeScanFatalError("Release: " + platformName + " not supported", e); + } + JavaFileManager fm = platform.getFileManager(); + return new SystemModuleClassResolver(fm); + } + + record Info(ClassFileSource source, ClassModel model) {} + + public abstract void forEach(BiConsumer action); + public abstract Optional lookup(ClassDesc desc); + + @Override + public abstract void close() throws IOException; + + private static class SimpleClassResolver extends ClassResolver { + + private final Map classMap; + + public SimpleClassResolver(Map classMap) { + this.classMap = classMap; + } + + public void forEach(BiConsumer action) { + classMap.forEach(action); + } + + public Optional lookup(ClassDesc desc) { + return Optional.ofNullable(classMap.get(desc)); + } + + @Override + public void close() {} + } + + private static class SystemModuleClassResolver extends ClassResolver { + + private final JavaFileManager platformFileManager; + private final Map packageToSystemModule; + private final Map cache = new HashMap<>(); + + public SystemModuleClassResolver(JavaFileManager platformFileManager) { + this.platformFileManager = platformFileManager; + this.packageToSystemModule = packageToSystemModule(platformFileManager); + } + + private static Map packageToSystemModule(JavaFileManager platformFileManager) { + try { + Set locations = platformFileManager.listLocationsForModules( + StandardLocation.SYSTEM_MODULES).iterator().next(); + + Map result = new HashMap<>(); + for (JavaFileManager.Location loc : locations) { + JavaFileObject jfo = platformFileManager.getJavaFileForInput(loc, "module-info", JavaFileObject.Kind.CLASS); + ModuleDescriptor descriptor = ModuleDescriptor.read(jfo.openInputStream()); + for (ModuleDescriptor.Exports export : descriptor.exports()) { + if (!export.isQualified()) { + result.put(export.source(), descriptor.name()); + } + } + } + return result; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public void forEach(BiConsumer action) { + throw new UnsupportedOperationException("NYI"); + } + + @Override + public Optional lookup(ClassDesc desc) { + return Optional.ofNullable(cache.computeIfAbsent(desc, _ -> { + String qualName = JNativeScanTask.qualName(desc); + String moduleName = packageToSystemModule.get(desc.packageName()); + if (moduleName != null) { + try { + JavaFileManager.Location loc = platformFileManager.getLocationForModule(StandardLocation.SYSTEM_MODULES, moduleName); + JavaFileObject jfo = platformFileManager.getJavaFileForInput(loc, qualName, JavaFileObject.Kind.CLASS); + if (jfo == null) { + throw new JNativeScanFatalError("System class can not be found: " + qualName); + } + ClassModel model = ClassFile.of().parse(jfo.openInputStream().readAllBytes()); + return new Info(null, model); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + return null; + })); + } + + @Override + public void close() throws IOException { + platformFileManager.close(); + } + } +} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/JNativeScanFatalError.java b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/JNativeScanFatalError.java new file mode 100644 index 00000000000..15cf86e03c3 --- /dev/null +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/JNativeScanFatalError.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.tools.jnativescan; + +import java.io.Serial; + +// Exception used in case of fatal error that is reasonably expected and handled. +public class JNativeScanFatalError extends RuntimeException { + @Serial + private static final long serialVersionUID = 1L; + + public JNativeScanFatalError(String message) { + super(message); + } + + public JNativeScanFatalError(String message, Throwable cause) { + super(message, cause); + } + + public JNativeScanFatalError(Throwable cause) { + super(cause); + } +} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/JNativeScanTask.java b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/JNativeScanTask.java new file mode 100644 index 00000000000..2ff172e9c1b --- /dev/null +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/JNativeScanTask.java @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.tools.jnativescan; + +import java.io.IOException; +import java.io.PrintWriter; +import java.lang.constant.ClassDesc; +import java.lang.module.Configuration; +import java.lang.module.ModuleFinder; +import java.lang.module.ResolvedModule; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.jar.JarFile; +import java.util.jar.Manifest; +import java.util.stream.Collectors; +import java.util.zip.ZipFile; + +class JNativeScanTask { + + private final PrintWriter out; + private final List classPaths; + private final List modulePaths; + private final List cmdRootModules; + private final Runtime.Version version; + private final Action action; + + public JNativeScanTask(PrintWriter out, List classPaths, List modulePaths, + List cmdRootModules, Runtime.Version version, Action action) { + this.out = out; + this.classPaths = classPaths; + this.modulePaths = modulePaths; + this.version = version; + this.action = action; + this.cmdRootModules = cmdRootModules; + } + + public void run() throws JNativeScanFatalError { + List toScan = new ArrayList<>(findAllClassPathJars()); + + ModuleFinder moduleFinder = ModuleFinder.of(modulePaths.toArray(Path[]::new)); + List rootModules = cmdRootModules; + if (rootModules.contains("ALL-MODULE-PATH")) { + rootModules = allModuleNames(moduleFinder); + } + Configuration config = systemConfiguration().resolveAndBind(ModuleFinder.of(), moduleFinder, rootModules); + for (ResolvedModule m : config.modules()) { + toScan.add(new ClassFileSource.Module(m.reference())); + } + + SortedMap>> allRestrictedMethods; + try(ClassResolver classesToScan = ClassResolver.forClassFileSources(toScan, version); + ClassResolver systemClassResolver = ClassResolver.forSystemModules(version)) { + NativeMethodFinder finder = NativeMethodFinder.create(classesToScan, systemClassResolver); + allRestrictedMethods = finder.findAll(); + } catch (IOException e) { + throw new RuntimeException(e); + } + + switch (action) { + case PRINT -> printNativeAccess(allRestrictedMethods); + case DUMP_ALL -> dumpAll(allRestrictedMethods); + } + } + + private List findAllClassPathJars() throws JNativeScanFatalError { + List result = new ArrayList<>(); + for (Path path : classPaths) { + if (isJarFile(path)) { + Deque jarsToScan = new ArrayDeque<>(); + jarsToScan.offer(path); + + // recursively look for all class path jars, starting at the root jars + // in this.classPaths, and recursively following all Class-Path manifest + // attributes + while (!jarsToScan.isEmpty()) { + Path jar = jarsToScan.poll(); + String[] classPathAttribute = classPathAttribute(jar); + Path parentDir = jar.getParent(); + for (String classPathEntry : classPathAttribute) { + Path otherJar = parentDir != null + ? parentDir.resolve(classPathEntry) + : Path.of(classPathEntry); + if (Files.exists(otherJar)) { + // Class-Path attribute specifies that jars that + // are not found are simply ignored. Do the same here + jarsToScan.offer(otherJar); + } + } + result.add(new ClassFileSource.ClassPathJar(jar)); + } + } else if (Files.isDirectory(path)) { + result.add(new ClassFileSource.ClassPathDirectory(path)); + } else { + throw new JNativeScanFatalError( + "Path does not appear to be a jar file, or directory containing classes: " + path); + } + } + return result; + } + + private String[] classPathAttribute(Path jar) { + try (JarFile jf = new JarFile(jar.toFile(), false, ZipFile.OPEN_READ, version)) { + Manifest manifest = jf.getManifest(); + if (manifest != null) { + String attrib = manifest.getMainAttributes().getValue("Class-Path"); + if (attrib != null) { + return attrib.split("\\s+"); + } + } + return new String[0]; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private Configuration systemConfiguration() { + ModuleFinder systemFinder = ModuleFinder.ofSystem(); + Configuration system = Configuration.resolve(systemFinder, List.of(Configuration.empty()), ModuleFinder.of(), + allModuleNames(systemFinder)); // resolve all of them + return system; + } + + private List allModuleNames(ModuleFinder finder) { + return finder.findAll().stream().map(mr -> mr.descriptor().name()).toList(); + } + + private void printNativeAccess(SortedMap>> allRestrictedMethods) { + String nativeAccess = allRestrictedMethods.keySet().stream() + .map(ClassFileSource::moduleName) + .distinct() + .collect(Collectors.joining(",")); + out.println(nativeAccess); + } + + private void dumpAll(SortedMap>> allRestrictedMethods) { + if (allRestrictedMethods.isEmpty()) { + out.println(" "); + } else { + allRestrictedMethods.forEach((module, perClass) -> { + out.println(module.path() + " (" + module.moduleName() + "):"); + perClass.forEach((classDesc, restrictedUses) -> { + out.println(" " + qualName(classDesc) + ":"); + restrictedUses.forEach(use -> { + switch (use) { + case RestrictedUse.NativeMethodDecl(MethodRef nmd) -> + out.println(" " + nmd + " is a native method declaration"); + case RestrictedUse.RestrictedMethodRefs(MethodRef referent, Set referees) -> { + out.println(" " + referent + " references restricted methods:"); + referees.forEach(referee -> out.println(" " + referee)); + } + } + }); + }); + }); + } + } + + private static boolean isJarFile(Path path) throws JNativeScanFatalError { + return Files.exists(path) && Files.isRegularFile(path) && path.toString().endsWith(".jar"); + } + + public enum Action { + DUMP_ALL, + PRINT + } + + public static String qualName(ClassDesc desc) { + String packagePrefix = desc.packageName().isEmpty() ? "" : desc.packageName() + "."; + return packagePrefix + desc.displayName(); + } +} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/Main.java b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/Main.java new file mode 100644 index 00000000000..425a106d599 --- /dev/null +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/Main.java @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.tools.jnativescan; + +import jdk.internal.joptsimple.*; +import jdk.internal.opt.CommandLine; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Path; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; +import java.util.spi.ToolProvider; + +public class Main { + + private static boolean DEBUG = Boolean.getBoolean("com.sun.tools.jnativescan.DEBUG"); + + private static final int SUCCESS_CODE = 0; + private static final int FATAL_ERROR_CODE = 1; + + private final PrintWriter out; + private final PrintWriter err; + + private Main(PrintWriter out, PrintWriter err) { + this.out = out; + this.err = err; + } + + private void printError(String message) { + err.println("ERROR: " + message); + } + + private void printUsage() { + out.print(""" + Use 'jnativescan --help' for help + """); + } + + private void printVersion() { + out.println(System.getProperty("java.version")); + } + + public int run(String[] args) { + if (args.length < 1) { + printUsage(); + return FATAL_ERROR_CODE; + } + + try { + String[] expandedArgs = expandArgFiles(args); + parseOptionsAndRun(expandedArgs); + } catch (JNativeScanFatalError fatalError) { + printError(fatalError.getMessage()); + for (Throwable cause = fatalError.getCause(); + cause instanceof JNativeScanFatalError jNativeScanFatalError; + cause = jNativeScanFatalError.getCause()) { + err.println("CAUSED BY: " + jNativeScanFatalError.getMessage()); + } + if (DEBUG) { + fatalError.printStackTrace(err); + } + return FATAL_ERROR_CODE; + } catch (Throwable e) { + printError("Unexpected exception encountered"); + e.printStackTrace(err); + return FATAL_ERROR_CODE; + } + + return SUCCESS_CODE; + } + + private void parseOptionsAndRun(String[] expandedArgs) throws JNativeScanFatalError { + OptionParser parser = new OptionParser(false); + OptionSpec helpOpt = parser.acceptsAll(List.of("?", "h", "help"), "help").forHelp(); + OptionSpec versionOpt = parser.accepts("version", "Print version information and exit"); + OptionSpec classPathOpt = parser.accepts( + "class-path", + "The class path as used at runtime") + .withRequiredArg() + .withValuesSeparatedBy(File.pathSeparatorChar) + .withValuesConvertedBy(PARSE_PATH); + OptionSpec modulePathOpt = parser.accepts( + "module-path", + "The module path as used at runtime") + .withRequiredArg() + .withValuesSeparatedBy(File.pathSeparatorChar) + .withValuesConvertedBy(PARSE_PATH); + OptionSpec releaseOpt = parser.accepts( + "release", + "The runtime version that will run the application") + .withRequiredArg() + .withValuesConvertedBy(PARSE_VERSION); + OptionSpec addModulesOpt = parser.accepts( + "add-modules", + "List of root modules to scan") + .requiredIf(modulePathOpt) + .withRequiredArg() + .withValuesSeparatedBy(','); + OptionSpec printNativeAccessOpt = parser.accepts( + "print-native-access", + "print a comma separated list of modules that may perform native access operations." + + " ALL-UNNAMED is used to indicate unnamed modules."); + + OptionSet optionSet; + try { + optionSet = parser.parse(expandedArgs); + } catch (OptionException oe) { + throw new JNativeScanFatalError("Parsing options failed: " + oe.getMessage(), oe); + } + + if (optionSet.nonOptionArguments().size() != 0) { + throw new JNativeScanFatalError("jnativescan does not accept positional arguments"); + } + + if (optionSet.has(helpOpt)) { + out.println(""" + The jnativescan tool can be used to find methods that may access native functionality when + run. This includes restricted method calls and 'native' method declarations. + """); + try { + parser.printHelpOn(out); + return; + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + if (optionSet.has(versionOpt)) { + printVersion(); + return; + } + + List classPathJars = optionSet.valuesOf(classPathOpt); + List modulePaths = optionSet.valuesOf(modulePathOpt); + List rootModules = optionSet.valuesOf(addModulesOpt); + Runtime.Version version = Optional.ofNullable(optionSet.valueOf(releaseOpt)).orElse(Runtime.version()); + + JNativeScanTask.Action action = JNativeScanTask.Action.DUMP_ALL; + if (optionSet.has(printNativeAccessOpt)) { + action = JNativeScanTask.Action.PRINT; + } + + new JNativeScanTask(out, classPathJars, modulePaths, rootModules, version, action).run(); + } + + private static String[] expandArgFiles(String[] args) throws JNativeScanFatalError { + try { + return CommandLine.parse(args); + } catch (IOException e) { // file not found + throw new JNativeScanFatalError(e.getMessage(), e); + } + } + + public static void main(String[] args) { + System.exit(new Main.Provider().run(System.out, System.err, args)); + } + + public static class Provider implements ToolProvider { + + @Override + public String name() { + return "jnativescan"; + } + + @Override + public int run(PrintWriter out, PrintWriter err, String... args) { + return new Main(out, err).run(args); + } + } + + // where + private static final ValueConverter PARSE_PATH = new ValueConverter<>() { + @Override + public Path convert(String value) { + return Path.of(value); + } + + @Override + public Class valueType() { + return Path.class; + } + + @Override + public String valuePattern() { + return "Path"; + } + }; + + private static final ValueConverter PARSE_VERSION = new ValueConverter<>() { + @Override + public Runtime.Version convert(String value) { + try { + return Runtime.Version.parse(value); + } catch (IllegalArgumentException e) { + throw new JNativeScanFatalError("Invalid release: " + value + ": " + e.getMessage()); + } + } + + @Override + public Class valueType() { + return Runtime.Version.class; + } + + @Override + public String valuePattern() { + return "Version"; + } + }; +} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/MethodRef.java b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/MethodRef.java new file mode 100644 index 00000000000..b19e4e7ec8f --- /dev/null +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/MethodRef.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.tools.jnativescan; + +import java.lang.classfile.MethodModel; +import java.lang.classfile.constantpool.MemberRefEntry; +import java.lang.classfile.instruction.InvokeInstruction; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; + +record MethodRef(ClassDesc owner, String name, MethodTypeDesc type) { + public static MethodRef ofModel(MethodModel model) { + return new MethodRef(model.parent().orElseThrow().thisClass().asSymbol(), + model.methodName().stringValue(), model.methodTypeSymbol()); + } + + public static MethodRef ofInvokeInstruction(InvokeInstruction instruction) { + return new MethodRef(instruction.owner().asSymbol(), + instruction.name().stringValue(), instruction.typeSymbol()); + } + + @Override + public String toString() { + return JNativeScanTask.qualName(owner) + "::" + name + type.displayDescriptor(); + } +} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/NativeMethodFinder.java b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/NativeMethodFinder.java new file mode 100644 index 00000000000..681b954d4cd --- /dev/null +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/NativeMethodFinder.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.tools.jnativescan; + +import com.sun.tools.jnativescan.RestrictedUse.NativeMethodDecl; +import com.sun.tools.jnativescan.RestrictedUse.RestrictedMethodRefs; + +import java.io.IOException; +import java.lang.classfile.Attributes; +import java.lang.classfile.ClassModel; +import java.lang.classfile.MethodModel; +import java.lang.classfile.instruction.InvokeInstruction; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; +import java.lang.reflect.AccessFlag; +import java.util.*; + +class NativeMethodFinder { + + // ct.sym uses this fake name for the restricted annotation instead + // see make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java + private static final String RESTRICTED_NAME = "Ljdk/internal/javac/Restricted+Annotation;"; + + private final Map cache = new HashMap<>(); + private final ClassResolver classesToScan; + private final ClassResolver systemClassResolver; + + private NativeMethodFinder(ClassResolver classesToScan, ClassResolver systemClassResolver) { + this.classesToScan = classesToScan; + this.systemClassResolver = systemClassResolver; + } + + public static NativeMethodFinder create(ClassResolver classesToScan, ClassResolver systemClassResolver) throws JNativeScanFatalError, IOException { + return new NativeMethodFinder(classesToScan, systemClassResolver); + } + + public SortedMap>> findAll() throws JNativeScanFatalError { + SortedMap>> restrictedMethods + = new TreeMap<>(Comparator.comparing(ClassFileSource::path)); + classesToScan.forEach((_, info) -> { + ClassModel classModel = info.model(); + List perClass = new ArrayList<>(); + classModel.methods().forEach(methodModel -> { + if (methodModel.flags().has(AccessFlag.NATIVE)) { + perClass.add(new NativeMethodDecl(MethodRef.ofModel(methodModel))); + } else { + SortedSet perMethod = new TreeSet<>(Comparator.comparing(MethodRef::toString)); + methodModel.code().ifPresent(code -> { + try { + code.forEach(e -> { + switch (e) { + case InvokeInstruction invoke -> { + MethodRef ref = MethodRef.ofInvokeInstruction(invoke); + if (isRestrictedMethod(ref)) { + perMethod.add(ref); + } + } + default -> { + } + } + }); + } catch (JNativeScanFatalError e) { + throw new JNativeScanFatalError("Error while processing method: " + + MethodRef.ofModel(methodModel), e); + } + }); + if (!perMethod.isEmpty()) { + perClass.add(new RestrictedMethodRefs(MethodRef.ofModel(methodModel), perMethod)); + } + } + }); + if (!perClass.isEmpty()) { + restrictedMethods.computeIfAbsent(info.source(), + _ -> new TreeMap<>(Comparator.comparing(JNativeScanTask::qualName))) + .put(classModel.thisClass().asSymbol(), perClass); + } + }); + return restrictedMethods; + } + + private boolean isRestrictedMethod(MethodRef ref) throws JNativeScanFatalError { + return cache.computeIfAbsent(ref, methodRef -> { + if (methodRef.owner().isArray()) { + // no restricted methods in arrays atm, and we can't look them up since they have no class file + return false; + } + Optional info = systemClassResolver.lookup(methodRef.owner()); + if (!info.isPresent()) { + return false; + } + ClassModel classModel = info.get().model(); + Optional methodModel = findMethod(classModel, methodRef.name(), methodRef.type()); + if (!methodModel.isPresent()) { + // If we are here, the method was referenced through a subclass of the class containing the actual + // method declaration. We could implement a method resolver (that needs to be version aware + // as well) to find the method model of the declaration, but it's not really worth it. + // None of the restricted methods (atm) are exposed through more than 1 public type, so it's not + // possible for user code to reference them through a subclass. + return false; + } + + return hasRestrictedAnnotation(methodModel.get()); + }); + } + + private static boolean hasRestrictedAnnotation(MethodModel method) { + return method.findAttribute(Attributes.runtimeVisibleAnnotations()) + .map(rva -> rva.annotations().stream().anyMatch(ann -> + ann.className().stringValue().equals(RESTRICTED_NAME))) + .orElse(false); + } + + private static Optional findMethod(ClassModel classModel, String name, MethodTypeDesc type) { + return classModel.methods().stream() + .filter(m -> m.methodName().stringValue().equals(name) + && m.methodType().stringValue().equals(type.descriptorString())) + .findFirst(); + } +} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/RestrictedUse.java b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/RestrictedUse.java new file mode 100644 index 00000000000..58c5798d33f --- /dev/null +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/RestrictedUse.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.tools.jnativescan; + +import java.util.SortedSet; + +sealed interface RestrictedUse { + record RestrictedMethodRefs(MethodRef referent, SortedSet referees) implements RestrictedUse {} + record NativeMethodDecl(MethodRef decl) implements RestrictedUse {} +} diff --git a/src/jdk.jdeps/share/classes/module-info.java b/src/jdk.jdeps/share/classes/module-info.java index e8ad319d70c..3fdd3ca32d2 100644 --- a/src/jdk.jdeps/share/classes/module-info.java +++ b/src/jdk.jdeps/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,12 +28,13 @@ /** * Defines tools for analysing dependencies in Java libraries and programs, * including the {@index jdeps jdeps tool}, - * {@index javap javap tool}, and - * {@index jdeprscan jdeprscan tool} tools. + * {@index javap javap tool}, + * {@index jdeprscan jdeprscan tool}, and + * {@index jnativescan jnativescan tool} tools. * *

* This module provides the equivalent of command-line access to the - * javap and jdeps tools via the + * javap, jdeps, and jnativescan tools via the * {@link java.util.spi.ToolProvider ToolProvider} service provider * interface (SPI)

* @@ -49,12 +50,14 @@ * @toolGuide javap * @toolGuide jdeprscan * @toolGuide jdeps + * @toolGuide jnativescan * * @provides java.util.spi.ToolProvider - * Use {@link java.util.spi.ToolProvider#findFirst ToolProvider.findFirst("javap")} - * or {@link java.util.spi.ToolProvider#findFirst ToolProvider.findFirst("jdeps")} + * Use {@link java.util.spi.ToolProvider#findFirst ToolProvider.findFirst("javap")}, + * {@link java.util.spi.ToolProvider#findFirst ToolProvider.findFirst("jdeps")}, + * or {@link java.util.spi.ToolProvider#findFirst ToolProvider.findFirst("jnativescan")} * to obtain an instance of a {@code ToolProvider} that provides the equivalent - * of command-line access to the {@code javap} or {@code jdeps} tool. + * of command-line access to the {@code javap}, {@code jdeps}, {@code jnativescan} tool. * * @moduleGraph * @since 9 @@ -63,10 +66,14 @@ module jdk.jdeps { requires java.compiler; requires jdk.compiler; + requires jdk.internal.opt; + + uses com.sun.tools.javac.platform.PlatformProvider; exports com.sun.tools.classfile to jdk.jlink; provides java.util.spi.ToolProvider with com.sun.tools.javap.Main.JavapToolProvider, - com.sun.tools.jdeps.Main.JDepsToolProvider; + com.sun.tools.jdeps.Main.JDepsToolProvider, + com.sun.tools.jnativescan.Main.Provider; } diff --git a/src/jdk.jdeps/share/man/jnativescan.1 b/src/jdk.jdeps/share/man/jnativescan.1 new file mode 100644 index 00000000000..ff7f18277f2 --- /dev/null +++ b/src/jdk.jdeps/share/man/jnativescan.1 @@ -0,0 +1,220 @@ +.\" Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. +.\" DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +.\" +.\" This code is free software; you can redistribute it and/or modify it +.\" under the terms of the GNU General Public License version 2 only, as +.\" published by the Free Software Foundation. +.\" +.\" This code is distributed in the hope that it will be useful, but WITHOUT +.\" ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +.\" FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +.\" version 2 for more details (a copy is included in the LICENSE file that +.\" accompanied this code). +.\" +.\" You should have received a copy of the GNU General Public License version +.\" 2 along with this work; if not, write to the Free Software Foundation, +.\" Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +.\" +.\" Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +.\" or visit www.oracle.com if you need additional information or have any +.\" questions. +.\" +.\" Automatically generated by Pandoc 2.19.2 +.\" +.\" Define V font for inline verbatim, using C font in formats +.\" that render this, and otherwise B font. +.ie "\f[CB]x\f[R]"x" \{\ +. ftr V B +. ftr VI BI +. ftr VB B +. ftr VBI BI +.\} +.el \{\ +. ftr V CR +. ftr VI CI +. ftr VB CB +. ftr VBI CBI +.\} +.TH "JNATIVESCAN" "1" "2025" "JDK 24-ea" "JDK Commands" +.hy +.SH NAME +.PP +jnativescan - static analysis tool that scans one or more jar files for +uses of native functionalities, such as restricted method calls or +\f[V]native\f[R] method declarations. +.SH SYNOPSIS +.PP +\f[V]jnativescan\f[R] [\f[I]options\f[R]] +.TP +\f[I]options\f[R] +See \f[B]Options for the jnativescan Command\f[R] +.SH DESCRIPTION +.PP +The \f[V]jnative\f[R] tool is a static analysis tool provided by the JDK +that scans a JAR file for uses of native functionalities, such as +restricted method calls or \f[V]native\f[R] method declarations. +.PP +\f[V]jnativescan\f[R] accepts a runtime class path and module path +configuration, as well as a set of root modules, and a target release. +It scans the jars on the class and module paths, and reports uses of +native functionalities either in a tree like structure, which also +identifies that calling classes and methods, or as a list of module +names when the \f[V]--print-native-access\f[R] flag is specified. +.SH OPTIONS FOR THE JNATIVESCAN COMMAND +.PP +The following options are available: +.TP +\f[V]--class-path\f[R] \f[I]path\f[R] +Used to specify a list of paths pointing to jar files to be scanned. +.PP +All jar files specified through this list will be scanned. +If a jar file contains a \f[V]Class-Path\f[R] attribute in its manifest, +jar files listed there will be scanned as well. +Jar files listed in the \f[V]Class-Path\f[R] manifest attribute that can +not be found are ignored. +All the jar files found are treated as if they belonged to the unnamed +module. +.TP +\f[V]--module-path\f[R] \f[I]path\f[R] +Used to specify a list of paths pointing to jar files or directories +containing jar files, that the tool can use to find modules that need to +be scanned. +The list of jar files that will be scanned depends on the +\f[V]--add-modules\f[R] option. +.RS +.PP +For both the \f[V]--class-path\f[R] and \f[V]--module-path\f[R] options, +\f[I]path\f[R] should be a search path that consists of one or more jar +files, separated by the system-specific path separator. +For example: +.IP \[bu] 2 +\f[B]Linux and macOS:\f[R] +.RS 2 +.RS +.PP +\f[V]--class-path /some/foo.jar:/another/different/bar.jar\f[R] +.RE +.RE +.PP +\f[B]Note:\f[R] +.PP +On Windows, use a semicolon (\f[V];\f[R]) as the separator instead of a +colon (\f[V]:\f[R]). +.IP \[bu] 2 +\f[B]Windows:\f[R] +.RS 2 +.RS +.PP +\f[V]--class-path C:\[rs]some\[rs]foo.jar;C:\[rs]another\[rs]different\[rs]bar.jar\f[R] +.RE +.RE +.RE +.TP +\f[V]--add-modules\f[R] \f[I]module[,module...]\f[R] +Used to specify a comma-separated list of module names that indicate the +root modules to scan. +All the root modules will be scanned, as well as any modules that they +depend on. +This includes dependencies on service implementations specified through +the \f[V]uses\f[R] directive in a module\[aq]s \f[V]module-info\f[R] +file. +All modules found on the module path that provide an implementation of +such a service will be scanned as well. +.TP +\f[V]--release\f[R] \f[I]version\f[R] +Used to specify the Java SE release that specifies the set of restricted +methods to scan for. +For multi-release jar files, this option also indicates the version of +class file that should be loaded from the jar. +This option should be set to the version of the runtime under which the +application is eventually intended to be run. +If this flag is omitted, the version of \f[V]jnativescan\f[R] is used as +release version, which is the same as the version of the JDK that the +tool belongs to. +.TP +\f[V]--print-native-access\f[R] +Print a comma-separated list of module names that use native +functionalities, instead of the default tree structure. +.TP +\f[V]--help\f[R] or \f[V]-h\f[R] +Prints out a full help message. +.TP +\f[V]--version\f[R] +Prints out the abbreviated version string of the tool. +.SH EXAMPLE OF \f[V]jnativescan\f[R] USE +.PP +\f[V]jnativescan\f[R] accepts a runtime configuration in the form of a +class path, module path, set of root modules, and a target release +version. +For the class path, the tool will scan all jar files, including those +found recursively through the \f[V]Class-Path\f[R] manifest attribute. +For the module path, the tool scans all root modules specified through +\f[V]--add-modules\f[R], and any (transitive) dependence of the root +modules, including any modules that contain service implementations that +are used by a scanned module. +.PP +By default, the tool prints out which jars, classes, and methods use +native functionalities, in a tree-like structure. +The following is an example output: +.IP +.nf +\f[CB] +$ jnativescan --class-path app.jar +app.jar (ALL-UNNAMED): + foo.Main: + foo.Main::main(String[])void references restricted methods: + java.lang.foreign.MemorySegment::reinterpret(long)MemorySegment + foo.Main::nativeMethod()void is a native method declaration +\f[R] +.fi +.PP +\f[V]app.jar (ALL-UNNAMED)\f[R] is the path to the jar file, with the +module name in parentheses behind it. +Since in this case the jar file appears on the class path, +\f[V]ALL-UNNAMED\f[R] is printed to indicate the unnamed module. +The second line of the output, \f[V]foo.Main\f[R], indicates that +methods using native functionalities were found in the +\f[V]foo.Main\f[R] class. +The next line: +.IP +.nf +\f[CB] + foo.Main::main(String[])void references restricted methods: +\f[R] +.fi +.PP +Indicates that the \f[V]main(String[])\f[R] method in the +\f[V]foo.Main\f[R] class references a restricted method, which is listed +on the following line as: +.IP +.nf +\f[CB] + java.lang.foreign.MemorySegment::reinterpret(long)MemorySegment +\f[R] +.fi +.PP +Lastly, the text: +.IP +.nf +\f[CB] + foo.Main::nativeMethod()void is a native method declaration +\f[R] +.fi +.PP +Indicates that the \f[V]foo.Main\f[R] class contains a declaration of a +\f[V]native\f[R] method named \f[V]nativeMethod\f[R]. +.PP +If we add \f[V]--print-native-access\f[R] to the example command line, +we instead get a list of the names of modules that contain accesses to +native functionalities: +.IP +.nf +\f[CB] +$ jnativescan --class-path app.jar --print-native-access +ALL-UNNAMED +\f[R] +.fi +.PP +In this case the output consists of just \f[V]ALL-UNNAMED\f[R], which +indicates a jar file on the class path, that is, in the unnamed module, +contains an access to native functionalities. diff --git a/test/jdk/tools/launcher/HelpFlagsTest.java b/test/jdk/tools/launcher/HelpFlagsTest.java index dda649b9f41..15c6c101dd0 100644 --- a/test/jdk/tools/launcher/HelpFlagsTest.java +++ b/test/jdk/tools/launcher/HelpFlagsTest.java @@ -141,6 +141,7 @@ private static class ToolHelpSpec { new ToolHelpSpec("jlink", 1, 1, 1, 0, 0, 0, 2), // -?, -h, --help new ToolHelpSpec("jmap", 1, 1, 1, 0, 1, 0, 1), // -?, -h, --help, -help accepted but not documented. new ToolHelpSpec("jmod", 1, 1, 1, 0, 1, 0, 2), // -?, -h, --help, -help accepted but not documented. + new ToolHelpSpec("jnativescan", 1, 1, 1, 0, 1, 0, 1), // -?, -h, --help, -help accepted but not documented. new ToolHelpSpec("jps", 1, 1, 1, 0, 1, 1, 1), // -?, -h, --help -help, Documents -help new ToolHelpSpec("jrunscript", 1, 1, 1, 0, 1, 1, 7), // -?, -h, --help -help, Documents -help new ToolHelpSpec("jshell", 1, 1, 1, 0, 1, 0, 1), // -?, -h, --help, -help accepted but not documented. diff --git a/test/langtools/TEST.groups b/test/langtools/TEST.groups index 74503501da9..e290a1431a3 100644 --- a/test/langtools/TEST.groups +++ b/test/langtools/TEST.groups @@ -63,6 +63,10 @@ langtools_jdeps = \ tools/all \ tools/jdeps +langtools_jnativescan = \ + tools/all \ + tools/jnativescan + langtools_slow = \ jdk/internal/shellsupport/doc/FullJavadocHelperTest.java diff --git a/test/langtools/tools/jnativescan/JNativeScanTestBase.java b/test/langtools/tools/jnativescan/JNativeScanTestBase.java new file mode 100644 index 00000000000..97c0b21a738 --- /dev/null +++ b/test/langtools/tools/jnativescan/JNativeScanTestBase.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Path; +import java.util.Arrays; + +import java.io.StringWriter; +import java.util.spi.ToolProvider; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.util.JarUtils; + +public class JNativeScanTestBase { + + public static final String MODULE_PATH = "mods"; + + private static final ToolProvider JNATIVESCAN_TOOL = ToolProvider.findFirst("jnativescan") + .orElseThrow(() -> new RuntimeException("jnativescan tool not found")); + + public static OutputAnalyzer jnativescan(String... args) { + return run(JNATIVESCAN_TOOL, args); + } + + private static OutputAnalyzer run(ToolProvider tp, String[] commands) { + int rc; + StringWriter sw = new StringWriter(); + StringWriter esw = new StringWriter(); + + try (PrintWriter pw = new PrintWriter(sw); + PrintWriter epw = new PrintWriter(esw)) { + System.out.println("Running " + tp.name() + ", Command: " + Arrays.toString(commands)); + rc = tp.run(pw, epw, commands); + } + OutputAnalyzer output = new OutputAnalyzer(sw.toString(), esw.toString(), rc); + output.outputTo(System.out); + output.errorTo(System.err); + return output; + } + + public static Path makeModularJar(String moduleName) throws IOException { + Path jarPath = Path.of(MODULE_PATH, moduleName + ".jar"); + Path moduleRoot = moduleRoot(moduleName); + JarUtils.createJarFile(jarPath, moduleRoot); + return jarPath; + } + + public static Path moduleRoot(String name) { + return Path.of(System.getProperty("test.module.path")).resolve(name); + } + + public static OutputAnalyzer assertSuccess(OutputAnalyzer output) { + if (output.getExitValue() != 0) { + throw new IllegalStateException("tool run failed"); + } + return output; + } + + public static OutputAnalyzer assertFailure(OutputAnalyzer output) { + if (output.getExitValue() == 0) { + throw new IllegalStateException("tool run succeeded"); + } + return output; + } +} diff --git a/test/langtools/tools/jnativescan/TestArrayTypeRefs.java b/test/langtools/tools/jnativescan/TestArrayTypeRefs.java new file mode 100644 index 00000000000..a439fdfdef9 --- /dev/null +++ b/test/langtools/tools/jnativescan/TestArrayTypeRefs.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib .. ./cases/modules + * @build JNativeScanTestBase + * cases.classpath.arrayref.App + * @run junit TestArrayTypeRefs + */ + +import jdk.test.lib.util.JarUtils; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.nio.file.Path; + +public class TestArrayTypeRefs extends JNativeScanTestBase { + + static Path ARRAY_REF; + + @BeforeAll + public static void before() throws IOException { + ARRAY_REF = Path.of("arrayref.jar"); + Path testClasses = Path.of(System.getProperty("test.classes", "")); + JarUtils.createJarFile(ARRAY_REF, testClasses, Path.of("arrayref", "App.class")); + } + + @Test + public void testSingleJarClassPath() { + assertSuccess(jnativescan("--class-path", ARRAY_REF.toString())) + .stderrShouldBeEmpty() + .stdoutShouldContain(""); + } +} diff --git a/test/langtools/tools/jnativescan/TestJNativeScan.java b/test/langtools/tools/jnativescan/TestJNativeScan.java new file mode 100644 index 00000000000..94db4924412 --- /dev/null +++ b/test/langtools/tools/jnativescan/TestJNativeScan.java @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib .. ./cases/modules + * @build JNativeScanTestBase + * org.singlejar/* org.lib/* org.myapp/* org.service/* + * cases.classpath.singlejar.main.Main + * cases.classpath.lib.Lib + * cases.classpath.app.App + * cases.classpath.unnamed_package.UnnamedPackage + * @run junit TestJNativeScan + */ + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.util.JarUtils; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.util.HashSet; +import java.util.Set; +import java.util.jar.Attributes; +import java.util.jar.Manifest; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +class TestJNativeScan extends JNativeScanTestBase { + + static Path TEST_CLASSES; + + static Path CLASS_PATH_APP; + static Path SINGLE_JAR_CLASS_PATH; + static Path SINGLE_JAR_MODULAR; + static Path ORG_MYAPP; + static Path ORG_LIB; + static Path UNNAMED_PACKAGE_JAR; + static Path LIB_JAR; + + @BeforeAll + public static void before() throws IOException { + SINGLE_JAR_CLASS_PATH = Path.of("singleJar.jar"); + TEST_CLASSES = Path.of(System.getProperty("test.classes", "")); + JarUtils.createJarFile(SINGLE_JAR_CLASS_PATH, TEST_CLASSES, Path.of("main", "Main.class")); + + LIB_JAR = Path.of("lib.jar"); + JarUtils.createJarFile(LIB_JAR, TEST_CLASSES, Path.of("lib", "Lib.class")); + Manifest manifest = new Manifest(); + Attributes mainAttrs = manifest.getMainAttributes(); + mainAttrs.put(Attributes.Name.MANIFEST_VERSION, "1.0"); // need version or other attributes will be ignored + mainAttrs.putValue("Class-Path", "lib.jar non-existent.jar"); + CLASS_PATH_APP = Path.of("app.jar"); + JarUtils.createJarFile(CLASS_PATH_APP, manifest, TEST_CLASSES, Path.of("app", "App.class")); + + SINGLE_JAR_MODULAR = makeModularJar("org.singlejar"); + ORG_MYAPP = makeModularJar("org.myapp"); + ORG_LIB = makeModularJar("org.lib"); + makeModularJar("org.service"); + + UNNAMED_PACKAGE_JAR = Path.of("unnamed_package.jar"); + JarUtils.createJarFile(UNNAMED_PACKAGE_JAR, TEST_CLASSES, Path.of("UnnamedPackage.class")); + } + + @Test + public void testSingleJarClassPath() { + assertSuccess(jnativescan("--class-path", SINGLE_JAR_CLASS_PATH.toString())) + .stderrShouldBeEmpty() + .stdoutShouldContain("ALL-UNNAMED") + .stdoutShouldContain("main.Main") + .stdoutShouldContain("main.Main::m()void is a native method declaration") + .stdoutShouldContain("main.Main::main(String[])void references restricted methods") + .stdoutShouldContain("java.lang.foreign.MemorySegment::reinterpret(long)MemorySegment"); + } + + @Test + public void testSingleJarModulePath() { + assertSuccess(jnativescan("--module-path", MODULE_PATH, "--add-modules", "org.singlejar")) + .stderrShouldBeEmpty() + .stdoutShouldContain("org.singlejar") + .stdoutShouldContain("org.singlejar.main.Main") + .stdoutShouldContain("org.singlejar.main.Main::m()void is a native method declaration") + .stdoutShouldContain("org.singlejar.main.Main::main(String[])void references restricted methods") + .stdoutShouldContain("java.lang.foreign.MemorySegment::reinterpret(long)MemorySegment"); + } + + @Test + public void testWithDepModule() { + assertSuccess(jnativescan("--module-path", MODULE_PATH, "--add-modules", "org.myapp")) + .stderrShouldBeEmpty() + .stdoutShouldContain("org.lib") + .stdoutShouldContain("org.lib.Lib") + .stdoutShouldContain("org.lib.Lib::m()void is a native method declaration") + .stdoutShouldContain("org.lib.Lib::doIt()void references restricted methods") + .stdoutShouldContain("java.lang.foreign.MemorySegment::reinterpret(long)MemorySegment") + .stdoutShouldContain("org.service") + .stdoutShouldContain("org.service.ServiceImpl") + .stdoutShouldContain("org.service.ServiceImpl::m()void is a native method declaration") + .stdoutShouldContain("org.service.ServiceImpl::doIt()void references restricted methods") + .stdoutShouldContain("java.lang.foreign.MemorySegment::reinterpret(long)MemorySegment"); + } + + @Test + public void testAllModulePath() { + assertSuccess(jnativescan("--module-path", MODULE_PATH, "--add-modules", "ALL-MODULE-PATH")) + .stderrShouldBeEmpty() + .stdoutShouldContain("org.singlejar") + .stdoutShouldContain("org.lib") + .stdoutShouldContain("org.service"); + } + + @Test + public void testClassPathAttribute() { + assertSuccess(jnativescan("--class-path", CLASS_PATH_APP.toString())) + .stderrShouldBeEmpty() + .stdoutShouldContain("ALL-UNNAMED") + .stdoutShouldContain("lib.Lib") + .stdoutShouldContain("lib.Lib::m()void is a native method declaration") + .stdoutShouldContain("lib.Lib::doIt()void references restricted methods") + .stdoutShouldContain("java.lang.foreign.MemorySegment::reinterpret(long)MemorySegment"); + } + + @Test + public void testInvalidRelease() { + assertFailure(jnativescan("--module-path", MODULE_PATH, "--add-modules", "ALL-MODULE-PATH", "--release", "asdf")) + .stderrShouldContain("Invalid release"); + } + + @Test + public void testReleaseNotSupported() { + assertFailure(jnativescan("--module-path", MODULE_PATH, "--add-modules", "ALL-MODULE-PATH", "--release", "9999999")) + .stderrShouldContain("Release: 9999999 not supported"); + } + + @Test + public void testFileDoesNotExist() { + assertFailure(jnativescan("--class-path", "non-existent.jar")) + .stderrShouldContain("Path does not appear to be a jar file, or directory containing classes"); + } + + @Test + public void testModuleNotAJarFile() { + String modulePath = moduleRoot("org.myapp").toString() + File.pathSeparator + ORG_LIB.toString(); + assertSuccess(jnativescan("--module-path", modulePath, + "--add-modules", "ALL-MODULE-PATH")) + .stdoutShouldContain("lib.Lib") + .stdoutShouldContain("lib.Lib::m()void is a native method declaration") + .stdoutShouldContain("lib.Lib::doIt()void references restricted methods") + .stdoutShouldContain("java.lang.foreign.MemorySegment::reinterpret(long)MemorySegment"); + } + + @Test + public void testPrintNativeAccess() { + assertSuccess(jnativescan("--module-path", MODULE_PATH, + "-add-modules", "org.singlejar,org.myapp", + "--print-native-access")) + .stdoutShouldMatch("org.lib,org.service,org.singlejar"); + } + + @Test + public void testNoDuplicateNames() { + String classPath = SINGLE_JAR_CLASS_PATH + File.pathSeparator + CLASS_PATH_APP; + OutputAnalyzer output = assertSuccess(jnativescan("--class-path", classPath, "--print-native-access")); + String[] moduleNames = output.getStdout().split(","); + Set names = new HashSet<>(); + for (String name : moduleNames) { + assertTrue(names.add(name.strip())); + } + } + + @Test + public void testUnnamedPackage() { + assertSuccess(jnativescan("--class-path", UNNAMED_PACKAGE_JAR.toString())) + .stderrShouldBeEmpty() + .stdoutShouldContain("ALL-UNNAMED") + .stdoutShouldNotContain(".UnnamedPackage") + .stdoutShouldContain("UnnamedPackage") + .stdoutShouldContain("UnnamedPackage::m()void is a native method declaration") + .stdoutShouldContain("UnnamedPackage::main(String[])void references restricted methods") + .stdoutShouldContain("java.lang.foreign.MemorySegment::reinterpret(long)MemorySegment"); + } + + @Test + public void testPositionalArguments() { + assertFailure(jnativescan("foo")) + .stdoutShouldBeEmpty() + .stderrShouldContain("jnativescan does not accept positional arguments"); + } + + @Test + public void testMissingRootModules() { + assertFailure(jnativescan("--module-path", MODULE_PATH)) + .stdoutShouldBeEmpty() + .stderrShouldContain("Missing required option(s) [add-modules]"); + } + + @Test + public void testClassPathDirectory() { + assertSuccess(jnativescan("--class-path", TEST_CLASSES.toString())) + .stderrShouldBeEmpty() + .stdoutShouldContain("ALL-UNNAMED") + .stdoutShouldContain("UnnamedPackage") + .stdoutShouldContain("UnnamedPackage::m()void is a native method declaration") + .stdoutShouldContain("UnnamedPackage::main(String[])void references restricted methods") + .stdoutShouldContain("main.Main") + .stdoutShouldContain("main.Main::m()void is a native method declaration") + .stdoutShouldContain("main.Main::main(String[])void references restricted methods") + .stdoutShouldContain("lib.Lib") + .stdoutShouldContain("lib.Lib::m()void is a native method declaration") + .stdoutShouldContain("lib.Lib::doIt()void references restricted methods") + .stdoutShouldContain("java.lang.foreign.MemorySegment::reinterpret(long)MemorySegment"); + } + + @Test + public void testMultipleClassPathJars() { + // make sure all of these are reported, even when they are all in the ALL-UNNAMED module + String classPath = UNNAMED_PACKAGE_JAR + + File.pathSeparator + SINGLE_JAR_CLASS_PATH + + File.pathSeparator + LIB_JAR; + assertSuccess(jnativescan("--class-path", classPath)) + .stderrShouldBeEmpty() + .stdoutShouldContain("ALL-UNNAMED") + .stdoutShouldContain("UnnamedPackage") + .stdoutShouldContain(UNNAMED_PACKAGE_JAR.toString()) + .stdoutShouldContain("lib.Lib") + .stdoutShouldContain(LIB_JAR.toString()) + .stdoutShouldContain("main.Main") + .stdoutShouldContain(SINGLE_JAR_CLASS_PATH.toString()); + } +} diff --git a/test/langtools/tools/jnativescan/TestMissingSystemClass.java b/test/langtools/tools/jnativescan/TestMissingSystemClass.java new file mode 100644 index 00000000000..5806590d0e0 --- /dev/null +++ b/test/langtools/tools/jnativescan/TestMissingSystemClass.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib .. ./cases/modules + * @build JNativeScanTestBase + * @compile --release 20 cases/classpath/missingsystem/App.java + * @run junit TestMissingSystemClass + */ + +import jdk.test.lib.util.JarUtils; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.nio.file.Path; + +public class TestMissingSystemClass extends JNativeScanTestBase { + + static Path MISSING_SYSTEM; + + @BeforeAll + public static void before() throws IOException { + MISSING_SYSTEM = Path.of("missingsystem.jar"); + Path testClasses = Path.of(System.getProperty("test.classes", "")); + JarUtils.createJarFile(MISSING_SYSTEM, testClasses, Path.of("missingsystem", "App.class")); + } + + @Test + public void testSingleJarClassPath() { + assertFailure(jnativescan("--class-path", MISSING_SYSTEM.toString(), "--release", "21")) + .stdoutShouldBeEmpty() + .stderrShouldContain("Error while processing method") + .stderrShouldContain("missingsystem.App::main(String[])void") + .stderrShouldContain("CAUSED BY:") + .stderrShouldContain("System class can not be found") + .stderrShouldContain("java.lang.Compiler"); + } +} diff --git a/test/langtools/tools/jnativescan/TestSubclassRefs.java b/test/langtools/tools/jnativescan/TestSubclassRefs.java new file mode 100644 index 00000000000..c8eed0439ee --- /dev/null +++ b/test/langtools/tools/jnativescan/TestSubclassRefs.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib .. ./cases/modules + * @build JNativeScanTestBase + * cases.classpath.subclassref.App + * @run junit TestSubclassRefs + */ + +import jdk.test.lib.util.JarUtils; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.nio.file.Path; + +public class TestSubclassRefs extends JNativeScanTestBase { + + static Path SUBCLASS_REF; + + @BeforeAll + public static void before() throws IOException { + SUBCLASS_REF = Path.of("subclassref.jar"); + Path testClasses = Path.of(System.getProperty("test.classes", "")); + JarUtils.createJarFile(SUBCLASS_REF, testClasses, Path.of("subclassref", "App.class")); + } + + @Test + public void testSingleJarClassPath() { + assertSuccess(jnativescan("--class-path", SUBCLASS_REF.toString())) + .stderrShouldBeEmpty() + .stdoutShouldContain(""); + } +} diff --git a/test/langtools/tools/jnativescan/cases/classpath/app/App.java b/test/langtools/tools/jnativescan/cases/classpath/app/App.java new file mode 100644 index 00000000000..f96ab11e576 --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/classpath/app/App.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package app; + +import lib.Lib; + +public class App { + public static void main(String[] args) { + Lib.doIt(); + } +} diff --git a/test/langtools/tools/jnativescan/cases/classpath/arrayref/App.java b/test/langtools/tools/jnativescan/cases/classpath/arrayref/App.java new file mode 100644 index 00000000000..aa480f392fb --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/classpath/arrayref/App.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package arrayref; + +public class App { + public static void main(String[] args) { + // reference an array method to see that + // RestrictedMethodFinder correctly handles + // references to array methods + args.clone(); + } +} diff --git a/test/langtools/tools/jnativescan/cases/classpath/lib/Lib.java b/test/langtools/tools/jnativescan/cases/classpath/lib/Lib.java new file mode 100644 index 00000000000..ec92696364c --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/classpath/lib/Lib.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package lib; + +import java.lang.foreign.MemorySegment; + +public class Lib { + public static void doIt() { + MemorySegment.ofAddress(1234).reinterpret(10); + } + + private static native void m(); +} diff --git a/test/langtools/tools/jnativescan/cases/classpath/missingsystem/App.java b/test/langtools/tools/jnativescan/cases/classpath/missingsystem/App.java new file mode 100644 index 00000000000..0e20fe81eec --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/classpath/missingsystem/App.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package missingsystem; + +public class App { + public static void main(String[] args) { + // this class was present in Java 20, but removed in 21 + // if we compile with --release 20, but run jnativescan + // with --release 21, we should get an error + java.lang.Compiler.enable(); + } +} diff --git a/test/langtools/tools/jnativescan/cases/classpath/singlejar/main/Main.java b/test/langtools/tools/jnativescan/cases/classpath/singlejar/main/Main.java new file mode 100644 index 00000000000..280e8646f9f --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/classpath/singlejar/main/Main.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package main; + +import java.lang.foreign.*; + +public class Main { + public static void main(String[] args) { + MemorySegment.ofAddress(1234).reinterpret(10); + } + + private static native void m(); +} diff --git a/test/langtools/tools/jnativescan/cases/classpath/subclassref/App.java b/test/langtools/tools/jnativescan/cases/classpath/subclassref/App.java new file mode 100644 index 00000000000..abe9e41265e --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/classpath/subclassref/App.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package subclassref; + +import java.util.List; + +public class App { + public static void main(String[] args) { + List l = List.of(args); + l.stream(); // List does not declare stream() + } +} diff --git a/test/langtools/tools/jnativescan/cases/classpath/unnamed_package/UnnamedPackage.java b/test/langtools/tools/jnativescan/cases/classpath/unnamed_package/UnnamedPackage.java new file mode 100644 index 00000000000..4e8dfe69b5a --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/classpath/unnamed_package/UnnamedPackage.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.foreign.*; + +public class UnnamedPackage { + public static void main(String[] args) { + MemorySegment.ofAddress(1234).reinterpret(10); + } + + private static native void m(); +} diff --git a/test/langtools/tools/jnativescan/cases/modules/org.lib/module-info.java b/test/langtools/tools/jnativescan/cases/modules/org.lib/module-info.java new file mode 100644 index 00000000000..8572ed80e43 --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/modules/org.lib/module-info.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module org.lib { + exports org.lib; +} diff --git a/test/langtools/tools/jnativescan/cases/modules/org.lib/org/lib/Lib.java b/test/langtools/tools/jnativescan/cases/modules/org.lib/org/lib/Lib.java new file mode 100644 index 00000000000..3f9ea0e1ada --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/modules/org.lib/org/lib/Lib.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.lib; + +import java.lang.foreign.*; + +public class Lib { + public static void doIt() { + MemorySegment.ofAddress(1234).reinterpret(10); + } + + private static native void m(); +} diff --git a/test/langtools/tools/jnativescan/cases/modules/org.lib/org/lib/Service.java b/test/langtools/tools/jnativescan/cases/modules/org.lib/org/lib/Service.java new file mode 100644 index 00000000000..2e406d926a6 --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/modules/org.lib/org/lib/Service.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.lib; + +public interface Service { +} diff --git a/test/langtools/tools/jnativescan/cases/modules/org.myapp/module-info.java b/test/langtools/tools/jnativescan/cases/modules/org.myapp/module-info.java new file mode 100644 index 00000000000..8155fb5d8f2 --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/modules/org.myapp/module-info.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module org.myapp { + requires org.lib; + + uses org.lib.Service; +} diff --git a/test/langtools/tools/jnativescan/cases/modules/org.myapp/org/myapp/main/Main.java b/test/langtools/tools/jnativescan/cases/modules/org.myapp/org/myapp/main/Main.java new file mode 100644 index 00000000000..c2329b2ceeb --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/modules/org.myapp/org/myapp/main/Main.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.myapp.main; + +import org.lib.Lib; + +public class Main { + public static void main(String[] args) { + Lib.doIt(); + } +} diff --git a/test/langtools/tools/jnativescan/cases/modules/org.service/module-info.java b/test/langtools/tools/jnativescan/cases/modules/org.service/module-info.java new file mode 100644 index 00000000000..431dd64172d --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/modules/org.service/module-info.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +module org.service { + requires org.lib; + + provides org.lib.Service with org.service.ServiceImpl; +} diff --git a/test/langtools/tools/jnativescan/cases/modules/org.service/org/service/ServiceImpl.java b/test/langtools/tools/jnativescan/cases/modules/org.service/org/service/ServiceImpl.java new file mode 100644 index 00000000000..6e643f1c649 --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/modules/org.service/org/service/ServiceImpl.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.service; + +import org.lib.Service; + +import java.lang.foreign.MemorySegment; + +public class ServiceImpl implements Service { + public void doIt() { + MemorySegment.ofAddress(1234).reinterpret(10); + } + + private native void m(); +} diff --git a/test/langtools/tools/jnativescan/cases/modules/org.singlejar/module-info.java b/test/langtools/tools/jnativescan/cases/modules/org.singlejar/module-info.java new file mode 100644 index 00000000000..c9f96e4f771 --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/modules/org.singlejar/module-info.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +module org.singlejar { + +} diff --git a/test/langtools/tools/jnativescan/cases/modules/org.singlejar/org/singlejar/main/Main.java b/test/langtools/tools/jnativescan/cases/modules/org.singlejar/org/singlejar/main/Main.java new file mode 100644 index 00000000000..c6925eaf649 --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/modules/org.singlejar/org/singlejar/main/Main.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.singlejar.main; + +import java.lang.foreign.*; + +public class Main { + public static void main(String[] args) { + MemorySegment.ofAddress(1234).reinterpret(10); + } + + private static native void m(); +} From be3676f6bbc2d8041e43cf7bcfaee7fb9d864378 Mon Sep 17 00:00:00 2001 From: Matias Saavedra Silva Date: Mon, 8 Jul 2024 14:04:32 +0000 Subject: [PATCH 010/460] 8304484: CDS dynamic dumping incorrectly leads to "Error occurred during initialization of VM" Reviewed-by: ccheung, iklam --- src/hotspot/share/classfile/classLoader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp index 910cbe48c5c..e410824e300 100644 --- a/src/hotspot/share/classfile/classLoader.cpp +++ b/src/hotspot/share/classfile/classLoader.cpp @@ -470,7 +470,7 @@ bool ClassPathImageEntry::is_modules_image() const { void ClassLoader::exit_with_path_failure(const char* error, const char* message) { assert(CDSConfig::is_dumping_archive(), "sanity"); tty->print_cr("Hint: enable -Xlog:class+path=info to diagnose the failure"); - vm_exit_during_initialization(error, message); + vm_exit_during_cds_dumping(error, message); } #endif From d8c1c6ab0543c986280dcfa1c6c79e010a7b35fb Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 8 Jul 2024 15:45:26 +0000 Subject: [PATCH 011/460] 8335604: Serial: Inline Generation::contiguous_available Reviewed-by: tschatzl --- src/hotspot/share/gc/serial/defNewGeneration.cpp | 5 ----- src/hotspot/share/gc/serial/defNewGeneration.hpp | 2 -- src/hotspot/share/gc/serial/generation.hpp | 4 ---- src/hotspot/share/gc/serial/tenuredGeneration.cpp | 6 +----- src/hotspot/share/gc/serial/tenuredGeneration.hpp | 2 -- 5 files changed, 1 insertion(+), 18 deletions(-) diff --git a/src/hotspot/share/gc/serial/defNewGeneration.cpp b/src/hotspot/share/gc/serial/defNewGeneration.cpp index acf7e239103..715b82fd38d 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.cpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp @@ -533,11 +533,6 @@ size_t DefNewGeneration::capacity_before_gc() const { return eden()->capacity(); } -size_t DefNewGeneration::contiguous_available() const { - return eden()->free(); -} - - void DefNewGeneration::object_iterate(ObjectClosure* blk) { eden()->object_iterate(blk); from()->object_iterate(blk); diff --git a/src/hotspot/share/gc/serial/defNewGeneration.hpp b/src/hotspot/share/gc/serial/defNewGeneration.hpp index a7ee555902a..011b79fdabd 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.hpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.hpp @@ -172,8 +172,6 @@ class DefNewGeneration: public Generation { // heuristic resizing decisions. size_t unsafe_max_alloc_nogc() const; - size_t contiguous_available() const; - size_t max_eden_size() const { return _max_eden_size; } size_t max_survivor_size() const { return _max_survivor_size; } diff --git a/src/hotspot/share/gc/serial/generation.hpp b/src/hotspot/share/gc/serial/generation.hpp index 5e5aad5d0c1..a757c97c5cb 100644 --- a/src/hotspot/share/gc/serial/generation.hpp +++ b/src/hotspot/share/gc/serial/generation.hpp @@ -96,10 +96,6 @@ class Generation: public CHeapObj { // for the allocation of objects. virtual size_t max_capacity() const; - // The largest number of contiguous free bytes in the generation, - // including expansion (Assumes called at a safepoint.) - virtual size_t contiguous_available() const = 0; - MemRegion reserved() const { return _reserved; } /* Returns "TRUE" iff "p" points into the reserved area of the generation. */ diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.cpp b/src/hotspot/share/gc/serial/tenuredGeneration.cpp index f1389b48557..b1b75070947 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.cpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.cpp @@ -377,7 +377,7 @@ void TenuredGeneration::update_counters() { } bool TenuredGeneration::promotion_attempt_is_safe(size_t max_promotion_in_bytes) const { - size_t available = contiguous_available(); + size_t available = _the_space->free() + _virtual_space.uncommitted_size(); size_t av_promo = (size_t)_avg_promoted->padded_average(); bool res = (available >= av_promo) || (available >= max_promotion_in_bytes); @@ -413,10 +413,6 @@ TenuredGeneration::expand_and_allocate(size_t word_size, bool is_tlab) { return allocate(word_size, is_tlab); } -size_t TenuredGeneration::contiguous_available() const { - return _the_space->free() + _virtual_space.uncommitted_size(); -} - void TenuredGeneration::assert_correct_size_change_locking() { assert_locked_or_safepoint(Heap_lock); } diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.hpp b/src/hotspot/share/gc/serial/tenuredGeneration.hpp index bcb2d668213..dcec912d488 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.hpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.hpp @@ -124,8 +124,6 @@ class TenuredGeneration: public Generation { const char* name() const { return "tenured generation"; } const char* short_name() const { return "Tenured"; } - size_t contiguous_available() const; - // Iteration void object_iterate(ObjectClosure* blk); From a9b7f42f29120a3cca0d341350ff03cae485e68b Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Mon, 8 Jul 2024 16:20:01 +0000 Subject: [PATCH 012/460] 8333826: Update --release 23 symbol information for JDK 23 build 29 Reviewed-by: iris, jlahoda --- src/jdk.compiler/share/data/symbols/java.desktop-N.sym.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/jdk.compiler/share/data/symbols/java.desktop-N.sym.txt b/src/jdk.compiler/share/data/symbols/java.desktop-N.sym.txt index fdc899578cf..577ff91c7ca 100644 --- a/src/jdk.compiler/share/data/symbols/java.desktop-N.sym.txt +++ b/src/jdk.compiler/share/data/symbols/java.desktop-N.sym.txt @@ -119,6 +119,10 @@ class name javax/swing/JScrollBar method name setMinimumSize descriptor (Ljava/awt/Dimension;)V flags 1 method name setMaximumSize descriptor (Ljava/awt/Dimension;)V flags 1 +class name javax/swing/plaf/basic/BasicSliderUI +-method name descriptor ()V +method name descriptor ()V flags 1 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="23") + class name javax/swing/plaf/synth/SynthTreeUI method name getCollapsedIcon descriptor ()Ljavax/swing/Icon; flags 1 From 284671a1e4fb5bfe15b20b7f41fc24415b1235ed Mon Sep 17 00:00:00 2001 From: Calvin Cheung Date: Mon, 8 Jul 2024 16:44:22 +0000 Subject: [PATCH 013/460] 8335449: runtime/cds/DeterministicDump.java fails with File content different at byte ... Reviewed-by: matsaave, iklam --- test/hotspot/jtreg/runtime/cds/DeterministicDump.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/runtime/cds/DeterministicDump.java b/test/hotspot/jtreg/runtime/cds/DeterministicDump.java index 8f9bb4a5829..cc8d8c2b1dd 100644 --- a/test/hotspot/jtreg/runtime/cds/DeterministicDump.java +++ b/test/hotspot/jtreg/runtime/cds/DeterministicDump.java @@ -25,7 +25,7 @@ * @test * @bug 8241071 * @summary The same JDK build should always generate the same archive file (no randomness). - * @requires vm.cds + * @requires vm.cds & vm.flagless * @library /test/lib * @run driver DeterministicDump */ From 3a87eb5c4606ce39970962895315567e8606eba7 Mon Sep 17 00:00:00 2001 From: Kelvin Nilsen Date: Mon, 8 Jul 2024 18:03:19 +0000 Subject: [PATCH 014/460] 8335126: Shenandoah: Improve OOM handling Reviewed-by: shade, ysr, wkemper, rkennke --- .../gc/shenandoah/shenandoahControlThread.cpp | 3 +- .../gc/shenandoah/shenandoahDegeneratedGC.cpp | 1 - .../share/gc/shenandoah/shenandoahHeap.cpp | 48 ++++++++++++------- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index e538ca02467..95a70de5790 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -318,7 +318,8 @@ void ShenandoahControlThread::service_concurrent_normal_cycle(GCCause::Cause cau ShenandoahConcurrentGC gc; if (gc.collect(cause)) { - // Cycle is complete + // Cycle is complete. There were no failed allocation requests and no degeneration, so count this as good progress. + heap->notify_gc_progress(); heap->heuristics()->record_success_concurrent(); heap->shenandoah_policy()->record_success_concurrent(gc.abbreviated()); } else { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp index fb5283bb1d8..6b597d9b2d7 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp @@ -228,7 +228,6 @@ void ShenandoahDegenGC::op_degenerated() { // Check for futility and fail. There is no reason to do several back-to-back Degenerated cycles, // because that probably means the heap is overloaded and/or fragmented. if (!metrics.is_good_progress()) { - heap->notify_gc_no_progress(); heap->cancel_gc(GCCause::_shenandoah_upgrade_to_full_gc); op_degenerated_futile(); } else { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index ee3f4e7d8eb..5c5b6f7ebe5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -945,24 +945,36 @@ HeapWord* ShenandoahHeap::allocate_memory(ShenandoahAllocRequest& req) { return nullptr; } - // Block until control thread reacted, then retry allocation. - // - // It might happen that one of the threads requesting allocation would unblock - // way later after GC happened, only to fail the second allocation, because - // other threads have already depleted the free storage. In this case, a better - // strategy is to try again, as long as GC makes progress (or until at least - // one full GC has completed). - size_t original_count = shenandoah_policy()->full_gc_count(); - while (result == nullptr - && (get_gc_no_progress_count() == 0 || original_count == shenandoah_policy()->full_gc_count())) { - control_thread()->handle_alloc_failure(req, true); - result = allocate_memory_under_lock(req, in_new_region); - } - - if (log_is_enabled(Debug, gc, alloc)) { - ResourceMark rm; - log_debug(gc, alloc)("Thread: %s, Result: " PTR_FORMAT ", Request: %s, Size: " SIZE_FORMAT ", Original: " SIZE_FORMAT ", Latest: " SIZE_FORMAT, - Thread::current()->name(), p2i(result), req.type_string(), req.size(), original_count, get_gc_no_progress_count()); + if (result == nullptr) { + // Block until control thread reacted, then retry allocation. + // + // It might happen that one of the threads requesting allocation would unblock + // way later after GC happened, only to fail the second allocation, because + // other threads have already depleted the free storage. In this case, a better + // strategy is to try again, until at least one full GC has completed. + // + // Stop retrying and return nullptr to cause OOMError exception if our allocation failed even after: + // a) We experienced a GC that had good progress, or + // b) We experienced at least one Full GC (whether or not it had good progress) + // + // TODO: Consider GLOBAL GC rather than Full GC to remediate OOM condition: https://bugs.openjdk.org/browse/JDK-8335910 + + size_t original_count = shenandoah_policy()->full_gc_count(); + while ((result == nullptr) && (original_count == shenandoah_policy()->full_gc_count())) { + control_thread()->handle_alloc_failure(req, true); + result = allocate_memory_under_lock(req, in_new_region); + } + if (result != nullptr) { + // If our allocation request has been satisifed after it initially failed, we count this as good gc progress + notify_gc_progress(); + } + if (log_is_enabled(Debug, gc, alloc)) { + ResourceMark rm; + log_debug(gc, alloc)("Thread: %s, Result: " PTR_FORMAT ", Request: %s, Size: " SIZE_FORMAT + ", Original: " SIZE_FORMAT ", Latest: " SIZE_FORMAT, + Thread::current()->name(), p2i(result), req.type_string(), req.size(), + original_count, get_gc_no_progress_count()); + } } } else { assert(req.is_gc_alloc(), "Can only accept GC allocs here"); From 3733fe3a207078b585421cd2a098e808fafaa817 Mon Sep 17 00:00:00 2001 From: "lawrence.andrews" Date: Mon, 8 Jul 2024 19:14:33 +0000 Subject: [PATCH 015/460] 8335789: [TESTBUG] XparColor.java test fails with Error. Parse Exception: Invalid or unrecognized bugid: @ Reviewed-by: aivanov --- test/jdk/java/awt/print/PrinterJob/XparColor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/java/awt/print/PrinterJob/XparColor.java b/test/jdk/java/awt/print/PrinterJob/XparColor.java index 9a85a78af55..30713b1424e 100644 --- a/test/jdk/java/awt/print/PrinterJob/XparColor.java +++ b/test/jdk/java/awt/print/PrinterJob/XparColor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /** * @test * @bug 4179262 - @ @key printer + * @key printer * @summary Confirm that transparent colors are printed correctly. The * printout should show transparent rings with increasing darkness toward * the center. From babf6df7d97e4beedb25e689634d999412c1e950 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Mon, 8 Jul 2024 20:09:07 +0000 Subject: [PATCH 016/460] 8334757: AssertionError: Missing type variable in where clause Reviewed-by: jlahoda, vromero --- .../javac/util/RichDiagnosticFormatter.java | 3 +++ .../CantAnnotateClassWithTypeVariable.java | 19 +++++++++++++++++++ .../CantAnnotateClassWithTypeVariable.out | 2 ++ 3 files changed, 24 insertions(+) create mode 100644 test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateClassWithTypeVariable.java create mode 100644 test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateClassWithTypeVariable.out diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java index e1faa02bd38..3bc5c671bfd 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java @@ -184,6 +184,9 @@ protected void preprocessArgument(Object arg) { if (arg instanceof Type type) { preprocessType(type); } + else if (arg instanceof JCDiagnostic.AnnotatedType type) { + preprocessType(type.type()); + } else if (arg instanceof Symbol symbol) { preprocessSymbol(symbol); } diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateClassWithTypeVariable.java b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateClassWithTypeVariable.java new file mode 100644 index 00000000000..8d575caec57 --- /dev/null +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateClassWithTypeVariable.java @@ -0,0 +1,19 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8334757 + * @compile/fail/ref=CantAnnotateClassWithTypeVariable.out -XDrawDiagnostics CantAnnotateClassWithTypeVariable.java + */ + +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +public class CantAnnotateClassWithTypeVariable { + @Target(ElementType.TYPE_USE) + @interface TA {} + + static class A { + static class B {} + } + + @TA A.B f() {} +} diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateClassWithTypeVariable.out b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateClassWithTypeVariable.out new file mode 100644 index 00000000000..80fa9f2cdd9 --- /dev/null +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateClassWithTypeVariable.out @@ -0,0 +1,2 @@ +CantAnnotateClassWithTypeVariable.java:18:14: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @CantAnnotateClassWithTypeVariable.TA), CantAnnotateClassWithTypeVariable.A, @CantAnnotateClassWithTypeVariable.TA CantAnnotateClassWithTypeVariable.A.B +1 error From bb1f8a1698553d5962569ac8912edd0d7ef010dd Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Mon, 8 Jul 2024 20:10:27 +0000 Subject: [PATCH 017/460] 8335904: Fix invalid comment in ShenandoahLock Reviewed-by: shade --- src/hotspot/share/gc/shenandoah/shenandoahLock.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp b/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp index 6fc74c53e63..63c6c9ea886 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp @@ -44,7 +44,7 @@ void ShenandoahLock::contended_lock(bool allow_block_for_safepoint) { template void ShenandoahLock::contended_lock_internal(JavaThread* java_thread) { assert(!ALLOW_BLOCK || java_thread != nullptr, "Must have a Java thread when allowing block."); - // Spin this much on multi-processor, do not spin on multi-processor. + // Spin this much, but only on multi-processor systems. int ctr = os::is_MP() ? 0xFF : 0; // Apply TTAS to avoid more expensive CAS calls if the lock is still held by other thread. while (Atomic::load(&_state) == locked || From 9c7a6eabb93c570fdb74076edc931576ed6be3e0 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Mon, 8 Jul 2024 20:14:26 +0000 Subject: [PATCH 018/460] 8312125: Refactor CDS enum class handling Reviewed-by: matsaave, ccheung --- src/hotspot/share/cds/cdsEnumKlass.cpp | 136 +++++++++++++++++++++++ src/hotspot/share/cds/cdsEnumKlass.hpp | 50 +++++++++ src/hotspot/share/cds/heapShared.cpp | 94 +--------------- src/hotspot/share/cds/heapShared.hpp | 4 - src/hotspot/share/oops/instanceKlass.cpp | 3 +- 5 files changed, 192 insertions(+), 95 deletions(-) create mode 100644 src/hotspot/share/cds/cdsEnumKlass.cpp create mode 100644 src/hotspot/share/cds/cdsEnumKlass.hpp diff --git a/src/hotspot/share/cds/cdsEnumKlass.cpp b/src/hotspot/share/cds/cdsEnumKlass.cpp new file mode 100644 index 00000000000..b77f2fd9d16 --- /dev/null +++ b/src/hotspot/share/cds/cdsEnumKlass.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 "precompiled.hpp" +#include "cds/archiveHeapLoader.hpp" +#include "cds/cdsEnumKlass.hpp" +#include "cds/heapShared.hpp" +#include "classfile/vmClasses.hpp" +#include "classfile/systemDictionaryShared.hpp" +#include "memory/resourceArea.hpp" +#include "oops/fieldStreams.inline.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/fieldDescriptor.inline.hpp" + +#if INCLUDE_CDS_JAVA_HEAP + +bool CDSEnumKlass::is_enum_obj(oop orig_obj) { + Klass* k = orig_obj->klass(); + Klass* buffered_k = ArchiveBuilder::get_buffered_klass(k); + return k->is_instance_klass() && + InstanceKlass::cast(k)->java_super() == vmClasses::Enum_klass(); +} + +// -- Handling of Enum objects +// Java Enum classes have synthetic methods that look like this +// enum MyEnum {FOO, BAR} +// MyEnum:: { +// /*static final MyEnum*/ MyEnum::FOO = new MyEnum("FOO"); +// /*static final MyEnum*/ MyEnum::BAR = new MyEnum("BAR"); +// } +// +// If MyEnum::FOO object is referenced by any of the archived subgraphs, we must +// ensure the archived value equals (in object address) to the runtime value of +// MyEnum::FOO. +// +// However, since MyEnum:: is synthetically generated by javac, there's +// no way of programmatically handling this inside the Java code (as you would handle +// ModuleLayer::EMPTY_LAYER, for example). +// +// Instead, we archive all static field of such Enum classes. At runtime, +// HeapShared::initialize_enum_klass() skips the method and instead pulls +// the static fields out of the archived heap. +void CDSEnumKlass::handle_enum_obj(int level, + KlassSubGraphInfo* subgraph_info, + oop orig_obj) { + assert(level > 1, "must never be called at the first (outermost) level"); + assert(is_enum_obj(orig_obj), "must be"); + + InstanceKlass* ik = InstanceKlass::cast(orig_obj->klass()); + if (ik->has_archived_enum_objs()) { + return; + } + + ik->set_has_archived_enum_objs(); + ArchiveBuilder::get_buffered_klass(ik)->set_has_archived_enum_objs(); + + oop mirror = ik->java_mirror(); + for (JavaFieldStream fs(ik); !fs.done(); fs.next()) { + if (fs.access_flags().is_static()) { + archive_static_field(level, subgraph_info, ik, mirror, fs); + } + } +} + +void CDSEnumKlass::archive_static_field(int level, KlassSubGraphInfo* subgraph_info, + InstanceKlass* ik, oop mirror, JavaFieldStream& fs) { + ResourceMark rm; + fieldDescriptor& fd = fs.field_descriptor(); + if (fd.field_type() != T_OBJECT && fd.field_type() != T_ARRAY) { + guarantee(false, "static field %s::%s must be T_OBJECT or T_ARRAY", + ik->external_name(), fd.name()->as_C_string()); + } + oop oop_field = mirror->obj_field(fd.offset()); + if (oop_field == nullptr) { + guarantee(false, "static field %s::%s must not be null", + ik->external_name(), fd.name()->as_C_string()); + } else if (oop_field->klass() != ik && oop_field->klass() != ik->array_klass_or_null()) { + guarantee(false, "static field %s::%s is of the wrong type", + ik->external_name(), fd.name()->as_C_string()); + } + bool success = HeapShared::archive_reachable_objects_from(level, subgraph_info, oop_field); + assert(success, "VM should have exited with unarchivable objects for _level > 1"); + int root_index = HeapShared::append_root(oop_field); + log_info(cds, heap)("Archived enum obj @%d %s::%s (" INTPTR_FORMAT ")", + root_index, ik->external_name(), fd.name()->as_C_string(), + p2i((oopDesc*)oop_field)); + SystemDictionaryShared::add_enum_klass_static_field(ik, root_index); +} + +bool CDSEnumKlass::initialize_enum_klass(InstanceKlass* k, TRAPS) { + if (!ArchiveHeapLoader::is_in_use()) { + return false; + } + + RunTimeClassInfo* info = RunTimeClassInfo::get_for(k); + assert(info != nullptr, "sanity"); + + if (log_is_enabled(Info, cds, heap)) { + ResourceMark rm; + log_info(cds, heap)("Initializing Enum class: %s", k->external_name()); + } + + oop mirror = k->java_mirror(); + int i = 0; + for (JavaFieldStream fs(k); !fs.done(); fs.next()) { + if (fs.access_flags().is_static()) { + int root_index = info->enum_klass_static_field_root_index_at(i++); + fieldDescriptor& fd = fs.field_descriptor(); + assert(fd.field_type() == T_OBJECT || fd.field_type() == T_ARRAY, "must be"); + mirror->obj_field_put(fd.offset(), HeapShared::get_root(root_index, /*clear=*/true)); + } + } + return true; +} +#endif // INCLUDE_CDS_JAVA_HEAP diff --git a/src/hotspot/share/cds/cdsEnumKlass.hpp b/src/hotspot/share/cds/cdsEnumKlass.hpp new file mode 100644 index 00000000000..c898bfec60d --- /dev/null +++ b/src/hotspot/share/cds/cdsEnumKlass.hpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + * + */ + +#ifndef SHARE_CDS_CDSENUMKLASS_HPP +#define SHARE_CDS_CDSENUMKLASS_HPP + +#include "memory/allStatic.hpp" +#include "oops/oop.hpp" +#include "utilities/exceptions.hpp" +#include "utilities/macros.hpp" + +class InstanceKlass; +class JavaFieldStream; +class KlassSubGraphInfo; + +class CDSEnumKlass: AllStatic { +public: + static bool is_enum_obj(oop orig_obj); + static void handle_enum_obj(int level, + KlassSubGraphInfo* subgraph_info, + oop orig_obj); + static bool initialize_enum_klass(InstanceKlass* k, TRAPS) NOT_CDS_JAVA_HEAP_RETURN_(false); + +private: + static void archive_static_field(int level, KlassSubGraphInfo* subgraph_info, + InstanceKlass* ik, oop mirror, JavaFieldStream& fs); +}; + +#endif // SHARE_CDS_CDSENUMKLASS_HPP diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index 7b519a57d57..ff84ddc13fc 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -28,6 +28,7 @@ #include "cds/archiveHeapWriter.hpp" #include "cds/archiveUtils.hpp" #include "cds/cdsConfig.hpp" +#include "cds/cdsEnumKlass.hpp" #include "cds/cdsHeapVerifier.hpp" #include "cds/heapShared.hpp" #include "cds/metaspaceShared.hpp" @@ -451,95 +452,6 @@ void HeapShared::set_has_native_pointers(oop src_obj) { info->set_has_native_pointers(); } -// -- Handling of Enum objects -// Java Enum classes have synthetic methods that look like this -// enum MyEnum {FOO, BAR} -// MyEnum:: { -// /*static final MyEnum*/ MyEnum::FOO = new MyEnum("FOO"); -// /*static final MyEnum*/ MyEnum::BAR = new MyEnum("BAR"); -// } -// -// If MyEnum::FOO object is referenced by any of the archived subgraphs, we must -// ensure the archived value equals (in object address) to the runtime value of -// MyEnum::FOO. -// -// However, since MyEnum:: is synthetically generated by javac, there's -// no way of programmatically handling this inside the Java code (as you would handle -// ModuleLayer::EMPTY_LAYER, for example). -// -// Instead, we archive all static field of such Enum classes. At runtime, -// HeapShared::initialize_enum_klass() will skip the method and pull -// the static fields out of the archived heap. -void HeapShared::check_enum_obj(int level, - KlassSubGraphInfo* subgraph_info, - oop orig_obj) { - assert(level > 1, "must never be called at the first (outermost) level"); - Klass* k = orig_obj->klass(); - Klass* buffered_k = ArchiveBuilder::get_buffered_klass(k); - if (!k->is_instance_klass()) { - return; - } - InstanceKlass* ik = InstanceKlass::cast(k); - if (ik->java_super() == vmClasses::Enum_klass() && !ik->has_archived_enum_objs()) { - ResourceMark rm; - ik->set_has_archived_enum_objs(); - buffered_k->set_has_archived_enum_objs(); - oop mirror = ik->java_mirror(); - - for (JavaFieldStream fs(ik); !fs.done(); fs.next()) { - if (fs.access_flags().is_static()) { - fieldDescriptor& fd = fs.field_descriptor(); - if (fd.field_type() != T_OBJECT && fd.field_type() != T_ARRAY) { - guarantee(false, "static field %s::%s must be T_OBJECT or T_ARRAY", - ik->external_name(), fd.name()->as_C_string()); - } - oop oop_field = mirror->obj_field(fd.offset()); - if (oop_field == nullptr) { - guarantee(false, "static field %s::%s must not be null", - ik->external_name(), fd.name()->as_C_string()); - } else if (oop_field->klass() != ik && oop_field->klass() != ik->array_klass_or_null()) { - guarantee(false, "static field %s::%s is of the wrong type", - ik->external_name(), fd.name()->as_C_string()); - } - bool success = archive_reachable_objects_from(level, subgraph_info, oop_field); - assert(success, "VM should have exited with unarchivable objects for _level > 1"); - int root_index = append_root(oop_field); - log_info(cds, heap)("Archived enum obj @%d %s::%s (" INTPTR_FORMAT ")", - root_index, ik->external_name(), fd.name()->as_C_string(), - p2i((oopDesc*)oop_field)); - SystemDictionaryShared::add_enum_klass_static_field(ik, root_index); - } - } - } -} - -// See comments in HeapShared::check_enum_obj() -bool HeapShared::initialize_enum_klass(InstanceKlass* k, TRAPS) { - if (!ArchiveHeapLoader::is_in_use()) { - return false; - } - - RunTimeClassInfo* info = RunTimeClassInfo::get_for(k); - assert(info != nullptr, "sanity"); - - if (log_is_enabled(Info, cds, heap)) { - ResourceMark rm; - log_info(cds, heap)("Initializing Enum class: %s", k->external_name()); - } - - oop mirror = k->java_mirror(); - int i = 0; - for (JavaFieldStream fs(k); !fs.done(); fs.next()) { - if (fs.access_flags().is_static()) { - int root_index = info->enum_klass_static_field_root_index_at(i++); - fieldDescriptor& fd = fs.field_descriptor(); - assert(fd.field_type() == T_OBJECT || fd.field_type() == T_ARRAY, "must be"); - mirror->obj_field_put(fd.offset(), get_root(root_index, /*clear=*/true)); - } - } - return true; -} - void HeapShared::archive_objects(ArchiveHeapInfo *heap_info) { { NoSafepointVerifier nsv; @@ -1241,7 +1153,9 @@ bool HeapShared::archive_reachable_objects_from(int level, WalkOopAndArchiveClosure walker(level, record_klasses_only, subgraph_info, orig_obj); orig_obj->oop_iterate(&walker); - check_enum_obj(level + 1, subgraph_info, orig_obj); + if (CDSEnumKlass::is_enum_obj(orig_obj)) { + CDSEnumKlass::handle_enum_obj(level + 1, subgraph_info, orig_obj); + } return true; } diff --git a/src/hotspot/share/cds/heapShared.hpp b/src/hotspot/share/cds/heapShared.hpp index aa8c1dd3bc4..fa34289a38e 100644 --- a/src/hotspot/share/cds/heapShared.hpp +++ b/src/hotspot/share/cds/heapShared.hpp @@ -212,9 +212,6 @@ class HeapShared: AllStatic { }; private: - static void check_enum_obj(int level, KlassSubGraphInfo* subgraph_info, - oop orig_obj); - static const int INITIAL_TABLE_SIZE = 15889; // prime number static const int MAX_TABLE_SIZE = 1000000; typedef ResizeableResourceHashtable Date: Tue, 9 Jul 2024 08:10:55 +0000 Subject: [PATCH 019/460] 8335955: JDK-8335742 wrongly used a "JDK-" prefix in the problemlist bug number Reviewed-by: iwalulya --- test/hotspot/jtreg/ProblemList-Virtual.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/ProblemList-Virtual.txt b/test/hotspot/jtreg/ProblemList-Virtual.txt index ac35f60e661..06110ddcbc1 100644 --- a/test/hotspot/jtreg/ProblemList-Virtual.txt +++ b/test/hotspot/jtreg/ProblemList-Virtual.txt @@ -89,7 +89,7 @@ vmTestbase/nsk/jdi/VMOutOfMemoryException/VMOutOfMemoryException001/VMOutOfMemor ### # Fails on Windows because of additional memory allocation. -gc/g1/TestMixedGCLiveThreshold.java#25percent JDK-8334759 windows-x64 +gc/g1/TestMixedGCLiveThreshold.java#25percent 8334759 windows-x64 ########## ## Tests incompatible with with virtual test thread factory. From 2a2964759c73b3b9ab6afaad109383c89952977b Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Tue, 9 Jul 2024 08:25:00 +0000 Subject: [PATCH 020/460] 8334777: Test javax/management/remote/mandatory/notif/NotifReconnectDeadlockTest.java failed with NullPointerException Reviewed-by: cjplummer, dholmes --- .../remote/mandatory/notif/NotifReconnectDeadlockTest.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/jdk/javax/management/remote/mandatory/notif/NotifReconnectDeadlockTest.java b/test/jdk/javax/management/remote/mandatory/notif/NotifReconnectDeadlockTest.java index 72ae5766307..8f8ef54eade 100644 --- a/test/jdk/javax/management/remote/mandatory/notif/NotifReconnectDeadlockTest.java +++ b/test/jdk/javax/management/remote/mandatory/notif/NotifReconnectDeadlockTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,9 @@ * @bug 6199899 * @summary Tests reconnection done by a fetching notif thread. * @author Shanliang JIANG + * @requires vm.compMode != "Xcomp" + * @comment Running with -Xcomp is likely to cause a timeout from ServerCommunicatorAdmin + * before addNotificationListener can complete. * * @run clean NotifReconnectDeadlockTest * @run build NotifReconnectDeadlockTest From 8f62f31dff564289a2422d58e8ecd5062d443b81 Mon Sep 17 00:00:00 2001 From: Amit Kumar Date: Tue, 9 Jul 2024 08:26:25 +0000 Subject: [PATCH 021/460] 8335906: [s390x] Test Failure: GTestWrapper.java Reviewed-by: stuefe --- src/hotspot/share/runtime/os.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 7b766707b0d..490a04aa6f1 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -959,7 +959,7 @@ static void print_ascii_form(stringStream& ascii_form, uint64_t value, int units uint8_t c[sizeof(v)]; } u = { value }; for (int i = 0; i < unitsize; i++) { - const int idx = LITTLE_ENDIAN_ONLY(i) BIG_ENDIAN_ONLY(sizeof(u.v) - 1 - i); + const int idx = LITTLE_ENDIAN_ONLY(i) BIG_ENDIAN_ONLY(sizeof(u.v) - unitsize + i); const uint8_t c = u.c[idx]; ascii_form.put(isprint(c) && isascii(c) ? c : '.'); } From f3ff4f7427c3c3f5cb2a115a61462bb9d28de1cd Mon Sep 17 00:00:00 2001 From: Severin Gehwolf Date: Tue, 9 Jul 2024 10:21:47 +0000 Subject: [PATCH 022/460] 8335882: platform/cgroup/TestSystemSettings.java fails on Alpine Linux Reviewed-by: stuefe, mbaesken --- test/jdk/jdk/internal/platform/cgroup/TestSystemSettings.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/jdk/internal/platform/cgroup/TestSystemSettings.java b/test/jdk/jdk/internal/platform/cgroup/TestSystemSettings.java index 8d9279e1603..0e668b1f969 100644 --- a/test/jdk/jdk/internal/platform/cgroup/TestSystemSettings.java +++ b/test/jdk/jdk/internal/platform/cgroup/TestSystemSettings.java @@ -24,7 +24,7 @@ /* * @test * @key cgroups - * @requires os.family == "linux" + * @requires (os.family == "linux" & !vm.musl) * @requires vm.flagless * @library /test/lib * @build TestSystemSettings From 0e0dfca21f64ecfcb3e5ed7cdc2a173834faa509 Mon Sep 17 00:00:00 2001 From: Aleksei Voitylov Date: Tue, 9 Jul 2024 10:27:44 +0000 Subject: [PATCH 023/460] 8330806: test/hotspot/jtreg/compiler/c1/TestLargeMonitorOffset.java fails on ARM32 Reviewed-by: snazarki, dsamersoff --- src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp index 688790f07e5..999f8fe5904 100644 --- a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp @@ -152,8 +152,14 @@ void LIR_Assembler::osr_entry() { int monitor_offset = (method()->max_locals() + 2 * (number_of_locks - 1)) * BytesPerWord; for (int i = 0; i < number_of_locks; i++) { int slot_offset = monitor_offset - (i * 2 * BytesPerWord); - __ ldr(R1, Address(OSR_buf, slot_offset + 0*BytesPerWord)); - __ ldr(R2, Address(OSR_buf, slot_offset + 1*BytesPerWord)); + if (slot_offset >= 4096 - BytesPerWord) { + __ add_slow(R2, OSR_buf, slot_offset); + __ ldr(R1, Address(R2, 0*BytesPerWord)); + __ ldr(R2, Address(R2, 1*BytesPerWord)); + } else { + __ ldr(R1, Address(OSR_buf, slot_offset + 0*BytesPerWord)); + __ ldr(R2, Address(OSR_buf, slot_offset + 1*BytesPerWord)); + } __ str(R1, frame_map()->address_for_monitor_lock(i)); __ str(R2, frame_map()->address_for_monitor_object(i)); } From 531a6d85b00b88688668ab1ced0db6ce0214a5f1 Mon Sep 17 00:00:00 2001 From: Volker Simonis Date: Tue, 9 Jul 2024 13:11:07 +0000 Subject: [PATCH 024/460] 8335911: Document ccls indexer in doc/ide.md Reviewed-by: erikj --- doc/ide.html | 11 ++++++----- doc/ide.md | 3 ++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/doc/ide.html b/doc/ide.html index 0dd16b7b9e6..ef6f434013e 100644 --- a/doc/ide.html +++ b/doc/ide.html @@ -63,11 +63,12 @@
Alternative indexers

The main vscode-project target configures the default C++ support in Visual Studio Code. There are also other source indexers that can be installed, that may provide additional features. It's -currently possible to generate configuration for two such indexers, clangd and rtags. These can be -configured by appending the name of the indexer to the make target, such -as:

+currently possible to generate configuration for three such indexers, clangd, ccls +and rtags. These can +be configured by appending the name of the indexer to the make target, +such as:

make vscode-project-clangd

Additional instructions for configuring the given indexer will be displayed after the workspace has been generated.

diff --git a/doc/ide.md b/doc/ide.md index 40e3430a438..d6ebb7b742a 100644 --- a/doc/ide.md +++ b/doc/ide.md @@ -32,7 +32,8 @@ choose `File -> Open Workspace...` in Visual Studio Code. The main `vscode-project` target configures the default C++ support in Visual Studio Code. There are also other source indexers that can be installed, that may provide additional features. It's currently possible to generate -configuration for two such indexers, [clangd](https://clang.llvm.org/extra/clangd/) +configuration for three such indexers, [clangd](https://clang.llvm.org/extra/clangd/), +[ccls](https://github.com/MaskRay/ccls/wiki/Visual-Studio-Code) and [rtags](https://github.com/Andersbakken/rtags). These can be configured by appending the name of the indexer to the make target, such as: From 7e11fb702696df733ca89d325200f2e9414402d9 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 9 Jul 2024 13:11:20 +0000 Subject: [PATCH 025/460] 8335688: Fix -Wzero-as-null-pointer-constant warnings from fflush calls in jvmti tests Reviewed-by: jwaters, coleenp --- .../libAddModuleUsesAndProvidesTest.c | 6 +- .../GenerateEvents/libGenerateEvents1.cpp | 2 +- .../GenerateEvents/libGenerateEvents2.cpp | 4 +- .../FilteredFields/libFilteredFieldsTest.cpp | 4 +- .../libMissedStackMapFrames.cpp | 2 +- .../libRedefineRetransform.cpp | 2 +- .../FramePop/framepop02/libframepop02.cpp | 4 +- .../thread/GetStackTrace/get_stack_trace.hpp | 2 +- .../SuspendResume1/libSuspendResume1.cpp | 6 +- .../getclfld007/getclfld007.cpp | 6 +- .../followref001/followref001.cpp | 58 ++++++++-------- .../followref002/followref002.cpp | 62 ++++++++--------- .../followref003/followref003.cpp | 68 +++++++++---------- .../followref004/followref004.cpp | 12 ++-- .../followref005/followref005.cpp | 2 +- .../followref006/followref006.cpp | 2 +- .../earlyretbase/earlyretbase.cpp | 12 ++-- .../earlyretfp/earlyretfp.cpp | 18 ++--- .../earlyretint/earlyretint.cpp | 14 ++-- .../earlyretlong/earlyretlong.cpp | 14 ++-- .../earlyretobj/earlyretobj.cpp | 14 ++-- .../earlyretstr/earlyretstr.cpp | 12 ++-- .../earlyretvoid/earlyretvoid.cpp | 12 ++-- .../getallstktr001/getallstktr001.cpp | 6 +- .../getcpool001/getcpool001.cpp | 6 +- 25 files changed, 175 insertions(+), 175 deletions(-) diff --git a/test/hotspot/jtreg/serviceability/jvmti/AddModuleUsesAndProvides/libAddModuleUsesAndProvidesTest.c b/test/hotspot/jtreg/serviceability/jvmti/AddModuleUsesAndProvides/libAddModuleUsesAndProvidesTest.c index 86f9993c703..a979d1f913e 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/AddModuleUsesAndProvides/libAddModuleUsesAndProvidesTest.c +++ b/test/hotspot/jtreg/serviceability/jvmti/AddModuleUsesAndProvides/libAddModuleUsesAndProvidesTest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -200,7 +200,7 @@ Java_MyPackage_AddModuleUsesAndProvidesTest_checkUses(JNIEnv *env, throw_exc(env, "Check #UC3: service can not be used unexpectedly"); return FAILED; } - fflush(0); + fflush(NULL); return PASSED; } @@ -275,7 +275,7 @@ Java_MyPackage_AddModuleUsesAndProvidesTest_checkProvides(JNIEnv *env, throw_exc(env, "Check #PC2: error in add provides to baseModule with correct service and serviceImpl"); return FAILED; } - fflush(0); + fflush(NULL); return PASSED; } diff --git a/test/hotspot/jtreg/serviceability/jvmti/GenerateEvents/libGenerateEvents1.cpp b/test/hotspot/jtreg/serviceability/jvmti/GenerateEvents/libGenerateEvents1.cpp index fa60c07f8db..0f040175bf9 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/GenerateEvents/libGenerateEvents1.cpp +++ b/test/hotspot/jtreg/serviceability/jvmti/GenerateEvents/libGenerateEvents1.cpp @@ -71,7 +71,7 @@ CompiledMethodLoad(jvmtiEnv* jvmti, jmethodID method, check_jvmti_status(env, err, "CompiledMethodLoad: Error in JVMTI GetMethodName"); printf("%s: CompiledMethodLoad: %s%s\n", AGENT_NAME, name, sign); - fflush(0); + fflush(nullptr); } JNIEXPORT jint JNICALL diff --git a/test/hotspot/jtreg/serviceability/jvmti/GenerateEvents/libGenerateEvents2.cpp b/test/hotspot/jtreg/serviceability/jvmti/GenerateEvents/libGenerateEvents2.cpp index 7af061196a1..d582a964892 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/GenerateEvents/libGenerateEvents2.cpp +++ b/test/hotspot/jtreg/serviceability/jvmti/GenerateEvents/libGenerateEvents2.cpp @@ -71,7 +71,7 @@ CompiledMethodLoad(jvmtiEnv* jvmti, jmethodID method, check_jvmti_status(env, err, "CompiledMethodLoad: Error in JVMTI GetMethodName"); printf("%s: CompiledMethodLoad: %s%s\n", AGENT_NAME, name, sign); - fflush(0); + fflush(nullptr); } JNIEXPORT jint JNICALL @@ -132,7 +132,7 @@ Java_MyPackage_GenerateEventsTest_agent2FailStatus(JNIEnv *env, jclass cls) { printf("check2: Unexpected non-zero event count in agent2: %d\n", agent2_event_count); } printf("\n"); - fflush(0); + fflush(nullptr); return fail_status; } diff --git a/test/hotspot/jtreg/serviceability/jvmti/GetClassFields/FilteredFields/libFilteredFieldsTest.cpp b/test/hotspot/jtreg/serviceability/jvmti/GetClassFields/FilteredFields/libFilteredFieldsTest.cpp index 28bfaaa03bd..fbefb1219e6 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/GetClassFields/FilteredFields/libFilteredFieldsTest.cpp +++ b/test/hotspot/jtreg/serviceability/jvmti/GetClassFields/FilteredFields/libFilteredFieldsTest.cpp @@ -35,7 +35,7 @@ jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { jint res = jvm->GetEnv((void **)&jvmti, JVMTI_VERSION_1_1); if (res != JNI_OK || jvmti == nullptr) { printf("Wrong result of a valid call to GetEnv!\n"); - fflush(0); + fflush(nullptr); return JNI_ERR; } return JNI_OK; @@ -72,7 +72,7 @@ Java_FilteredFieldsTest_getJVMTIFieldCount(JNIEnv *env, jclass cls, jclass clazz printf(" [%d]: %s\n", i, name); jvmti->Deallocate((unsigned char *)name); } - fflush(0); + fflush(nullptr); return fcount; } diff --git a/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/MissedStackMapFrames/libMissedStackMapFrames.cpp b/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/MissedStackMapFrames/libMissedStackMapFrames.cpp index 5cebf608c34..066794d1d60 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/MissedStackMapFrames/libMissedStackMapFrames.cpp +++ b/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/MissedStackMapFrames/libMissedStackMapFrames.cpp @@ -31,7 +31,7 @@ static void _log(const char* format, ...) { va_start(args, format); vprintf(format, args); va_end(args); - fflush(0); + fflush(nullptr); } static jvmtiEnv* jvmti = nullptr; diff --git a/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/RedefineRetransform/libRedefineRetransform.cpp b/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/RedefineRetransform/libRedefineRetransform.cpp index 518e147c942..450b0f35918 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/RedefineRetransform/libRedefineRetransform.cpp +++ b/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/RedefineRetransform/libRedefineRetransform.cpp @@ -36,7 +36,7 @@ static void _log(const char* format, ...) { va_start(args, format); vprintf(format, args); va_end(args); - fflush(0); + fflush(nullptr); } static bool isTestClass(const char* name) { diff --git a/test/hotspot/jtreg/serviceability/jvmti/events/FramePop/framepop02/libframepop02.cpp b/test/hotspot/jtreg/serviceability/jvmti/events/FramePop/framepop02/libframepop02.cpp index 61c9a91184b..93df7f98277 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/events/FramePop/framepop02/libframepop02.cpp +++ b/test/hotspot/jtreg/serviceability/jvmti/events/FramePop/framepop02/libframepop02.cpp @@ -194,7 +194,7 @@ void JNICALL MethodEntry(jvmtiEnv *jvmti, JNIEnv *jni, { if (printdump == JNI_TRUE) { print_current_time(); - fflush(0); + fflush(nullptr); LOG(">>> %sMethod entry\n>>>", (isNative == JNI_TRUE) ? "Native " : ""); printInfo(jni, jvmti, thr, method, frameCount); } @@ -231,7 +231,7 @@ void JNICALL FramePop(jvmtiEnv *jvmti, JNIEnv *jni, { if (printdump == JNI_TRUE) { print_current_time(); - fflush(0); + fflush(nullptr); LOG(" >>> Frame Pop\n>>>"); printInfo(jni, jvmti, thr, method, frameCount); } diff --git a/test/hotspot/jtreg/serviceability/jvmti/thread/GetStackTrace/get_stack_trace.hpp b/test/hotspot/jtreg/serviceability/jvmti/thread/GetStackTrace/get_stack_trace.hpp index d7c85704275..b8828b0e80f 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/thread/GetStackTrace/get_stack_trace.hpp +++ b/test/hotspot/jtreg/serviceability/jvmti/thread/GetStackTrace/get_stack_trace.hpp @@ -70,7 +70,7 @@ int compare_stack_trace(jvmtiEnv *jvmti, JNIEnv *jni, jthread thread, int exp_idx = expected_frames_length - 1 - i; printf("expected idx %d\n", exp_idx); - fflush(0); + fflush(nullptr); if (i < expected_frames_length) { // for generated classes don't compare lambda indicies diff --git a/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendResume1/libSuspendResume1.cpp b/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendResume1/libSuspendResume1.cpp index f05e619e0bd..93ad399b121 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendResume1/libSuspendResume1.cpp +++ b/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendResume1/libSuspendResume1.cpp @@ -138,7 +138,7 @@ check_suspended_state(JNIEnv* jni, jthread thread, int thr_idx, char* tname, con LOG("## Agent: %s: virtual thread of carrier thread has state: %s (%d)\n", func_name, TranslateState(state), (int)state); - fflush(0); + fflush(nullptr); } set_agent_fail_status(); fatal(jni, "check_resumed_state: expected SUSPENDED flag in thread state"); @@ -169,7 +169,7 @@ check_resumed_state(JNIEnv* jni, jthread thread, int thr_idx, char* tname, const LOG("## Agent: %s: virtual thread of carrier thread has state: %s (%d)\n", func_name, TranslateState(state), (int)state); - fflush(0); + fflush(nullptr); } set_agent_fail_status(); fatal(jni, "check_resumed_state: NOT expected SUSPENDED flag in thread state"); @@ -210,7 +210,7 @@ test_thread_resume(JNIEnv* jni, jthread thread, int thr_idx, char* tname) { LOG("## Agent: test_thread_resume: virtual thread of carrier thread has state: %s (%d)\n", TranslateState(state), (int)state); - fflush(0); + fflush(nullptr); } check_jvmti_status(jni, err, "test_thread_resume: error in JVMTI ResumeThread"); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007/getclfld007.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007/getclfld007.cpp index 3cd33384330..89a62346ca9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007/getclfld007.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007/getclfld007.cpp @@ -86,7 +86,7 @@ Java_nsk_jvmti_GetClassFields_getclfld007_check(JNIEnv *env, jclass cls, jclass if (jvmti == nullptr) { printf("JVMTI client was not properly loaded!\n"); - fflush(0); + fflush(nullptr); result = STATUS_FAILED; return; } @@ -98,7 +98,7 @@ Java_nsk_jvmti_GetClassFields_getclfld007_check(JNIEnv *env, jclass cls, jclass if (err != JVMTI_ERROR_NONE) { printf("GetClassFields unexpected error: %s (%d)\n", TranslateError(err), err); - fflush(0); + fflush(nullptr); result = STATUS_FAILED; return; } @@ -132,7 +132,7 @@ Java_nsk_jvmti_GetClassFields_getclfld007_check(JNIEnv *env, jclass cls, jclass jvmti->Deallocate((unsigned char *)name); jvmti->Deallocate((unsigned char *)sig); } - fflush(0); + fflush(nullptr); } JNIEXPORT int JNICALL diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref001/followref001.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref001/followref001.cpp index ff431aa2203..b33128b4916 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref001/followref001.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref001/followref001.cpp @@ -137,14 +137,14 @@ static bool initObjectDescList(jvmtiEnv* jvmti, *objectsCount = 1 + 2 * chainLength; printf("Allocate memory for objects list: %d objects\n", *objectsCount); - fflush(0); + fflush(nullptr); if (!NSK_JVMTI_VERIFY(jvmti->Allocate((*objectsCount * sizeof(ObjectDesc)), (unsigned char**) objectDescList))) { nsk_jvmti_setFailStatus(); return false; } printf(" ... allocated array: 0x%p\n", (void*)objectDescList); - fflush(0); + fflush(nullptr); { int k; @@ -179,7 +179,7 @@ static bool getAndTagClasses(jvmtiEnv* jvmti, } printf("\nFound debugee class: 0x%p\n %s\n", (void*) *debugeeClass, DEBUGEE_CLASS_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (*rootObjectClass = jni->FindClass(ROOT_OBJECT_CLASS_NAME)) != nullptr)) { @@ -194,7 +194,7 @@ static bool getAndTagClasses(jvmtiEnv* jvmti, printf("\nFound root object class: 0x%p, tag=%ld\n %s\n", (void*) *rootObjectClass,(long) ROOT_CLASS_TAG, ROOT_OBJECT_CLASS_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (*chainObjectClass = @@ -209,7 +209,7 @@ static bool getAndTagClasses(jvmtiEnv* jvmti, printf("\nFound chain object class: 0x%p, tag=%ld\n %s\n", (void*) *chainObjectClass, (long) CHAIN_CLASS_TAG, CHAIN_OBJECT_CLASS_NAME); - fflush(0); + fflush(nullptr); return true; } /* getAndTagClasses */ @@ -234,7 +234,7 @@ static bool getFieldsAndObjects(jvmtiEnv* jvmti, } printf("\nFound fieldID: 0x%p - \'%s\' static field in debugee class\n", (void*) rootObjectField, OBJECT_FIELD_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (*reachableChainField = jni->GetFieldID(rootObjectClass, REACHABLE_CHAIN_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != nullptr)) { @@ -243,7 +243,7 @@ static bool getFieldsAndObjects(jvmtiEnv* jvmti, } printf("\nFound fieldID: 0x%p - \'%s\' field in root object class\n", (void*) reachableChainField, REACHABLE_CHAIN_FIELD_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (*unreachableChainField = jni->GetFieldID(rootObjectClass, UNREACHABLE_CHAIN_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != nullptr)) { @@ -253,7 +253,7 @@ static bool getFieldsAndObjects(jvmtiEnv* jvmti, printf("\nFound fieldID: 0x%p - \'%s\' field in root object class\n", (void*) unreachableChainField, UNREACHABLE_CHAIN_FIELD_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (*nextField = jni->GetFieldID(chainObjectClass, NEXT_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != nullptr)) { @@ -262,7 +262,7 @@ static bool getFieldsAndObjects(jvmtiEnv* jvmti, } printf("\nFound fieldID: 0x%p - \'%s\' field in chain object class\n", (void*) nextField, NEXT_FIELD_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (*rootObjectPtr = jni->GetStaticObjectField(debugeeClass, rootObjectField)) != nullptr)) { @@ -270,14 +270,14 @@ static bool getFieldsAndObjects(jvmtiEnv* jvmti, return false; } printf("\nFound root object: 0x%p\n", (void*) *rootObjectPtr); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (*rootObjectPtr = jni->NewGlobalRef(*rootObjectPtr)) != nullptr)) { nsk_jvmti_setFailStatus(); return false; } printf("Created root object global ref: 0x%p\n", (void*)*rootObjectPtr); - fflush(0); + fflush(nullptr); return true; } /* getFieldsAndObjects */ @@ -318,7 +318,7 @@ static bool getAndTagChainObjects( nsk_jvmti_setFailStatus(); } printf(" tag=%-5ld object=0x%p\n", (long)objTag, (void*)nextObj); - fflush(0); + fflush(nullptr); /* To continue traversing objects in the chain */ if (!getAndTagChainObjects(jvmti, @@ -394,7 +394,7 @@ static int getAndTagTestedObjects( (long) ROOT_OBJECT_TAG, (void*) *rootObjectPtr); printf(" reachable objects chain: %d objects\n", chainLength); - fflush(0); + fflush(nullptr); if (!getAndTagChainObjects(jvmti, jni, @@ -453,7 +453,7 @@ static bool checkTestedObjects(jvmtiEnv* jvmti, } printf("\nReachable objects:\n"); - fflush(0); + fflush(nullptr); for (i = 0; i < chainLength; i++) { idx = i + 1; printf("Reachable object:\n" @@ -488,7 +488,7 @@ static bool checkTestedObjects(jvmtiEnv* jvmti, NSK_COMPLAIN0("Unreachable object was iterated\n"); nsk_jvmti_setFailStatus(); } - fflush(0); + fflush(nullptr); } return true; @@ -514,7 +514,7 @@ static void releaseTestedObjects(jvmtiEnv* jvmti, } } - fflush(0); + fflush(nullptr); } /* releaseTestedObjects */ @@ -542,7 +542,7 @@ jint JNICALL heapReferenceCallback( /* ss45998: class_tag=>referrence_class_tag */ printf(" size: %" LL "d, tag_ptr: 0x%p, referrer_tag_ptr: 0x%p, length: %-d\n", size, tag_ptr, referrer_tag_ptr, length); - fflush(0); + fflush(nullptr); if (((uintptr_t) tag_ptr & FULL_32_BIT_MASK) == FULL_32_BIT_MASK) { NSK_COMPLAIN1("wrong tag_ptr passed to " @@ -567,7 +567,7 @@ jint JNICALL heapReferenceCallback( printf(" class_tag=%" LL "d, tag=%" LL "d, size=%" LL "d," " ref_tag=%" LL "d, referrer_index=%d\n\n", class_tag, tag, size, ref_tag, referrer_index); - fflush(0); + fflush(nullptr); if (length != -1) { NSK_COMPLAIN1("wrong length passed to heapReferenceCallback: " @@ -647,7 +647,7 @@ jint JNICALL heapReferenceCallback( case JVMTI_HEAP_REFERENCE_OTHER: { NSK_COMPLAIN1("This reference kind was not expected: %s\n", ref_kind_str[reference_kind]); - fflush(0); + fflush(nullptr); nsk_jvmti_setFailStatus(); return 0; } @@ -674,7 +674,7 @@ jint JNICALL primitiveFieldCallback( (long) class_tag, (long) DEREF(tag_ptr), (int) value_type); - fflush(0); + fflush(nullptr); return 0; } /* primitiveFieldCallback */ @@ -694,7 +694,7 @@ jint JNICALL arrayPrimitiveValueCallback( (long) DEREF(tag_ptr), (int) element_count, (int) element_type); - fflush(0); + fflush(nullptr); return 0; } /* arrayPrimitiveValueCallback */ @@ -711,7 +711,7 @@ jint JNICALL stringPrimitiveValueCallback( (long) class_tag, (long) DEREF(tag_ptr), (int) value_length); - fflush(0); + fflush(nullptr); return 0; } /* stringPrimitiveValueCallback */ @@ -725,14 +725,14 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { jobject rootObject = nullptr; printf("Wait for tested objects created\n"); - fflush(0); + fflush(nullptr); if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout))) { return; } printf(">>> Obtain and tag tested objects from debugee class\n"); - fflush(0); + fflush(nullptr); if (!NSK_VERIFY(getAndTagTestedObjects(jvmti, jni, @@ -745,7 +745,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf(">>> Let debugee to clean links to unreachable objects\n"); - fflush(0); + fflush(nullptr); if (!NSK_VERIFY(nsk_jvmti_resumeSync())) { return; @@ -755,7 +755,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf(">>> Start iteration from root tested object: 0x%p\n\n", rootObject); - fflush(0); + fflush(nullptr); if (!NSK_JVMTI_VERIFY(jvmti->FollowReferences((jint) 0, /* heap_filter */ (jclass) nullptr, /* class */ @@ -767,19 +767,19 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf(">>> Check if reachable objects were iterated:\n"); - fflush(0); + fflush(nullptr); if (!checkTestedObjects(jvmti, jni, chainLength, objectDescList)) { nsk_jvmti_setFailStatus(); } printf(">>> Clean used data\n"); - fflush(0); + fflush(nullptr); releaseTestedObjects(jvmti, jni, chainLength, objectDescList, rootObject); printf(">>> Let debugee to finish\n"); - fflush(0); + fflush(nullptr); if (!NSK_VERIFY(nsk_jvmti_resumeSync())) { return; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref002/followref002.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref002/followref002.cpp index 6366b430776..9ea3a5d0d01 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref002/followref002.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref002/followref002.cpp @@ -131,7 +131,7 @@ static int getAndTagChainObjects( nsk_jvmti_setFailStatus(); } printf(" tag=%-5ld object=0x%p\n", (long)objTag, (void*)obj); - fflush(0); + fflush(nullptr); if (!getAndTagChainObjects(jvmti, jni, obj, nextField, nextFieldName, @@ -170,14 +170,14 @@ static int getAndTagTestedObjects( *objectsCount = 1 + 2 * chainLength; printf("Allocate memory for objects list: %d objects\n", *objectsCount); - fflush(0); + fflush(nullptr); if (!NSK_JVMTI_VERIFY(jvmti->Allocate((*objectsCount * sizeof(ObjectDesc)), (unsigned char**)objectDescList))) { nsk_jvmti_setFailStatus(); return NSK_FALSE; } printf(" ... allocated array: 0x%p\n", (void*)objectDescList); - fflush(0); + fflush(nullptr); { int k; @@ -191,7 +191,7 @@ static int getAndTagTestedObjects( (*objectDescList)[0].exp_class_tag = rootClassTag; printf("Find debugee class: %s\n", DEBUGEE_CLASS_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (debugeeClass = jni->FindClass(DEBUGEE_CLASS_NAME)) != nullptr)) { nsk_jvmti_setFailStatus(); return NSK_FALSE; @@ -199,7 +199,7 @@ static int getAndTagTestedObjects( printf(" ... found class: 0x%p\n", (void*)debugeeClass); printf("Find root object class: %s\n", ROOT_OBJECT_CLASS_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (rootObjectClass = jni->FindClass(ROOT_OBJECT_CLASS_NAME)) != nullptr)) { nsk_jvmti_setFailStatus(); return NSK_FALSE; @@ -212,7 +212,7 @@ static int getAndTagTestedObjects( printf(" tag=%-5ld rootClass=0x%p\n", (long)rootClassTag, (void*)rootObjectClass); printf("Find chain object class: %s\n", CHAIN_OBJECT_CLASS_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (chainObjectClass = jni->FindClass(CHAIN_OBJECT_CLASS_NAME)) != nullptr)) { nsk_jvmti_setFailStatus(); @@ -226,7 +226,7 @@ static int getAndTagTestedObjects( printf(" tag=%-5ld chainClass=0x%p\n", (long)chainClassTag, (void*)chainObjectClass); printf("Find static field in debugee class: %s\n", OBJECT_FIELD_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (objectField = jni->GetStaticFieldID(debugeeClass, OBJECT_FIELD_NAME, ROOT_OBJECT_CLASS_SIG)) != nullptr)) { nsk_jvmti_setFailStatus(); @@ -235,7 +235,7 @@ static int getAndTagTestedObjects( printf(" ... got fieldID: 0x%p\n", (void*)objectField); printf("Find instance field in root object class: %s\n", REACHABLE_CHAIN_FIELD_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (reachableChainField = jni->GetFieldID(rootObjectClass, REACHABLE_CHAIN_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != nullptr)) { nsk_jvmti_setFailStatus(); @@ -244,7 +244,7 @@ static int getAndTagTestedObjects( printf(" ... got fieldID: 0x%p\n", (void*)reachableChainField); printf("Find instance field in root object class: %s\n", UNREACHABLE_CHAIN_FIELD_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (unreachableChainField = jni->GetFieldID(rootObjectClass, UNREACHABLE_CHAIN_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != nullptr)) { nsk_jvmti_setFailStatus(); @@ -253,7 +253,7 @@ static int getAndTagTestedObjects( printf(" ... got fieldID: 0x%p\n", (void*)unreachableChainField); printf("Find instance field in chain object class: %s\n", TAIL_FIELD_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (tailField = jni->GetFieldID(chainObjectClass, TAIL_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != nullptr)) { nsk_jvmti_setFailStatus(); @@ -262,14 +262,14 @@ static int getAndTagTestedObjects( printf(" ... got fieldID: 0x%p\n", (void*)tailField); printf("Get root object from static field: %s\n", OBJECT_FIELD_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (*rootObject = jni->GetStaticObjectField(debugeeClass, objectField)) != nullptr)) { nsk_jvmti_setFailStatus(); return NSK_FALSE; } printf(" ... got object: 0x%p\n", (void*)*rootObject); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (*rootObject = jni->NewGlobalRef(*rootObject)) != nullptr)) { nsk_jvmti_setFailStatus(); @@ -280,7 +280,7 @@ static int getAndTagTestedObjects( printf("Obtain and tag chain objects:\n"); printf(" root tested object:\n"); - fflush(0); + fflush(nullptr); if (!NSK_JVMTI_VERIFY(jvmti->SetTag(*rootObject, rootObjectTag))) { nsk_jvmti_setFailStatus(); } @@ -295,7 +295,7 @@ static int getAndTagTestedObjects( (*objectDescList)[chainLength].exp_found = 1; printf(" reachable objects chain: %d objects\n", chainLength); - fflush(0); + fflush(nullptr); if (!getAndTagChainObjects(jvmti, jni, *rootObject, reachableChainField, REACHABLE_CHAIN_FIELD_NAME, @@ -348,7 +348,7 @@ static int checkTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, } printf("\nReachable objects:\n"); - fflush(0); + fflush(nullptr); for (i = 0; i < chainLength; i++) { idx = i + 1; printf("Reachable object:\n" @@ -383,7 +383,7 @@ static int checkTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, NSK_COMPLAIN0("Unreachable object was iterated\n"); nsk_jvmti_setFailStatus(); } - fflush(0); + fflush(nullptr); } return NSK_TRUE; @@ -404,7 +404,7 @@ static int releaseTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength, } } - fflush(0); + fflush(nullptr); return NSK_TRUE; } /* releaseTestedObjects */ @@ -456,7 +456,7 @@ jint JNICALL heapReferenceCallback( (long) size, (long) ref_tag, (int) referrer_index); - fflush(0); + fflush(nullptr); if (tag_ptr == nullptr) { NSK_COMPLAIN1("null tag_ptr is passed to heapReferenceCallback:" @@ -531,7 +531,7 @@ jint JNICALL heapReferenceCallback( case JVMTI_HEAP_REFERENCE_OTHER: { NSK_COMPLAIN1("This reference kind was not expected: %s\n", ref_kind_str[reference_kind]); - fflush(0); + fflush(nullptr); nsk_jvmti_setFailStatus(); return 0; } @@ -556,7 +556,7 @@ jint JNICALL primitiveFieldCallback( (long) class_tag, (long) DEREF(tag_ptr), (int) value_type); - fflush(0); + fflush(nullptr); return 0; } @@ -574,7 +574,7 @@ jint JNICALL arrayPrimitiveValueCallback( (long) DEREF(tag_ptr), (int) element_count, (int) element_type); - fflush(0); + fflush(nullptr); return 0; } @@ -590,7 +590,7 @@ jint JNICALL stringPrimitiveValueCallback( (long) class_tag, (long) DEREF(tag_ptr), (int) value_length); - fflush(0); + fflush(nullptr); return 0; } @@ -602,13 +602,13 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { jobject rootObject = nullptr; printf("Wait for tested objects created\n"); - fflush(0); + fflush(nullptr); if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout))) { return; } printf(">>> Obtain and tag tested objects from debugee class\n"); - fflush(0); + fflush(nullptr); { if (!NSK_VERIFY(getAndTagTestedObjects(jvmti, jni, chainLength, &objectsCount, @@ -618,7 +618,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf(">>> Let debugee to clean links to unreachable objects\n"); - fflush(0); + fflush(nullptr); { if (!NSK_VERIFY(nsk_jvmti_resumeSync())) { return; @@ -629,7 +629,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf("\n\n>>> Start 1-st iteration for root tested object: 0x%p\n", rootObject); - fflush(0); + fflush(nullptr); { jint heap_filter = JVMTI_HEAP_FILTER_UNTAGGED | JVMTI_HEAP_FILTER_CLASS_UNTAGGED; if (!NSK_JVMTI_VERIFY(jvmti->FollowReferences(heap_filter, @@ -643,7 +643,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf(">>> Check if reachable objects were iterated\n"); - fflush(0); + fflush(nullptr); { if (!checkTestedObjects(jvmti, jni, chainLength, objectDescList)) { nsk_jvmti_setFailStatus(); @@ -660,7 +660,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf("\n\n>>> Start 2-nd iteration for root tested object: 0x%p\n", rootObject); - fflush(0); + fflush(nullptr); { /* This time everythig is filtered out */ jint heap_filter = JVMTI_HEAP_FILTER_UNTAGGED | JVMTI_HEAP_FILTER_CLASS_UNTAGGED | @@ -676,7 +676,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf(">>> Check if reachable objects were not reported this time\n"); - fflush(0); + fflush(nullptr); { if (!checkTestedObjects(jvmti, jni, chainLength, objectDescList)) { nsk_jvmti_setFailStatus(); @@ -684,7 +684,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf(">>> Clean used data\n"); - fflush(0); + fflush(nullptr); { if (!NSK_VERIFY(releaseTestedObjects(jvmti, jni, chainLength, objectDescList, rootObject))) { return; @@ -692,7 +692,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf("Let debugee to finish\n"); - fflush(0); + fflush(nullptr); if (!NSK_VERIFY(nsk_jvmti_resumeSync())) return; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref003/followref003.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref003/followref003.cpp index cb0385ee653..80cbf856f45 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref003/followref003.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref003/followref003.cpp @@ -146,7 +146,7 @@ static int getChainObjects(jvmtiEnv* jvmti, JNIEnv* jni, jobject firstObject, nsk_jvmti_setFailStatus(); } printf(" tag=%-5ld object=0x%p\n", (long)objTag, (void*)obj); - fflush(0); + fflush(nullptr); if (!getChainObjects(jvmti, jni, obj, nextField, nextFieldName, nextField, nextFieldName, count, objectDescList, tag, reachable)) { @@ -173,14 +173,14 @@ static int getTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength, *objectsCount = 1 + 2 * chainLength; printf("Allocate memory for objects list: %d objects\n", *objectsCount); - fflush(0); + fflush(nullptr); if (!NSK_JVMTI_VERIFY(jvmti->Allocate((*objectsCount * sizeof(ObjectDesc)), (unsigned char**)objectDescList))) { nsk_jvmti_setFailStatus(); return NSK_FALSE; } printf(" ... allocated array: 0x%p\n", (void*)objectDescList); - fflush(0); + fflush(nullptr); { int k; @@ -194,7 +194,7 @@ static int getTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength, (*objectDescList)[0].exp_class_tag = rootClassTag; printf("Find debugee class: %s\n", DEBUGEE_CLASS_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (debugeeClass = jni->FindClass(DEBUGEE_CLASS_NAME)) != nullptr)) { nsk_jvmti_setFailStatus(); return NSK_FALSE; @@ -202,7 +202,7 @@ static int getTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength, printf(" ... found class: 0x%p\n", (void*)debugeeClass); printf("Find root object class: %s\n", ROOT_OBJECT_CLASS_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (rootObjectClass = jni->FindClass(ROOT_OBJECT_CLASS_NAME)) != nullptr)) { nsk_jvmti_setFailStatus(); return NSK_FALSE; @@ -216,7 +216,7 @@ static int getTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength, (long)rootClassTag, (void*)rootObjectClass); printf("Find chain object class: %s\n", CHAIN_OBJECT_CLASS_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (chainObjectClass = jni->FindClass(CHAIN_OBJECT_CLASS_NAME)) != nullptr)) { nsk_jvmti_setFailStatus(); @@ -232,7 +232,7 @@ static int getTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength, (long)chainClassTag, (void*)chainObjectClass); printf("Find static field in debugee class: %s\n", OBJECT_FIELD_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (objectField = jni->GetStaticFieldID(debugeeClass, OBJECT_FIELD_NAME, ROOT_OBJECT_CLASS_SIG)) != nullptr)) { nsk_jvmti_setFailStatus(); @@ -241,7 +241,7 @@ static int getTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength, printf(" ... got fieldID: 0x%p\n", (void*)objectField); printf("Find instance field in root object class: %s\n", REACHABLE_CHAIN_FIELD_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (reachableChainField = jni->GetFieldID(rootObjectClass, REACHABLE_CHAIN_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != nullptr)) { nsk_jvmti_setFailStatus(); @@ -250,7 +250,7 @@ static int getTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength, printf(" ... got fieldID: 0x%p\n", (void*)reachableChainField); printf("Find instance field in root object class: %s\n", UNREACHABLE_CHAIN_FIELD_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (unreachableChainField = jni->GetFieldID(rootObjectClass, UNREACHABLE_CHAIN_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != nullptr)) { nsk_jvmti_setFailStatus(); @@ -259,7 +259,7 @@ static int getTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength, printf(" ... got fieldID: 0x%p\n", (void*)unreachableChainField); printf("Find instance field in chain object class: %s\n", TAIL_FIELD_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (tailField = jni->GetFieldID(chainObjectClass, TAIL_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != nullptr)) { nsk_jvmti_setFailStatus(); @@ -268,14 +268,14 @@ static int getTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength, printf(" ... got fieldID: 0x%p\n", (void*)tailField); printf("Get root object from static field: %s\n", OBJECT_FIELD_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (*rootObject = jni->GetStaticObjectField(debugeeClass, objectField)) != nullptr)) { nsk_jvmti_setFailStatus(); return NSK_FALSE; } printf(" ... got object: 0x%p\n", (void*)*rootObject); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (*rootObject = jni->NewGlobalRef(*rootObject)) != nullptr)) { nsk_jvmti_setFailStatus(); @@ -286,7 +286,7 @@ static int getTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength, printf("Obtain and tag chain objects:\n"); printf(" root tested object\n"); - fflush(0); + fflush(nullptr); if (!NSK_JVMTI_VERIFY(jvmti->SetTag(*rootObject, rootObjectTag))) { nsk_jvmti_setFailStatus(); } @@ -298,7 +298,7 @@ static int getTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength, (*objectDescList)[0].tag = rootObjectTag; printf(" reachable objects chain: %d objects\n", chainLength); - fflush(0); + fflush(nullptr); if (!getChainObjects(jvmti, jni, *rootObject, reachableChainField, REACHABLE_CHAIN_FIELD_NAME, tailField, TAIL_FIELD_NAME, @@ -347,7 +347,7 @@ static int checkTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, } printf("\nReachable objects:\n"); - fflush(0); + fflush(nullptr); for (i = 0; i < chainLength; i++) { idx = i + 1; printf("Reachable object:\n" @@ -382,7 +382,7 @@ static int checkTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, NSK_COMPLAIN0("Unreachable object was iterated\n"); nsk_jvmti_setFailStatus(); } - fflush(0); + fflush(nullptr); } return NSK_TRUE; @@ -403,7 +403,7 @@ static int releaseTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength, } } - fflush(0); + fflush(nullptr); return NSK_TRUE; } @@ -646,7 +646,7 @@ jint JNICALL heapReferenceCallback( (long) size); } - fflush(0); + fflush(nullptr); return 0; } @@ -665,7 +665,7 @@ jint JNICALL heapReferenceCallback( method, (long) location, (int) index); - fflush(0); + fflush(nullptr); if (tag_ptr == nullptr) { NSK_COMPLAIN1("null tag_ptr is passed to heapReferenceCallback:" @@ -748,7 +748,7 @@ jint JNICALL heapReferenceCallback( if (tag != rootObjectTag || class_tag != rootClassTag) { NSK_COMPLAIN1("This reference kind was not expected: %s\n", ref_kind_str[ref_kind]); - fflush(0); + fflush(nullptr); nsk_jvmti_setFailStatus(); } break; @@ -818,7 +818,7 @@ jint JNICALL heapReferenceCallback( default: { NSK_COMPLAIN1("This reference kind was not expected: %s\n\n", ref_kind_str[ref_kind]); - fflush(0); + fflush(nullptr); nsk_jvmti_setFailStatus(); break; } @@ -840,7 +840,7 @@ jint JNICALL primitiveFieldCallback (long) class_tag, (long) DEREF(tag_ptr), (int) value_type); - fflush(0); + fflush(nullptr); return 0; } @@ -853,7 +853,7 @@ jint JNICALL arrayPrimitiveValueCallback (long) DEREF(tag_ptr), (int) element_count, (int) element_type); - fflush(0); + fflush(nullptr); return 0; } @@ -865,7 +865,7 @@ jint JNICALL stringPrimitiveValueCallback (long) class_tag, (long) DEREF(tag_ptr), (int) value_length); - fflush(0); + fflush(nullptr); return 0; } @@ -902,13 +902,13 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { jobject rootObject = nullptr; printf("Wait for tested objects created\n"); - fflush(0); + fflush(nullptr); if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout))) { return; } printf(">>> Obtain and tag tested objects from debugee class\n"); - fflush(0); + fflush(nullptr); { if (!NSK_VERIFY(getTestedObjects(jvmti, jni, chainLength, &objectsCount, &objectDescList, &rootObject))) { @@ -917,7 +917,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf(">>> Let debugee to clean links to unreachable objects\n"); - fflush(0); + fflush(nullptr); { if (!NSK_VERIFY(nsk_jvmti_resumeSync())) { return; @@ -933,7 +933,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf("\n\n>>> Start 1-st iteration starting from the heap root\n"); - fflush(0); + fflush(nullptr); { if (!NSK_JVMTI_VERIFY(jvmti->FollowReferences((jint) 0, /* heap_filter */ (jclass) nullptr, /* class */ @@ -946,7 +946,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf(">>> Check if reachable objects were iterated\n"); - fflush(0); + fflush(nullptr); { if (!checkTestedObjects(jvmti, jni, chainLength, objectDescList)) { nsk_jvmti_setFailStatus(); @@ -968,7 +968,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf("\n\n>>> Start 2-nd iteration starting from the heap root\n"); - fflush(0); + fflush(nullptr); first_followref = 0; { jint heap_filter = JVMTI_HEAP_FILTER_UNTAGGED @@ -985,7 +985,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { printf(">>> Check that both reachable and unreachable " "objects were not iterated\n"); - fflush(0); + fflush(nullptr); { if (!checkTestedObjects(jvmti, jni, chainLength, objectDescList)) { nsk_jvmti_setFailStatus(); @@ -994,7 +994,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { printf(">>> Clean used data\n"); - fflush(0); + fflush(nullptr); { if (!NSK_VERIFY(releaseTestedObjects(jvmti, jni, chainLength, objectDescList, rootObject))) { @@ -1003,7 +1003,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf("Let debugee to finish\n"); - fflush(0); + fflush(nullptr); if (!NSK_VERIFY(nsk_jvmti_resumeSync())) return; } @@ -1047,7 +1047,7 @@ jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { info = INFO_HEAPOBJ; else { printf("Unknown option value: info=%s\n", infoOpt); - fflush(0); + fflush(nullptr); return JNI_ERR; } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref004/followref004.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref004/followref004.cpp index e73534de8b6..2446b5f7caf 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref004/followref004.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref004/followref004.cpp @@ -86,7 +86,7 @@ jint JNICALL primitiveFieldCallback( (long) DEREF(tag_ptr), (int) value_type); - fflush(0); + fflush(nullptr); markTagVisited(DEREF(tag_ptr)); @@ -111,7 +111,7 @@ jint JNICALL arrayPrimitiveValueCallback( (long) DEREF(tag_ptr), (int) element_count, (int) element_type); - fflush(0); + fflush(nullptr); markTagVisited(DEREF(tag_ptr)); @@ -132,7 +132,7 @@ jint JNICALL stringPrimitiveValueCallback( (long) class_tag, (long) DEREF(tag_ptr), (int) value_length); - fflush(0); + fflush(nullptr); markTagVisited(DEREF(tag_ptr)); @@ -168,14 +168,14 @@ static void JNICALL agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) jvmtiError retCode; printf(">>> Sync with Java code\n"); - fflush(0); + fflush(nullptr); if (!NSK_VERIFY(nsk_jvmti_waitForSync(g_timeout))) { return; } printf(">>> Create JNI global references\n"); - fflush(0); + fflush(nullptr); createGlobalRefs(jni); @@ -192,7 +192,7 @@ static void JNICALL agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) checkThatAllTagsVisited(); printf(">>> Let debugee to finish\n"); - fflush(0); + fflush(nullptr); if (!NSK_VERIFY(nsk_jvmti_resumeSync())) { return; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref005/followref005.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref005/followref005.cpp index 333ddcccf83..d0194feab02 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref005/followref005.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref005/followref005.cpp @@ -88,7 +88,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf(">>> Let debugee to finish\n"); - fflush(0); + fflush(nullptr); if (!NSK_VERIFY(nsk_jvmti_waitForSync(g_timeout))) { return; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref006/followref006.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref006/followref006.cpp index 54485fb809a..5c5e3780321 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref006/followref006.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref006/followref006.cpp @@ -181,7 +181,7 @@ static void JNICALL agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) checkNoObjIterated(jni, jvmti, JAVA_UTIL_CALENDAR_CLASS_NAME); NSK_DISPLAY0("Let debugee to finish"); - fflush(0); + fflush(nullptr); if (!NSK_VERIFY(nsk_jvmti_waitForSync(g_timeout))) { return; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretbase/earlyretbase.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretbase/earlyretbase.cpp index 47b9618d19c..6c57004fc5f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretbase/earlyretbase.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretbase/earlyretbase.cpp @@ -33,7 +33,7 @@ extern "C" { #define STATUS_FAILED 2 #define PASSED 0 -#define RETURN_FAILED errCode = STATUS_FAILED; fflush(0); return errCode +#define RETURN_FAILED errCode = STATUS_FAILED; fflush(nullptr); return errCode static jvmtiEnv *jvmti = nullptr; static jvmtiCapabilities caps; @@ -59,7 +59,7 @@ MethodExit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thr, if (method == midActiveMethod) { printf("#### MethodExit event occurred ####\n"); - fflush(0); + fflush(nullptr); meth_exit_gen_events++; } } @@ -70,7 +70,7 @@ FramePop(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread, if (method == midActiveMethod) { printf("#### FramePop event occurred ####\n"); - fflush(0); + fflush(nullptr); pop_frame_gen_events++; } } @@ -120,7 +120,7 @@ Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretbase_resThread(JNIEnv *env, return JNI_ERR; } printf("<<<<<<<< ResumeThread() is successfully done\n"); - fflush(0); + fflush(nullptr); return PASSED; } @@ -176,7 +176,7 @@ Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretbase_doForceEarlyReturn(JNIEnv *env RETURN_FAILED; } printf("Check #1 PASSED: ForceEarlyReturn() is successfully done\n"); - fflush(0); + fflush(nullptr); return(errCode); } @@ -268,7 +268,7 @@ Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretbase_check(JNIEnv *env, jclass cls) "events generated correctly\n"); errCode = PASSED; } - fflush(0); + fflush(nullptr); return errCode; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretfp/earlyretfp.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretfp/earlyretfp.cpp index 9a0ce3d8550..5e7506a871e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretfp/earlyretfp.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretfp/earlyretfp.cpp @@ -33,7 +33,7 @@ extern "C" { #define PASSED 0 #define STATUS_FAILED 2 -#define RETURN_FAILED errCode = STATUS_FAILED; fflush(0); return +#define RETURN_FAILED errCode = STATUS_FAILED; fflush(nullptr); return #define METHCNT 2 static jvmtiEnv *jvmti = nullptr; @@ -175,7 +175,7 @@ void check(jvmtiEnv *jvmti_env, jthread thr, jmethodID mid, printf(" expected: %d\n", framesCount + 1); RETURN_FAILED; } - fflush(0); + fflush(nullptr); } void JNICALL Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, @@ -220,7 +220,7 @@ void JNICALL Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, TranslateError(err), err); RETURN_FAILED; } - fflush(0); + fflush(nullptr); } void JNICALL SingleStep(jvmtiEnv *jvmti_env, JNIEnv *env, @@ -256,7 +256,7 @@ void JNICALL SingleStep(jvmtiEnv *jvmti_env, JNIEnv *env, RETURN_FAILED; } } - fflush(0); + fflush(nullptr); } void JNICALL MethodExit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread, @@ -289,7 +289,7 @@ void JNICALL MethodExit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread, printf("Method was_popped_by_exception unexpectedly\n"); errCode = STATUS_FAILED; } - fflush(0); + fflush(nullptr); } #ifdef STATIC_BUILD @@ -361,7 +361,7 @@ jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { printf("Warning: Breakpoint or SingleStep event are not implemented\n"); } - fflush(0); + fflush(nullptr); return JNI_OK; } @@ -431,7 +431,7 @@ Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretfp_printFloat( JNIEnv *env, jclass cls, jfloat val) { printf("\n>>> Returned value is %8.4f, hex: %#a\n", val, val); - fflush(0); + fflush(nullptr); return; } @@ -440,7 +440,7 @@ Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretfp_printDouble( JNIEnv *env, jclass cls, jdouble val) { printf("\n>>> Returned value is %8.4f, hex: %#a\n", val, val); - fflush(0); + fflush(nullptr); return; } @@ -451,7 +451,7 @@ Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretfp_check(JNIEnv *env, jclass cls) { framesCount, framesExpected); errCode = STATUS_FAILED; } - fflush(0); + fflush(nullptr); return errCode; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretint/earlyretint.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretint/earlyretint.cpp index feb51d5fc40..16cd4c38567 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretint/earlyretint.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretint/earlyretint.cpp @@ -33,7 +33,7 @@ extern "C" { #define PASSED 0 #define STATUS_FAILED 2 -#define RETURN_FAILED errCode = STATUS_FAILED; fflush(0); return +#define RETURN_FAILED errCode = STATUS_FAILED; fflush(nullptr); return static jvmtiEnv *jvmti = nullptr; static jvmtiCapabilities caps; @@ -184,7 +184,7 @@ void check(jvmtiEnv *jvmti_env, jthread thr, jmethodID mid, printf(" expected: %d\n", framesCount + 1); RETURN_FAILED; } - fflush(0); + fflush(nullptr); } void JNICALL Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, @@ -229,7 +229,7 @@ void JNICALL Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, TranslateError(err), err); RETURN_FAILED; } - fflush(0); + fflush(nullptr); } void JNICALL SingleStep(jvmtiEnv *jvmti_env, JNIEnv *env, @@ -270,7 +270,7 @@ void JNICALL SingleStep(jvmtiEnv *jvmti_env, JNIEnv *env, RETURN_FAILED; } } - fflush(0); + fflush(nullptr); } void JNICALL MethodExit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread, @@ -295,7 +295,7 @@ void JNICALL MethodExit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread, printf("Method was_popped_by_exception unexpectedly\n"); errCode = STATUS_FAILED; } - fflush(0); + fflush(nullptr); } #ifdef STATIC_BUILD @@ -452,7 +452,7 @@ Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretint_printInt( JNIEnv *env, jclass cls, jint val) { printf("\n>>> Returned value: dec %d, hex: %#x\n", val, val); - fflush(0); + fflush(nullptr); return; } @@ -463,7 +463,7 @@ Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretint_check(JNIEnv *env, jclass cls) framesCount, framesExpected); errCode = STATUS_FAILED; } - fflush(0); + fflush(nullptr); return errCode; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretlong/earlyretlong.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretlong/earlyretlong.cpp index 170d6839bef..2cb1a318d44 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretlong/earlyretlong.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretlong/earlyretlong.cpp @@ -34,7 +34,7 @@ extern "C" { #define PASSED 0 #define STATUS_FAILED 2 -#define RETURN_FAILED errCode = STATUS_FAILED; fflush(0); return +#define RETURN_FAILED errCode = STATUS_FAILED; fflush(nullptr); return static jvmtiEnv *jvmti = nullptr; static jvmtiCapabilities caps; @@ -168,7 +168,7 @@ void check(jvmtiEnv *jvmti_env, jthread thr, jmethodID mid, printf(" expected: %d\n", framesCount + 1); RETURN_FAILED; } - fflush(0); + fflush(nullptr); } void JNICALL Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, @@ -213,7 +213,7 @@ void JNICALL Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, TranslateError(err), err); RETURN_FAILED; } - fflush(0); + fflush(nullptr); } void JNICALL SingleStep(jvmtiEnv *jvmti_env, JNIEnv *env, @@ -251,7 +251,7 @@ void JNICALL SingleStep(jvmtiEnv *jvmti_env, JNIEnv *env, RETURN_FAILED; } } - fflush(0); + fflush(nullptr); } void JNICALL MethodExit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread, @@ -276,7 +276,7 @@ void JNICALL MethodExit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread, errCode = STATUS_FAILED; } } - fflush(0); + fflush(nullptr); } #ifdef STATIC_BUILD @@ -412,7 +412,7 @@ Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretlong_printLong( printf("\n>>> Returned value: dec: %" LL "d, hex: %#x %#x\n", val, iptr[0], iptr[1]); - fflush(0); + fflush(nullptr); return; } @@ -423,7 +423,7 @@ Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretlong_check(JNIEnv *env, jclass cls) framesCount, framesExpected); errCode = STATUS_FAILED; } - fflush(0); + fflush(nullptr); return errCode; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretobj/earlyretobj.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretobj/earlyretobj.cpp index 6faf82f9ed9..ee3b79632d5 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretobj/earlyretobj.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretobj/earlyretobj.cpp @@ -34,7 +34,7 @@ extern "C" { #define PASSED 0 #define STATUS_FAILED 2 -#define RETURN_FAILED errCode = STATUS_FAILED; fflush(0); return +#define RETURN_FAILED errCode = STATUS_FAILED; fflush(nullptr); return static jvmtiEnv *jvmti = nullptr; static jvmtiCapabilities caps; @@ -168,7 +168,7 @@ void check(jvmtiEnv *jvmti_env, jthread thr, jmethodID mid, printf(" expected: %d\n", framesCount + 1); RETURN_FAILED; } - fflush(0); + fflush(nullptr); } void JNICALL Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, @@ -213,7 +213,7 @@ void JNICALL Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, TranslateError(err), err); RETURN_FAILED; } - fflush(0); + fflush(nullptr); } void JNICALL SingleStep(jvmtiEnv *jvmti_env, JNIEnv *env, @@ -251,7 +251,7 @@ void JNICALL SingleStep(jvmtiEnv *jvmti_env, JNIEnv *env, RETURN_FAILED; } } - fflush(0); + fflush(nullptr); } void JNICALL MethodExit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread, @@ -274,7 +274,7 @@ void JNICALL MethodExit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread, errCode = STATUS_FAILED; } } - fflush(0); + fflush(nullptr); } #ifdef STATIC_BUILD @@ -410,7 +410,7 @@ Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretobj_check(JNIEnv *env, jclass cls) framesCount, framesExpected); errCode = STATUS_FAILED; } - fflush(0); + fflush(nullptr); return errCode; } @@ -419,7 +419,7 @@ Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretobj_printObject( JNIEnv *env, jclass cls, jobject obj) { printf("\nReturned jobject: %#" PRIxPTR "\n", (uintptr_t)obj); - fflush(0); + fflush(nullptr); return; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretstr/earlyretstr.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretstr/earlyretstr.cpp index 6ebb50026a3..8465d05f956 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretstr/earlyretstr.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretstr/earlyretstr.cpp @@ -33,7 +33,7 @@ extern "C" { #define PASSED 0 #define STATUS_FAILED 2 -#define RETURN_FAILED errCode = STATUS_FAILED; fflush(0); return +#define RETURN_FAILED errCode = STATUS_FAILED; fflush(nullptr); return static jvmtiEnv *jvmti = nullptr; static jvmtiCapabilities caps; @@ -167,7 +167,7 @@ void check(jvmtiEnv *jvmti_env, jthread thr, jmethodID mid, printf(" expected: %d\n", framesCount + 1); RETURN_FAILED; } - fflush(0); + fflush(nullptr); } void JNICALL Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, @@ -212,7 +212,7 @@ void JNICALL Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, TranslateError(err), err); RETURN_FAILED; } - fflush(0); + fflush(nullptr); } void JNICALL SingleStep(jvmtiEnv *jvmti_env, JNIEnv *env, @@ -249,7 +249,7 @@ void JNICALL SingleStep(jvmtiEnv *jvmti_env, JNIEnv *env, RETURN_FAILED; } } - fflush(0); + fflush(nullptr); } void JNICALL MethodExit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread, @@ -273,7 +273,7 @@ void JNICALL MethodExit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread, errCode = STATUS_FAILED; } } - fflush(0); + fflush(nullptr); } #ifdef STATIC_BUILD @@ -409,7 +409,7 @@ Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretstr_check(JNIEnv *env, jclass cls) framesCount, framesExpected); errCode = STATUS_FAILED; } - fflush(0); + fflush(nullptr); return errCode; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretvoid/earlyretvoid.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretvoid/earlyretvoid.cpp index 4919d27e9e7..e66b9fc97ac 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretvoid/earlyretvoid.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretvoid/earlyretvoid.cpp @@ -33,7 +33,7 @@ extern "C" { #define PASSED 0 #define STATUS_FAILED 2 -#define RETURN_FAILED errCode = STATUS_FAILED; fflush(0); return +#define RETURN_FAILED errCode = STATUS_FAILED; fflush(nullptr); return static jvmtiEnv *jvmti = nullptr; static jvmtiCapabilities caps; @@ -155,7 +155,7 @@ void check(jvmtiEnv *jvmti_env, jthread thr, jmethodID mid, } jvmti_env->Deallocate((unsigned char*)table); } - fflush(0); + fflush(nullptr); } void JNICALL Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, @@ -192,7 +192,7 @@ void JNICALL Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, TranslateError(err), err); RETURN_FAILED; } - fflush(0); + fflush(nullptr); } void JNICALL SingleStep(jvmtiEnv *jvmti_env, JNIEnv *env, @@ -223,7 +223,7 @@ void JNICALL SingleStep(jvmtiEnv *jvmti_env, JNIEnv *env, RETURN_FAILED; } } - fflush(0); + fflush(nullptr); } #ifdef STATIC_BUILD @@ -339,7 +339,7 @@ Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretvoid_getReady( } else { framesExpected = depth; } - fflush(0); + fflush(nullptr); } JNIEXPORT jint JNICALL @@ -349,7 +349,7 @@ Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretvoid_check(JNIEnv *env, jclass cls) framesCount, framesExpected); errCode = STATUS_FAILED; } - fflush(0); + fflush(nullptr); return errCode; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/GetAllStackTraces/getallstktr001/getallstktr001.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/GetAllStackTraces/getallstktr001/getallstktr001.cpp index c1f0443186f..8916186531d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/GetAllStackTraces/getallstktr001/getallstktr001.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/GetAllStackTraces/getallstktr001/getallstktr001.cpp @@ -179,7 +179,7 @@ void compare_all_frames(int ti, int frames_count, printf("thr #%d: compare frame #%d: fields are the same: " " method: 0x%p, location: %#" LL "x\n", ti, fi, fr1->method, fr1->location); - fflush(0); + fflush(nullptr); } } @@ -225,7 +225,7 @@ void compare_one_stack_trace(int ti, " jthread: 0x%p, state: %d, frame_count: %d\n", ti, stk1->thread, stk1->state, stk1->frame_count); - fflush(0); + fflush(nullptr); compare_all_frames(ti, stk1->frame_count, stk1->frame_buffer, @@ -291,7 +291,7 @@ Java_nsk_jvmti_unit_GetAllStackTraces_getallstktr001_GetThreadsInfo( iGlobalStatus = STATUS_FAILED; } printf("GetThreadInfo %d: thread: %s\n", ti, thread_info[ti].name); - fflush(0); + fflush(nullptr); } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/GetConstantPool/getcpool001/getcpool001.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/GetConstantPool/getcpool001/getcpool001.cpp index 997e6c667e6..d3905ad65eb 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/GetConstantPool/getcpool001/getcpool001.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/GetConstantPool/getcpool001/getcpool001.cpp @@ -36,7 +36,7 @@ extern "C" { static jvmtiCapabilities caps; static jvmtiEventCallbacks callbacks; -#define RETURN_FAILED errCode = STATUS_FAILED; fflush(0); return +#define RETURN_FAILED errCode = STATUS_FAILED; fflush(nullptr); return static jint errCode = PASSED; static jvmtiEnv *jvmti = nullptr; @@ -63,7 +63,7 @@ Java_nsk_jvmti_unit_GetConstantPool_getcpool001_getCP( /* Print Constant Pool attrs*/ printf("getCP: id = %d, cnt = %03d, bytes_cnt = %04d\n", id, cp_cnt, cp_bytes_cnt); - fflush(0); + fflush(nullptr); } void JNICALL Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, @@ -83,7 +83,7 @@ void JNICALL Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, TranslateError(err), err); RETURN_FAILED; } - fflush(0); + fflush(nullptr); } #ifdef STATIC_BUILD From 1472124489c841642996ae984e21c533ffec8091 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Tue, 9 Jul 2024 20:38:09 +0000 Subject: [PATCH 026/460] 8333364: Minor cleanup could be done in com.sun.crypto.provider Reviewed-by: mullan, valeriep --- .../sun/crypto/provider/AESKeyGenerator.java | 12 +- .../com/sun/crypto/provider/AESKeyWrap.java | 30 ++--- .../sun/crypto/provider/AESKeyWrapPadded.java | 34 ++--- .../sun/crypto/provider/ARCFOURCipher.java | 8 +- .../sun/crypto/provider/ChaCha20Cipher.java | 35 +++-- .../provider/ChaCha20Poly1305Parameters.java | 7 +- .../crypto/provider/CipherBlockChaining.java | 4 +- .../com/sun/crypto/provider/CipherCore.java | 21 ++- .../crypto/provider/CipherTextStealing.java | 5 +- .../sun/crypto/provider/ConstructKeys.java | 6 +- .../com/sun/crypto/provider/DESCrypt.java | 126 +++++++++--------- .../sun/crypto/provider/DESKeyFactory.java | 4 +- .../sun/crypto/provider/DESedeKeyFactory.java | 4 +- .../crypto/provider/DESedeKeyGenerator.java | 4 +- .../sun/crypto/provider/DESedeWrapCipher.java | 15 +-- .../com/sun/crypto/provider/DHKEM.java | 20 +-- .../sun/crypto/provider/DHKeyAgreement.java | 30 ++--- .../crypto/provider/DHKeyPairGenerator.java | 5 +- .../crypto/provider/ElectronicCodeBook.java | 6 +- .../sun/crypto/provider/FeedbackCipher.java | 6 +- .../classes/com/sun/crypto/provider/GCTR.java | 5 +- .../com/sun/crypto/provider/GHASH.java | 7 +- .../crypto/provider/GaloisCounterMode.java | 34 ++--- .../com/sun/crypto/provider/HmacCore.java | 27 ++-- .../com/sun/crypto/provider/HmacMD5.java | 9 +- .../crypto/provider/HmacMD5KeyGenerator.java | 5 +- .../com/sun/crypto/provider/HmacSHA1.java | 9 +- .../crypto/provider/HmacSHA1KeyGenerator.java | 5 +- .../sun/crypto/provider/ISO10126Padding.java | 5 +- .../com/sun/crypto/provider/JceKeyStore.java | 14 +- .../com/sun/crypto/provider/KWUtil.java | 10 +- .../com/sun/crypto/provider/KeyProtector.java | 6 +- .../sun/crypto/provider/KeyWrapCipher.java | 20 +-- .../sun/crypto/provider/OAEPParameters.java | 12 +- .../sun/crypto/provider/OutputFeedback.java | 4 +- .../sun/crypto/provider/PBEKeyFactory.java | 4 +- .../com/sun/crypto/provider/PBES1Core.java | 6 +- .../sun/crypto/provider/PBES2Parameters.java | 20 ++- .../sun/crypto/provider/PBKDF2KeyImpl.java | 21 +-- .../com/sun/crypto/provider/PBMAC1Core.java | 4 +- .../com/sun/crypto/provider/PKCS5Padding.java | 5 +- .../com/sun/crypto/provider/Poly1305.java | 12 +- .../com/sun/crypto/provider/RC2Crypt.java | 4 +- .../com/sun/crypto/provider/RSACipher.java | 7 +- .../com/sun/crypto/provider/SslMacCore.java | 23 ++-- .../provider/TlsKeyMaterialGenerator.java | 12 +- .../sun/crypto/provider/TlsPrfGenerator.java | 8 +- 47 files changed, 313 insertions(+), 367 deletions(-) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/AESKeyGenerator.java b/src/java.base/share/classes/com/sun/crypto/provider/AESKeyGenerator.java index 2672807aadd..51671fdf25d 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/AESKeyGenerator.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/AESKeyGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,19 +25,19 @@ package com.sun.crypto.provider; -import java.security.SecureRandom; -import java.security.InvalidParameterException; import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; +import java.security.InvalidParameterException; +import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; import java.util.Arrays; import javax.crypto.KeyGeneratorSpi; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; + import sun.security.util.SecurityProviderConstants; /** - * This class generates a AES key. + * This class generates an AES key. * * @author Valerie Peng * @@ -105,7 +105,7 @@ protected void engineInit(int keysize, SecureRandom random) { * @return the new AES key */ protected SecretKey engineGenerateKey() { - SecretKeySpec aesKey = null; + SecretKeySpec aesKey; if (this.random == null) { this.random = SunJCE.getRandom(); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrap.java b/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrap.java index 9cb33899640..7fad0b84d07 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrap.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,11 +25,11 @@ package com.sun.crypto.provider; -import java.util.Arrays; -import java.security.*; -import java.security.spec.*; -import javax.crypto.*; -import javax.crypto.spec.*; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.MessageDigest; +import javax.crypto.IllegalBlockSizeException; + import static com.sun.crypto.provider.KWUtil.*; /** @@ -66,7 +66,7 @@ String getFeedback() { @Override void save() { throw new UnsupportedOperationException("save not supported"); - }; + } /** * Restores the content of this cipher to the previous saved one. @@ -74,7 +74,7 @@ void save() { @Override void restore() { throw new UnsupportedOperationException("restore not supported"); - }; + } /** * Initializes the cipher in the specified mode with the given key @@ -112,20 +112,20 @@ void init(boolean decrypting, String algorithm, byte[] key, byte[] iv) @Override void reset() { throw new UnsupportedOperationException("reset not supported"); - }; + } - // no support for multi-part encryption + // no support for multipart encryption @Override int encrypt(byte[] pt, int ptOfs, int ptLen, byte[] ct, int ctOfs) { - throw new UnsupportedOperationException("multi-part not supported"); - }; + throw new UnsupportedOperationException("multipart not supported"); + } - // no support for multi-part decryption + // no support for multipart decryption @Override int decrypt(byte[] ct, int ctOfs, int ctLen, byte[] pt, int ptOfs) { - throw new UnsupportedOperationException("multi-part not supported"); - }; + throw new UnsupportedOperationException("multipart not supported"); + } /** * Performs single-part encryption operation. diff --git a/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrapPadded.java b/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrapPadded.java index 4ae96acbca8..1e4e7236c8c 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrapPadded.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrapPadded.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,12 +25,12 @@ package com.sun.crypto.provider; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; import java.util.Arrays; import java.util.HexFormat; -import java.security.*; -import java.security.spec.*; -import javax.crypto.*; -import javax.crypto.spec.*; +import javax.crypto.IllegalBlockSizeException; + import static com.sun.crypto.provider.KWUtil.*; /** @@ -49,7 +49,7 @@ class AESKeyWrapPadded extends FeedbackCipher { private static final byte[] PAD_BLK = new byte[SEMI_BLKSIZE - 1]; - // set the first semiblock of dest with iv and inLen + // set the first semi-block of dest with iv and inLen private static void setIvAndLen(byte[] dest, byte[] iv, int inLen) { assert(dest.length >= SEMI_BLKSIZE) : "buffer needs at least 8 bytes"; @@ -60,7 +60,7 @@ private static void setIvAndLen(byte[] dest, byte[] iv, int inLen) { dest[7] = (byte) (inLen & 0xFF); } - // validate the recovered internal ivAndLen semiblock against iv and + // validate the recovered internal ivAndLen semi-block against iv and // return the recovered input length private static int validateIV(byte[] ivAndLen, byte[] iv) throws IllegalBlockSizeException { @@ -103,7 +103,7 @@ String getFeedback() { @Override void save() { throw new UnsupportedOperationException("save not supported"); - }; + } /** * Restores the content of this cipher to the previous saved one. @@ -111,7 +111,7 @@ void save() { @Override void restore() { throw new UnsupportedOperationException("restore not supported"); - }; + } /** * Initializes the cipher in the specified mode with the given key @@ -151,19 +151,19 @@ void init(boolean decrypting, String algorithm, byte[] key, byte[] iv) @Override void reset() { throw new UnsupportedOperationException("reset not supported"); - }; + } - // no support for multi-part encryption + // no support for multipart encryption @Override int encrypt(byte[] pt, int ptOfs, int ptLen, byte[] ct, int ctOfs) { - throw new UnsupportedOperationException("multi-part not supported"); - }; + throw new UnsupportedOperationException("multipart not supported"); + } - // no support for multi-part decryption + // no support for multipart decryption @Override int decrypt(byte[] ct, int ctOfs, int ctLen, byte[] pt, int ptOfs) { - throw new UnsupportedOperationException("multi-part not supported"); - }; + throw new UnsupportedOperationException("multipart not supported"); + } /** * Performs single-part encryption operation. @@ -199,7 +199,7 @@ int encryptFinal(byte[] pt, int dummy1, int ptLen, byte[] dummy2, } if (ptLen <= BLKSIZE) { - // overwrite the first semiblock with iv and input length + // overwrite the first semi-block with iv and input length setIvAndLen(pt, iv, actualLen); embeddedCipher.encryptBlock(pt, 0, pt, 0); } else { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/ARCFOURCipher.java b/src/java.base/share/classes/com/sun/crypto/provider/ARCFOURCipher.java index 09d5a8cddeb..d7c0f3dd35d 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/ARCFOURCipher.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/ARCFOURCipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -114,7 +114,7 @@ private void crypt(byte[] in, int inOfs, int inLen, byte[] out, // Modes do not make sense with stream ciphers, but allow ECB // see JCE spec. protected void engineSetMode(String mode) throws NoSuchAlgorithmException { - if (mode.equalsIgnoreCase("ECB") == false) { + if (!mode.equalsIgnoreCase("ECB")) { throw new NoSuchAlgorithmException("Unsupported mode " + mode); } } @@ -123,7 +123,7 @@ protected void engineSetMode(String mode) throws NoSuchAlgorithmException { // see JCE spec. protected void engineSetPadding(String padding) throws NoSuchPaddingException { - if (padding.equalsIgnoreCase("NoPadding") == false) { + if (!padding.equalsIgnoreCase("NoPadding")) { throw new NoSuchPaddingException("Padding must be NoPadding"); } } @@ -201,7 +201,7 @@ private static byte[] getEncodedKey(Key key) throws InvalidKeyException { if (!keyAlg.equals("RC4") && !keyAlg.equals("ARCFOUR")) { throw new InvalidKeyException("Not an ARCFOUR key: " + keyAlg); } - if ("RAW".equals(key.getFormat()) == false) { + if (!"RAW".equals(key.getFormat())) { throw new InvalidKeyException("Key encoding format must be RAW"); } byte[] encodedKey = key.getEncoded(); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Cipher.java b/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Cipher.java index ed2fda5bf00..fc39b4ed634 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Cipher.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Cipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -156,7 +156,7 @@ protected ChaCha20Cipher() { } */ @Override protected void engineSetMode(String mode) throws NoSuchAlgorithmException { - if (mode.equalsIgnoreCase("None") == false) { + if (!mode.equalsIgnoreCase("None")) { throw new NoSuchAlgorithmException("Mode must be None"); } } @@ -174,7 +174,7 @@ protected void engineSetMode(String mode) throws NoSuchAlgorithmException { @Override protected void engineSetPadding(String padding) throws NoSuchPaddingException { - if (padding.equalsIgnoreCase("NoPadding") == false) { + if (!padding.equalsIgnoreCase("NoPadding")) { throw new NoSuchPaddingException("Padding must be NoPadding"); } } @@ -326,7 +326,7 @@ protected void engineInit(int opmode, Key key, // We will ignore the secure random implementation and use the nonce // from the AlgorithmParameterSpec instead. - byte[] newNonce = null; + byte[] newNonce; switch (mode) { case MODE_NONE: if (!(params instanceof ChaCha20ParameterSpec)) { @@ -360,7 +360,7 @@ protected void engineInit(int opmode, Key key, /** * Initialize the engine using the {@code AlgorithmParameter} initialization - * format. This cipher does supports initialization with + * format. This cipher supports initialization with * {@code AlgorithmParameter} objects for ChaCha20-Poly1305 but not for * ChaCha20 as a simple stream cipher. In the latter case, it will throw * an {@code InvalidAlgorithmParameterException} if the value is non-null. @@ -618,7 +618,7 @@ private void checkKeyAndNonce(byte[] newKeyBytes, byte[] newNonce) * or if the key encoding format is not {@code RAW}. */ private static byte[] getEncodedKey(Key key) throws InvalidKeyException { - if ("RAW".equals(key.getFormat()) == false) { + if (!"RAW".equals(key.getFormat())) { throw new InvalidKeyException("Key encoding format must be RAW"); } byte[] encodedKey = key.getEncoded(); @@ -675,7 +675,7 @@ protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) { @Override protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out, int outOfs) throws ShortBufferException { - int bytesUpdated = 0; + int bytesUpdated; try { bytesUpdated = engine.doUpdate(in, inOfs, inLen, out, outOfs); } catch (KeyException ke) { @@ -691,10 +691,10 @@ protected int engineUpdate(byte[] in, int inOfs, int inLen, * @param output ByteBuffer that will hold the resulting data. This * must be large enough to hold the resulting data. * - * @return the length in bytes of the data written into the {@code out} + * @return the length in bytes of the data written into the {@code output} * buffer. * - * @throws ShortBufferException if the buffer {@code out} does not have + * @throws ShortBufferException if the buffer {@code output} does not have * enough space to hold the resulting data. */ @Override @@ -763,7 +763,7 @@ protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen) protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out, int outOfs) throws ShortBufferException, AEADBadTagException { - int bytesUpdated = 0; + int bytesUpdated; try { bytesUpdated = engine.doFinal(in, inOfs, inLen, out, outOfs); } catch (KeyException ke) { @@ -785,6 +785,9 @@ protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out, * * @return the resulting plaintext or ciphertext bytes. * + * @throws ShortBufferException if the buffer {@code output} does not have + * enough space to hold the resulting data. + * * @throws AEADBadTagException if, during decryption, the provided tag * does not match the calculated tag. */ @@ -947,12 +950,8 @@ protected int engineGetKeySize(Key key) throws InvalidKeyException { * key and nonce into their proper locations. The counter field is not * set here. * - * @throws IllegalArgumentException if the key or nonce are not in - * their proper lengths (32 bytes for the key, 12 bytes for the - * nonce). - * @throws InvalidKeyException if the key does not support an encoded form. */ - private void setInitialState() throws InvalidKeyException { + private void setInitialState() { // Apply constants to first 4 words startState[0] = STATE_CONST_0; startState[1] = STATE_CONST_1; @@ -1257,11 +1256,11 @@ private int authUpdate(byte[] data, int offset, int length) { * @param out the array to write the resulting tag into * @param outOff the offset to begin writing the data. * - * @throws ShortBufferException if there is insufficient room to + * @throws ProviderException if there is insufficient room to * write the tag. */ private void authFinalizeData(byte[] data, int dataOff, int length, - byte[] out, int outOff) throws ShortBufferException { + byte[] out, int outOff) { // Update with the final chunk of ciphertext, then pad to a // multiple of 16. if (data != null) { @@ -1300,7 +1299,7 @@ private void authPad16(long dataLen) { * @param dLen the length of the application data. * @param buf the buffer to write the two lengths into. * - * @note it is the caller's responsibility to provide an array large + * @implNote it is the caller's responsibility to provide an array large * enough to hold the two longs. */ private void authWriteLengths(long aLen, long dLen, byte[] buf) { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Poly1305Parameters.java b/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Poly1305Parameters.java index 762827d0152..ab9d4a23e60 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Poly1305Parameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Poly1305Parameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -206,8 +206,7 @@ protected byte[] engineGetEncoded(String encodingMethod) protected String engineToString() { String LINE_SEP = System.lineSeparator(); HexDumpEncoder encoder = new HexDumpEncoder(); - StringBuilder sb = new StringBuilder(LINE_SEP + "nonce:" + - LINE_SEP + "[" + encoder.encodeBuffer(nonce) + "]"); - return sb.toString(); + return LINE_SEP + "nonce:" + + LINE_SEP + "[" + encoder.encodeBuffer(nonce) + "]"; } } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/CipherBlockChaining.java b/src/java.base/share/classes/com/sun/crypto/provider/CipherBlockChaining.java index 5d756e26847..4bd7faea722 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/CipherBlockChaining.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/CipherBlockChaining.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -180,7 +180,7 @@ private int implEncrypt(byte[] plain, int plainOffset, int plainLen, * *

It is also the application's responsibility to make sure that * init has been called before this method is called. - * (This check is omitted here, to avoid double checking.) + * (This check is omitted here, to avoid double-checking.) * * @param cipher the buffer with the input data to be decrypted * @param cipherOffset the offset in cipherOffset diff --git a/src/java.base/share/classes/com/sun/crypto/provider/CipherCore.java b/src/java.base/share/classes/com/sun/crypto/provider/CipherCore.java index 2555448e3c0..c808756fa1d 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/CipherCore.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/CipherCore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,7 +67,7 @@ final class CipherCore { /* * unit size (number of input bytes that can be processed at a time) */ - private int unitBytes = 0; + private int unitBytes; /* * index of the content size left in the buffer @@ -91,17 +91,17 @@ final class CipherCore { * input bytes that are processed at a time is different from the block * size) */ - private int diffBlocksize = 0; + private int diffBlocksize; /* * padding class */ - private Padding padding = null; + private Padding padding; /* * internal cipher engine */ - private FeedbackCipher cipher = null; + private FeedbackCipher cipher; /* * the cipher mode @@ -136,7 +136,7 @@ final class CipherCore { /* * The buffer should be usable for all cipher mode and padding * schemes. Thus, it has to be at least (blockSize+1) for CTS. - * In decryption mode, it also hold the possible padding block. + * In decryption mode, it also holds the possible padding block. */ buffer = new byte[blockSize*2]; @@ -334,7 +334,7 @@ AlgorithmParameters getParameters(String algName) { if (cipherMode == ECB_MODE) { return null; } - AlgorithmParameters params = null; + AlgorithmParameters params; AlgorithmParameterSpec spec; byte[] iv = getIV(); if (iv == null) { @@ -545,7 +545,7 @@ static byte[] getKeyBytes(Key key) throws InvalidKeyException { */ byte[] update(byte[] input, int inputOffset, int inputLen) { - byte[] output = null; + byte[] output; try { output = new byte[getOutputSizeByOperation(inputLen, false)]; int len = update(input, inputOffset, inputLen, output, @@ -930,8 +930,7 @@ private byte[] prepareInputBuffer(byte[] input, int inputOffset, private int fillOutputBuffer(byte[] finalBuf, int finalOffset, byte[] output, int outOfs, int finalBufLen, byte[] input) - throws ShortBufferException, BadPaddingException, - IllegalBlockSizeException { + throws BadPaddingException, IllegalBlockSizeException { int len; try { @@ -967,7 +966,7 @@ private int checkOutputCapacity(byte[] output, int outputOffset, private int finalNoPadding(byte[] in, int inOfs, byte[] out, int outOfs, int len) - throws IllegalBlockSizeException, ShortBufferException { + throws IllegalBlockSizeException { if (in == null || len == 0) { return 0; diff --git a/src/java.base/share/classes/com/sun/crypto/provider/CipherTextStealing.java b/src/java.base/share/classes/com/sun/crypto/provider/CipherTextStealing.java index 630f8707fde..da46f220825 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/CipherTextStealing.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/CipherTextStealing.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,6 @@ package com.sun.crypto.provider; import javax.crypto.IllegalBlockSizeException; -import javax.crypto.ShortBufferException; /** * This class represents ciphers in cipher text stealing (CTS) mode. @@ -153,7 +152,7 @@ int encryptFinal(byte[] plain, int plainOffset, int plainLen, * *

It is also the application's responsibility to make sure that * init has been called before this method is called. - * (This check is omitted here, to avoid double checking.) + * (This check is omitted here, to avoid double-checking.) * * @param cipher the buffer with the input data to be decrypted * @param cipherOffset the offset in cipherOffset diff --git a/src/java.base/share/classes/com/sun/crypto/provider/ConstructKeys.java b/src/java.base/share/classes/com/sun/crypto/provider/ConstructKeys.java index e8375d1eb81..2019104941e 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/ConstructKeys.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/ConstructKeys.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,7 +54,7 @@ final class ConstructKeys { private static final PublicKey constructPublicKey(byte[] encodedKey, int ofs, int len, String encodedKeyAlgorithm) throws InvalidKeyException, NoSuchAlgorithmException { - PublicKey key = null; + PublicKey key; byte[] keyBytes = (ofs == 0 && encodedKey.length == len) ? encodedKey : Arrays.copyOfRange(encodedKey, ofs, ofs + len); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); @@ -88,7 +88,7 @@ private static final PublicKey constructPublicKey(byte[] encodedKey, private static final PrivateKey constructPrivateKey(byte[] encodedKey, int ofs, int len, String encodedKeyAlgorithm) throws InvalidKeyException, NoSuchAlgorithmException { - PrivateKey key = null; + PrivateKey key; byte[] keyBytes = (ofs == 0 && encodedKey.length == len) ? encodedKey : Arrays.copyOfRange(encodedKey, ofs, ofs + len); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DESCrypt.java b/src/java.base/share/classes/com/sun/crypto/provider/DESCrypt.java index acbde75cd84..29a5ba25408 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DESCrypt.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DESCrypt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ */ class DESCrypt extends SymmetricCipher implements DESConstants { - private static final int s0p[] = { + private static final int[] s0p = { 0x00410100, 0x00010000, 0x40400000, 0x40410100, 0x00400000, 0x40010100, 0x40010000, 0x40400000, 0x40010100, 0x00410100, 0x00410000, 0x40000100, 0x40400100, 0x00400000, 0x00000000, @@ -56,7 +56,7 @@ class DESCrypt extends SymmetricCipher implements DESConstants { 0x40000000, 0x40410000, 0x00000100, 0x40010100, }; - private static final int s1p[] = { + private static final int[] s1p = { 0x08021002, 0x00000000, 0x00021000, 0x08020000, 0x08000002, 0x00001002, 0x08001000, 0x00021000, 0x00001000, 0x08020002, 0x00000002, 0x08001000, 0x00020002, 0x08021000, 0x08020000, @@ -72,7 +72,7 @@ class DESCrypt extends SymmetricCipher implements DESConstants { 0x08001002, 0x00000002, 0x08020000, 0x00021000, }; - private static final int s2p[] = { + private static final int[] s2p = { 0x20800000, 0x00808020, 0x00000020, 0x20800020, 0x20008000, 0x00800000, 0x20800020, 0x00008020, 0x00800020, 0x00008000, 0x00808000, 0x20000000, 0x20808020, 0x20000020, 0x20000000, @@ -88,7 +88,7 @@ class DESCrypt extends SymmetricCipher implements DESConstants { 0x20800000, 0x20008020, 0x00000020, 0x00808000, }; - private static final int s3p[] = { + private static final int[] s3p = { 0x00080201, 0x02000200, 0x00000001, 0x02080201, 0x00000000, 0x02080000, 0x02000201, 0x00080001, 0x02080200, 0x02000001, 0x02000000, 0x00000201, 0x02000001, 0x00080201, 0x00080000, @@ -104,7 +104,7 @@ class DESCrypt extends SymmetricCipher implements DESConstants { 0x00000201, 0x02000000, 0x02000001, 0x02080200, }; - private static final int s4p[] = { + private static final int[] s4p = { 0x01000000, 0x00002000, 0x00000080, 0x01002084, 0x01002004, 0x01000080, 0x00002084, 0x01002000, 0x00002000, 0x00000004, 0x01000004, 0x00002080, 0x01000084, 0x01002004, 0x01002080, @@ -120,7 +120,7 @@ class DESCrypt extends SymmetricCipher implements DESConstants { 0x00000004, 0x00002084, 0x01002000, 0x01000004, }; - private static final int s5p[] = { + private static final int[] s5p = { 0x10000008, 0x00040008, 0x00000000, 0x10040400, 0x00040008, 0x00000400, 0x10000408, 0x00040000, 0x00000408, 0x10040408, 0x00040400, 0x10000000, 0x10000400, 0x10000008, 0x10040000, @@ -136,7 +136,7 @@ class DESCrypt extends SymmetricCipher implements DESConstants { 0x10040000, 0x00000408, 0x00000008, 0x10040008, }; - private static final int s6p[] = { + private static final int[] s6p = { 0x00000800, 0x00000040, 0x00200040, 0x80200000, 0x80200840, 0x80000800, 0x00000840, 0x00000000, 0x00200000, 0x80200040, 0x80000040, 0x00200800, 0x80000000, 0x00200840, 0x00200800, @@ -152,7 +152,7 @@ class DESCrypt extends SymmetricCipher implements DESConstants { 0x80200000, 0x00200840, 0x00200800, 0x80000800, }; - private static final int s7p[] = { + private static final int[] s7p = { 0x04100010, 0x04104000, 0x00004010, 0x00000000, 0x04004000, 0x00100010, 0x04100000, 0x04104010, 0x00000010, 0x04000000, 0x00104000, 0x00004010, 0x00104010, 0x04004010, 0x04000010, @@ -168,112 +168,112 @@ class DESCrypt extends SymmetricCipher implements DESConstants { 0x04000000, 0x04100010, 0x00004000, 0x00104010, }; - private static final int permRight0[] = { + private static final int[] permRight0 = { 0x00000000, 0x40000000, 0x00400000, 0x40400000, 0x00004000, 0x40004000, 0x00404000, 0x40404000, 0x00000040, 0x40000040, 0x00400040, 0x40400040, 0x00004040, 0x40004040, 0x00404040, 0x40404040, }; - private static final int permLeft1[] = { + private static final int[] permLeft1 = { 0x00000000, 0x40000000, 0x00400000, 0x40400000, 0x00004000, 0x40004000, 0x00404000, 0x40404000, 0x00000040, 0x40000040, 0x00400040, 0x40400040, 0x00004040, 0x40004040, 0x00404040, 0x40404040, }; - private static final int permRight2[] = { + private static final int[] permRight2 = { 0x00000000, 0x10000000, 0x00100000, 0x10100000, 0x00001000, 0x10001000, 0x00101000, 0x10101000, 0x00000010, 0x10000010, 0x00100010, 0x10100010, 0x00001010, 0x10001010, 0x00101010, 0x10101010, }; - private static final int permLeft3[] = { + private static final int[] permLeft3 = { 0x00000000, 0x10000000, 0x00100000, 0x10100000, 0x00001000, 0x10001000, 0x00101000, 0x10101000, 0x00000010, 0x10000010, 0x00100010, 0x10100010, 0x00001010, 0x10001010, 0x00101010, 0x10101010, }; - private static final int permRight4[] = { + private static final int[] permRight4 = { 0x00000000, 0x04000000, 0x00040000, 0x04040000, 0x00000400, 0x04000400, 0x00040400, 0x04040400, 0x00000004, 0x04000004, 0x00040004, 0x04040004, 0x00000404, 0x04000404, 0x00040404, 0x04040404, }; - private static final int permLeft5[] = { + private static final int[] permLeft5 = { 0x00000000, 0x04000000, 0x00040000, 0x04040000, 0x00000400, 0x04000400, 0x00040400, 0x04040400, 0x00000004, 0x04000004, 0x00040004, 0x04040004, 0x00000404, 0x04000404, 0x00040404, 0x04040404, }; - private static final int permRight6[] = { + private static final int[] permRight6 = { 0x00000000, 0x01000000, 0x00010000, 0x01010000, 0x00000100, 0x01000100, 0x00010100, 0x01010100, 0x00000001, 0x01000001, 0x00010001, 0x01010001, 0x00000101, 0x01000101, 0x00010101, 0x01010101, }; - private static final int permLeft7[] = { + private static final int[] permLeft7 = { 0x00000000, 0x01000000, 0x00010000, 0x01010000, 0x00000100, 0x01000100, 0x00010100, 0x01010100, 0x00000001, 0x01000001, 0x00010001, 0x01010001, 0x00000101, 0x01000101, 0x00010101, 0x01010101, }; - private static final int permRight8[] = { + private static final int[] permRight8 = { 0x00000000, 0x80000000, 0x00800000, 0x80800000, 0x00008000, 0x80008000, 0x00808000, 0x80808000, 0x00000080, 0x80000080, 0x00800080, 0x80800080, 0x00008080, 0x80008080, 0x00808080, 0x80808080, }; - private static final int permLeft9[] = { + private static final int[] permLeft9 = { 0x00000000, 0x80000000, 0x00800000, 0x80800000, 0x00008000, 0x80008000, 0x00808000, 0x80808000, 0x00000080, 0x80000080, 0x00800080, 0x80800080, 0x00008080, 0x80008080, 0x00808080, 0x80808080, }; - private static final int permRightA[] = { + private static final int[] permRightA = { 0x00000000, 0x20000000, 0x00200000, 0x20200000, 0x00002000, 0x20002000, 0x00202000, 0x20202000, 0x00000020, 0x20000020, 0x00200020, 0x20200020, 0x00002020, 0x20002020, 0x00202020, 0x20202020, }; - private static final int permLeftB[] = { + private static final int[] permLeftB = { 0x00000000, 0x20000000, 0x00200000, 0x20200000, 0x00002000, 0x20002000, 0x00202000, 0x20202000, 0x00000020, 0x20000020, 0x00200020, 0x20200020, 0x00002020, 0x20002020, 0x00202020, 0x20202020, }; - private static final int permRightC[] = { + private static final int[] permRightC = { 0x00000000, 0x08000000, 0x00080000, 0x08080000, 0x00000800, 0x08000800, 0x00080800, 0x08080800, 0x00000008, 0x08000008, 0x00080008, 0x08080008, 0x00000808, 0x08000808, 0x00080808, 0x08080808, }; - private static final int permLeftD[] = { + private static final int[] permLeftD = { 0x00000000, 0x08000000, 0x00080000, 0x08080000, 0x00000800, 0x08000800, 0x00080800, 0x08080800, 0x00000008, 0x08000008, 0x00080008, 0x08080008, 0x00000808, 0x08000808, 0x00080808, 0x08080808, }; - private static final int permRightE[] = { + private static final int[] permRightE = { 0x00000000, 0x02000000, 0x00020000, 0x02020000, 0x00000200, 0x02000200, 0x00020200, 0x02020200, 0x00000002, 0x02000002, 0x00020002, 0x02020002, 0x00000202, 0x02000202, 0x00020202, 0x02020202, }; - private static final int permLeftF[] = { + private static final int[] permLeftF = { 0x00000000, 0x02000000, 0x00020000, 0x02020000, 0x00000200, 0x02000200, 0x00020200, 0x02020200, 0x00000002, 0x02000002, 0x00020002, 0x02020002, 0x00000202, 0x02000202, 0x00020202, @@ -283,224 +283,224 @@ class DESCrypt extends SymmetricCipher implements DESConstants { /* * Initial Permutation */ - private static final int initPermLeft0[] = { + private static final int[] initPermLeft0 = { 0x00000000, 0x00008000, 0x00000000, 0x00008000, 0x00000080, 0x00008080, 0x00000080, 0x00008080, 0x00000000, 0x00008000, 0x00000000, 0x00008000, 0x00000080, 0x00008080, 0x00000080, 0x00008080, }; - private static final int initPermRight0[] = { + private static final int[] initPermRight0 = { 0x00000000, 0x00000000, 0x00008000, 0x00008000, 0x00000000, 0x00000000, 0x00008000, 0x00008000, 0x00000080, 0x00000080, 0x00008080, 0x00008080, 0x00000080, 0x00000080, 0x00008080, 0x00008080, }; - private static final int initPermLeft1[] = { + private static final int[] initPermLeft1 = { 0x00000000, 0x80000000, 0x00000000, 0x80000000, 0x00800000, 0x80800000, 0x00800000, 0x80800000, 0x00000000, 0x80000000, 0x00000000, 0x80000000, 0x00800000, 0x80800000, 0x00800000, 0x80800000, }; - private static final int initPermRight1[] = { + private static final int[] initPermRight1 = { 0x00000000, 0x00000000, 0x80000000, 0x80000000, 0x00000000, 0x00000000, 0x80000000, 0x80000000, 0x00800000, 0x00800000, 0x80800000, 0x80800000, 0x00800000, 0x00800000, 0x80800000, 0x80800000, }; - private static final int initPermLeft2[] = { + private static final int[] initPermLeft2 = { 0x00000000, 0x00004000, 0x00000000, 0x00004000, 0x00000040, 0x00004040, 0x00000040, 0x00004040, 0x00000000, 0x00004000, 0x00000000, 0x00004000, 0x00000040, 0x00004040, 0x00000040, 0x00004040, }; - private static final int initPermRight2[] = { + private static final int[] initPermRight2 = { 0x00000000, 0x00000000, 0x00004000, 0x00004000, 0x00000000, 0x00000000, 0x00004000, 0x00004000, 0x00000040, 0x00000040, 0x00004040, 0x00004040, 0x00000040, 0x00000040, 0x00004040, 0x00004040, }; - private static final int initPermLeft3[] = { + private static final int[] initPermLeft3 = { 0x00000000, 0x40000000, 0x00000000, 0x40000000, 0x00400000, 0x40400000, 0x00400000, 0x40400000, 0x00000000, 0x40000000, 0x00000000, 0x40000000, 0x00400000, 0x40400000, 0x00400000, 0x40400000, }; - private static final int initPermRight3[] = { + private static final int[] initPermRight3 = { 0x00000000, 0x00000000, 0x40000000, 0x40000000, 0x00000000, 0x00000000, 0x40000000, 0x40000000, 0x00400000, 0x00400000, 0x40400000, 0x40400000, 0x00400000, 0x00400000, 0x40400000, 0x40400000, }; - private static final int initPermLeft4[] = { + private static final int[] initPermLeft4 = { 0x00000000, 0x00002000, 0x00000000, 0x00002000, 0x00000020, 0x00002020, 0x00000020, 0x00002020, 0x00000000, 0x00002000, 0x00000000, 0x00002000, 0x00000020, 0x00002020, 0x00000020, 0x00002020, }; - private static final int initPermRight4[] = { + private static final int[] initPermRight4 = { 0x00000000, 0x00000000, 0x00002000, 0x00002000, 0x00000000, 0x00000000, 0x00002000, 0x00002000, 0x00000020, 0x00000020, 0x00002020, 0x00002020, 0x00000020, 0x00000020, 0x00002020, 0x00002020, }; - private static final int initPermLeft5[] = { + private static final int[] initPermLeft5 = { 0x00000000, 0x20000000, 0x00000000, 0x20000000, 0x00200000, 0x20200000, 0x00200000, 0x20200000, 0x00000000, 0x20000000, 0x00000000, 0x20000000, 0x00200000, 0x20200000, 0x00200000, 0x20200000, }; - private static final int initPermRight5[] = { + private static final int[] initPermRight5 = { 0x00000000, 0x00000000, 0x20000000, 0x20000000, 0x00000000, 0x00000000, 0x20000000, 0x20000000, 0x00200000, 0x00200000, 0x20200000, 0x20200000, 0x00200000, 0x00200000, 0x20200000, 0x20200000, }; - private static final int initPermLeft6[] = { + private static final int[] initPermLeft6 = { 0x00000000, 0x00001000, 0x00000000, 0x00001000, 0x00000010, 0x00001010, 0x00000010, 0x00001010, 0x00000000, 0x00001000, 0x00000000, 0x00001000, 0x00000010, 0x00001010, 0x00000010, 0x00001010, }; - private static final int initPermRight6[] = { + private static final int[] initPermRight6 = { 0x00000000, 0x00000000, 0x00001000, 0x00001000, 0x00000000, 0x00000000, 0x00001000, 0x00001000, 0x00000010, 0x00000010, 0x00001010, 0x00001010, 0x00000010, 0x00000010, 0x00001010, 0x00001010, }; - private static final int initPermLeft7[] = { + private static final int[] initPermLeft7 = { 0x00000000, 0x10000000, 0x00000000, 0x10000000, 0x00100000, 0x10100000, 0x00100000, 0x10100000, 0x00000000, 0x10000000, 0x00000000, 0x10000000, 0x00100000, 0x10100000, 0x00100000, 0x10100000, }; - private static final int initPermRight7[] = { + private static final int[] initPermRight7 = { 0x00000000, 0x00000000, 0x10000000, 0x10000000, 0x00000000, 0x00000000, 0x10000000, 0x10000000, 0x00100000, 0x00100000, 0x10100000, 0x10100000, 0x00100000, 0x00100000, 0x10100000, 0x10100000, }; - private static final int initPermLeft8[] = { + private static final int[] initPermLeft8 = { 0x00000000, 0x00000800, 0x00000000, 0x00000800, 0x00000008, 0x00000808, 0x00000008, 0x00000808, 0x00000000, 0x00000800, 0x00000000, 0x00000800, 0x00000008, 0x00000808, 0x00000008, 0x00000808, }; - private static final int initPermRight8[] = { + private static final int[] initPermRight8 = { 0x00000000, 0x00000000, 0x00000800, 0x00000800, 0x00000000, 0x00000000, 0x00000800, 0x00000800, 0x00000008, 0x00000008, 0x00000808, 0x00000808, 0x00000008, 0x00000008, 0x00000808, 0x00000808, }; - private static final int initPermLeft9[] = { + private static final int[] initPermLeft9 = { 0x00000000, 0x08000000, 0x00000000, 0x08000000, 0x00080000, 0x08080000, 0x00080000, 0x08080000, 0x00000000, 0x08000000, 0x00000000, 0x08000000, 0x00080000, 0x08080000, 0x00080000, 0x08080000, }; - private static final int initPermRight9[] = { + private static final int[] initPermRight9 = { 0x00000000, 0x00000000, 0x08000000, 0x08000000, 0x00000000, 0x00000000, 0x08000000, 0x08000000, 0x00080000, 0x00080000, 0x08080000, 0x08080000, 0x00080000, 0x00080000, 0x08080000, 0x08080000, }; - private static final int initPermLeftA[] = { + private static final int[] initPermLeftA = { 0x00000000, 0x00000400, 0x00000000, 0x00000400, 0x00000004, 0x00000404, 0x00000004, 0x00000404, 0x00000000, 0x00000400, 0x00000000, 0x00000400, 0x00000004, 0x00000404, 0x00000004, 0x00000404, }; - private static final int initPermRightA[] = { + private static final int[] initPermRightA = { 0x00000000, 0x00000000, 0x00000400, 0x00000400, 0x00000000, 0x00000000, 0x00000400, 0x00000400, 0x00000004, 0x00000004, 0x00000404, 0x00000404, 0x00000004, 0x00000004, 0x00000404, 0x00000404, }; - private static final int initPermLeftB[] = { + private static final int[] initPermLeftB = { 0x00000000, 0x04000000, 0x00000000, 0x04000000, 0x00040000, 0x04040000, 0x00040000, 0x04040000, 0x00000000, 0x04000000, 0x00000000, 0x04000000, 0x00040000, 0x04040000, 0x00040000, 0x04040000, }; - private static final int initPermRightB[] = { + private static final int[] initPermRightB = { 0x00000000, 0x00000000, 0x04000000, 0x04000000, 0x00000000, 0x00000000, 0x04000000, 0x04000000, 0x00040000, 0x00040000, 0x04040000, 0x04040000, 0x00040000, 0x00040000, 0x04040000, 0x04040000, }; - private static final int initPermLeftC[] = { + private static final int[] initPermLeftC = { 0x00000000, 0x00000200, 0x00000000, 0x00000200, 0x00000002, 0x00000202, 0x00000002, 0x00000202, 0x00000000, 0x00000200, 0x00000000, 0x00000200, 0x00000002, 0x00000202, 0x00000002, 0x00000202, }; - private static final int initPermRightC[] = { + private static final int[] initPermRightC = { 0x00000000, 0x00000000, 0x00000200, 0x00000200, 0x00000000, 0x00000000, 0x00000200, 0x00000200, 0x00000002, 0x00000002, 0x00000202, 0x00000202, 0x00000002, 0x00000002, 0x00000202, 0x00000202, }; - private static final int initPermLeftD[] = { + private static final int[] initPermLeftD = { 0x00000000, 0x02000000, 0x00000000, 0x02000000, 0x00020000, 0x02020000, 0x00020000, 0x02020000, 0x00000000, 0x02000000, 0x00000000, 0x02000000, 0x00020000, 0x02020000, 0x00020000, 0x02020000, }; - private static final int initPermRightD[] = { + private static final int[] initPermRightD = { 0x00000000, 0x00000000, 0x02000000, 0x02000000, 0x00000000, 0x00000000, 0x02000000, 0x02000000, 0x00020000, 0x00020000, 0x02020000, 0x02020000, 0x00020000, 0x00020000, 0x02020000, 0x02020000, }; - private static final int initPermLeftE[] = { + private static final int[] initPermLeftE = { 0x00000000, 0x00000100, 0x00000000, 0x00000100, 0x00000001, 0x00000101, 0x00000001, 0x00000101, 0x00000000, 0x00000100, 0x00000000, 0x00000100, 0x00000001, 0x00000101, 0x00000001, 0x00000101, }; - private static final int initPermRightE[] = { + private static final int[] initPermRightE = { 0x00000000, 0x00000000, 0x00000100, 0x00000100, 0x00000000, 0x00000000, 0x00000100, 0x00000100, 0x00000001, 0x00000001, 0x00000101, 0x00000101, 0x00000001, 0x00000001, 0x00000101, 0x00000101, }; - private static final int initPermLeftF[] = { + private static final int[] initPermLeftF = { 0x00000000, 0x01000000, 0x00000000, 0x01000000, 0x00010000, 0x01010000, 0x00010000, 0x01010000, 0x00000000, 0x01000000, 0x00000000, 0x01000000, 0x00010000, 0x01010000, 0x00010000, 0x01010000, }; - private static final int initPermRightF[] = { + private static final int[] initPermRightF = { 0x00000000, 0x00000000, 0x01000000, 0x01000000, 0x00000000, 0x00000000, 0x01000000, 0x01000000, 0x00010000, 0x00010000, 0x01010000, 0x01010000, 0x00010000, 0x00010000, 0x01010000, @@ -586,7 +586,7 @@ void decryptBlock(byte[] cipher, int cipherOffset, void cipherBlock(byte[] in, int inOffset, byte[] out, int outOffset) { - byte key[]; + byte[] key; int temp; int i, j; int offset; @@ -638,7 +638,7 @@ void cipherBlock(byte[] in, int inOffset, byte[] out, int outOffset) { } private static void perm(int left, int right, - byte out[], int offset) { + byte[] out, int offset) { int low, high, temp; temp = left; @@ -687,7 +687,7 @@ private static void perm(int left, int right, } - private static int initialPermutationLeft(byte block[], int offset) { + private static int initialPermutationLeft(byte[] block, int offset) { int l; l = initPermLeft1[block[offset] & 0xf]; @@ -709,7 +709,7 @@ private static int initialPermutationLeft(byte block[], int offset) { return l; } - private static int initialPermutationRight(byte block[], int offset) { + private static int initialPermutationRight(byte[] block, int offset) { int l; l = initPermRight1[block[offset] & 0xf]; @@ -731,9 +731,9 @@ private static int initialPermutationRight(byte block[], int offset) { return l; } - void expandKey(byte key[]) { + void expandKey(byte[] key) { int octet; - byte ek[] = new byte[128]; + byte[] ek = new byte[128]; octet = key[0]; if ((octet & 0x80) != 0) { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DESKeyFactory.java b/src/java.base/share/classes/com/sun/crypto/provider/DESKeyFactory.java index fa06797abc2..fd3320b070d 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DESKeyFactory.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DESKeyFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -104,7 +104,7 @@ protected KeySpec engineGetKeySpec(SecretKey key, Class keySpec) try { - if ((key instanceof SecretKey) + if ((key != null) && (key.getAlgorithm().equalsIgnoreCase("DES")) && (key.getFormat().equalsIgnoreCase("RAW"))) { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DESedeKeyFactory.java b/src/java.base/share/classes/com/sun/crypto/provider/DESedeKeyFactory.java index fd20415bb2d..b769aab417b 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DESedeKeyFactory.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DESedeKeyFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -103,7 +103,7 @@ protected KeySpec engineGetKeySpec(SecretKey key, Class keySpec) throws InvalidKeySpecException { try { - if ((key instanceof SecretKey) + if ((key != null) && (key.getAlgorithm().equalsIgnoreCase("DESede")) && (key.getFormat().equalsIgnoreCase("RAW"))) { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DESedeKeyGenerator.java b/src/java.base/share/classes/com/sun/crypto/provider/DESedeKeyGenerator.java index 28684b0f9e7..325c0588777 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DESedeKeyGenerator.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DESedeKeyGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -130,7 +130,7 @@ protected SecretKey engineGenerateKey() { java.util.Arrays.fill(tmpkey, (byte)0x00); } - DESedeKey desEdeKey = null; + DESedeKey desEdeKey; try { desEdeKey = new DESedeKey(rawkey); } catch (InvalidKeyException ike) { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DESedeWrapCipher.java b/src/java.base/share/classes/com/sun/crypto/provider/DESedeWrapCipher.java index 92d25b57a7e..f9281ae9295 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DESedeWrapCipher.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DESedeWrapCipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -137,13 +137,13 @@ protected int engineGetBlockSize() { */ protected int engineGetOutputSize(int inputLen) { // can only return an upper-limit if not initialized yet. - int result = 0; + int result; if (decrypting) { result = inputLen - 16; // CHECKSUM_LEN + IV_LEN; } else { result = Math.addExact(inputLen, 16); } - return (result < 0? 0:result); + return (Math.max(result, 0)); } /** @@ -210,7 +210,7 @@ protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { - byte[] currIv = null; + byte[] currIv; if (opmode == Cipher.WRAP_MODE) { decrypting = false; if (params == null) { @@ -380,7 +380,7 @@ protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, /** * Returns the parameters used with this cipher. * Note that null maybe returned if this cipher does not use any - * parameters or when it has not be set, e.g. initialized with + * parameters or when it has not been set, e.g. initialized with * UNWRAP_MODE but wrapped key data has not been given. * * @return the parameters used with this cipher; can be null. @@ -556,9 +556,8 @@ protected Key engineUnwrap(byte[] wrappedKey, buffer2, 0); int keyValLen = buffer2.length - CHECKSUM_LEN; byte[] cks = getChecksum(buffer2, 0, keyValLen); - int offset = keyValLen; for (int i = 0; i < CHECKSUM_LEN; i++) { - if (buffer2[offset + i] != cks[i]) { + if (buffer2[keyValLen + i] != cks[i]) { throw new InvalidKeyException("Checksum comparison failed"); } } @@ -588,7 +587,7 @@ private static final byte[] getChecksum(byte[] in) { return getChecksum(in, 0, in.length); } private static final byte[] getChecksum(byte[] in, int offset, int len) { - MessageDigest md = null; + MessageDigest md; try { md = MessageDigest.getInstance("SHA1"); } catch (NoSuchAlgorithmException nsae) { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DHKEM.java b/src/java.base/share/classes/com/sun/crypto/provider/DHKEM.java index bd1c3f7c380..3fa6b14762a 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DHKEM.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DHKEM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,21 +24,23 @@ */ package com.sun.crypto.provider; -import sun.security.jca.JCAUtil; -import sun.security.ssl.HKDF; -import sun.security.util.*; - -import javax.crypto.*; -import javax.crypto.spec.SecretKeySpec; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.math.BigInteger; -import java.nio.charset.StandardCharsets; import java.security.*; -import java.security.interfaces.*; +import java.security.interfaces.ECKey; +import java.security.interfaces.ECPublicKey; +import java.security.interfaces.XECKey; +import java.security.interfaces.XECPublicKey; import java.security.spec.*; import java.util.Arrays; import java.util.Objects; +import javax.crypto.*; +import javax.crypto.spec.SecretKeySpec; + +import sun.security.jca.JCAUtil; +import sun.security.ssl.HKDF; +import sun.security.util.*; // Implementing DHKEM defined inside https://www.rfc-editor.org/rfc/rfc9180.html, // without the AuthEncap and AuthDecap functions diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DHKeyAgreement.java b/src/java.base/share/classes/com/sun/crypto/provider/DHKeyAgreement.java index 01f978fff61..5eebf98acc3 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DHKeyAgreement.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DHKeyAgreement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,23 +25,15 @@ package com.sun.crypto.provider; -import java.util.*; -import java.lang.*; import java.math.BigInteger; -import java.security.AccessController; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.security.PrivilegedAction; -import java.security.ProviderException; +import java.security.*; import java.security.spec.AlgorithmParameterSpec; -import java.security.spec.InvalidKeySpecException; +import java.util.Arrays; import javax.crypto.KeyAgreementSpi; -import javax.crypto.ShortBufferException; import javax.crypto.SecretKey; -import javax.crypto.spec.*; +import javax.crypto.ShortBufferException; +import javax.crypto.spec.DHParameterSpec; +import javax.crypto.spec.SecretKeySpec; import sun.security.util.KeyUtil; @@ -180,7 +172,7 @@ protected void engineInit(Key key, AlgorithmParameterSpec params, * @param key the key for this phase. For example, in the case of * Diffie-Hellman between 2 parties, this would be the other party's * Diffie-Hellman public key. - * @param lastPhase flag which indicates whether or not this is the last + * @param lastPhase flag which indicates if this is the last * phase of this key agreement. * * @return the (intermediate) key resulting from this phase, or null if @@ -227,7 +219,7 @@ protected Key engineDoPhase(Key key, boolean lastPhase) // intermediate secret, in which case we wrap it into a // Diffie-Hellman public key object and return it. generateSecret = true; - if (lastPhase == false) { + if (!lastPhase) { byte[] intermediate = engineGenerateSecret(); return new DHPublicKey(new BigInteger(1, intermediate), init_p, init_g); @@ -293,7 +285,7 @@ protected byte[] engineGenerateSecret() protected int engineGenerateSecret(byte[] sharedSecret, int offset) throws IllegalStateException, ShortBufferException { - if (generateSecret == false) { + if (!generateSecret) { throw new IllegalStateException ("Key agreement has not been completed yet"); } @@ -413,9 +405,7 @@ protected SecretKey engineGenerateSecret(String algorithm) int keysize = secret.length; if (keysize >= BlowfishConstants.BLOWFISH_MAX_KEYSIZE) keysize = BlowfishConstants.BLOWFISH_MAX_KEYSIZE; - SecretKeySpec skey = new SecretKeySpec(secret, 0, keysize, - "Blowfish"); - return skey; + return new SecretKeySpec(secret, 0, keysize, "Blowfish"); } else if (algorithm.equalsIgnoreCase("AES")) { // AES int keysize = secret.length; diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DHKeyPairGenerator.java b/src/java.base/share/classes/com/sun/crypto/provider/DHKeyPairGenerator.java index 4cc979cb29a..89d4fcfc402 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DHKeyPairGenerator.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DHKeyPairGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,11 +28,10 @@ import java.math.BigInteger; import java.security.*; import java.security.spec.AlgorithmParameterSpec; -import java.security.spec.InvalidParameterSpecException; import javax.crypto.spec.DHParameterSpec; -import javax.crypto.spec.DHGenParameterSpec; import sun.security.provider.ParameterCache; + import static sun.security.util.SecurityProviderConstants.DEF_DH_KEY_SIZE; import static sun.security.util.SecurityProviderConstants.getDefDHPrivateExpSize; diff --git a/src/java.base/share/classes/com/sun/crypto/provider/ElectronicCodeBook.java b/src/java.base/share/classes/com/sun/crypto/provider/ElectronicCodeBook.java index c2085816453..ba8a564be11 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/ElectronicCodeBook.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/ElectronicCodeBook.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,9 +27,9 @@ import java.security.InvalidKeyException; import java.security.ProviderException; -import sun.security.util.ArrayUtil; -import java.util.Objects; + import jdk.internal.vm.annotation.IntrinsicCandidate; +import sun.security.util.ArrayUtil; /** * This class represents ciphers in electronic codebook (ECB) mode. diff --git a/src/java.base/share/classes/com/sun/crypto/provider/FeedbackCipher.java b/src/java.base/share/classes/com/sun/crypto/provider/FeedbackCipher.java index 6c0e10eb6d0..985c1b81f43 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/FeedbackCipher.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/FeedbackCipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -157,7 +157,7 @@ abstract int encrypt(byte[] plain, int plainOffset, int plainLen, */ int encryptFinal(byte[] plain, int plainOffset, int plainLen, byte[] cipher, int cipherOffset) - throws IllegalBlockSizeException, ShortBufferException { + throws IllegalBlockSizeException { return encrypt(plain, plainOffset, plainLen, cipher, cipherOffset); } /** @@ -199,7 +199,7 @@ abstract int decrypt(byte[] cipher, int cipherOffset, int cipherLen, */ int decryptFinal(byte[] cipher, int cipherOffset, int cipherLen, byte[] plain, int plainOffset) - throws IllegalBlockSizeException, ShortBufferException { + throws IllegalBlockSizeException { return decrypt(cipher, cipherOffset, cipherLen, plain, plainOffset); } } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/GCTR.java b/src/java.base/share/classes/com/sun/crypto/provider/GCTR.java index 7aaec3d6c1a..926a56c140b 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/GCTR.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/GCTR.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -79,8 +79,7 @@ private long blocksUntilRollover() { ByteBuffer buf = ByteBuffer.wrap(counter, counter.length - 4, 4); buf.order(ByteOrder.BIG_ENDIAN); long ctr32 = 0xFFFFFFFFL & buf.getInt(); - long blocksLeft = (1L << 32) - ctr32; - return blocksLeft; + return (1L << 32) - ctr32; } private void checkBlock() { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/GHASH.java b/src/java.base/share/classes/com/sun/crypto/provider/GHASH.java index b7aaf6059d5..6b8c2e9c1a9 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/GHASH.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/GHASH.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -190,9 +190,8 @@ int update(ByteBuffer ct, int inLen) { // If ct is a direct bytebuffer, send it directly to the intrinsic if (ct.isDirect()) { - int processed = inLen; processBlocksDirect(ct, inLen); - return processed; + return inLen; } else if (!ct.isReadOnly()) { // If a non-read only heap bytebuffer, use the array update method int processed = update(ct.array(), @@ -273,7 +272,7 @@ private static void ghashRangeCheck(byte[] in, int inOfs, int inLen, /* * This is an intrinsified method. The method's argument list must match * the hotspot signature. This method and methods called by it, cannot - * throw exceptions or allocate arrays as it will breaking intrinsics + * throw exceptions or allocate arrays as it will break intrinsics. */ @IntrinsicCandidate private static void processBlocks(byte[] data, int inOfs, int blocks, diff --git a/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java b/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java index 8cfd7d13f12..44cfb76d162 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,38 +25,24 @@ package com.sun.crypto.provider; -import jdk.internal.access.JavaNioAccess; -import jdk.internal.access.SharedSecrets; -import jdk.internal.misc.Unsafe; -import sun.nio.ch.DirectBuffer; -import sun.security.jca.JCAUtil; -import sun.security.util.ArrayUtil; - -import javax.crypto.AEADBadTagException; -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.CipherSpi; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.ShortBufferException; -import javax.crypto.spec.GCMParameterSpec; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.nio.ByteBuffer; import java.nio.ByteOrder; -import java.security.AlgorithmParameters; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.ProviderException; -import java.security.SecureRandom; +import java.security.*; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.InvalidParameterSpecException; import java.util.Arrays; +import javax.crypto.*; +import javax.crypto.spec.GCMParameterSpec; +import jdk.internal.access.JavaNioAccess; +import jdk.internal.access.SharedSecrets; +import jdk.internal.misc.Unsafe; import jdk.internal.vm.annotation.IntrinsicCandidate; +import sun.nio.ch.DirectBuffer; +import sun.security.jca.JCAUtil; +import sun.security.util.ArrayUtil; /** * This class represents ciphers in GaloisCounter (GCM) mode. diff --git a/src/java.base/share/classes/com/sun/crypto/provider/HmacCore.java b/src/java.base/share/classes/com/sun/crypto/provider/HmacCore.java index fecc30a5a08..c6707fb9941 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/HmacCore.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/HmacCore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,16 +25,12 @@ package com.sun.crypto.provider; -import java.util.Arrays; - import java.nio.ByteBuffer; - +import java.security.*; +import java.security.spec.AlgorithmParameterSpec; +import java.util.Arrays; import javax.crypto.MacSpi; import javax.crypto.SecretKey; -import java.security.*; -import java.security.spec.*; - -import sun.security.x509.AlgorithmId; /** * This class constitutes the core of HMAC- algorithms, where @@ -87,8 +83,7 @@ abstract class HmacCore extends MacSpi implements Cloneable { break; } } - } catch (NoSuchAlgorithmException nsae) { - continue; + } catch (NoSuchAlgorithmException ignored) { } } if (md == null) { @@ -169,7 +164,7 @@ protected void engineInit(Key key, AlgorithmParameterSpec params) * @param input the input byte to be processed. */ protected void engineUpdate(byte input) { - if (first == true) { + if (first) { // compute digest for 1st pass; start with inner pad md.update(k_ipad); first = false; @@ -187,8 +182,8 @@ protected void engineUpdate(byte input) { * @param offset the offset in input where the input starts. * @param len the number of bytes to process. */ - protected void engineUpdate(byte input[], int offset, int len) { - if (first == true) { + protected void engineUpdate(byte[] input, int offset, int len) { + if (first) { // compute digest for 1st pass; start with inner pad md.update(k_ipad); first = false; @@ -205,7 +200,7 @@ protected void engineUpdate(byte input[], int offset, int len) { * @param input the input byte buffer. */ protected void engineUpdate(ByteBuffer input) { - if (first == true) { + if (first) { // compute digest for 1st pass; start with inner pad md.update(k_ipad); first = false; @@ -221,7 +216,7 @@ protected void engineUpdate(ByteBuffer input) { * @return the HMAC result. */ protected byte[] engineDoFinal() { - if (first == true) { + if (first) { // compute digest for 1st pass; start with inner pad md.update(k_ipad); } else { @@ -250,7 +245,7 @@ protected byte[] engineDoFinal() { * HMAC was initialized with. */ protected void engineReset() { - if (first == false) { + if (!first) { md.reset(); first = true; } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/HmacMD5.java b/src/java.base/share/classes/com/sun/crypto/provider/HmacMD5.java index ccf85561db9..3e85ad51bb3 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/HmacMD5.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/HmacMD5.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,12 +25,7 @@ package com.sun.crypto.provider; -import java.nio.ByteBuffer; - -import javax.crypto.MacSpi; -import javax.crypto.SecretKey; -import java.security.*; -import java.security.spec.*; +import java.security.NoSuchAlgorithmException; /** * This is an implementation of the HMAC-MD5 algorithm. diff --git a/src/java.base/share/classes/com/sun/crypto/provider/HmacMD5KeyGenerator.java b/src/java.base/share/classes/com/sun/crypto/provider/HmacMD5KeyGenerator.java index ba29e3c7479..2634128dd28 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/HmacMD5KeyGenerator.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/HmacMD5KeyGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,9 +25,8 @@ package com.sun.crypto.provider; -import java.security.SecureRandom; -import java.security.InvalidParameterException; import java.security.InvalidAlgorithmParameterException; +import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; import java.util.Arrays; import javax.crypto.KeyGeneratorSpi; diff --git a/src/java.base/share/classes/com/sun/crypto/provider/HmacSHA1.java b/src/java.base/share/classes/com/sun/crypto/provider/HmacSHA1.java index b79dc9d9658..0a17cad0ea3 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/HmacSHA1.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/HmacSHA1.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,12 +25,7 @@ package com.sun.crypto.provider; -import java.nio.ByteBuffer; - -import javax.crypto.MacSpi; -import javax.crypto.SecretKey; -import java.security.*; -import java.security.spec.*; +import java.security.NoSuchAlgorithmException; /** * This is an implementation of the HMAC-SHA1 algorithm. diff --git a/src/java.base/share/classes/com/sun/crypto/provider/HmacSHA1KeyGenerator.java b/src/java.base/share/classes/com/sun/crypto/provider/HmacSHA1KeyGenerator.java index 9d92d60ae36..19977777503 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/HmacSHA1KeyGenerator.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/HmacSHA1KeyGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,9 +25,8 @@ package com.sun.crypto.provider; -import java.security.SecureRandom; -import java.security.InvalidParameterException; import java.security.InvalidAlgorithmParameterException; +import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; import java.util.Arrays; import javax.crypto.KeyGeneratorSpi; diff --git a/src/java.base/share/classes/com/sun/crypto/provider/ISO10126Padding.java b/src/java.base/share/classes/com/sun/crypto/provider/ISO10126Padding.java index a86f313e2c9..43f15342284 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/ISO10126Padding.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/ISO10126Padding.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -119,7 +119,6 @@ public int unpad(byte[] in, int off, int len) { * @return the length of the padding */ public int padLength(int len) { - int paddingOctet = blockSize - (len % blockSize); - return paddingOctet; + return blockSize - (len % blockSize); } } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/JceKeyStore.java b/src/java.base/share/classes/com/sun/crypto/provider/JceKeyStore.java index fcc450387af..ab8f2d7097b 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/JceKeyStore.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/JceKeyStore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,7 +75,7 @@ private static final class PrivateKeyEntry { Date date; // the creation date of this entry byte[] protectedKey; Certificate[] chain; - }; + } // Secret key private static final class SecretKeyEntry { @@ -93,7 +93,7 @@ private static final class SecretKeyEntry { private static final class TrustedCertEntry { Date date; // the creation date of this entry Certificate cert; - }; + } /** * Private keys and certificates are stored in a hashtable. @@ -119,7 +119,7 @@ private static final class TrustedCertEntry { public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException, UnrecoverableKeyException { - Key key = null; + Key key; Object entry = entries.get(alias.toLowerCase(Locale.ENGLISH)); @@ -652,7 +652,7 @@ public void engineStore(OutputStream stream, char[] password) * the keystore (such as deleting or modifying key or * certificate entries). */ - byte digest[] = md.digest(); + byte[] digest = md.digest(); dos.write(digest); dos.flush(); @@ -691,8 +691,8 @@ public void engineLoad(InputStream stream, char[] password) MessageDigest md = null; CertificateFactory cf = null; Hashtable cfs = null; - ByteArrayInputStream bais = null; - byte[] encoded = null; + ByteArrayInputStream bais; + byte[] encoded; int trustedKeyCount = 0, privateKeyCount = 0, secretKeyCount = 0; if (stream == null) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/KWUtil.java b/src/java.base/share/classes/com/sun/crypto/provider/KWUtil.java index 7892ca198a8..e5dc8920326 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/KWUtil.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/KWUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,10 +26,6 @@ package com.sun.crypto.provider; import java.util.Arrays; -import java.security.*; -import java.security.spec.*; -import javax.crypto.*; -import javax.crypto.spec.*; /** * This class acts as the base class for AES KeyWrap algorithms as defined @@ -58,7 +54,7 @@ static final int W(byte[] icvIn, byte[] in, int inLen, ("Invalid data length for W: " + inLen); assert(icvIn.length == SEMI_BLKSIZE) : "Invalid ICV buffer size"; - // overwrite the first block of in with the icv semiblock + // overwrite the first block of in with the icv semi-block System.arraycopy(icvIn, 0, in, 0, SEMI_BLKSIZE); int n = inLen / SEMI_BLKSIZE - 1; @@ -93,7 +89,7 @@ static final int W(byte[] icvIn, byte[] in, int inLen, * data until the initial value and padding bytes are verified. * @param in input bytes, i.e. the to-be-processed data * @param inLen length of the to-be-processed bytes - * @param ivOut buffer for holding the recovered ICV semiblock + * @param ivOut buffer for holding the recovered ICV semi-block * @param cipher the initialized cipher object used * @return the recovered data length, i.e. {@code (inLen - icvOut.length)} */ diff --git a/src/java.base/share/classes/com/sun/crypto/provider/KeyProtector.java b/src/java.base/share/classes/com/sun/crypto/provider/KeyProtector.java index eadc032b36a..f2d3efd685c 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/KeyProtector.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/KeyProtector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -98,7 +98,7 @@ final class KeyProtector { iterationCount > MAX_ITERATION_COUNT) { iterationCount = DEFAULT_ITERATION_COUNT; } - } catch (NumberFormatException e) {} + } catch (NumberFormatException ignored) {} } ITERATION_COUNT = iterationCount; } @@ -369,7 +369,7 @@ Key unseal(SealedObject so, int maxLength) sKey = new PBEKey(pbeKeySpec, "PBEWithMD5AndTripleDES"); pbeKeySpec.clearPassword(); - SealedObjectForKeyProtector soForKeyProtector = null; + SealedObjectForKeyProtector soForKeyProtector; if (!(so instanceof SealedObjectForKeyProtector)) { soForKeyProtector = new SealedObjectForKeyProtector(so); } else { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/KeyWrapCipher.java b/src/java.base/share/classes/com/sun/crypto/provider/KeyWrapCipher.java index dfd2ec2b04b..fb69a27c62d 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/KeyWrapCipher.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/KeyWrapCipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -285,7 +285,7 @@ protected int engineGetOutputSize(int inLen) { padLen = SEMI_BLKSIZE - n; } } - // then add the first semiblock and padLen to result + // then add the first semi-block and padLen to result result = Math.addExact(result, SEMI_BLKSIZE + padLen); } else { result = inLen - SEMI_BLKSIZE; @@ -339,7 +339,7 @@ private void implInit(int opmode, Key key, byte[] iv, SecureRandom random) protected void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException { try { - implInit(opmode, key, (byte[])null, random); + implInit(opmode, key, null, random); } catch (InvalidAlgorithmParameterException iae) { // should never happen throw new AssertionError(iae); @@ -394,9 +394,9 @@ protected void engineInit(int opmode, Key key, AlgorithmParameters params, byte[] iv = null; if (params != null) { try { - AlgorithmParameterSpec spec = + IvParameterSpec spec = params.getParameterSpec(IvParameterSpec.class); - iv = ((IvParameterSpec)spec).getIV(); + iv = spec.getIV(); } catch (InvalidParameterSpecException ispe) { throw new InvalidAlgorithmParameterException( "Only IvParameterSpec is accepted"); @@ -462,7 +462,7 @@ private void implUpdate(byte[] in, int inOfs, int inLen) { if (inLen <= 0) return; if (opmode == Cipher.ENCRYPT_MODE && dataIdx == 0) { - // the first semiblock is for iv, store data after it + // the first semi-block is for iv, store data after it dataIdx = SEMI_BLKSIZE; } store(in, inOfs, inLen); @@ -595,8 +595,8 @@ private int implDoFinal(byte[] in, int inOfs, int inLen, byte[] out) } // helper routine for in-place encryption. - // 'inBuf' = semiblock | plain text | extra bytes if padding is used - // 'inLen' = semiblock length + plain text length + // 'inBuf' = semi-block | plain text | extra bytes if padding is used + // 'inLen' = semi-block length + plain text length private int helperEncrypt(byte[] inBuf, int inLen) throws IllegalBlockSizeException, ShortBufferException { @@ -646,7 +646,7 @@ private int helperDecrypt(byte[] inBuf, int inLen) */ @Override protected AlgorithmParameters engineGetParameters() { - AlgorithmParameters params = null; + AlgorithmParameters params; byte[] iv = cipher.getIV(); if (iv == null) { @@ -711,7 +711,7 @@ protected byte[] engineWrap(Key key) // output size is known, allocate output buffer byte[] out = new byte[engineGetOutputSize(encoded.length)]; - // reserve the first semiblock and do not write data + // reserve the first semi-block and do not write data int len = SEMI_BLKSIZE; System.arraycopy(encoded, 0, out, len, encoded.length); len += encoded.length; diff --git a/src/java.base/share/classes/com/sun/crypto/provider/OAEPParameters.java b/src/java.base/share/classes/com/sun/crypto/provider/OAEPParameters.java index 9d724728893..3b826aa38f2 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/OAEPParameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/OAEPParameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -225,11 +225,9 @@ protected byte[] engineGetEncoded(String encodingMethod) } protected String engineToString() { - StringBuilder sb = new StringBuilder(); - sb.append("MD: " + mdName + "\n"); - sb.append("MGF: MGF1" + mgfSpec.getDigestAlgorithm() + "\n"); - sb.append("PSource: PSpecified " + - (p.length==0? "":Debug.toHexString(new BigInteger(p))) + "\n"); - return sb.toString(); + return "MD: " + mdName + "\n" + + "MGF: MGF1" + mgfSpec.getDigestAlgorithm() + "\n" + + "PSource: PSpecified " + + (p.length == 0 ? "" : Debug.toHexString(new BigInteger(p))) + "\n"; } } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/OutputFeedback.java b/src/java.base/share/classes/com/sun/crypto/provider/OutputFeedback.java index aa56144f090..414659fcf3d 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/OutputFeedback.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/OutputFeedback.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,7 +53,7 @@ final class OutputFeedback extends FeedbackCipher { private final byte[] register; /* - * number of bytes for each stream unit, defaults to the blocksize + * number of bytes for each stream unit, defaults to the block size * of the embedded cipher */ private final int numBytes; diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBEKeyFactory.java b/src/java.base/share/classes/com/sun/crypto/provider/PBEKeyFactory.java index 02451e536c6..da73d0bc7ce 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBEKeyFactory.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBEKeyFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -261,7 +261,7 @@ protected SecretKey engineGenerateSecret(KeySpec keySpec) */ protected KeySpec engineGetKeySpec(SecretKey key, Class keySpecCl) throws InvalidKeySpecException { - if ((key instanceof SecretKey) + if ((key != null) && (validTypes.contains(key.getAlgorithm().toUpperCase(Locale.ENGLISH))) && (key.getFormat().equalsIgnoreCase("RAW"))) { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBES1Core.java b/src/java.base/share/classes/com/sun/crypto/provider/PBES1Core.java index 68b1771d7d9..e10b0b1a7cf 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBES1Core.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBES1Core.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -161,7 +161,7 @@ byte[] getIV() { * does not use any parameters. */ AlgorithmParameters getParameters() { - AlgorithmParameters params = null; + AlgorithmParameters params; if (salt == null) { salt = new byte[8]; SunJCE.getRandom().nextBytes(salt); @@ -303,7 +303,7 @@ private byte[] deriveCipherKey(byte[] passwdBytes) { // Concatenate the output from each digest round with the // password, and use the result as the input to the next digest // operation. - byte[] toBeHashed = null; + byte[] toBeHashed; result = new byte[DESedeKeySpec.DES_EDE_KEY_LEN + DESConstants.DES_BLOCK_SIZE]; for (i = 0; i < 2; i++) { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java b/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java index fb3dfa00148..d6b7d00d360 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -131,8 +131,8 @@ abstract class PBES2Parameters extends AlgorithmParametersSpi { PBES2Parameters(String pbes2AlgorithmName) throws NoSuchAlgorithmException { int and; - String kdfAlgo = null; - String cipherAlgo = null; + String kdfAlgo; + String cipherAlgo; // Extract the KDF and encryption algorithm names this.pbes2AlgorithmName = pbes2AlgorithmName; @@ -210,9 +210,6 @@ protected void engineInit(AlgorithmParameterSpec paramSpec) protected void engineInit(byte[] encoded) throws IOException { - String kdfAlgo = null; - String cipherAlgo = null; - DerValue pBES2_params = new DerValue(encoded); if (pBES2_params.tag != DerValue.tag_Sequence) { throw new IOException("PBE parameter parsing error: " @@ -231,16 +228,15 @@ protected void engineInit(byte[] encoded) kdf = pBES2_params.data.getDerValue(); } - kdfAlgo = parseKDF(kdf); + String kdfAlgo = parseKDF(kdf); if (pBES2_params.tag != DerValue.tag_Sequence) { throw new IOException("PBE parameter parsing error: " + "not an ASN.1 SEQUENCE tag"); } - cipherAlgo = parseES(pBES2_params.data.getDerValue()); + String cipherAlgo = parseES(pBES2_params.data.getDerValue()); - this.pbes2AlgorithmName = new StringBuilder().append("PBEWith") - .append(kdfAlgo).append("And").append(cipherAlgo).toString(); + this.pbes2AlgorithmName = "PBEWith" + kdfAlgo + "And" + cipherAlgo; } @SuppressWarnings("deprecation") @@ -305,7 +301,7 @@ private String parseKDF(DerValue keyDerivationFunc) throws IOException { @SuppressWarnings("deprecation") private String parseES(DerValue encryptionScheme) throws IOException { - String cipherAlgo = null; + String cipherAlgo; cipherAlgo_OID = encryptionScheme.data.getOID(); if (aes128CBC_OID.equals(cipherAlgo_OID)) { @@ -399,7 +395,7 @@ protected byte[] engineGetEncoded(String encodingMethod) /* * Returns a formatted string describing the parameters. * - * The algorithn name pattern is: "PBEWithAnd" + * The algorithm name pattern is: "PBEWithAnd" * where is one of: HmacSHA1, HmacSHA224, HmacSHA256, HmacSHA384, * HmacSHA512, HmacSHA512/224, or HmacSHA512/256 and is * AES with a keysize suffix. diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java b/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java index a02ce2d1551..c8b9c392a4b 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,26 +25,29 @@ package com.sun.crypto.provider; -import java.io.*; -import java.lang.ref.Reference; +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; +import java.io.ObjectStreamException; import java.lang.ref.Cleaner; +import java.lang.ref.Reference; import java.nio.ByteBuffer; import java.nio.CharBuffer; -import java.util.Arrays; -import java.util.Locale; -import java.security.MessageDigest; -import java.security.KeyRep; import java.security.GeneralSecurityException; +import java.security.KeyRep; +import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.spec.InvalidKeySpecException; +import java.util.Arrays; +import java.util.Locale; import javax.crypto.Mac; import javax.crypto.SecretKey; import javax.crypto.spec.PBEKeySpec; -import static java.nio.charset.StandardCharsets.UTF_8; - import jdk.internal.ref.CleanerFactory; +import static java.nio.charset.StandardCharsets.UTF_8; + /** * This class represents a PBE key derived using PBKDF2 defined * in PKCS#5 v2.0. meaning that diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java index 56059a89264..146999e35ce 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,7 +61,7 @@ abstract class PBMAC1Core extends HmacCore { } private static PBKDF2Core getKDFImpl(String algo) { - PBKDF2Core kdf = null; + PBKDF2Core kdf; switch(algo) { case "HmacSHA1": kdf = new PBKDF2Core.HmacSHA1(); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PKCS5Padding.java b/src/java.base/share/classes/com/sun/crypto/provider/PKCS5Padding.java index af072c6f5d7..a8ba711d658 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PKCS5Padding.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PKCS5Padding.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -120,7 +120,6 @@ public int unpad(byte[] in, int off, int len) { * @return the length of the padding */ public int padLength(int len) { - int paddingOctet = blockSize - (len % blockSize); - return paddingOctet; + return blockSize - (len % blockSize); } } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/Poly1305.java b/src/java.base/share/classes/com/sun/crypto/provider/Poly1305.java index 1752bb8dddd..1473cf4aba1 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/Poly1305.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/Poly1305.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,16 +26,18 @@ package com.sun.crypto.provider; import java.nio.ByteBuffer; -import java.security.Key; import java.security.InvalidKeyException; +import java.security.Key; import java.security.spec.AlgorithmParameterSpec; import java.util.Arrays; import java.util.Objects; -import sun.security.util.math.*; -import sun.security.util.math.intpoly.*; -import jdk.internal.vm.annotation.IntrinsicCandidate; import jdk.internal.vm.annotation.ForceInline; +import jdk.internal.vm.annotation.IntrinsicCandidate; +import sun.security.util.math.IntegerFieldModuloP; +import sun.security.util.math.IntegerModuloP; +import sun.security.util.math.MutableIntegerModuloP; +import sun.security.util.math.intpoly.IntegerPolynomial1305; /** * This class represents the Poly1305 function defined in RFC 7539. diff --git a/src/java.base/share/classes/com/sun/crypto/provider/RC2Crypt.java b/src/java.base/share/classes/com/sun/crypto/provider/RC2Crypt.java index aa3100c1b7d..78f25f33b2d 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/RC2Crypt.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/RC2Crypt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -108,7 +108,7 @@ void initEffectiveKeyBits(int effectiveKeyBits) { static void checkKey(String algorithm, int keyLength) throws InvalidKeyException { - if (algorithm.equals("RC2") == false) { + if (!algorithm.equals("RC2")) { throw new InvalidKeyException("Key algorithm must be RC2"); } if ((keyLength < 5) || (keyLength > 128)) { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java b/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java index df76f78bfb5..b48917e7557 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ import java.security.spec.AlgorithmParameterSpec; import java.security.spec.InvalidParameterSpecException; import java.security.spec.MGF1ParameterSpec; +import java.util.Objects; import javax.crypto.*; import javax.crypto.spec.PSource; @@ -126,7 +127,7 @@ public RSACipher() { // modes do not make sense for RSA, but allow ECB // see JCE spec protected void engineSetMode(String mode) throws NoSuchAlgorithmException { - if (mode.equalsIgnoreCase("ECB") == false) { + if (!mode.equalsIgnoreCase("ECB")) { throw new NoSuchAlgorithmException("Unsupported mode " + mode); } } @@ -468,7 +469,7 @@ protected Key engineUnwrap(byte[] wrappedKey, String algorithm, boolean isTlsRsaPremasterSecret = algorithm.equals("TlsRsaPremasterSecret"); - byte[] encoded = null; + byte[] encoded; update(wrappedKey, 0, wrappedKey.length); try { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/SslMacCore.java b/src/java.base/share/classes/com/sun/crypto/provider/SslMacCore.java index 057c139b594..0d25c0064c4 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/SslMacCore.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/SslMacCore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,11 +26,10 @@ package com.sun.crypto.provider; import java.nio.ByteBuffer; - -import javax.crypto.MacSpi; -import javax.crypto.SecretKey; import java.security.*; import java.security.spec.AlgorithmParameterSpec; +import javax.crypto.MacSpi; +import javax.crypto.SecretKey; import static com.sun.crypto.provider.TlsPrfGenerator.genPad; @@ -109,7 +108,7 @@ void init(Key key, AlgorithmParameterSpec params) * @param input the input byte to be processed. */ void update(byte input) { - if (first == true) { + if (first) { // compute digest for 1st pass; start with inner pad md.update(secret); md.update(pad1); @@ -128,8 +127,8 @@ void update(byte input) { * @param offset the offset in input where the input starts. * @param len the number of bytes to process. */ - void update(byte input[], int offset, int len) { - if (first == true) { + void update(byte[] input, int offset, int len) { + if (first) { // compute digest for 1st pass; start with inner pad md.update(secret); md.update(pad1); @@ -141,7 +140,7 @@ void update(byte input[], int offset, int len) { } void update(ByteBuffer input) { - if (first == true) { + if (first) { // compute digest for 1st pass; start with inner pad md.update(secret); md.update(pad1); @@ -158,7 +157,7 @@ void update(ByteBuffer input) { * @return the Mac result. */ byte[] doFinal() { - if (first == true) { + if (first) { // compute digest for 1st pass; start with inner pad md.update(secret); md.update(pad1); @@ -189,7 +188,7 @@ byte[] doFinal() { * Mac was initialized with. */ void reset() { - if (first == false) { + if (!first) { md.reset(); first = true; } @@ -211,7 +210,7 @@ protected void engineInit(Key key, AlgorithmParameterSpec params) protected void engineUpdate(byte input) { core.update(input); } - protected void engineUpdate(byte input[], int offset, int len) { + protected void engineUpdate(byte[] input, int offset, int len) { core.update(input, offset, len); } protected void engineUpdate(ByteBuffer input) { @@ -244,7 +243,7 @@ protected void engineInit(Key key, AlgorithmParameterSpec params) protected void engineUpdate(byte input) { core.update(input); } - protected void engineUpdate(byte input[], int offset, int len) { + protected void engineUpdate(byte[] input, int offset, int len) { core.update(input, offset, len); } protected void engineUpdate(ByteBuffer input) { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java b/src/java.base/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java index 56e4dd97663..2440b45a2ae 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,11 +62,11 @@ protected void engineInit(SecureRandom random) { @SuppressWarnings("deprecation") protected void engineInit(AlgorithmParameterSpec params, SecureRandom random) throws InvalidAlgorithmParameterException { - if (params instanceof TlsKeyMaterialParameterSpec == false) { + if (!(params instanceof TlsKeyMaterialParameterSpec)) { throw new InvalidAlgorithmParameterException(MSG); } this.spec = (TlsKeyMaterialParameterSpec)params; - if ("RAW".equals(spec.getMasterSecret().getFormat()) == false) { + if (!"RAW".equals(spec.getMasterSecret().getFormat())) { throw new InvalidAlgorithmParameterException( "Key format must be RAW"); } @@ -105,8 +105,6 @@ private SecretKey engineGenerateKey0(byte[] masterSecret) throws GeneralSecurity SecretKey clientMacKey = null; SecretKey serverMacKey = null; - SecretKey clientCipherKey = null; - SecretKey serverCipherKey = null; IvParameterSpec clientIv = null; IvParameterSpec serverIv = null; @@ -194,8 +192,10 @@ private SecretKey engineGenerateKey0(byte[] masterSecret) throws GeneralSecurity System.arraycopy(keyBlock, ofs, serverKeyBytes, 0, keyLength); ofs += keyLength; + SecretKey clientCipherKey; + SecretKey serverCipherKey; try { - if (isExportable == false) { + if (!isExportable) { // cipher keys clientCipherKey = new SecretKeySpec(clientKeyBytes, alg); serverCipherKey = new SecretKeySpec(serverKeyBytes, alg); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java b/src/java.base/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java index 1102f4b94ee..f8f733b6d2f 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -132,12 +132,12 @@ protected void engineInit(SecureRandom random) { @SuppressWarnings("deprecation") protected void engineInit(AlgorithmParameterSpec params, SecureRandom random) throws InvalidAlgorithmParameterException { - if (params instanceof TlsPrfParameterSpec == false) { + if (!(params instanceof TlsPrfParameterSpec)) { throw new InvalidAlgorithmParameterException(MSG); } this.spec = (TlsPrfParameterSpec)params; SecretKey key = spec.getSecret(); - if ((key != null) && ("RAW".equals(key.getFormat()) == false)) { + if ((key != null) && (!"RAW".equals(key.getFormat()))) { throw new InvalidAlgorithmParameterException( "Key encoding format must be RAW"); } @@ -378,7 +378,7 @@ private static void expand(MessageDigest digest, int hmacSize, * TLS 1.2 uses a different hash algorithm than 1.0/1.1 for the PRF * calculations. As of 2010, there is no PKCS11-level support for TLS * 1.2 PRF calculations, and no known OS's have an internal variant - * we could use. Therefore for TLS 1.2, we are updating JSSE to request + * we could use. Therefore, for TLS 1.2, we are updating JSSE to request * a different provider algorithm: "SunTls12Prf". If we reused the * name "SunTlsPrf", the PKCS11 provider would need be updated to * fail correctly when presented with the wrong version number From dcf4e0d51f392afe2711223484e932e3826e8864 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Wed, 10 Jul 2024 03:30:19 +0000 Subject: [PATCH 027/460] 8335966: Remove incorrect problem listing of java/lang/instrument/NativeMethodPrefixAgent.java in ProblemList-Virtual.txt Reviewed-by: kevinw, amenkov --- test/jdk/ProblemList-Virtual.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/jdk/ProblemList-Virtual.txt b/test/jdk/ProblemList-Virtual.txt index c45353e65ed..d7692b578cd 100644 --- a/test/jdk/ProblemList-Virtual.txt +++ b/test/jdk/ProblemList-Virtual.txt @@ -36,8 +36,6 @@ javax/management/remote/mandatory/loading/MissingClassTest.java 8145413 windows- javax/management/remote/mandatory/loading/RMIDownloadTest.java 8308366 windows-x64 -java/lang/instrument/NativeMethodPrefixAgent.java 8307169 generic-all - java/lang/ScopedValue/StressStackOverflow.java#default 8309646 generic-all java/lang/ScopedValue/StressStackOverflow.java#no-TieredCompilation 8309646 generic-all java/lang/ScopedValue/StressStackOverflow.java#TieredStopAtLevel1 8309646 generic-all From b5909cabeef22954f4d9c642b1cbf288b3454562 Mon Sep 17 00:00:00 2001 From: Koichi Sakata Date: Wed, 10 Jul 2024 05:57:11 +0000 Subject: [PATCH 028/460] 8323242: Remove vestigial DONT_USE_REGISTER_DEFINES Reviewed-by: gli, kvn --- src/hotspot/cpu/zero/register_zero.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/hotspot/cpu/zero/register_zero.hpp b/src/hotspot/cpu/zero/register_zero.hpp index 1b6f52879ef..fd30f206762 100644 --- a/src/hotspot/cpu/zero/register_zero.hpp +++ b/src/hotspot/cpu/zero/register_zero.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright 2007 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -114,8 +114,6 @@ class ConcreteRegisterImpl : public AbstractRegisterImpl { }; CONSTANT_REGISTER_DECLARATION(Register, noreg, (-1)); -#ifndef DONT_USE_REGISTER_DEFINES #define noreg ((Register)(noreg_RegisterEnumValue)) -#endif #endif // CPU_ZERO_REGISTER_ZERO_HPP From a44b60c8c14ad998e51239f48e64779304aaac50 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 10 Jul 2024 07:53:52 +0000 Subject: [PATCH 029/460] 8335778: runtime/ClassInitErrors/TestStackOverflowDuringInit.java fails on ppc64 platforms after JDK-8334545 Reviewed-by: dholmes, asteiner --- .../runtime/ClassInitErrors/TestStackOverflowDuringInit.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/runtime/ClassInitErrors/TestStackOverflowDuringInit.java b/test/hotspot/jtreg/runtime/ClassInitErrors/TestStackOverflowDuringInit.java index 3917abe85ad..180dc539795 100644 --- a/test/hotspot/jtreg/runtime/ClassInitErrors/TestStackOverflowDuringInit.java +++ b/test/hotspot/jtreg/runtime/ClassInitErrors/TestStackOverflowDuringInit.java @@ -31,7 +31,7 @@ * @requires vm.flagless * @comment Run with the smallest stack possible to limit the execution time. * This is the smallest stack that is supported by all platforms. - * @run main/othervm -Xss240K -Xint TestStackOverflowDuringInit + * @run main/othervm -Xss384K -Xint TestStackOverflowDuringInit */ import java.io.ByteArrayOutputStream; From 537d20afbff255489a7b1bdb0410b9d1aba715b7 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Wed, 10 Jul 2024 09:55:56 +0000 Subject: [PATCH 030/460] 8335766: Switch case with pattern matching and guard clause compiles inconsistently Reviewed-by: abimpoudis --- .../com/sun/tools/javac/parser/JavacParser.java | 10 +++++++++- .../tools/javac/patterns/DisambiguatePatterns.java | 6 +++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java index ef2d71831dc..f570ad54c58 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -3436,7 +3436,15 @@ PatternResult analyzePattern(int lookahead) { : PatternResult.PATTERN; } parenDepth++; break; - case RPAREN: parenDepth--; break; + case RPAREN: + parenDepth--; + if (parenDepth == 0 && + typeDepth == 0 && + peekToken(lookahead, TokenKind.IDENTIFIER) && + S.token(lookahead + 1).name() == names.when) { + return PatternResult.PATTERN; + } + break; case ARROW: return parenDepth > 0 ? PatternResult.EXPRESSION : pendingResult; case FINAL: diff --git a/test/langtools/tools/javac/patterns/DisambiguatePatterns.java b/test/langtools/tools/javac/patterns/DisambiguatePatterns.java index ef4d065f912..d6180c1810f 100644 --- a/test/langtools/tools/javac/patterns/DisambiguatePatterns.java +++ b/test/langtools/tools/javac/patterns/DisambiguatePatterns.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -109,6 +109,10 @@ public static void main(String... args) throws Throwable { ExpressionType.EXPRESSION); test.disambiguationTest("a & b", ExpressionType.EXPRESSION); + test.disambiguationTest("R r when (x > 0)", + ExpressionType.PATTERN); + test.disambiguationTest("R(int x) when (x > 0)", + ExpressionType.PATTERN); } private final ParserFactory factory; From e0fb949460d0c7e2ab1697a6466e7d4831a20a33 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Wed, 10 Jul 2024 14:28:20 +0000 Subject: [PATCH 031/460] 8335779: JFR: Hide sleep events Reviewed-by: mgronlun --- .../share/jfr/support/jfrIntrinsics.hpp | 2 +- src/hotspot/share/runtime/objectMonitor.cpp | 2 +- .../share/classes/jdk/jfr/internal/JVM.java | 1 + .../classes/jdk/jfr/internal/JVMSupport.java | 4 +- .../jdk/jfr/internal/MetadataRepository.java | 4 +- .../jfr/internal/consumer/OngoingStream.java | 16 ++-- .../jfr/internal/consumer/RecordingInput.java | 7 +- .../internal/consumer/RepositoryFiles.java | 19 ++-- .../internal/{ => management}/HiddenWait.java | 12 ++- .../internal/management/StreamBarrier.java | 48 ++++++---- .../classes/jdk/jfr/internal/util/Utils.java | 23 +---- .../jdk/management/jfr/DownLoadThread.java | 14 +-- .../classes/jdk/management/jfr/FileDump.java | 52 ++++++----- test/jdk/jdk/jfr/jvm/TestHiddenWait.java | 88 +++++++++++++++++++ 14 files changed, 192 insertions(+), 100 deletions(-) rename src/jdk.jfr/share/classes/jdk/jfr/internal/{ => management}/HiddenWait.java (82%) create mode 100644 test/jdk/jdk/jfr/jvm/TestHiddenWait.java diff --git a/src/hotspot/share/jfr/support/jfrIntrinsics.hpp b/src/hotspot/share/jfr/support/jfrIntrinsics.hpp index 6520f3cb00c..77affc69926 100644 --- a/src/hotspot/share/jfr/support/jfrIntrinsics.hpp +++ b/src/hotspot/share/jfr/support/jfrIntrinsics.hpp @@ -47,7 +47,7 @@ class JfrIntrinsicSupport : AllStatic { #define JFR_HAVE_INTRINSICS #define JFR_TEMPLATES(template) \ - template(jdk_jfr_internal_HiddenWait, "jdk/jfr/internal/HiddenWait") \ + template(jdk_jfr_internal_management_HiddenWait, "jdk/jfr/internal/management/HiddenWait") \ template(jdk_jfr_internal_JVM, "jdk/jfr/internal/JVM") \ template(jdk_jfr_internal_event_EventWriterFactory, "jdk/jfr/internal/event/EventWriterFactory") \ template(jdk_jfr_internal_event_EventConfiguration_signature, "Ljdk/jfr/internal/event/EventConfiguration;") \ diff --git a/src/hotspot/share/runtime/objectMonitor.cpp b/src/hotspot/share/runtime/objectMonitor.cpp index ba463231592..c509ed691cd 100644 --- a/src/hotspot/share/runtime/objectMonitor.cpp +++ b/src/hotspot/share/runtime/objectMonitor.cpp @@ -1442,7 +1442,7 @@ bool ObjectMonitor::check_owner(TRAPS) { static inline bool is_excluded(const Klass* monitor_klass) { assert(monitor_klass != nullptr, "invariant"); NOT_JFR_RETURN_(false); - JFR_ONLY(return vmSymbols::jdk_jfr_internal_HiddenWait() == monitor_klass->name();) + JFR_ONLY(return vmSymbols::jdk_jfr_internal_management_HiddenWait() == monitor_klass->name();) } static void post_monitor_wait_event(EventJavaMonitorWait* event, diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java index 2e600c8c029..cc0ee05a948 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java @@ -31,6 +31,7 @@ import jdk.jfr.Event; import jdk.jfr.internal.event.EventConfiguration; import jdk.jfr.internal.event.EventWriter; +import jdk.jfr.internal.management.HiddenWait; /** * Interface against the JVM. diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMSupport.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMSupport.java index 114052ecea2..7fde28a3d21 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMSupport.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMSupport.java @@ -30,6 +30,7 @@ import jdk.jfr.Recording; import jdk.jfr.internal.event.EventConfiguration; +import jdk.jfr.internal.management.HiddenWait; import jdk.jfr.internal.util.Utils; import jdk.jfr.internal.util.ValueFormatter; @@ -118,7 +119,8 @@ private static void awaitUniqueTimestamp() { lastTimestamp = time; return; } - Utils.takeNap(1); + HiddenWait hiddenWait = new HiddenWait(); + hiddenWait.takeNap(1); } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java index 4a7bc734d75..49afd0082d8 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java @@ -47,6 +47,7 @@ import jdk.jfr.ValueDescriptor; import jdk.jfr.internal.consumer.RepositoryFiles; import jdk.jfr.internal.event.EventConfiguration; +import jdk.jfr.internal.management.HiddenWait; import jdk.jfr.internal.periodic.PeriodicEvents; import jdk.jfr.internal.util.Utils; @@ -57,6 +58,7 @@ public final class MetadataRepository { private final Map nativeEventTypes = LinkedHashMap.newHashMap(150); private final Map nativeControls = LinkedHashMap.newHashMap(150); private final SettingsManager settingsManager = new SettingsManager(); + private final HiddenWait threadSleeper = new HiddenWait(); private Constructor cachedEventConfigurationConstructor; private boolean staleMetadata = true; private boolean unregistered; @@ -341,7 +343,7 @@ private void awaitEpochMilliShift() { lastMillis = millis; return; } - Utils.takeNap(1); + threadSleeper.takeNap(1); } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/OngoingStream.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/OngoingStream.java index 1816d00f345..e0dd7fa2ad8 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/OngoingStream.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/OngoingStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ import jdk.jfr.internal.SecuritySupport; import jdk.jfr.internal.SecuritySupport.SafePath; import jdk.jfr.internal.management.EventByteStream; +import jdk.jfr.internal.management.HiddenWait; import jdk.jfr.internal.management.ManagementSupport; public final class OngoingStream extends EventByteStream { @@ -44,6 +45,7 @@ public final class OngoingStream extends EventByteStream { private final RepositoryFiles repositoryFiles; private final Recording recording; + private final HiddenWait threadSleeper = new HiddenWait(); private final int blockSize; private final long endTimeNanos; private final byte[] headerBytes = new byte[HEADER_SIZE]; @@ -195,19 +197,13 @@ private byte[] readWithHeader(int size) throws IOException { return bytes; } } - takeNap(); + if (!threadSleeper.takeNap(10)) { + throw new IOException("Read operation interrupted"); + } } return EMPTY_ARRAY; } - private void takeNap() throws IOException { - try { - Thread.sleep(10); - } catch (InterruptedException ie) { - throw new IOException("Read operation interrupted", ie); - } - } - private boolean ensureInput() throws IOException { if (input == null) { if (SecuritySupport.getFileSize(new SafePath(path)) < HEADER_SIZE) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RecordingInput.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RecordingInput.java index 90a03130f49..69ec73f57fd 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RecordingInput.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RecordingInput.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,8 @@ import java.io.IOException; import java.io.RandomAccessFile; import java.nio.file.Path; + +import jdk.jfr.internal.management.HiddenWait; import jdk.jfr.internal.util.Utils; public final class RecordingInput implements DataInput, AutoCloseable { @@ -67,6 +69,7 @@ public void reset() { } private final int blockSize; private final FileAccess fileAccess; + private final HiddenWait threadSleeper = new HiddenWait(); private long pollCount = 1000; private RandomAccessFile file; private String filename; @@ -453,6 +456,6 @@ public void pollWait() throws IOException { if (pollCount < 0) { throw new IOException("Recording file is stuck in locked stream state."); } - Utils.takeNap(1); + threadSleeper.takeNap(1); } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RepositoryFiles.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RepositoryFiles.java index 6ef88ecad37..3f0611f9981 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RepositoryFiles.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RepositoryFiles.java @@ -46,9 +46,10 @@ import jdk.jfr.internal.Logger; import jdk.jfr.internal.Repository; import jdk.jfr.internal.SecuritySupport.SafePath; +import jdk.jfr.internal.management.HiddenWait;; public final class RepositoryFiles { - private static final Object WAIT_OBJECT = new Object(); + private static final HiddenWait WAIT_OBJECT = new HiddenWait(); private static final String DIRECTORY_PATTERN = "DDDD_DD_DD_DD_DD_DD_"; public static void notifyNewFile() { synchronized (WAIT_OBJECT) { @@ -59,7 +60,7 @@ public static void notifyNewFile() { private final FileAccess fileAccess; private final NavigableMap pathSet = new TreeMap<>(); private final Map pathLookup = new HashMap<>(); - private final Object waitObject; + private final HiddenWait waitObject; private boolean allowSubDirectory; private volatile boolean closed; private Path repository; @@ -67,7 +68,7 @@ public static void notifyNewFile() { public RepositoryFiles(FileAccess fileAccess, Path repository, boolean allowSubDirectory) { this.repository = repository; this.fileAccess = fileAccess; - this.waitObject = repository == null ? WAIT_OBJECT : new Object(); + this.waitObject = repository == null ? WAIT_OBJECT : new HiddenWait(); this.allowSubDirectory = allowSubDirectory; } @@ -108,7 +109,7 @@ private boolean updatePaths(boolean wait) { // was accessed. Just ignore, and retry later. } if (wait) { - nap(); + waitObject.takeNap(1000); } else { return pathLookup.size() > beforeSize; } @@ -157,16 +158,6 @@ private Path path(long timestamp, boolean wait) { } } - private void nap() { - try { - synchronized (waitObject) { - waitObject.wait(1000); - } - } catch (InterruptedException e) { - // ignore - } - } - private boolean updatePaths() throws IOException, DirectoryIteratorException { boolean foundNew = false; Path repoPath = repository; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/HiddenWait.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/management/HiddenWait.java similarity index 82% rename from src/jdk.jfr/share/classes/jdk/jfr/internal/HiddenWait.java rename to src/jdk.jfr/share/classes/jdk/jfr/internal/management/HiddenWait.java index 26505990332..9070faad5a6 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/HiddenWait.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/management/HiddenWait.java @@ -22,11 +22,21 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jfr.internal; +package jdk.jfr.internal.management; /** * The HiddenWait class is used to exclude jdk.JavaMonitorWait events * from being generated when Object.wait() is called on an object of this type. */ public final class HiddenWait { + + public synchronized boolean takeNap(long timeoutMillis) { + try { + this.wait(timeoutMillis); + return true; + } catch (InterruptedException e) { + // Ok, ignore + return false; + } + } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/management/StreamBarrier.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/management/StreamBarrier.java index 0b3132da217..7f1db163b4e 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/management/StreamBarrier.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/management/StreamBarrier.java @@ -39,45 +39,57 @@ * processing should not continue. */ public final class StreamBarrier implements Closeable { - + private final HiddenWait lock = new HiddenWait(); private boolean activated = false; private boolean used = false; private long end = Long.MAX_VALUE; // Blocks thread until barrier is deactivated - public synchronized void check() { - while (activated) { - try { - this.wait(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); + public void check() { + synchronized (lock) { + while (activated) { + try { + lock.wait(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } } } } - public synchronized void setStreamEnd(long timestamp) { - end = timestamp; + public void setStreamEnd(long timestamp) { + synchronized(lock) { + end = timestamp; + } } - public synchronized long getStreamEnd() { - return end; + public long getStreamEnd() { + synchronized(lock) { + return end; + } } - public synchronized void activate() { - activated = true; - used = true; + public void activate() { + synchronized (lock) { + activated = true; + used = true; + } } @Override public synchronized void close() throws IOException { - activated = false; - this.notifyAll(); + synchronized (lock) { + activated = false; + lock.notifyAll(); + } } /** * Returns {@code true) if barrier is, or has been, in active state, {@code false) otherwise. */ - public synchronized boolean used() { - return used; + public boolean used() { + synchronized (lock) { + return used; + } } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Utils.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Utils.java index 5e04a25fe7d..ae83727096a 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Utils.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Utils.java @@ -48,19 +48,19 @@ import jdk.jfr.Event; import jdk.jfr.EventType; import jdk.jfr.RecordingState; -import jdk.jfr.internal.HiddenWait; import jdk.jfr.internal.LogLevel; import jdk.jfr.internal.LogTag; import jdk.jfr.internal.Logger; import jdk.jfr.internal.MirrorEvent; import jdk.jfr.internal.SecuritySupport; import jdk.jfr.internal.Type; +import jdk.jfr.internal.management.HiddenWait; import jdk.jfr.internal.settings.PeriodSetting; import jdk.jfr.internal.settings.StackTraceSetting; import jdk.jfr.internal.settings.ThresholdSetting; public final class Utils { - private static final Object flushObject = new Object(); + private static final HiddenWait flushObject = new HiddenWait(); private static final String LEGACY_EVENT_NAME_PREFIX = "com.oracle.jdk."; /** @@ -351,17 +351,6 @@ private static boolean isSupportedType(Class type) { return Type.isValidJavaFieldType(type.getName()); } - public static void takeNap(long millis) { - HiddenWait hiddenWait = new HiddenWait(); - try { - synchronized(hiddenWait) { - hiddenWait.wait(millis); - } - } catch (InterruptedException e) { - // ok - } - } - public static void notifyFlush() { synchronized (flushObject) { flushObject.notifyAll(); @@ -369,13 +358,7 @@ public static void notifyFlush() { } public static void waitFlush(long timeOut) { - synchronized (flushObject) { - try { - flushObject.wait(timeOut); - } catch (InterruptedException e) { - // OK - } - } + flushObject.takeNap(timeOut); } public static Instant epochNanosToInstant(long epochNanos) { diff --git a/src/jdk.management.jfr/share/classes/jdk/management/jfr/DownLoadThread.java b/src/jdk.management.jfr/share/classes/jdk/management/jfr/DownLoadThread.java index 5ce66692537..05895f0f4a9 100644 --- a/src/jdk.management.jfr/share/classes/jdk/management/jfr/DownLoadThread.java +++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/DownLoadThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,12 +30,14 @@ import java.util.Map; import jdk.jfr.internal.management.ManagementSupport; +import jdk.jfr.internal.management.HiddenWait; final class DownLoadThread extends Thread { private final RemoteRecordingStream stream; private final Instant startTime; private final Instant endTime; private final DiskRepository diskRepository; + private final HiddenWait threadSleeper = new HiddenWait(); DownLoadThread(RemoteRecordingStream stream, String name) { super(name); @@ -64,7 +66,7 @@ public void run() { if (bytes.length != 0) { diskRepository.write(bytes); } else { - takeNap(); + threadSleeper.takeNap(1000); } } } catch (IOException ioe) { @@ -73,12 +75,4 @@ public void run() { diskRepository.complete(); } } - - private void takeNap() { - try { - Thread.sleep(1000); - } catch (InterruptedException ie) { - // ignore - } - } } diff --git a/src/jdk.management.jfr/share/classes/jdk/management/jfr/FileDump.java b/src/jdk.management.jfr/share/classes/jdk/management/jfr/FileDump.java index 7da0fe351c4..37ba2967326 100644 --- a/src/jdk.management.jfr/share/classes/jdk/management/jfr/FileDump.java +++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/FileDump.java @@ -32,8 +32,10 @@ import java.util.Deque; import jdk.management.jfr.DiskRepository.DiskChunk; +import jdk.jfr.internal.management.HiddenWait; final class FileDump { + private final HiddenWait lock = new HiddenWait(); private final Deque chunks = new ArrayDeque<>(); private final long stopTimeMillis; private boolean complete; @@ -42,45 +44,53 @@ final class FileDump { this.stopTimeMillis = stopTimeMillis; } - public synchronized void add(DiskChunk dc) { - if (isComplete()) { - return; - } - dc.acquire(); - chunks.addFirst(dc); - long endMillis = dc.endTimeNanos / 1_000_000; - if (endMillis >= stopTimeMillis) { - setComplete(); + public void add(DiskChunk dc) { + synchronized (lock) { + if (isComplete()) { + return; + } + dc.acquire(); + chunks.addFirst(dc); + long endMillis = dc.endTimeNanos / 1_000_000; + if (endMillis >= stopTimeMillis) { + setComplete(); + } } } - public synchronized boolean isComplete() { - return complete; + public boolean isComplete() { + synchronized (lock) { + return complete; + } } - public synchronized void setComplete() { - complete = true; - this.notifyAll(); + public void setComplete() { + synchronized (lock) { + complete = true; + lock.notifyAll(); + } } - public synchronized void close() { - for (DiskChunk dc : chunks) { - dc.release(); + public void close() { + synchronized (lock) { + for (DiskChunk dc : chunks) { + dc.release(); + } + chunks.clear(); + complete = true; } - chunks.clear(); - complete = true; } private DiskChunk oldestChunk() throws InterruptedException { while (true) { - synchronized (this) { + synchronized (lock) { if (!chunks.isEmpty()) { return chunks.pollLast(); } if (complete) { return null; } - this.wait(); + lock.wait(); } } } diff --git a/test/jdk/jdk/jfr/jvm/TestHiddenWait.java b/test/jdk/jdk/jfr/jvm/TestHiddenWait.java new file mode 100644 index 00000000000..f4b810f192e --- /dev/null +++ b/test/jdk/jdk/jfr/jvm/TestHiddenWait.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.jvm; + +import java.nio.file.Path; +import java.time.Duration; +import java.util.List; +import java.util.concurrent.atomic.AtomicLong; + +import jdk.jfr.Recording; +import jdk.jfr.Name; +import jdk.jfr.Event; +import jdk.jfr.FlightRecorder; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordingStream; +import jdk.test.lib.jfr.Events; + +/** + * @test TestHiddenWait + * @key jfr + * @summary Checks that JFR code don't emit noise in the form of ThreadSleep and JavaMonitorWait events. + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm jdk.jfr.jvm.TestHiddenWait + */ +public class TestHiddenWait { + static final String PERIODIC_EVENT_NAME = "test.Periodic"; + + @Name(PERIODIC_EVENT_NAME) + public static class PeriodicEvent extends Event { + } + + public static void main(String... args) throws Exception { + FlightRecorder.addPeriodicEvent(PeriodicEvent.class, () -> { + PeriodicEvent event = new PeriodicEvent(); + event.commit(); + }); + try (Recording r = new Recording()) { + AtomicLong counter = new AtomicLong(); + r.enable("jdk.ThreadSleep").withoutThreshold(); + r.enable("jdk.JavaMonitorWait").withoutThreshold(); + r.enable(PERIODIC_EVENT_NAME).withPeriod(Duration.ofMillis(100)); + r.start(); + // Triggers Object.wait() in stream barrier + try (RecordingStream b = new RecordingStream()) { + b.startAsync(); + b.stop(); + } + // Wait for for periodic events + try (RecordingStream s = new RecordingStream()) { + s.onEvent(PERIODIC_EVENT_NAME, e -> { + if (counter.incrementAndGet() >= 2) { + s.close(); + } + }); + s.start(); + } + List events = Events.fromRecording(r); + for (RecordedEvent event : events) { + if (!event.getEventType().getName().equals(PERIODIC_EVENT_NAME)) { + System.out.println(event); + throw new Exception("Didn't expect ThreadSleep or JavaMonitorWait events"); + } + } + } + } +} From e6c5aa7a6cb54c647d261facdcffa6a410849627 Mon Sep 17 00:00:00 2001 From: Christian Stein Date: Wed, 10 Jul 2024 15:12:49 +0000 Subject: [PATCH 032/460] 8336012: Fix usages of jtreg-reserved properties Reviewed-by: jjg --- test/jdk/java/lang/invoke/PrivateInvokeTest.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/jdk/java/lang/invoke/PrivateInvokeTest.java b/test/jdk/java/lang/invoke/PrivateInvokeTest.java index 12edf8e3263..8ae78d96713 100644 --- a/test/jdk/java/lang/invoke/PrivateInvokeTest.java +++ b/test/jdk/java/lang/invoke/PrivateInvokeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,8 +67,6 @@ public class PrivateInvokeTest { String vstr = System.getProperty(THIS_CLASS.getSimpleName()+".verbose"); if (vstr == null) vstr = System.getProperty(THIS_CLASS.getName()+".verbose"); - if (vstr == null) - vstr = System.getProperty("test.verbose"); if (vstr != null) verbose = Integer.parseInt(vstr); } private static int referenceKind(Method m) { From fb9a227e02ebf826edb762283e15dd7e402f8433 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Wed, 10 Jul 2024 15:34:27 +0000 Subject: [PATCH 033/460] 8313909: [JVMCI] assert(cp->tag_at(index).is_unresolved_klass()) in lookupKlassInPool Reviewed-by: yzheng, never --- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index d92d1930173..68168c56b9a 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -897,7 +897,9 @@ C2V_VMENTRY_NULL(jobject, lookupKlassInPool, (JNIEnv* env, jobject, ARGUMENT_PAI } else if (tag.is_symbol()) { symbol = cp->symbol_at(index); } else { - assert(cp->tag_at(index).is_unresolved_klass(), "wrong tag"); + if (!tag.is_unresolved_klass()) { + JVMCI_THROW_MSG_NULL(InternalError, err_msg("Expected %d at index %d, got %d", JVM_CONSTANT_UnresolvedClassInError, index, tag.value())); + } symbol = cp->klass_name_at(index); } } From fb66716a1bc914db194c5b0b833cc2317704f166 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Wed, 10 Jul 2024 16:12:40 +0000 Subject: [PATCH 034/460] 8331725: ubsan: pc may not always be the entry point for a VtableStub Reviewed-by: kvn, mbaesken --- src/hotspot/share/code/vtableStubs.cpp | 24 ++++++++++++++++++++---- src/hotspot/share/code/vtableStubs.hpp | 23 +++++++++++++---------- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/src/hotspot/share/code/vtableStubs.cpp b/src/hotspot/share/code/vtableStubs.cpp index 5a54426d6a4..a65852e247f 100644 --- a/src/hotspot/share/code/vtableStubs.cpp +++ b/src/hotspot/share/code/vtableStubs.cpp @@ -255,6 +255,19 @@ inline uint VtableStubs::hash(bool is_vtable_stub, int vtable_index){ } +inline uint VtableStubs::unsafe_hash(address entry_point) { + // The entrypoint may or may not be a VtableStub. Generate a hash as if it was. + address vtable_stub_addr = entry_point - VtableStub::entry_offset(); + assert(CodeCache::contains(vtable_stub_addr), "assumed to always be the case"); + address vtable_type_addr = vtable_stub_addr + offset_of(VtableStub, _type); + address vtable_index_addr = vtable_stub_addr + offset_of(VtableStub, _index); + bool is_vtable_stub = *vtable_type_addr == static_cast(VtableStub::Type::vtable_stub); + int vtable_index; + memcpy(&vtable_index, vtable_index_addr, sizeof(vtable_index)); + return hash(is_vtable_stub, vtable_index); +} + + VtableStub* VtableStubs::lookup(bool is_vtable_stub, int vtable_index) { assert_lock_strong(VtableStubs_lock); unsigned hash = VtableStubs::hash(is_vtable_stub, vtable_index); @@ -275,12 +288,15 @@ void VtableStubs::enter(bool is_vtable_stub, int vtable_index, VtableStub* s) { } VtableStub* VtableStubs::entry_point(address pc) { + // The pc may or may not be the entry point for a VtableStub. Use unsafe_hash + // to generate the hash that would have been used if it was. The lookup in the + // _table will only succeed if there is a VtableStub with an entry point at + // the pc. MutexLocker ml(VtableStubs_lock, Mutex::_no_safepoint_check_flag); - VtableStub* stub = (VtableStub*)(pc - VtableStub::entry_offset()); - uint hash = VtableStubs::hash(stub->is_vtable_stub(), stub->index()); + uint hash = VtableStubs::unsafe_hash(pc); VtableStub* s; - for (s = Atomic::load(&_table[hash]); s != nullptr && s != stub; s = s->next()) {} - return (s == stub) ? s : nullptr; + for (s = Atomic::load(&_table[hash]); s != nullptr && s->entry_point() != pc; s = s->next()) {} + return (s != nullptr && s->entry_point() == pc) ? s : nullptr; } bool VtableStubs::contains(address pc) { diff --git a/src/hotspot/share/code/vtableStubs.hpp b/src/hotspot/share/code/vtableStubs.hpp index 426753ef008..06acd8f25b9 100644 --- a/src/hotspot/share/code/vtableStubs.hpp +++ b/src/hotspot/share/code/vtableStubs.hpp @@ -28,7 +28,6 @@ #include "asm/macroAssembler.hpp" #include "code/vmreg.hpp" #include "memory/allStatic.hpp" -#include "sanitizers/ub.hpp" #include "utilities/checkedCast.hpp" // A VtableStub holds an individual code stub for a pair (vtable index, #args) for either itables or vtables @@ -94,6 +93,7 @@ class VtableStubs : AllStatic { static VtableStub* lookup (bool is_vtable_stub, int vtable_index); static void enter (bool is_vtable_stub, int vtable_index, VtableStub* s); static inline uint hash (bool is_vtable_stub, int vtable_index); + static inline uint unsafe_hash (address entry_point); static address find_stub (bool is_vtable_stub, int vtable_index); static void bookkeeping(MacroAssembler* masm, outputStream* out, VtableStub* s, address npe_addr, address ame_addr, bool is_vtable_stub, @@ -119,6 +119,12 @@ class VtableStub { private: friend class VtableStubs; + enum class Type : uint8_t { + itable_stub, + vtable_stub, + }; + + static address _chunk; // For allocation static address _chunk_end; // For allocation static VMReg _receiver_location; // Where to find receiver @@ -127,14 +133,14 @@ class VtableStub { const short _index; // vtable index short _ame_offset; // Where an AbstractMethodError might occur short _npe_offset; // Where a NullPointerException might occur - bool _is_vtable_stub; // True if vtable stub, false, is itable stub + Type _type; // Type, either vtable stub or itable stub /* code follows here */ // The vtableStub code void* operator new(size_t size, int code_size) throw(); VtableStub(bool is_vtable_stub, short index) : _next(nullptr), _index(index), _ame_offset(-1), _npe_offset(-1), - _is_vtable_stub(is_vtable_stub) {} + _type(is_vtable_stub ? Type::vtable_stub : Type::itable_stub) {} VtableStub* next() const { return _next; } int index() const { return _index; } static VMReg receiver_location() { return _receiver_location; } @@ -142,12 +148,12 @@ class VtableStub { public: address code_begin() const { return (address)(this + 1); } - address code_end() const { return code_begin() + VtableStubs::code_size_limit(_is_vtable_stub); } + address code_end() const { return code_begin() + VtableStubs::code_size_limit(is_vtable_stub()); } address entry_point() const { return code_begin(); } static int entry_offset() { return sizeof(class VtableStub); } bool matches(bool is_vtable_stub, int index) const { - return _index == index && _is_vtable_stub == is_vtable_stub; + return _index == index && this->is_vtable_stub() == is_vtable_stub; } bool contains(address pc) const { return code_begin() <= pc && pc < code_end(); } @@ -173,11 +179,8 @@ class VtableStub { public: // Query - bool is_itable_stub() { return !_is_vtable_stub; } - // We reinterpret arbitrary memory as VtableStub. This does not cause failures because the lookup/equality - // check will reject false objects. Disabling UBSan is a temporary workaround until JDK-8331725 is fixed. - ATTRIBUTE_NO_UBSAN - bool is_vtable_stub() { return _is_vtable_stub; } + bool is_itable_stub() const { return _type == Type::itable_stub; } + bool is_vtable_stub() const { return _type == Type::vtable_stub; } bool is_abstract_method_error(address epc) { return epc == code_begin()+_ame_offset; } bool is_null_pointer_exception(address epc) { return epc == code_begin()+_npe_offset; } From 7ab96c74e2c39f430a5c2f65a981da7314a2385b Mon Sep 17 00:00:00 2001 From: Patricio Chilano Mateo Date: Wed, 10 Jul 2024 16:26:16 +0000 Subject: [PATCH 035/460] 8335409: Can't allocate and retain memory from resource area in frame::oops_interpreted_do oop closure after 8329665 Reviewed-by: dholmes, stuefe, coleenp, shade --- src/hotspot/share/interpreter/oopMapCache.cpp | 60 ++++++++----------- src/hotspot/share/interpreter/oopMapCache.hpp | 23 ++++--- src/hotspot/share/runtime/frame.cpp | 1 - 3 files changed, 35 insertions(+), 49 deletions(-) diff --git a/src/hotspot/share/interpreter/oopMapCache.cpp b/src/hotspot/share/interpreter/oopMapCache.cpp index a10f8c439ea..87b124e9d79 100644 --- a/src/hotspot/share/interpreter/oopMapCache.cpp +++ b/src/hotspot/share/interpreter/oopMapCache.cpp @@ -66,9 +66,6 @@ class OopMapCacheEntry: private InterpreterOopMap { public: OopMapCacheEntry() : InterpreterOopMap() { _next = nullptr; -#ifdef ASSERT - _resource_allocate_bit_mask = false; -#endif } }; @@ -177,9 +174,13 @@ class VerifyClosure : public OffsetClosure { InterpreterOopMap::InterpreterOopMap() { initialize(); -#ifdef ASSERT - _resource_allocate_bit_mask = true; -#endif +} + +InterpreterOopMap::~InterpreterOopMap() { + if (has_valid_mask() && mask_size() > small_mask_limit) { + assert(_bit_mask[0] != 0, "should have pointer to C heap"); + FREE_C_HEAP_ARRAY(uintptr_t, _bit_mask[0]); + } } bool InterpreterOopMap::is_empty() const { @@ -399,37 +400,24 @@ void OopMapCacheEntry::deallocate(OopMapCacheEntry* const entry) { // Implementation of OopMapCache -void InterpreterOopMap::resource_copy(OopMapCacheEntry* from) { - assert(_resource_allocate_bit_mask, - "Should not resource allocate the _bit_mask"); - assert(from->has_valid_mask(), - "Cannot copy entry with an invalid mask"); +void InterpreterOopMap::copy_from(const OopMapCacheEntry* src) { + // The expectation is that this InterpreterOopMap is recently created + // and empty. It is used to get a copy of a cached entry. + assert(!has_valid_mask(), "InterpreterOopMap object can only be filled once"); + assert(src->has_valid_mask(), "Cannot copy entry with an invalid mask"); - set_method(from->method()); - set_bci(from->bci()); - set_mask_size(from->mask_size()); - set_expression_stack_size(from->expression_stack_size()); - _num_oops = from->num_oops(); + set_method(src->method()); + set_bci(src->bci()); + set_mask_size(src->mask_size()); + set_expression_stack_size(src->expression_stack_size()); + _num_oops = src->num_oops(); // Is the bit mask contained in the entry? - if (from->mask_size() <= small_mask_limit) { - memcpy((void *)_bit_mask, (void *)from->_bit_mask, - mask_word_size() * BytesPerWord); + if (src->mask_size() <= small_mask_limit) { + memcpy(_bit_mask, src->_bit_mask, mask_word_size() * BytesPerWord); } else { - // The expectation is that this InterpreterOopMap is a recently created - // and empty. It is used to get a copy of a cached entry. - // If the bit mask has a value, it should be in the - // resource area. - assert(_bit_mask[0] == 0 || - Thread::current()->resource_area()->contains((void*)_bit_mask[0]), - "The bit mask should have been allocated from a resource area"); - // Allocate the bit_mask from a Resource area for performance. Allocating - // from the C heap as is done for OopMapCache has a significant - // performance impact. - _bit_mask[0] = (uintptr_t) NEW_RESOURCE_ARRAY(uintptr_t, mask_word_size()); - assert(_bit_mask[0] != 0, "bit mask was not allocated"); - memcpy((void*) _bit_mask[0], (void*) from->_bit_mask[0], - mask_word_size() * BytesPerWord); + _bit_mask[0] = (uintptr_t) NEW_C_HEAP_ARRAY(uintptr_t, mask_word_size(), mtClass); + memcpy((void*) _bit_mask[0], (void*) src->_bit_mask[0], mask_word_size() * BytesPerWord); } } @@ -512,7 +500,7 @@ void OopMapCache::lookup(const methodHandle& method, for (int i = 0; i < probe_depth; i++) { OopMapCacheEntry *entry = entry_at(probe + i); if (entry != nullptr && !entry->is_empty() && entry->match(method, bci)) { - entry_for->resource_copy(entry); + entry_for->copy_from(entry); assert(!entry_for->is_empty(), "A non-empty oop map should be returned"); log_debug(interpreter, oopmap)("- found at hash %d", probe + i); return; @@ -526,7 +514,7 @@ void OopMapCache::lookup(const methodHandle& method, OopMapCacheEntry* tmp = NEW_C_HEAP_OBJ(OopMapCacheEntry, mtClass); tmp->initialize(); tmp->fill(method, bci); - entry_for->resource_copy(tmp); + entry_for->copy_from(tmp); if (method->should_not_be_cached()) { // It is either not safe or not a good idea to cache this Method* @@ -627,7 +615,7 @@ void OopMapCache::compute_one_oop_map(const methodHandle& method, int bci, Inter tmp->initialize(); tmp->fill(method, bci); if (tmp->has_valid_mask()) { - entry->resource_copy(tmp); + entry->copy_from(tmp); } OopMapCacheEntry::deallocate(tmp); } diff --git a/src/hotspot/share/interpreter/oopMapCache.hpp b/src/hotspot/share/interpreter/oopMapCache.hpp index 7037b2c7d1f..062b4178ce0 100644 --- a/src/hotspot/share/interpreter/oopMapCache.hpp +++ b/src/hotspot/share/interpreter/oopMapCache.hpp @@ -36,13 +36,14 @@ // OopMapCache's are allocated lazily per InstanceKlass. // The oopMap (InterpreterOopMap) is stored as a bit mask. If the -// bit_mask can fit into two words it is stored in +// bit_mask can fit into four words it is stored in // the _bit_mask array, otherwise it is allocated on the heap. // For OopMapCacheEntry the bit_mask is allocated in the C heap // because these entries persist between garbage collections. -// For InterpreterOopMap the bit_mask is allocated in -// a resource area for better performance. InterpreterOopMap -// should only be created and deleted during same garbage collection. +// For InterpreterOopMap the bit_mask is allocated in the C heap +// to avoid issues with allocations from the resource area that have +// to live accross the oop closure. InterpreterOopMap should only be +// created and deleted during the same garbage collection. // // If ENABBLE_ZAP_DEAD_LOCALS is defined, two bits are used // per entry instead of one. In all cases, @@ -88,9 +89,6 @@ class InterpreterOopMap: ResourceObj { unsigned short _bci; // the bci for which the mask is valid protected: -#ifdef ASSERT - bool _resource_allocate_bit_mask; -#endif int _num_oops; intptr_t _bit_mask[N]; // the bit mask if // mask_size <= small_mask_limit, @@ -128,12 +126,13 @@ class InterpreterOopMap: ResourceObj { public: InterpreterOopMap(); + ~InterpreterOopMap(); - // Copy the OopMapCacheEntry in parameter "from" into this - // InterpreterOopMap. If the _bit_mask[0] in "from" points to - // allocated space (i.e., the bit mask was to large to hold - // in-line), allocate the space from a Resource area. - void resource_copy(OopMapCacheEntry* from); + // Copy the OopMapCacheEntry in parameter "src" into this + // InterpreterOopMap. If the _bit_mask[0] in "src" points to + // allocated space (i.e., the bit mask was too large to hold + // in-line), allocate the space from the C heap. + void copy_from(const OopMapCacheEntry* src); void iterate_oop(OffsetClosure* oop_closure) const; void print() const; diff --git a/src/hotspot/share/runtime/frame.cpp b/src/hotspot/share/runtime/frame.cpp index 8f5d2ad4acb..1aed46d5880 100644 --- a/src/hotspot/share/runtime/frame.cpp +++ b/src/hotspot/share/runtime/frame.cpp @@ -947,7 +947,6 @@ void frame::oops_interpreted_do(OopClosure* f, const RegisterMap* map, bool quer InterpreterFrameClosure blk(this, max_locals, m->max_stack(), f); // process locals & expression stack - ResourceMark rm(thread); InterpreterOopMap mask; if (query_oop_map_cache) { m->mask_for(m, bci, &mask); From 66db71563c3ebd715a1192a9b399b618d7bdb8d0 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Wed, 10 Jul 2024 16:36:39 +0000 Subject: [PATCH 036/460] 8335637: Add explicit non-null return value expectations to Object.toString() Reviewed-by: jpai, alanb, smarks, prappo --- src/java.base/share/classes/java/lang/Object.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/java.base/share/classes/java/lang/Object.java b/src/java.base/share/classes/java/lang/Object.java index b8bfdc3e3f9..d9813df57a4 100644 --- a/src/java.base/share/classes/java/lang/Object.java +++ b/src/java.base/share/classes/java/lang/Object.java @@ -237,6 +237,10 @@ public boolean equals(Object obj) { /** * {@return a string representation of the object} + * + * Satisfying this method's contract implies a non-{@code null} + * result must be returned. + * * @apiNote * In general, the * {@code toString} method returns a string that From 242f1133f8e1b373de3714cefc7f6701c39707fe Mon Sep 17 00:00:00 2001 From: Yudi Zheng Date: Wed, 10 Jul 2024 19:42:23 +0000 Subject: [PATCH 037/460] 8334481: [JVMCI] add LINK_TO_NATIVE to MethodHandleAccessProvider.IntrinsicMethod Reviewed-by: dnsimon --- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 1 + .../jdk/vm/ci/hotspot/HotSpotMethodHandleAccessProvider.java | 2 ++ .../share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java | 1 + .../classes/jdk/vm/ci/meta/MethodHandleAccessProvider.java | 4 +++- 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 8f83d483bcf..f55c7bf91a9 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -778,6 +778,7 @@ declare_constant(vmIntrinsics::_linkToStatic) \ declare_constant(vmIntrinsics::_linkToSpecial) \ declare_constant(vmIntrinsics::_linkToInterface) \ + declare_constant(vmIntrinsics::_linkToNative) \ \ declare_constant(vmSymbols::FIRST_SID) \ declare_constant(vmSymbols::SID_LIMIT) \ diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMethodHandleAccessProvider.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMethodHandleAccessProvider.java index 7e47196a42b..3d3d140b1ca 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMethodHandleAccessProvider.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMethodHandleAccessProvider.java @@ -146,6 +146,8 @@ public static IntrinsicMethod getMethodHandleIntrinsic(int intrinsicId) { return IntrinsicMethod.LINK_TO_STATIC; } else if (intrinsicId == config.vmIntrinsicLinkToVirtual) { return IntrinsicMethod.LINK_TO_VIRTUAL; + } else if (intrinsicId == config.vmIntrinsicLinkToNative) { + return IntrinsicMethod.LINK_TO_NATIVE; } return null; } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java index c49f24efed5..57f9473c902 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -342,6 +342,7 @@ final int baseVtableLength() { final int vmIntrinsicLinkToStatic = getConstant("vmIntrinsics::_linkToStatic", Integer.class); final int vmIntrinsicLinkToSpecial = getConstant("vmIntrinsics::_linkToSpecial", Integer.class); final int vmIntrinsicLinkToInterface = getConstant("vmIntrinsics::_linkToInterface", Integer.class); + final int vmIntrinsicLinkToNative = getConstant("vmIntrinsics::_linkToNative", Integer.class); final int codeInstallResultOk = getConstant("JVMCI::ok", Integer.class); final int codeInstallResultDependenciesFailed = getConstant("JVMCI::dependencies_failed", Integer.class); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MethodHandleAccessProvider.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MethodHandleAccessProvider.java index f053905b160..eb8b9721d49 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MethodHandleAccessProvider.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MethodHandleAccessProvider.java @@ -45,7 +45,9 @@ enum IntrinsicMethod { /** The method {@code MethodHandle.linkToVirtual}. */ LINK_TO_VIRTUAL, /** The method {@code MethodHandle.linkToInterface}. */ - LINK_TO_INTERFACE + LINK_TO_INTERFACE, + /** The method {@code MethodHandle.linkToNative}. */ + LINK_TO_NATIVE } /** From cad68e06ecad1e19091d1af9c0f9b8145d6842fb Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Wed, 10 Jul 2024 21:06:39 +0000 Subject: [PATCH 038/460] 8335935: Chained builders not sending transformed models to next transforms Reviewed-by: asotona --- .../java/lang/classfile/CodeBuilder.java | 4 +- .../classfile/impl/BlockCodeBuilderImpl.java | 16 +- .../classfile/impl/BufferedCodeBuilder.java | 4 +- .../classfile/impl/ChainedClassBuilder.java | 16 +- .../classfile/impl/ChainedMethodBuilder.java | 10 +- .../classfile/impl/DirectCodeBuilder.java | 4 +- .../internal/classfile/impl/LabelContext.java | 4 +- .../classfile/impl/TerminalCodeBuilder.java | 8 +- .../impl/TransformingCodeBuilder.java | 91 ---------- test/jdk/jdk/classfile/TransformTests.java | 163 ++++++++++++++++++ 10 files changed, 196 insertions(+), 124 deletions(-) delete mode 100644 src/java.base/share/classes/jdk/internal/classfile/impl/TransformingCodeBuilder.java diff --git a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java index cffa560bef3..a1666375091 100644 --- a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java @@ -86,7 +86,7 @@ import static java.util.Objects.requireNonNull; import static jdk.internal.classfile.impl.BytecodeHelpers.handleDescToHandleInfo; -import jdk.internal.classfile.impl.TransformingCodeBuilder; + import jdk.internal.javac.PreviewFeature; /** @@ -192,7 +192,7 @@ public sealed interface CodeBuilder default CodeBuilder transforming(CodeTransform transform, Consumer handler) { var resolved = transform.resolve(this); resolved.startHandler().run(); - handler.accept(new TransformingCodeBuilder(this, resolved.consumer())); + handler.accept(new ChainedCodeBuilder(this, resolved.consumer())); resolved.endHandler().run(); return this; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java index ffe1a2bd616..66e974b4a51 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,13 +51,13 @@ public BlockCodeBuilderImpl(CodeBuilder parent, Label breakLabel) { public void start() { topLocal = topLocal(parent); - terminalMaxLocals = topLocal(terminal); - terminal.with((LabelTarget) startLabel); + terminalMaxLocals = terminal.curTopLocal(); + parent.with((LabelTarget) startLabel); } public void end() { - terminal.with((LabelTarget) endLabel); - if (terminalMaxLocals != topLocal(terminal)) { + parent.with((LabelTarget) endLabel); + if (terminalMaxLocals != terminal.curTopLocal()) { throw new IllegalStateException("Interference in local variable slot management"); } } @@ -73,10 +73,8 @@ public boolean isEmpty() { private int topLocal(CodeBuilder parent) { return switch (parent) { case BlockCodeBuilderImpl b -> b.topLocal; - case ChainedCodeBuilder b -> topLocal(b.terminal); - case DirectCodeBuilder b -> b.curTopLocal(); - case BufferedCodeBuilder b -> b.curTopLocal(); - case TransformingCodeBuilder b -> topLocal(b.delegate); + case ChainedCodeBuilder b -> b.terminal.curTopLocal(); + case TerminalCodeBuilder b -> b.curTopLocal(); }; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java index 60e73cdd987..8603c77ab8b 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,7 @@ import java.util.function.Consumer; public final class BufferedCodeBuilder - implements TerminalCodeBuilder, LabelContext { + implements TerminalCodeBuilder { private final SplitConstantPool constantPool; private final ClassFileImpl context; private final List elements = new ArrayList<>(); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java index cc19bf9d31c..b33d192f9b3 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,13 +33,11 @@ public final class ChainedClassBuilder implements ClassBuilder, Consumer { - private final ClassBuilder downstream; private final DirectClassBuilder terminal; private final Consumer consumer; public ChainedClassBuilder(ClassBuilder downstream, Consumer consumer) { - this.downstream = downstream; this.consumer = consumer; this.terminal = switch (downstream) { case ChainedClassBuilder cb -> cb.terminal; @@ -60,10 +58,11 @@ public Optional original() { @Override public ClassBuilder withField(Utf8Entry name, Utf8Entry descriptor, Consumer handler) { - return downstream.with(new BufferedFieldBuilder(terminal.constantPool, terminal.context, + consumer.accept(new BufferedFieldBuilder(terminal.constantPool, terminal.context, name, descriptor, null) .run(handler) .toModel()); + return this; } @Override @@ -72,16 +71,18 @@ public ClassBuilder transformField(FieldModel field, FieldTransform transform) { field.fieldName(), field.fieldType(), field); builder.transform(field, transform); - return downstream.with(builder.toModel()); + consumer.accept(builder.toModel()); + return this; } @Override public ClassBuilder withMethod(Utf8Entry name, Utf8Entry descriptor, int flags, Consumer handler) { - return downstream.with(new BufferedMethodBuilder(terminal.constantPool, terminal.context, + consumer.accept(new BufferedMethodBuilder(terminal.constantPool, terminal.context, name, descriptor, null) .run(handler) .toModel()); + return this; } @Override @@ -89,7 +90,8 @@ public ClassBuilder transformMethod(MethodModel method, MethodTransform transfor BufferedMethodBuilder builder = new BufferedMethodBuilder(terminal.constantPool, terminal.context, method.methodName(), method.methodType(), method); builder.transform(method, transform); - return downstream.with(builder.toModel()); + consumer.accept(builder.toModel()); + return this; } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedMethodBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedMethodBuilder.java index 38850aec109..866dda2c5bc 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedMethodBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedMethodBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,13 +36,11 @@ import java.lang.classfile.constantpool.ConstantPoolBuilder; public final class ChainedMethodBuilder implements MethodBuilder { - final MethodBuilder downstream; final TerminalMethodBuilder terminal; final Consumer consumer; public ChainedMethodBuilder(MethodBuilder downstream, Consumer consumer) { - this.downstream = downstream; this.consumer = consumer; this.terminal = switch (downstream) { case ChainedMethodBuilder cb -> cb.terminal; @@ -58,16 +56,18 @@ public MethodBuilder with(MethodElement element) { @Override public MethodBuilder withCode(Consumer handler) { - return downstream.with(terminal.bufferedCodeBuilder(null) + consumer.accept(terminal.bufferedCodeBuilder(null) .run(handler) .toModel()); + return this; } @Override public MethodBuilder transformCode(CodeModel code, CodeTransform transform) { BufferedCodeBuilder builder = terminal.bufferedCodeBuilder(code); builder.transform(code, transform); - return downstream.with(builder.toModel()); + consumer.accept(builder.toModel()); + return this; } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java index b961a12031f..0b6549a82da 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,7 +75,7 @@ public final class DirectCodeBuilder extends AbstractDirectBuilder - implements TerminalCodeBuilder, LabelContext { + implements TerminalCodeBuilder { private final List characterRanges = new ArrayList<>(); final List handlers = new ArrayList<>(); private final List localVariables = new ArrayList<>(); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/LabelContext.java b/src/java.base/share/classes/jdk/internal/classfile/impl/LabelContext.java index e17adcbcf12..749abbed23b 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/LabelContext.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/LabelContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ import java.lang.classfile.Label; public sealed interface LabelContext - permits BufferedCodeBuilder, CodeImpl, DirectCodeBuilder { + permits TerminalCodeBuilder, CodeImpl { Label newLabel(); Label getLabel(int bci); void setLabelTarget(Label label, int bci); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/TerminalCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/TerminalCodeBuilder.java index e13b09b0a4d..6e3ca516bf4 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/TerminalCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/TerminalCodeBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ import java.lang.classfile.CodeBuilder; -public sealed interface TerminalCodeBuilder extends CodeBuilder - permits DirectCodeBuilder, BufferedCodeBuilder, TransformingCodeBuilder { - +public sealed interface TerminalCodeBuilder extends CodeBuilder, LabelContext + permits DirectCodeBuilder, BufferedCodeBuilder { + int curTopLocal(); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/TransformingCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/TransformingCodeBuilder.java deleted file mode 100644 index 4ffc75d3edc..00000000000 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/TransformingCodeBuilder.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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 jdk.internal.classfile.impl; - -import java.lang.classfile.CodeBuilder; -import java.lang.classfile.CodeModel; -import java.util.Optional; -import java.util.function.Consumer; -import java.lang.classfile.CodeElement; -import java.lang.classfile.Label; -import java.lang.classfile.TypeKind; -import java.lang.classfile.constantpool.ConstantPoolBuilder; - -public final class TransformingCodeBuilder implements TerminalCodeBuilder { - - final CodeBuilder delegate; - final Consumer consumer; - - public TransformingCodeBuilder(CodeBuilder delegate, Consumer consumer) { - this.delegate = delegate; - this.consumer = consumer; - } - - @Override - public CodeBuilder with(CodeElement e) { - consumer.accept(e); - return this; - } - - @Override - public Optional original() { - return delegate.original(); - } - - @Override - public Label newLabel() { - return delegate.newLabel(); - } - - @Override - public Label startLabel() { - return delegate.startLabel(); - } - - @Override - public Label endLabel() { - return delegate.endLabel(); - } - - @Override - public int receiverSlot() { - return delegate.receiverSlot(); - } - - @Override - public int parameterSlot(int paramNo) { - return delegate.parameterSlot(paramNo); - } - - @Override - public int allocateLocal(TypeKind typeKind) { - return delegate.allocateLocal(typeKind); - } - - @Override - public ConstantPoolBuilder constantPool() { - return delegate.constantPool(); - } -} diff --git a/test/jdk/jdk/classfile/TransformTests.java b/test/jdk/jdk/classfile/TransformTests.java index 1df7b73bda5..0cc1dafdf32 100644 --- a/test/jdk/jdk/classfile/TransformTests.java +++ b/test/jdk/jdk/classfile/TransformTests.java @@ -23,9 +23,22 @@ /* * @test + * @bug 8336010 * @summary Testing ClassFile transformations. * @run junit TransformTests */ +import java.lang.classfile.ClassBuilder; +import java.lang.classfile.CodeBuilder; +import java.lang.classfile.CodeElement; +import java.lang.classfile.FieldModel; +import java.lang.classfile.FieldTransform; +import java.lang.classfile.Label; +import java.lang.classfile.MethodTransform; +import java.lang.classfile.instruction.BranchInstruction; +import java.lang.classfile.instruction.LabelTarget; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; +import java.lang.reflect.AccessFlag; import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; @@ -39,8 +52,13 @@ import java.lang.classfile.CodeTransform; import java.lang.classfile.MethodModel; import java.lang.classfile.instruction.ConstantInstruction; +import java.util.HashSet; +import java.util.Set; + import org.junit.jupiter.api.Test; +import static java.lang.classfile.ClassFile.*; +import static java.lang.constant.ConstantDescs.*; import static org.junit.jupiter.api.Assertions.*; /** @@ -126,6 +144,151 @@ void testSeqN() throws Exception { assertEquals(invoke(cc.transformClass(cm, transformCode(foo2foo.andThen(foo2bar).andThen(bar2baz)))), "baz"); } + /** + * Test to ensure class elements, such as field and + * methods defined with transform/with, are visible + * to next transforms. + */ + @Test + void testClassChaining() throws Exception { + var bytes = Files.readAllBytes(testClassPath); + var cf = ClassFile.of(); + var cm = cf.parse(bytes); + var otherCm = cf.parse(cf.build(ClassDesc.of("Temp"), clb -> clb + .withMethodBody("baz", MTD_void, ACC_STATIC, CodeBuilder::return_) + .withField("baz", CD_long, ACC_STATIC))); + + var methodBaz = otherCm.methods().getFirst(); + var fieldBaz = otherCm.fields().getFirst(); + + ClassTransform transform1 = ClassTransform.endHandler(cb -> { + ClassBuilder ret; + ret = cb.withMethodBody("bar", MTD_void, ACC_STATIC, CodeBuilder::return_); + assertSame(cb, ret); + ret = cb.transformMethod(methodBaz, MethodTransform.ACCEPT_ALL); + assertSame(cb, ret); + ret = cb.withField("bar", CD_int, ACC_STATIC); + assertSame(cb, ret); + ret = cb.transformField(fieldBaz, FieldTransform.ACCEPT_ALL); + assertSame(cb, ret); + }); + + Set methodNames = new HashSet<>(); + Set fieldNames = new HashSet<>(); + ClassTransform transform2 = (cb, ce) -> { + if (ce instanceof MethodModel mm) { + methodNames.add(mm.methodName().stringValue()); + } + if (ce instanceof FieldModel fm) { + fieldNames.add(fm.fieldName().stringValue()); + } + cb.with(ce); + }; + + cf.transformClass(cm, transform1.andThen(transform2)); + + assertEquals(Set.of(INIT_NAME, "foo", "bar", "baz"), methodNames); + assertEquals(Set.of("bar", "baz"), fieldNames); + } + + /** + * Test to ensure method elements, such as generated + * or transformed code, are visible to transforms. + */ + @Test + void testMethodChaining() throws Exception { + var mtd = MethodTypeDesc.of(CD_String); + + var cf = ClassFile.of(); + + // withCode + var cm = cf.parse(cf.build(ClassDesc.of("Temp"), clb -> clb + .withMethod("baz", mtd, ACC_STATIC | ACC_NATIVE, _ -> {}))); + + MethodTransform transform1 = MethodTransform.endHandler(mb -> { + var ret = mb.withCode(cob -> cob.loadConstant("foo").areturn()); + assertSame(mb, ret); + }); + + boolean[] sawWithCode = { false }; + MethodTransform transform2 = (mb, me) -> { + if (me instanceof CodeModel) { + sawWithCode[0] = true; + } + mb.with(me); + }; + + cf.transformClass(cm, ClassTransform.transformingMethods(transform1.andThen(transform2))); + + assertTrue(sawWithCode[0], "Code attribute generated not visible"); + + // transformCode + var outerCm = cf.parse(testClassPath); + var foo = outerCm.methods().stream() + .filter(m -> m.flags().has(AccessFlag.STATIC)) + .findFirst().orElseThrow(); + + MethodTransform transform3 = MethodTransform.endHandler(mb -> { + var ret = mb.transformCode(foo.code().orElseThrow(), CodeTransform.ACCEPT_ALL); + assertSame(mb, ret); + }); + + boolean[] sawTransformCode = { false }; + MethodTransform transform4 = (mb, me) -> { + if (me instanceof CodeModel) { + sawTransformCode[0] = true; + } + mb.with(me); + }; + + cf.transformClass(cm, ClassTransform.transformingMethods(transform3.andThen(transform4))); + + assertTrue(sawTransformCode[0], "Code attribute transformed not visible"); + } + + /** + * Test to ensure code elements, such as code block + * begin and end labels, are visible to transforms. + */ + @Test + void testCodeChaining() throws Exception { + var bytes = Files.readAllBytes(testClassPath); + var cf = ClassFile.of(); + var cm = cf.parse(bytes); + + CodeTransform transform1 = new CodeTransform() { + @Override + public void atStart(CodeBuilder builder) { + builder.block(bcb -> { + bcb.loadConstant(9876L); + bcb.goto_(bcb.endLabel()); + }); + } + + @Override + public void accept(CodeBuilder builder, CodeElement element) { + builder.with(element); + } + }; + Set

"x&#178;=5"
* - * + * *
"x²=5"
* - * + * *
"x&#178;=5"
* * * - * Built-in - * character entity - * + * Built-in character entity + * *
"y&lt;6"
* - * + * *
"y<6"
* - * + * *
"y&lt;6"
* * * - * Literal newline between - * - *
- * "x=5&#10;y=6"
+ * Literal newline between + * + *
"x=5&#10;y=6"
* - * + * *
"x=5 y=6"
* - * + * *
"x=5&#10;y=6"
* * * - * Normalized newline between - * + * Normalized newline between + * *
"x=5
  * y=6"
* - * + * *
"x=5 y=6"
* - * + * *
"x=5 y=6"
* * * - * Entity e with literal newline - * + * Entity e with literal newline + * *
  * <!ENTITY e '...&#10;...'> [...]> "x=5&e;y=6"
* - * Dependent on Implementation and Load Options - * Dependent on Implementation and Load/Save Options + * Dependent on Implementation and Load Options + * Dependent on Implementation and Load/Save Options * * * From 5100303c6c5e4224d2c41f90719139bb5f4e236e Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Thu, 11 Jul 2024 18:40:40 +0000 Subject: [PATCH 052/460] 8335668: NumberFormat integer only parsing should throw exception for edge case Reviewed-by: naoto --- .../classes/java/text/DecimalFormat.java | 14 +++++--- .../Format/NumberFormat/LenientParseTest.java | 30 ++++++++++++++-- .../Format/NumberFormat/StrictParseTest.java | 34 ++++++++++++++++--- 3 files changed, 67 insertions(+), 11 deletions(-) diff --git a/src/java.base/share/classes/java/text/DecimalFormat.java b/src/java.base/share/classes/java/text/DecimalFormat.java index 1f249888a28..04acca1ceb5 100644 --- a/src/java.base/share/classes/java/text/DecimalFormat.java +++ b/src/java.base/share/classes/java/text/DecimalFormat.java @@ -2379,8 +2379,8 @@ private final boolean subparse(String text, ParsePosition parsePosition, NumericPosition pos = subparseNumber(text, position, digits, true, isExponent, status); position = pos.fullPos; - // First character after the prefix was un-parseable, should - // fail regardless if lenient or strict. + // First character after the prefix was un-parseable or parsing integer + // only with no integer portion. Should fail regardless if lenient or strict. if (position == -1) { parsePosition.index = oldStart; parsePosition.errorIndex = oldStart; @@ -2421,8 +2421,8 @@ private final boolean subparse(String text, ParsePosition parsePosition, } // When parsing integer only, index should be int pos - // If intPos is 0, the entire value was integer - if (isParseIntegerOnly() && pos.intPos > 0) { + // If intPos is -1, the entire value was integer and index should be full pos + if (isParseIntegerOnly() && pos.intPos != -1) { parsePosition.index = pos.intPos; } else { // increment the index by the suffix @@ -2474,7 +2474,7 @@ NumericPosition subparseNumber(String text, int position, boolean isExponent, boolean[] status) { // process digits or Inf, find decimal position status[STATUS_INFINITE] = false; - int intIndex = 0; + int intIndex = -1; if (!isExponent && text.regionMatches(position, symbols.getInfinity(), 0, symbols.getInfinity().length())) { position += symbols.getInfinity().length(); @@ -2570,6 +2570,10 @@ NumericPosition subparseNumber(String text, int position, // Cancel out backup setting (see grouping handler below) backup = -1; } else if (!isExponent && ch == decimal) { + if (isParseIntegerOnly() && startPos == position) { + // Parsing int only with no integer portion, fail + return new NumericPosition(-1, intIndex); + } // Check grouping size on decimal separator if (parseStrict && isGroupingViolation(position, prevSeparatorIndex)) { return new NumericPosition( diff --git a/test/jdk/java/text/Format/NumberFormat/LenientParseTest.java b/test/jdk/java/text/Format/NumberFormat/LenientParseTest.java index 41f8961ff32..c85fe0f6cbb 100644 --- a/test/jdk/java/text/Format/NumberFormat/LenientParseTest.java +++ b/test/jdk/java/text/Format/NumberFormat/LenientParseTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8327640 8331485 8333456 + * @bug 8327640 8331485 8333456 8335668 * @summary Test suite for NumberFormat parsing when lenient. * @run junit/othervm -Duser.language=en -Duser.country=US LenientParseTest * @run junit/othervm -Duser.language=ja -Duser.country=JP LenientParseTest @@ -128,6 +128,28 @@ public void numFmtStrictIntegerOnlyUsed(String toParse, int expectedValue, int e dFmt.setParseIntegerOnly(false); } + // 8335668: Parsing with integer only against String with no integer portion + // should fail, not return 0. Expected error index should be 0 + @Test + public void integerParseOnlyFractionOnlyTest() { + var fmt = NumberFormat.getIntegerInstance(); + failParse(fmt, localizeText("."), 0); + failParse(fmt, localizeText(".0"), 0); + failParse(fmt, localizeText(".55"), 0); + } + + // 8335668: Parsing with integer only against String with no integer portion + // should fail, not return 0. Expected error index should be 0 + @Test // Non-localized, run once + @EnabledIfSystemProperty(named = "user.language", matches = "en") + public void compactIntegerParseOnlyFractionOnlyTest() { + var fmt = NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT); + fmt.setParseIntegerOnly(true); + failParse(fmt, ".K", 0); + failParse(fmt, ".0K", 0); + failParse(fmt, ".55K", 0); + } + @Test // Non-localized, only run once @EnabledIfSystemProperty(named = "user.language", matches = "en") public void badExponentParseNumberFormatTest() { @@ -313,7 +335,11 @@ private static Stream validFullParseStrings() { Arguments.of("10000", 10000d), Arguments.of("100,000", 100000d), Arguments.of("1,000,000", 1000000d), - Arguments.of("10,000,000", 10000000d)) + Arguments.of("10,000,000", 10000000d), + // Smaller value cases (w/ decimal) + Arguments.of(".1", .1d), + Arguments.of("1.1", 1.1d), + Arguments.of("11.1", 11.1d)) .map(args -> Arguments.of( localizeText(String.valueOf(args.get()[0])), args.get()[1])); } diff --git a/test/jdk/java/text/Format/NumberFormat/StrictParseTest.java b/test/jdk/java/text/Format/NumberFormat/StrictParseTest.java index 333bc1b0506..3e90ccb39ce 100644 --- a/test/jdk/java/text/Format/NumberFormat/StrictParseTest.java +++ b/test/jdk/java/text/Format/NumberFormat/StrictParseTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8327640 8331485 8333755 + * @bug 8327640 8331485 8333755 8335668 * @summary Test suite for NumberFormat parsing with strict leniency * @run junit/othervm -Duser.language=en -Duser.country=US StrictParseTest * @run junit/othervm -Duser.language=ja -Duser.country=JP StrictParseTest @@ -203,6 +203,28 @@ public void numFmtStrictIntegerOnlyUsedTest(String toParse, Number expVal) { } } + // 8335668: Parsing with integer only against String with no integer portion + // should fail, not return 0. Expected error index should be 0 + @Test + public void integerParseOnlyFractionOnlyTest() { + var fmt = NumberFormat.getIntegerInstance(); + failParse(fmt, localizeText("."), 0); + failParse(fmt, localizeText(".0"), 0); + failParse(fmt, localizeText(".55"), 0); + } + + // 8335668: Parsing with integer only against String with no integer portion + // should fail, not return 0. Expected error index should be 0 + @Test // Non-localized, run once + @EnabledIfSystemProperty(named = "user.language", matches = "en") + public void compactIntegerParseOnlyFractionOnlyTest() { + var fmt = NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT); + fmt.setParseIntegerOnly(true); + failParse(fmt, ".K", 0); + failParse(fmt, ".0K", 0); + failParse(fmt, ".55K", 0); + } + // 8333755: Parsing behavior should follow normal strict behavior // when it comes to failures. @ParameterizedTest @@ -426,8 +448,8 @@ private static Stream badParseStrings() { Arguments.of("1,234a", 5), Arguments.of("1,.a", 2), Arguments.of("1.a", 2), - Arguments.of(".22a", 3), - Arguments.of(".1a1", 2), + Arguments.of("1.22a", 4), + Arguments.of("1.1a1", 3), Arguments.of("1,234,a", 5), // Double decimal Arguments.of("1,234..5", 5)) @@ -453,7 +475,11 @@ private static Stream validParseStrings() { Arguments.of("10000", 10000d), Arguments.of("100,000", 100000d), Arguments.of("1,000,000", 1000000d), - Arguments.of("10,000,000", 10000000d)) + Arguments.of("10,000,000", 10000000d), + // Smaller value cases (w/ decimal) + Arguments.of(".1", .1d), + Arguments.of("1.1", 1.1d), + Arguments.of("11.1", 11.1d)) .map(args -> Arguments.of( localizeText(String.valueOf(args.get()[0])), args.get()[1])); } From 9eb611e7f07ebb6eb0cbcca32d644abf8352c991 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Thu, 11 Jul 2024 19:53:52 +0000 Subject: [PATCH 053/460] 8334055: Unhelpful 'required: reference' diagnostics after JDK-8043226 Reviewed-by: vromero --- .../classes/com/sun/tools/javac/comp/Attr.java | 9 +-------- .../failures/CantAnnotateMissingSymbol.java | 16 ++++++++++++++++ .../failures/CantAnnotateMissingSymbol.out | 2 ++ .../failures/CantAnnotatePackages.java | 2 +- .../failures/CantAnnotatePackages.out | 6 +++--- .../failures/CantAnnotateScoping.java | 2 +- .../failures/CantAnnotateScoping.out | 9 ++++----- 7 files changed, 28 insertions(+), 18 deletions(-) create mode 100644 test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateMissingSymbol.java create mode 100644 test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateMissingSymbol.out diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index f58319496e9..9b79846ba40 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -5241,14 +5241,7 @@ public void visitModifiers(JCModifiers tree) { public void visitAnnotatedType(JCAnnotatedType tree) { attribAnnotationTypes(tree.annotations, env); - Type underlyingType = - attribTree(tree.underlyingType, env, new ResultInfo(KindSelector.TYP_PCK, Type.noType)); - if (underlyingType.hasTag(PACKAGE)) { - // Type annotations are not admissible on packages, but we handle packages here to - // report better diagnostics later in validateAnnotatedType. - result = tree.type = underlyingType; - return; - } + Type underlyingType = attribType(tree.underlyingType, env); Type annotatedType = underlyingType.preannotatedType(); if (!env.info.isNewClass) diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateMissingSymbol.java b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateMissingSymbol.java new file mode 100644 index 00000000000..469cffa37a6 --- /dev/null +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateMissingSymbol.java @@ -0,0 +1,16 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8026564 8043226 + * @summary 8334055 + * @compile/fail/ref=CantAnnotateMissingSymbol.out -XDrawDiagnostics CantAnnotateMissingSymbol.java + */ + +import java.lang.annotation.*; +import java.util.List; + +class CantAnnotateMissingSymbol { + List<@TA NoSuch> x; +} + +@Target(ElementType.TYPE_USE) +@interface TA { } diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateMissingSymbol.out b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateMissingSymbol.out new file mode 100644 index 00000000000..b875cd2be7b --- /dev/null +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateMissingSymbol.out @@ -0,0 +1,2 @@ +CantAnnotateMissingSymbol.java:12:14: compiler.err.cant.resolve.location: kindname.class, NoSuch, , , (compiler.misc.location: kindname.class, CantAnnotateMissingSymbol, null) +1 error diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotatePackages.java b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotatePackages.java index d7587dfcf5f..d35351b6f40 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotatePackages.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotatePackages.java @@ -1,6 +1,6 @@ /* * @test /nodynamiccopyright/ - * @bug 8026564 8043226 + * @bug 8026564 8043226 8334055 * @summary The parts of a fully-qualified type can't be annotated. * @author Werner Dietl * @compile/fail/ref=CantAnnotatePackages.out -XDrawDiagnostics CantAnnotatePackages.java diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotatePackages.out b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotatePackages.out index 6e2b9cb93b0..b91d65828b9 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotatePackages.out +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotatePackages.out @@ -1,5 +1,5 @@ +CantAnnotatePackages.java:16:14: compiler.err.cant.resolve.location: kindname.class, java, , , (compiler.misc.location: kindname.class, CantAnnotatePackages, null) +CantAnnotatePackages.java:17:9: compiler.err.cant.resolve.location: kindname.class, lang, , , (compiler.misc.location: kindname.package, java, null) +CantAnnotatePackages.java:18:14: compiler.err.cant.resolve.location: kindname.class, lang, , , (compiler.misc.location: kindname.package, java, null) CantAnnotatePackages.java:14:18: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @TA), java.lang, @TA java.lang.Object -CantAnnotatePackages.java:16:14: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @TA), java.lang, @TA java.lang.Object -CantAnnotatePackages.java:17:9: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @TA), java.lang, @TA java.lang.Object -CantAnnotatePackages.java:18:14: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @TA), java.lang, @TA java.lang.Object 4 errors diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.java b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.java index aec691c913d..4bdd791909c 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.java @@ -1,6 +1,6 @@ /* * @test /nodynamiccopyright/ - * @bug 8006733 8006775 8043226 + * @bug 8006733 8006775 8043226 8334055 * @summary Ensure behavior for nested types is correct. * @author Werner Dietl * @compile/fail/ref=CantAnnotateScoping.out -XDrawDiagnostics CantAnnotateScoping.java diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.out b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.out index 2ae736ad315..ade5333a446 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.out +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.out @@ -1,13 +1,12 @@ -CantAnnotateScoping.java:68:18: compiler.err.doesnt.exist: java.XXX +CantAnnotateScoping.java:63:9: compiler.err.cant.resolve.location: kindname.class, lang, , , (compiler.misc.location: kindname.package, java, null) +CantAnnotateScoping.java:68:9: compiler.err.cant.resolve.location: kindname.class, XXX, , , (compiler.misc.location: kindname.package, java, null) +CantAnnotateScoping.java:71:9: compiler.err.cant.resolve.location: kindname.class, lang, , , (compiler.misc.location: kindname.package, java, null) CantAnnotateScoping.java:38:14: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @TA), Test.Outer, @TA Test.Outer.SInner CantAnnotateScoping.java:51:18: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @TA), java.lang, @TA java.lang.Object CantAnnotateScoping.java:60:37: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation: @TA,@TA2), java.lang, @DTA @TA @TA2 java.lang.Object CantAnnotateScoping.java:40:14: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @TA), Test.Outer, @TA Test.Outer.SInner -CantAnnotateScoping.java:63:11: compiler.err.annotation.type.not.applicable.to.type: DA -CantAnnotateScoping.java:68:11: compiler.err.annotation.type.not.applicable.to.type: DA -CantAnnotateScoping.java:71:9: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @TA), java.lang, @TA java.lang.Object CantAnnotateScoping.java:44:34: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation: @TA,@TA2), Test.Outer, @TA @TA2 Test.Outer.SInner CantAnnotateScoping.java:44:25: compiler.err.annotation.type.not.applicable.to.type: DA CantAnnotateScoping.java:48:38: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @TA), Test.Outer, @TA Test.Outer.SInner CantAnnotateScoping.java:48:34: compiler.err.annotation.type.not.applicable.to.type: DA -12 errors +11 errors From 73e3e0edeb20c6f701b213423476f92fb05dd262 Mon Sep 17 00:00:00 2001 From: Dean Long Date: Thu, 11 Jul 2024 20:18:16 +0000 Subject: [PATCH 054/460] 8321509: False positive in get_trampoline fast path causes crash Reviewed-by: kvn, adinn, thartmann --- .../cpu/aarch64/globalDefinitions_aarch64.hpp | 4 +- .../cpu/aarch64/nativeInst_aarch64.cpp | 39 +++++++++---------- .../cpu/aarch64/nativeInst_aarch64.hpp | 7 ++-- src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp | 33 ++++++++++------ src/hotspot/share/code/relocInfo.cpp | 8 ++++ src/hotspot/share/code/relocInfo.hpp | 5 +++ 6 files changed, 58 insertions(+), 38 deletions(-) diff --git a/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp b/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp index 63f6c9491c8..faf635dc332 100644 --- a/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -76,4 +76,6 @@ const bool CCallingConventionRequiresIntsAsLongs = false; #define USE_POINTERS_TO_REGISTER_IMPL_ARRAY +#define USE_TRAMPOLINE_STUB_FIX_OWNER + #endif // CPU_AARCH64_GLOBALDEFINITIONS_AARCH64_HPP diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp index c88705618e6..5a3f9d228ca 100644 --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -51,13 +51,18 @@ void NativeInstruction::wrote(int offset) { } address NativeCall::destination() const { - address addr = (address)this; - address destination = instruction_address() + displacement(); + address addr = instruction_address(); + address destination = addr + displacement(); + + // Performance optimization: no need to call find_blob() if it is a self-call + if (destination == addr) { + return destination; + } // Do we use a trampoline stub for this call? CodeBlob* cb = CodeCache::find_blob(addr); - assert(cb && cb->is_nmethod(), "sanity"); - nmethod *nm = (nmethod *)cb; + assert(cb != nullptr && cb->is_nmethod(), "nmethod expected"); + nmethod *nm = cb->as_nmethod(); if (nm->stub_contains(destination) && is_NativeCallTrampolineStub_at(destination)) { // Yes we do, so get the destination from the trampoline stub. const address trampoline_stub_addr = destination; @@ -72,12 +77,8 @@ address NativeCall::destination() const { // call instruction at all times. // // Used in the runtime linkage of calls; see class CompiledIC. -// -// Add parameter assert_lock to switch off assertion -// during code generation, where no patching lock is needed. -void NativeCall::set_destination_mt_safe(address dest, bool assert_lock) { - assert(!assert_lock || - (Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) || +void NativeCall::set_destination_mt_safe(address dest) { + assert((Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) || CompiledICLocker::is_safe(addr_at(0)), "concurrent code patching"); @@ -104,22 +105,18 @@ void NativeCall::set_destination_mt_safe(address dest, bool assert_lock) { } address NativeCall::get_trampoline() { - address call_addr = addr_at(0); + address call_addr = instruction_address(); CodeBlob *code = CodeCache::find_blob(call_addr); - assert(code != nullptr, "Could not find the containing code blob"); + assert(code != nullptr && code->is_nmethod(), "nmethod expected"); + nmethod* nm = code->as_nmethod(); - address bl_destination - = MacroAssembler::pd_call_destination(call_addr); - if (code->contains(bl_destination) && + address bl_destination = call_addr + displacement(); + if (nm->stub_contains(bl_destination) && is_NativeCallTrampolineStub_at(bl_destination)) return bl_destination; - if (code->is_nmethod()) { - return trampoline_stub_Relocation::get_trampoline_for(call_addr, (nmethod*)code); - } - - return nullptr; + return trampoline_stub_Relocation::get_trampoline_for(call_addr, nm); } // Inserts a native call instruction at a given pc diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp index 974214d985b..0eb5ff815be 100644 --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2108, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -174,6 +174,7 @@ class NativeCall: public NativeInstruction { int displacement() const { return (int_at(displacement_offset) << 6) >> 4; } address displacement_address() const { return addr_at(displacement_offset); } address return_address() const { return addr_at(return_address_offset); } + address raw_destination() const { return instruction_address() + displacement(); } address destination() const; void set_destination(address dest) { @@ -213,9 +214,7 @@ class NativeCall: public NativeInstruction { // // Used in the runtime linkage of calls; see class CompiledIC. // (Cf. 4506997 and 4479829, where threads witnessed garbage displacements.) - - // The parameter assert_lock disables the assertion during code generation. - void set_destination_mt_safe(address dest, bool assert_lock = true); + void set_destination_mt_safe(address dest); address get_trampoline(); #if INCLUDE_JVMCI diff --git a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp index 332f2499693..c4c8648d552 100644 --- a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp @@ -60,13 +60,12 @@ void Relocation::pd_set_data_value(address x, bool verify_only) { address Relocation::pd_call_destination(address orig_addr) { assert(is_call(), "should be a call here"); - if (NativeCall::is_call_at(addr())) { - address trampoline = nativeCall_at(addr())->get_trampoline(); - if (trampoline) { - return nativeCallTrampolineStub_at(trampoline)->destination(); + if (orig_addr == nullptr) { + if (NativeCall::is_call_at(addr())) { + NativeCall* call = nativeCall_at(addr()); + return call->destination(); } - } - if (orig_addr != nullptr) { + } else { address new_addr = MacroAssembler::pd_call_destination(orig_addr); // If call is branch to self, don't try to relocate it, just leave it // as branch to self. This happens during code generation if the code @@ -82,16 +81,26 @@ address Relocation::pd_call_destination(address orig_addr) { void Relocation::pd_set_call_destination(address x) { assert(is_call(), "should be a call here"); if (NativeCall::is_call_at(addr())) { - address trampoline = nativeCall_at(addr())->get_trampoline(); - if (trampoline) { - nativeCall_at(addr())->set_destination_mt_safe(x, /* assert_lock */false); - return; - } + NativeCall* call = nativeCall_at(addr()); + call->set_destination(x); + } else { + MacroAssembler::pd_patch_instruction(addr(), x); } - MacroAssembler::pd_patch_instruction(addr(), x); assert(pd_call_destination(addr()) == x, "fail in reloc"); } +void trampoline_stub_Relocation::pd_fix_owner_after_move() { + NativeCall* call = nativeCall_at(owner()); + assert(call->raw_destination() == owner(), "destination should be empty"); + address trampoline = addr(); + address dest = nativeCallTrampolineStub_at(trampoline)->destination(); + if (!Assembler::reachable_from_branch_at(owner(), dest)) { + dest = trampoline; + } + call->set_destination(dest); +} + + address* Relocation::pd_address_in_code() { return (address*)(addr() + 8); } diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp index 3b19b63f244..a379f88ddc1 100644 --- a/src/hotspot/share/code/relocInfo.cpp +++ b/src/hotspot/share/code/relocInfo.cpp @@ -373,6 +373,14 @@ void CallRelocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer } +#ifdef USE_TRAMPOLINE_STUB_FIX_OWNER +void trampoline_stub_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { + // Finalize owner destination only for nmethods + if (dest->blob() != nullptr) return; + pd_fix_owner_after_move(); +} +#endif + //// pack/unpack methods void oop_Relocation::pack_data_to(CodeSection* dest) { diff --git a/src/hotspot/share/code/relocInfo.hpp b/src/hotspot/share/code/relocInfo.hpp index 6d0907d97de..25cca49e50b 100644 --- a/src/hotspot/share/code/relocInfo.hpp +++ b/src/hotspot/share/code/relocInfo.hpp @@ -1258,6 +1258,11 @@ class runtime_call_w_cp_Relocation : public CallRelocation { // in the code, it can patch it to jump to the trampoline where is // sufficient space for a far branch. Needed on PPC. class trampoline_stub_Relocation : public Relocation { +#ifdef USE_TRAMPOLINE_STUB_FIX_OWNER + void pd_fix_owner_after_move(); + void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) override; +#endif + public: static RelocationHolder spec(address static_call) { return RelocationHolder::construct(static_call); From 889055713ea83f899ebd7bf640dcf3c3e1a82ebe Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Thu, 11 Jul 2024 20:44:21 +0000 Subject: [PATCH 055/460] 8335623: Clean up HtmlTag.HtmlTag and make the ARIA role attribute global Reviewed-by: liach --- .../jdk/javadoc/internal/doclint/HtmlTag.java | 22 +------------------ 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/HtmlTag.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/HtmlTag.java index 0c820dae913..fa9d3ea578d 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/HtmlTag.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/HtmlTag.java @@ -507,7 +507,7 @@ public enum Attr { PROFILE, REV, REVERSED, - ROLE, + ROLE(true), ROWSPAN, RULES, SCHEME, @@ -606,26 +606,6 @@ private static class AttrMap extends EnumMap { this.attrs = new EnumMap<>(Attr.class); for (Map m: attrMaps) this.attrs.putAll(m); - attrs.put(Attr.CLASS, AttrKind.OK); - attrs.put(Attr.ID, AttrKind.OK); - attrs.put(Attr.STYLE, AttrKind.OK); - attrs.put(Attr.ROLE, AttrKind.OK); - // for now, assume that all ARIA attributes are allowed on all tags. - attrs.put(Attr.ARIA_ACTIVEDESCENDANT, AttrKind.OK); - attrs.put(Attr.ARIA_CONTROLS, AttrKind.OK); - attrs.put(Attr.ARIA_DESCRIBEDBY, AttrKind.OK); - attrs.put(Attr.ARIA_EXPANDED, AttrKind.OK); - attrs.put(Attr.ARIA_LABEL, AttrKind.OK); - attrs.put(Attr.ARIA_LABELLEDBY, AttrKind.OK); - attrs.put(Attr.ARIA_LEVEL, AttrKind.OK); - attrs.put(Attr.ARIA_MULTISELECTABLE, AttrKind.OK); - attrs.put(Attr.ARIA_OWNS, AttrKind.OK); - attrs.put(Attr.ARIA_POSINSET, AttrKind.OK); - attrs.put(Attr.ARIA_READONLY, AttrKind.OK); - attrs.put(Attr.ARIA_REQUIRED, AttrKind.OK); - attrs.put(Attr.ARIA_SELECTED, AttrKind.OK); - attrs.put(Attr.ARIA_SETSIZE, AttrKind.OK); - attrs.put(Attr.ARIA_SORT, AttrKind.OK); } public boolean accepts(HtmlTag t) { From 687601ebcaedf133fd4d5cecc42c5aadf9c73f3c Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Thu, 11 Jul 2024 20:45:34 +0000 Subject: [PATCH 056/460] 8336257: Additional tests in jmxremote/startstop to match on PID not app name Reviewed-by: cjplummer, alanb, amenkov, dcubed --- .../sun/management/jmxremote/startstop/JMXStartStopTest.java | 5 +++-- .../jmxremote/startstop/JMXStatusPerfCountersTest.java | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/test/jdk/sun/management/jmxremote/startstop/JMXStartStopTest.java b/test/jdk/sun/management/jmxremote/startstop/JMXStartStopTest.java index 13a4f7bea73..3d125325449 100644 --- a/test/jdk/sun/management/jmxremote/startstop/JMXStartStopTest.java +++ b/test/jdk/sun/management/jmxremote/startstop/JMXStartStopTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -72,7 +72,7 @@ public class JMXStartStopTest { private static final boolean verbose = false; - private static ManagementAgentJcmd jcmd = new ManagementAgentJcmd(TEST_APP_NAME, verbose); + private static ManagementAgentJcmd jcmd; private static void dbg_print(String msg) { if (verbose) { @@ -347,6 +347,7 @@ public synchronized void start() throws InterruptedException, IOException, Timeo "the requested port not being available"); } pid = p.pid(); + jcmd = new ManagementAgentJcmd(p, verbose); } catch (TimeoutException e) { if (p != null) { p.destroy(); diff --git a/test/jdk/sun/management/jmxremote/startstop/JMXStatusPerfCountersTest.java b/test/jdk/sun/management/jmxremote/startstop/JMXStatusPerfCountersTest.java index fc7a0de2d06..e3703ba8dbc 100644 --- a/test/jdk/sun/management/jmxremote/startstop/JMXStatusPerfCountersTest.java +++ b/test/jdk/sun/management/jmxremote/startstop/JMXStatusPerfCountersTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,7 +67,6 @@ public static void setupClass() throws Exception { @BeforeTest public void setup() { - jcmd = new ManagementAgentJcmd(TEST_APP_NAME, false); } @BeforeMethod @@ -76,6 +75,7 @@ public void startTestApp() throws Exception { TEST_APP_NAME, testAppPb, (Predicate)l->l.trim().equals("main enter") ); + jcmd = new ManagementAgentJcmd(testApp, false); } @AfterMethod From b3ef2a600cfec31723dc78fe552e9cf9976b0337 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Thu, 11 Jul 2024 20:51:27 +0000 Subject: [PATCH 057/460] 8336036: Synthetic documentation for a record's equals is incorrect for floating-point types Reviewed-by: prappo --- .../doclets/toolkit/resources/doclets.properties | 6 ++++-- .../doclet/testRecordTypes/TestRecordTypes.java | 14 +++++++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties index 859289ff8bd..0ee9429ec0c 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties @@ -319,10 +319,12 @@ doclet.record_equals_doc.fullbody.head=\ doclet.record_equals_doc.fullbody.tail.both=\ Reference components are compared with \ {@link java.util.Objects#equals(Object,Object) Objects::equals(Object,Object)}; \ - primitive components are compared with '=='. + primitive components are compared with the compare method from \ + their corresponding wrapper classes. doclet.record_equals_doc.fullbody.tail.primitive=\ - All components in this record class are compared with '=='. + All components in this record class are compared with the compare \ + method from their corresponding wrapper classes. doclet.record_equals_doc.fullbody.tail.reference=\ All components in this record class are compared with \ diff --git a/test/langtools/jdk/javadoc/doclet/testRecordTypes/TestRecordTypes.java b/test/langtools/jdk/javadoc/doclet/testRecordTypes/TestRecordTypes.java index c4579c501ec..f9aa3cfd6fa 100644 --- a/test/langtools/jdk/javadoc/doclet/testRecordTypes/TestRecordTypes.java +++ b/test/langtools/jdk/javadoc/doclet/testRecordTypes/TestRecordTypes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -237,7 +237,8 @@ public record R(int r1) { }"""); """ Indicates whether some other object is "equal to" this one. The objects are equa\ l if the other object is of the same class and if all the record components are \ - equal. All components in this record class are compared with '=='.""", + equal. All components in this record class are compared with the compare method from their corresponding wrapper classes.""", """ r1""", """ @@ -300,7 +301,8 @@ public record R(int r1) { }"""); """ Indicates whether some other object is "equal to" this one. The objects are equa\ l if the other object is of the same class and if all the record components are \ - equal. All components in this record class are compared with '=='.""", + equal. All components in this record class are compared with the compare method from their corresponding wrapper classes.""", """ r1""", """ @@ -311,7 +313,8 @@ l if the other object is of the same class and if all the record components are @Test public void testGeneratedEqualsPrimitive(Path base) throws IOException { testGeneratedEquals(base, "int a, int b", - "All components in this record class are compared with '=='."); + "All components in this record class are compared with the compare method " + + "from their corresponding wrapper classes."); } @Test @@ -324,7 +327,8 @@ public void testGeneratedEqualsReference(Path base) throws IOException { public void testGeneratedEqualsMixed(Path base) throws IOException { testGeneratedEquals(base, "int a, Object b", "Reference components are compared with Objects::equals(Object,Object); " - + "primitive components are compared with '=='."); + + "primitive components are compared with the compare method from their " + + "corresponding wrapper classes."); } private void testGeneratedEquals(Path base, String comps, String expect) throws IOException { From 81a0d1ba03bbdbe718302b3925cdc207d5d05232 Mon Sep 17 00:00:00 2001 From: Vanitha B P Date: Thu, 11 Jul 2024 21:27:30 +0000 Subject: [PATCH 058/460] 8325525: Create jtreg test case for JDK-8325203 Reviewed-by: asemenyuk, almatvee --- .../apps/ChildProcessAppLauncher.java | 37 ++++++++ .../jpackage/windows/WinChildProcessTest.java | 88 +++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 test/jdk/tools/jpackage/apps/ChildProcessAppLauncher.java create mode 100644 test/jdk/tools/jpackage/windows/WinChildProcessTest.java diff --git a/test/jdk/tools/jpackage/apps/ChildProcessAppLauncher.java b/test/jdk/tools/jpackage/apps/ChildProcessAppLauncher.java new file mode 100644 index 00000000000..11be90bc456 --- /dev/null +++ b/test/jdk/tools/jpackage/apps/ChildProcessAppLauncher.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; + +public class ChildProcessAppLauncher { + + public static void main(String[] args) throws IOException { + String calcPath = Path.of(System.getenv("SystemRoot"), "system32", "calc.exe").toString(); + ProcessBuilder processBuilder = new ProcessBuilder(calcPath); + Process process = processBuilder.start(); + System.out.println("Calc id=" + process.pid()); + System.exit(0); + } +} diff --git a/test/jdk/tools/jpackage/windows/WinChildProcessTest.java b/test/jdk/tools/jpackage/windows/WinChildProcessTest.java new file mode 100644 index 00000000000..2928f7f1c5f --- /dev/null +++ b/test/jdk/tools/jpackage/windows/WinChildProcessTest.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 8325203 + * @summary Test that Jpackage windows executable application kills the launched 3rd party application + * when System.exit(0) is invoked along with terminating java program. + * @library ../helpers + * @library /test/lib + * @requires os.family == "windows" + * @build WinChildProcessTest + * @build jdk.jpackage.test.* + * @build WinChildProcessTest + * @modules jdk.jpackage/jdk.jpackage.internal + * @run main/othervm -Xmx512m jdk.jpackage.test.Main + * --jpt-run=WinChildProcessTest + * + */ + +import java.util.List; +import java.util.Optional; + +import java.nio.file.Path; + +import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.Executor; +import jdk.jpackage.test.TKit; + +public class WinChildProcessTest { + private static final Path TEST_APP_JAVA = TKit.TEST_SRC_ROOT + .resolve("apps/ChildProcessAppLauncher.java"); + + @Test + public static void test() throws Throwable { + long calcPid = 0; + try { + JPackageCommand cmd = JPackageCommand + .helloAppImage(TEST_APP_JAVA + "*Hello"); + + // Create the image of the third party application launcher + cmd.executeAndAssertImageCreated(); + + // Start the third party application launcher and dump and save the + // output of the application + List output = new Executor().saveOutput().dumpOutput() + .setExecutable(cmd.appLauncherPath().toAbsolutePath()) + .execute(0).getOutput(); + String pidStr = output.get(0); + + // parse calculator PID + calcPid = Long.parseLong(pidStr.split("=", 2)[1]); + + // Check whether the termination of third party application launcher + // also terminating the launched third party application + // If third party application is not terminated the test is + // successful else failure + Optional processHandle = ProcessHandle.of(calcPid); + boolean isAlive = processHandle.isPresent() + && processHandle.get().isAlive(); + System.out.println("Is Alive " + isAlive); + TKit.assertTrue(isAlive, "Check is calculator process is alive"); + } finally { + // Kill only a specific calculator instance + Runtime.getRuntime().exec("taskkill /F /PID " + calcPid); + } + } +} \ No newline at end of file From c703d290425f85a06e61d72c9672ac2adac92db9 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Fri, 12 Jul 2024 05:56:53 +0000 Subject: [PATCH 059/460] 8335710: serviceability/dcmd/vm/SystemDumpMapTest.java and SystemMapTest.java fail on Linux Alpine after 8322475 Reviewed-by: stuefe, lucy --- .../jtreg/serviceability/dcmd/vm/SystemMapTestBase.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTestBase.java b/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTestBase.java index 000e977a590..3d1284b09ee 100644 --- a/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTestBase.java +++ b/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTestBase.java @@ -49,8 +49,8 @@ public class SystemMapTestBase { regexBase_committed + "/bin/java", // libjvm regexBase_committed + "/lib/.*/libjvm.so", - // vdso library, should be part of all user space apps on all architectures OpenJDK supports. - regexBase_committed + "\\[vdso\\]", + // heap segment, should be part of all user space apps on all architectures OpenJDK supports. + regexBase_committed + "\\[heap\\]", // we should see the hs-perf data file, and it should appear as shared as well as committed regexBase_shared_and_committed + "hsperfdata_.*" }; From 1fe3ada001e188754df5de00bf6804f028ad274b Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Fri, 12 Jul 2024 08:14:56 +0000 Subject: [PATCH 060/460] 8336284: Test TestClhsdbJstackLock.java/TestJhsdbJstackLock.java fails with -Xcomp after JDK-8335743 Reviewed-by: cjplummer, amenkov --- test/hotspot/jtreg/serviceability/sa/TestClhsdbJstackLock.java | 2 +- test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackLock.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/serviceability/sa/TestClhsdbJstackLock.java b/test/hotspot/jtreg/serviceability/sa/TestClhsdbJstackLock.java index e4d4361e651..266b14167ef 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestClhsdbJstackLock.java +++ b/test/hotspot/jtreg/serviceability/sa/TestClhsdbJstackLock.java @@ -59,7 +59,7 @@ public static void main (String... args) throws Exception { "^\\s+- waiting to lock <0x[0-9a-f]+> \\(a java\\.lang\\.Class for LingeredAppWithLock\\)$", "^\\s+- locked <0x[0-9a-f]+> \\(a java\\.lang\\.Thread\\)$", "^\\s+- locked <0x[0-9a-f]+> \\(a java\\.lang\\.Class for int\\)$", - "^\\s+- waiting on <0x[0-9a-f]+> \\(a java\\.lang\\.Object\\)$")); + "^\\s+- waiting on (<0x[0-9a-f]+> \\(a java\\.lang\\.Object\\)|)$")); unExpStrMap.put("jstack", List.of( "missing reason for ")); test.run(app.getPid(), cmds, expStrMap, unExpStrMap); diff --git a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackLock.java b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackLock.java index 98c42866091..d3c7f611031 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackLock.java +++ b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackLock.java @@ -65,7 +65,7 @@ public static void main (String... args) throws Exception { out.shouldMatch("^\\s+- waiting to lock <0x[0-9a-f]+> \\(a java\\.lang\\.Class for LingeredAppWithLock\\)$"); out.shouldMatch("^\\s+- locked <0x[0-9a-f]+> \\(a java\\.lang\\.Thread\\)$"); out.shouldMatch("^\\s+- locked <0x[0-9a-f]+> \\(a java\\.lang\\.Class for int\\)$"); - out.shouldMatch("^\\s+- waiting on <0x[0-9a-f]+> \\(a java\\.lang\\.Object\\)$"); + out.shouldMatch("^\\s+- waiting on (<0x[0-9a-f]+> \\(a java\\.lang\\.Object\\)|)$"); out.stderrShouldBeEmptyIgnoreDeprecatedWarnings(); From f677b90eb93026d3fdfd4ae19d48415a7d8318e8 Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Fri, 12 Jul 2024 08:19:24 +0000 Subject: [PATCH 061/460] 8267887: RMIConnector_NPETest.java fails after removal of RMI Activation (JDK-8267123) Reviewed-by: cjplummer, sspitsyn --- test/jdk/ProblemList.txt | 2 - .../connection/RMIConnector_NPETest.java | 77 ------------------- 2 files changed, 79 deletions(-) delete mode 100644 test/jdk/javax/management/remote/mandatory/connection/RMIConnector_NPETest.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 20dfcef539d..05e42b49330 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -528,8 +528,6 @@ javax/management/MBeanServer/OldMBeanServerTest.java 8030957 aix-all javax/management/monitor/DerivedGaugeMonitorTest.java 8042211 generic-all -javax/management/remote/mandatory/connection/RMIConnector_NPETest.java 8267887 generic-all - javax/management/remote/mandatory/connection/BrokenConnectionTest.java 8262312 linux-all ############################################################################ diff --git a/test/jdk/javax/management/remote/mandatory/connection/RMIConnector_NPETest.java b/test/jdk/javax/management/remote/mandatory/connection/RMIConnector_NPETest.java deleted file mode 100644 index 29a91a464c7..00000000000 --- a/test/jdk/javax/management/remote/mandatory/connection/RMIConnector_NPETest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2010, 2016, 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 - * @summary NPE IN RMIConnector.connect - * @bug 6984520 - * @library /java/rmi/testlibrary - * @modules java.management.rmi - * java.rmi/sun.rmi.registry - * java.rmi/sun.rmi.server - * java.rmi/sun.rmi.transport - * java.rmi/sun.rmi.transport.tcp - * @run clean RMIConnector_NPETest - * @run build TestLibrary RMID - * @run build RMIConnector_NPETest - * @run main RMIConnector_NPETest - */ -import java.io.IOException; -import javax.management.*; -import javax.management.remote.rmi.*; - -public class RMIConnector_NPETest { - public static void main(String argv[]) throws Exception { - RMID rmid = RMID.createRMID(); - Exception failureCause = null; - RMIConnector agent = null; - - try { - rmid.start(); - int rmidPort = rmid.getPort(); - MBeanServer mbs = MBeanServerFactory.createMBeanServer(); - RMIJRMPServerImpl rmiserver = new RMIJRMPServerImpl(rmidPort, null, null, null); - rmiserver.setMBeanServer(mbs); - agent = new RMIConnector(rmiserver, null); - agent.connect(); - } catch (NullPointerException npe) { - failureCause = npe; - } catch (Exception e) { - // OK - } finally { - if (agent != null) { - try { - agent.close(); - } catch (IOException e) { - // ignore - } - } - rmid.destroy(); - } - - if (failureCause != null) { - TestLibrary.bomb("Test failed", failureCause); - } - - } -} From 7a6203296416268f1c3f269d0db2b0c817642a34 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Fri, 12 Jul 2024 09:30:38 +0000 Subject: [PATCH 062/460] 8336081: Fix -Wzero-as-null-pointer-constant warnings in JVMTypedFlagLimit ctors Reviewed-by: dholmes, jwaters --- src/hotspot/share/runtime/flags/jvmFlagLimit.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/runtime/flags/jvmFlagLimit.hpp b/src/hotspot/share/runtime/flags/jvmFlagLimit.hpp index 69df96f226d..4a9c9c66d9b 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagLimit.hpp +++ b/src/hotspot/share/runtime/flags/jvmFlagLimit.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -155,7 +155,7 @@ class JVMTypedFlagLimit : public JVMFlagLimit { // dummy - no range or constraint. This object will not be emitted into the .o file // because we declare it as "const" but has no reference to it. constexpr JVMTypedFlagLimit(int type_enum) : - JVMFlagLimit(0, 0, JVMFlagConstraintPhase::AtParse, 0), _min(0), _max(0) {} + JVMFlagLimit(0, 0, JVMFlagConstraintPhase::AtParse, 0), _min(), _max() {} // range only constexpr JVMTypedFlagLimit(int type_enum, T min, T max) : @@ -163,7 +163,7 @@ class JVMTypedFlagLimit : public JVMFlagLimit { // constraint only constexpr JVMTypedFlagLimit(int type_enum, ConstraintMarker dummy2, short func, JVMFlagConstraintPhase phase) : - JVMFlagLimit(type_enum, func, phase, HAS_CONSTRAINT), _min(0), _max(0) {} + JVMFlagLimit(type_enum, func, phase, HAS_CONSTRAINT), _min(), _max() {} // range and constraint constexpr JVMTypedFlagLimit(int type_enum, T min, T max, ConstraintMarker dummy2, short func, JVMFlagConstraintPhase phase) : From 9b6f6c5c9dd6d0fbb056e8d84c3a0888a3320edf Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Fri, 12 Jul 2024 09:33:04 +0000 Subject: [PATCH 063/460] 8336082: Fix -Wzero-as-null-pointer-constant warnings in SimpleCompactHashtable Reviewed-by: coleenp, dholmes --- .../share/classfile/compactHashtable.hpp | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/classfile/compactHashtable.hpp b/src/hotspot/share/classfile/compactHashtable.hpp index e99369cc5c3..6cb689ad20d 100644 --- a/src/hotspot/share/classfile/compactHashtable.hpp +++ b/src/hotspot/share/classfile/compactHashtable.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -204,18 +204,20 @@ class SimpleCompactHashtable { u4* _entries; public: - SimpleCompactHashtable() { - _entry_count = 0; - _bucket_count = 0; - _buckets = 0; - _entries = 0; - } + SimpleCompactHashtable() : + _base_address(nullptr), + _bucket_count(0), + _entry_count(0), + _buckets(nullptr), + _entries(nullptr) + {} void reset() { + _base_address = nullptr; _bucket_count = 0; _entry_count = 0; - _buckets = 0; - _entries = 0; + _buckets = nullptr; + _entries = nullptr; } void init(address base_address, u4 entry_count, u4 bucket_count, u4* buckets, u4* entries); From eec0e155f303ff4bbdab172765ca7c92c2b94cbd Mon Sep 17 00:00:00 2001 From: Volker Simonis Date: Fri, 12 Jul 2024 12:09:58 +0000 Subject: [PATCH 064/460] 8335619: Add an @apiNote to j.l.i.ClassFileTransformer to warn about recursive class loading and ClassCircularityErrors Reviewed-by: alanb, stuefe, liach --- .../lang/instrument/ClassFileTransformer.java | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java b/src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java index d4c17f1cfdc..ee2037fac5b 100644 --- a/src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java +++ b/src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -155,11 +155,28 @@ * logging or debugging of format corruptions. * *

- * Note the term class file is used as defined in section 3.1 of - * The Java Virtual Machine Specification, to mean a - * sequence of bytes in class file format, whether or not they reside in a + * Note the term class file is used as defined in chapter {@jvms 4} The + * {@code class} File Format of The Java Virtual Machine Specification, + * to mean a sequence of bytes in class file format, whether or not they reside in a * file. * + * @apiNote + * Great care must be taken when transforming core JDK classes which are at the + * same time required during the transformation process as this can lead to class + * circularity or linkage errors. + * + *

+ * If for example the invocation of {@link #transform transform()} for a class + * {@code C} requires loading or resolving the same class {@code C}, + * an error is thrown that is an instance of {@link LinkageError} (or a subclass). + * If the {@link LinkageError} occurs during reference resolution (see section + * {@jvms 5.4.3} Resolution of The Java Virtual Machine Specification) + * for a class {@code D}, the resolution of the corresponding reference in class + * {@code D} will permanently fail with the same error at any subsequent attempt. + * This means that a {@link LinkageError} triggered during transformation of + * {@code C} in a class {@code D} not directly related to {@code C} can repeatedly + * occur later in arbitrary user code which uses {@code D}. + * * @see java.lang.instrument.Instrumentation * @since 1.5 */ From 559826c2922851dbe45ead23ad1d73b1846334ac Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Fri, 12 Jul 2024 12:17:21 +0000 Subject: [PATCH 065/460] 8332474: Tighten up ToolBox' JavacTask to not silently accept javac crash as a failure Reviewed-by: vromero --- .../com/sun/tools/javac/comp/Modules.java | 1 + .../tools/lib/toolbox/AbstractTask.java | 60 ++++++++++++++++--- .../tools/lib/toolbox/JavacTask.java | 20 +++++++ 3 files changed, 72 insertions(+), 9 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java index 1136cb5621a..3d893252218 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java @@ -330,6 +330,7 @@ private void enterModule(JCCompilationUnit toplevel, ClassSymbol c, Set> implements Task { private final Map redirects = new EnumMap<>(OutputKind.class); private final Map envVars = new HashMap<>(); private Expect expect = Expect.SUCCESS; - int expectedExitCode = 0; + //validator for exit codes, first parameter is the exit code + //the second the test name: + private BiConsumer exitCodeValidator = null; /** * Create a task that will execute in the specified mode. @@ -67,7 +70,7 @@ protected AbstractTask(ToolBox tb, Mode mode) { * @return the result of calling {@code run()} */ public Result run(Expect expect) { - expect(expect, Integer.MIN_VALUE); + expect(expect, (_, _) -> {}); return run(); } @@ -83,17 +86,56 @@ public Result run(Expect expect, int exitCode) { return run(); } + /** + * Sets the expected outcome of the task and calls {@code run()}. + * @param expect the expected outcome + * @param exitCodeValidator an exit code validator. The first parameter will + * be the actual exit code, the second test name, + * should throw TaskError if the exit code is not + * as expected. Only used if the expected outcome + * is {@code FAIL} + * @return the result of calling {@code run()} + */ + public Result run(Expect expect, + BiConsumer exitCodeValidator) { + expect(expect, exitCodeValidator); + return run(); + } + + /** + * Sets the expected outcome and expected exit code of the task. + * The exit code will not be checked if the outcome is + * {@code Expect.SUCCESS} or if the exit code is set to + * {@code Integer.MIN_VALUE}. + * @param expect the expected outcome + * @param expectedExitCode the expected exit code + */ + protected void expect(Expect expect, int expectedExitCode) { + expect(expect, (exitCode, testName) -> { + if (expectedExitCode != Integer.MIN_VALUE && + exitCode != expectedExitCode) { + throw new TaskError("Task " + testName + "failed with unexpected exit code " + + exitCode + ", expected " + expectedExitCode); + } + }); + } + /** * Sets the expected outcome and expected exit code of the task. * The exit code will not be checked if the outcome is * {@code Expect.SUCCESS} or if the exit code is set to * {@code Integer.MIN_VALUE}. * @param expect the expected outcome - * @param exitCode the expected exit code + * @param exitCodeValidator an exit code validator. The first parameter will + * be the actual exit code, the second test name, + * should throw TaskError if the exit code is not + * as expected. Only used if the expected outcome + * is {@code FAIL} */ - protected void expect(Expect expect, int exitCode) { + protected void expect(Expect expect, + BiConsumer exitCodeValidator) { this.expect = expect; - this.expectedExitCode = exitCode; + this.exitCodeValidator = exitCodeValidator; } /** @@ -119,11 +161,11 @@ protected Result checkExit(Result result) throws TaskError { throw new TaskError("Task " + name() + " succeeded unexpectedly"); } - if (expectedExitCode != Integer.MIN_VALUE - && result.exitCode != expectedExitCode) { + try { + exitCodeValidator.accept(result.exitCode, name()); + } catch (Throwable t) { result.writeAll(); - throw new TaskError("Task " + name() + "failed with unexpected exit code " - + result.exitCode + ", expected " + expectedExitCode); + throw t; } break; } diff --git a/test/langtools/tools/lib/toolbox/JavacTask.java b/test/langtools/tools/lib/toolbox/JavacTask.java index 5991d9e6063..ed056099e84 100644 --- a/test/langtools/tools/lib/toolbox/JavacTask.java +++ b/test/langtools/tools/lib/toolbox/JavacTask.java @@ -314,6 +314,26 @@ public String name() { return "javac"; } + @Override + public Result run(Expect expect) { + int expectedExitCode = expect == Expect.SUCCESS ? 0 : 1; + + return run(expect, (exitCode, testName) -> { + if (exitCode == 4) { + throw new TaskError("Task " + testName + " failed due to a javac crash " + + "(exit code 4)"); + } + }); + } + + @Override + public Result run(Expect expect, int exitCode) { + if (exitCode == 4) { + throw new IllegalArgumentException("Disallowed exit code: 4"); + } + return super.run(expect, exitCode); + } + /** * Calls the compiler with the arguments as currently configured. * @return a Result object indicating the outcome of the compilation From 2fc7eb44a018974734832576a0a2631ae747e0cd Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Fri, 12 Jul 2024 12:37:58 +0000 Subject: [PATCH 066/460] 8155030: The Menu Mnemonics are always displayed for GTK LAF Hides mnemonics on menus, buttons, and labels for GTK L&F. Moved shared code for hiding mnemonics into sun/swing/MnemonicHandler and AltProcessor to avoid code duplication. Reviewed-by: prr, tr, achung, dnguyen, aivanov --- .../classes/com/apple/laf/AquaButtonUI.java | 7 +- .../classes/com/apple/laf/AquaLabelUI.java | 21 +-- .../com/apple/laf/AquaLookAndFeel.java | 11 +- .../com/apple/laf/AquaMenuPainter.java | 38 ++++-- .../java/swing/plaf/gtk/GTKGraphicsUtils.java | 21 ++- .../java/swing/plaf/gtk/GTKLookAndFeel.java | 70 ++++++++-- .../share/classes/sun/swing/AltProcessor.java | 67 ++++++++++ .../classes/sun/swing/MnemonicHandler.java} | 100 ++++++--------- .../plaf/windows/WindowsGraphicsUtils.java | 75 ++++------- .../swing/plaf/windows/WindowsLabelUI.java | 7 +- .../plaf/windows/WindowsLookAndFeel.java | 42 +----- .../swing/plaf/windows/WindowsMenuBarUI.java | 6 +- .../swing/plaf/windows/WindowsMenuItemUI.java | 5 +- .../plaf/windows/WindowsPopupMenuUI.java | 9 +- .../swing/plaf/windows/WindowsRootPaneUI.java | 36 +++--- .../swing/JMenuBar/TestMenuMnemonic.java | 8 +- .../JMenuBar/TestMenuMnemonicLinuxAndMac.java | 121 ++++++++++++++++++ .../javax/swing/LookAndFeel/bug4736093.java | 12 +- .../plaf/windows/6921687/bug6921687.java | 11 +- 19 files changed, 428 insertions(+), 239 deletions(-) create mode 100644 src/java.desktop/share/classes/sun/swing/AltProcessor.java rename src/java.desktop/{macosx/classes/com/apple/laf/AquaMnemonicHandler.java => share/classes/sun/swing/MnemonicHandler.java} (52%) create mode 100644 test/jdk/javax/swing/JMenuBar/TestMenuMnemonicLinuxAndMac.java diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonUI.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonUI.java index dab893252cf..063923ff807 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonUI.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,6 +75,7 @@ import com.apple.laf.AquaUtilControlSize.Sizeable; import com.apple.laf.AquaUtils.RecyclableSingleton; import com.apple.laf.AquaUtils.RecyclableSingletonFromDefaultConstructor; +import sun.swing.MnemonicHandler; import sun.swing.SwingUtilities2; public class AquaButtonUI extends BasicButtonUI implements Sizeable { @@ -487,12 +488,10 @@ protected void paintIcon(final Graphics g, final AbstractButton b, final Rectang * Use the paintText method which takes the AbstractButton argument. */ protected void paintText(final Graphics g, final JComponent c, final Rectangle localTextRect, final String text) { - final Graphics2D g2d = g instanceof Graphics2D ? (Graphics2D)g : null; - final AbstractButton b = (AbstractButton)c; final ButtonModel model = b.getModel(); final FontMetrics fm = g.getFontMetrics(); - final int mnemonicIndex = AquaMnemonicHandler.isMnemonicHidden() ? -1 : b.getDisplayedMnemonicIndex(); + final int mnemonicIndex = MnemonicHandler.isMnemonicHidden() ? -1 : b.getDisplayedMnemonicIndex(); /* Draw the Text */ if (model.isEnabled()) { diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaLabelUI.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaLabelUI.java index fb5682d0541..e0f282325e4 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaLabelUI.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaLabelUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,16 +25,19 @@ package com.apple.laf; -import java.awt.*; +import java.awt.Color; +import java.awt.Graphics; -import javax.swing.*; -import javax.swing.plaf.*; -import javax.swing.plaf.basic.*; - -import sun.swing.SwingUtilities2; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicLabelUI; import com.apple.laf.AquaUtils.RecyclableSingleton; import com.apple.laf.AquaUtils.RecyclableSingletonFromDefaultConstructor; +import sun.swing.MnemonicHandler; +import sun.swing.SwingUtilities2; public class AquaLabelUI extends BasicLabelUI { private static final RecyclableSingleton aquaLabelUI = new RecyclableSingletonFromDefaultConstructor(AquaLabelUI.class); @@ -55,7 +58,7 @@ protected void uninstallListeners(final JLabel c) { protected void paintEnabledText(final JLabel l, final Graphics g, final String s, final int textX, final int textY) { int mnemIndex = l.getDisplayedMnemonicIndex(); - if (AquaMnemonicHandler.isMnemonicHidden()) { + if (MnemonicHandler.isMnemonicHidden()) { mnemIndex = -1; } @@ -72,7 +75,7 @@ protected void paintEnabledText(final JLabel l, final Graphics g, final String s */ protected void paintDisabledText(final JLabel l, final Graphics g, final String s, final int textX, final int textY) { int accChar = l.getDisplayedMnemonicIndex(); - if (AquaMnemonicHandler.isMnemonicHidden()) { + if (MnemonicHandler.isMnemonicHidden()) { accChar = -1; } diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaLookAndFeel.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaLookAndFeel.java index d68cd1448ea..83604e5d835 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaLookAndFeel.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaLookAndFeel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,8 @@ import apple.laf.JRSUIControl; import apple.laf.JRSUIUtils; +import sun.swing.AltProcessor; +import sun.swing.MnemonicHandler; import sun.swing.SwingAccessor; import sun.swing.SwingUtilities2; @@ -174,7 +176,9 @@ public Void run() { spf.setActive(true); PopupFactory.setSharedInstance(spf); - KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventPostProcessor(AquaMnemonicHandler.getInstance()); + KeyboardFocusManager.getCurrentKeyboardFocusManager() + .addKeyEventPostProcessor(AltProcessor.getInstance()); + MnemonicHandler.setMnemonicHidden(true); } /** @@ -185,7 +189,8 @@ public Void run() { * @see #initialize */ public void uninitialize() { - KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventPostProcessor(AquaMnemonicHandler.getInstance()); + KeyboardFocusManager.getCurrentKeyboardFocusManager() + .removeKeyEventPostProcessor(AltProcessor.getInstance()); final PopupFactory popupFactory = PopupFactory.getSharedInstance(); if (popupFactory instanceof ScreenPopupFactory spf) { diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaMenuPainter.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaMenuPainter.java index 5a13822fd5a..8f1a6799ff6 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaMenuPainter.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaMenuPainter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,21 +25,39 @@ package com.apple.laf; -import java.awt.*; -import java.awt.event.*; - -import javax.swing.*; +import java.awt.Color; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Rectangle; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; + +import javax.swing.ButtonModel; +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; +import javax.swing.KeyStroke; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; import javax.swing.border.Border; import javax.swing.plaf.basic.BasicHTML; import javax.swing.text.View; -import sun.swing.SwingUtilities2; - -import apple.laf.JRSUIConstants.*; - +import apple.laf.JRSUIConstants.State; +import apple.laf.JRSUIConstants.Widget; import com.apple.laf.AquaIcon.InvertableIcon; import com.apple.laf.AquaUtils.RecyclableSingleton; import com.apple.laf.AquaUtils.RecyclableSingletonFromDefaultConstructor; +import sun.swing.MnemonicHandler; +import sun.swing.SwingUtilities2; /** * AquaMenuPainter, implements paintMenuItem to avoid code duplication @@ -287,7 +305,7 @@ protected void paintMenuItem(final Client client, final Graphics g, final JCompo if (v != null) { v.paint(g, textRect); } else { - final int mnemonic = (AquaMnemonicHandler.isMnemonicHidden() ? -1 : model.getMnemonic()); + final int mnemonic = (MnemonicHandler.isMnemonicHidden() ? -1 : model.getMnemonic()); drawString(g, c, text, mnemonic, textRect.x, textRect.y + fm.getAscent(), isEnabled, isSelected); } } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKGraphicsUtils.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKGraphicsUtils.java index 0ef404593f5..2a0aa7be41c 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKGraphicsUtils.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKGraphicsUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,12 +24,19 @@ */ package com.sun.java.swing.plaf.gtk; -import javax.swing.*; -import javax.swing.plaf.synth.*; import java.awt.Color; import java.awt.Graphics; import java.awt.Rectangle; +import javax.swing.AbstractButton; +import javax.swing.JComponent; +import javax.swing.plaf.synth.Region; +import javax.swing.plaf.synth.SynthConstants; +import javax.swing.plaf.synth.SynthContext; +import javax.swing.plaf.synth.SynthGraphicsUtils; + +import sun.swing.MnemonicHandler; + /** * @author Joshua Outwater */ @@ -49,6 +56,11 @@ public void paintText(SynthContext context, Graphics g, String text, int componentState = context.getComponentState(); String themeName = GTKLookAndFeel.getGtkThemeName(); + + if (MnemonicHandler.isMnemonicHidden()) { + mnemonicIndex = -1; + } + if (themeName != null && themeName.startsWith("blueprint") && shouldShadowText(context.getRegion(), componentState)) { @@ -115,7 +127,8 @@ public void paintText(SynthContext context, Graphics g, String text, g.setColor(color); } } - super.paintText(context, g, text, bounds, mnemonicIndex); + super.paintText(context, g, text, bounds, + MnemonicHandler.isMnemonicHidden() ? -1 : mnemonicIndex); } private static boolean shouldShadowText(Region id, int state) { diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java index 65f29ea8384..93ba22d8dd3 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java @@ -25,28 +25,50 @@ package com.sun.java.swing.plaf.gtk; -import java.awt.*; -import java.beans.*; -import java.io.File; -import java.lang.ref.*; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Insets; +import java.awt.KeyboardFocusManager; +import java.awt.Toolkit; +import java.awt.Window; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.Locale; -import javax.swing.*; -import javax.swing.colorchooser.*; -import javax.swing.plaf.*; -import javax.swing.plaf.synth.*; +import java.util.HashMap; +import java.util.Map; + +import javax.swing.JComponent; +import javax.swing.JTextField; +import javax.swing.LayoutStyle; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.colorchooser.AbstractColorChooserPanel; +import javax.swing.plaf.BorderUIResource; +import javax.swing.plaf.ColorUIResource; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.DimensionUIResource; +import javax.swing.plaf.InsetsUIResource; +import javax.swing.plaf.synth.Region; +import javax.swing.plaf.synth.SynthConstants; +import javax.swing.plaf.synth.SynthLookAndFeel; +import javax.swing.plaf.synth.SynthStyleFactory; import javax.swing.text.DefaultEditorKit; import com.sun.java.swing.plaf.gtk.GTKConstants.PositionType; import com.sun.java.swing.plaf.gtk.GTKConstants.StateType; -import java.util.HashMap; -import java.util.Map; import sun.awt.SunToolkit; import sun.awt.UNIXToolkit; -import sun.awt.OSInfo; import sun.security.action.GetPropertyAction; +import sun.swing.AltProcessor; import sun.swing.DefaultLayoutStyle; +import sun.swing.MnemonicHandler; import sun.swing.SwingAccessor; import sun.swing.SwingUtilities2; @@ -866,7 +888,6 @@ public Object createValue(UIDefaults table) { "ctrl released ENTER", "release" }, - "ScrollBar.squareButtons", Boolean.FALSE, "ScrollBar.thumbHeight", Integer.valueOf(14), "ScrollBar.width", Integer.valueOf(16), @@ -1414,6 +1435,10 @@ static boolean isLeftToRight(Component c) { return c.getComponentOrientation().isLeftToRight(); } + /** + * {@inheritDoc} + */ + @Override public void initialize() { /* * We need to call loadGTK() to ensure that the native GTK @@ -1456,6 +1481,23 @@ public void initialize() { gtkAAFontSettingsCond = SwingUtilities2.isLocalDisplay(); aaTextInfo = new HashMap<>(2); SwingUtilities2.putAATextInfo(gtkAAFontSettingsCond, aaTextInfo); + + KeyboardFocusManager.getCurrentKeyboardFocusManager() + .addKeyEventPostProcessor(AltProcessor.getInstance()); + + // By default mnemonics are hidden for GTK L&F + MnemonicHandler.setMnemonicHidden(true); + } + + /** + * {@inheritDoc} + */ + @Override + public void uninitialize() { + KeyboardFocusManager.getCurrentKeyboardFocusManager() + .removeKeyEventPostProcessor(AltProcessor.getInstance()); + MnemonicHandler.setMnemonicHidden(false); + super.uninitialize(); } static ReferenceQueue queue = new ReferenceQueue(); diff --git a/src/java.desktop/share/classes/sun/swing/AltProcessor.java b/src/java.desktop/share/classes/sun/swing/AltProcessor.java new file mode 100644 index 00000000000..c7bb7b3d410 --- /dev/null +++ b/src/java.desktop/share/classes/sun/swing/AltProcessor.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.swing; + +import java.awt.KeyEventPostProcessor; +import java.awt.Window; +import java.awt.event.KeyEvent; + +import javax.swing.JRootPane; +import javax.swing.SwingUtilities; + +public final class AltProcessor implements KeyEventPostProcessor { + + private AltProcessor() {} + + private static final AltProcessor altProcessor = new AltProcessor(); + + public static KeyEventPostProcessor getInstance() { + return altProcessor; + } + + @Override + public boolean postProcessKeyEvent(final KeyEvent ev) { + if (ev.getKeyCode() != KeyEvent.VK_ALT) { + return false; + } + + final JRootPane root = SwingUtilities.getRootPane(ev.getComponent()); + final Window winAncestor = (root == null ? null : SwingUtilities.getWindowAncestor(root)); + + switch (ev.getID()) { + case KeyEvent.KEY_PRESSED: + MnemonicHandler.setMnemonicHidden(false); + break; + case KeyEvent.KEY_RELEASED: + MnemonicHandler.setMnemonicHidden(true); + break; + } + + MnemonicHandler.repaintMnemonicsInWindow(winAncestor); + + return false; + } +} diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaMnemonicHandler.java b/src/java.desktop/share/classes/sun/swing/MnemonicHandler.java similarity index 52% rename from src/java.desktop/macosx/classes/com/apple/laf/AquaMnemonicHandler.java rename to src/java.desktop/share/classes/sun/swing/MnemonicHandler.java index 76c97358828..b4f0cac7c61 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaMnemonicHandler.java +++ b/src/java.desktop/share/classes/sun/swing/MnemonicHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,39 +23,27 @@ * questions. */ -package com.apple.laf; +package sun.swing; -import java.awt.*; -import java.awt.event.KeyEvent; +import java.awt.Component; +import java.awt.Container; +import java.awt.Window; -import javax.swing.*; +import javax.swing.AbstractButton; +import javax.swing.JLabel; +import javax.swing.UIManager; -import com.apple.laf.AquaUtils.RecyclableSingleton; -import com.apple.laf.AquaUtils.RecyclableSingletonFromDefaultConstructor; +public final class MnemonicHandler { -public class AquaMnemonicHandler { - private static final RecyclableSingleton altProcessor = new RecyclableSingletonFromDefaultConstructor(AltProcessor.class); - public static KeyEventPostProcessor getInstance() { - return altProcessor.get(); - } + private static boolean isMnemonicHidden; - protected static boolean isMnemonicHidden = true; // true by default - - public static void setMnemonicHidden(final boolean hide) { - if (UIManager.getBoolean("Button.showMnemonics")) { - // Do not hide mnemonics if the UI defaults do not support this - isMnemonicHidden = false; - } else { - isMnemonicHidden = hide; - } - } + private MnemonicHandler() {} /** - * Gets the state of the hide mnemonic flag. This only has meaning if this feature is supported by the underlying OS. + * Gets the state of the hide mnemonic flag. + * This only has meaning if this feature is supported by the underlying OS. * * @return true if mnemonics are hidden, otherwise, false - * @see #setMnemonicHidden - * @since 1.4 */ public static boolean isMnemonicHidden() { if (UIManager.getBoolean("Button.showMnemonics")) { @@ -65,34 +53,27 @@ public static boolean isMnemonicHidden() { return isMnemonicHidden; } - static class AltProcessor implements KeyEventPostProcessor { - public boolean postProcessKeyEvent(final KeyEvent ev) { - if (ev.getKeyCode() != KeyEvent.VK_ALT) { - return false; - } - - final JRootPane root = SwingUtilities.getRootPane(ev.getComponent()); - final Window winAncestor = (root == null ? null : SwingUtilities.getWindowAncestor(root)); - - switch(ev.getID()) { - case KeyEvent.KEY_PRESSED: - setMnemonicHidden(false); - break; - case KeyEvent.KEY_RELEASED: - setMnemonicHidden(true); - break; - } - - repaintMnemonicsInWindow(winAncestor); - - return false; + /** + * Sets the state of the hide mnemonic flag. This flag is used by the + * component UI delegates to determine if the mnemonic should be rendered. + * This method is a non operation if the underlying operating system + * does not support the mnemonic hiding feature. + * + * @param hide true if mnemonics should be hidden + */ + public static void setMnemonicHidden(final boolean hide) { + if (UIManager.getBoolean("Button.showMnemonics")) { + // Do not hide mnemonics if the UI defaults do not support this + isMnemonicHidden = false; + } else { + isMnemonicHidden = hide; } } - /* + /** * Repaints all the components with the mnemonics in the given window and all its owned windows. */ - static void repaintMnemonicsInWindow(final Window w) { + public static void repaintMnemonicsInWindow(final Window w) { if (w == null || !w.isShowing()) { return; } @@ -105,29 +86,22 @@ static void repaintMnemonicsInWindow(final Window w) { repaintMnemonicsInContainer(w); } - /* + /** * Repaints all the components with the mnemonics in container. * Recursively searches for all the subcomponents. */ - static void repaintMnemonicsInContainer(final Container cont) { - for (int i = 0; i < cont.getComponentCount(); i++) { - final Component c = cont.getComponent(i); + private static void repaintMnemonicsInContainer(final Container cont) { + final Component[] elements = cont.getComponents(); + for (final Component c : elements) { if (c == null || !c.isVisible()) { continue; } - if (c instanceof AbstractButton && ((AbstractButton)c).getMnemonic() != '\0') { - c.repaint(); - continue; - } - - if (c instanceof JLabel && ((JLabel)c).getDisplayedMnemonic() != '\0') { + if ((c instanceof AbstractButton b && b.getMnemonic() != '\0') + || (c instanceof JLabel l && l.getDisplayedMnemonic() != '\0')) { c.repaint(); - continue; - } - - if (c instanceof Container) { - repaintMnemonicsInContainer((Container)c); + } else if (c instanceof Container) { + repaintMnemonicsInContainer((Container) c); } } } diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsGraphicsUtils.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsGraphicsUtils.java index ff38130f728..cb4b5caa86d 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsGraphicsUtils.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsGraphicsUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,14 +25,31 @@ package com.sun.java.swing.plaf.windows; -import sun.swing.SwingUtilities2; - -import java.awt.*; - -import javax.swing.*; +import java.awt.Color; +import java.awt.Component; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Point; +import java.awt.Rectangle; + +import javax.swing.AbstractButton; +import javax.swing.ButtonModel; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JRadioButton; +import javax.swing.JToggleButton; +import javax.swing.UIManager; import javax.swing.plaf.UIResource; -import static com.sun.java.swing.plaf.windows.TMSchema.*; +import sun.swing.MnemonicHandler; +import sun.swing.SwingUtilities2; + +import static com.sun.java.swing.plaf.windows.TMSchema.Part; +import static com.sun.java.swing.plaf.windows.TMSchema.Prop; +import static com.sun.java.swing.plaf.windows.TMSchema.State; +import static com.sun.java.swing.plaf.windows.TMSchema.TypeEnum; /** * A collection of static utility methods used for rendering the Windows look @@ -60,7 +77,7 @@ public static void paintText(Graphics g, AbstractButton b, int mnemIndex = b.getDisplayedMnemonicIndex(); // W2K Feature: Check to see if the Underscore should be rendered. - if (WindowsLookAndFeel.isMnemonicHidden() == true) { + if (MnemonicHandler.isMnemonicHidden()) { mnemIndex = -1; } @@ -191,46 +208,4 @@ static boolean isLeftToRight(Component c) { return c.getComponentOrientation().isLeftToRight(); } - /* - * Repaints all the components with the mnemonics in the given window and - * all its owned windows. - */ - static void repaintMnemonicsInWindow(Window w) { - if(w == null || !w.isShowing()) { - return; - } - - Window[] ownedWindows = w.getOwnedWindows(); - for(int i=0;i

Provides classfile parsing, generation, and transformation library.

* The {@code java.lang.classfile} package contains classes for reading, writing, and - * modifying Java class files, as specified in Chapter {@jvms 4} of the Java - * Java Virtual Machine Specification. + * modifying Java class files, as specified in Chapter {@jvms 4} of the + * Java Virtual Machine Specification. * *

Reading classfiles

* The main class for reading classfiles is {@link java.lang.classfile.ClassModel}; we From 9695f09581bac856ad97943cca15c65dc21d2adf Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Thu, 8 Aug 2024 16:11:08 +0000 Subject: [PATCH 348/460] 8337683: Fix -Wconversion problem with arrayOop.hpp Reviewed-by: stefank, dholmes --- src/hotspot/share/oops/arrayOop.hpp | 18 +++++++++--------- src/hotspot/share/runtime/atomic.hpp | 5 +++-- src/hotspot/share/utilities/byteswap.hpp | 3 ++- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/hotspot/share/oops/arrayOop.hpp b/src/hotspot/share/oops/arrayOop.hpp index 0aa26500bd8..1ca8a9530a4 100644 --- a/src/hotspot/share/oops/arrayOop.hpp +++ b/src/hotspot/share/oops/arrayOop.hpp @@ -68,10 +68,10 @@ class arrayOopDesc : public oopDesc { // The header is considered the oop part of this type plus the length. // This is not equivalent to sizeof(arrayOopDesc) which should not appear in the code. static int header_size_in_bytes() { - size_t hs = length_offset_in_bytes() + sizeof(int); + int hs = length_offset_in_bytes() + (int)sizeof(int); #ifdef ASSERT // make sure it isn't called before UseCompressedOops is initialized. - static size_t arrayoopdesc_hs = 0; + static int arrayoopdesc_hs = 0; if (arrayoopdesc_hs == 0) arrayoopdesc_hs = hs; assert(arrayoopdesc_hs == hs, "header size can't change"); #endif // ASSERT @@ -83,13 +83,13 @@ class arrayOopDesc : public oopDesc { // it occupies the second half of the _klass field in oopDesc. static int length_offset_in_bytes() { return UseCompressedClassPointers ? klass_gap_offset_in_bytes() : - sizeof(arrayOopDesc); + (int)sizeof(arrayOopDesc); } // Returns the offset of the first element. static int base_offset_in_bytes(BasicType type) { - size_t hs = header_size_in_bytes(); - return (int)(element_type_should_be_aligned(type) ? align_up(hs, BytesPerLong) : hs); + int hs = header_size_in_bytes(); + return element_type_should_be_aligned(type) ? align_up(hs, BytesPerLong) : hs; } // Returns the address of the first element. The elements in the array will not @@ -134,14 +134,14 @@ class arrayOopDesc : public oopDesc { assert(type < T_CONFLICT, "wrong type"); assert(type2aelembytes(type) != 0, "wrong type"); - size_t hdr_size_in_bytes = base_offset_in_bytes(type); + int hdr_size_in_bytes = base_offset_in_bytes(type); // This is rounded-up and may overlap with the first array elements. - size_t hdr_size_in_words = align_up(hdr_size_in_bytes, HeapWordSize) / HeapWordSize; + int hdr_size_in_words = align_up(hdr_size_in_bytes, HeapWordSize) / HeapWordSize; const size_t max_element_words_per_size_t = - align_down((SIZE_MAX/HeapWordSize - hdr_size_in_words), MinObjAlignment); + align_down((SIZE_MAX/HeapWordSize - (size_t)hdr_size_in_words), MinObjAlignment); const size_t max_elements_per_size_t = - HeapWordSize * max_element_words_per_size_t / type2aelembytes(type); + HeapWordSize * max_element_words_per_size_t / (size_t)type2aelembytes(type); if ((size_t)max_jint < max_elements_per_size_t) { // It should be ok to return max_jint here, but parts of the code // (CollectedHeap, Klass::oop_oop_iterate(), and more) uses an int for diff --git a/src/hotspot/share/runtime/atomic.hpp b/src/hotspot/share/runtime/atomic.hpp index 399a78fd3fc..bf198b5f562 100644 --- a/src/hotspot/share/runtime/atomic.hpp +++ b/src/hotspot/share/runtime/atomic.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ #include "runtime/orderAccess.hpp" #include "utilities/align.hpp" #include "utilities/bytes.hpp" +#include "utilities/checkedCast.hpp" #include "utilities/macros.hpp" #include @@ -1118,7 +1119,7 @@ inline T Atomic::CmpxchgByteUsingInt::operator()(T volatile* dest, uint8_t canon_compare_value = compare_value; volatile uint32_t* aligned_dest = reinterpret_cast(align_down(dest, sizeof(uint32_t))); - size_t offset = pointer_delta(dest, aligned_dest, 1); + uint32_t offset = checked_cast(pointer_delta(dest, aligned_dest, 1)); uint32_t idx = (Endian::NATIVE == Endian::BIG) ? (sizeof(uint32_t) - 1 - offset) diff --git a/src/hotspot/share/utilities/byteswap.hpp b/src/hotspot/share/utilities/byteswap.hpp index fba0775cf49..9c3b53630b3 100644 --- a/src/hotspot/share/utilities/byteswap.hpp +++ b/src/hotspot/share/utilities/byteswap.hpp @@ -26,6 +26,7 @@ #define SHARE_UTILITIES_BYTESWAP_HPP #include "metaprogramming/enableIf.hpp" +#include "utilities/checkedCast.hpp" #include "utilities/globalDefinitions.hpp" #include @@ -63,7 +64,7 @@ struct ByteswapFallbackImpl; template struct ByteswapFallbackImpl { inline constexpr uint16_t operator()(uint16_t x) const { - return (((x & UINT16_C(0x00ff)) << 8) | ((x & UINT16_C(0xff00)) >> 8)); + return checked_cast(((x & UINT16_C(0x00ff)) << 8) | ((x & UINT16_C(0xff00)) >> 8)); } }; From 53c9f037fb2805aab5ab9729166ce7d5bc7a77f9 Mon Sep 17 00:00:00 2001 From: Jiangli Zhou Date: Thu, 8 Aug 2024 16:31:02 +0000 Subject: [PATCH 349/460] 8336849: Remove .llvm_addrsig section from JDK/VM static libraries (.a files) Reviewed-by: ihse --- make/common/native/Link.gmk | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/make/common/native/Link.gmk b/make/common/native/Link.gmk index 2090218ffbb..ca03c6ee6b1 100644 --- a/make/common/native/Link.gmk +++ b/make/common/native/Link.gmk @@ -109,6 +109,11 @@ define CreateStaticLibrary $(if $$($1_LINK_OBJS_RELATIVE), $$(CD) $$(OUTPUTDIR) ; ) \ $$($1_LD) $(LDFLAGS_CXX_PARTIAL_LINKING) $$($1_SYSROOT_LDFLAGS) \ -o $$($1_TARGET_RELOCATABLE) $$($1_LD_OBJ_ARG)) + # 'ld -r' might invalidate the .llvm_addrsig section, and this will cause subsequent + # calls to lld (with '-Wl,--icf=safe') to fail when linking with this library, so + # remove that section. + $$(call ExecuteWithLog, $$($1_OBJECT_DIR)/$$($1_SAFE_NAME)_objcopy_remove_llvm_addrsig_section, \ + $$($1_OBJCOPY) --remove-section=.llvm_addrsig $$($1_TARGET_RELOCATABLE)) endif $$(call ExecuteWithLog, $$($1_OBJECT_DIR)/$$($1_SAFE_NAME)_run_ar, \ $(if $$($1_LINK_OBJS_RELATIVE), $$(CD) $$(OUTPUTDIR) ; ) \ From bfb75b96266f4c5840e2edea13f9aa2c801518cf Mon Sep 17 00:00:00 2001 From: Roger Riggs Date: Thu, 8 Aug 2024 16:53:38 +0000 Subject: [PATCH 350/460] 8336926: jdk/internal/util/ReferencedKeyTest.java can fail with ConcurrentModificationException Reviewed-by: bpb, shade, dfuchs --- .../jdk/internal/util/ReferencedKeyMap.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/util/ReferencedKeyMap.java b/src/java.base/share/classes/jdk/internal/util/ReferencedKeyMap.java index 9c364cd7813..810d43ae38a 100644 --- a/src/java.base/share/classes/jdk/internal/util/ReferencedKeyMap.java +++ b/src/java.base/share/classes/jdk/internal/util/ReferencedKeyMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -219,8 +219,14 @@ public boolean containsValue(Object value) { @Override public V get(Object key) { - Objects.requireNonNull(key, "key must not be null"); removeStaleReferences(); + return getNoCheckStale(key); + } + + // Internal get(key) without removing stale references that would modify the keyset. + // Use when iterating or streaming over the keys to avoid ConcurrentModificationException. + private V getNoCheckStale(Object key) { + Objects.requireNonNull(key, "key must not be null"); return map.get(lookupKey(key)); } @@ -291,7 +297,7 @@ public Collection values() { public Set> entrySet() { removeStaleReferences(); return filterKeySet() - .map(k -> new AbstractMap.SimpleEntry<>(k, get(k))) + .map(k -> new AbstractMap.SimpleEntry<>(k, getNoCheckStale(k))) .collect(Collectors.toSet()); } @@ -335,7 +341,7 @@ public V replace(K key, V value) { public String toString() { removeStaleReferences(); return filterKeySet() - .map(k -> k + "=" + get(k)) + .map(k -> k + "=" + getNoCheckStale(k)) .collect(Collectors.joining(", ", "{", "}")); } From e7a0b5b09bcfcd8b09667e51ec588e206f0652ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Thu, 8 Aug 2024 18:45:11 +0000 Subject: [PATCH 351/460] 8334780: Crash: assert(h_array_list.not_null()) failed: invariant Reviewed-by: egahlin, shade --- src/hotspot/share/jfr/support/jfrJdkJfrEvent.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/jfr/support/jfrJdkJfrEvent.cpp b/src/hotspot/share/jfr/support/jfrJdkJfrEvent.cpp index cd476302289..0c2fb0206ec 100644 --- a/src/hotspot/share/jfr/support/jfrJdkJfrEvent.cpp +++ b/src/hotspot/share/jfr/support/jfrJdkJfrEvent.cpp @@ -136,7 +136,9 @@ jobject JdkJfrEvent::get_all_klasses(TRAPS) { transform_klasses_to_local_jni_handles(event_subklasses, THREAD); Handle h_array_list(THREAD, new_java_util_arraylist(THREAD)); - assert(h_array_list.not_null(), "invariant"); + if (h_array_list.is_null()) { + return empty_java_util_arraylist; + } static const char add_method_name[] = "add"; static const char add_method_signature[] = "(Ljava/lang/Object;)Z"; From 9f08a01cb6ebb08f67749aabdff4efaedfaf3228 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Thu, 8 Aug 2024 19:47:50 +0000 Subject: [PATCH 352/460] 8338010: WB_IsFrameDeoptimized miss ResourceMark Reviewed-by: dholmes, shade --- src/hotspot/share/prims/whitebox.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 6ee33a61079..544eeabb5c2 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -799,6 +799,7 @@ WB_END WB_ENTRY(jboolean, WB_IsFrameDeoptimized(JNIEnv* env, jobject o, jint depth)) bool result = false; if (thread->has_last_Java_frame()) { + ResourceMark rm(THREAD); RegisterMap reg_map(thread, RegisterMap::UpdateMap::include, RegisterMap::ProcessFrames::include, From 55c509708e9b89a7609fd41b6e5a271f250bbacd Mon Sep 17 00:00:00 2001 From: Jiawei Tang Date: Fri, 9 Aug 2024 02:29:15 +0000 Subject: [PATCH 353/460] 8337331: crash: pinned virtual thread will lead to jvm crash when running with the javaagent option Reviewed-by: dholmes, sspitsyn --- src/hotspot/share/prims/jvmtiExport.cpp | 10 +-- .../TestPinCaseWithCFLH.java | 77 +++++++++++++++++++ 2 files changed, 82 insertions(+), 5 deletions(-) create mode 100644 test/hotspot/jtreg/serviceability/jvmti/vthread/TestPinCaseWithCFLH/TestPinCaseWithCFLH.java diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index f79116f5ebe..95cc54d9313 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -929,9 +929,8 @@ class JvmtiClassFileLoadHookPoster : public StackObj { _cached_class_file_ptr = cache_ptr; _has_been_modified = false; - if (_thread->is_in_any_VTMS_transition()) { - return; // no events should be posted if thread is in any VTMS transition - } + assert(!_thread->is_in_any_VTMS_transition(), "CFLH events are not allowed in any VTMS transition"); + _state = JvmtiExport::get_jvmti_thread_state(_thread); if (_state != nullptr) { _class_being_redefined = _state->get_class_being_redefined(); @@ -1091,8 +1090,9 @@ bool JvmtiExport::post_class_file_load_hook(Symbol* h_name, if (JvmtiEnv::get_phase() < JVMTI_PHASE_PRIMORDIAL) { return false; } - if (JavaThread::current()->is_in_tmp_VTMS_transition()) { - return false; // skip CFLH events in tmp VTMS transition + + if (JavaThread::current()->is_in_any_VTMS_transition()) { + return false; // no events should be posted if thread is in any VTMS transition } JvmtiClassFileLoadHookPoster poster(h_name, class_loader, diff --git a/test/hotspot/jtreg/serviceability/jvmti/vthread/TestPinCaseWithCFLH/TestPinCaseWithCFLH.java b/test/hotspot/jtreg/serviceability/jvmti/vthread/TestPinCaseWithCFLH/TestPinCaseWithCFLH.java new file mode 100644 index 00000000000..02755a0289f --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/vthread/TestPinCaseWithCFLH/TestPinCaseWithCFLH.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +import java.lang.instrument.ClassFileTransformer; +import java.lang.instrument.IllegalClassFormatException; +import java.lang.instrument.Instrumentation; +import java.security.ProtectionDomain; +import jdk.test.lib.thread.VThreadPinner; + +/* + * @test + * @summary javaagent + tracePinnedThreads will cause jvm crash/ run into deadlock when the virtual thread is pinned + * @library /test/lib + * @requires vm.continuations + * @requires vm.jvmti + * @modules java.base/java.lang:+open + * @compile TestPinCaseWithCFLH.java + * @build jdk.test.lib.Utils + * @run driver jdk.test.lib.util.JavaAgentBuilder + * TestPinCaseWithCFLH TestPinCaseWithCFLH.jar + * @run main/othervm/timeout=100 -Djdk.virtualThreadScheduler.maxPoolSize=1 + * -Djdk.tracePinnedThreads=full --enable-native-access=ALL-UNNAMED + * -javaagent:TestPinCaseWithCFLH.jar TestPinCaseWithCFLH + */ +public class TestPinCaseWithCFLH { + + public static class TestClassFileTransformer implements ClassFileTransformer { + public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, + ProtectionDomain protectionDomain, byte[] classfileBuffer) + throws IllegalClassFormatException { + return classfileBuffer; + } + } + + // Called when agent is loaded at startup + public static void premain(String agentArgs, Instrumentation instrumentation) throws Exception { + instrumentation.addTransformer(new TestClassFileTransformer()); + } + + private static int result = 0; + + public static void main(String[] args) throws Exception{ + Thread t1 = Thread.ofVirtual().name("vthread-1").start(() -> { + VThreadPinner.runPinned(() -> { + try { + // try yield, will pin, + // javaagent + tracePinnedThreads should not lead to crash + // (because of the class `PinnedThreadPrinter`) + Thread.sleep(500); + } catch (Exception e) { + e.printStackTrace(); + } + }); + }); + t1.join(); + } + +} \ No newline at end of file From 0c1e9111d226b601236b9826e27ecc67a8b625fb Mon Sep 17 00:00:00 2001 From: Gui Cao Date: Fri, 9 Aug 2024 02:59:37 +0000 Subject: [PATCH 354/460] 8338019: Fix simple -Wzero-as-null-pointer-constant warnings in riscv code Reviewed-by: fyang, mli, luhenry --- src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp | 2 +- src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp | 2 +- src/hotspot/cpu/riscv/frame_riscv.cpp | 2 +- src/hotspot/cpu/riscv/nativeInst_riscv.cpp | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp index 798679185d3..3d146b87707 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp @@ -542,7 +542,7 @@ void LIR_Assembler::const2mem(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmi insn = &MacroAssembler::sw; break; case T_OBJECT: // fall through case T_ARRAY: - assert(c->as_jobject() == 0, "should be"); + assert(c->as_jobject() == nullptr, "should be"); if (UseCompressedOops && !wide) { insn = &MacroAssembler::sw; } else { diff --git a/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp b/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp index 9fa8939837a..e999b703b3e 100644 --- a/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp @@ -1066,4 +1066,4 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { #undef __ -const char *Runtime1::pd_name_for_address(address entry) { Unimplemented(); return 0; } +const char *Runtime1::pd_name_for_address(address entry) { Unimplemented(); } diff --git a/src/hotspot/cpu/riscv/frame_riscv.cpp b/src/hotspot/cpu/riscv/frame_riscv.cpp index 32825a02c5e..96dca4704ad 100644 --- a/src/hotspot/cpu/riscv/frame_riscv.cpp +++ b/src/hotspot/cpu/riscv/frame_riscv.cpp @@ -269,7 +269,7 @@ void frame::patch_pc(Thread* thread, address pc) { // Either the return address is the original one or we are going to // patch in the same address that's already there. - assert(_pc == pc_old || pc == pc_old || pc_old == 0, "must be"); + assert(_pc == pc_old || pc == pc_old || pc_old == nullptr, "must be"); DEBUG_ONLY(address old_pc = _pc;) *pc_addr = pc; _pc = pc; // must be set before call to get_deopt_original_pc diff --git a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp index f0357f1cd30..6c9e0986869 100644 --- a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp +++ b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp @@ -685,7 +685,7 @@ address NativeJump::jump_destination() const { // load // return -1 if jump to self or to 0 - if ((dest == (address) this) || dest == 0) { + if ((dest == (address) this) || dest == nullptr) { dest = (address) -1; } @@ -714,7 +714,7 @@ address NativeGeneralJump::jump_destination() const { // a general jump // return -1 if jump to self or to 0 - if ((dest == (address) this) || dest == 0) { + if ((dest == (address) this) || dest == nullptr) { dest = (address) -1; } From 9ab8c6b9ba90ffd12600a250c8704571e9feb78d Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Fri, 9 Aug 2024 05:09:27 +0000 Subject: [PATCH 355/460] 8335130: The test "javax/swing/plaf/synth/ComponentsOrientationSupport/5033822/bug5033822.java" fails because the background color of the tabs is displayed incorrectly. Reviewed-by: achung, psadhukhan --- .../sun/java/swing/plaf/gtk/GTKPainter.java | 34 ++++++++-------- .../swing/plaf/nimbus/SynthPainterImpl.java | 39 ++++++++++--------- .../swing/plaf/synth/SynthTabbedPaneUI.java | 8 +--- 3 files changed, 41 insertions(+), 40 deletions(-) diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java index 4787696a367..ea27a2a6e0d 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java @@ -935,25 +935,27 @@ public void paintTabbedPaneTabBackground(SynthContext context, Graphics g, int x, int y, int w, int h, int tabIndex) { - Region id = context.getRegion(); - int state = context.getComponentState(); - int gtkState = ((state & SynthConstants.SELECTED) != 0 ? - SynthConstants.ENABLED : SynthConstants.PRESSED); JTabbedPane pane = (JTabbedPane)context.getComponent(); - int placement = pane.getTabPlacement(); + if (UIManager.getBoolean("TabbedPane.tabsOpaque") || pane.isOpaque()) { + Region id = context.getRegion(); + int state = context.getComponentState(); + int gtkState = ((state & SynthConstants.SELECTED) != 0 ? + SynthConstants.ENABLED : SynthConstants.PRESSED); + int placement = pane.getTabPlacement(); - // Fill the tab rect area - g.fillRect(x, y, w, h); + // Fill the tab rect area + g.fillRect(x, y, w, h); - synchronized (UNIXToolkit.GTK_LOCK) { - if (! ENGINE.paintCachedImage(g, x, y, w, h, - id, gtkState, placement, tabIndex)) { - PositionType side = POSITIONS[placement - 1]; - ENGINE.startPainting(g, x, y, w, h, - id, gtkState, placement, tabIndex); - ENGINE.paintExtension(g, context, id, gtkState, - ShadowType.OUT, "tab", x, y, w, h, side, tabIndex); - ENGINE.finishPainting(); + synchronized (UNIXToolkit.GTK_LOCK) { + if (!ENGINE.paintCachedImage(g, x, y, w, h, + id, gtkState, placement, tabIndex)) { + PositionType side = POSITIONS[placement - 1]; + ENGINE.startPainting(g, x, y, w, h, + id, gtkState, placement, tabIndex); + ENGINE.paintExtension(g, context, id, gtkState, + ShadowType.OUT, "tab", x, y, w, h, side, tabIndex); + ENGINE.finishPainting(); + } } } } diff --git a/src/java.desktop/share/classes/javax/swing/plaf/nimbus/SynthPainterImpl.java b/src/java.desktop/share/classes/javax/swing/plaf/nimbus/SynthPainterImpl.java index c990c968ff6..9dfd422f6dd 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/nimbus/SynthPainterImpl.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/nimbus/SynthPainterImpl.java @@ -2098,24 +2098,27 @@ public void paintTabbedPaneTabBackground(SynthContext context, Graphics g, public void paintTabbedPaneTabBackground(SynthContext context, Graphics g, int x, int y, int w, int h, int tabIndex, int orientation) { - if (orientation == JTabbedPane.LEFT) { - AffineTransform transform = new AffineTransform(); - transform.scale(-1, 1); - transform.rotate(Math.toRadians(90)); - paintBackground(context, g, y, x, h, w, transform); - } else if (orientation == JTabbedPane.RIGHT) { - AffineTransform transform = new AffineTransform(); - transform.rotate(Math.toRadians(90)); - transform.translate(0, -(x + w)); - paintBackground(context, g, y, 0, h, w, transform); - } else if (orientation == JTabbedPane.BOTTOM) { - AffineTransform transform = new AffineTransform(); - transform.translate(x,y); - transform.scale(1, -1); - transform.translate(0,-h); - paintBackground(context, g, 0, 0, w, h, transform); - } else { - paintBackground(context, g, x, y, w, h, null); + JTabbedPane pane = (JTabbedPane)context.getComponent(); + if (UIManager.getBoolean("TabbedPane.tabsOpaque") || pane.isOpaque()) { + if (orientation == JTabbedPane.LEFT) { + AffineTransform transform = new AffineTransform(); + transform.scale(-1, 1); + transform.rotate(Math.toRadians(90)); + paintBackground(context, g, y, x, h, w, transform); + } else if (orientation == JTabbedPane.RIGHT) { + AffineTransform transform = new AffineTransform(); + transform.rotate(Math.toRadians(90)); + transform.translate(0, -(x + w)); + paintBackground(context, g, y, 0, h, w, transform); + } else if (orientation == JTabbedPane.BOTTOM) { + AffineTransform transform = new AffineTransform(); + transform.translate(x, y); + transform.scale(1, -1); + transform.translate(0, -h); + paintBackground(context, g, 0, 0, w, h, transform); + } else { + paintBackground(context, g, x, y, w, h, null); + } } } diff --git a/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java b/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java index 837c4d8298f..3378ef9e8b3 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java @@ -127,7 +127,6 @@ public class SynthTabbedPaneUI extends BasicTabbedPaneUI // Background color for unselected tabs private Color unselectedBackground; private boolean contentOpaque = true; - private boolean tabsOpaque = true; /** * @@ -156,7 +155,6 @@ private boolean scrollableTabLayoutEnabled() { protected void installDefaults() { selectColor = UIManager.getColor("TabbedPane.selected"); contentOpaque = UIManager.getBoolean("TabbedPane.contentOpaque"); - tabsOpaque = UIManager.getBoolean("TabbedPane.tabsOpaque"); unselectedBackground = UIManager.getColor("TabbedPane.unselectedBackground"); updateStyle(tabPane); } @@ -655,10 +653,8 @@ private void paintTab(SynthContext ss, Graphics g, g.setColor(getUnselectedBackgroundAt(tabIndex)); } - if (tabsOpaque || tabPane.isOpaque()) { - tabContext.getPainter().paintTabbedPaneTabBackground(tabContext, g, - x, y, width, height, tabIndex, placement); - } + tabContext.getPainter().paintTabbedPaneTabBackground(tabContext, g, + x, y, width, height, tabIndex, placement); tabContext.getPainter().paintTabbedPaneTabBorder(tabContext, g, x, y, width, height, tabIndex, placement); From 00aac4097abd3c5e6144734cfd44228bc31892fb Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Fri, 9 Aug 2024 06:26:22 +0000 Subject: [PATCH 356/460] 8338058: map_or_reserve_memory_aligned Windows enhance remap assertion Reviewed-by: mdoerr, clanger --- src/hotspot/os/windows/os_windows.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 1cc7d9aa33a..65ba13b0d9e 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -3463,6 +3463,7 @@ static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int fi } assert(aligned_base != nullptr, "Did not manage to re-map after %d attempts?", max_attempts); + assert(aligned_base != nullptr, "Did not manage to re-map after %d attempts (size %zu, alignment %zu, file descriptor %d)", max_attempts, size, alignment, file_desc); return aligned_base; } From c01f53ac2dab1d4d2cd1e4d45a67f9373d4a9c7e Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Fri, 9 Aug 2024 07:17:59 +0000 Subject: [PATCH 357/460] 8337876: [IR Framework] Add support for IR tests with @Stable Reviewed-by: shade, kvn --- .../jtreg/compiler/lib/ir_framework/README.md | 11 ++- .../lib/ir_framework/TestFramework.java | 13 +++- .../ir_framework/driver/TestVMProcess.java | 15 ++-- .../tests/TestPhaseIRMatching.java | 2 +- .../tests/TestPrivilegedMode.java | 69 +++++++++++++++++++ 5 files changed, 103 insertions(+), 7 deletions(-) create mode 100644 test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPrivilegedMode.java diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/README.md b/test/hotspot/jtreg/compiler/lib/ir_framework/README.md index 3f6e0d4163f..55d9fcbaece 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/README.md +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/README.md @@ -157,7 +157,16 @@ The framework allows the use of additional compiler control annotations for help - [@ForceCompile](./ForceCompile.java) - [@ForceCompileClassInitializer](./ForceCompileClassInitializer.java) -### 2.5 Framework Debug and Stress Flags +### 2.5 IR Tests with Privileged Classes +To run tests in a privileged mode (e.g. when using `@Stable`, `@Contended`, `@ReservedStackAccess` etc.), one need to add the test classes to the boot classpath. This can easily be achieved by calling `TestFramework.addTestClassesToBootClassPath()` on the test framework object: +``` +TestFramework testFramework = new TestFramework(); +testFramework + .addTestClassesToBootClassPath() + .start(); +``` + +### 2.6 Framework Debug and Stress Flags The framework provides various stress and debug flags. They should mainly be used as JTreg VM and/or Javaoptions (apart from `VerifyIR`). The following (property) flags are supported: - `-DVerifyIR=false`: Explicitly disable IR verification. This is useful, for example, if some scenarios use VM flags that let `@IR` annotation rules fail and the user does not want to provide separate IR rules or add flag preconditions to the already existing IR rules. diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java b/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java index 67fadbc4eac..d477aa44763 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java @@ -172,6 +172,7 @@ public class TestFramework { private Set scenarioIndices; private List flags; private int defaultWarmup = -1; + private boolean testClassesOnBootClassPath; /* * Public interface methods @@ -323,6 +324,15 @@ public TestFramework addScenarios(Scenario... scenarios) { return this; } + /** + * Add test classes to boot classpath. This adds all classes found on path {@link jdk.test.lib.Utils#TEST_CLASSES} + * to the boot classpath with "-Xbootclasspath/a". This is useful when trying to run tests in a privileged mode. + */ + public TestFramework addTestClassesToBootClassPath() { + this.testClassesOnBootClassPath = true; + return this; + } + /** * Start the testing of the implicitly (by {@link #TestFramework()}) or explicitly (by {@link #TestFramework(Class)}) * set test class. @@ -744,7 +754,8 @@ private boolean onlyWhitelistedJTregVMAndJavaOptsFlags() { } private void runTestVM(List additionalFlags) { - TestVMProcess testVMProcess = new TestVMProcess(additionalFlags, testClass, helperClasses, defaultWarmup); + TestVMProcess testVMProcess = new TestVMProcess(additionalFlags, testClass, helperClasses, defaultWarmup, + testClassesOnBootClassPath); if (shouldVerifyIR) { try { TestClassParser testClassParser = new TestClassParser(testClass); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java index 04f8096d969..8c168b73260 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java @@ -34,6 +34,7 @@ import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; +import java.io.File; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -63,11 +64,12 @@ public class TestVMProcess { private OutputAnalyzer oa; private String irEncoding; - public TestVMProcess(List additionalFlags, Class testClass, Set> helperClasses, int defaultWarmup) { + public TestVMProcess(List additionalFlags, Class testClass, Set> helperClasses, int defaultWarmup, + boolean testClassesOnBootClassPath) { this.cmds = new ArrayList<>(); TestFrameworkSocket socket = new TestFrameworkSocket(); try (socket) { - prepareTestVMFlags(additionalFlags, socket, testClass, helperClasses, defaultWarmup); + prepareTestVMFlags(additionalFlags, socket, testClass, helperClasses, defaultWarmup, testClassesOnBootClassPath); start(); } processSocketOutput(socket); @@ -91,11 +93,16 @@ public static String getLastTestVMOutput() { } private void prepareTestVMFlags(List additionalFlags, TestFrameworkSocket socket, Class testClass, - Set> helperClasses, int defaultWarmup) { + Set> helperClasses, int defaultWarmup, boolean testClassesOnBootClassPath) { // Set java.library.path so JNI tests which rely on jtreg nativepath setting work cmds.add("-Djava.library.path=" + Utils.TEST_NATIVE_PATH); // Need White Box access in test VM. - cmds.add("-Xbootclasspath/a:."); + String bootClassPath = "-Xbootclasspath/a:."; + if (testClassesOnBootClassPath) { + // Add test classes themselves to boot classpath to make them privileged. + bootClassPath += File.pathSeparator + Utils.TEST_CLASSES; + } + cmds.add(bootClassPath); cmds.add("-XX:+UnlockDiagnosticVMOptions"); cmds.add("-XX:+WhiteBoxAPI"); // Ignore CompileCommand flags which have an impact on the profiling information. diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPhaseIRMatching.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPhaseIRMatching.java index 9a39fb5310f..f0056ebc79d 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPhaseIRMatching.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPhaseIRMatching.java @@ -66,7 +66,7 @@ private static void run(Class testClass) { List noAdditionalFlags = new ArrayList<>(); FlagVMProcess flagVMProcess = new FlagVMProcess(testClass, noAdditionalFlags); List testVMFlags = flagVMProcess.getTestVMFlags(); - TestVMProcess testVMProcess = new TestVMProcess(testVMFlags, testClass, null, -1); + TestVMProcess testVMProcess = new TestVMProcess(testVMFlags, testClass, null, -1, false); TestClassParser testClassParser = new TestClassParser(testClass); Matchable testClassMatchable = testClassParser.parse(testVMProcess.getHotspotPidFileName(), testVMProcess.getIrEncoding()); diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPrivilegedMode.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPrivilegedMode.java new file mode 100644 index 00000000000..347b2eb39fb --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPrivilegedMode.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package ir_framework.tests; + +import compiler.lib.ir_framework.*; +import compiler.lib.ir_framework.driver.irmatching.IRViolationException; + +import jdk.internal.vm.annotation.Stable; +import jdk.test.lib.Asserts; + +/* + * @test + * @requires vm.flagless + * @summary Test that IR framework successfully adds test class to boot classpath in order to run in privileged mode. + * @modules java.base/jdk.internal.vm.annotation + * @library /test/lib / + * @run driver ir_framework.tests.TestPrivilegedMode + */ + +public class TestPrivilegedMode { + static @Stable int iFld; // Treated as constant after first being set. + + public static void main(String[] args) { + try { + TestFramework.run(); + Asserts.fail("should not reach"); + } catch (IRViolationException e) { + // Without adding test class to boot classpath, we fail to replace the field load by a constant. + Asserts.assertTrue(e.getExceptionInfo().contains("Matched forbidden node")); + Asserts.assertTrue(e.getExceptionInfo().contains("LoadI")); + } + + // When adding the test class to the boot classpath, we can replace the field load by a constant. + new TestFramework().addTestClassesToBootClassPath().start(); + } + + @Test + @Arguments(setup = "setup") + @IR(failOn = IRNode.LOAD_I) + public int test() { + return iFld; + } + + @Setup + public void setup() { + iFld = 34; + } +} From 82d5768c1bdccfaf97a41f32a8bfcfd03a0fb378 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Fri, 9 Aug 2024 07:20:01 +0000 Subject: [PATCH 358/460] 8337840: Remove redundant null check in ObjectOutputStream.writeProxyDesc Reviewed-by: rriggs --- src/java.base/share/classes/java/io/ObjectOutputStream.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/io/ObjectOutputStream.java b/src/java.base/share/classes/java/io/ObjectOutputStream.java index 2dcf174cf53..3650b101353 100644 --- a/src/java.base/share/classes/java/io/ObjectOutputStream.java +++ b/src/java.base/share/classes/java/io/ObjectOutputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1272,7 +1272,7 @@ private void writeProxyDesc(ObjectStreamClass desc, boolean unshared) } bout.setBlockDataMode(true); - if (cl != null && isCustomSubclass()) { + if (isCustomSubclass()) { ReflectUtil.checkPackageAccess(cl); } annotateProxyClass(cl); From f74109bd178c92a9dff1ca6fce03b25f51a0384f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Fri, 9 Aug 2024 07:29:56 +0000 Subject: [PATCH 359/460] 8337939: ZGC: Make assertions and checks less convoluted and explicit Reviewed-by: stefank, ayang, eosterlund --- src/hotspot/share/gc/z/zAddress.cpp | 6 ++-- src/hotspot/share/gc/z/zAddress.inline.hpp | 30 +++++++++++++++---- src/hotspot/share/gc/z/zBarrier.inline.hpp | 6 ++-- src/hotspot/share/gc/z/zBarrierSet.inline.hpp | 4 +-- src/hotspot/share/gc/z/zHeapIterator.cpp | 2 +- src/hotspot/share/gc/z/zMark.cpp | 4 +-- src/hotspot/share/gc/z/zMark.inline.hpp | 4 +-- src/hotspot/share/gc/z/zPage.inline.hpp | 2 +- .../share/gc/z/zReferenceProcessor.cpp | 4 +-- src/hotspot/share/gc/z/zVerify.cpp | 24 +++++++++------ 10 files changed, 55 insertions(+), 31 deletions(-) diff --git a/src/hotspot/share/gc/z/zAddress.cpp b/src/hotspot/share/gc/z/zAddress.cpp index d1c199fad07..1cd33e44a05 100644 --- a/src/hotspot/share/gc/z/zAddress.cpp +++ b/src/hotspot/share/gc/z/zAddress.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -93,9 +93,7 @@ static void initialize_check_oop_function() { #ifdef CHECK_UNHANDLED_OOPS if (ZVerifyOops) { // Enable extra verification of usages of oops in oopsHierarchy.hpp - check_oop_function = [](oopDesc* obj) { - (void)to_zaddress(obj); - }; + check_oop_function = &check_is_valid_zaddress; } #endif } diff --git a/src/hotspot/share/gc/z/zAddress.inline.hpp b/src/hotspot/share/gc/z/zAddress.inline.hpp index 4adbf50bc86..bbc92a7e2aa 100644 --- a/src/hotspot/share/gc/z/zAddress.inline.hpp +++ b/src/hotspot/share/gc/z/zAddress.inline.hpp @@ -333,10 +333,22 @@ inline void dereferenceable_test(zaddress addr) { } #endif -inline zaddress to_zaddress(uintptr_t value) { - const zaddress addr = zaddress(value); +inline void check_is_valid_zaddress(zaddress addr) { assert_is_valid(addr); DEBUG_ONLY(dereferenceable_test(addr)); +} + +inline void check_is_valid_zaddress(uintptr_t value) { + check_is_valid_zaddress(zaddress(value)); +} + +inline void check_is_valid_zaddress(oopDesc* o) { + check_is_valid_zaddress(uintptr_t(o)); +} + +inline zaddress to_zaddress(uintptr_t value) { + const zaddress addr = zaddress(value); + check_is_valid_zaddress(addr); return addr; } @@ -344,7 +356,7 @@ inline zaddress to_zaddress(oopDesc* o) { return to_zaddress(uintptr_t(o)); } -inline oop to_oop(zaddress addr) { +inline void assert_is_oop_or_null(zaddress addr) { const oop obj = cast_to_oop(addr); assert(!ZVerifyOops || oopDesc::is_oop_or_null(obj), "Broken oop: " PTR_FORMAT " [" PTR_FORMAT " " PTR_FORMAT " " PTR_FORMAT " " PTR_FORMAT "]", p2i(obj), @@ -352,7 +364,16 @@ inline oop to_oop(zaddress addr) { *(uintptr_t*)(untype(addr) + 0x08), *(uintptr_t*)(untype(addr) + 0x10), *(uintptr_t*)(untype(addr) + 0x18)); - return obj; +} + +inline void assert_is_oop(zaddress addr) { + assert(!is_null(addr), "Should not be null"); + assert_is_oop_or_null(addr); +} + +inline oop to_oop(zaddress addr) { + assert_is_oop_or_null(addr); + return cast_to_oop(addr); } inline zaddress operator+(zaddress addr, size_t size) { @@ -378,7 +399,6 @@ inline void assert_is_valid(zaddress_unsafe addr) { DEBUG_ONLY(is_valid(addr, true /* assert_on_failure */);) } - inline uintptr_t untype(zaddress_unsafe addr) { return static_cast(addr); } diff --git a/src/hotspot/share/gc/z/zBarrier.inline.hpp b/src/hotspot/share/gc/z/zBarrier.inline.hpp index b3191e9ae3f..a3eb7a9ca67 100644 --- a/src/hotspot/share/gc/z/zBarrier.inline.hpp +++ b/src/hotspot/share/gc/z/zBarrier.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -745,7 +745,7 @@ inline void ZBarrier::mark_and_remember(volatile zpointer* p, zaddress addr) { template inline void ZBarrier::mark(zaddress addr) { - assert(!ZVerifyOops || oopDesc::is_oop(to_oop(addr), false), "must be oop"); + assert_is_oop(addr); if (ZHeap::heap()->is_old(addr)) { ZGeneration::old()->mark_object_if_active(addr); @@ -757,7 +757,7 @@ inline void ZBarrier::mark(zaddress addr) { template inline void ZBarrier::mark_young(zaddress addr) { assert(ZGeneration::young()->is_phase_mark(), "Should only be called during marking"); - assert(!ZVerifyOops || oopDesc::is_oop(to_oop(addr), false), "must be oop"); + assert_is_oop(addr); assert(ZHeap::heap()->is_young(addr), "Must be young"); ZGeneration::young()->mark_object(addr); diff --git a/src/hotspot/share/gc/z/zBarrierSet.inline.hpp b/src/hotspot/share/gc/z/zBarrierSet.inline.hpp index d53b69345dd..174cdfd9e90 100644 --- a/src/hotspot/share/gc/z/zBarrierSet.inline.hpp +++ b/src/hotspot/share/gc/z/zBarrierSet.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -430,7 +430,7 @@ class ZLoadBarrierOopClosure : public BasicOopIterateClosure { template inline void ZBarrierSet::AccessBarrier::clone_in_heap(oop src, oop dst, size_t size) { - assert_is_valid(to_zaddress(src)); + check_is_valid_zaddress(src); if (dst->is_objArray()) { // Cloning an object array is similar to performing array copy. diff --git a/src/hotspot/share/gc/z/zHeapIterator.cpp b/src/hotspot/share/gc/z/zHeapIterator.cpp index 50fc921131f..e149a976add 100644 --- a/src/hotspot/share/gc/z/zHeapIterator.cpp +++ b/src/hotspot/share/gc/z/zHeapIterator.cpp @@ -146,7 +146,7 @@ class ZHeapIteratorUncoloredRootOopClosure : public OopClosure { oop load_oop(oop* p) { const oop o = Atomic::load(p); - assert_is_valid(to_zaddress(o)); + check_is_valid_zaddress(o); return RawAccess<>::oop_load(p); } diff --git a/src/hotspot/share/gc/z/zMark.cpp b/src/hotspot/share/gc/z/zMark.cpp index eb342495f57..d33b86c83e5 100644 --- a/src/hotspot/share/gc/z/zMark.cpp +++ b/src/hotspot/share/gc/z/zMark.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -365,7 +365,7 @@ void ZMark::follow_array_object(objArrayOop obj, bool finalizable) { } // Should be convertible to colorless oop - assert_is_valid(to_zaddress(obj)); + check_is_valid_zaddress(obj); zpointer* const addr = (zpointer*)obj->base(); const size_t length = (size_t)obj->length(); diff --git a/src/hotspot/share/gc/z/zMark.inline.hpp b/src/hotspot/share/gc/z/zMark.inline.hpp index b5302593610..9edc57a6000 100644 --- a/src/hotspot/share/gc/z/zMark.inline.hpp +++ b/src/hotspot/share/gc/z/zMark.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ template inline void ZMark::mark_object(zaddress addr) { - assert(!ZVerifyOops || oopDesc::is_oop(to_oop(addr)), "Should be oop"); + assert_is_oop(addr); ZPage* const page = _page_table->get(addr); if (page->is_allocating()) { diff --git a/src/hotspot/share/gc/z/zPage.inline.hpp b/src/hotspot/share/gc/z/zPage.inline.hpp index fcf69c685f7..d8ecad57190 100644 --- a/src/hotspot/share/gc/z/zPage.inline.hpp +++ b/src/hotspot/share/gc/z/zPage.inline.hpp @@ -311,7 +311,7 @@ inline bool ZPage::mark_object(zaddress addr, bool finalizable, bool& inc_live) assert(is_in(addr), "Invalid address"); // Verify oop - (void)to_oop(addr); + assert_is_oop(addr); // Set mark bit const BitMap::idx_t index = bit_index(addr); diff --git a/src/hotspot/share/gc/z/zReferenceProcessor.cpp b/src/hotspot/share/gc/z/zReferenceProcessor.cpp index df8cb2b0e95..1252de2ac27 100644 --- a/src/hotspot/share/gc/z/zReferenceProcessor.cpp +++ b/src/hotspot/share/gc/z/zReferenceProcessor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -143,7 +143,7 @@ bool ZReferenceProcessor::is_inactive(zaddress reference, oop referent, Referenc return !is_null(reference_next(reference)); } else { // Verification - (void)to_zaddress(referent); + check_is_valid_zaddress(referent); // A non-FinalReference is inactive if the referent is null. The referent can only // be null if the application called Reference.enqueue() or Reference.clear(). diff --git a/src/hotspot/share/gc/z/zVerify.cpp b/src/hotspot/share/gc/z/zVerify.cpp index d47886ec7c2..b735965e9d4 100644 --- a/src/hotspot/share/gc/z/zVerify.cpp +++ b/src/hotspot/share/gc/z/zVerify.cpp @@ -111,6 +111,16 @@ static bool z_is_null_relaxed(zpointer o) { return (untype(o) & ~color_mask) == 0; } +static void z_verify_oop_object(zaddress addr, zpointer o, void* p) { + const oop obj = cast_to_oop(addr); + guarantee(oopDesc::is_oop(obj), BAD_OOP_ARG(o, p)); +} + +static void z_verify_root_oop_object(zaddress addr, void* p) { + const oop obj = cast_to_oop(addr); + guarantee(oopDesc::is_oop(obj), BAD_OOP_ARG(addr, p)); +} + static void z_verify_old_oop(zpointer* p) { const zpointer o = *p; assert(o != zpointer::null, "Old should not contain raw null"); @@ -121,7 +131,7 @@ static void z_verify_old_oop(zpointer* p) { // safepoint after reference processing, where we hold the driver lock and // know there is no concurrent remembered set processing in the young generation. const zaddress addr = ZPointer::uncolor(o); - guarantee(oopDesc::is_oop(to_oop(addr)), BAD_OOP_ARG(o, p)); + z_verify_oop_object(addr, o, p); } else { const zaddress addr = ZBarrier::load_barrier_on_oop_field_preloaded(nullptr, o); // Old to young pointers might not be mark good if the young @@ -143,15 +153,11 @@ static void z_verify_young_oop(zpointer* p) { guarantee(ZPointer::is_marked_young(o), BAD_OOP_ARG(o, p)); if (ZPointer::is_load_good(o)) { - guarantee(oopDesc::is_oop(to_oop(ZPointer::uncolor(o))), BAD_OOP_ARG(o, p)); + z_verify_oop_object(ZPointer::uncolor(o), o, p); } } } -static void z_verify_root_oop_object(zaddress o, void* p) { - guarantee(oopDesc::is_oop(to_oop(o)), BAD_OOP_ARG(o, p)); -} - static void z_verify_uncolored_root_oop(zaddress* p) { assert(!ZHeap::heap()->is_in((uintptr_t)p), "Roots shouldn't be in heap"); const zaddress o = *p; @@ -168,7 +174,7 @@ static void z_verify_possibly_weak_oop(zpointer* p) { const zaddress addr = ZBarrier::load_barrier_on_oop_field_preloaded(nullptr, o); guarantee(ZHeap::heap()->is_old(addr) || ZPointer::is_marked_young(o), BAD_OOP_ARG(o, p)); guarantee(ZHeap::heap()->is_young(addr) || ZHeap::heap()->is_object_live(addr), BAD_OOP_ARG(o, p)); - guarantee(oopDesc::is_oop(to_oop(addr)), BAD_OOP_ARG(o, p)); + z_verify_oop_object(addr, o, p); // Verify no missing remset entries. We are holding the driver lock here and that // allows us to more precisely verify the remembered set, as there is no concurrent @@ -211,14 +217,14 @@ class ZVerifyColoredRootClosure : public OopClosure { // Minor collections could have relocated the object; // use load barrier to find correct object. const zaddress addr = ZBarrier::load_barrier_on_oop_field_preloaded(nullptr, o); - z_verify_root_oop_object(addr, p); + z_verify_oop_object(addr, o, p); } else { // Don't know the state of the oop if (is_valid(o)) { // it looks like a valid colored oop; // use load barrier to find correct object. const zaddress addr = ZBarrier::load_barrier_on_oop_field_preloaded(nullptr, o); - z_verify_root_oop_object(addr, p); + z_verify_oop_object(addr, o, p); } } } From 53fce38a3ff8700fef640fffc066efc21ff9c25f Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Fri, 9 Aug 2024 07:53:15 +0000 Subject: [PATCH 360/460] 8338062: JFR: Remove TestStartDuration.java and TestStartName.java from ProblemList.txt Reviewed-by: mgronlun --- test/jdk/ProblemList.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 8aedbc77931..293d9d108d3 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -745,8 +745,6 @@ jdk/incubator/vector/LoadJsvmlTest.java 8305390 windows- # jdk_jfr jdk/jfr/event/runtime/TestResidentSetSizeEvent.java 8309846 aix-ppc64 -jdk/jfr/startupargs/TestStartName.java 8214685 windows-x64 -jdk/jfr/startupargs/TestStartDuration.java 8214685 windows-x64 jdk/jfr/jvm/TestWaste.java 8282427 generic-all ############################################################################ From 6ebd5d74d57b334e7cf0b1282d7bb469a56fb3d6 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Fri, 9 Aug 2024 08:23:44 +0000 Subject: [PATCH 361/460] 8338036: Serial: Remove Generation::update_counters Reviewed-by: kbarrett --- src/hotspot/share/gc/serial/generation.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/serial/generation.hpp b/src/hotspot/share/gc/serial/generation.hpp index beb29928f48..c6a9f94a870 100644 --- a/src/hotspot/share/gc/serial/generation.hpp +++ b/src/hotspot/share/gc/serial/generation.hpp @@ -114,8 +114,7 @@ class Generation: public CHeapObj { public: // Performance Counter support - virtual void update_counters() = 0; - virtual CollectorCounters* counters() { return _gc_counters; } + CollectorCounters* counters() { return _gc_counters; } GCMemoryManager* gc_manager() const { assert(_gc_manager != nullptr, "not initialized yet"); From c37e8638c98cb4516569304e9a0ab477affb0641 Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Fri, 9 Aug 2024 09:12:41 +0000 Subject: [PATCH 362/460] 8314125: RISC-V: implement Base64 intrinsic - encoding Reviewed-by: fyang, luhenry --- src/hotspot/cpu/riscv/assembler_riscv.hpp | 13 + src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 223 ++++++++++++++++++ src/hotspot/cpu/riscv/vm_version_riscv.cpp | 5 + 3 files changed, 241 insertions(+) diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index e4280ab34e1..79279be7acc 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -1828,6 +1828,19 @@ enum Nf { #undef INSN +#define INSN(NAME, op, width, umop, mop, mew, nf) \ + void NAME(VectorRegister Vd_or_Vs3, Register Rs1, VectorMask vm = unmasked) { \ + patch_VLdSt(op, Vd_or_Vs3, width, Rs1, umop, vm, mop, mew, nf); \ + } + + // Vector Unit-Stride Segment Load Instructions + INSN(vlseg3e8_v, 0b0000111, 0b000, 0b00000, 0b00, 0b0, g3); + + // Vector Unit-Stride Segment Store Instructions + INSN(vsseg4e8_v, 0b0100111, 0b000, 0b00000, 0b00, 0b0, g4); + +#undef INSN + #define INSN(NAME, op, width, mop, mew) \ void NAME(VectorRegister Vd, Register Rs1, VectorRegister Vs2, VectorMask vm = unmasked, Nf nf = g1) { \ patch_VLdSt(op, Vd, width, Rs1, Vs2->raw_encoding(), vm, mop, mew, nf); \ diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index 198835d733f..6a2c6c7d6c9 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -5103,6 +5103,225 @@ class StubGenerator: public StubCodeGenerator { return (address) start; } + /** + * vector registers: + * input VectorRegister's: intputV1-V3, for m2 they could be v2, v4, v6, for m1 they could be v1, v2, v3 + * index VectorRegister's: idxV1-V4, for m2 they could be v8, v10, v12, v14, for m1 they could be v4, v5, v6, v7 + * output VectorRegister's: outputV1-V4, for m2 they could be v16, v18, v20, v22, for m1 they could be v8, v9, v10, v11 + * + * NOTE: each field will occupy a vector register group + */ + void base64_vector_encode_round(Register src, Register dst, Register codec, + Register size, Register stepSrc, Register stepDst, + VectorRegister inputV1, VectorRegister inputV2, VectorRegister inputV3, + VectorRegister idxV1, VectorRegister idxV2, VectorRegister idxV3, VectorRegister idxV4, + VectorRegister outputV1, VectorRegister outputV2, VectorRegister outputV3, VectorRegister outputV4, + Assembler::LMUL lmul) { + // set vector register type/len + __ vsetvli(x0, size, Assembler::e8, lmul); + + // segmented load src into v registers: mem(src) => vr(3) + __ vlseg3e8_v(inputV1, src); + + // src = src + register_group_len_bytes * 3 + __ add(src, src, stepSrc); + + // encoding + // 1. compute index into lookup table: vr(3) => vr(4) + __ vsrl_vi(idxV1, inputV1, 2); + + __ vsrl_vi(idxV2, inputV2, 2); + __ vsll_vi(inputV1, inputV1, 6); + __ vor_vv(idxV2, idxV2, inputV1); + __ vsrl_vi(idxV2, idxV2, 2); + + __ vsrl_vi(idxV3, inputV3, 4); + __ vsll_vi(inputV2, inputV2, 4); + __ vor_vv(idxV3, inputV2, idxV3); + __ vsrl_vi(idxV3, idxV3, 2); + + __ vsll_vi(idxV4, inputV3, 2); + __ vsrl_vi(idxV4, idxV4, 2); + + // 2. indexed load: vr(4) => vr(4) + __ vluxei8_v(outputV1, codec, idxV1); + __ vluxei8_v(outputV2, codec, idxV2); + __ vluxei8_v(outputV3, codec, idxV3); + __ vluxei8_v(outputV4, codec, idxV4); + + // segmented store encoded data in v registers back to dst: vr(4) => mem(dst) + __ vsseg4e8_v(outputV1, dst); + + // dst = dst + register_group_len_bytes * 4 + __ add(dst, dst, stepDst); + } + + /** + * void j.u.Base64.Encoder.encodeBlock(byte[] src, int sp, int sl, byte[] dst, int dp, boolean isURL) + * + * Input arguments: + * c_rarg0 - src, source array + * c_rarg1 - sp, src start offset + * c_rarg2 - sl, src end offset + * c_rarg3 - dst, dest array + * c_rarg4 - dp, dst start offset + * c_rarg5 - isURL, Base64 or URL character set + */ + address generate_base64_encodeBlock() { + alignas(64) static const char toBase64[64] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' + }; + + alignas(64) static const char toBase64URL[64] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_' + }; + + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "encodeBlock"); + address start = __ pc(); + __ enter(); + + Register src = c_rarg0; + Register soff = c_rarg1; + Register send = c_rarg2; + Register dst = c_rarg3; + Register doff = c_rarg4; + Register isURL = c_rarg5; + + Register codec = c_rarg6; + Register length = c_rarg7; // total length of src data in bytes + + Label ProcessData, Exit; + + // length should be multiple of 3 + __ sub(length, send, soff); + // real src/dst to process data + __ add(src, src, soff); + __ add(dst, dst, doff); + + // load the codec base address + __ la(codec, ExternalAddress((address) toBase64)); + __ beqz(isURL, ProcessData); + __ la(codec, ExternalAddress((address) toBase64URL)); + __ BIND(ProcessData); + + // vector version + if (UseRVV) { + Label ProcessM2, ProcessM1, ProcessScalar; + + Register size = soff; + Register stepSrcM1 = send; + Register stepSrcM2 = doff; + Register stepDst = isURL; + + __ mv(size, MaxVectorSize * 2); + __ mv(stepSrcM1, MaxVectorSize * 3); + __ slli(stepSrcM2, stepSrcM1, 1); + __ mv(stepDst, MaxVectorSize * 2 * 4); + + __ blt(length, stepSrcM2, ProcessM1); + + __ BIND(ProcessM2); + base64_vector_encode_round(src, dst, codec, + size, stepSrcM2, stepDst, + v2, v4, v6, // inputs + v8, v10, v12, v14, // indexes + v16, v18, v20, v22, // outputs + Assembler::m2); + + __ sub(length, length, stepSrcM2); + __ bge(length, stepSrcM2, ProcessM2); + + __ BIND(ProcessM1); + __ blt(length, stepSrcM1, ProcessScalar); + + __ srli(size, size, 1); + __ srli(stepDst, stepDst, 1); + base64_vector_encode_round(src, dst, codec, + size, stepSrcM1, stepDst, + v1, v2, v3, // inputs + v4, v5, v6, v7, // indexes + v8, v9, v10, v11, // outputs + Assembler::m1); + __ sub(length, length, stepSrcM1); + + __ BIND(ProcessScalar); + } + + // scalar version + { + Register byte1 = soff, byte0 = send, byte2 = doff; + Register combined24Bits = isURL; + + __ beqz(length, Exit); + + Label ScalarLoop; + __ BIND(ScalarLoop); + { + // plain: [byte0[7:0] : byte1[7:0] : byte2[7:0]] => + // encoded: [byte0[7:2] : byte0[1:0]+byte1[7:4] : byte1[3:0]+byte2[7:6] : byte2[5:0]] + + // load 3 bytes src data + __ lbu(byte0, Address(src, 0)); + __ lbu(byte1, Address(src, 1)); + __ lbu(byte2, Address(src, 2)); + __ addi(src, src, 3); + + // construct 24 bits from 3 bytes + __ slliw(byte0, byte0, 16); + __ slliw(byte1, byte1, 8); + __ orr(combined24Bits, byte0, byte1); + __ orr(combined24Bits, combined24Bits, byte2); + + // get codec index and encode(ie. load from codec by index) + __ slliw(byte0, combined24Bits, 8); + __ srliw(byte0, byte0, 26); + __ add(byte0, codec, byte0); + __ lbu(byte0, byte0); + + __ slliw(byte1, combined24Bits, 14); + __ srliw(byte1, byte1, 26); + __ add(byte1, codec, byte1); + __ lbu(byte1, byte1); + + __ slliw(byte2, combined24Bits, 20); + __ srliw(byte2, byte2, 26); + __ add(byte2, codec, byte2); + __ lbu(byte2, byte2); + + __ andi(combined24Bits, combined24Bits, 0x3f); + __ add(combined24Bits, codec, combined24Bits); + __ lbu(combined24Bits, combined24Bits); + + // store 4 bytes encoded data + __ sb(byte0, Address(dst, 0)); + __ sb(byte1, Address(dst, 1)); + __ sb(byte2, Address(dst, 2)); + __ sb(combined24Bits, Address(dst, 3)); + + __ sub(length, length, 3); + __ addi(dst, dst, 4); + // loop back + __ bnez(length, ScalarLoop); + } + } + + __ BIND(Exit); + + __ leave(); + __ ret(); + + return (address) start; + } + void adler32_process_bytes(Register buff, Register s1, Register s2, VectorRegister vtable, VectorRegister vzero, VectorRegister vbytes, VectorRegister vs1acc, VectorRegister vs2acc, Register temp0, Register temp1, Register temp2, Register temp3, @@ -5996,6 +6215,10 @@ static const int64_t right_3_bits = right_n_bits(3); StubRoutines::_sha1_implCompressMB = generate_sha1_implCompress(true, "sha1_implCompressMB"); } + if (UseBASE64Intrinsics) { + StubRoutines::_base64_encodeBlock = generate_base64_encodeBlock(); + } + if (UseAdler32Intrinsics) { StubRoutines::_updateBytesAdler32 = generate_updateBytesAdler32(); } diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp index ac2d6cde1a2..e9c6226f446 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -265,6 +265,11 @@ void VM_Version::c2_initialize() { // as there are extra checks inside it which could disable UseRVV // in some situations. + // Base64 + if (FLAG_IS_DEFAULT(UseBASE64Intrinsics)) { + FLAG_SET_DEFAULT(UseBASE64Intrinsics, true); + } + if (FLAG_IS_DEFAULT(UseVectorizedHashCodeIntrinsic)) { FLAG_SET_DEFAULT(UseVectorizedHashCodeIntrinsic, true); } From 140716078694a338e2c2f837841761262cee5542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Fri, 9 Aug 2024 09:24:50 +0000 Subject: [PATCH 363/460] 8313931: Javadoc: links to type parameters actually generate links to classes Reviewed-by: jjg --- .../doclets/formats/html/ClassWriter.java | 50 +++++-- .../doclets/formats/html/HtmlIds.java | 16 +++ .../doclets/formats/html/HtmlLinkFactory.java | 13 +- .../formats/html/resources/script.js.template | 18 ++- .../formats/html/resources/stylesheet.css | 22 +++- .../formats/html/taglets/LinkTaglet.java | 24 +++- .../formats/html/taglets/ParamTaglet.java | 6 +- .../doclets/toolkit/util/CommentHelper.java | 6 + .../TestDeprecatedDocs.java | 8 +- .../TestDirectedInheritance.java | 6 +- .../doclet/testErasure/TestErasure.java | 8 +- .../TestGenericMethodLinkTaglet.java | 6 +- .../jdk/javadoc/doclet/testHref/TestHref.java | 5 +- .../doclet/testInterface/TestInterface.java | 36 ++--- .../TestLinkTagletTypeParam.java | 124 ++++++++++++++++++ .../TestMemberInheritance.java | 4 +- .../doclet/testModules/TestModules.java | 2 +- .../TestNewLanguageFeatures.java | 22 ++-- .../testParamTaglet/TestParamTaglet.java | 6 +- .../doclet/testProperty/TestProperty.java | 4 +- .../testRecordTypes/TestRecordTypes.java | 2 +- .../TestSerializedForm.java | 5 +- .../javadoc/doclet/testThrows/TestThrows.java | 4 +- .../testTypeParams/TestTypeParameters.java | 20 ++- .../testTypeParams/pkg/CtorTypeParam.java | 6 + .../doclet/testUnicode/TestUnicode.java | 4 +- 26 files changed, 336 insertions(+), 91 deletions(-) create mode 100644 test/langtools/jdk/javadoc/doclet/testLinkTaglet/TestLinkTagletTypeParam.java diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java index a1fd27fefdd..8218e5128be 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java @@ -37,6 +37,7 @@ import javax.lang.model.element.Name; import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; +import javax.lang.model.element.TypeParameterElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.SimpleElementVisitor8; @@ -155,7 +156,7 @@ protected void buildClassTree(Content classContent) { * @param target the content to which the documentation will be added */ protected void buildClassInfo(Content target) { - Content c = HtmlTree.DIV(HtmlStyles.horizontalScroll); + var c = new ContentBuilder(); buildParamInfo(c); buildSuperInterfacesInfo(c); buildImplementedInterfacesInfo(c); @@ -164,11 +165,13 @@ protected void buildClassInfo(Content target) { buildInterfaceUsageInfo(c); buildNestedClassInfo(c); buildFunctionalInterfaceInfo(c); - buildClassSignature(c); - buildDeprecationInfo(c); - buildClassDescription(c); - buildClassTagInfo(c); - + c.add(new HtmlTree(HtmlTag.HR)); + var div = HtmlTree.DIV(HtmlStyles.horizontalScroll); + buildClassSignature(div); + buildDeprecationInfo(div); + buildClassDescription(div); + buildClassTagInfo(div); + c.add(div); target.add(getClassInfo(c)); } @@ -432,12 +435,9 @@ private void setRecordDocumentation(TypeElement elem) { protected Content getHeader(String header) { HtmlTree body = getBody(getWindowTitle(utils.getSimpleName(typeElement))); var div = HtmlTree.DIV(HtmlStyles.header); - HtmlLinkInfo linkInfo = new HtmlLinkInfo(configuration, - HtmlLinkInfo.Kind.SHOW_TYPE_PARAMS_AND_BOUNDS, typeElement) - .linkToSelf(false); // Let's not link to ourselves in the header var heading = HtmlTree.HEADING_TITLE(Headings.PAGE_TITLE_HEADING, HtmlStyles.title, Text.of(header)); - heading.add(getTypeParameterLinks(linkInfo)); + heading.add(getTypeParameters()); div.add(heading); bodyContents.setHeader(getHeader(PageMode.CLASS, typeElement)) .addMainContent(MarkerComments.START_OF_CLASS_DATA) @@ -445,6 +445,35 @@ protected Content getHeader(String header) { return body; } + // Renders type parameters for the class heading, creating id attributes + // if @param block tags are missing in doc comment. + private Content getTypeParameters() { + var content = new ContentBuilder(); + var typeParams = typeElement.getTypeParameters(); + if (!typeParams.isEmpty()) { + // Generate id attributes if @param tags are missing for type parameters. + // Note that this does not handle the case where some but not all @param tags are missing. + var needsId = !utils.hasBlockTag(typeElement, DocTree.Kind.PARAM); + var linkInfo = new HtmlLinkInfo(configuration, + HtmlLinkInfo.Kind.SHOW_TYPE_PARAMS_AND_BOUNDS, typeElement) + .linkToSelf(false); // Let's not link to ourselves in the header + content.add("<"); + var first = true; + for (TypeParameterElement t : typeParams) { + if (!first) { + content.add(",").add(new HtmlTree(HtmlTag.WBR)); + } + var typeParamLink = getLink(linkInfo.forType(t.asType())); + content.add(needsId + ? HtmlTree.SPAN_ID(htmlIds.forTypeParam(t.getSimpleName().toString(), typeElement), typeParamLink) + : typeParamLink); + first = false; + } + content.add(">"); + } + return content; + } + protected Content getClassContentHeader() { return getContentHeader(); } @@ -473,7 +502,6 @@ public TypeElement getCurrentPageElement() { } protected void addClassSignature(Content classInfo) { - classInfo.add(new HtmlTree(HtmlTag.HR)); classInfo.add(new Signatures.TypeSignature(typeElement, this) .toContent()); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java index 1b9896fafa0..8b48c7a6f22 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java @@ -462,6 +462,22 @@ public static HtmlId forText(String text, Map counts) { return HtmlId.of(count == 0 ? base : base + "-" + count); } + /** + * Returns an id for text documenting a type parameter of a class or method. + * + * @param paramName the name of the type parameter + * @param owner the enclosing element + * + * @return the id + */ + public HtmlId forTypeParam(String paramName, Element owner) { + if (utils.isExecutableElement(owner)) { + return HtmlId.of(forMember((ExecutableElement) owner).getFirst().name() + + "-type-param-" + paramName); + } + return HtmlId.of("type-param-" + paramName); + } + /** * Returns an id for one of the kinds of section in the pages for item group summaries. * diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java index 22af1e4a024..8e0c010dd1a 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java @@ -162,9 +162,11 @@ public Content visitTypeVariable(TypeVariable type, HtmlLinkInfo linkInfo) { Element owner = typevariable.asElement().getEnclosingElement(); if (linkInfo.linkTypeParameters() && utils.isTypeElement(owner)) { linkInfo.setTypeElement((TypeElement) owner); - Content label = newContent(); - label.add(utils.getTypeName(type, false)); - linkInfo.label(label).skipPreview(true); + if (linkInfo.getLabel() == null || linkInfo.getLabel().isEmpty()) { + Content label = newContent(); + label.add(utils.getTypeName(type, false)); + linkInfo.label(label).skipPreview(true); + } link.add(getClassLink(linkInfo)); } else { // No need to link method type parameters. @@ -242,6 +244,11 @@ protected Content getClassLink(HtmlLinkInfo linkInfo) { boolean isTypeLink = linkInfo.getType() != null && utils.isTypeVariable(utils.getComponentType(linkInfo.getType())); title = getClassToolTip(typeElement, isTypeLink); + if (isTypeLink) { + linkInfo.fragment(m_writer.configuration.htmlIds.forTypeParam( + utils.getTypeName(utils.getComponentType(linkInfo.getType()), false), + typeElement).name()); + } } Content label = linkInfo.getClassLinkLabel(configuration); if (linkInfo.getContext() == HtmlLinkInfo.Kind.SHOW_TYPE_PARAMS_IN_LABEL) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template index ef09e6df90f..71ef8476708 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template @@ -232,6 +232,20 @@ document.addEventListener("readystatechange", (e) => { }); document.addEventListener("DOMContentLoaded", function(e) { setTopMargin(); + // Reset animation for type parameter target highlight + document.querySelectorAll("a").forEach((link) => { + link.addEventListener("click", (e) => { + const href = e.currentTarget.getAttribute("href"); + if (href && href.startsWith("#") && href.indexOf("type-param-") > -1) { + const target = document.getElementById(decodeURI(href.substring(1))); + if (target) { + target.style.animation = "none"; + void target.offsetHeight; + target.style.removeProperty("animation"); + } + } + }) + }); // Make sure current element is visible in breadcrumb navigation on small displays const subnav = document.querySelector("ol.sub-nav-list"); if (subnav && subnav.lastElementChild) { @@ -286,7 +300,7 @@ document.addEventListener("DOMContentLoaded", function(e) { }); var expanded = false; var windowWidth; - function collapse() { + function collapse(e) { if (expanded) { mainnav.removeAttribute("style"); if (toc) { @@ -336,7 +350,7 @@ document.addEventListener("DOMContentLoaded", function(e) { document.querySelectorAll("h1, h2, h3, h4, h5, h6") .forEach((hdr, idx) => { // Create anchor links for headers with an associated id attribute - var id = hdr.getAttribute("id") || hdr.parentElement.getAttribute("id") + var id = hdr.parentElement.getAttribute("id") || hdr.getAttribute("id") || (hdr.querySelector("a") && hdr.querySelector("a").getAttribute("id")); if (id) { var template = document.createElement('template'); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css index 4e37588f6cd..1130f14dc35 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css @@ -63,7 +63,7 @@ --search-input-text-color: #000000; --search-input-placeholder-color: #909090; /* Highlight color for active search tag target */ - --search-tag-highlight-color: #ffff00; + --search-tag-highlight-color: #ffff66; /* Adjustments for icon and active background colors of copy-to-clipboard buttons */ --copy-icon-brightness: 100%; --copy-button-background-color-active: rgba(168, 168, 176, 0.3); @@ -307,7 +307,7 @@ ol.sub-nav-list a.current-selection { */ .title { color:var(--title-color); - margin:10px 0; + margin:10px 0 12px 0; } .sub-title { margin:5px 0 0 0; @@ -988,6 +988,22 @@ input::placeholder { .search-tag-result:target { background-color:var(--search-tag-highlight-color); } +dd > span:target, +h1 > span:target { + animation: 2.4s ease-out highlight; +} +section.class-description dd > span:target, +section.class-description h1 > span:target { + scroll-margin-top: 20em; +} +@keyframes highlight { + from { + background-color: var(--search-tag-highlight-color); + } + 60% { + background-color: var(--search-tag-highlight-color); + } +} details.page-search-details { display: inline-block; } @@ -1040,7 +1056,7 @@ span#page-search-link { z-index: 5; } .inherited-list { - margin: 10px 0 10px 0; + margin: 10px 0; } .horizontal-scroll { overflow: auto hidden; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java index e16acd0315a..b16a1490b63 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -176,7 +176,7 @@ Content linkSeeReferenceOutput(Element holder, return htmlWriter.getPackageLink(refPackage, labelContent, refFragment); } else { // @see is not referencing an included class, module or package. Check for cross-links. - String refModuleName = ch.getReferencedModuleName(refSignature); + String refModuleName = ch.getReferencedModuleName(refSignature); DocLink elementCrossLink = (refPackage != null) ? htmlWriter.getCrossPackageLink(refPackage) : (config.extern.isModule(refModuleName)) ? htmlWriter.getCrossModuleLink(utils.elementUtils.getModuleElement(refModuleName)) @@ -190,12 +190,28 @@ Content linkSeeReferenceOutput(Element holder, if (!config.isDocLintReferenceGroupEnabled()) { reportWarning.accept( "doclet.link.see.reference_not_found", - new Object[] { refSignature}); + new Object[] {refSignature}); } return htmlWriter.invalidTagOutput(resources.getText("doclet.link.see.reference_invalid"), - Optional.of(labelContent.isEmpty() ? text: labelContent)); + Optional.of(labelContent.isEmpty() ? text : labelContent)); } } + } else if (utils.isTypeParameterElement(ref)) { + // This is a type parameter of a generic class, method or constructor + if (labelContent.isEmpty()) { + labelContent = plainOrCode(isPlain, Text.of(utils.getSimpleName(ref))); + } + if (refMem == null) { + return htmlWriter.getLink( + new HtmlLinkInfo(config, HtmlLinkInfo.Kind.LINK_TYPE_PARAMS, ref.asType()) + .label(labelContent)); + } else { + // HtmlLinkFactory does not render type parameters of generic methods as links, so instead of + // teaching it how to do it (making the code even more complex) just create the link directly. + return htmlWriter.getLink(new HtmlLinkInfo(config, HtmlLinkInfo.Kind.PLAIN, refClass) + .fragment(config.htmlIds.forTypeParam(ref.getSimpleName().toString(), refMem).name()) + .label((labelContent))); + } } else if (refFragment == null) { // Must be a class reference since refClass is not null and refFragment is null. if (labelContent.isEmpty() && refTree != null) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/ParamTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/ParamTaglet.java index ed46e6c5c86..8a3c47bbfd4 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/ParamTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/ParamTaglet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -278,7 +278,9 @@ private Content paramTagOutput(Element element, ParamTree paramTag, String param body.add(" - "); List description = ch.getDescription(paramTag); body.add(htmlWriter.commentTagsToContent(element, description, context.within(paramTag))); - return HtmlTree.DD(body); + return HtmlTree.DD(paramTag.isTypeParameter() + ? HtmlTree.SPAN_ID(config.htmlIds.forTypeParam(paramName, element), body) + : body); } private record Documentation(ParamTree paramTree, ExecutableElement method) { } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java index d7a0bd2d0a0..30aa86aea71 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java @@ -188,6 +188,12 @@ public Element getReferencedMember(Element e) { Utils utils = configuration.utils; if (e == null) { return null; + } else if (utils.isTypeParameterElement(e)) { + // Return the enclosing member for type parameters of generic methods or constructors. + Element encl = e.getEnclosingElement(); + if (utils.isExecutableElement(encl)) { + return encl; + } } return (utils.isExecutableElement(e) || utils.isVariableElement(e)) ? e : null; } diff --git a/test/langtools/jdk/javadoc/doclet/testDeprecatedDocs/TestDeprecatedDocs.java b/test/langtools/jdk/javadoc/doclet/testDeprecatedDocs/TestDeprecatedDocs.java index 2bd9da59578..165fadc8e05 100644 --- a/test/langtools/jdk/javadoc/doclet/testDeprecatedDocs/TestDeprecatedDocs.java +++ b/test/langtools/jdk/javadoc/doclet/testDeprecatedDocs/TestDeprecatedDocs.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -102,7 +102,6 @@ public void test() { checkOutput("pkg/TestAnnotationType.html", true, """ -
@Deprecated(forRemoval=true) @Documented public @interface
@Deprecated(forRemoval=true) public class TestClass extends java.lang.Object
@@ -212,7 +210,6 @@ public void test() { checkOutput("pkg/TestEnum.html", true, """ -
@Deprecated(forRemoval=true) public enum TestEnum extends java.lang.Enum<
@Deprecated(forRemoval=true) public class TestError extends java.lang.Error
@@ -244,7 +240,6 @@ public void test() { checkOutput("pkg/TestException.html", true, """ -
@Deprecated(forRemoval=true) public class TestException extends java.lang.Exception
@@ -255,7 +250,6 @@ public void test() { checkOutput("pkg/TestInterface.html", true, """ -
@Deprecated(forRemoval=true) public class TestInterface extends java.lang.Object
diff --git a/test/langtools/jdk/javadoc/doclet/testDirectedInheritance/TestDirectedInheritance.java b/test/langtools/jdk/javadoc/doclet/testDirectedInheritance/TestDirectedInheritance.java index 89eb68db1df..0f2b398e626 100644 --- a/test/langtools/jdk/javadoc/doclet/testDirectedInheritance/TestDirectedInheritance.java +++ b/test/langtools/jdk/javadoc/doclet/testDirectedInheritance/TestDirectedInheritance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -154,8 +154,8 @@ public interface E1 extends I1, I2 {
I2: main description
""", """
Type Parameters:
-
E - I2: first type parameter
-
F - I2: second type parameter
+
E - I2: first type parameter
+
F - I2: second type parameter
Parameters:
eObj - I2: parameter
Returns:
diff --git a/test/langtools/jdk/javadoc/doclet/testErasure/TestErasure.java b/test/langtools/jdk/javadoc/doclet/testErasure/TestErasure.java index f80074c50e2..ee2ec08b884 100644 --- a/test/langtools/jdk/javadoc/doclet/testErasure/TestErasure.java +++ b/test/langtools/jdk/javadoc/doclet/testErasure/TestErasure.java @@ -199,7 +199,7 @@ class X { }
 
\ Foo\ - (T arg)
+ (T arg)
 
 <T extends X>
\ @@ -227,10 +227,10 @@ class X { } // methods checkOutput("Foo.html", true, """
abstract T
+ method-summary-table-tab3">abstract T
m\ - (T arg)
+ (T arg)
 
Test Feature
"""); } -} \ No newline at end of file +} diff --git a/test/langtools/jdk/javadoc/doclet/testGenericMethodLinkTaglet/TestGenericMethodLinkTaglet.java b/test/langtools/jdk/javadoc/doclet/testGenericMethodLinkTaglet/TestGenericMethodLinkTaglet.java index a9a4be1b262..db23064e9ca 100644 --- a/test/langtools/jdk/javadoc/doclet/testGenericMethodLinkTaglet/TestGenericMethodLinkTaglet.java +++ b/test/langtools/jdk/javadoc/doclet/testGenericMethodLinkTaglet/TestGenericMethodLinkTaglet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8188248 + * @bug 8188248 8313931 * @summary NullPointerException on generic methods * @library /tools/lib ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool @@ -67,7 +67,7 @@ public void test(Path base) throws Exception { checkOutput("pkg/A.html", true, """ - A"""); + param T"""); } void createTestClass(Path srcDir) throws Exception { diff --git a/test/langtools/jdk/javadoc/doclet/testHref/TestHref.java b/test/langtools/jdk/javadoc/doclet/testHref/TestHref.java index f21ad223fb4..b9dff5ff2a8 100644 --- a/test/langtools/jdk/javadoc/doclet/testHref/TestHref.java +++ b/test/langtools/jdk/javadoc/doclet/testHref/TestHref.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,7 +75,8 @@ public void test() { checkOutput("pkg/C4.html", true, //Header does not link to the page itself. - "Class C4<E extends C4<E>>", + """ + Class C4<E extends C4<E>>""", //Signature does not link to the page itself. """ public abstract class method
 in interface&\ nbsp;Interface<CE>""", + href="#type-param-CE" title="type parameter in Child">CE>""", //Make sure "Overrides" has substituted type parameters. """
Overrides:
method in class Parent<Parent<CE>
"""); checkOutput("pkg/Parent.html", true, @@ -190,7 +190,7 @@ public void test1() {
Overrides:
method1 in class&\ nbsp;GrandParent<<\ - a href="Child.html" title="type parameter in Child">CE>"""); + a href="#type-param-CE" title="type parameter in Child">CE>"""); } @Test @@ -209,17 +209,17 @@ public void test2() { erface in pkg2">Spliterator Spliterator.\ OfDouble, Spliter\ - ator.OfInt<Integer>, Spliterator.OfPrimitive<T,T_C\ - ONS,T,T_C\ + ONS,T_SPLITR extends Spliterator.OfPrimitive<T,<\ - a href="Spliterator.OfPrimitive.html" title="type parameter in Spliterator.OfPri\ - mitive">T_CONS,T,<\ + a href="Spliterator.OfPrimitive.html#type-param-T_CONS" title="type parameter in Spliterator.OfPri\ + mitive">T_CONS,T_SPLITR>>"""); checkOutput("pkg2/Spliterator.html", true, """ @@ -236,21 +236,21 @@ public void test2() {
static interface 
Spliterator.OfInt<Integer&\ + Spliterator.OfInt.html#type-param-Integer" title="type parameter in Spliterator.OfInt">Integer&\ gt;
 
static interface 
Spliterator.OfPrimitive\ - <T,T,T_CONS,T_SPLITR extends <\ + e.html#type-param-T_SPLITR" title="type parameter in Spliterator.OfPrimitive">T_SPLITR extends <\ a href="Spliterator.OfPrimitive.html" title="interface in pkg2">Spliterator.OfPr\ - imitive<T,<T,T_CONS,T_SPLITRT_SPLITR>>
 
"""); diff --git a/test/langtools/jdk/javadoc/doclet/testLinkTaglet/TestLinkTagletTypeParam.java b/test/langtools/jdk/javadoc/doclet/testLinkTaglet/TestLinkTagletTypeParam.java new file mode 100644 index 00000000000..5cb1f687d45 --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testLinkTaglet/TestLinkTagletTypeParam.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8313931 + * @summary Javadoc: links to type parameters actually generate links to classes + * @library /tools/lib ../../lib + * @modules jdk.javadoc/jdk.javadoc.internal.tool + * @build toolbox.ToolBox javadoc.tester.* + * @run main TestLinkTagletTypeParam + */ + +import javadoc.tester.JavadocTester; +import toolbox.ToolBox; + +import java.io.IOException; +import java.nio.file.Path; + +public class TestLinkTagletTypeParam extends JavadocTester { + + public static void main(String... args) throws Exception { + var tester = new TestLinkTagletTypeParam(); + tester.runTests(); + } + + ToolBox tb = new ToolBox(); + + @JavadocTester.Test + public void testClassTypeParameterLink(Path base) throws IOException { + Path src = base.resolve("src"); + + tb.writeJavaFiles(src, + """ + /** + * Link to {@link F}. + * + * @param the first type param + * @param an Appendable + * + * @see APND the second type parameter + */ + public class Test { + private Test() {} + } + """); + + javadoc("-Xdoclint:none", + "-d", base.resolve("api").toString(), + "-sourcepath", src.toString(), + src.resolve("Test.java").toString()); + checkExit(JavadocTester.Exit.OK); + + checkOrder("Test.html", + """ +
Type Parameters:
+
F - the first type param
+
APND - an Appendable
""", + """ + Link to
F.""", + """ +
See Also:
+
+ """); + } + + @JavadocTester.Test + public void testMethodTypeParameterLink(Path base) throws IOException { + Path src = base.resolve("src"); + + tb.writeJavaFiles(src, + """ + /** + * Class comment. + */ + public class Test { + /** + * Link to {@link T} and {@linkplain T link with label}. + * + * @param the T + * @param appendable the appendable + */ + public T append(final T appendable) { + return appendable; + } + } + """); + + javadoc("-Xdoclint:reference", + "-d", base.resolve("api").toString(), + "-sourcepath", src.toString(), + src.resolve("Test.java").toString()); + + checkOutput(JavadocTester.Output.OUT, true, + ""); + + checkOutput("Test.html", true, + """ + Link to T and link with label."""); + } +} diff --git a/test/langtools/jdk/javadoc/doclet/testMemberInheritance/TestMemberInheritance.java b/test/langtools/jdk/javadoc/doclet/testMemberInheritance/TestMemberInheritance.java index 705cae327e3..559f7b08d38 100644 --- a/test/langtools/jdk/javadoc/doclet/testMemberInheritance/TestMemberInheritance.java +++ b/test/langtools/jdk/javadoc/doclet/testMemberInheritance/TestMemberInheritance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -120,8 +120,8 @@ interface in pkg">BaseInterface
checkOutput("pkg2/DocumentedNonGenericChild.html", true, """
-

+
public abstract class DocumentedNonGenericChild extends java.lang.Object
diff --git a/test/langtools/jdk/javadoc/doclet/testModules/TestModules.java b/test/langtools/jdk/javadoc/doclet/testModules/TestModules.java index 79bad12f95d..4d3628544f8 100644 --- a/test/langtools/jdk/javadoc/doclet/testModules/TestModules.java +++ b/test/langtools/jdk/javadoc/doclet/testModules/TestModules.java @@ -1360,8 +1360,8 @@ void checkLinkSource(boolean includePrivate) { checkOutput("moduleA/testpkgmdlA/TestClassInModuleA.html", true, """
-

+
public class TestClassInModuleA diff --git a/test/langtools/jdk/javadoc/doclet/testNewLanguageFeatures/TestNewLanguageFeatures.java b/test/langtools/jdk/javadoc/doclet/testNewLanguageFeatures/TestNewLanguageFeatures.java index a54fbbcff75..eafad8c3245 100644 --- a/test/langtools/jdk/javadoc/doclet/testNewLanguageFeatures/TestNewLanguageFeatures.java +++ b/test/langtools/jdk/javadoc/doclet/testNewLanguageFeatures/TestNewLanguageFeatures.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -117,7 +117,7 @@ void checkTypeParameters() { // Check class type parameters section. """
Type Parameters:
-
E - the type parameter for this class.""", +
E - the type parameter for this class.
""", // Type parameters in @see/@link """
@@ -130,12 +130,14 @@ void checkTypeParameters() {
""", // Method that uses class type parameter. """ - (E param)""", + (E param)""", // Method type parameter section. """
Type Parameters:
-
T - This is the first type parameter.
-
V - This is the second type parameter.""", +
T - Th\ + is is the first type parameter.
+
V - Th\ + is is the second type parameter.
""", // Signature of method with type parameters """
public E[]
methodThatReturnsTypeParameterA(E[] \ + ref="#type-param-E" title="type parameter in TypeParameters">E[] \ e)""", """
public E[] methodThatReturnsTypePa\ - rameterA((E[] e)
""", """ @@ -176,7 +178,7 @@ void checkTypeParameters() { """
<X extends java.lang.Throwable>
E
\ + href="#type-param-E" title="type parameter in TypeParameters">E
\
Type Parameters: -
T2 - type 2
+
T2 - type 2
Parameters:
t1 - param 1
t3 - param 3
@@ -92,7 +92,7 @@ public void test() { checkOutput("pkg/C.Nested.html", true, """
Type Parameters:
-
T1 - type 1
+
T1 - type 1
"""); } } diff --git a/test/langtools/jdk/javadoc/doclet/testProperty/TestProperty.java b/test/langtools/jdk/javadoc/doclet/testProperty/TestProperty.java index 7ce046c0757..94ad1a8040f 100644 --- a/test/langtools/jdk/javadoc/doclet/testProperty/TestProperty.java +++ b/test/langtools/jdk/javadoc/doclet/testProperty/TestProperty.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -110,7 +110,7 @@ class in pkg">ObjectProperty
<public final <\ span class="return-type">Obje\ - ctProperty<java.util.List<T>> listProperty<\ /div>
This is an Object property where the Object is a single List<T>.
diff --git a/test/langtools/jdk/javadoc/doclet/testRecordTypes/TestRecordTypes.java b/test/langtools/jdk/javadoc/doclet/testRecordTypes/TestRecordTypes.java index f9aa3cfd6fa..3b6a8a4fc72 100644 --- a/test/langtools/jdk/javadoc/doclet/testRecordTypes/TestRecordTypes.java +++ b/test/langtools/jdk/javadoc/doclet/testRecordTypes/TestRecordTypes.java @@ -175,7 +175,7 @@ public record R(int r1) { }"""); """
Type Parameters:
-
T - This is a type parameter.
+
T - This is a type parameter.
Record Components:
r1 - This is a component.
""", diff --git a/test/langtools/jdk/javadoc/doclet/testSerializedForm/TestSerializedForm.java b/test/langtools/jdk/javadoc/doclet/testSerializedForm/TestSerializedForm.java index 9bf2ac362c6..af3e36aa7d8 100644 --- a/test/langtools/jdk/javadoc/doclet/testSerializedForm/TestSerializedForm.java +++ b/test/langtools/jdk/javadoc/doclet/testSerializedForm/TestSerializedForm.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -219,6 +219,7 @@ public void test2() { """ Fields[] singleArray""", """ - java.lang.Class<E> someClass"""); + java.lang.Class<E> someClass"""); } } diff --git a/test/langtools/jdk/javadoc/doclet/testThrows/TestThrows.java b/test/langtools/jdk/javadoc/doclet/testThrows/TestThrows.java index ca4592ea5f8..e4c57857899 100644 --- a/test/langtools/jdk/javadoc/doclet/testThrows/TestThrows.java +++ b/test/langtools/jdk/javadoc/doclet/testThrows/TestThrows.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -83,7 +83,7 @@ public interface C { """
Type Parameters:
-
T - the throwable
+
T - the throwable
Throws:
T - if a specific error occurs
java.lang.Exception - if an exception occurs
diff --git a/test/langtools/jdk/javadoc/doclet/testTypeParams/TestTypeParameters.java b/test/langtools/jdk/javadoc/doclet/testTypeParams/TestTypeParameters.java index 0d95ee38cdc..dad610acb30 100644 --- a/test/langtools/jdk/javadoc/doclet/testTypeParams/TestTypeParameters.java +++ b/test/langtools/jdk/javadoc/doclet/testTypeParams/TestTypeParameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 4927167 4974929 6381729 7010344 8025633 8081854 8182765 8187288 8261976 + * @bug 4927167 4974929 6381729 7010344 8025633 8081854 8182765 8187288 8261976 8313931 * @summary When the type parameters are more than 10 characters in length, * make sure there is a line break between type params and return type * in member summary. Also, test for type parameter links in package-summary and @@ -110,10 +110,22 @@ public void test3() {
 <T extends java.lang.Runnable>
-
 
""", +
+
Generic constructor.
""", """
public\  <T extends java.lang.Runnable>\ -  CtorTypeParam()
"""); +  CtorTypeParam()
""", + """ + T""", + """ +
Type Parameters:
+
T - the type parameter
""", + """ +
See Also:
+
+ """); } } diff --git a/test/langtools/jdk/javadoc/doclet/testTypeParams/pkg/CtorTypeParam.java b/test/langtools/jdk/javadoc/doclet/testTypeParams/pkg/CtorTypeParam.java index a7f2309475d..690471861db 100644 --- a/test/langtools/jdk/javadoc/doclet/testTypeParams/pkg/CtorTypeParam.java +++ b/test/langtools/jdk/javadoc/doclet/testTypeParams/pkg/CtorTypeParam.java @@ -24,6 +24,12 @@ package pkg; public class CtorTypeParam { + /** + * Generic constructor. {@link T} + * + * @param the type parameter + * @see T link to type parameter + */ public CtorTypeParam() { } } diff --git a/test/langtools/jdk/javadoc/doclet/testUnicode/TestUnicode.java b/test/langtools/jdk/javadoc/doclet/testUnicode/TestUnicode.java index 76008260343..cf30488ec7b 100644 --- a/test/langtools/jdk/javadoc/doclet/testUnicode/TestUnicode.java +++ b/test/langtools/jdk/javadoc/doclet/testUnicode/TestUnicode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -101,7 +101,7 @@ public class Code<##> { """
Type Parameters:
-
## - the ##
+
## - the ##
""".replaceAll("##", chineseElephant), """ From 2b5aec2aad3883d4d407ec3a572f78755d60190d Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Fri, 9 Aug 2024 11:28:59 +0000 Subject: [PATCH 364/460] 8338109: java/awt/Mouse/EnterExitEvents/ResizingFrameTest.java duplicate in ProblemList Reviewed-by: aivanov --- test/jdk/ProblemList.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 293d9d108d3..6cde7111383 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -375,7 +375,7 @@ java/awt/Modal/MultipleDialogs/MultipleDialogs3Test.java 8198665 macosx-all java/awt/Modal/MultipleDialogs/MultipleDialogs4Test.java 8198665 macosx-all java/awt/Modal/MultipleDialogs/MultipleDialogs5Test.java 8198665 macosx-all java/awt/Mouse/EnterExitEvents/DragWindowOutOfFrameTest.java 8177326 macosx-all -java/awt/Mouse/EnterExitEvents/ResizingFrameTest.java 8005021 macosx-all +java/awt/Mouse/EnterExitEvents/ResizingFrameTest.java 8005021,8332158 macosx-all,linux-x64 java/awt/Mouse/EnterExitEvents/FullscreenEnterEventTest.java 8051455 macosx-all java/awt/Mouse/MouseModifiersUnitTest/MouseModifiersUnitTest_Standard.java 7124407,8302787 macosx-all,windows-all java/awt/Mouse/RemovedComponentMouseListener/RemovedComponentMouseListener.java 8157170 macosx-all @@ -475,7 +475,6 @@ java/awt/Choice/SelectNewItemTest/SelectNewItemTest.java 8324782 macosx-all # Wayland related -java/awt/Mouse/EnterExitEvents/ResizingFrameTest.java 8332158 linux-x64 java/awt/FullScreen/FullscreenWindowProps/FullscreenWindowProps.java 8280991 linux-x64 java/awt/FullScreen/SetFullScreenTest.java 8332155 linux-x64 From 069e0ea69f43960164d3e077d2c7b950cde77927 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Fri, 9 Aug 2024 12:00:15 +0000 Subject: [PATCH 365/460] 8338064: Give better error for ConcurrentHashTable corruption Reviewed-by: dholmes, shade --- .../share/utilities/concurrentHashTable.hpp | 5 ++ .../utilities/concurrentHashTable.inline.hpp | 6 +- .../StringTableCorruptionTest.java | 59 +++++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 test/hotspot/jtreg/runtime/stringtable/StringTableCorruptionTest.java diff --git a/src/hotspot/share/utilities/concurrentHashTable.hpp b/src/hotspot/share/utilities/concurrentHashTable.hpp index 991ea9fe3c6..4e506d5fe84 100644 --- a/src/hotspot/share/utilities/concurrentHashTable.hpp +++ b/src/hotspot/share/utilities/concurrentHashTable.hpp @@ -65,6 +65,7 @@ class ConcurrentHashTable : public CHeapObj { // the InternalTable or user-defined memory. class Node { private: + DEBUG_ONLY(size_t _saved_hash); Node * volatile _next; VALUE _value; public: @@ -77,6 +78,10 @@ class ConcurrentHashTable : public CHeapObj { Node* next() const; void set_next(Node* node) { _next = node; } Node* const volatile * next_ptr() { return &_next; } +#ifdef ASSERT + size_t saved_hash() const { return _saved_hash; } + void set_saved_hash(size_t hash) { _saved_hash = hash; } +#endif VALUE* value() { return &_value; } diff --git a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp index 78c7e148bbb..f035aeae448 100644 --- a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp +++ b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp @@ -679,7 +679,9 @@ inline bool ConcurrentHashTable:: // Keep in odd list odd = aux->next_ptr(); } else { - fatal("aux_index does not match even or odd indices"); + const char* msg = "Cannot resize table: Node hash code has changed possibly due to corruption of the contents."; + DEBUG_ONLY(fatal("%s Node hash code changed from " SIZE_FORMAT " to " SIZE_FORMAT, msg, aux->saved_hash(), aux_hash);) + NOT_DEBUG(fatal("%s", msg);) } } aux = aux_next; @@ -892,6 +894,7 @@ inline bool ConcurrentHashTable:: size_t i = 0; uintx hash = lookup_f.get_hash(); Node* new_node = Node::create_node(_context, value, nullptr); + DEBUG_ONLY(new_node->set_saved_hash(hash);) while (true) { { @@ -1117,6 +1120,7 @@ inline bool ConcurrentHashTable:: Bucket* bucket = get_bucket_in(table, hash); assert(!bucket->have_redirect() && !bucket->is_locked(), "bad"); Node* new_node = Node::create_node(_context, value, bucket->first()); + DEBUG_ONLY(new_node->set_saved_hash(hash);) if (!bucket->cas_first(new_node, bucket->first())) { assert(false, "bad"); } diff --git a/test/hotspot/jtreg/runtime/stringtable/StringTableCorruptionTest.java b/test/hotspot/jtreg/runtime/stringtable/StringTableCorruptionTest.java new file mode 100644 index 00000000000..e4d6a2e5d0f --- /dev/null +++ b/test/hotspot/jtreg/runtime/stringtable/StringTableCorruptionTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8333356 + * @summary Verify new error message for corrupting string table contents. + * @requires vm.flagless + * @modules java.base/java.lang:open + * @library /test/lib + * @modules java.base/jdk.internal.misc + * @run driver StringTableCorruptionTest test + */ + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class StringTableCorruptionTest { + public static void main(String[] args) throws Exception { + if (args.length > 0) { + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("--add-opens", "java.base/java.lang=ALL-UNNAMED", + "-XX:-CreateCoredumpOnCrash", "StringTableCorruptionTest"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("Node hash code has changed possibly due to corruption of the contents."); + output.shouldNotHaveExitValue(0); + return; + } + + Field f = String.class.getDeclaredField("value"); + f.setAccessible(true); + f.set("s1".intern(), f.get("s2")); + for (int i = 0; i < 4_000_000; i++) { + ("s_" + i).intern(); + } + } +} From 3cf3f300de1e9d2c8767877ed3a26679e34b7d22 Mon Sep 17 00:00:00 2001 From: Casper Norrbin Date: Fri, 9 Aug 2024 14:32:29 +0000 Subject: [PATCH 366/460] 8330191: Fix typo in precompiled.hpp Reviewed-by: jsjolen, szaldana --- src/hotspot/share/precompiled/precompiled.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/precompiled/precompiled.hpp b/src/hotspot/share/precompiled/precompiled.hpp index c53a78de87b..07922d12969 100644 --- a/src/hotspot/share/precompiled/precompiled.hpp +++ b/src/hotspot/share/precompiled/precompiled.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,7 @@ // These header files are included in at least 130 C++ files, as of // measurements made in November 2018. This list excludes files named -// *.include.hpp, since including them decreased build performance. +// *.inline.hpp, since including them decreased build performance. #include "classfile/classLoaderData.hpp" #include "classfile/javaClasses.hpp" From 60fa08fcfe5c6551ee3120330ade93e45df618c7 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Fri, 9 Aug 2024 17:08:19 +0000 Subject: [PATCH 367/460] 8337797: Additional ExternalAddress cleanup Reviewed-by: adinn, thartmann --- src/hotspot/cpu/aarch64/jniFastGetField_aarch64.cpp | 4 ++-- src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp | 9 ++------- src/hotspot/cpu/x86/assembler_x86.cpp | 1 + src/hotspot/cpu/x86/jniFastGetField_x86_32.cpp | 8 ++++---- src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp | 6 +++--- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 4 ++-- src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp | 4 ++-- src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp | 4 ++-- src/hotspot/cpu/x86/stubGenerator_x86_64_arraycopy.cpp | 2 +- src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp | 4 ++-- 10 files changed, 21 insertions(+), 25 deletions(-) diff --git a/src/hotspot/cpu/aarch64/jniFastGetField_aarch64.cpp b/src/hotspot/cpu/aarch64/jniFastGetField_aarch64.cpp index e79b93651b0..aea268ea944 100644 --- a/src/hotspot/cpu/aarch64/jniFastGetField_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/jniFastGetField_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -201,7 +201,7 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { { __ enter(); - __ lea(rscratch1, ExternalAddress(slow_case_addr)); + __ lea(rscratch1, RuntimeAddress(slow_case_addr)); __ blr(rscratch1); __ leave(); __ ret(lr); diff --git a/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp b/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp index 8423ecad8a3..f7d702c6310 100644 --- a/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp +++ b/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -173,12 +173,7 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { { __ enter(); - ExternalAddress target(slow_case_addr); - __ relocate(target.rspec(), [&] { - int32_t offset; - __ la(t0, target.target(), offset); - __ jalr(t0, offset); - }); + __ rt_call(slow_case_addr); __ leave(); __ ret(); } diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp index 001ff472f40..207d3fbb61e 100644 --- a/src/hotspot/cpu/x86/assembler_x86.cpp +++ b/src/hotspot/cpu/x86/assembler_x86.cpp @@ -1780,6 +1780,7 @@ void Assembler::call(Register dst) { void Assembler::call(Address adr) { + assert(!adr._rspec.reloc()->is_data(), "should not use ExternalAddress for call"); InstructionMark im(this); prefix(adr); emit_int8((unsigned char)0xFF); diff --git a/src/hotspot/cpu/x86/jniFastGetField_x86_32.cpp b/src/hotspot/cpu/x86/jniFastGetField_x86_32.cpp index 34be2a61b5a..52e4388c5d2 100644 --- a/src/hotspot/cpu/x86/jniFastGetField_x86_32.cpp +++ b/src/hotspot/cpu/x86/jniFastGetField_x86_32.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -138,7 +138,7 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { default: ShouldNotReachHere(); } // tail call - __ jump (ExternalAddress(slow_case_addr)); + __ jump (RuntimeAddress(slow_case_addr)); __ flush (); @@ -251,7 +251,7 @@ address JNI_FastGetField::generate_fast_get_long_field() { __ pop (rsi); address slow_case_addr = jni_GetLongField_addr();; // tail call - __ jump (ExternalAddress(slow_case_addr)); + __ jump (RuntimeAddress(slow_case_addr)); __ flush (); @@ -350,7 +350,7 @@ address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) { default: ShouldNotReachHere(); } // tail call - __ jump (ExternalAddress(slow_case_addr)); + __ jump (RuntimeAddress(slow_case_addr)); __ flush (); diff --git a/src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp b/src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp index 4506205c259..e94b7d12b0b 100644 --- a/src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp +++ b/src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -118,7 +118,7 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { default: break; } // tail call - __ jump (ExternalAddress(slow_case_addr), rscratch1); + __ jump (RuntimeAddress(slow_case_addr), rscratch1); __ flush (); @@ -206,7 +206,7 @@ address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) { default: break; } // tail call - __ jump (ExternalAddress(slow_case_addr), rscratch1); + __ jump (RuntimeAddress(slow_case_addr), rscratch1); __ flush (); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index affd18f937c..c8234d6b9b8 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -2329,7 +2329,7 @@ void MacroAssembler::incrementl(Address dst, int value) { void MacroAssembler::jump(AddressLiteral dst, Register rscratch) { assert(rscratch != noreg || always_reachable(dst), "missing"); - + assert(!dst.rspec().reloc()->is_data(), "should not use ExternalAddress for jump"); if (reachable(dst)) { jmp_literal(dst.target(), dst.rspec()); } else { @@ -2340,7 +2340,7 @@ void MacroAssembler::jump(AddressLiteral dst, Register rscratch) { void MacroAssembler::jump_cc(Condition cc, AddressLiteral dst, Register rscratch) { assert(rscratch != noreg || always_reachable(dst), "missing"); - + assert(!dst.rspec().reloc()->is_data(), "should not use ExternalAddress for jump_cc"); if (reachable(dst)) { InstructionMark im(this); relocate(dst.reloc()); diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp index 80be7c7d5b6..d313c1b216a 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp @@ -704,10 +704,10 @@ static void range_check(MacroAssembler* masm, Register pc_reg, Register temp_reg address code_start, address code_end, Label& L_ok) { Label L_fail; - __ lea(temp_reg, ExternalAddress(code_start)); + __ lea(temp_reg, AddressLiteral(code_start, relocInfo::none)); __ cmpptr(pc_reg, temp_reg); __ jcc(Assembler::belowEqual, L_fail); - __ lea(temp_reg, ExternalAddress(code_end)); + __ lea(temp_reg, AddressLiteral(code_end, relocInfo::none)); __ cmpptr(pc_reg, temp_reg); __ jcc(Assembler::below, L_ok); __ bind(L_fail); diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index f2488ef4e74..d27b1d141fc 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -824,10 +824,10 @@ static void range_check(MacroAssembler* masm, Register pc_reg, Register temp_reg address code_start, address code_end, Label& L_ok) { Label L_fail; - __ lea(temp_reg, ExternalAddress(code_start)); + __ lea(temp_reg, AddressLiteral(code_start, relocInfo::none)); __ cmpptr(pc_reg, temp_reg); __ jcc(Assembler::belowEqual, L_fail); - __ lea(temp_reg, ExternalAddress(code_end)); + __ lea(temp_reg, AddressLiteral(code_end, relocInfo::none)); __ cmpptr(pc_reg, temp_reg); __ jcc(Assembler::below, L_ok); __ bind(L_fail); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_arraycopy.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_arraycopy.cpp index d8f7a6b272b..5b316881d03 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_arraycopy.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_arraycopy.cpp @@ -215,7 +215,7 @@ void StubGenerator::array_overlap_test(address no_overlap_target, Label* NOLp, A __ cmpptr(to, from); __ lea(end_from, Address(from, count, sf, 0)); if (NOLp == nullptr) { - ExternalAddress no_overlap(no_overlap_target); + RuntimeAddress no_overlap(no_overlap_target); __ jump_cc(Assembler::belowEqual, no_overlap); __ cmpptr(to, end_from); __ jump_cc(Assembler::aboveEqual, no_overlap); diff --git a/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp b/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp index 7e0814c014b..62022d780a2 100644 --- a/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp +++ b/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -180,7 +180,7 @@ bool os::win32::register_code_area(char *low, char *high) { MacroAssembler* masm = new MacroAssembler(&cb); pDCD = (pDynamicCodeData) masm->pc(); - masm->jump(ExternalAddress((address)&HandleExceptionFromCodeCache), rscratch1); + masm->jump(RuntimeAddress((address)&HandleExceptionFromCodeCache), rscratch1); masm->flush(); // Create an Unwind Structure specifying no unwind info From 358d77dafbe0e35d5b20340fccddc0fb8f3db82a Mon Sep 17 00:00:00 2001 From: Dmitry Chuyko Date: Fri, 9 Aug 2024 17:56:37 +0000 Subject: [PATCH 368/460] 8337657: AArch64: No need for acquire fence in safepoint poll during JNI calls Reviewed-by: phh --- src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp | 12 ++---------- .../aarch64/templateInterpreterGenerator_aarch64.cpp | 11 ++--------- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index 65c026b95ab..8ce4230baa2 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -1883,16 +1883,8 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Check for safepoint operation in progress and/or pending suspend requests. { - // We need an acquire here to ensure that any subsequent load of the - // global SafepointSynchronize::_state flag is ordered after this load - // of the thread-local polling word. We don't want this poll to - // return false (i.e. not safepointing) and a later poll of the global - // SafepointSynchronize::_state spuriously to return true. - // - // This is to avoid a race when we're in a native->Java transition - // racing the code which wakes up from a safepoint. - - __ safepoint_poll(safepoint_in_progress, true /* at_return */, true /* acquire */, false /* in_nmethod */); + // No need for acquire as Java threads always disarm themselves. + __ safepoint_poll(safepoint_in_progress, true /* at_return */, false /* acquire */, false /* in_nmethod */); __ ldrw(rscratch1, Address(rthread, JavaThread::suspend_flags_offset())); __ cbnzw(rscratch1, safepoint_in_progress); __ bind(safepoint_in_progress_done); diff --git a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp index d639d9cf17e..ed2450a9110 100644 --- a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp @@ -1413,15 +1413,8 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { { Label L, Continue; - // We need an acquire here to ensure that any subsequent load of the - // global SafepointSynchronize::_state flag is ordered after this load - // of the thread-local polling word. We don't want this poll to - // return false (i.e. not safepointing) and a later poll of the global - // SafepointSynchronize::_state spuriously to return true. - // - // This is to avoid a race when we're in a native->Java transition - // racing the code which wakes up from a safepoint. - __ safepoint_poll(L, true /* at_return */, true /* acquire */, false /* in_nmethod */); + // No need for acquire as Java threads always disarm themselves. + __ safepoint_poll(L, true /* at_return */, false /* acquire */, false /* in_nmethod */); __ ldrw(rscratch2, Address(rthread, JavaThread::suspend_flags_offset())); __ cbz(rscratch2, Continue); __ bind(L); From 6a3d045221c338fefec9bd59245324eae60b156b Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Sun, 11 Aug 2024 18:34:18 +0000 Subject: [PATCH 369/460] 8337709: Use allocated states for chunking large array processing Reviewed-by: iwalulya, tschatzl --- .../share/gc/g1/g1ParScanThreadState.cpp | 90 +++++++---- .../share/gc/g1/g1ParScanThreadState.hpp | 12 +- .../share/gc/shared/partialArrayState.cpp | 152 ++++++++++++++++++ .../share/gc/shared/partialArrayState.hpp | 136 ++++++++++++++++ .../gc/shared/partialArrayTaskStepper.cpp | 6 +- .../gc/shared/partialArrayTaskStepper.hpp | 59 ++++--- .../shared/partialArrayTaskStepper.inline.hpp | 71 +++----- src/hotspot/share/gc/shared/taskqueue.hpp | 21 ++- .../shared/test_partialArrayTaskStepper.cpp | 42 ++--- 9 files changed, 444 insertions(+), 145 deletions(-) create mode 100644 src/hotspot/share/gc/shared/partialArrayState.cpp create mode 100644 src/hotspot/share/gc/shared/partialArrayState.hpp diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp index e4ac20ca7ea..f81c3241a1a 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp @@ -35,6 +35,7 @@ #include "gc/g1/g1Trace.hpp" #include "gc/g1/g1YoungGCAllocationFailureInjector.inline.hpp" #include "gc/shared/continuationGCSupport.inline.hpp" +#include "gc/shared/partialArrayState.hpp" #include "gc/shared/partialArrayTaskStepper.inline.hpp" #include "gc/shared/preservedMarks.inline.hpp" #include "gc/shared/stringdedup/stringDedup.hpp" @@ -43,6 +44,7 @@ #include "oops/access.inline.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.hpp" +#include "runtime/mutexLocker.hpp" #include "runtime/prefetch.inline.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" @@ -61,7 +63,8 @@ G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h, uint worker_id, uint num_workers, G1CollectionSet* collection_set, - G1EvacFailureRegions* evac_failure_regions) + G1EvacFailureRegions* evac_failure_regions, + PartialArrayStateAllocator* pas_allocator) : _g1h(g1h), _task_queue(g1h->task_queue(worker_id)), _rdc_local_qset(rdcqs), @@ -80,8 +83,8 @@ G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h, _surviving_young_words(nullptr), _surviving_words_length(collection_set->young_region_length() + 1), _old_gen_is_full(false), - _partial_objarray_chunk_size(ParGCArrayScanChunk), - _partial_array_stepper(num_workers), + _partial_array_state_allocator(pas_allocator), + _partial_array_stepper(num_workers, ParGCArrayScanChunk), _string_dedup_requests(), _max_num_optional_regions(collection_set->optional_region_length()), _numa(g1h->numa()), @@ -169,9 +172,9 @@ void G1ParScanThreadState::verify_task(oop* task) const { "task=" PTR_FORMAT " p=" PTR_FORMAT, p2i(task), p2i(p)); } -void G1ParScanThreadState::verify_task(PartialArrayScanTask task) const { +void G1ParScanThreadState::verify_task(PartialArrayState* task) const { // Must be in the collection set--it's already been copied. - oop p = task.to_source_array(); + oop p = task->source(); assert(_g1h->is_in_cset(p), "p=" PTR_FORMAT, p2i(p)); } @@ -180,8 +183,8 @@ void G1ParScanThreadState::verify_task(ScannerTask task) const { verify_task(task.to_narrow_oop_ptr()); } else if (task.is_oop_ptr()) { verify_task(task.to_oop_ptr()); - } else if (task.is_partial_array_task()) { - verify_task(task.to_partial_array_task()); + } else if (task.is_partial_array_state()) { + verify_task(task.to_partial_array_state()); } else { ShouldNotReachHere(); } @@ -223,34 +226,39 @@ void G1ParScanThreadState::do_oop_evac(T* p) { } MAYBE_INLINE_EVACUATION -void G1ParScanThreadState::do_partial_array(PartialArrayScanTask task) { - oop from_obj = task.to_source_array(); +void G1ParScanThreadState::do_partial_array(PartialArrayState* state) { + oop to_obj = state->destination(); +#ifdef ASSERT + oop from_obj = state->source(); assert(_g1h->is_in_reserved(from_obj), "must be in heap."); assert(from_obj->is_objArray(), "must be obj array"); assert(from_obj->is_forwarded(), "must be forwarded"); - - oop to_obj = from_obj->forwardee(); assert(from_obj != to_obj, "should not be chunking self-forwarded objects"); assert(to_obj->is_objArray(), "must be obj array"); +#endif // ASSERT + objArrayOop to_array = objArrayOop(to_obj); - PartialArrayTaskStepper::Step step - = _partial_array_stepper.next(objArrayOop(from_obj), - to_array, - _partial_objarray_chunk_size); - for (uint i = 0; i < step._ncreate; ++i) { - push_on_queue(ScannerTask(PartialArrayScanTask(from_obj))); + // Claim a chunk and get number of additional tasks to enqueue. + PartialArrayTaskStepper::Step step = _partial_array_stepper.next(state); + // Push any additional partial scan tasks needed. Pushed before processing + // the claimed chunk to allow other workers to steal while we're processing. + if (step._ncreate > 0) { + state->add_references(step._ncreate); + for (uint i = 0; i < step._ncreate; ++i) { + push_on_queue(ScannerTask(state)); + } } G1HeapRegionAttr dest_attr = _g1h->region_attr(to_array); G1SkipCardEnqueueSetter x(&_scanner, dest_attr.is_new_survivor()); - // Process claimed task. The length of to_array is not correct, but - // fortunately the iteration ignores the length field and just relies - // on start/end. + // Process claimed task. to_array->oop_iterate_range(&_scanner, - step._index, - step._index + _partial_objarray_chunk_size); + checked_cast(step._index), + checked_cast(step._index + _partial_array_stepper.chunk_size())); + // Release reference to the state, now that we're done with it. + _partial_array_state_allocator->release(_worker_id, state); } MAYBE_INLINE_EVACUATION @@ -260,20 +268,30 @@ void G1ParScanThreadState::start_partial_objarray(G1HeapRegionAttr dest_attr, assert(from_obj->is_objArray(), "precondition"); assert(from_obj->is_forwarded(), "precondition"); assert(from_obj->forwardee() == to_obj, "precondition"); - assert(from_obj != to_obj, "should not be scanning self-forwarded objects"); assert(to_obj->is_objArray(), "precondition"); objArrayOop to_array = objArrayOop(to_obj); - PartialArrayTaskStepper::Step step - = _partial_array_stepper.start(objArrayOop(from_obj), - to_array, - _partial_objarray_chunk_size); + size_t array_length = to_array->length(); + PartialArrayTaskStepper::Step step = _partial_array_stepper.start(array_length); // Push any needed partial scan tasks. Pushed before processing the // initial chunk to allow other workers to steal while we're processing. - for (uint i = 0; i < step._ncreate; ++i) { - push_on_queue(ScannerTask(PartialArrayScanTask(from_obj))); + if (step._ncreate > 0) { + assert(step._index < array_length, "invariant"); + assert(((array_length - step._index) % _partial_array_stepper.chunk_size()) == 0, + "invariant"); + PartialArrayState* state = + _partial_array_state_allocator->allocate(_worker_id, + from_obj, to_obj, + step._index, + array_length, + step._ncreate); + for (uint i = 0; i < step._ncreate; ++i) { + push_on_queue(ScannerTask(state)); + } + } else { + assert(step._index == array_length, "invariant"); } // Skip the card enqueue iff the object (to_array) is in survivor region. @@ -284,9 +302,8 @@ void G1ParScanThreadState::start_partial_objarray(G1HeapRegionAttr dest_attr, G1SkipCardEnqueueSetter x(&_scanner, dest_attr.is_young()); // Process the initial chunk. No need to process the type in the // klass, as it will already be handled by processing the built-in - // module. The length of to_array is not correct, but fortunately - // the iteration ignores that length field and relies on start/end. - to_array->oop_iterate_range(&_scanner, 0, step._index); + // module. + to_array->oop_iterate_range(&_scanner, 0, checked_cast(step._index)); } MAYBE_INLINE_EVACUATION @@ -297,7 +314,7 @@ void G1ParScanThreadState::dispatch_task(ScannerTask task) { } else if (task.is_oop_ptr()) { do_oop_evac(task.to_oop_ptr()); } else { - do_partial_array(task.to_partial_array_task()); + do_partial_array(task.to_partial_array_state()); } } @@ -582,7 +599,8 @@ G1ParScanThreadState* G1ParScanThreadStateSet::state_for_worker(uint worker_id) worker_id, _num_workers, _collection_set, - _evac_failure_regions); + _evac_failure_regions, + &_partial_array_state_allocator); } return _states[worker_id]; } @@ -715,7 +733,9 @@ G1ParScanThreadStateSet::G1ParScanThreadStateSet(G1CollectedHeap* g1h, _surviving_young_words_total(NEW_C_HEAP_ARRAY(size_t, collection_set->young_region_length() + 1, mtGC)), _num_workers(num_workers), _flushed(false), - _evac_failure_regions(evac_failure_regions) { + _evac_failure_regions(evac_failure_regions), + _partial_array_state_allocator(num_workers) +{ _preserved_marks_set.init(num_workers); for (uint i = 0; i < num_workers; ++i) { _states[i] = nullptr; diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp index 24ca682e141..1cfd6fca08a 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp @@ -32,6 +32,7 @@ #include "gc/shared/ageTable.hpp" #include "gc/shared/copyFailedInfo.hpp" #include "gc/shared/gc_globals.hpp" +#include "gc/shared/partialArrayState.hpp" #include "gc/shared/partialArrayTaskStepper.hpp" #include "gc/shared/preservedMarks.hpp" #include "gc/shared/stringdedup/stringDedup.hpp" @@ -87,7 +88,8 @@ class G1ParScanThreadState : public CHeapObj { // available for allocation. bool _old_gen_is_full; // Size (in elements) of a partial objArray task chunk. - int _partial_objarray_chunk_size; + size_t _partial_objarray_chunk_size; + PartialArrayStateAllocator* _partial_array_state_allocator; PartialArrayTaskStepper _partial_array_stepper; StringDedup::Requests _string_dedup_requests; @@ -129,7 +131,8 @@ class G1ParScanThreadState : public CHeapObj { uint worker_id, uint num_workers, G1CollectionSet* collection_set, - G1EvacFailureRegions* evac_failure_regions); + G1EvacFailureRegions* evac_failure_regions, + PartialArrayStateAllocator* partial_array_state_allocator); virtual ~G1ParScanThreadState(); void set_ref_discoverer(ReferenceDiscoverer* rd) { _scanner.set_ref_discoverer(rd); } @@ -140,7 +143,7 @@ class G1ParScanThreadState : public CHeapObj { void verify_task(narrowOop* task) const NOT_DEBUG_RETURN; void verify_task(oop* task) const NOT_DEBUG_RETURN; - void verify_task(PartialArrayScanTask task) const NOT_DEBUG_RETURN; + void verify_task(PartialArrayState* task) const NOT_DEBUG_RETURN; void verify_task(ScannerTask task) const NOT_DEBUG_RETURN; void push_on_queue(ScannerTask task); @@ -169,7 +172,7 @@ class G1ParScanThreadState : public CHeapObj { size_t flush_stats(size_t* surviving_young_words, uint num_workers, BufferNodeList* buffer_log); private: - void do_partial_array(PartialArrayScanTask task); + void do_partial_array(PartialArrayState* state); void start_partial_objarray(G1HeapRegionAttr dest_dir, oop from, oop to); HeapWord* allocate_copy_slow(G1HeapRegionAttr* dest_attr, @@ -252,6 +255,7 @@ class G1ParScanThreadStateSet : public StackObj { uint _num_workers; bool _flushed; G1EvacFailureRegions* _evac_failure_regions; + PartialArrayStateAllocator _partial_array_state_allocator; public: G1ParScanThreadStateSet(G1CollectedHeap* g1h, diff --git a/src/hotspot/share/gc/shared/partialArrayState.cpp b/src/hotspot/share/gc/shared/partialArrayState.cpp new file mode 100644 index 00000000000..583c5dede40 --- /dev/null +++ b/src/hotspot/share/gc/shared/partialArrayState.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "gc/shared/partialArrayState.hpp" +#include "memory/allocation.inline.hpp" +#include "memory/arena.hpp" +#include "nmt/memflags.hpp" +#include "oops/oopsHierarchy.hpp" +#include "runtime/atomic.hpp" +#include "runtime/orderAccess.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" +#include + +PartialArrayState::PartialArrayState(oop src, oop dst, + size_t index, size_t length, + size_t initial_refcount) + : _source(src), + _destination(dst), + _length(length), + _index(index), + _refcount(initial_refcount) +{ + assert(index <= length, "precondition"); +} + +void PartialArrayState::add_references(size_t count) { + size_t new_count = Atomic::add(&_refcount, count, memory_order_relaxed); + assert(new_count >= count, "reference count overflow"); +} + +class PartialArrayStateAllocator::Impl : public CHeapObj { + struct FreeListEntry; + + Arena* _arenas; + FreeListEntry** _free_lists; + uint _num_workers; + +public: + Impl(uint num_workers); + ~Impl(); + + NONCOPYABLE(Impl); + + PartialArrayState* allocate(uint worker_id, + oop src, oop dst, + size_t index, size_t length, + size_t initial_refcount); + void release(uint worker_id, PartialArrayState* state); +}; + +struct PartialArrayStateAllocator::Impl::FreeListEntry { + FreeListEntry* _next; + + FreeListEntry(FreeListEntry* next) : _next(next) {} + ~FreeListEntry() = default; + + NONCOPYABLE(FreeListEntry); +}; + +PartialArrayStateAllocator::Impl::Impl(uint num_workers) + : _arenas(NEW_C_HEAP_ARRAY(Arena, num_workers, mtGC)), + _free_lists(NEW_C_HEAP_ARRAY(FreeListEntry*, num_workers, mtGC)), + _num_workers(num_workers) +{ + for (uint i = 0; i < _num_workers; ++i) { + ::new (&_arenas[i]) Arena(mtGC); + _free_lists[i] = nullptr; + } +} + +PartialArrayStateAllocator::Impl::~Impl() { + // We don't need to clean up the free lists. Deallocating the entries + // does nothing, since we're using arena allocation. Instead, leave it + // to the arena destructor to release the memory. + FREE_C_HEAP_ARRAY(FreeListEntry*, _free_lists); + for (uint i = 0; i < _num_workers; ++i) { + _arenas[i].~Arena(); + } +} + +PartialArrayState* PartialArrayStateAllocator::Impl::allocate(uint worker_id, + oop src, oop dst, + size_t index, + size_t length, + size_t initial_refcount) { + void* p; + FreeListEntry* head = _free_lists[worker_id]; + if (head == nullptr) { + p = NEW_ARENA_OBJ(&_arenas[worker_id], PartialArrayState); + } else { + _free_lists[worker_id] = head->_next; + head->~FreeListEntry(); + p = head; + } + return ::new (p) PartialArrayState(src, dst, index, length, initial_refcount); +} + +void PartialArrayStateAllocator::Impl::release(uint worker_id, PartialArrayState* state) { + size_t refcount = Atomic::sub(&state->_refcount, size_t(1), memory_order_release); + if (refcount != 0) { + assert(refcount + 1 != 0, "refcount underflow"); + } else { + OrderAccess::acquire(); + state->~PartialArrayState(); + _free_lists[worker_id] = ::new (state) FreeListEntry(_free_lists[worker_id]); + } +} + +PartialArrayStateAllocator::PartialArrayStateAllocator(uint num_workers) + : _impl(new Impl(num_workers)) +{} + +PartialArrayStateAllocator::~PartialArrayStateAllocator() { + delete _impl; +} + +PartialArrayState* PartialArrayStateAllocator::allocate(uint worker_id, + oop src, oop dst, + size_t index, + size_t length, + size_t initial_refcount) { + return _impl->allocate(worker_id, src, dst, index, length, initial_refcount); +} + +void PartialArrayStateAllocator::release(uint worker_id, PartialArrayState* state) { + _impl->release(worker_id, state); +} + diff --git a/src/hotspot/share/gc/shared/partialArrayState.hpp b/src/hotspot/share/gc/shared/partialArrayState.hpp new file mode 100644 index 00000000000..f3bfc3ed8b8 --- /dev/null +++ b/src/hotspot/share/gc/shared/partialArrayState.hpp @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_SHARED_PARTIALARRAYSTATE_HPP +#define SHARE_GC_SHARED_PARTIALARRAYSTATE_HPP + +#include "oops/oopsHierarchy.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" + +class PartialArrayStateAllocator; + +// Instances of this class are used to represent processing progress for an +// array task in a taskqueue. When a sufficiently large array needs to be +// processed, such that it is desirable to split up the processing into +// parallelizable subtasks, a state object is allocated for the array. +// Multiple tasks referring to the state can then be added to the taskqueue +// for later processing, either by the current thread or by some other thread +// that steals one of those tasks. +// +// Processing a state involves using the state to claim a segment of the +// array, and processing that segment. Claiming is done by atomically +// incrementing the index, thereby claiming the segment from the old to new +// index values. New tasks should also be added as needed to ensure the +// entire array will be processed. A PartialArrayTaskStepper can be used to +// help with this. +// +// States are allocated and released using a PartialArrayStateAllocator. +// States are reference counted to aid in that management. Each task +// referring to a given state that is added to a taskqueue must increase the +// reference count by one. When the processing of a task referring to a state +// is complete, the reference count must be decreased by one. When the +// reference count reaches zero the state should be released to the allocator +// for later reuse. +class PartialArrayState { + oop _source; + oop _destination; + size_t _length; + volatile size_t _index; + volatile size_t _refcount; + + friend class PartialArrayStateAllocator; + + PartialArrayState(oop src, oop dst, + size_t index, size_t length, + size_t initial_refcount); + ~PartialArrayState() = default; + + NONCOPYABLE(PartialArrayState); + +public: + // Add count references, one per referring task being added to a taskqueue. + void add_references(size_t count); + + // The source array oop. + oop source() const { return _source; } + + // The destination array oop. In some circumstances the source and + // destination may be the same. + oop destination() const { return _destination; } + + // The length of the array oop. + size_t length() const { return _length; } + + // A pointer to the start index for the next segment to process, for atomic + // update. + volatile size_t* index_addr() { return &_index; } +}; + +// This class provides memory management for PartialArrayStates. +// +// States are initially allocated from a set of arenas owned by the allocator. +// This allows the entire set of allocated states to be discarded without the +// need to keep track of or find them under some circumstances. For example, +// if G1 concurrent marking is aborted and needs to restart because of a full +// marking queue, the queue doesn't need to be searched for tasks referring to +// states to allow releasing them. Instead the queue contents can just be +// discarded, and the memory for the no longer referenced states will +// eventually be reclaimed when the arenas are reset. +// +// A set of free-lists is placed in front of the arena allocators. This +// causes the maximum number of allocated states to be based on the number of +// in-progress arrays, rather than the total number of arrays that need to be +// processed. The use of free-list allocators is the reason for reference +// counting states. +// +// The arena and free-list to use for an allocation operation is designated by +// the worker_id used in the operation. This avoids locking and such on those +// data structures, at the cost of possibly doing more total arena allocation +// that would be needed with a single shared arena and free-list. +class PartialArrayStateAllocator { + class Impl; + Impl* _impl; + +public: + PartialArrayStateAllocator(uint num_workers); + ~PartialArrayStateAllocator(); + + NONCOPYABLE(PartialArrayStateAllocator); + + // Create a new state, obtaining the memory for it from the free-list or + // arena associated with worker_id. + PartialArrayState* allocate(uint worker_id, + oop src, oop dst, + size_t index, size_t length, + size_t initial_refcount); + + // Decrement the state's refcount. If the new refcount is zero, add the + // state to the free-list associated with worker_id. The state must have + // been allocated by this allocator, but that allocation doesn't need to + // have been associated with worker_id. + void release(uint worker_id, PartialArrayState* state); +}; + +#endif // SHARE_GC_SHARED_PARTIALARRAYSTATE_HPP diff --git a/src/hotspot/share/gc/shared/partialArrayTaskStepper.cpp b/src/hotspot/share/gc/shared/partialArrayTaskStepper.cpp index ed52d7abff1..6faa162ac7b 100644 --- a/src/hotspot/share/gc/shared/partialArrayTaskStepper.cpp +++ b/src/hotspot/share/gc/shared/partialArrayTaskStepper.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "gc/shared/partialArrayTaskStepper.hpp" #include "oops/arrayOop.hpp" +#include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/powerOfTwo.hpp" @@ -48,7 +49,8 @@ static uint compute_task_fanout(uint task_limit) { return result; } -PartialArrayTaskStepper::PartialArrayTaskStepper(uint n_workers) : +PartialArrayTaskStepper::PartialArrayTaskStepper(uint n_workers, size_t chunk_size) : + _chunk_size(chunk_size), _task_limit(compute_task_limit(n_workers)), _task_fanout(compute_task_fanout(_task_limit)) {} diff --git a/src/hotspot/share/gc/shared/partialArrayTaskStepper.hpp b/src/hotspot/share/gc/shared/partialArrayTaskStepper.hpp index aec993f907c..a68d9bd3612 100644 --- a/src/hotspot/share/gc/shared/partialArrayTaskStepper.hpp +++ b/src/hotspot/share/gc/shared/partialArrayTaskStepper.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,55 +28,52 @@ #include "oops/arrayOop.hpp" #include "utilities/globalDefinitions.hpp" -// Helper for handling PartialArrayTasks. +class PartialArrayState; + +// Helper for partial array chunking tasks. // // When an array is large, we want to split it up into chunks that can be -// processed in parallel. Each task (implicitly) represents such a chunk. -// We can enqueue multiple tasks at the same time. We want to enqueue -// enough tasks to benefit from the available parallelism, while not so many -// as to substantially expand the task queues. -// -// A task directly refers to the from-space array. The from-space array's -// forwarding pointer refers to the associated to-space array, and its -// length is the actual length. The to-space array's length field is used to -// indicate processing progress. It is the starting index of the next chunk -// to process, or equals the actual length when there are no more chunks to -// be processed. +// processed in parallel. Each task (implicitly) represents such a chunk. We +// can enqueue multiple tasks at the same time. We want to enqueue enough +// tasks to benefit from the available parallelism, while not so many as to +// substantially expand the task queues. class PartialArrayTaskStepper { public: - PartialArrayTaskStepper(uint n_workers); + PartialArrayTaskStepper(uint n_workers, size_t chunk_size); struct Step { - int _index; // Array index for the step. + size_t _index; // Array index for the step. uint _ncreate; // Number of new tasks to create. }; - // Set to's length to the end of the initial chunk, which is the start of - // the first partial task if the array is large enough to need splitting. - // Returns a Step with _index being that index and _ncreate being the - // initial number of partial tasks to enqueue. - inline Step start(arrayOop from, arrayOop to, int chunk_size) const; + // Called with the length of the array to be processed. Returns a Step with + // _index being the end of the initial chunk, which the caller should + // process. This is also the starting index for the next chunk to process. + // The _ncreate is the number of tasks to enqueue to continue processing the + // array. If _ncreate is zero then _index will be length. + inline Step start(size_t length) const; + + // Atomically increment state's index by chunk_size() to claim the next + // chunk. Returns a Step with _index being the starting index of the + // claimed chunk and _ncreate being the number of additional partial tasks + // to enqueue. + inline Step next(PartialArrayState* state) const; - // Increment to's length by chunk_size to claim the next chunk. Returns a - // Step with _index being the starting index of the claimed chunk and - // _ncreate being the number of additional partial tasks to enqueue. - // precondition: chunk_size must be the same as used to start the task sequence. - inline Step next(arrayOop from, arrayOop to, int chunk_size) const; + // The size of chunks to claim for each task. + inline size_t chunk_size() const; class TestSupport; // For unit tests private: + // Size (number of elements) of a chunk to process. + size_t _chunk_size; // Limit on the number of partial array tasks to create for a given array. uint _task_limit; // Maximum number of new tasks to create when processing an existing task. uint _task_fanout; - // Split start/next into public part dealing with oops and private - // impl dealing with lengths and pointers to lengths, for unit testing. - // length is the actual length obtained from the from-space object. - // to_length_addr is the address of the to-space object's length value. - inline Step start_impl(int length, int* to_length_addr, int chunk_size) const; - inline Step next_impl(int length, int* to_length_addr, int chunk_size) const; + // For unit tests. + inline Step next_impl(size_t length, volatile size_t* index_addr) const; }; #endif // SHARE_GC_SHARED_PARTIALARRAYTASKSTEPPER_HPP diff --git a/src/hotspot/share/gc/shared/partialArrayTaskStepper.inline.hpp b/src/hotspot/share/gc/shared/partialArrayTaskStepper.inline.hpp index aa9a02c4902..1d43578b5fe 100644 --- a/src/hotspot/share/gc/shared/partialArrayTaskStepper.inline.hpp +++ b/src/hotspot/share/gc/shared/partialArrayTaskStepper.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,66 +25,46 @@ #ifndef SHARE_GC_SHARED_PARTIALARRAYTASKSTEPPER_INLINE_HPP #define SHARE_GC_SHARED_PARTIALARRAYTASKSTEPPER_INLINE_HPP +#include "gc/shared/partialArrayState.hpp" #include "gc/shared/partialArrayTaskStepper.hpp" - -#include "oops/arrayOop.hpp" #include "runtime/atomic.hpp" +#include "utilities/checkedCast.hpp" +#include "utilities/debug.hpp" -PartialArrayTaskStepper::Step -PartialArrayTaskStepper::start_impl(int length, - int* to_length_addr, - int chunk_size) const { - assert(chunk_size > 0, "precondition"); - - int end = length % chunk_size; // End of initial chunk. - // Set to's length to end of initial chunk. Partial tasks use that length - // field as the start of the next chunk to process. Must be done before - // enqueuing partial scan tasks, in case other threads steal any of those - // tasks. - // - // The value of end can be 0, either because of a 0-length array or - // because length is a multiple of the chunk size. Both of those are - // relatively rare and handled in the normal course of the iteration, so - // not worth doing anything special about here. - *to_length_addr = end; +size_t PartialArrayTaskStepper::chunk_size() const { + return _chunk_size; +} +PartialArrayTaskStepper::Step +PartialArrayTaskStepper::start(size_t length) const { + size_t end = length % _chunk_size; // End of initial chunk. // If the initial chunk is the complete array, then don't need any partial // tasks. Otherwise, start with just one partial task; see new task // calculation in next(). - Step result = { end, (length > end) ? 1u : 0u }; - return result; + return Step{ end, (length > end) ? 1u : 0u }; } PartialArrayTaskStepper::Step -PartialArrayTaskStepper::start(arrayOop from, arrayOop to, int chunk_size) const { - return start_impl(from->length(), to->length_addr(), chunk_size); -} - -PartialArrayTaskStepper::Step -PartialArrayTaskStepper::next_impl(int length, - int* to_length_addr, - int chunk_size) const { - assert(chunk_size > 0, "precondition"); - - // The start of the next task is in the length field of the to-space object. +PartialArrayTaskStepper::next_impl(size_t length, volatile size_t* index_addr) const { + // The start of the next task is in the state's index. // Atomically increment by the chunk size to claim the associated chunk. // Because we limit the number of enqueued tasks to being no more than the // number of remaining chunks to process, we can use an atomic add for the // claim, rather than a CAS loop. - int start = Atomic::fetch_then_add(to_length_addr, - chunk_size, - memory_order_relaxed); + size_t start = Atomic::fetch_then_add(index_addr, + _chunk_size, + memory_order_relaxed); - assert(start < length, "invariant: start %d, length %d", start, length); - assert(((length - start) % chunk_size) == 0, - "invariant: start %d, length %d, chunk size %d", - start, length, chunk_size); + assert(start < length, "invariant: start %zu, length %zu", start, length); + assert(((length - start) % _chunk_size) == 0, + "invariant: start %zu, length %zu, chunk size %zu", + start, length, _chunk_size); // Determine the number of new tasks to create. // Zero-based index for this partial task. The initial task isn't counted. - uint task_num = (start / chunk_size); + uint task_num = checked_cast(start / _chunk_size); // Number of tasks left to process, including this one. - uint remaining_tasks = (length - start) / chunk_size; + uint remaining_tasks = checked_cast((length - start) / _chunk_size); assert(remaining_tasks > 0, "invariant"); // Compute number of pending tasks, including this one. The maximum number // of tasks is a function of task_num (N) and _task_fanout (F). @@ -106,13 +86,12 @@ PartialArrayTaskStepper::next_impl(int length, // of tasks to add for this task. uint pending = MIN3(max_pending, remaining_tasks, _task_limit); uint ncreate = MIN2(_task_fanout, MIN2(remaining_tasks, _task_limit + 1) - pending); - Step result = { start, ncreate }; - return result; + return Step{ start, ncreate }; } PartialArrayTaskStepper::Step -PartialArrayTaskStepper::next(arrayOop from, arrayOop to, int chunk_size) const { - return next_impl(from->length(), to->length_addr(), chunk_size); +PartialArrayTaskStepper::next(PartialArrayState* state) const { + return next_impl(state->length(), state->index_addr()); } #endif // SHARE_GC_SHARED_PARTIALARRAYTASKSTEPPER_INLINE_HPP diff --git a/src/hotspot/share/gc/shared/taskqueue.hpp b/src/hotspot/share/gc/shared/taskqueue.hpp index 2e21ba33b0b..2ea75e1457c 100644 --- a/src/hotspot/share/gc/shared/taskqueue.hpp +++ b/src/hotspot/share/gc/shared/taskqueue.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -576,6 +576,7 @@ class ObjArrayTask // Wrapper over an oop that is a partially scanned array. // Can be converted to a ScannerTask for placement in associated task queues. // Refers to the partially copied source array oop. +// Temporarily retained to support ParallelGC until it adopts PartialArrayState. class PartialArrayScanTask { oop _src; @@ -586,7 +587,9 @@ class PartialArrayScanTask { oop to_source_array() const { return _src; } }; -// Discriminated union over oop*, narrowOop*, and PartialArrayScanTask. +class PartialArrayState; + +// Discriminated union over oop*, narrowOop*, and PartialArrayState. // Uses a low tag in the associated pointer to identify the category. // Used as a task queue element type. class ScannerTask { @@ -624,9 +627,13 @@ class ScannerTask { explicit ScannerTask(narrowOop* p) : _p(encode(p, NarrowOopTag)) {} + // Temporarily retained to support ParallelGC until it adopts PartialArrayState. explicit ScannerTask(PartialArrayScanTask t) : _p(encode(t.to_source_array(), PartialArrayTag)) {} + explicit ScannerTask(PartialArrayState* state) : + _p(encode(state, PartialArrayTag)) {} + // Trivially copyable. // Predicate implementations assume OopTag == 0, others are powers of 2. @@ -639,10 +646,15 @@ class ScannerTask { return (raw_value() & NarrowOopTag) != 0; } + // Temporarily retained to support ParallelGC until it adopts PartialArrayState. bool is_partial_array_task() const { return (raw_value() & PartialArrayTag) != 0; } + bool is_partial_array_state() const { + return (raw_value() & PartialArrayTag) != 0; + } + oop* to_oop_ptr() const { return static_cast(decode(OopTag)); } @@ -651,9 +663,14 @@ class ScannerTask { return static_cast(decode(NarrowOopTag)); } + // Temporarily retained to support ParallelGC until it adopts PartialArrayState. PartialArrayScanTask to_partial_array_task() const { return PartialArrayScanTask(cast_to_oop(decode(PartialArrayTag))); } + + PartialArrayState* to_partial_array_state() const { + return static_cast(decode(PartialArrayTag)); + } }; #endif // SHARE_GC_SHARED_TASKQUEUE_HPP diff --git a/test/hotspot/gtest/gc/shared/test_partialArrayTaskStepper.cpp b/test/hotspot/gtest/gc/shared/test_partialArrayTaskStepper.cpp index fb797ba12c1..3bb3a74437c 100644 --- a/test/hotspot/gtest/gc/shared/test_partialArrayTaskStepper.cpp +++ b/test/hotspot/gtest/gc/shared/test_partialArrayTaskStepper.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,50 +32,42 @@ using Stepper = PartialArrayTaskStepper; class PartialArrayTaskStepper::TestSupport : AllStatic { public: - static Step start(const Stepper* stepper, - int length, - int* to_length_addr, - uint chunk_size) { - return stepper->start_impl(length, to_length_addr, chunk_size); - } - static Step next(const Stepper* stepper, - int length, - int* to_length_addr, - uint chunk_size) { - return stepper->next_impl(length, to_length_addr, chunk_size); + size_t length, + size_t* to_length_addr) { + return stepper->next_impl(length, to_length_addr); } }; using StepperSupport = PartialArrayTaskStepper::TestSupport; -static int simulate(const Stepper* stepper, - int length, - int* to_length_addr, - uint chunk_size) { - Step init = StepperSupport::start(stepper, length, to_length_addr, chunk_size); +static uint simulate(const Stepper* stepper, + size_t length, + size_t* to_length_addr) { + Step init = stepper->start(length); + *to_length_addr = init._index; uint queue_count = init._ncreate; - int task = 0; + uint task = 0; for ( ; queue_count > 0; ++task) { --queue_count; - Step step = StepperSupport::next(stepper, length, to_length_addr, chunk_size); + Step step = StepperSupport::next(stepper, length, to_length_addr); queue_count += step._ncreate; } return task; } -static void run_test(int length, int chunk_size, uint n_workers) { - const PartialArrayTaskStepper stepper(n_workers); - int to_length; - int tasks = simulate(&stepper, length, &to_length, chunk_size); +static void run_test(size_t length, size_t chunk_size, uint n_workers) { + const PartialArrayTaskStepper stepper(n_workers, chunk_size); + size_t to_length; + uint tasks = simulate(&stepper, length, &to_length); ASSERT_EQ(length, to_length); ASSERT_EQ(tasks, length / chunk_size); } TEST(PartialArrayTaskStepperTest, doit) { - for (int chunk_size = 50; chunk_size <= 500; chunk_size += 50) { + for (size_t chunk_size = 50; chunk_size <= 500; chunk_size += 50) { for (uint n_workers = 1; n_workers <= 256; n_workers = (n_workers * 3 / 2 + 1)) { - for (int length = 0; length <= 1000000; length = (length * 2 + 1)) { + for (size_t length = 0; length <= 1000000; length = (length * 2 + 1)) { run_test(length, chunk_size, n_workers); } // Ensure we hit boundary cases for length % chunk_size == 0. From 0e7c1c1afeaba1c125b70cabe7b1b7a3193ee5c3 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Mon, 12 Aug 2024 06:26:27 +0000 Subject: [PATCH 370/460] 8338112: Test testlibrary_tests/ir_framework/tests/TestPrivilegedMode.java fails with release build Reviewed-by: chagedorn, thartmann --- .../ir_framework/tests/TestPrivilegedMode.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPrivilegedMode.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPrivilegedMode.java index 347b2eb39fb..2122be83a0f 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPrivilegedMode.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPrivilegedMode.java @@ -31,7 +31,7 @@ /* * @test - * @requires vm.flagless + * @requires vm.debug == true & vm.compiler2.enabled & vm.flagless * @summary Test that IR framework successfully adds test class to boot classpath in order to run in privileged mode. * @modules java.base/jdk.internal.vm.annotation * @library /test/lib / From 692f5cbdb9bd94f03e5f18ddf07d56fbb5c0d456 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Mon, 12 Aug 2024 07:32:10 +0000 Subject: [PATCH 371/460] 8338101: remove old remap assertion in map_or_reserve_memory_aligned after JDK-8338058 Reviewed-by: mdoerr, clanger --- src/hotspot/os/windows/os_windows.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 65ba13b0d9e..cb0fe95269b 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -3462,8 +3462,8 @@ static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int fi os::attempt_reserve_memory_at(aligned_base, size, false, flag); } - assert(aligned_base != nullptr, "Did not manage to re-map after %d attempts?", max_attempts); - assert(aligned_base != nullptr, "Did not manage to re-map after %d attempts (size %zu, alignment %zu, file descriptor %d)", max_attempts, size, alignment, file_desc); + assert(aligned_base != nullptr, + "Did not manage to re-map after %d attempts (size %zu, alignment %zu, file descriptor %d)", max_attempts, size, alignment, file_desc); return aligned_base; } From 03204600c596214895ef86581eba9722f76d39b3 Mon Sep 17 00:00:00 2001 From: Andrew Haley Date: Mon, 12 Aug 2024 07:38:43 +0000 Subject: [PATCH 372/460] 8337958: Out-of-bounds array access in secondary_super_cache Reviewed-by: vlivanov, shade --- src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp | 4 ++-- src/hotspot/cpu/riscv/macroAssembler_riscv.cpp | 4 ++-- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 5 ++--- src/hotspot/share/oops/klass.cpp | 13 ++++++++----- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 25dfaca6dca..9dd4371cf69 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -1730,8 +1730,8 @@ void MacroAssembler::lookup_secondary_supers_table_slow_path(Register r_super_kl // The bitmap is full to bursting. // Implicit invariant: BITMAP_FULL implies (length > 0) assert(Klass::SECONDARY_SUPERS_BITMAP_FULL == ~uintx(0), ""); - cmn(r_bitmap, (u1)1); - br(EQ, L_huge); + cmpw(r_array_length, (u1)(Klass::SECONDARY_SUPERS_TABLE_SIZE - 2)); + br(GT, L_huge); // NB! Our caller has checked bits 0 and 1 in the bitmap. The // current slot (at secondary_supers[r_array_index]) has not yet diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index e0b24b7fd66..c6624cb45bb 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -3973,8 +3973,8 @@ void MacroAssembler::lookup_secondary_supers_table_slow_path(Register r_super_kl // Check if bitmap is SECONDARY_SUPERS_BITMAP_FULL assert(Klass::SECONDARY_SUPERS_BITMAP_FULL == ~uintx(0), "Adjust this code"); - addi(t0, r_bitmap, (u1)1); - beqz(t0, L_bitmap_full); + subw(t0, r_array_length, Klass::SECONDARY_SUPERS_TABLE_SIZE - 2); + bgtz(t0, L_bitmap_full); // NB! Our caller has checked bits 0 and 1 in the bitmap. The // current slot (at secondary_supers[r_array_index]) has not yet diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index c8234d6b9b8..78bcabb2000 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -4945,9 +4945,8 @@ void MacroAssembler::lookup_secondary_supers_table_slow_path(Register r_super_kl // The bitmap is full to bursting. // Implicit invariant: BITMAP_FULL implies (length > 0) - assert(Klass::SECONDARY_SUPERS_BITMAP_FULL == ~uintx(0), ""); - cmpq(r_bitmap, (int32_t)-1); // sign-extends immediate to 64-bit value - jcc(Assembler::equal, L_huge); + cmpl(r_array_length, (int32_t)Klass::SECONDARY_SUPERS_TABLE_SIZE - 2); + jcc(Assembler::greater, L_huge); // NB! Our caller has checked bits 0 and 1 in the bitmap. The // current slot (at secondary_supers[r_array_index]) has not yet diff --git a/src/hotspot/share/oops/klass.cpp b/src/hotspot/share/oops/klass.cpp index 1fed317a860..964bb030b96 100644 --- a/src/hotspot/share/oops/klass.cpp +++ b/src/hotspot/share/oops/klass.cpp @@ -306,6 +306,7 @@ void Klass::set_secondary_supers(Array* secondaries, uintx bitmap) { if (UseSecondarySupersTable && secondaries != nullptr) { uintx real_bitmap = compute_secondary_supers_bitmap(secondaries); assert(bitmap == real_bitmap, "must be"); + assert(secondaries->length() >= (int)population_count(bitmap), "must be"); } #endif _bitmap = bitmap; @@ -344,11 +345,12 @@ uintx Klass::hash_secondary_supers(Array* secondaries, bool rewrite) { return uintx(1) << hash_slot; } - // For performance reasons we don't use a hashed table unless there - // are at least two empty slots in it. If there were only one empty - // slot it'd take a long time to create the table and the resulting - // search would be no faster than linear probing. - if (length > SECONDARY_SUPERS_TABLE_SIZE - 2) { + // Invariant: _secondary_supers.length >= population_count(_secondary_supers_bitmap) + + // Don't attempt to hash a table that's completely full, because in + // the case of an absent interface linear probing would not + // terminate. + if (length >= SECONDARY_SUPERS_TABLE_SIZE) { return SECONDARY_SUPERS_BITMAP_FULL; } @@ -788,6 +790,7 @@ void Klass::remove_java_mirror() { void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) { assert(is_klass(), "ensure C++ vtable is restored"); assert(is_shared(), "must be set"); + assert(secondary_supers()->length() >= (int)population_count(_bitmap), "must be"); JFR_ONLY(RESTORE_ID(this);) if (log_is_enabled(Trace, cds, unshareable)) { ResourceMark rm(THREAD); From a6c0630737bbf2f2e6c64863ff9b43c50c4742b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Mon, 12 Aug 2024 10:58:05 +0000 Subject: [PATCH 373/460] 8337938: ZUtils::alloc_aligned allocates without reporting to NMT Reviewed-by: stefank, kbarrett --- src/hotspot/os/posix/gc/z/zUtils_posix.cpp | 43 ------------------- .../os/windows/gc/z/zUtils_windows.cpp | 40 ----------------- src/hotspot/share/gc/z/zStat.cpp | 4 +- src/hotspot/share/gc/z/zUtils.hpp | 4 +- src/hotspot/share/gc/z/zUtils.inline.hpp | 15 ++++++- src/hotspot/share/gc/z/zValue.inline.hpp | 6 +-- 6 files changed, 21 insertions(+), 91 deletions(-) delete mode 100644 src/hotspot/os/posix/gc/z/zUtils_posix.cpp delete mode 100644 src/hotspot/os/windows/gc/z/zUtils_windows.cpp diff --git a/src/hotspot/os/posix/gc/z/zUtils_posix.cpp b/src/hotspot/os/posix/gc/z/zUtils_posix.cpp deleted file mode 100644 index dc5af2b973a..00000000000 --- a/src/hotspot/os/posix/gc/z/zUtils_posix.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2015, 2023, 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 "precompiled.hpp" -#include "gc/z/zUtils.hpp" -#include "utilities/debug.hpp" -#include "utilities/globalDefinitions.hpp" - -#include - -uintptr_t ZUtils::alloc_aligned(size_t alignment, size_t size) { - void* res = nullptr; - - // Use raw posix_memalign as long as we have no wrapper for it - ALLOW_C_FUNCTION(::posix_memalign, int rc = posix_memalign(&res, alignment, size);) - if (rc != 0) { - fatal("posix_memalign() failed"); - } - - memset(res, 0, size); - - return (uintptr_t)res; -} diff --git a/src/hotspot/os/windows/gc/z/zUtils_windows.cpp b/src/hotspot/os/windows/gc/z/zUtils_windows.cpp deleted file mode 100644 index 29f7f55e2d1..00000000000 --- a/src/hotspot/os/windows/gc/z/zUtils_windows.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2019, 2023, 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 "precompiled.hpp" -#include "gc/z/zUtils.hpp" -#include "utilities/debug.hpp" - -#include - -uintptr_t ZUtils::alloc_aligned(size_t alignment, size_t size) { - void* const res = _aligned_malloc(size, alignment); - - if (res == nullptr) { - fatal("_aligned_malloc failed"); - } - - memset(res, 0, size); - - return (uintptr_t)res; -} diff --git a/src/hotspot/share/gc/z/zStat.cpp b/src/hotspot/share/gc/z/zStat.cpp index 613f7b2740b..c2a7a23c04f 100644 --- a/src/hotspot/share/gc/z/zStat.cpp +++ b/src/hotspot/share/gc/z/zStat.cpp @@ -35,7 +35,7 @@ #include "gc/z/zRelocationSetSelector.inline.hpp" #include "gc/z/zStat.hpp" #include "gc/z/zTracer.inline.hpp" -#include "gc/z/zUtils.hpp" +#include "gc/z/zUtils.inline.hpp" #include "memory/metaspaceUtils.hpp" #include "memory/resourceArea.hpp" #include "runtime/atomic.hpp" @@ -364,7 +364,7 @@ void ZStatValue::initialize() { // Allocation aligned memory const size_t size = _cpu_offset * ZCPU::count(); - _base = ZUtils::alloc_aligned(ZCacheLineSize, size); + _base = ZUtils::alloc_aligned_unfreeable(ZCacheLineSize, size); } const char* ZStatValue::group() const { diff --git a/src/hotspot/share/gc/z/zUtils.hpp b/src/hotspot/share/gc/z/zUtils.hpp index f82ef06235c..59e789d5b38 100644 --- a/src/hotspot/share/gc/z/zUtils.hpp +++ b/src/hotspot/share/gc/z/zUtils.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ class ZUtils : public AllStatic { static const char* thread_name(); // Allocation - static uintptr_t alloc_aligned(size_t alignment, size_t size); + static uintptr_t alloc_aligned_unfreeable(size_t alignment, size_t size); // Size conversion static size_t bytes_to_words(size_t size_in_words); diff --git a/src/hotspot/share/gc/z/zUtils.inline.hpp b/src/hotspot/share/gc/z/zUtils.inline.hpp index eda9fca9398..b6acf12df30 100644 --- a/src/hotspot/share/gc/z/zUtils.inline.hpp +++ b/src/hotspot/share/gc/z/zUtils.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,11 +28,24 @@ #include "gc/z/zAddress.inline.hpp" #include "oops/oop.inline.hpp" +#include "runtime/os.hpp" #include "utilities/align.hpp" #include "utilities/copy.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" +inline uintptr_t ZUtils::alloc_aligned_unfreeable(size_t alignment, size_t size) { + const size_t padded_size = size + (alignment - 1); + void* const addr = os::malloc(padded_size, mtGC); + void* const aligned_addr = align_up(addr, alignment); + + memset(aligned_addr, 0, size); + + // Since free expects pointers returned by malloc, aligned_addr cannot be + // freed since it is most likely not the same as addr after alignment. + return (uintptr_t)aligned_addr; +} + inline size_t ZUtils::bytes_to_words(size_t size_in_bytes) { assert(is_aligned(size_in_bytes, BytesPerWord), "Size not word aligned"); return size_in_bytes >> LogBytesPerWord; diff --git a/src/hotspot/share/gc/z/zValue.inline.hpp b/src/hotspot/share/gc/z/zValue.inline.hpp index b8c86cdd5c5..2367bac0f0a 100644 --- a/src/hotspot/share/gc/z/zValue.inline.hpp +++ b/src/hotspot/share/gc/z/zValue.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ #include "gc/z/zCPU.inline.hpp" #include "gc/z/zGlobals.hpp" #include "gc/z/zNUMA.hpp" -#include "gc/z/zUtils.hpp" +#include "gc/z/zUtils.inline.hpp" #include "runtime/globals.hpp" #include "utilities/align.hpp" @@ -58,7 +58,7 @@ uintptr_t ZValueStorage::alloc(size_t size) { // Allocate new block of memory const size_t block_alignment = offset; const size_t block_size = offset * S::count(); - _top = ZUtils::alloc_aligned(block_alignment, block_size); + _top = ZUtils::alloc_aligned_unfreeable(block_alignment, block_size); _end = _top + offset; // Retry allocation From 89a15f1414f89d2dd32eac791e9155fcb4207e56 Mon Sep 17 00:00:00 2001 From: Daniel Gredler Date: Mon, 12 Aug 2024 12:09:22 +0000 Subject: [PATCH 374/460] 8337681: PNGImageWriter uses much more memory than necessary Reviewed-by: prr, lbourges --- .../imageio/plugins/png/PNGImageWriter.java | 22 ++- .../plugins/png/RasterReuseWriteTest.java | 182 ++++++++++++++++++ 2 files changed, 199 insertions(+), 5 deletions(-) create mode 100644 test/jdk/javax/imageio/plugins/png/RasterReuseWriteTest.java diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java index 27707613f76..ca9ba7631ca 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java @@ -26,6 +26,7 @@ package com.sun.imageio.plugins.png; import java.awt.Rectangle; +import java.awt.image.BufferedImage; import java.awt.image.IndexColorModel; import java.awt.image.Raster; import java.awt.image.RenderedImage; @@ -919,17 +920,28 @@ private void encodePass(ImageOutputStream os, int bitDepth = metadata.IHDR_bitDepth; for (int row = minY + yOffset; row < minY + height; row += ySkip) { - Rectangle rect = new Rectangle(minX, row, width, 1); - Raster ras = image.getData(rect); + Raster ras; + if (image instanceof BufferedImage bi) { + // Use the raster directly (no copy). + ras = bi.getRaster(); + } else if (image.getNumXTiles() == 1 && image.getNumYTiles() == 1 && + image.getTileWidth() == width && image.getTileHeight() == height) { + // Use the single tile directly (no copy). + ras = image.getTile(image.getMinTileX(), image.getMinTileY()); + } else { + // Make a copy of the raster data. + Rectangle rect = new Rectangle(minX, row, width, 1); + ras = image.getData(rect); + } + if (sourceBands != null) { - ras = ras.createChild(minX, row, width, 1, minX, row, - sourceBands); + ras = ras.createChild(minX, row, width, 1, minX, row, sourceBands); } ras.getPixels(minX, row, width, 1, samples); if (image.getColorModel().isAlphaPremultiplied()) { - WritableRaster wr = ras.createCompatibleWritableRaster(); + WritableRaster wr = ras.createCompatibleWritableRaster(minX, row, width, 1); wr.setPixels(wr.getMinX(), wr.getMinY(), wr.getWidth(), wr.getHeight(), samples); diff --git a/test/jdk/javax/imageio/plugins/png/RasterReuseWriteTest.java b/test/jdk/javax/imageio/plugins/png/RasterReuseWriteTest.java new file mode 100644 index 00000000000..64adaa6d196 --- /dev/null +++ b/test/jdk/javax/imageio/plugins/png/RasterReuseWriteTest.java @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8337681 + * @summary Test that raster use optimization does not cause any regressions. + */ + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.awt.image.RenderedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import javax.imageio.IIOImage; +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.stream.ImageInputStream; +import javax.imageio.stream.ImageOutputStream; +import javax.imageio.stream.MemoryCacheImageOutputStream; + +public class RasterReuseWriteTest { + + public static void main(String[] args) throws Exception { + test(BufferedImage.TYPE_INT_RGB); + test(BufferedImage.TYPE_INT_ARGB); + test(BufferedImage.TYPE_INT_ARGB_PRE); + test(BufferedImage.TYPE_4BYTE_ABGR); + test(BufferedImage.TYPE_4BYTE_ABGR_PRE); + } + + private static void test(int type) throws Exception { + + // swaps blue and red + int bands = (type == BufferedImage.TYPE_INT_RGB ? 3 : 4); + int[] sourceBands = bands == 3 ? new int[] { 2, 1, 0 } : + new int[] { 2, 1, 0, 3 }; + + // test writing a BufferedImage without source bands + BufferedImage img1 = createImage(256, 256, type); + byte[] bytes1 = writePng(img1, null); + BufferedImage img2 = ImageIO.read(new ByteArrayInputStream(bytes1)); + compare(img1, img2, false); + + // test writing a BufferedImage with source bands + BufferedImage img3 = createImage(256, 256, type); + byte[] bytes3 = writePng(img3, sourceBands); + BufferedImage img4 = ImageIO.read(new ByteArrayInputStream(bytes3)); + compare(img3, img4, true); + + // test writing a non-BufferedImage with source bands and one tile + RenderedImage img5 = toTiledImage(img1, 256); + byte[] bytes5 = writePng(img5, sourceBands); + BufferedImage img6 = ImageIO.read(new ByteArrayInputStream(bytes5)); + compare(img5, img6, true); + + // test writing a non-BufferedImage with source bands and multiple tiles + RenderedImage img7 = toTiledImage(img1, 128); + byte[] bytes7 = writePng(img7, sourceBands); + BufferedImage img8 = ImageIO.read(new ByteArrayInputStream(bytes7)); + compare(img7, img8, true); + } + + private static BufferedImage createImage(int w, int h, int type) throws Exception { + BufferedImage img = new BufferedImage(w, h, type); + Graphics2D g2d = img.createGraphics(); + g2d.setColor(Color.WHITE); + g2d.fillRect(0, 0, w, h); + g2d.setColor(Color.GREEN); + g2d.drawRect(20, 20, 100, 50); + g2d.setColor(Color.RED); + g2d.drawRect(80, 10, 100, 40); + g2d.setColor(Color.BLUE); + g2d.fillRect(40, 60, 120, 30); + g2d.dispose(); + return img; + } + + private static byte[] writePng(RenderedImage img, int[] sourceBands) throws Exception { + ImageWriter writer = ImageIO.getImageWritersByFormatName("png").next(); + ImageWriteParam param = writer.getDefaultWriteParam(); + param.setSourceBands(sourceBands); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageOutputStream stream = new MemoryCacheImageOutputStream(baos); + writer.setOutput(stream); + writer.write(null, new IIOImage(img, null, null), param); + writer.dispose(); + stream.flush(); + return baos.toByteArray(); + } + + private static void compare(RenderedImage img1, RenderedImage img2, boolean blueAndRedSwapped) { + int[] pixels1 = getRgbPixels(img1); + int[] pixels2 = getRgbPixels(img2); + for (int i = 0; i < pixels1.length; i++) { + int expected; + if (blueAndRedSwapped && pixels1[i] == 0xFFFF0000) { + expected = 0xFF0000FF; // red -> blue + } else if (blueAndRedSwapped && pixels1[i] == 0xFF0000FF) { + expected = 0xFFFF0000; // blue -> red + } else { + expected = pixels1[i]; // no change + } + int actual = pixels2[i]; + if (actual != expected) { + throw new RuntimeException("Pixel " + i + ": expected " + + Integer.toHexString(expected) + ", but got " + + Integer.toHexString(actual)); + } + } + } + + private static int[] getRgbPixels(RenderedImage img) { + int w = img.getWidth(); + int h = img.getHeight(); + if (img instanceof BufferedImage bi) { + return bi.getRGB(0, 0, w, h, null, 0, w); + } else { + BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2d = bi.createGraphics(); + g2d.drawRenderedImage(img, new AffineTransform()); + g2d.dispose(); + return bi.getRGB(0, 0, w, h, null, 0, w); + } + } + + private static RenderedImage toTiledImage(BufferedImage img, int tileSize) throws Exception { + + // write to TIFF + ImageWriter writer = ImageIO.getImageWritersByFormatName("tiff").next(); + ImageWriteParam param = writer.getDefaultWriteParam(); + param.setTilingMode(ImageWriteParam.MODE_EXPLICIT); + param.setTiling(tileSize, tileSize, 0, 0); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageOutputStream stream = new MemoryCacheImageOutputStream(baos); + writer.setOutput(stream); + writer.write(null, new IIOImage(img, null, null), param); + writer.dispose(); + stream.flush(); + byte[] bytes = baos.toByteArray(); + + // read from TIFF + ImageReader reader = ImageIO.getImageReadersByFormatName("tiff").next(); + ImageInputStream input = ImageIO.createImageInputStream(new ByteArrayInputStream(bytes)); + reader.setInput(input); + RenderedImage ri = reader.readAsRenderedImage(0, null); + if (ri instanceof BufferedImage) { + throw new RuntimeException("Unexpected BufferedImage"); + } + int tw = ri.getTileWidth(); + int th = ri.getTileHeight(); + if (tw != tileSize || th != tileSize) { + throw new RuntimeException("Expected tile size " + tileSize + + ", but found " + tw + "x" + th); + } + return ri; + } +} From 61d1dc59535a3dc186bc1986a04efdb4e5a8fa18 Mon Sep 17 00:00:00 2001 From: Vicente Romero Date: Mon, 12 Aug 2024 13:52:57 +0000 Subject: [PATCH 375/460] 8334466: Ambiguous method call with generics may cause FunctionDescriptorLookupError Reviewed-by: jlahoda --- .../com/sun/tools/javac/comp/Resolve.java | 14 ++++++++--- ...WithFunctionDescriptorLookupErrorTest.java | 25 +++++++++++++++++++ ...hWithFunctionDescriptorLookupErrorTest.out | 2 ++ 3 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 test/langtools/tools/javac/lambda/CrashWithFunctionDescriptorLookupErrorTest.java create mode 100644 test/langtools/tools/javac/lambda/CrashWithFunctionDescriptorLookupErrorTest.out 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 c71b6d341dc..5bf1bc0ead1 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 @@ -1219,9 +1219,17 @@ private boolean unrelatedInterfaces(Type t, Type s) { /** Parameters {@code t} and {@code s} are unrelated functional interface types. */ private boolean functionalInterfaceMostSpecific(Type t, Type s, JCTree tree) { - Type tDesc = types.findDescriptorType(types.capture(t)); - Type tDescNoCapture = types.findDescriptorType(t); - Type sDesc = types.findDescriptorType(s); + Type tDesc; + Type tDescNoCapture; + Type sDesc; + try { + tDesc = types.findDescriptorType(types.capture(t)); + tDescNoCapture = types.findDescriptorType(t); + sDesc = types.findDescriptorType(s); + } catch (Types.FunctionDescriptorLookupError ex) { + // don't report, a more meaningful error should be reported upstream + return false; + } final List tTypeParams = tDesc.getTypeArguments(); final List tTypeParamsNoCapture = tDescNoCapture.getTypeArguments(); final List sTypeParams = sDesc.getTypeArguments(); diff --git a/test/langtools/tools/javac/lambda/CrashWithFunctionDescriptorLookupErrorTest.java b/test/langtools/tools/javac/lambda/CrashWithFunctionDescriptorLookupErrorTest.java new file mode 100644 index 00000000000..bfdfc30609d --- /dev/null +++ b/test/langtools/tools/javac/lambda/CrashWithFunctionDescriptorLookupErrorTest.java @@ -0,0 +1,25 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8334466 + * @summary Ambiguous method call with generics may cause FunctionDescriptorLookupError + * @compile/fail/ref=CrashWithFunctionDescriptorLookupErrorTest.out -XDrawDiagnostics CrashWithFunctionDescriptorLookupErrorTest.java + */ + +import java.util.List; + +class CrashWithFunctionDescriptorLookupErrorTest { + void m() { + List list = List.of(new X()); + test(list.get(0)); + } + + void test(A a) { } + void test(B b) { } + + interface A> { T a(); } + interface B> { T b(); } + class X implements A, B { + public X a() { return null; } + public X b() { return null; } + } +} diff --git a/test/langtools/tools/javac/lambda/CrashWithFunctionDescriptorLookupErrorTest.out b/test/langtools/tools/javac/lambda/CrashWithFunctionDescriptorLookupErrorTest.out new file mode 100644 index 00000000000..06afbc8bc18 --- /dev/null +++ b/test/langtools/tools/javac/lambda/CrashWithFunctionDescriptorLookupErrorTest.out @@ -0,0 +1,2 @@ +CrashWithFunctionDescriptorLookupErrorTest.java:13:9: compiler.err.ref.ambiguous: test, kindname.method, test(CrashWithFunctionDescriptorLookupErrorTest.A), CrashWithFunctionDescriptorLookupErrorTest, kindname.method, test(CrashWithFunctionDescriptorLookupErrorTest.B), CrashWithFunctionDescriptorLookupErrorTest +1 error From a36fb368e1a3630d32908884f4abdc3382eb9aaa Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Mon, 12 Aug 2024 15:33:31 +0000 Subject: [PATCH 376/460] 8338108: Give better error message in configure if a full XCode is missing Reviewed-by: jwaters, erikj, shade --- make/autoconf/toolchain.m4 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4 index 57064df1ed7..12d450cc708 100644 --- a/make/autoconf/toolchain.m4 +++ b/make/autoconf/toolchain.m4 @@ -678,6 +678,9 @@ AC_DEFUN_ONCE([TOOLCHAIN_DETECT_TOOLCHAIN_EXTRA], test_metal=`$METAL --version 2>&1` if test $? -ne 0; then AC_MSG_RESULT([no]) + AC_MSG_NOTICE([A full XCode is required to build the JDK (not only command line tools)]) + AC_MSG_NOTICE([If you have XCode installed, you might need to reset the Xcode active developer directory]) + AC_MSG_NOTICE([using 'sudo xcode-select -r']) AC_MSG_ERROR([XCode tool 'metal' neither found in path nor with xcrun]) else AC_MSG_RESULT([yes, will be using '$METAL']) From 04b146a31f55825e2c8e3c8e42310b3b3337ae95 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Mon, 12 Aug 2024 15:43:40 +0000 Subject: [PATCH 377/460] 8337334: Test tools/javac/7142086/T7142086.java timeout with fastdebug binary Reviewed-by: vromero --- test/langtools/TEST.ROOT | 3 ++- test/langtools/tools/javac/7142086/T7142086.java | 12 ++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/test/langtools/TEST.ROOT b/test/langtools/TEST.ROOT index 11daad5244f..d816d5b096b 100644 --- a/test/langtools/TEST.ROOT +++ b/test/langtools/TEST.ROOT @@ -42,4 +42,5 @@ requires.extraPropDefns.vmOpts = \ -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI \ --add-exports java.base/jdk.internal.foreign=ALL-UNNAMED requires.properties= \ - vm.continuations + vm.continuations \ + vm.debug diff --git a/test/langtools/tools/javac/7142086/T7142086.java b/test/langtools/tools/javac/7142086/T7142086.java index bc8260bd486..b6521b7ffbc 100644 --- a/test/langtools/tools/javac/7142086/T7142086.java +++ b/test/langtools/tools/javac/7142086/T7142086.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,12 +23,20 @@ /* * @test - * @bug 7142086 + * @bug 7142086 8337334 + * @requires vm.debug == false * @summary performance problem in Check.checkOverrideClashes(...) * @modules jdk.compiler * @run main/timeout=10 T7142086 */ +/* + * @test + * @requires vm.debug == true + * @modules jdk.compiler + * @run main/timeout=20 T7142086 + */ + import com.sun.source.util.JavacTask; import java.net.URI; import java.util.List; From f84240bca80d2ff01e198bb67931ad4725a5b334 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Mon, 12 Aug 2024 16:03:41 +0000 Subject: [PATCH 378/460] 8338011: CDS archived heap object support for 64-bit Windows Reviewed-by: stuefe, shade, ccheung --- src/hotspot/share/cds/filemap.cpp | 42 +++++++++++++++++--------- src/hotspot/share/cds/heapShared.cpp | 1 - src/hotspot/share/utilities/macros.hpp | 4 +-- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index 96c826fb67e..c5a9d5cceed 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -2178,21 +2178,35 @@ bool FileMapInfo::map_heap_region_impl() { // Map the archived heap data. No need to call MemTracker::record_virtual_memory_type() // for mapped region as it is part of the reserved java heap, which is already recorded. char* addr = (char*)_mapped_heap_memregion.start(); - char* base = map_memory(_fd, _full_path, r->file_offset(), - addr, _mapped_heap_memregion.byte_size(), r->read_only(), - r->allow_exec()); - if (base == nullptr || base != addr) { - dealloc_heap_region(); - log_info(cds)("UseSharedSpaces: Unable to map at required address in java heap. " - INTPTR_FORMAT ", size = " SIZE_FORMAT " bytes", - p2i(addr), _mapped_heap_memregion.byte_size()); - return false; - } + char* base; - if (VerifySharedSpaces && !r->check_region_crc(base)) { - dealloc_heap_region(); - log_info(cds)("UseSharedSpaces: mapped heap region is corrupt"); - return false; + if (MetaspaceShared::use_windows_memory_mapping()) { + if (!read_region(MetaspaceShared::hp, addr, + align_up(_mapped_heap_memregion.byte_size(), os::vm_page_size()), + /* do_commit = */ true)) { + dealloc_heap_region(); + log_error(cds)("Failed to read archived heap region into " INTPTR_FORMAT, p2i(addr)); + return false; + } + // Checks for VerifySharedSpaces is already done inside read_region() + base = addr; + } else { + base = map_memory(_fd, _full_path, r->file_offset(), + addr, _mapped_heap_memregion.byte_size(), r->read_only(), + r->allow_exec()); + if (base == nullptr || base != addr) { + dealloc_heap_region(); + log_info(cds)("UseSharedSpaces: Unable to map at required address in java heap. " + INTPTR_FORMAT ", size = " SIZE_FORMAT " bytes", + p2i(addr), _mapped_heap_memregion.byte_size()); + return false; + } + + if (VerifySharedSpaces && !r->check_region_crc(base)) { + dealloc_heap_region(); + log_info(cds)("UseSharedSpaces: mapped heap region is corrupt"); + return false; + } } r->set_mapped_base(base); diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index ff84ddc13fc..0a0dc56c894 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -1554,7 +1554,6 @@ void HeapShared::archive_object_subgraphs(ArchivableStaticFieldInfo fields[], // by any of these static fields. // At runtime, these classes are initialized before X's archived fields // are restored by HeapShared::initialize_from_archived_subgraph(). - int i; for (int i = 0; fields[i].valid(); ) { ArchivableStaticFieldInfo* info = &fields[i]; const char* klass_name = info->klass_name; diff --git a/src/hotspot/share/utilities/macros.hpp b/src/hotspot/share/utilities/macros.hpp index 244b18ecdd4..1034dec0d9a 100644 --- a/src/hotspot/share/utilities/macros.hpp +++ b/src/hotspot/share/utilities/macros.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -621,7 +621,7 @@ #define COMPILER_HEADER(basename) XSTR(COMPILER_HEADER_STEM(basename).hpp) #define COMPILER_HEADER_INLINE(basename) XSTR(COMPILER_HEADER_STEM(basename).inline.hpp) -#if INCLUDE_CDS && INCLUDE_G1GC && defined(_LP64) && !defined(_WINDOWS) +#if INCLUDE_CDS && INCLUDE_G1GC && defined(_LP64) #define INCLUDE_CDS_JAVA_HEAP 1 #define CDS_JAVA_HEAP_ONLY(x) x #define NOT_CDS_JAVA_HEAP(x) From 8d0831478338e9b084b2c47f46eba9faae3a5eb6 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Mon, 12 Aug 2024 17:15:39 +0000 Subject: [PATCH 379/460] 8337795: Type annotation attached to incorrect type during class reading Reviewed-by: vromero --- .../com/sun/tools/javac/jvm/ClassReader.java | 145 ++++++++---------- .../processing/model/type/BasicAnnoTests.java | 4 + 2 files changed, 65 insertions(+), 84 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java index dba5fb6a197..fcc1efda8dc 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java @@ -36,9 +36,9 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; -import java.util.function.BiFunction; import java.util.function.IntFunction; import java.util.function.Predicate; +import java.util.stream.IntStream; import javax.lang.model.element.Modifier; import javax.lang.model.element.NestingKind; @@ -2461,13 +2461,8 @@ private Type addTypeAnnotations(Type type, Predicate fil .add(attribute); } - // Search the structure of the type to find the contained types at each type path - Map> attributesByType = new HashMap<>(); - new TypeAnnotationLocator(attributesByPath, attributesByType).visit(type, List.nil()); - // Rewrite the type and add the annotations - type = new TypeAnnotationTypeMapping(attributesByType).visit(type, null); - Assert.check(attributesByType.isEmpty(), "Failed to apply annotations to types"); + type = new TypeAnnotationStructuralTypeMapping(attributesByPath).visit(type, List.nil()); return type; } @@ -2495,120 +2490,102 @@ private static Predicate classExtends(int index) { } /** - * Visit all contained types, assembling a type path to represent the current location, and - * record the types at each type path that need to be annotated. + * A type mapping that rewrites the type to include type annotations. + * + *

This logic is similar to {@link Type.StructuralTypeMapping}, but also tracks the path to + * the contained types being rewritten, and so cannot easily share the existing logic. */ - private static class TypeAnnotationLocator - extends Types.DefaultTypeVisitor> { + private static final class TypeAnnotationStructuralTypeMapping + extends Types.TypeMapping> { + private final Map, - ListBuffer> attributesByPath; - private final Map> attributesByType; + ListBuffer> attributesByPath; - private TypeAnnotationLocator( + private TypeAnnotationStructuralTypeMapping( Map, ListBuffer> - attributesByPath, - Map> attributesByType) { + attributesByPath) { this.attributesByPath = attributesByPath; - this.attributesByType = attributesByType; } + @Override - public Void visitClassType(ClassType t, List path) { + public Type visitClassType(ClassType t, List path) { // As described in JVMS 4.7.20.2, type annotations on nested types are located with // 'left-to-right' steps starting on 'the outermost part of the type for which a type // annotation is admissible'. So the current path represents the outermost containing // type of the type being visited, and we add type path steps for every contained nested // type. - List enclosing = List.nil(); - for (Type curr = t; - curr != null && curr != Type.noType; + Type outer = t.getEnclosingType(); + Type outer1 = outer != Type.noType ? visit(outer, path) : outer; + for (Type curr = t.getEnclosingType(); + curr != Type.noType; curr = curr.getEnclosingType()) { - enclosing = enclosing.prepend((ClassType) curr); - } - for (ClassType te : enclosing) { - if (te.typarams_field != null) { - int i = 0; - for (Type typaram : te.typarams_field) { - visit(typaram, path.append(new TypeAnnotationPosition.TypePathEntry( - TypeAnnotationPosition.TypePathEntryKind.TYPE_ARGUMENT, i++))); - } - } - visitType(te, path); path = path.append(TypeAnnotationPosition.TypePathEntry.INNER_TYPE); } - return null; + List typarams = t.getTypeArguments(); + List typarams1 = rewriteTypeParams(path, typarams); + if (outer1 != outer || typarams != typarams1) { + t = new ClassType(outer1, typarams1, t.tsym, t.getMetadata()); + } + return reannotate(t, path); } - @Override - public Void visitWildcardType( - WildcardType t, List path) { - visit(t.type, path.append(TypeAnnotationPosition.TypePathEntry.WILDCARD)); - return super.visitWildcardType(t, path); + private List rewriteTypeParams( + List path, List typarams) { + var i = IntStream.iterate(0, x -> x + 1).iterator(); + return typarams.map(typaram -> visit(typaram, + path.append(new TypeAnnotationPosition.TypePathEntry( + TypeAnnotationPosition.TypePathEntryKind.TYPE_ARGUMENT, i.nextInt())))); } @Override - public Void visitArrayType(ArrayType t, List path) { - visit(t.elemtype, path.append(TypeAnnotationPosition.TypePathEntry.ARRAY)); - return super.visitArrayType(t, path); + public Type visitWildcardType( + WildcardType wt, List path) { + Type t = wt.type; + if (t != null) { + t = visit(t, path.append(TypeAnnotationPosition.TypePathEntry.WILDCARD)); + } + if (t != wt.type) { + wt = new WildcardType(t, wt.kind, wt.tsym, wt.bound, wt.getMetadata()); + } + return reannotate(wt, path); } @Override - public Void visitType(Type t, List path) { - ListBuffer attributes = attributesByPath.remove(path); - if (attributes != null) { - attributesByType.put(t, attributes.toList()); + public Type visitArrayType(ArrayType t, List path) { + Type elemtype = t.elemtype; + Type elemtype1 = + visit(elemtype, path.append(TypeAnnotationPosition.TypePathEntry.ARRAY)); + if (elemtype1 != elemtype) { + t = new ArrayType(elemtype1, t.tsym, t.getMetadata()); } - return null; + return reannotate(t, path); } - } - - /** A type mapping that rewrites the type to include type annotations. */ - private static class TypeAnnotationTypeMapping extends Type.StructuralTypeMapping { - private final Map> attributesByType; - - private TypeAnnotationTypeMapping( - Map> attributesByType) { - this.attributesByType = attributesByType; + @Override + public Type visitType(Type t, List path) { + return reannotate(t, path); } - private Type reannotate(T t, BiFunction f) { - // We're relying on object identify of Type instances to record where the annotations - // need to be added, so we have to retrieve the annotations for each type before - // rewriting it, and then add them after its contained types have been rewritten. - List attributes = attributesByType.remove(t); - Type mapped = f.apply(t, null); - if (attributes == null) { - return mapped; + Type reannotate(Type type, List path) { + List attributes = attributesForPath(path); + if (attributes.isEmpty()) { + return type; } // Runtime-visible and -invisible annotations are completed separately, so if the same // type has annotations from both it will get annotated twice. - TypeMetadata.Annotations existing = mapped.getMetadata(TypeMetadata.Annotations.class); + TypeMetadata.Annotations existing = type.getMetadata(TypeMetadata.Annotations.class); if (existing != null) { existing.annotationBuffer().addAll(attributes); - return mapped; + return type; } - return mapped.annotatedType(attributes); + return type.annotatedType(attributes); } - @Override - public Type visitClassType(ClassType t, Void unused) { - return reannotate(t, super::visitClassType); - } - - @Override - public Type visitWildcardType(WildcardType t, Void unused) { - return reannotate(t, super::visitWildcardType); - } - - @Override - public Type visitArrayType(ArrayType t, Void unused) { - return reannotate(t, super::visitArrayType); - } - - @Override - public Type visitType(Type t, Void unused) { - return reannotate(t, (x, u) -> x); + List attributesForPath( + List path) { + ListBuffer attributes = attributesByPath.remove(path); + return attributes != null ? attributes.toList() : List.nil(); } } diff --git a/test/langtools/tools/javac/processing/model/type/BasicAnnoTests.java b/test/langtools/tools/javac/processing/model/type/BasicAnnoTests.java index d45edc8e3d6..acd91eac8c7 100644 --- a/test/langtools/tools/javac/processing/model/type/BasicAnnoTests.java +++ b/test/langtools/tools/javac/processing/model/type/BasicAnnoTests.java @@ -717,4 +717,8 @@ private class GenericNested { GenericNested(@TA(120) GenericInner120 GenericInner120.this) {} } } + + @Test(posn=1, annoType=TA.class, expect="130") + @Test(posn=23, annoType=TA.class, expect="131") + public Map<@TA(130) String, @TA(131) String> f130; } From 99edb4a45d6a4a871dec9c07b41b3ab66b89a4b6 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Mon, 12 Aug 2024 17:20:20 +0000 Subject: [PATCH 380/460] 8337702: Use new ForwardExceptionNode to call StubRoutines::forward_exception_entry() Reviewed-by: thartmann --- src/hotspot/cpu/aarch64/aarch64.ad | 13 ++++++++ src/hotspot/cpu/arm/arm.ad | 14 +++++++++ src/hotspot/cpu/ppc/ppc.ad | 15 +++++++++ src/hotspot/cpu/riscv/riscv.ad | 16 ++++++++++ src/hotspot/cpu/s390/s390.ad | 14 +++++++++ src/hotspot/cpu/x86/x86_32.ad | 12 ++++++++ src/hotspot/cpu/x86/x86_64.ad | 12 ++++++++ src/hotspot/share/adlc/formssel.cpp | 34 ++++++++++++--------- src/hotspot/share/opto/callnode.hpp | 11 +++++++ src/hotspot/share/opto/classes.hpp | 1 + src/hotspot/share/opto/domgraph.cpp | 1 + src/hotspot/share/opto/gcm.cpp | 5 ++- src/hotspot/share/opto/generateOptoStub.cpp | 14 ++++----- src/hotspot/share/opto/matcher.cpp | 15 ++++++++- src/hotspot/share/runtime/vmStructs.cpp | 1 + 15 files changed, 153 insertions(+), 25 deletions(-) diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index d8db75961d8..66a24a61f29 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -16184,6 +16184,19 @@ instruct TailjmpInd(iRegPNoSpNoRfp jump_target, iRegP_R0 ex_oop) ins_pipe(pipe_class_call); %} +// Forward exception. +instruct ForwardExceptionjmp() +%{ + match(ForwardException); + ins_cost(CALL_COST); + + format %{ "b forward_exception_stub" %} + ins_encode %{ + __ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry())); + %} + ins_pipe(pipe_class_call); +%} + // Create exception oop: created by stack-crawling runtime code. // Created exception is now available to this handler, and is setup // just prior to jumping to this handler. No code emitted. diff --git a/src/hotspot/cpu/arm/arm.ad b/src/hotspot/cpu/arm/arm.ad index 638c48ad5aa..2c7de0a58a2 100644 --- a/src/hotspot/cpu/arm/arm.ad +++ b/src/hotspot/cpu/arm/arm.ad @@ -8953,6 +8953,20 @@ instruct tailjmpInd(IPRegP jump_target, RExceptionRegP ex_oop) %{ ins_pipe(tail_call); %} +// Forward exception. +instruct ForwardExceptionjmp() +%{ + match(ForwardException); + ins_cost(CALL_COST); + + format %{ "b forward_exception_stub" %} + ins_encode %{ + // OK to trash Rtemp, because Rtemp is used by stub + __ jump(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type, Rtemp); + %} + ins_pipe(tail_call); +%} + // Create exception oop: created by stack-crawling runtime code. // Created exception is now available to this handler, and is setup // just prior to jumping to this handler. No code emitted. diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index 38485da9581..b34d3ef1501 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -14534,6 +14534,21 @@ instruct tailjmpInd(iRegPdstNoScratch jump_target, rarg1RegP ex_oop) %{ ins_pipe(pipe_class_call); %} +// Forward exception. +instruct ForwardExceptionjmp() +%{ + match(ForwardException); + ins_cost(CALL_COST); + + format %{ "Jmp forward_exception_stub" %} + ins_encode %{ + __ set_inst_mark(); + __ b64_patchable(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type); + __ clear_inst_mark(); + %} + ins_pipe(pipe_class_call); +%} + // Create exception oop: created by stack-crawling runtime code. // Created exception is now available to this handler, and is setup // just prior to jumping to this handler. No code emitted. diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 1e26c2bf142..d3e2b0549e9 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -10617,6 +10617,22 @@ instruct TailjmpInd(iRegPNoSpNoFp jump_target, iRegP_R10 ex_oop) ins_pipe(pipe_class_call); %} +// Forward exception. +instruct ForwardExceptionjmp() +%{ + match(ForwardException); + + ins_cost(BRANCH_COST); + + format %{ "j forward_exception_stub\t#@ForwardException" %} + + ins_encode %{ + __ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry())); + %} + + ins_pipe(pipe_class_call); +%} + // Create exception oop: created by stack-crawling runtime code. // Created exception is now available to this handler, and is setup // just prior to jumping to this handler. No code emitted. diff --git a/src/hotspot/cpu/s390/s390.ad b/src/hotspot/cpu/s390/s390.ad index e3dcfdb8759..4de1a4e7b7f 100644 --- a/src/hotspot/cpu/s390/s390.ad +++ b/src/hotspot/cpu/s390/s390.ad @@ -9517,6 +9517,20 @@ instruct tailjmpInd(iRegP jump_target, rarg1RegP ex_oop) %{ ins_pipe(pipe_class_dummy); %} +// Forward exception. +instruct ForwardExceptionjmp() %{ + match(ForwardException); + ins_cost(CALL_COST); + format %{ "Jmp forward_exception_stub" %} + ins_encode %{ + __ set_inst_mark(); + __ load_const_optimized(Z_R1_scratch, (address)StubRoutines::forward_exception_entry()); + __ z_br(Z_R1_scratch); + __ clear_inst_mark(); + %} + ins_pipe(pipe_class_dummy); +%} + // Create exception oop: created by stack-crawling runtime code. // Created exception is now available to this handler, and is setup // just prior to jumping to this handler. No code emitted. diff --git a/src/hotspot/cpu/x86/x86_32.ad b/src/hotspot/cpu/x86/x86_32.ad index 49a3cad37df..7aa4f6a29a1 100644 --- a/src/hotspot/cpu/x86/x86_32.ad +++ b/src/hotspot/cpu/x86/x86_32.ad @@ -13583,6 +13583,18 @@ instruct tailjmpInd(eRegP_no_EBP jump_target, eAXRegP ex_oop) %{ ins_pipe( pipe_jmp ); %} +// Forward exception. +instruct ForwardExceptionjmp() +%{ + match(ForwardException); + + format %{ "JMP forward_exception_stub" %} + ins_encode %{ + __ jump(RuntimeAddress(StubRoutines::forward_exception_entry()), noreg); + %} + ins_pipe(pipe_jmp); +%} + // Create exception oop: created by stack-crawling runtime code. // Created exception is now available to this handler, and is setup // just prior to jumping to this handler. No code emitted. diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index 1490cfa60b3..3bc4cac2f06 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -12592,6 +12592,18 @@ instruct tailjmpInd(no_rbp_RegP jump_target, rax_RegP ex_oop) ins_pipe(pipe_jmp); %} +// Forward exception. +instruct ForwardExceptionjmp() +%{ + match(ForwardException); + + format %{ "jmp forward_exception_stub" %} + ins_encode %{ + __ jump(RuntimeAddress(StubRoutines::forward_exception_entry()), noreg); + %} + ins_pipe(pipe_jmp); +%} + // Create exception oop: created by stack-crawling runtime code. // Created exception is now available to this handler, and is setup // just prior to jumping to this handler. No code emitted. diff --git a/src/hotspot/share/adlc/formssel.cpp b/src/hotspot/share/adlc/formssel.cpp index be97547f8ce..e7df38ff221 100644 --- a/src/hotspot/share/adlc/formssel.cpp +++ b/src/hotspot/share/adlc/formssel.cpp @@ -210,15 +210,16 @@ bool InstructForm::is_pinned(FormDict &globals) { if ( ! _matrule) return false; int index = 0; - if (_matrule->find_type("Goto", index)) return true; - if (_matrule->find_type("If", index)) return true; - if (_matrule->find_type("CountedLoopEnd",index)) return true; - if (_matrule->find_type("Return", index)) return true; - if (_matrule->find_type("Rethrow", index)) return true; - if (_matrule->find_type("TailCall", index)) return true; - if (_matrule->find_type("TailJump", index)) return true; - if (_matrule->find_type("Halt", index)) return true; - if (_matrule->find_type("Jump", index)) return true; + if (_matrule->find_type("Goto", index)) return true; + if (_matrule->find_type("If", index)) return true; + if (_matrule->find_type("CountedLoopEnd", index)) return true; + if (_matrule->find_type("Return", index)) return true; + if (_matrule->find_type("Rethrow", index)) return true; + if (_matrule->find_type("TailCall", index)) return true; + if (_matrule->find_type("TailJump", index)) return true; + if (_matrule->find_type("ForwardException", index)) return true; + if (_matrule->find_type("Halt", index)) return true; + if (_matrule->find_type("Jump", index)) return true; return is_parm(globals); } @@ -228,12 +229,13 @@ bool InstructForm::is_projection(FormDict &globals) { if ( ! _matrule) return false; int index = 0; - if (_matrule->find_type("Goto", index)) return true; - if (_matrule->find_type("Return", index)) return true; - if (_matrule->find_type("Rethrow", index)) return true; - if (_matrule->find_type("TailCall",index)) return true; - if (_matrule->find_type("TailJump",index)) return true; - if (_matrule->find_type("Halt", index)) return true; + if (_matrule->find_type("Goto", index)) return true; + if (_matrule->find_type("Return", index)) return true; + if (_matrule->find_type("Rethrow", index)) return true; + if (_matrule->find_type("TailCall", index)) return true; + if (_matrule->find_type("TailJump", index)) return true; + if (_matrule->find_type("ForwardException", index)) return true; + if (_matrule->find_type("Halt", index)) return true; return false; } @@ -376,6 +378,7 @@ bool InstructForm::is_ideal_return() const { if (_matrule->find_type("Rethrow",index)) return true; if (_matrule->find_type("TailCall",index)) return true; if (_matrule->find_type("TailJump",index)) return true; + if (_matrule->find_type("ForwardException", index)) return true; return false; } @@ -894,6 +897,7 @@ uint InstructForm::oper_input_base(FormDict &globals) { strcmp(_matrule->_opType,"Rethrow" )==0 || strcmp(_matrule->_opType,"TailCall" )==0 || strcmp(_matrule->_opType,"TailJump" )==0 || + strcmp(_matrule->_opType,"ForwardException")==0 || strcmp(_matrule->_opType,"SafePoint" )==0 || strcmp(_matrule->_opType,"Halt" )==0 ) return AdlcVMDeps::Parms; // Skip the machine-state edges diff --git a/src/hotspot/share/opto/callnode.hpp b/src/hotspot/share/opto/callnode.hpp index 120bb112ec5..2d3835b71ad 100644 --- a/src/hotspot/share/opto/callnode.hpp +++ b/src/hotspot/share/opto/callnode.hpp @@ -152,6 +152,17 @@ class RethrowNode : public Node { }; +//------------------------------ForwardExceptionNode--------------------------- +// Pop stack frame and jump to StubRoutines::forward_exception_entry() +class ForwardExceptionNode : public ReturnNode { +public: + ForwardExceptionNode(Node* cntrl, Node* i_o, Node* memory, Node* frameptr, Node* retadr) + : ReturnNode(TypeFunc::Parms, cntrl, i_o, memory, frameptr, retadr) { + } + + virtual int Opcode() const; +}; + //------------------------------TailCallNode----------------------------------- // Pop stack frame and jump indirect class TailCallNode : public ReturnNode { diff --git a/src/hotspot/share/opto/classes.hpp b/src/hotspot/share/opto/classes.hpp index dc613776873..8bee6279446 100644 --- a/src/hotspot/share/opto/classes.hpp +++ b/src/hotspot/share/opto/classes.hpp @@ -184,6 +184,7 @@ macro(FastLock) macro(FastUnlock) macro(FmaD) macro(FmaF) +macro(ForwardException) macro(Goto) macro(Halt) macro(CountPositives) diff --git a/src/hotspot/share/opto/domgraph.cpp b/src/hotspot/share/opto/domgraph.cpp index 363005d1181..84f83ef131b 100644 --- a/src/hotspot/share/opto/domgraph.cpp +++ b/src/hotspot/share/opto/domgraph.cpp @@ -239,6 +239,7 @@ uint Block_Stack::most_frequent_successor( Block *b ) { break; case Op_TailCall: case Op_TailJump: + case Op_ForwardException: case Op_Return: case Op_Halt: case Op_Rethrow: diff --git a/src/hotspot/share/opto/gcm.cpp b/src/hotspot/share/opto/gcm.cpp index 23ae8cbcb6b..3880bea07d7 100644 --- a/src/hotspot/share/opto/gcm.cpp +++ b/src/hotspot/share/opto/gcm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2031,6 +2031,7 @@ float Block::succ_prob(uint i) { case Op_TailCall: case Op_TailJump: + case Op_ForwardException: case Op_Return: case Op_Halt: case Op_Rethrow: @@ -2084,6 +2085,7 @@ int Block::num_fall_throughs() { case Op_NeverBranch: case Op_TailCall: case Op_TailJump: + case Op_ForwardException: case Op_Return: case Op_Halt: case Op_Rethrow: @@ -2129,6 +2131,7 @@ bool Block::succ_fall_through(uint i) { case Op_NeverBranch: case Op_TailCall: case Op_TailJump: + case Op_ForwardException: case Op_Return: case Op_Halt: case Op_Rethrow: diff --git a/src/hotspot/share/opto/generateOptoStub.cpp b/src/hotspot/share/opto/generateOptoStub.cpp index 9bd7d42a3f9..e22f484c179 100644 --- a/src/hotspot/share/opto/generateOptoStub.cpp +++ b/src/hotspot/share/opto/generateOptoStub.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -255,13 +255,11 @@ void GraphKit::gen_stub(address C_function, Node* if_not_null = _gvn.transform( new IfTrueNode(iff) ); assert (StubRoutines::forward_exception_entry() != nullptr, "must be generated before"); - Node *exc_target = makecon(TypeRawPtr::make( StubRoutines::forward_exception_entry() )); - Node *to_exc = new TailCallNode(if_not_null, - i_o(), - exit_memory, - frameptr(), - returnadr(), - exc_target, null()); + Node *to_exc = new ForwardExceptionNode(if_not_null, + i_o(), + exit_memory, + frameptr(), + returnadr()); root()->add_req(_gvn.transform(to_exc)); // bind to root to keep live C->init_start(start); diff --git a/src/hotspot/share/opto/matcher.cpp b/src/hotspot/share/opto/matcher.cpp index 4e2306602e6..bf773d43d3d 100644 --- a/src/hotspot/share/opto/matcher.cpp +++ b/src/hotspot/share/opto/matcher.cpp @@ -804,6 +804,10 @@ void Matcher::Fixup_Save_On_Entry( ) { if (ret_edge_cnt > TypeFunc::Parms) ret_rms[TypeFunc::Parms+0] = _return_value_mask; + // Input RegMask array shared by all ForwardExceptions + uint forw_exc_edge_cnt = TypeFunc::Parms; + RegMask* forw_exc_rms = init_input_masks( forw_exc_edge_cnt + soe_cnt, _return_addr_mask, c_frame_ptr_mask ); + // Input RegMask array shared by all Rethrows. uint reth_edge_cnt = TypeFunc::Parms+1; RegMask *reth_rms = init_input_masks( reth_edge_cnt + soe_cnt, _return_addr_mask, c_frame_ptr_mask ); @@ -863,6 +867,7 @@ void Matcher::Fixup_Save_On_Entry( ) { case Op_Rethrow : exit->_in_rms = reth_rms; break; case Op_TailCall : exit->_in_rms = tail_call_rms; break; case Op_TailJump : exit->_in_rms = tail_jump_rms; break; + case Op_ForwardException: exit->_in_rms = forw_exc_rms; break; case Op_Halt : exit->_in_rms = halt_rms; break; default : ShouldNotReachHere(); } @@ -882,6 +887,7 @@ void Matcher::Fixup_Save_On_Entry( ) { reth_rms [ reth_edge_cnt] = mreg2regmask[i]; tail_call_rms[tail_call_edge_cnt] = mreg2regmask[i]; tail_jump_rms[tail_jump_edge_cnt] = mreg2regmask[i]; + forw_exc_rms [ forw_exc_edge_cnt] = mreg2regmask[i]; // Halts need the SOE registers, but only in the stack as debug info. // A just-prior uncommon-trap or deoptimization will use the SOE regs. halt_rms [ halt_edge_cnt] = *idealreg2spillmask[_register_save_type[i]]; @@ -899,6 +905,7 @@ void Matcher::Fixup_Save_On_Entry( ) { reth_rms [ reth_edge_cnt].Insert(OptoReg::Name(i+1)); tail_call_rms[tail_call_edge_cnt].Insert(OptoReg::Name(i+1)); tail_jump_rms[tail_jump_edge_cnt].Insert(OptoReg::Name(i+1)); + forw_exc_rms [ forw_exc_edge_cnt].Insert(OptoReg::Name(i+1)); halt_rms [ halt_edge_cnt].Insert(OptoReg::Name(i+1)); mproj = new MachProjNode( start, proj_cnt, ret_rms[ret_edge_cnt], Op_RegD ); proj_cnt += 2; // Skip 2 for doubles @@ -911,6 +918,7 @@ void Matcher::Fixup_Save_On_Entry( ) { reth_rms [ reth_edge_cnt] = RegMask::Empty; tail_call_rms[tail_call_edge_cnt] = RegMask::Empty; tail_jump_rms[tail_jump_edge_cnt] = RegMask::Empty; + forw_exc_rms [ forw_exc_edge_cnt] = RegMask::Empty; halt_rms [ halt_edge_cnt] = RegMask::Empty; mproj = C->top(); } @@ -925,6 +933,7 @@ void Matcher::Fixup_Save_On_Entry( ) { reth_rms [ reth_edge_cnt].Insert(OptoReg::Name(i+1)); tail_call_rms[tail_call_edge_cnt].Insert(OptoReg::Name(i+1)); tail_jump_rms[tail_jump_edge_cnt].Insert(OptoReg::Name(i+1)); + forw_exc_rms [ forw_exc_edge_cnt].Insert(OptoReg::Name(i+1)); halt_rms [ halt_edge_cnt].Insert(OptoReg::Name(i+1)); mproj = new MachProjNode( start, proj_cnt, ret_rms[ret_edge_cnt], Op_RegL ); proj_cnt += 2; // Skip 2 for longs @@ -937,6 +946,7 @@ void Matcher::Fixup_Save_On_Entry( ) { reth_rms [ reth_edge_cnt] = RegMask::Empty; tail_call_rms[tail_call_edge_cnt] = RegMask::Empty; tail_jump_rms[tail_jump_edge_cnt] = RegMask::Empty; + forw_exc_rms [ forw_exc_edge_cnt] = RegMask::Empty; halt_rms [ halt_edge_cnt] = RegMask::Empty; mproj = C->top(); } else { @@ -948,11 +958,13 @@ void Matcher::Fixup_Save_On_Entry( ) { reth_edge_cnt ++; tail_call_edge_cnt ++; tail_jump_edge_cnt ++; + forw_exc_edge_cnt++; halt_edge_cnt ++; // Add a use of the SOE register to all exit paths - for( uint j=1; j < root->req(); j++ ) + for (uint j=1; j < root->req(); j++) { root->in(j)->add_req(mproj); + } } // End of if a save-on-entry register } // End of for all machine registers } @@ -1070,6 +1082,7 @@ static void match_alias_type(Compile* C, Node* n, Node* m) { case Op_Halt: case Op_TailCall: case Op_TailJump: + case Op_ForwardException: nidx = Compile::AliasIdxBot; nat = TypePtr::BOTTOM; break; diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 4b6381bd05e..27dc10d2adb 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -1422,6 +1422,7 @@ declare_c2_type(RethrowNode, Node) \ declare_c2_type(TailCallNode, ReturnNode) \ declare_c2_type(TailJumpNode, ReturnNode) \ + declare_c2_type(ForwardExceptionNode, ReturnNode) \ declare_c2_type(SafePointNode, MultiNode) \ declare_c2_type(CallNode, SafePointNode) \ declare_c2_type(CallJavaNode, CallNode) \ From 2ca136a7adb6defaea3b7a69d30e6c36bda66e6a Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Mon, 12 Aug 2024 17:26:51 +0000 Subject: [PATCH 381/460] 8337815: Relax G1EvacStats atomic operations Reviewed-by: kbarrett, tschatzl, shade --- src/hotspot/share/gc/g1/g1EvacStats.inline.hpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1EvacStats.inline.hpp b/src/hotspot/share/gc/g1/g1EvacStats.inline.hpp index 4b4c6e104b7..d4cae1f9836 100644 --- a/src/hotspot/share/gc/g1/g1EvacStats.inline.hpp +++ b/src/hotspot/share/gc/g1/g1EvacStats.inline.hpp @@ -30,25 +30,25 @@ #include "runtime/atomic.hpp" inline void G1EvacStats::add_direct_allocated(size_t value) { - Atomic::add(&_direct_allocated, value); + Atomic::add(&_direct_allocated, value, memory_order_relaxed); } inline void G1EvacStats::add_num_plab_filled(size_t value) { - Atomic::add(&_num_plab_filled, value); + Atomic::add(&_num_plab_filled, value, memory_order_relaxed); } inline void G1EvacStats::add_num_direct_allocated(size_t value) { - Atomic::add(&_num_direct_allocated, value); + Atomic::add(&_num_direct_allocated, value, memory_order_relaxed); } inline void G1EvacStats::add_region_end_waste(size_t value) { - Atomic::add(&_region_end_waste, value); - Atomic::inc(&_regions_filled); + Atomic::add(&_region_end_waste, value, memory_order_relaxed); + Atomic::inc(&_regions_filled, memory_order_relaxed); } inline void G1EvacStats::add_failure_used_and_waste(size_t used, size_t waste) { - Atomic::add(&_failure_used, used); - Atomic::add(&_failure_waste, waste); + Atomic::add(&_failure_used, used, memory_order_relaxed); + Atomic::add(&_failure_waste, waste, memory_order_relaxed); } #endif // SHARE_GC_G1_G1EVACSTATS_INLINE_HPP From 41e31d6b0ae00d70b6fb20c89318fde2bc605edb Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Mon, 12 Aug 2024 17:56:46 +0000 Subject: [PATCH 382/460] 8337622: IllegalArgumentException in java.lang.reflect.Field.get Reviewed-by: dholmes, shade --- src/hotspot/share/classfile/javaClasses.cpp | 7 --- src/hotspot/share/classfile/javaClasses.hpp | 1 + .../reflect/ComponentTypeFieldTest.java | 50 +++++++++++++++++++ 3 files changed, 51 insertions(+), 7 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/reflect/ComponentTypeFieldTest.java diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index ab9460e2b9b..8a6c8a8ce0b 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -1452,19 +1452,12 @@ void java_lang_Class::compute_offsets() { InstanceKlass* k = vmClasses::Class_klass(); CLASS_FIELDS_DO(FIELD_COMPUTE_OFFSET); - - // Init lock is a C union with component_mirror. Only instanceKlass mirrors have - // init_lock and only ArrayKlass mirrors have component_mirror. Since both are oops - // GC treats them the same. - _init_lock_offset = _component_mirror_offset; - CLASS_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET); } #if INCLUDE_CDS void java_lang_Class::serialize_offsets(SerializeClosure* f) { f->do_bool(&_offsets_computed); - f->do_u4((u4*)&_init_lock_offset); CLASS_FIELDS_DO(FIELD_SERIALIZE_OFFSET); diff --git a/src/hotspot/share/classfile/javaClasses.hpp b/src/hotspot/share/classfile/javaClasses.hpp index 57914e189b7..eb3c5e29fdb 100644 --- a/src/hotspot/share/classfile/javaClasses.hpp +++ b/src/hotspot/share/classfile/javaClasses.hpp @@ -209,6 +209,7 @@ class java_lang_String : AllStatic { macro(java_lang_Class, static_oop_field_count, int_signature, false) \ macro(java_lang_Class, protection_domain, object_signature, false) \ macro(java_lang_Class, source_file, object_signature, false) \ + macro(java_lang_Class, init_lock, object_signature, false) class java_lang_Class : AllStatic { friend class VMStructs; diff --git a/test/hotspot/jtreg/runtime/reflect/ComponentTypeFieldTest.java b/test/hotspot/jtreg/runtime/reflect/ComponentTypeFieldTest.java new file mode 100644 index 00000000000..6296a7f970e --- /dev/null +++ b/test/hotspot/jtreg/runtime/reflect/ComponentTypeFieldTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8337622 + * @summary (reflect) java.lang.Class componentType field not found. + * @library /test/lib + * @modules java.base/java.lang:open + * @run main ComponentTypeFieldTest + */ + +import java.lang.reflect.Field; +import static jdk.test.lib.Asserts.*; + +public class ComponentTypeFieldTest { + + public static void main(String[] args) throws Exception { + Field f = Class.class.getDeclaredField("componentType"); + f.setAccessible(true); + Object val = f.get(Runnable.class); + assertTrue(val == null); + System.out.println("val is " + val); + + Object arrayVal = f.get(Integer[].class); + System.out.println("val is " + arrayVal); + String arrayValString = arrayVal.toString(); + assertTrue(arrayValString.equals("class java.lang.Integer")); + } +} From b93b74e3ebd220e94fb5e33d2ebc62181db97bb0 Mon Sep 17 00:00:00 2001 From: Roger Riggs Date: Mon, 12 Aug 2024 19:28:46 +0000 Subject: [PATCH 383/460] 8338060: jdk/internal/util/ReferencedKeyTest should be more robust Reviewed-by: never --- .../jdk/internal/util/ReferencedKeyTest.java | 130 ++++++++++-------- 1 file changed, 76 insertions(+), 54 deletions(-) diff --git a/test/jdk/jdk/internal/util/ReferencedKeyTest.java b/test/jdk/jdk/internal/util/ReferencedKeyTest.java index 75690fa6e25..c68908a8d5a 100644 --- a/test/jdk/jdk/internal/util/ReferencedKeyTest.java +++ b/test/jdk/jdk/internal/util/ReferencedKeyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8285932 8310913 + * @bug 8285932 8310913 8336390 8338060 * @summary Test features provided by the ReferencedKeyMap/ReferencedKeySet classes. * @modules java.base/jdk.internal.util * @compile --patch-module java.base=${test.src} ReferencedKeyTest.java @@ -36,14 +36,27 @@ import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.function.BooleanSupplier; +import java.util.function.Function; import java.util.function.Supplier; +import java.util.stream.IntStream; public class ReferencedKeyTest { - static long BASE_KEY = 10_000_000L; + private static String BASE_KEY = "BASEKEY-"; + + // Return a String (identity object) that can be a key in WeakHashMap. + private static String genKey(int i) { + return BASE_KEY + i; + } + + // Return a String of the letter 'a' plus the integer (0..0xffff) + private static String genValue(int i) { + return String.valueOf((char) ('a' + i)); + } public static void main(String[] args) { mapTest(false, HashMap::new); @@ -63,73 +76,77 @@ static void assertTrue(boolean test, String message) { } } - static void mapTest(boolean isSoft, Supplier, String>> supplier) { - Map map = ReferencedKeyMap.create(isSoft, supplier); - populate(map); + static void mapTest(boolean isSoft, Supplier, String>> supplier) { + Map map = ReferencedKeyMap.create(isSoft, supplier); + var strongKeys = populate(map); // Retain references to the keys + methods(map); + Reference.reachabilityFence(strongKeys); + + strongKeys = null; // drop strong key references if (!isSoft) { if (!collect(() -> map.isEmpty())) { throw new RuntimeException("WeakReference map not collecting!"); } } - populate(map); - methods(map); } - static void setTest(boolean isSoft, Supplier, ReferenceKey>> supplier) { - ReferencedKeySet set = ReferencedKeySet.create(isSoft, supplier); - populate(set); + static void setTest(boolean isSoft, Supplier, ReferenceKey>> supplier) { + ReferencedKeySet set = ReferencedKeySet.create(isSoft, supplier); + var strongKeys = populate(set); // Retain references to the keys + methods(set); + Reference.reachabilityFence(strongKeys); + + strongKeys = null; // drop strong key references if (!isSoft) { if (!collect(() -> set.isEmpty())) { throw new RuntimeException("WeakReference set not collecting!"); } } - populate(set); - methods(set); } - static void methods(Map map) { + static void methods(Map map) { assertTrue(map.size() == 26, "missing key"); - assertTrue(map.containsKey(BASE_KEY + 'a' -'a'), "missing key"); - assertTrue(map.get(BASE_KEY + 'b' -'a').equals("b"), "wrong key"); + assertTrue(map.containsKey(genKey('a' -'a')), "missing key"); + assertTrue(map.get(genKey('b' -'a')).equals("b"), "wrong key"); assertTrue(map.containsValue("c"), "missing value"); - map.remove(BASE_KEY + 'd' -'a'); - assertTrue(map.get(BASE_KEY + 'd' -'a') == null, "not removed"); - map.putAll(Map.of(1L, "A", 2L, "B")); - assertTrue(map.get(2L).equals("B"), "collection not added"); - assertTrue(map.containsKey(1L), "key missing"); + map.remove(genKey('d' -'a')); + assertTrue(map.get(genKey('d' -'a')) == null, "not removed"); + map.putAll(Map.of(genKey(1), "A", genKey(2), "B")); + assertTrue(map.get(genKey(2)).equals("B"), "collection not added"); + assertTrue(map.containsKey(genKey(1)), "key missing"); assertTrue(map.containsValue("A"), "key missing"); - assertTrue(map.entrySet().contains(Map.entry(1L, "A")), "key missing"); - map.putIfAbsent(3L, "C"); - assertTrue(map.get(3L).equals("C"), "key missing"); - map.putIfAbsent(2L, "D"); - assertTrue(map.get(2L).equals("B"), "key replaced"); - map.remove(3L); - assertTrue(map.get(3L) == null, "key not removed"); - map.replace(2L, "D"); - assertTrue(map.get(2L).equals("D"), "key not replaced"); - map.replace(2L, "B", "E"); - assertTrue(map.get(2L).equals("D"), "key replaced"); + assertTrue(map.entrySet().contains(Map.entry(genKey(1), "A")), "key missing"); + map.putIfAbsent(genKey(3), "C"); + assertTrue(map.get(genKey(3)).equals("C"), "key missing"); + map.putIfAbsent(genKey(2), "D"); + assertTrue(map.get(genKey(2)).equals("B"), "key replaced"); + map.remove(genKey(3)); + assertTrue(map.get(genKey(3)) == null, "key not removed"); + map.replace(genKey(2), "D"); + assertTrue(map.get(genKey(2)).equals("D"), "key not replaced"); + map.replace(genKey(2), "B", "E"); + assertTrue(map.get(genKey(2)).equals("D"), "key replaced"); } - static void methods(ReferencedKeySet set) { + static void methods(ReferencedKeySet set) { assertTrue(set.size() == 26, "missing key"); - assertTrue(set.contains(BASE_KEY + 3), "missing key"); - set.remove(BASE_KEY + 3); - assertTrue(!set.contains(BASE_KEY + 3), "not removed"); - Long element1 = set.get(BASE_KEY + 2); - Long element2 = set.get(BASE_KEY + 3); - Long element3 = set.get(BASE_KEY + 4); - Long intern1 = set.intern(BASE_KEY + 2); - Long intern2 = set.intern(BASE_KEY + 3); - Long intern3 = set.intern(BASE_KEY + 4, e -> e); + assertTrue(set.contains(genKey(3)), "missing key"); + set.remove(genKey(3)); + assertTrue(!set.contains(genKey(3)), "not removed"); + String element1 = set.get(genKey(2)); + String element2 = set.get(genKey(3)); + String element3 = set.get(genKey(4)); + String intern1 = set.intern(genKey(2)); + String intern2 = set.intern(genKey(3)); + String intern3 = set.intern(genKey(4), e -> e); assertTrue(element1 != null, "missing key"); assertTrue(element2 == null, "not removed"); assertTrue(element1 == intern1, "intern failed"); // must be same object assertTrue(intern2 != null, "intern failed"); assertTrue(element3 == intern3, "intern failed"); - Long value1 = Long.valueOf(BASE_KEY + 999); - Long value2 = Long.valueOf(BASE_KEY + 999); + String value1 = genKey(999); + String value2 = genKey(999); assertTrue(set.add(value1), "key not added"); assertTrue(!set.add(value1), "key added after second attempt"); assertTrue(!set.add(value2), "key should not have been added"); @@ -164,18 +181,23 @@ static boolean collect(BooleanSupplier booleanSupplier) { return booleanSupplier.getAsBoolean(); } - static void populate(Map map) { - for (int i = 0; i < 26; i++) { - Long key = BASE_KEY + i; - String value = String.valueOf((char) ('a' + i)); - map.put(key, value); + static List populate(Map map) { + var keyRefs = genStrings(0, 26, ReferencedKeyTest::genKey); + var valueRefs = genStrings(0, 26, ReferencedKeyTest::genValue); + for (int i = 0; i < keyRefs.size(); i++) { + map.put(keyRefs.get(i), valueRefs.get(i)); } + return keyRefs; } - static void populate(Set set) { - for (int i = 0; i < 26; i++) { - Long value = BASE_KEY + i; - set.add(value); - } + static List populate(Set set) { + var keyRefs = genStrings(0, 26, ReferencedKeyTest::genKey); + set.addAll(keyRefs); + return keyRefs; + } + + // Generate a List of consecutive strings using a function int -> String + static List genStrings(int min, int maxExclusive, Function genString) { + return IntStream.range(min, maxExclusive).mapToObj(i -> genString.apply(i)).toList(); } } From 4417c276e484c1fe137ed7f4a7c28709d0c99af2 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Mon, 12 Aug 2024 19:43:36 +0000 Subject: [PATCH 384/460] 8330535: Update nsk/jdb tests to use driver instead of othervm Reviewed-by: cjplummer --- .../caught_exception002/caught_exception002.java | 10 +++------- .../nsk/jdb/classes/classes001/classes001.java | 10 +++------- .../jdb/classpath/classpath001/classpath001.java | 10 +++------- .../vmTestbase/nsk/jdb/clear/clear002/clear002.java | 10 +++------- .../vmTestbase/nsk/jdb/clear/clear003/clear003.java | 10 +++------- .../vmTestbase/nsk/jdb/clear/clear004/clear004.java | 8 ++------ .../vmTestbase/nsk/jdb/down/down002/down002.java | 10 +++------- .../vmTestbase/nsk/jdb/dump/dump002/dump002.java | 10 +++------- .../vmTestbase/nsk/jdb/eval/eval001/eval001.java | 10 +++------- .../nsk/jdb/exclude/exclude001/exclude001.java | 10 +++------- .../nsk/jdb/fields/fields001/fields001.java | 10 +++------- .../nsk/jdb/hidden_class/hc001/hc001.java | 10 +++------- .../nsk/jdb/ignore/ignore001/ignore001.java | 10 +++------- .../jdb/interrupt/interrupt001/interrupt001.java | 10 +++------- .../vmTestbase/nsk/jdb/kill/kill001/kill001.java | 10 +++------- .../vmTestbase/nsk/jdb/kill/kill002/kill002.java | 10 +++------- .../vmTestbase/nsk/jdb/klass/class001/class001.java | 10 +++------- .../vmTestbase/nsk/jdb/list/list002/list002.java | 10 +++------- .../vmTestbase/nsk/jdb/list/list003/list003.java | 11 ++++------- .../nsk/jdb/locals/locals002/locals002.java | 10 +++------- .../nsk/jdb/methods/methods002/methods002.java | 10 +++------- .../nsk/jdb/monitor/monitor001/monitor001.java | 10 +++------- .../nsk/jdb/monitor/monitor002/monitor002.java | 10 +++------- .../vmTestbase/nsk/jdb/next/next001/next001.java | 10 +++------- .../jdb/options/connect/connect001/connect001.java | 10 +++------- .../jdb/options/connect/connect002/connect002.java | 10 +++------- .../jdb/options/connect/connect003/connect003.java | 10 +++------- .../jdb/options/connect/connect004/connect004.java | 10 +++------- .../jdb/options/connect/connect005/connect005.java | 13 ++++--------- .../listconnectors001/listconnectors001.java | 10 +++------- .../jtreg/vmTestbase/nsk/jdb/pop/pop001/pop001.java | 10 +++------- .../pop_exception001/pop_exception001.java | 10 +++------- .../vmTestbase/nsk/jdb/print/print002/print002.java | 10 +++------- .../vmTestbase/nsk/jdb/read/read001/read001.java | 10 +++------- .../nsk/jdb/redefine/redefine001/redefine001.java | 10 +++------- .../nsk/jdb/reenter/reenter001/reenter001.java | 10 +++------- .../nsk/jdb/regression/b4689395/b4689395.java | 10 +++------- .../nsk/jdb/repeat/repeat001/repeat001.java | 10 +++------- .../nsk/jdb/resume/resume002/resume002.java | 10 +++------- .../jtreg/vmTestbase/nsk/jdb/run/run002/run002.java | 10 +++------- .../jtreg/vmTestbase/nsk/jdb/set/set001/set001.java | 10 +++------- .../jtreg/vmTestbase/nsk/jdb/set/set002/set002.java | 10 +++------- .../vmTestbase/nsk/jdb/step/step002/step002.java | 10 +++------- .../nsk/jdb/step_up/step_up001/step_up001.java | 10 +++------- .../nsk/jdb/stop_at/stop_at002/stop_at002.java | 8 ++------ .../nsk/jdb/stop_at/stop_at003/stop_at003.java | 10 +++------- .../nsk/jdb/stop_in/stop_in002/stop_in002.java | 10 +++------- .../nsk/jdb/suspend/suspend001/suspend001.java | 10 +++------- .../nsk/jdb/thread/thread002/thread002.java | 10 +++------- .../threadgroup/threadgroup002/threadgroup002.java | 10 +++------- .../threadgroups002/threadgroups002.java | 10 +++------- .../nsk/jdb/threads/threads002/threads002.java | 10 +++------- .../nsk/jdb/threads/threads003/threads003.java | 10 +++------- .../vmTestbase/nsk/jdb/trace/trace001/trace001.java | 10 +++------- .../uncaught_exception002.java | 10 +++------- .../jdb/unmonitor/unmonitor001/unmonitor001.java | 10 +++------- .../nsk/jdb/untrace/untrace001/untrace001.java | 10 +++------- .../nsk/jdb/unwatch/unwatch001/unwatch001.java | 10 +++------- .../nsk/jdb/unwatch/unwatch002/unwatch002.java | 10 +++------- .../jtreg/vmTestbase/nsk/jdb/up/up002/up002.java | 10 +++------- .../jtreg/vmTestbase/nsk/jdb/use/use001/use001.java | 10 +++------- .../vmTestbase/nsk/jdb/watch/watch001/watch001.java | 10 +++------- .../vmTestbase/nsk/jdb/watch/watch002/watch002.java | 10 +++------- .../vmTestbase/nsk/jdb/where/where004/where004.java | 10 +++------- .../vmTestbase/nsk/jdb/where/where005/where005.java | 10 +++------- .../vmTestbase/nsk/jdb/where/where006/where006.java | 10 +++------- .../nsk/jdb/wherei/wherei001/wherei001.java | 10 +++------- .../jtreg/vmTestbase/nsk/share/jdb/JdbTest.java | 11 +++++------ .../jtreg/vmTestbase/nsk/share/jdb/Launcher.java | 6 ++++-- 69 files changed, 210 insertions(+), 477 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/caught_exception/caught_exception002/caught_exception002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/caught_exception/caught_exception002/caught_exception002.java index 4eef7900d42..04ace5ba49c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/caught_exception/caught_exception002/caught_exception002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/caught_exception/caught_exception002/caught_exception002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.caught_exception.caught_exception002.caught_exception002a - * @run main/othervm + * @run driver * nsk.jdb.caught_exception.caught_exception002.caught_exception002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -69,14 +69,10 @@ public class caught_exception002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new caught_exception002().runTest(argv, out); + new caught_exception002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.caught_exception.caught_exception002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/classes/classes001/classes001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/classes/classes001/classes001.java index 40a5ebaa939..8543c7c6f1e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/classes/classes001/classes001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/classes/classes001/classes001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.classes.classes001.classes001a - * @run main/othervm + * @run driver * nsk.jdb.classes.classes001.classes001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -60,14 +60,10 @@ public class classes001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new classes001().runTest(argv, out); + new classes001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.classes.classes001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/classpath/classpath001/classpath001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/classpath/classpath001/classpath001.java index 0eea9a92ab2..25a86fe64cb 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/classpath/classpath001/classpath001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/classpath/classpath001/classpath001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.classpath.classpath001.classpath001a - * @run main/othervm + * @run driver * nsk.jdb.classpath.classpath001.classpath001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -59,14 +59,10 @@ public class classpath001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new classpath001().runTest(argv, out); + new classpath001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.classpath.classpath001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/clear/clear002/clear002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/clear/clear002/clear002.java index 7869a1340a7..cca80dad465 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/clear/clear002/clear002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/clear/clear002/clear002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.clear.clear002.clear002a - * @run main/othervm + * @run driver * nsk.jdb.clear.clear002.clear002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -61,14 +61,10 @@ public class clear002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new clear002().runTest(argv, out); + new clear002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.clear.clear002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/clear/clear003/clear003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/clear/clear003/clear003.java index cbbc851f29a..003b1f36edd 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/clear/clear003/clear003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/clear/clear003/clear003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2023, 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,7 +39,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.clear.clear003.clear003a - * @run main/othervm + * @run driver * nsk.jdb.clear.clear003.clear003 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -62,14 +62,10 @@ public class clear003 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new clear003().runTest(argv, out); + new clear003().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.clear.clear003"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/clear/clear004/clear004.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/clear/clear004/clear004.java index c0ec8d20370..5dfd33430e3 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/clear/clear004/clear004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/clear/clear004/clear004.java @@ -40,7 +40,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.clear.clear004.clear004a - * @run main/othervm + * @run driver * nsk.jdb.clear.clear004.clear004 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -63,14 +63,10 @@ public class clear004 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new clear004().runTest(argv, out); + new clear004().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.clear.clear004"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/down/down002/down002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/down/down002/down002.java index 29a40d9471d..99f4254891d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/down/down002/down002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/down/down002/down002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.down.down002.down002a - * @run main/othervm + * @run driver * nsk.jdb.down.down002.down002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -66,14 +66,10 @@ public class down002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new down002().runTest(argv, out); + new down002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.down.down002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/dump/dump002/dump002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/dump/dump002/dump002.java index 3e3b5b9b858..66a26e69f77 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/dump/dump002/dump002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/dump/dump002/dump002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.dump.dump002.dump002a - * @run main/othervm + * @run driver * nsk.jdb.dump.dump002.dump002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -70,15 +70,11 @@ public class dump002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; compoundPromptIdent = COMPOUND_PROMPT_IDENT; - return new dump002().runTest(argv, out); + new dump002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.dump.dump002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/eval/eval001/eval001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/eval/eval001/eval001.java index 98848ced90b..fc4fb14dd2d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/eval/eval001/eval001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/eval/eval001/eval001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,7 +52,7 @@ * @clean nsk.jdb.eval.eval001.eval001a * @compile -g:lines,source,vars eval001a.java * - * @run main/othervm + * @run driver * nsk.jdb.eval.eval001.eval001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -75,14 +75,10 @@ public class eval001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new eval001().runTest(argv, out); + new eval001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.eval.eval001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/exclude/exclude001/exclude001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/exclude/exclude001/exclude001.java index cee8ca44d58..c7805cc6c95 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/exclude/exclude001/exclude001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/exclude/exclude001/exclude001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,7 +59,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.exclude.exclude001.exclude001a - * @run main/othervm/timeout=600 + * @run driver/timeout=600 * nsk.jdb.exclude.exclude001.exclude001 * -arch=${os.family}-${os.simpleArch} * -waittime=10 @@ -82,14 +82,10 @@ public class exclude001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new exclude001().runTest(argv, out); + new exclude001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.exclude.exclude001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/fields/fields001/fields001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/fields/fields001/fields001.java index b5e2ccb58e5..c1cbba3232a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/fields/fields001/fields001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/fields/fields001/fields001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.fields.fields001.fields001a - * @run main/othervm + * @run driver * nsk.jdb.fields.fields001.fields001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -64,14 +64,10 @@ public class fields001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new fields001().runTest(argv, out); + new fields001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.fields.fields001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/hidden_class/hc001/hc001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/hidden_class/hc001/hc001.java index 5040eef9cef..a7c74e28aae 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/hidden_class/hc001/hc001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/hidden_class/hc001/hc001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ * jdk.jdwp.agent * @build nsk.jdb.hidden_class.hc001.hc001a * - * @run main/othervm + * @run driver * nsk.jdb.hidden_class.hc001.hc001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -60,13 +60,9 @@ public class hc001 extends JdbTest { static final int MAX_SLEEP_CNT = 3; public static void main(String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; // needed for JdbTest.runTest firstBreak = MAIN_METHOD_NAME; // needed for JdbTest.runTest - return new hc001().runTest(argv, out); + new hc001().runTest(argv); } static boolean checkPattern(String[] arr, String pattern) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/ignore/ignore001/ignore001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/ignore/ignore001/ignore001.java index 6eb8c91e1eb..48d256d22fc 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/ignore/ignore001/ignore001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/ignore/ignore001/ignore001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.ignore.ignore001.ignore001a - * @run main/othervm + * @run driver * nsk.jdb.ignore.ignore001.ignore001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -63,14 +63,10 @@ public class ignore001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new ignore001().runTest(argv, out); + new ignore001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.ignore.ignore001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/interrupt/interrupt001/interrupt001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/interrupt/interrupt001/interrupt001.java index 73f251b71e9..51bbdf6757a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/interrupt/interrupt001/interrupt001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/interrupt/interrupt001/interrupt001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.interrupt.interrupt001.interrupt001a - * @run main/othervm + * @run driver * nsk.jdb.interrupt.interrupt001.interrupt001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -73,13 +73,9 @@ public class interrupt001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; - return new interrupt001().runTest(argv, out); + new interrupt001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.interrupt.interrupt001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill001/kill001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill001/kill001.java index b770aafc510..a96498954b6 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill001/kill001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill001/kill001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,7 +49,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.kill.kill001.kill001a - * @run main/othervm + * @run driver * nsk.jdb.kill.kill001.kill001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -74,13 +74,9 @@ public class kill001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; - return new kill001().runTest(argv, out); + new kill001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.kill.kill001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill002/kill002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill002/kill002.java index 230dcdf12ba..ed5306346dc 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill002/kill002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill002/kill002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.kill.kill002.kill002a - * @run main/othervm + * @run driver * nsk.jdb.kill.kill002.kill002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -66,13 +66,9 @@ public class kill002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; - return new kill002().runTest(argv, out); + new kill002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.kill.kill002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/klass/class001/class001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/klass/class001/class001.java index 4c548348dc3..ee37e393f70 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/klass/class001/class001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/klass/class001/class001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.klass.class001.class001a - * @run main/othervm + * @run driver * nsk.jdb.klass.class001.class001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -63,14 +63,10 @@ public class class001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new class001().runTest(argv, out); + new class001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.klass.class001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/list/list002/list002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/list/list002/list002.java index 4180ea3bb45..38282a425ec 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/list/list002/list002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/list/list002/list002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,7 +44,7 @@ * /test/lib * @build nsk.jdb.list.list002.list002a * @run driver jdk.test.lib.FileInstaller list002a.java src/nsk/jdb/list/list002/list002a.java - * @run main/othervm + * @run driver * nsk.jdb.list.list002.list002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -68,14 +68,10 @@ public class list002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new list002().runTest(argv, out); + new list002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.list.list002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/list/list003/list003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/list/list003/list003.java index d06bf38bd85..e7d773486ee 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/list/list003/list003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/list/list003/list003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.list.list003.list003a - * @run main/othervm + * @run driver * nsk.jdb.list.list003.list003 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -47,6 +47,7 @@ * -jdb.option="-J-Duser.language=en -J-Duser.country=US" * -java.options="${test.vm.opts} ${test.java.opts}" * -workdir=. + * -jdb.option="-sourcepath ${test.src}/../../../.." * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" */ @@ -98,13 +99,9 @@ protected List parseListOutput(String[] lines) { } public static void main(String[] args) { - System.exit(run(args, System.out) + JCK_STATUS_BASE); - } - - public static int run(String[] args, PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; - return new list003().runTest(args, out); + new list003().runTest(args); } @Override diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/locals/locals002/locals002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/locals/locals002/locals002.java index 793cdc04608..09a97ff83a5 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/locals/locals002/locals002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/locals/locals002/locals002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,7 +52,7 @@ * @clean nsk.jdb.locals.locals002.locals002a * @compile -g:lines,source,vars locals002a.java * - * @run main/othervm + * @run driver * nsk.jdb.locals.locals002.locals002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -75,15 +75,11 @@ public class locals002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; compoundPromptIdent = COMPOUND_PROMPT_IDENT; - return new locals002().runTest(argv, out); + new locals002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.locals.locals002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/methods/methods002/methods002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/methods/methods002/methods002.java index 2bacbab101b..ef480d52c03 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/methods/methods002/methods002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/methods/methods002/methods002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.methods.methods002.methods002a - * @run main/othervm + * @run driver * nsk.jdb.methods.methods002.methods002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -73,14 +73,10 @@ public class methods002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new methods002().runTest(argv, out); + new methods002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.methods.methods002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/monitor/monitor001/monitor001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/monitor/monitor001/monitor001.java index 1fd1f8c328b..94cac5ca787 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/monitor/monitor001/monitor001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/monitor/monitor001/monitor001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.monitor.monitor001.monitor001a - * @run main/othervm + * @run driver * nsk.jdb.monitor.monitor001.monitor001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -69,14 +69,10 @@ public class monitor001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new monitor001().runTest(argv, out); + new monitor001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.monitor.monitor001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/monitor/monitor002/monitor002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/monitor/monitor002/monitor002.java index 53c856128ce..790eb746916 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/monitor/monitor002/monitor002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/monitor/monitor002/monitor002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.monitor.monitor002.monitor002a - * @run main/othervm + * @run driver * nsk.jdb.monitor.monitor002.monitor002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -65,14 +65,10 @@ public class monitor002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new monitor002().runTest(argv, out); + new monitor002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.monitor.monitor002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/next/next001/next001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/next/next001/next001.java index 206199f0bb3..3d0c810b5c4 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/next/next001/next001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/next/next001/next001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.next.next001.next001a - * @run main/othervm + * @run driver * nsk.jdb.next.next001.next001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -69,14 +69,10 @@ public class next001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new next001().runTest(argv, out); + new next001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.next.next001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect001/connect001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect001/connect001.java index a78f3a96db4..85cdbb27997 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect001/connect001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect001/connect001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.options.connect.connect001.connect001a - * @run main/othervm + * @run driver * nsk.jdb.options.connect.connect001.connect001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -71,14 +71,10 @@ public class connect001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new connect001().runTest(argv, out); + new connect001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.options.connect.connect001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect002/connect002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect002/connect002.java index 78bcf2fb973..a3219de0cc4 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect002/connect002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect002/connect002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.options.connect.connect002.connect002a - * @run main/othervm + * @run driver * nsk.jdb.options.connect.connect002.connect002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -71,14 +71,10 @@ public class connect002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new connect002().runTest(argv, out); + new connect002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.options.connect.connect002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect003/connect003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect003/connect003.java index 701f611d2ff..465e3c9deb2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect003/connect003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect003/connect003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.options.connect.connect003.connect003a - * @run main/othervm + * @run driver * nsk.jdb.options.connect.connect003.connect003 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -71,14 +71,10 @@ public class connect003 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new connect003().runTest(argv, out); + new connect003().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.options.connect.connect003"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect004/connect004.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect004/connect004.java index adaa58627dd..075e9c30268 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect004/connect004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect004/connect004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.options.connect.connect004.connect004a - * @run main/othervm + * @run driver * nsk.jdb.options.connect.connect004.connect004 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -71,14 +71,10 @@ public class connect004 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new connect004().runTest(argv, out); + new connect004().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.options.connect.connect004"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect005/connect005.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect005/connect005.java index 8a670392466..7bd44a5927c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect005/connect005.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect005/connect005.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.options.connect.connect005.connect005a - * @run main/othervm + * @run driver * nsk.jdb.options.connect.connect005.connect005 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -70,15 +70,10 @@ public class connect005 extends JdbTest { - public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { - debuggeeClass = DEBUGGEE_CLASS; + public static void main (String argv[]) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new connect005().runTest(argv, out); + new connect005().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.options.connect.connect005"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/listconnectors/listconnectors001/listconnectors001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/listconnectors/listconnectors001/listconnectors001.java index d814df91cc6..b4961be11ee 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/listconnectors/listconnectors001/listconnectors001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/listconnectors/listconnectors001/listconnectors001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,7 +51,7 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm + * @run driver * nsk.jdb.options.listconnectors.listconnectors001.listconnectors001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -75,14 +75,10 @@ public class listconnectors001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new listconnectors001().runTest(argv, out); + new listconnectors001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.options.connect"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/pop/pop001/pop001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/pop/pop001/pop001.java index e449a5771f2..c508538fa1e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/pop/pop001/pop001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/pop/pop001/pop001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.pop.pop001.pop001a - * @run main/othervm + * @run driver * nsk.jdb.pop.pop001.pop001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -70,14 +70,10 @@ public class pop001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new pop001().runTest(argv, out); + new pop001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.pop.pop001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/pop_exception/pop_exception001/pop_exception001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/pop_exception/pop_exception001/pop_exception001.java index f70a5ffb960..49921cd26cc 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/pop_exception/pop_exception001/pop_exception001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/pop_exception/pop_exception001/pop_exception001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.pop_exception.pop_exception001.pop_exception001a - * @run main/othervm + * @run driver * nsk.jdb.pop_exception.pop_exception001.pop_exception001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -63,14 +63,10 @@ public class pop_exception001 extends JdbTest { static final String LAST_BREAK = DEBUGGEE_CLASS + ".lastBreak"; public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new pop_exception001().runTest(argv, out); + new pop_exception001().runTest(argv); } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/print/print002/print002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/print/print002/print002.java index e339a0a321b..1993c1f4d95 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/print/print002/print002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/print/print002/print002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,7 +52,7 @@ * @clean nsk.jdb.print.print002.print002a * @compile -g:lines,source,vars print002a.java * - * @run main/othervm + * @run driver * nsk.jdb.print.print002.print002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -75,14 +75,10 @@ public class print002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new print002().runTest(argv, out); + new print002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.print.print002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/read/read001/read001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/read/read001/read001.java index b5ca64334d7..60c80139a65 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/read/read001/read001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/read/read001/read001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,7 +52,7 @@ * @clean nsk.jdb.read.read001.read001a * @compile -g:lines,source,vars read001a.java * - * @run main/othervm + * @run driver * nsk.jdb.read.read001.read001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -76,14 +76,10 @@ public class read001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new read001().runTest(argv, out); + new read001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.read.read001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/redefine/redefine001/redefine001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/redefine/redefine001/redefine001.java index 80ff33889a4..d3988ac443c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/redefine/redefine001/redefine001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/redefine/redefine001/redefine001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,7 +56,7 @@ * -cp ${test.class.path} * ${test.src}/newclass_g/RedefinedClass.java * - * @run main/othervm + * @run driver * nsk.jdb.redefine.redefine001.redefine001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -80,14 +80,10 @@ public class redefine001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new redefine001().runTest(argv, out); + new redefine001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.redefine.redefine001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/reenter/reenter001/reenter001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/reenter/reenter001/reenter001.java index ebc063942c6..4013d85ab75 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/reenter/reenter001/reenter001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/reenter/reenter001/reenter001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.reenter.reenter001.reenter001a - * @run main/othervm + * @run driver * nsk.jdb.reenter.reenter001.reenter001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -69,14 +69,10 @@ public class reenter001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new reenter001().runTest(argv, out); + new reenter001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.reenter.reenter001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/regression/b4689395/b4689395.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/regression/b4689395/b4689395.java index 82d8235fee7..2cb3cc0eccf 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/regression/b4689395/b4689395.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/regression/b4689395/b4689395.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -101,7 +101,7 @@ * -cp ${test.class.path} * ${test.src}/newclass/b4689395a.java * - * @run main/othervm + * @run driver * nsk.jdb.regression.b4689395.b4689395 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -131,13 +131,9 @@ public class b4689395 extends JdbTest { private String classFile; public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; - return new b4689395().runTest(argv, out); + new b4689395().runTest(argv); } public b4689395() { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/repeat/repeat001/repeat001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/repeat/repeat001/repeat001.java index e0489db2829..67ce5ea4e74 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/repeat/repeat001/repeat001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/repeat/repeat001/repeat001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.repeat.repeat001.repeat001a - * @run main/othervm + * @run driver * nsk.jdb.repeat.repeat001.repeat001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -68,13 +68,9 @@ public class repeat001 extends JdbTest { static final String FIRST_BREAK = DEBUGGEE_CLASS + ".main"; public static void main(String[] args) { - System.exit(run(args, System.out) + JCK_STATUS_BASE); - } - - public static int run(String[] args, PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; - return new repeat001().runTest(args, out); + new repeat001().runTest(args); } protected static boolean isPrompt(String line) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/resume/resume002/resume002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/resume/resume002/resume002.java index ab4df2625fe..9607413036c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/resume/resume002/resume002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/resume/resume002/resume002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.resume.resume002.resume002a - * @run main/othervm + * @run driver * nsk.jdb.resume.resume002.resume002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -73,14 +73,10 @@ public class resume002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new resume002().runTest(argv, out); + new resume002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.resume.resume002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/run/run002/run002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/run/run002/run002.java index da837ab0f8b..9b23ac4de25 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/run/run002/run002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/run/run002/run002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,7 +44,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.run.run002.run002a - * @run main/othervm + * @run driver * nsk.jdb.run.run002.run002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -67,14 +67,10 @@ public class run002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new run002().runTest(argv, out); + new run002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.run.run002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/set/set001/set001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/set/set001/set001.java index d00362b228c..7b97f47b529 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/set/set001/set001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/set/set001/set001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,7 +53,7 @@ * @clean nsk.jdb.set.set001.set001a * @compile -g:lines,source,vars set001a.java * - * @run main/othervm + * @run driver * nsk.jdb.set.set001.set001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -76,14 +76,10 @@ public class set001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new set001().runTest(argv, out); + new set001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.set.set001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/set/set002/set002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/set/set002/set002.java index dca4e554afa..91d84821040 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/set/set002/set002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/set/set002/set002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,7 +53,7 @@ * @clean nsk.jdb.set.set002.set002a * @compile -g:lines,source,vars set002a.java * - * @run main/othervm + * @run driver * nsk.jdb.set.set002.set002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -76,15 +76,11 @@ public class set002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new set002().runTest(argv, out); + new set002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.set.set002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/step/step002/step002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/step/step002/step002.java index 4df163ca1a9..c9cc342783e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/step/step002/step002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/step/step002/step002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,7 +56,7 @@ * @clean nsk.jdb.step.step002.step002a * @compile -g:lines,source,vars step002a.java * - * @run main/othervm + * @run driver * nsk.jdb.step.step002.step002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -79,14 +79,10 @@ public class step002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new step002().runTest(argv, out); + new step002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.step.step002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/step_up/step_up001/step_up001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/step_up/step_up001/step_up001.java index 590a476dbbe..d4c60f937fa 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/step_up/step_up001/step_up001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/step_up/step_up001/step_up001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,7 +45,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.step_up.step_up001.step_up001a - * @run main/othervm + * @run driver * nsk.jdb.step_up.step_up001.step_up001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -68,14 +68,10 @@ public class step_up001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new step_up001().runTest(argv, out); + new step_up001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.step_up.step_up001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_at/stop_at002/stop_at002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_at/stop_at002/stop_at002.java index 9dae8c17cfc..30cb6ed2c68 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_at/stop_at002/stop_at002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_at/stop_at002/stop_at002.java @@ -37,7 +37,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.stop_at.stop_at002.stop_at002a - * @run main/othervm + * @run driver * nsk.jdb.stop_at.stop_at002.stop_at002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -67,14 +67,10 @@ public class stop_at002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new stop_at002().runTest(argv, out); + new stop_at002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.stop_at.stop_at002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_at/stop_at003/stop_at003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_at/stop_at003/stop_at003.java index ecd66ca7c95..06eacea58b9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_at/stop_at003/stop_at003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_at/stop_at003/stop_at003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,7 +49,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.stop_at.stop_at003.stop_at003a - * @run main/othervm + * @run driver * nsk.jdb.stop_at.stop_at003.stop_at003 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -79,14 +79,10 @@ public class stop_at003 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new stop_at003().runTest(argv, out); + new stop_at003().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.stop_at.stop_at003"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_in/stop_in002/stop_in002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_in/stop_in002/stop_in002.java index e4c2058fd97..710f05c078c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_in/stop_in002/stop_in002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_in/stop_in002/stop_in002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.stop_in.stop_in002.stop_in002a - * @run main/othervm + * @run driver * nsk.jdb.stop_in.stop_in002.stop_in002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -80,14 +80,10 @@ public class stop_in002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new stop_in002().runTest(argv, out); + new stop_in002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.stop_in.stop_in002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/suspend/suspend001/suspend001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/suspend/suspend001/suspend001.java index 18e5c27d31c..20c9778f251 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/suspend/suspend001/suspend001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/suspend/suspend001/suspend001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.suspend.suspend001.suspend001a - * @run main/othervm + * @run driver * nsk.jdb.suspend.suspend001.suspend001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -69,14 +69,10 @@ public class suspend001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new suspend001().runTest(argv, out); + new suspend001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.suspend.suspend001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/thread/thread002/thread002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/thread/thread002/thread002.java index 487ac49e66e..c8b55b0beee 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/thread/thread002/thread002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/thread/thread002/thread002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.thread.thread002.thread002a - * @run main/othervm + * @run driver * nsk.jdb.thread.thread002.thread002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -66,14 +66,10 @@ public class thread002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new thread002().runTest(argv, out); + new thread002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.thread.thread002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/threadgroup/threadgroup002/threadgroup002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/threadgroup/threadgroup002/threadgroup002.java index 72bbf358474..8ff58b11bec 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/threadgroup/threadgroup002/threadgroup002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/threadgroup/threadgroup002/threadgroup002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,7 +45,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.threadgroup.threadgroup002.threadgroup002a - * @run main/othervm + * @run driver * nsk.jdb.threadgroup.threadgroup002.threadgroup002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -69,14 +69,10 @@ public class threadgroup002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new threadgroup002().runTest(argv, out); + new threadgroup002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.threadgroup.threadgroup002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/threadgroups/threadgroups002/threadgroups002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/threadgroups/threadgroups002/threadgroups002.java index 67ee29006b4..56f4dceda9e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/threadgroups/threadgroups002/threadgroups002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/threadgroups/threadgroups002/threadgroups002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.threadgroups.threadgroups002.threadgroups002a - * @run main/othervm + * @run driver * nsk.jdb.threadgroups.threadgroups002.threadgroups002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -64,14 +64,10 @@ public class threadgroups002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new threadgroups002().runTest(argv, out); + new threadgroups002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.threadgroups.threadgroups002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/threads/threads002/threads002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/threads/threads002/threads002.java index e9afd794d81..fdc52ad7a2a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/threads/threads002/threads002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/threads/threads002/threads002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.threads.threads002.threads002a - * @run main/othervm + * @run driver * nsk.jdb.threads.threads002.threads002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -65,14 +65,10 @@ public class threads002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new threads002().runTest(argv, out); + new threads002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.threads.threads002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/threads/threads003/threads003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/threads/threads003/threads003.java index 4332eb69cf9..f290cc71bb5 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/threads/threads003/threads003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/threads/threads003/threads003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.threads.threads003.threads003a - * @run main/othervm + * @run driver * nsk.jdb.threads.threads003.threads003 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -65,14 +65,10 @@ public class threads003 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new threads003().runTest(argv, out); + new threads003().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.threads.threads003"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/trace/trace001/trace001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/trace/trace001/trace001.java index 0e289f93aee..492d5b438c8 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/trace/trace001/trace001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/trace/trace001/trace001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.trace.trace001.trace001a - * @run main/othervm + * @run driver * nsk.jdb.trace.trace001.trace001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -71,14 +71,10 @@ public class trace001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new trace001().runTest(argv, out); + new trace001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.trace.trace001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/uncaught_exception/uncaught_exception002/uncaught_exception002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/uncaught_exception/uncaught_exception002/uncaught_exception002.java index dd1d0748c0f..32f7750cdb5 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/uncaught_exception/uncaught_exception002/uncaught_exception002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/uncaught_exception/uncaught_exception002/uncaught_exception002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,7 +52,7 @@ * @clean nsk.jdb.uncaught_exception.uncaught_exception002.uncaught_exception002a * @compile -g:lines,source,vars uncaught_exception002a.java * - * @run main/othervm + * @run driver * nsk.jdb.uncaught_exception.uncaught_exception002.uncaught_exception002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -75,14 +75,10 @@ public class uncaught_exception002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new uncaught_exception002(true).runTest(argv, out); + new uncaught_exception002(true).runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.uncaught_exception.uncaught_exception002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/unmonitor/unmonitor001/unmonitor001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/unmonitor/unmonitor001/unmonitor001.java index 7d98824be73..195b2427ae5 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/unmonitor/unmonitor001/unmonitor001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/unmonitor/unmonitor001/unmonitor001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,7 +56,7 @@ * @clean nsk.jdb.unmonitor.unmonitor001.unmonitor001a * @compile -g:lines,source,vars unmonitor001a.java * - * @run main/othervm + * @run driver * nsk.jdb.unmonitor.unmonitor001.unmonitor001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -79,14 +79,10 @@ public class unmonitor001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new unmonitor001().runTest(argv, out); + new unmonitor001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.unmonitor.unmonitor001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/untrace/untrace001/untrace001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/untrace/untrace001/untrace001.java index daad477dbb4..0891e5b931c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/untrace/untrace001/untrace001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/untrace/untrace001/untrace001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,7 +54,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.untrace.untrace001.untrace001a - * @run main/othervm + * @run driver * nsk.jdb.untrace.untrace001.untrace001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -77,14 +77,10 @@ public class untrace001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new untrace001().runTest(argv, out); + new untrace001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.untrace.untrace001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/unwatch/unwatch001/unwatch001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/unwatch/unwatch001/unwatch001.java index b8c71645edb..aff9890e58d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/unwatch/unwatch001/unwatch001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/unwatch/unwatch001/unwatch001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.unwatch.unwatch001.unwatch001a - * @run main/othervm + * @run driver * nsk.jdb.unwatch.unwatch001.unwatch001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -73,14 +73,10 @@ public class unwatch001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new unwatch001().runTest(argv, out); + new unwatch001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.unwatch.unwatch001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/unwatch/unwatch002/unwatch002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/unwatch/unwatch002/unwatch002.java index e32cc0b8e5d..1078e2b3da3 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/unwatch/unwatch002/unwatch002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/unwatch/unwatch002/unwatch002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,7 +51,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.unwatch.unwatch002.unwatch002a - * @run main/othervm + * @run driver * nsk.jdb.unwatch.unwatch002.unwatch002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -74,14 +74,10 @@ public class unwatch002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new unwatch002().runTest(argv, out); + new unwatch002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.unwatch.unwatch002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/up/up002/up002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/up/up002/up002.java index 5b2cb393df4..78c01074abb 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/up/up002/up002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/up/up002/up002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.up.up002.up002a - * @run main/othervm + * @run driver * nsk.jdb.up.up002.up002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -66,14 +66,10 @@ public class up002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new up002().runTest(argv, out); + new up002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.up.up002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/use/use001/use001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/use/use001/use001.java index 1454b39b2bf..81ad1dd48ac 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/use/use001/use001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/use/use001/use001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2023, 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 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.use.use001.use001a - * @run main/othervm + * @run driver * nsk.jdb.use.use001.use001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -67,14 +67,10 @@ public class use001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new use001().runTest(argv, out); + new use001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.use.use001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/watch/watch001/watch001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/watch/watch001/watch001.java index 8d434fcfc74..dfc154d1b41 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/watch/watch001/watch001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/watch/watch001/watch001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,7 +48,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.watch.watch001.watch001a - * @run main/othervm + * @run driver * nsk.jdb.watch.watch001.watch001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -71,15 +71,11 @@ public class watch001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; compoundPromptIdent = COMPOUND_PROMPT_IDENT; - return new watch001().runTest(argv, out); + new watch001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.watch.watch001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/watch/watch002/watch002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/watch/watch002/watch002.java index cb0535117d9..84c80a59ebf 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/watch/watch002/watch002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/watch/watch002/watch002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,7 +48,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.watch.watch002.watch002a - * @run main/othervm + * @run driver * nsk.jdb.watch.watch002.watch002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -71,15 +71,11 @@ public class watch002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; compoundPromptIdent = COMPOUND_PROMPT_IDENT; - return new watch002().runTest(argv, out); + new watch002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.watch.watch002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/where/where004/where004.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/where/where004/where004.java index e4cbf50e62f..9002c35e16e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/where/where004/where004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/where/where004/where004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.where.where004.where004a - * @run main/othervm + * @run driver * nsk.jdb.where.where004.where004 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -64,14 +64,10 @@ public class where004 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new where004().runTest(argv, out); + new where004().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.where.where004"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/where/where005/where005.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/where/where005/where005.java index b949916aae7..2fded987272 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/where/where005/where005.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/where/where005/where005.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.where.where005.where005a - * @run main/othervm + * @run driver * nsk.jdb.where.where005.where005 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -65,14 +65,10 @@ public class where005 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new where005(true).runTest(argv, out); + new where005(true).runTest(argv); } public where005 (boolean debuggeeShouldFail) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/where/where006/where006.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/where/where006/where006.java index bf7622c48b3..11dc185238f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/where/where006/where006.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/where/where006/where006.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.where.where006.where006a - * @run main/othervm + * @run driver * nsk.jdb.where.where006.where006 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -65,14 +65,10 @@ public class where006 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new where006().runTest(argv, out); + new where006().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.where.where006"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/wherei/wherei001/wherei001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/wherei/wherei001/wherei001.java index 431206b5551..e4d75620f0b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/wherei/wherei001/wherei001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/wherei/wherei001/wherei001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.wherei.wherei001.wherei001a - * @run main/othervm + * @run driver * nsk.jdb.wherei.wherei001.wherei001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -60,14 +60,10 @@ public class wherei001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new wherei001().runTest(argv, out); + new wherei001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.wherei.wherei001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/JdbTest.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/JdbTest.java index 349216f4329..aa7ad833b53 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/JdbTest.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/JdbTest.java @@ -125,14 +125,15 @@ protected void initJdb() { protected void afterJdbExit() { } - protected int runTest(String argv[], PrintStream out) { + protected void runTest(String argv[]) { + PrintStream out = System.out; try { argumentHandler = new JdbArgumentHandler(argv); log = new Log(out, argumentHandler); if (shouldPass()) { log.println("TEST PASSED"); - return PASSED; + return; } try { @@ -226,16 +227,14 @@ protected int runTest(String argv[], PrintStream out) { if (!success) { log.complain("TEST FAILED"); - return FAILED; + throw new RuntimeException("TEST FAILED"); } } catch (Throwable t) { out.println("Caught unexpected exception while starting the test: " + t); t.printStackTrace(out); - out.println("TEST FAILED"); - return FAILED; + throw new RuntimeException("TEST FAILED", t); } out.println("TEST PASSED"); - return PASSED; } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/Launcher.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/Launcher.java index 35df95b2d6f..d4437413495 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/Launcher.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/Launcher.java @@ -180,10 +180,12 @@ private String[] makeJdbCmdLine (String classToExecute) { } else /* LaunchingConnector or DefaultConnector */ { connect.append("vmexec=" + argumentHandler.getLaunchExecName().trim()); + connect.append(",options="); + connect.append(" \"-cp\""); + connect.append(" \"" + System.getProperty("test.class.path") + "\""); + String debuggeeOpts = argumentHandler.getDebuggeeOptions(); if (debuggeeOpts.trim().length() > 0) { - //connect.append(",options=" + debuggeeOpts.trim()); - connect.append(",options="); for (String arg : debuggeeOpts.split("\\s+")) { connect.append(" \""); connect.append(arg); From 5079c38ddf345b21d8cb1c959bc36c4341e11da6 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Mon, 12 Aug 2024 22:12:01 +0000 Subject: [PATCH 385/460] 8338160: Fix -Wzero-as-null-pointer-constant warnings in management.cpp Reviewed-by: dholmes --- src/hotspot/share/services/management.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/services/management.cpp b/src/hotspot/share/services/management.cpp index 2c9f36c098d..ac7e1daf397 100644 --- a/src/hotspot/share/services/management.cpp +++ b/src/hotspot/share/services/management.cpp @@ -1820,7 +1820,7 @@ JVM_END // of a given length and return the objArrayOop static objArrayOop get_memory_usage_objArray(jobjectArray array, int length, TRAPS) { if (array == nullptr) { - THROW_(vmSymbols::java_lang_NullPointerException(), 0); + THROW_NULL(vmSymbols::java_lang_NullPointerException()); } objArrayOop oa = objArrayOop(JNIHandles::resolve_non_null(array)); @@ -1828,16 +1828,16 @@ static objArrayOop get_memory_usage_objArray(jobjectArray array, int length, TRA // array must be of the given length if (length != array_h->length()) { - THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), - "The length of the given MemoryUsage array does not match the number of memory pools.", 0); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), + "The length of the given MemoryUsage array does not match the number of memory pools."); } // check if the element of array is of type MemoryUsage class Klass* usage_klass = Management::java_lang_management_MemoryUsage_klass(CHECK_NULL); Klass* element_klass = ObjArrayKlass::cast(array_h->klass())->element_klass(); if (element_klass != usage_klass) { - THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), - "The element type is not MemoryUsage class", 0); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), + "The element type is not MemoryUsage class"); } return array_h(); From e70c9bccaae375be1ee6812dabc9fbaff01a6ab0 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Mon, 12 Aug 2024 23:00:04 +0000 Subject: [PATCH 386/460] 8338248: PartialArrayStateAllocator::Impl leaks Arena array Reviewed-by: kbarrett, shade --- src/hotspot/share/gc/shared/partialArrayState.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/share/gc/shared/partialArrayState.cpp b/src/hotspot/share/gc/shared/partialArrayState.cpp index 583c5dede40..fd23a320222 100644 --- a/src/hotspot/share/gc/shared/partialArrayState.cpp +++ b/src/hotspot/share/gc/shared/partialArrayState.cpp @@ -100,6 +100,7 @@ PartialArrayStateAllocator::Impl::~Impl() { for (uint i = 0; i < _num_workers; ++i) { _arenas[i].~Arena(); } + FREE_C_HEAP_ARRAY(Arena*, _arenas); } PartialArrayState* PartialArrayStateAllocator::Impl::allocate(uint worker_id, From d77e6fe45c7b834db457a772ce0bea514d2e44f3 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 13 Aug 2024 05:46:38 +0000 Subject: [PATCH 387/460] 8338154: Fix -Wzero-as-null-pointer-constant warnings in gtest framework Reviewed-by: ihse, dholmes, jwaters --- make/hotspot/lib/CompileGtest.gmk | 3 ++- test/hotspot/gtest/gtestMain.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/make/hotspot/lib/CompileGtest.gmk b/make/hotspot/lib/CompileGtest.gmk index 696adb0c95f..424743ba279 100644 --- a/make/hotspot/lib/CompileGtest.gmk +++ b/make/hotspot/lib/CompileGtest.gmk @@ -57,7 +57,8 @@ $(eval $(call SetupJdkLibrary, BUILD_GTEST_LIBGTEST, \ $(GTEST_FRAMEWORK_SRC)/googletest/src \ $(GTEST_FRAMEWORK_SRC)/googlemock/src, \ INCLUDE_FILES := gtest-all.cc gmock-all.cc, \ - DISABLED_WARNINGS_gcc := undef unused-result format-nonliteral maybe-uninitialized, \ + DISABLED_WARNINGS_gcc := undef unused-result format-nonliteral \ + maybe-uninitialized zero-as-null-pointer-constant, \ DISABLED_WARNINGS_clang := undef unused-result format-nonliteral, \ DEFAULT_CFLAGS := false, \ CFLAGS := $(JVM_CFLAGS) \ diff --git a/test/hotspot/gtest/gtestMain.cpp b/test/hotspot/gtest/gtestMain.cpp index bc8ca29f72d..0bd251e8094 100644 --- a/test/hotspot/gtest/gtestMain.cpp +++ b/test/hotspot/gtest/gtestMain.cpp @@ -336,7 +336,7 @@ static void run_in_new_thread(const args_t* args) { extern "C" void* thread_wrapper(void* p) { const args_t* const p_args = (const args_t*) p; runUnitTestsInner(p_args->argc, p_args->argv); - return 0; + return nullptr; } static void run_in_new_thread(const args_t* args) { From 73ddb7deab26c526337ec6e7cd5f528f698a552c Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Tue, 13 Aug 2024 05:52:44 +0000 Subject: [PATCH 388/460] 8335628: C2 SuperWord: cleanup: remove SuperWord::longer_type_for_conversion Reviewed-by: chagedorn, kvn --- src/hotspot/share/opto/superword.cpp | 25 +------------------------ src/hotspot/share/opto/superword.hpp | 3 --- 2 files changed, 1 insertion(+), 27 deletions(-) diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index 0e1328a4485..2a43d2ec0af 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -691,9 +691,7 @@ bool SuperWord::can_pack_into_pair(Node* s1, Node* s2) { BasicType bt2 = velt_basic_type(s2); if(!is_java_primitive(bt1) || !is_java_primitive(bt2)) return false; - BasicType longer_bt = longer_type_for_conversion(s1); - if (Matcher::max_vector_size_auto_vectorization(bt1) < 2 || - (longer_bt != T_ILLEGAL && Matcher::max_vector_size_auto_vectorization(longer_bt) < 2)) { + if (Matcher::max_vector_size_auto_vectorization(bt1) < 2) { return false; // No vectors for this type } @@ -2442,27 +2440,6 @@ VStatus VLoopBody::construct() { return VStatus::make_success(); } -BasicType SuperWord::longer_type_for_conversion(Node* n) const { - if (!(VectorNode::is_convert_opcode(n->Opcode()) || - VectorNode::is_scalar_op_that_returns_int_but_vector_op_returns_long(n->Opcode())) || - !in_bb(n->in(1))) { - return T_ILLEGAL; - } - assert(in_bb(n), "must be in the bb"); - BasicType src_t = velt_basic_type(n->in(1)); - BasicType dst_t = velt_basic_type(n); - // Do not use superword for non-primitives. - // Superword does not support casting involving unsigned types. - if (!is_java_primitive(src_t) || is_unsigned_subword_type(src_t) || - !is_java_primitive(dst_t) || is_unsigned_subword_type(dst_t)) { - return T_ILLEGAL; - } - int src_size = type2aelembytes(src_t); - int dst_size = type2aelembytes(dst_t); - return src_size == dst_size ? T_ILLEGAL - : (src_size > dst_size ? src_t : dst_t); -} - void VLoopTypes::compute_vector_element_type() { #ifndef PRODUCT if (_vloop.is_trace_vector_element_type()) { diff --git a/src/hotspot/share/opto/superword.hpp b/src/hotspot/share/opto/superword.hpp index 65f87082525..8b24e0cf3a1 100644 --- a/src/hotspot/share/opto/superword.hpp +++ b/src/hotspot/share/opto/superword.hpp @@ -623,9 +623,6 @@ class SuperWord : public ResourceObj { // Is use->in(u_idx) a vector use? bool is_vector_use(Node* use, int u_idx) const; - // Return the longer type for vectorizable type-conversion node or illegal type for other nodes. - BasicType longer_type_for_conversion(Node* n) const; - bool is_velt_basic_type_compatible_use_def(Node* use, Node* def) const; bool schedule_and_apply() const; From c27a8c8c8b867e6812b905f6154762802a498dbd Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Tue, 13 Aug 2024 05:52:58 +0000 Subject: [PATCH 389/460] 8338124: C2 SuperWord: MulAddS2I input permutation still partially broken after JDK-8333840 Reviewed-by: chagedorn, thartmann, kvn --- src/hotspot/share/opto/superword.cpp | 2 +- .../loopopts/superword/TestMulAddS2I.java | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index 2a43d2ec0af..bb5fed78b02 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -2270,7 +2270,7 @@ Node_List* PackSet::strided_pack_input_at_index_or_null(const Node_List* pack, c return nullptr; // size mismatch } - for (uint i = 1; i < pack->size(); i++) { + for (uint i = 0; i < pack->size(); i++) { if (pack->at(i)->in(index) != pack_in->at(i * stride + offset)) { return nullptr; // use-def mismatch } diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestMulAddS2I.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestMulAddS2I.java index e0f073c7f8f..fb99fc5983a 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestMulAddS2I.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestMulAddS2I.java @@ -53,6 +53,7 @@ public class TestMulAddS2I { static final int[] GOLDEN_J; static final int[] GOLDEN_K; static final int[] GOLDEN_L; + static final int[] GOLDEN_M; static { for (int i = 0; i < RANGE; i++) { @@ -71,6 +72,7 @@ public class TestMulAddS2I { GOLDEN_J = testj(new int[ITER]); GOLDEN_K = testk(new int[ITER]); GOLDEN_L = testl(new int[ITER]); + GOLDEN_M = testm(new int[ITER]); } @@ -80,7 +82,7 @@ public static void main(String[] args) { } @Run(test = {"testa", "testb", "testc", "testd", "teste", "testf", "testg", "testh", - "testi", "testj", "testk", "testl"}) + "testi", "testj", "testk", "testl", "testm"}) @Warmup(0) public static void run() { compare(testa(), GOLDEN_A, "testa"); @@ -95,6 +97,7 @@ public static void run() { compare(testj(new int[ITER]), GOLDEN_J, "testj"); compare(testk(new int[ITER]), GOLDEN_K, "testk"); compare(testl(new int[ITER]), GOLDEN_L, "testl"); + compare(testm(new int[ITER]), GOLDEN_M, "testm"); } public static void compare(int[] out, int[] golden, String name) { @@ -299,4 +302,17 @@ public static int[] testl(int[] out) { return out; } + @Test + @IR(counts = {IRNode.MUL_ADD_S2I, "> 0"}, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + @IR(counts = {IRNode.MUL_ADD_VS2VI, "= 0"}) + public static int[] testm(int[] out) { + for (int i = 0; i < ITER-4; i+=4) { + // Unrolled, with some swaps that prevent vectorization. + out[i+0] += ((sArr1[2*i+0] * sArr2[2*i+1]) + (sArr1[2*i+1] * sArr2[2*i+0])); // bad + out[i+1] += ((sArr1[2*i+2] * sArr2[2*i+2]) + (sArr1[2*i+3] * sArr2[2*i+3])); // ok + // 2-element gap + } + return out; + } } From 73f7a5f15dbba54a98f3916ff1190520ac07874d Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 13 Aug 2024 07:27:49 +0000 Subject: [PATCH 390/460] 8338155: Fix -Wzero-as-null-pointer-constant warnings involving PTHREAD_MUTEX_INITIALIZER Reviewed-by: dholmes, dlong --- src/hotspot/os/linux/os_perf_linux.cpp | 5 ++++- src/hotspot/os/posix/threadCritical_posix.cpp | 8 +++++++- src/hotspot/share/utilities/compilerWarnings.hpp | 6 +++++- src/hotspot/share/utilities/compilerWarnings_gcc.hpp | 5 ++++- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/hotspot/os/linux/os_perf_linux.cpp b/src/hotspot/os/linux/os_perf_linux.cpp index 87abbebe25f..a31a58e55af 100644 --- a/src/hotspot/os/linux/os_perf_linux.cpp +++ b/src/hotspot/os/linux/os_perf_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -430,7 +430,10 @@ static int get_boot_time(uint64_t* time) { } static int perf_context_switch_rate(double* rate) { + PRAGMA_DIAG_PUSH + PRAGMA_ZERO_AS_NULL_POINTER_CONSTANT_IGNORED static pthread_mutex_t contextSwitchLock = PTHREAD_MUTEX_INITIALIZER; + PRAGMA_DIAG_POP static uint64_t bootTime; static uint64_t lastTimeNanos; static uint64_t lastSwitches; diff --git a/src/hotspot/os/posix/threadCritical_posix.cpp b/src/hotspot/os/posix/threadCritical_posix.cpp index 45eba4c1585..cd3b42e71ba 100644 --- a/src/hotspot/os/posix/threadCritical_posix.cpp +++ b/src/hotspot/os/posix/threadCritical_posix.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2014 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -26,6 +26,7 @@ #include "precompiled.hpp" #include "runtime/javaThread.hpp" #include "runtime/threadCritical.hpp" +#include "utilities/compilerWarnings.hpp" // put OS-includes here # include @@ -35,7 +36,12 @@ // static pthread_t tc_owner = 0; + +PRAGMA_DIAG_PUSH +PRAGMA_ZERO_AS_NULL_POINTER_CONSTANT_IGNORED static pthread_mutex_t tc_mutex = PTHREAD_MUTEX_INITIALIZER; +PRAGMA_DIAG_POP + static int tc_count = 0; ThreadCritical::ThreadCritical() { diff --git a/src/hotspot/share/utilities/compilerWarnings.hpp b/src/hotspot/share/utilities/compilerWarnings.hpp index 28954843dc3..ddcaf022fa6 100644 --- a/src/hotspot/share/utilities/compilerWarnings.hpp +++ b/src/hotspot/share/utilities/compilerWarnings.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -82,6 +82,10 @@ #define PRAGMA_NONNULL_IGNORED #endif +#ifndef PRAGMA_ZERO_AS_NULL_POINTER_CONSTANT_IGNORED +#define PRAGMA_ZERO_AS_NULL_POINTER_CONSTANT_IGNORED +#endif + // Support warnings for use of certain C functions, except where explicitly // permitted. // diff --git a/src/hotspot/share/utilities/compilerWarnings_gcc.hpp b/src/hotspot/share/utilities/compilerWarnings_gcc.hpp index 53373ec628a..1dd5892e4c3 100644 --- a/src/hotspot/share/utilities/compilerWarnings_gcc.hpp +++ b/src/hotspot/share/utilities/compilerWarnings_gcc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,6 +67,9 @@ #define PRAGMA_NONNULL_IGNORED PRAGMA_DISABLE_GCC_WARNING("-Wnonnull") +#define PRAGMA_ZERO_AS_NULL_POINTER_CONSTANT_IGNORED \ + PRAGMA_DISABLE_GCC_WARNING("-Wzero-as-null-pointer-constant") + #if (__GNUC__ >= 10) // TODO: Re-enable warning attribute for Clang once // https://github.com/llvm/llvm-project/issues/56519 is fixed and released. From 5bf27098e22172ed5d3ec0c43fe0553f8322c4b1 Mon Sep 17 00:00:00 2001 From: Saint Wesonga Date: Tue, 13 Aug 2024 08:10:29 +0000 Subject: [PATCH 391/460] 8334475: UnsafeIntrinsicsTest.java#ZGenerationalDebug assert(!assert_on_failure) failed: Has low-order bits set Reviewed-by: stefank, eosterlund, aboldtch --- .../windows_aarch64/copy_windows_aarch64.hpp | 63 +++++++------------ 1 file changed, 23 insertions(+), 40 deletions(-) diff --git a/src/hotspot/os_cpu/windows_aarch64/copy_windows_aarch64.hpp b/src/hotspot/os_cpu/windows_aarch64/copy_windows_aarch64.hpp index ce2ad2d046f..96a34fe967b 100644 --- a/src/hotspot/os_cpu/windows_aarch64/copy_windows_aarch64.hpp +++ b/src/hotspot/os_cpu/windows_aarch64/copy_windows_aarch64.hpp @@ -26,8 +26,27 @@ #ifndef OS_CPU_WINDOWS_AARCH64_COPY_WINDOWS_AARCH64_HPP #define OS_CPU_WINDOWS_AARCH64_COPY_WINDOWS_AARCH64_HPP +#include "runtime/atomic.hpp" + #include +template +static void pd_conjoint_atomic_helper(const T* from, T* to, size_t count) { + if (from > to) { + while (count-- > 0) { + // Copy forwards + Atomic::store(to++, Atomic::load(from++)); + } + } else { + from += count - 1; + to += count - 1; + while (count-- > 0) { + // Copy backwards + Atomic::store(to--, Atomic::load(from--)); + } + } +} + static void pd_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) { (void)memmove(to, from, count * HeapWordSize); } @@ -71,55 +90,19 @@ static void pd_conjoint_bytes_atomic(const void* from, void* to, size_t count) { } static void pd_conjoint_jshorts_atomic(const jshort* from, jshort* to, size_t count) { - if (from > to) { - while (count-- > 0) { - // Copy forwards - *to++ = *from++; - } - } else { - from += count - 1; - to += count - 1; - while (count-- > 0) { - // Copy backwards - *to-- = *from--; - } - } + pd_conjoint_atomic_helper(from, to, count); } static void pd_conjoint_jints_atomic(const jint* from, jint* to, size_t count) { - if (from > to) { - while (count-- > 0) { - // Copy forwards - *to++ = *from++; - } - } else { - from += count - 1; - to += count - 1; - while (count-- > 0) { - // Copy backwards - *to-- = *from--; - } - } + pd_conjoint_atomic_helper(from, to, count); } static void pd_conjoint_jlongs_atomic(const jlong* from, jlong* to, size_t count) { - pd_conjoint_oops_atomic((const oop*)from, (oop*)to, count); + pd_conjoint_atomic_helper(from, to, count); } static void pd_conjoint_oops_atomic(const oop* from, oop* to, size_t count) { - if (from > to) { - while (count-- > 0) { - // Copy forwards - *to++ = *from++; - } - } else { - from += count - 1; - to += count - 1; - while (count-- > 0) { - // Copy backwards - *to-- = *from--; - } - } + pd_conjoint_atomic_helper(from, to, count); } static void pd_arrayof_conjoint_bytes(const HeapWord* from, HeapWord* to, size_t count) { From ba69ed7c58fcf99ed18dfd8840125ddcac9460bb Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 13 Aug 2024 08:11:47 +0000 Subject: [PATCH 392/460] 8338202: Shenandoah: Improve handshake closure labels Reviewed-by: rkennke, ysr, wkemper --- src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp | 2 +- .../share/gc/shenandoah/shenandoahConcurrentMark.cpp | 2 +- src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp | 6 +++--- src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp | 2 +- src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index ac2e732052a..86d6d91f72c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -823,7 +823,7 @@ void ShenandoahConcurrentGC::op_weak_roots() { // Perform handshake to flush out dead oops { ShenandoahTimingsTracker t(ShenandoahPhaseTimings::conc_weak_roots_rendezvous); - heap->rendezvous_threads(); + heap->rendezvous_threads("Shenandoah Concurrent Weak Roots"); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index 31157616e0e..dde446d824b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -179,7 +179,7 @@ class ShenandoahFlushSATBHandshakeClosure : public HandshakeClosure { SATBMarkQueueSet& _qset; public: ShenandoahFlushSATBHandshakeClosure(SATBMarkQueueSet& qset) : - HandshakeClosure("Shenandoah Flush SATB Handshake"), + HandshakeClosure("Shenandoah Flush SATB"), _qset(qset) {} void do_thread(Thread* thread) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index eb6de9719dc..0a20307abcb 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -1744,12 +1744,12 @@ void ShenandoahHeap::parallel_heap_region_iterate(ShenandoahHeapRegionClosure* b class ShenandoahRendezvousClosure : public HandshakeClosure { public: - inline ShenandoahRendezvousClosure() : HandshakeClosure("ShenandoahRendezvous") {} + inline ShenandoahRendezvousClosure(const char* name) : HandshakeClosure(name) {} inline void do_thread(Thread* thread) {} }; -void ShenandoahHeap::rendezvous_threads() { - ShenandoahRendezvousClosure cl; +void ShenandoahHeap::rendezvous_threads(const char* name) { + ShenandoahRendezvousClosure cl(name); Handshake::execute(&cl); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index f3625da218c..86bd7b83bbe 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -400,7 +400,7 @@ class ShenandoahHeap : public CollectedHeap, public ShenandoahSpaceInfo { void update_heap_region_states(bool concurrent); void rebuild_free_set(bool concurrent); - void rendezvous_threads(); + void rendezvous_threads(const char* name); void recycle_trash(); public: void notify_gc_progress(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp b/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp index 02a7fbeb8b5..f33b76bcd4e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp @@ -168,7 +168,7 @@ void ShenandoahUnload::unload() { // Make sure stale metadata and nmethods are no longer observable { ShenandoahTimingsTracker t(ShenandoahPhaseTimings::conc_class_unload_rendezvous); - heap->rendezvous_threads(); + heap->rendezvous_threads("Shenandoah Class Unloading"); } // Purge stale metadata and nmethods that were unlinked From fbe4cc96e223882a18c7ff666fe6f68b3fa2cfe4 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Tue, 13 Aug 2024 09:51:08 +0000 Subject: [PATCH 393/460] 8336384: AbstractQueuedSynchronizer.acquire should cancel acquire when failing due to a LinkageError or other errors Reviewed-by: alanb --- .../locks/AbstractQueuedLongSynchronizer.java | 19 ++++++++++++------- .../locks/AbstractQueuedSynchronizer.java | 19 ++++++++++++------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java index f4d7d0c08c0..2de1d17e7c1 100644 --- a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java +++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java @@ -369,14 +369,19 @@ final int acquire(Node node, long arg, boolean shared, } else if (node.status == 0) { node.status = WAITING; // enable signal and recheck } else { - long nanos; spins = postSpins = (byte)((postSpins << 1) | 1); - if (!timed) - LockSupport.park(this); - else if ((nanos = time - System.nanoTime()) > 0L) - LockSupport.parkNanos(this, nanos); - else - break; + try { + long nanos; + if (!timed) + LockSupport.park(this); + else if ((nanos = time - System.nanoTime()) > 0L) + LockSupport.parkNanos(this, nanos); + else + break; + } catch (Error | RuntimeException ex) { + cancelAcquire(node, interrupted, interruptible); // cancel & rethrow + throw ex; + } node.clearStatus(); if ((interrupted |= Thread.interrupted()) && interruptible) break; diff --git a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java index 1f51419f94c..2ea0d3ed3b0 100644 --- a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java +++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java @@ -748,14 +748,19 @@ final int acquire(Node node, int arg, boolean shared, } else if (node.status == 0) { node.status = WAITING; // enable signal and recheck } else { - long nanos; spins = postSpins = (byte)((postSpins << 1) | 1); - if (!timed) - LockSupport.park(this); - else if ((nanos = time - System.nanoTime()) > 0L) - LockSupport.parkNanos(this, nanos); - else - break; + try { + long nanos; + if (!timed) + LockSupport.park(this); + else if ((nanos = time - System.nanoTime()) > 0L) + LockSupport.parkNanos(this, nanos); + else + break; + } catch (Error | RuntimeException ex) { + cancelAcquire(node, interrupted, interruptible); // cancel & rethrow + throw ex; + } node.clearStatus(); if ((interrupted |= Thread.interrupted()) && interruptible) break; From ff8a9f9267c480fe0be8470cda870fd77763fb31 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Tue, 13 Aug 2024 11:48:50 +0000 Subject: [PATCH 394/460] 8337318: Deoptimization::relock_objects fails assert(monitor->owner() == Thread::current()) failed: must be Co-authored-by: Richard Reingruber Reviewed-by: rrich, dholmes, shade, pchilanomate --- src/hotspot/share/runtime/synchronizer.cpp | 4 +- test/jdk/com/sun/jdi/EATests.java | 83 +++++++++++++++++++++- 2 files changed, 84 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp index 2d45163d0f4..b4ff263d455 100644 --- a/src/hotspot/share/runtime/synchronizer.cpp +++ b/src/hotspot/share/runtime/synchronizer.cpp @@ -596,8 +596,8 @@ bool ObjectSynchronizer::enter_fast_impl(Handle obj, BasicLock* lock, JavaThread log_info(monitorinflation)("LockStack capacity exceeded, inflating."); ObjectMonitor* monitor = inflate_for(locking_thread, lock_stack.bottom(), inflate_cause_vm_internal); - assert(monitor->owner() == Thread::current(), "must be owner=" PTR_FORMAT " current=" PTR_FORMAT " mark=" PTR_FORMAT, - p2i(monitor->owner()), p2i(Thread::current()), monitor->object()->mark_acquire().value()); + assert(monitor->owner() == locking_thread, "must be owner=" PTR_FORMAT " locking_thread=" PTR_FORMAT " mark=" PTR_FORMAT, + p2i(monitor->owner()), p2i(locking_thread), monitor->object()->mark_acquire().value()); assert(!lock_stack.is_full(), "must have made room here"); } diff --git a/test/jdk/com/sun/jdi/EATests.java b/test/jdk/com/sun/jdi/EATests.java index 72859481659..adeb2174143 100644 --- a/test/jdk/com/sun/jdi/EATests.java +++ b/test/jdk/com/sun/jdi/EATests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 SAP SE. All rights reserved. + * Copyright (c) 2020, 2024 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 @@ -288,6 +288,7 @@ public static void main(String[] args) { // Relocking test cases new EARelockingSimpleTarget() .run(); + new EARelockingWithManyLightweightLocksTarget() .run(); new EARelockingSimpleWithAccessInOtherThreadTarget() .run(); new EARelockingSimpleWithAccessInOtherThread_02_DynamicCall_Target() .run(); new EARelockingRecursiveTarget() .run(); @@ -413,6 +414,7 @@ protected void runTests() throws Exception { // Relocking test cases new EARelockingSimple() .run(this); + new EARelockingWithManyLightweightLocks() .run(this); new EARelockingSimpleWithAccessInOtherThread() .run(this); new EARelockingSimpleWithAccessInOtherThread_02_DynamicCall() .run(this); new EARelockingRecursive() .run(this); @@ -1797,6 +1799,85 @@ public void dontinline_testMethod() { ///////////////////////////////////////////////////////////////////////////// +/** + * Like {@link EARelockingSimple}. The difference is that there are many + * lightweight locked objects when the relocking is done. With + * -XX:LockingMode=2 the lock stack of the thread will be full + * because of this. + */ + +class EARelockingWithManyLightweightLocks extends EATestCaseBaseDebugger { + + public void runTestCase() throws Exception { + BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); + printStack(bpe.thread()); + @SuppressWarnings("unused") + ObjectReference o = getLocalRef(bpe.thread().frame(1), XYVAL_NAME, "l1"); + } +} + +class EARelockingWithManyLightweightLocksTarget extends EATestCaseBaseTarget { + + static class Lock { + } + + public static Lock L0, L1, L2, L3, L4, L5, L6, L7, L8, L9; + + void allocateLocks() { + L0 = new Lock(); + L1 = new Lock(); + L2 = new Lock(); + L3 = new Lock(); + L4 = new Lock(); + L5 = new Lock(); + L6 = new Lock(); + L7 = new Lock(); + L8 = new Lock(); + L9 = new Lock(); + } + + @Override + public void setUp() { + super.setUp(); + allocateLocks(); + } + + @Override + public void warmupDone() { + super.warmupDone(); + allocateLocks(); // get rid of already inflated ones + } + + public void dontinline_testMethod() { + XYVal l1 = new XYVal(4, 2); + synchronized(L0) { + synchronized(L1) { + synchronized(L2) { + synchronized(L3) { + synchronized(L4) { + synchronized(L5) { + synchronized(L6) { + synchronized(L7) { + synchronized(L8) { + synchronized(L9) { + synchronized (l1) { + dontinline_brkpt(); + } + } + } + } + } + } + } + } + } + } + } + } +} + +///////////////////////////////////////////////////////////////////////////// + // The debugger reads and publishes an object with eliminated locking to an instance field. // A 2nd thread in the debuggee finds it there and changes its state using a synchronized method. // Without eager relocking the accesses are unsynchronized which can be observed. From 76e33b6c1517599e14ee34371c945aafcd752e4e Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Tue, 13 Aug 2024 13:13:14 +0000 Subject: [PATCH 395/460] 8336148: Test runtime/locking/TestRecursiveMonitorChurn.java failed: Unexpected Inflation Reviewed-by: dholmes, eosterlund --- .../runtime/locking/TestRecursiveMonitorChurn.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/hotspot/jtreg/runtime/locking/TestRecursiveMonitorChurn.java b/test/hotspot/jtreg/runtime/locking/TestRecursiveMonitorChurn.java index 19dd90015bf..806f32aad88 100644 --- a/test/hotspot/jtreg/runtime/locking/TestRecursiveMonitorChurn.java +++ b/test/hotspot/jtreg/runtime/locking/TestRecursiveMonitorChurn.java @@ -70,6 +70,18 @@ public static void main(String[] args) { if (pre_monitor_count != post_monitor_count) { final long monitor_count_change = post_monitor_count - pre_monitor_count; System.out.println("Unexpected change in monitor count: " + monitor_count_change); + + // Intermittent deflation and inflation may occur due to running the test + // with stress flags (like DeoptimizeALot) or with added instrumentation + // which runs in the same VM. + // An arbitrary fuzzy max difference of 10 (= 0.01% of COUNT) is chosen to + // allow for these occurrences to be skipped while still catching regressions. + final long fuzzy_max_difference = 10; + if (Math.abs(monitor_count_change) < fuzzy_max_difference) { + final String type = monitor_count_change < 0 ? "deflation" : "inflation"; + throw new SkippedException("Intermittent " + type + " detected. Invalid test."); + } + if (monitor_count_change < 0) { throw new RuntimeException("Unexpected Deflation"); } From 877fd5a768647790d0a43aaca247043bae70d708 Mon Sep 17 00:00:00 2001 From: Casper Norrbin Date: Tue, 13 Aug 2024 14:43:44 +0000 Subject: [PATCH 396/460] 8337595: Remove empty statements in src/hotspot/share/memory/metaspace Reviewed-by: stefank, dholmes, jwaters --- src/hotspot/share/memory/metaspace/metaspaceCommon.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/memory/metaspace/metaspaceCommon.hpp b/src/hotspot/share/memory/metaspace/metaspaceCommon.hpp index eae75e8194c..511f4e6e092 100644 --- a/src/hotspot/share/memory/metaspace/metaspaceCommon.hpp +++ b/src/hotspot/share/memory/metaspace/metaspaceCommon.hpp @@ -85,7 +85,7 @@ void print_percentage(outputStream* st, size_t total, size_t part); SIZE_FORMAT_X " is not aligned to " \ SIZE_FORMAT_X, (size_t)(uintptr_t)value, (size_t)(alignment)) #define assert_is_aligned_metaspace_pointer(p) \ - assert_is_aligned((p), metaspace::AllocationAlignmentByteSize); + assert_is_aligned((p), metaspace::AllocationAlignmentByteSize) #else #define assert_is_aligned(value, alignment) #define assert_is_aligned_metaspace_pointer(pointer) @@ -141,8 +141,8 @@ void print_number_of_classes(outputStream* out, uintx classes, uintx classes_sha #define HAVE_UL #ifdef HAVE_UL -#define UL(level, message) log_##level(metaspace)(LOGFMT ": " message, LOGFMT_ARGS); -#define UL2(level, message, ...) log_##level(metaspace)(LOGFMT ": " message, LOGFMT_ARGS, __VA_ARGS__); +#define UL(level, message) log_##level(metaspace)(LOGFMT ": " message, LOGFMT_ARGS) +#define UL2(level, message, ...) log_##level(metaspace)(LOGFMT ": " message, LOGFMT_ARGS, __VA_ARGS__) #else #define UL(level, ...) #define UL2(level, ...) From 9e282e5c966a9c065de8b901b7d30bb5c9ccf243 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Tue, 13 Aug 2024 15:05:49 +0000 Subject: [PATCH 397/460] 8337998: CompletionFailure in getEnclosingType attaching type annotations Reviewed-by: vromero --- .../com/sun/tools/javac/jvm/ClassReader.java | 15 ++- .../tools/javac/resources/compiler.properties | 5 + .../CompletionErrorOnEnclosingType.java | 98 +++++++++++++++++++ .../tools/javac/diags/examples.not-yet.txt | 1 + 4 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 test/langtools/tools/javac/annotations/typeAnnotations/CompletionErrorOnEnclosingType.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java index fcc1efda8dc..bd05cf91e91 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java @@ -62,6 +62,7 @@ import com.sun.tools.javac.jvm.ClassFile.Version; import com.sun.tools.javac.jvm.PoolConstant.NameAndType; import com.sun.tools.javac.main.Option; +import com.sun.tools.javac.resources.CompilerProperties.Errors; import com.sun.tools.javac.resources.CompilerProperties.Fragments; import com.sun.tools.javac.resources.CompilerProperties.Warnings; import com.sun.tools.javac.util.*; @@ -2311,9 +2312,17 @@ public void run() { * 4.7.20-A target_type to locate the correct type to rewrite, and then interpreting the JVMS * 4.7.20.2 type_path to associate the annotation with the correct contained type. */ - private static void addTypeAnnotationsToSymbol( - Symbol s, List attributes) { - new TypeAnnotationSymbolVisitor(attributes).visit(s, null); + private void addTypeAnnotationsToSymbol(Symbol s, List attributes) { + try { + new TypeAnnotationSymbolVisitor(attributes).visit(s, null); + } catch (CompletionFailure ex) { + JavaFileObject prev = log.useSource(currentClassFile); + try { + log.error(Errors.CantAttachTypeAnnotations(attributes, s.owner, s.name, ex.getDetailValue())); + } finally { + log.useSource(prev); + } + } } private static class TypeAnnotationSymbolVisitor diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties index 8576106e15f..10f06ad7017 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -2345,6 +2345,11 @@ compiler.warn.annotation.method.not.found=\ compiler.warn.annotation.method.not.found.reason=\ Cannot find annotation method ''{1}()'' in type ''{0}'': {2} +# 0: list of annotation, 1: symbol, 2: name, 3: message segment +compiler.err.cant.attach.type.annotations=\ + Cannot attach type annotations {0} to {1}.{2}:\n\ + {3} + # 0: file object, 1: symbol, 2: name compiler.warn.unknown.enum.constant=\ unknown enum constant {1}.{2} diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/CompletionErrorOnEnclosingType.java b/test/langtools/tools/javac/annotations/typeAnnotations/CompletionErrorOnEnclosingType.java new file mode 100644 index 00000000000..11b4e1ccbd4 --- /dev/null +++ b/test/langtools/tools/javac/annotations/typeAnnotations/CompletionErrorOnEnclosingType.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2024, Alphabet LLC. 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 8337998 + * @summary CompletionFailure in getEnclosingType attaching type annotations + * @library /tools/javac/lib /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + */ + +import toolbox.*; +import toolbox.Task.*; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +public class CompletionErrorOnEnclosingType { + ToolBox tb = new ToolBox(); + + public static void main(String... args) throws Exception { + CompletionErrorOnEnclosingType t = new CompletionErrorOnEnclosingType(); + t.testMissingEnclosingType(); + } + + void testMissingEnclosingType() throws Exception { + String annoSrc = + """ + import static java.lang.annotation.ElementType.TYPE_USE; + import java.lang.annotation.Target; + @Target(TYPE_USE) + @interface Anno {} + + class A {} + + class B { + private @Anno A a; + } + """; + String cSrc = + """ + class C { + B b; + } + """; + + Path base = Paths.get("."); + Path src = base.resolve("src"); + tb.createDirectories(src); + tb.writeJavaFiles(src, annoSrc, cSrc); + Path out = base.resolve("out"); + tb.createDirectories(out); + new JavacTask(tb).outdir(out).files(tb.findJavaFiles(src)).run(); + + // now if we remove A.class there will be an error but javac should not crash + tb.deleteFiles(out.resolve("A.class")); + List log = + new JavacTask(tb) + .outdir(out) + .classpath(out) + .options("-XDrawDiagnostics") + .files(src.resolve("C.java")) + .run(Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + var expectedOutput = + List.of( + "B.class:-:-: compiler.err.cant.attach.type.annotations: @Anno, B, a," + + " (compiler.misc.class.file.not.found: A)", + "1 error"); + if (!expectedOutput.equals(log)) { + throw new Exception("expected output not found: " + log); + } + } +} diff --git a/test/langtools/tools/javac/diags/examples.not-yet.txt b/test/langtools/tools/javac/diags/examples.not-yet.txt index 9a447927761..b2603338509 100644 --- a/test/langtools/tools/javac/diags/examples.not-yet.txt +++ b/test/langtools/tools/javac/diags/examples.not-yet.txt @@ -41,6 +41,7 @@ compiler.err.signature.doesnt.match.intf # UNUSED compiler.err.signature.doesnt.match.supertype # UNUSED compiler.err.source.cant.overwrite.input.file compiler.err.stack.sim.error +compiler.err.cant.attach.type.annotations # bad class file compiler.err.type.var.more.than.once # UNUSED compiler.err.type.var.more.than.once.in.result # UNUSED compiler.err.unexpected.type From 6af1d6ff210b3ddbc7d1585428b49631248a500b Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Tue, 13 Aug 2024 15:14:06 +0000 Subject: [PATCH 398/460] 8335927: Revisit AnnotationConstantValueEntry and AnnotationValue.OfConstant Reviewed-by: asotona --- .../java/lang/classfile/AnnotationValue.java | 347 +++++++++++++----- .../AnnotationConstantValueEntry.java | 19 +- .../constantpool/ConstantPoolBuilder.java | 19 - .../classfile/impl/AnnotationImpl.java | 47 +-- .../classfile/impl/AnnotationReader.java | 4 +- .../classfile/impl/ClassPrinterImpl.java | 20 +- test/jdk/jdk/classfile/AnnotationTest.java | 54 +-- test/jdk/jdk/classfile/ClassPrinterTest.java | 11 +- .../helpers/RebuildingTransformation.java | 4 +- .../classfile/AnonymousClassTest.java | 2 +- .../AnnotationDefaultVerifier.java | 4 +- .../annotations/TestAnnotationInfo.java | 8 +- 12 files changed, 358 insertions(+), 181 deletions(-) diff --git a/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java b/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java index 919c8a0441d..a4a1c218ac1 100644 --- a/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java +++ b/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java @@ -26,6 +26,7 @@ import java.lang.classfile.constantpool.AnnotationConstantValueEntry; import java.lang.classfile.constantpool.DoubleEntry; +import java.lang.classfile.constantpool.DynamicConstantPoolEntry; import java.lang.classfile.constantpool.FloatEntry; import java.lang.classfile.constantpool.IntegerEntry; import java.lang.classfile.constantpool.LongEntry; @@ -34,7 +35,7 @@ import jdk.internal.classfile.impl.TemporaryConstantPool; import java.lang.constant.ClassDesc; -import java.lang.constant.ConstantDesc; +import java.lang.constant.Constable; import java.util.ArrayList; import java.util.List; import jdk.internal.javac.PreviewFeature; @@ -49,191 +50,373 @@ * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) -public sealed interface AnnotationValue - permits AnnotationValue.OfAnnotation, AnnotationValue.OfArray, - AnnotationValue.OfConstant, AnnotationValue.OfClass, - AnnotationValue.OfEnum { +public sealed interface AnnotationValue { /** - * Models an annotation-valued element + * Models an annotation-valued element. + * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_ANNOTATION}. * * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) sealed interface OfAnnotation extends AnnotationValue permits AnnotationImpl.OfAnnotationImpl { - /** {@return the annotation} */ + /** {@return the annotation value} */ Annotation annotation(); } /** - * Models an array-valued element + * Models an array-valued element. + * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_ARRAY}. * * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) sealed interface OfArray extends AnnotationValue permits AnnotationImpl.OfArrayImpl { - /** {@return the values} */ + /** + * {@return the array elements of the array value} + * + * @apiNote + * All array elements derived from Java source code have the same type, + * which must not be an array type. ({@jls 9.6.1}) + */ List values(); } /** - * Models a constant-valued element + * Models a constant-valued element. * * @sealedGraph * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) - sealed interface OfConstant extends AnnotationValue - permits AnnotationValue.OfString, AnnotationValue.OfDouble, - AnnotationValue.OfFloat, AnnotationValue.OfLong, - AnnotationValue.OfInteger, AnnotationValue.OfShort, - AnnotationValue.OfCharacter, AnnotationValue.OfByte, - AnnotationValue.OfBoolean, AnnotationImpl.OfConstantImpl { - /** {@return the constant} */ + sealed interface OfConstant + extends AnnotationValue + permits OfString, OfDouble, OfFloat, OfLong, OfInt, OfShort, OfChar, OfByte, + OfBoolean, AnnotationImpl.OfConstantImpl { + /** + * {@return the constant pool entry backing this constant element} + * + * @apiNote + * Different types of constant values may share the same type of entry. + * For example, {@link OfInt} and {@link OfChar} are both + * backed by {@link IntegerEntry}. Use {@link #resolvedValue + * resolvedValue()} for a value of accurate type. + */ AnnotationConstantValueEntry constant(); - /** {@return the constant} */ - ConstantDesc constantValue(); - } - /** - * Models a constant-valued element + /** + * {@return the resolved live constant value, as an object} The type of + * the returned value may be a wrapper class or {@link String}. + * + * @apiNote + * The returned object, despite being {@link Constable}, may not + * {@linkplain Constable#describeConstable() describe} the right constant + * for encoding the annotation value in a class file. For example, + * {@link Character} returned by {@link OfChar} describes itself as a + * {@link DynamicConstantPoolEntry}, but it is actually backed by + * {@link IntegerEntry} in annotation format. + * Use {@link #constant constant()} for a correct constant pool representation. + */ + Constable resolvedValue(); + } + + /** + * Models a string-valued element. + * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_STRING}. * * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) - sealed interface OfString extends AnnotationValue.OfConstant + sealed interface OfString extends OfConstant permits AnnotationImpl.OfStringImpl { - /** {@return the constant} */ + /** {@return the backing UTF8 entry} */ + @Override + Utf8Entry constant(); + + /** {@return the constant string value} */ String stringValue(); + + /** + * {@return the resolved string value} + * + * @implSpec + * This method returns the same as {@link #stringValue()}. + */ + @Override + default String resolvedValue() { + return stringValue(); + } } /** - * Models a constant-valued element + * Models a double-valued element. + * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_DOUBLE}. * * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) - sealed interface OfDouble extends AnnotationValue.OfConstant + sealed interface OfDouble extends OfConstant permits AnnotationImpl.OfDoubleImpl { - /** {@return the constant} */ + /** {@return the backing double entry} */ + @Override + DoubleEntry constant(); + + /** {@return the constant double value} */ double doubleValue(); + + /** + * {@return the resolved double value} + * + * @implSpec + * This method returns the same as {@link #doubleValue()}. + */ + @Override + default Double resolvedValue() { + return doubleValue(); + } } /** - * Models a constant-valued element + * Models a float-valued element. + * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_FLOAT}. * * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) - sealed interface OfFloat extends AnnotationValue.OfConstant + sealed interface OfFloat extends OfConstant permits AnnotationImpl.OfFloatImpl { - /** {@return the constant} */ + /** {@return the backing float entry} */ + @Override + FloatEntry constant(); + + /** {@return the constant float value} */ float floatValue(); + + /** + * {@return the resolved float value} + * + * @implSpec + * This method returns the same as {@link #floatValue()}. + */ + @Override + default Float resolvedValue() { + return floatValue(); + } } /** - * Models a constant-valued element + * Models a long-valued element. + * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_LONG}. * * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) - sealed interface OfLong extends AnnotationValue.OfConstant + sealed interface OfLong extends OfConstant permits AnnotationImpl.OfLongImpl { - /** {@return the constant} */ + /** {@return the backing long entry} */ + @Override + LongEntry constant(); + + /** {@return the constant long value} */ long longValue(); + + /** + * {@return the resolved long value} + * + * @implSpec + * This method returns the same as {@link #longValue()}. + */ + @Override + default Long resolvedValue() { + return longValue(); + } } /** - * Models a constant-valued element + * Models an int-valued element. + * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_INT}. * * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) - sealed interface OfInteger extends AnnotationValue.OfConstant - permits AnnotationImpl.OfIntegerImpl { - /** {@return the constant} */ + sealed interface OfInt extends OfConstant + permits AnnotationImpl.OfIntImpl { + /** {@return the backing integer entry} */ + @Override + IntegerEntry constant(); + + /** {@return the constant int value} */ int intValue(); + + /** + * {@return the resolved int value} + * + * @implSpec + * This method returns the same as {@link #intValue()}. + */ + @Override + default Integer resolvedValue() { + return intValue(); + } } /** - * Models a constant-valued element + * Models a short-valued element. + * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_SHORT}. * * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) - sealed interface OfShort extends AnnotationValue.OfConstant + sealed interface OfShort extends OfConstant permits AnnotationImpl.OfShortImpl { - /** {@return the constant} */ + /** {@return the backing integer entry} */ + @Override + IntegerEntry constant(); + + /** + * {@return the constant short value} + * @jvms 2.11.1 Types and the Java Virtual Machine + */ short shortValue(); + + /** + * {@return the resolved short value} + * + * @implSpec + * This method returns the same as {@link #shortValue()}. + */ + @Override + default Short resolvedValue() { + return shortValue(); + } } /** - * Models a constant-valued element + * Models a char-valued element. + * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_CHAR}. * * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) - sealed interface OfCharacter extends AnnotationValue.OfConstant - permits AnnotationImpl.OfCharacterImpl { - /** {@return the constant} */ + sealed interface OfChar extends OfConstant + permits AnnotationImpl.OfCharImpl { + /** {@return the backing integer entry} */ + @Override + IntegerEntry constant(); + + /** + * {@return the constant char value} + * @jvms 2.11.1 Types and the Java Virtual Machine + */ char charValue(); + + /** + * {@return the resolved char value} + * + * @implSpec + * This method returns the same as {@link #charValue()}. + */ + @Override + default Character resolvedValue() { + return charValue(); + } } /** - * Models a constant-valued element + * Models a byte-valued element. + * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_BYTE}. * * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) - sealed interface OfByte extends AnnotationValue.OfConstant + sealed interface OfByte extends OfConstant permits AnnotationImpl.OfByteImpl { - /** {@return the constant} */ + /** {@return the backing integer entry} */ + @Override + IntegerEntry constant(); + + /** + * {@return the constant byte value} + * @jvms 2.11.1 Types and the Java Virtual Machine + */ byte byteValue(); + + /** + * {@return the resolved byte value} + * + * @implSpec + * This method returns the same as {@link #byteValue()}. + */ + @Override + default Byte resolvedValue() { + return byteValue(); + } } /** - * Models a constant-valued element + * Models a boolean-valued element. + * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_BOOLEAN}. * * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) - sealed interface OfBoolean extends AnnotationValue.OfConstant + sealed interface OfBoolean extends OfConstant permits AnnotationImpl.OfBooleanImpl { - /** {@return the constant} */ + /** {@return the backing integer entry} */ + @Override + IntegerEntry constant(); + + /** + * {@return the constant boolean value} + * @jvms 2.3.4 The boolean Type + */ boolean booleanValue(); + + /** + * {@return the resolved boolean value} + * + * @implSpec + * This method returns the same as {@link #booleanValue()}. + */ + @Override + default Boolean resolvedValue() { + return booleanValue(); + } } /** - * Models a class-valued element + * Models a class-valued element. + * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_CLASS}. * * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) sealed interface OfClass extends AnnotationValue permits AnnotationImpl.OfClassImpl { - /** {@return the class name} */ + /** {@return the class descriptor string} */ Utf8Entry className(); - /** {@return the class symbol} */ + /** {@return the class descriptor} */ default ClassDesc classSymbol() { return ClassDesc.ofDescriptor(className().stringValue()); } } /** - * Models an enum-valued element + * Models an enum-valued element. + * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_ENUM}. * * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) sealed interface OfEnum extends AnnotationValue permits AnnotationImpl.OfEnumImpl { - /** {@return the enum class name} */ + /** {@return the enum class descriptor string} */ Utf8Entry className(); - /** {@return the enum class symbol} */ + /** {@return the enum class descriptor} */ default ClassDesc classSymbol() { return ClassDesc.ofDescriptor(className().stringValue()); } @@ -249,7 +432,7 @@ default ClassDesc classSymbol() { /** * {@return an annotation element for a enum-valued element} - * @param className the name of the enum class + * @param className the descriptor string of the enum class * @param constantName the name of the enum constant */ static OfEnum ofEnum(Utf8Entry className, @@ -259,7 +442,7 @@ static OfEnum ofEnum(Utf8Entry className, /** * {@return an annotation element for a enum-valued element} - * @param className the name of the enum class + * @param className the descriptor of the enum class * @param constantName the name of the enum constant */ static OfEnum ofEnum(ClassDesc className, String constantName) { @@ -269,7 +452,7 @@ static OfEnum ofEnum(ClassDesc className, String constantName) { /** * {@return an annotation element for a class-valued element} - * @param className the name of the enum class + * @param className the descriptor string of the class */ static OfClass ofClass(Utf8Entry className) { return new AnnotationImpl.OfClassImpl(className); @@ -277,7 +460,7 @@ static OfClass ofClass(Utf8Entry className) { /** * {@return an annotation element for a class-valued element} - * @param className the name of the enum class + * @param className the descriptor of the class */ static OfClass ofClass(ClassDesc className) { return ofClass(TemporaryConstantPool.INSTANCE.utf8Entry(className.descriptorString())); @@ -287,7 +470,7 @@ static OfClass ofClass(ClassDesc className) { * {@return an annotation element for a string-valued element} * @param value the string */ - static OfConstant ofString(Utf8Entry value) { + static OfString ofString(Utf8Entry value) { return new AnnotationImpl.OfStringImpl(value); } @@ -295,7 +478,7 @@ static OfConstant ofString(Utf8Entry value) { * {@return an annotation element for a string-valued element} * @param value the string */ - static OfConstant ofString(String value) { + static OfString ofString(String value) { return ofString(TemporaryConstantPool.INSTANCE.utf8Entry(value)); } @@ -303,7 +486,7 @@ static OfConstant ofString(String value) { * {@return an annotation element for a double-valued element} * @param value the double value */ - static OfConstant ofDouble(DoubleEntry value) { + static OfDouble ofDouble(DoubleEntry value) { return new AnnotationImpl.OfDoubleImpl(value); } @@ -311,7 +494,7 @@ static OfConstant ofDouble(DoubleEntry value) { * {@return an annotation element for a double-valued element} * @param value the double value */ - static OfConstant ofDouble(double value) { + static OfDouble ofDouble(double value) { return ofDouble(TemporaryConstantPool.INSTANCE.doubleEntry(value)); } @@ -319,7 +502,7 @@ static OfConstant ofDouble(double value) { * {@return an annotation element for a float-valued element} * @param value the float value */ - static OfConstant ofFloat(FloatEntry value) { + static OfFloat ofFloat(FloatEntry value) { return new AnnotationImpl.OfFloatImpl(value); } @@ -327,7 +510,7 @@ static OfConstant ofFloat(FloatEntry value) { * {@return an annotation element for a float-valued element} * @param value the float value */ - static OfConstant ofFloat(float value) { + static OfFloat ofFloat(float value) { return ofFloat(TemporaryConstantPool.INSTANCE.floatEntry(value)); } @@ -335,7 +518,7 @@ static OfConstant ofFloat(float value) { * {@return an annotation element for a long-valued element} * @param value the long value */ - static OfConstant ofLong(LongEntry value) { + static OfLong ofLong(LongEntry value) { return new AnnotationImpl.OfLongImpl(value); } @@ -343,7 +526,7 @@ static OfConstant ofLong(LongEntry value) { * {@return an annotation element for a long-valued element} * @param value the long value */ - static OfConstant ofLong(long value) { + static OfLong ofLong(long value) { return ofLong(TemporaryConstantPool.INSTANCE.longEntry(value)); } @@ -351,15 +534,15 @@ static OfConstant ofLong(long value) { * {@return an annotation element for an int-valued element} * @param value the int value */ - static OfConstant ofInt(IntegerEntry value) { - return new AnnotationImpl.OfIntegerImpl(value); + static OfInt ofInt(IntegerEntry value) { + return new AnnotationImpl.OfIntImpl(value); } /** * {@return an annotation element for an int-valued element} * @param value the int value */ - static OfConstant ofInt(int value) { + static OfInt ofInt(int value) { return ofInt(TemporaryConstantPool.INSTANCE.intEntry(value)); } @@ -367,7 +550,7 @@ static OfConstant ofInt(int value) { * {@return an annotation element for a short-valued element} * @param value the short value */ - static OfConstant ofShort(IntegerEntry value) { + static OfShort ofShort(IntegerEntry value) { return new AnnotationImpl.OfShortImpl(value); } @@ -375,7 +558,7 @@ static OfConstant ofShort(IntegerEntry value) { * {@return an annotation element for a short-valued element} * @param value the short value */ - static OfConstant ofShort(short value) { + static OfShort ofShort(short value) { return ofShort(TemporaryConstantPool.INSTANCE.intEntry(value)); } @@ -383,15 +566,15 @@ static OfConstant ofShort(short value) { * {@return an annotation element for a char-valued element} * @param value the char value */ - static OfConstant ofChar(IntegerEntry value) { - return new AnnotationImpl.OfCharacterImpl(value); + static OfChar ofChar(IntegerEntry value) { + return new AnnotationImpl.OfCharImpl(value); } /** * {@return an annotation element for a char-valued element} * @param value the char value */ - static OfConstant ofChar(char value) { + static OfChar ofChar(char value) { return ofChar(TemporaryConstantPool.INSTANCE.intEntry(value)); } @@ -399,7 +582,7 @@ static OfConstant ofChar(char value) { * {@return an annotation element for a byte-valued element} * @param value the byte value */ - static OfConstant ofByte(IntegerEntry value) { + static OfByte ofByte(IntegerEntry value) { return new AnnotationImpl.OfByteImpl(value); } @@ -407,7 +590,7 @@ static OfConstant ofByte(IntegerEntry value) { * {@return an annotation element for a byte-valued element} * @param value the byte value */ - static OfConstant ofByte(byte value) { + static OfByte ofByte(byte value) { return ofByte(TemporaryConstantPool.INSTANCE.intEntry(value)); } @@ -415,7 +598,7 @@ static OfConstant ofByte(byte value) { * {@return an annotation element for a boolean-valued element} * @param value the boolean value */ - static OfConstant ofBoolean(IntegerEntry value) { + static OfBoolean ofBoolean(IntegerEntry value) { return new AnnotationImpl.OfBooleanImpl(value); } @@ -423,7 +606,7 @@ static OfConstant ofBoolean(IntegerEntry value) { * {@return an annotation element for a boolean-valued element} * @param value the boolean value */ - static OfConstant ofBoolean(boolean value) { + static OfBoolean ofBoolean(boolean value) { int i = value ? 1 : 0; return ofBoolean(TemporaryConstantPool.INSTANCE.intEntry(i)); } @@ -438,7 +621,7 @@ static OfAnnotation ofAnnotation(Annotation value) { /** * {@return an annotation element for an array-valued element} - * @param values the values + * @param values the array elements */ static OfArray ofArray(List values) { return new AnnotationImpl.OfArrayImpl(values); @@ -446,7 +629,7 @@ static OfArray ofArray(List values) { /** * {@return an annotation element for an array-valued element} - * @param values the values + * @param values the array elements */ static OfArray ofArray(AnnotationValue... values) { return ofArray(List.of(values)); diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/AnnotationConstantValueEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/AnnotationConstantValueEntry.java index 3a7053a49f5..d405f68570e 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/AnnotationConstantValueEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/AnnotationConstantValueEntry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,13 +24,23 @@ */ package java.lang.classfile.constantpool; +import java.lang.classfile.AnnotationValue; import java.lang.constant.ConstantDesc; import jdk.internal.javac.PreviewFeature; /** - * A constant pool entry that may be used as an annotation constant, - * which includes the four kinds of primitive constants, and UTF8 constants. + * A constant pool entry that may be used by annotation constant values, + * which includes the four kinds of primitive constants and UTF8 constants. + * These entries are also the only entries that do not refer to other + * constant pool entries. * + * @apiNote + * An annotation constant value entry alone is not sufficient to determine + * the annotation constant; for example, an {@link IntegerEntry} of {@code 1} + * can mean {@code true} in {@link AnnotationValue.OfBoolean} or {@code 1} + * in {@link AnnotationValue.OfInt}. + * + * @see AnnotationValue.OfConstant * @sealedGraph * @since 22 */ @@ -40,7 +50,8 @@ public sealed interface AnnotationConstantValueEntry extends PoolEntry /** * {@return the constant value} The constant value will be an {@link Integer}, - * {@link Long}, {@link Float}, {@link Double}, or {@link String}. + * {@link Long}, {@link Float}, {@link Double} for the primitive constants, + * or {@link String} for UTF8 constants. */ ConstantDesc constantValue(); } diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java index c0927175476..db77f8e2e8a 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java @@ -510,25 +510,6 @@ default LoadableConstantEntry loadableConstantEntry(ConstantDesc c) { throw new IllegalArgumentException("Illegal type: " + (c == null ? null : c.getClass())); } - /** - * {@return An {@link AnnotationConstantValueEntry} describing the provided - * constant} The constant should be an Integer, String, Long, Float, - * Double, ClassDesc (for a Class constant), or MethodTypeDesc (for a MethodType - * constant.) - * - * @param c the constant - */ - default AnnotationConstantValueEntry annotationConstantValueEntry(ConstantDesc c) { - if (c instanceof Integer i) return intEntry(i); - if (c instanceof String s) return utf8Entry(s); - if (c instanceof Long l) return longEntry(l); - if (c instanceof Float f) return floatEntry(f); - if (c instanceof Double d) return doubleEntry(d); - if (c instanceof ClassDesc cd) return utf8Entry(cd); - if (c instanceof MethodTypeDesc mtd) return utf8Entry(mtd); - throw new IllegalArgumentException("Illegal type: " + (c == null ? null : c.getClass())); - } - /** * {@return a {@link BootstrapMethodEntry} describing the provided * bootstrap method and static arguments} diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java index 03353e272a6..794e7915960 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java @@ -27,7 +27,6 @@ import java.lang.classfile.*; import java.lang.classfile.constantpool.*; -import java.lang.constant.ConstantDesc; import java.util.List; import static java.lang.classfile.ClassFile.*; @@ -80,12 +79,7 @@ public void writeTo(BufWriterImpl buf) { } } - public sealed interface OfConstantImpl extends AnnotationValue.OfConstant, Util.Writable - permits AnnotationImpl.OfStringImpl, AnnotationImpl.OfDoubleImpl, - AnnotationImpl.OfFloatImpl, AnnotationImpl.OfLongImpl, - AnnotationImpl.OfIntegerImpl, AnnotationImpl.OfShortImpl, - AnnotationImpl.OfCharacterImpl, AnnotationImpl.OfByteImpl, - AnnotationImpl.OfBooleanImpl { + public sealed interface OfConstantImpl extends AnnotationValue.OfConstant, Util.Writable { @Override default void writeTo(BufWriterImpl buf) { @@ -93,15 +87,10 @@ default void writeTo(BufWriterImpl buf) { buf.writeIndex(constant()); } - @Override - default ConstantDesc constantValue() { - return constant().constantValue(); - } - } public record OfStringImpl(Utf8Entry constant) - implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfString { + implements OfConstantImpl, AnnotationValue.OfString { @Override public char tag() { @@ -115,7 +104,7 @@ public String stringValue() { } public record OfDoubleImpl(DoubleEntry constant) - implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfDouble { + implements OfConstantImpl, AnnotationValue.OfDouble { @Override public char tag() { @@ -129,7 +118,7 @@ public double doubleValue() { } public record OfFloatImpl(FloatEntry constant) - implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfFloat { + implements OfConstantImpl, AnnotationValue.OfFloat { @Override public char tag() { @@ -143,7 +132,7 @@ public float floatValue() { } public record OfLongImpl(LongEntry constant) - implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfLong { + implements OfConstantImpl, AnnotationValue.OfLong { @Override public char tag() { @@ -156,8 +145,8 @@ public long longValue() { } } - public record OfIntegerImpl(IntegerEntry constant) - implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfInteger { + public record OfIntImpl(IntegerEntry constant) + implements OfConstantImpl, AnnotationValue.OfInt { @Override public char tag() { @@ -171,7 +160,7 @@ public int intValue() { } public record OfShortImpl(IntegerEntry constant) - implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfShort { + implements OfConstantImpl, AnnotationValue.OfShort { @Override public char tag() { @@ -180,12 +169,12 @@ public char tag() { @Override public short shortValue() { - return (short)constant().intValue(); + return (short) constant().intValue(); } } - public record OfCharacterImpl(IntegerEntry constant) - implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfCharacter { + public record OfCharImpl(IntegerEntry constant) + implements OfConstantImpl, AnnotationValue.OfChar { @Override public char tag() { @@ -194,12 +183,12 @@ public char tag() { @Override public char charValue() { - return (char)constant().intValue(); + return (char) constant().intValue(); } } public record OfByteImpl(IntegerEntry constant) - implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfByte { + implements OfConstantImpl, AnnotationValue.OfByte { @Override public char tag() { @@ -208,12 +197,12 @@ public char tag() { @Override public byte byteValue() { - return (byte)constant().intValue(); + return (byte) constant().intValue(); } } public record OfBooleanImpl(IntegerEntry constant) - implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfBoolean { + implements OfConstantImpl, AnnotationValue.OfBoolean { @Override public char tag() { @@ -222,15 +211,15 @@ public char tag() { @Override public boolean booleanValue() { - return constant().intValue() == 1; + return constant().intValue() != 0; } } public record OfArrayImpl(List values) implements AnnotationValue.OfArray, Util.Writable { - public OfArrayImpl(List values) { - this.values = List.copyOf(values); + public OfArrayImpl { + values = List.copyOf(values); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java index 2ada13aaba8..e21938bbc0c 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java @@ -60,10 +60,10 @@ public static AnnotationValue readElementValue(ClassReader classReader, int p) { ++p; return switch (tag) { case AEV_BYTE -> new AnnotationImpl.OfByteImpl(classReader.readEntry(p, IntegerEntry.class)); - case AEV_CHAR -> new AnnotationImpl.OfCharacterImpl(classReader.readEntry(p, IntegerEntry.class)); + case AEV_CHAR -> new AnnotationImpl.OfCharImpl(classReader.readEntry(p, IntegerEntry.class)); case AEV_DOUBLE -> new AnnotationImpl.OfDoubleImpl(classReader.readEntry(p, DoubleEntry.class)); case AEV_FLOAT -> new AnnotationImpl.OfFloatImpl(classReader.readEntry(p, FloatEntry.class)); - case AEV_INT -> new AnnotationImpl.OfIntegerImpl(classReader.readEntry(p, IntegerEntry.class)); + case AEV_INT -> new AnnotationImpl.OfIntImpl(classReader.readEntry(p, IntegerEntry.class)); case AEV_LONG -> new AnnotationImpl.OfLongImpl(classReader.readEntry(p, LongEntry.class)); case AEV_SHORT -> new AnnotationImpl.OfShortImpl(classReader.readEntry(p, IntegerEntry.class)); case AEV_BOOLEAN -> new AnnotationImpl.OfBooleanImpl(classReader.readEntry(p, IntegerEntry.class)); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java index fac2eba95fe..75346dd5998 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -507,15 +507,15 @@ private static String toXmlName(String name) { private static Node[] elementValueToTree(AnnotationValue v) { return switch (v) { - case OfString cv -> leafs("string", String.valueOf(cv.constantValue())); - case OfDouble cv -> leafs("double", String.valueOf(cv.constantValue())); - case OfFloat cv -> leafs("float", String.valueOf(cv.constantValue())); - case OfLong cv -> leafs("long", String.valueOf(cv.constantValue())); - case OfInteger cv -> leafs("int", String.valueOf(cv.constantValue())); - case OfShort cv -> leafs("short", String.valueOf(cv.constantValue())); - case OfCharacter cv -> leafs("char", String.valueOf(cv.constantValue())); - case OfByte cv -> leafs("byte", String.valueOf(cv.constantValue())); - case OfBoolean cv -> leafs("boolean", String.valueOf((int)cv.constantValue() != 0)); + case OfString cv -> leafs("string", String.valueOf(cv.stringValue())); + case OfDouble cv -> leafs("double", String.valueOf(cv.doubleValue())); + case OfFloat cv -> leafs("float", String.valueOf(cv.floatValue())); + case OfLong cv -> leafs("long", String.valueOf(cv.longValue())); + case OfInt cv -> leafs("int", String.valueOf(cv.intValue())); + case OfShort cv -> leafs("short", String.valueOf(cv.shortValue())); + case OfChar cv -> leafs("char", String.valueOf(cv.charValue())); + case OfByte cv -> leafs("byte", String.valueOf(cv.byteValue())); + case OfBoolean cv -> leafs("boolean", String.valueOf(cv.booleanValue())); case OfClass clv -> leafs("class", clv.className().stringValue()); case OfEnum ev -> leafs("enum class", ev.className().stringValue(), "constant name", ev.constantName().stringValue()); diff --git a/test/jdk/jdk/classfile/AnnotationTest.java b/test/jdk/jdk/classfile/AnnotationTest.java index 4ed3b2141ad..6b6b88b3de1 100644 --- a/test/jdk/jdk/classfile/AnnotationTest.java +++ b/test/jdk/jdk/classfile/AnnotationTest.java @@ -28,6 +28,8 @@ */ import java.lang.constant.ClassDesc; import static java.lang.constant.ConstantDescs.*; + +import java.lang.constant.ConstantDesc; import java.lang.constant.MethodTypeDesc; import java.util.AbstractMap; import java.util.ArrayList; @@ -39,6 +41,8 @@ import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; import java.lang.classfile.*; import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.util.stream.Stream; + import org.junit.jupiter.api.Test; import static java.util.stream.Collectors.toList; @@ -53,26 +57,30 @@ class AnnotationTest { enum E {C}; - private static Map constants + // name -> (value, poolValue) + private static final Map> constants = Map.ofEntries( - new AbstractMap.SimpleImmutableEntry<>("i", 1), - new AbstractMap.SimpleImmutableEntry<>("j", 1L), - new AbstractMap.SimpleImmutableEntry<>("s", 1), - new AbstractMap.SimpleImmutableEntry<>("b", 1), - new AbstractMap.SimpleImmutableEntry<>("f", 1.0f), - new AbstractMap.SimpleImmutableEntry<>("d", 1.0d), - new AbstractMap.SimpleImmutableEntry<>("z", 1), - new AbstractMap.SimpleImmutableEntry<>("c", (int) '1'), - new AbstractMap.SimpleImmutableEntry<>("st", "1"), - new AbstractMap.SimpleImmutableEntry<>("cl", ClassDesc.of("foo.Bar")), - new AbstractMap.SimpleImmutableEntry<>("en", E.C), - new AbstractMap.SimpleImmutableEntry<>("arr", new Object[] {1, "1", 1.0f}) + Map.entry("i", Map.entry(1, 1)), + Map.entry("j", Map.entry(1L, 1L)), + Map.entry("s", Map.entry((short) 1, 1)), + Map.entry("b", Map.entry((byte) 1, 1)), + Map.entry("f", Map.entry(1.0f, 1.0f)), + Map.entry("d", Map.entry(1.0d, 1.0d)), + Map.entry("z", Map.entry(true, 1)), + Map.entry("c", Map.entry('1', (int) '1')), + Map.entry("st", Map.entry("1", "1")) ); - private static final List constantElements = + private static final List constantElements = Stream.concat( constants.entrySet().stream() - .map(e -> AnnotationElement.of(e.getKey(), AnnotationValue.of(e.getValue()))) - .toList(); + .map(e -> Map.entry(e.getKey(), e.getValue().getKey())), + Stream.of( + Map.entry("cl", ClassDesc.of("foo.Bar")), + Map.entry("en", E.C), + Map.entry("arr", new Object[] {1, "1", 1.0f}) + )) + .map(e -> AnnotationElement.of(e.getKey(), AnnotationValue.of(e.getValue()))) + .toList(); private static List elements() { List list = new ArrayList<>(constantElements); @@ -88,9 +96,12 @@ private static boolean assertAnno(Annotation a, String annoClassDescriptor, bool names.add(evp.name().stringValue()); switch (evp.name().stringValue()) { case "i", "j", "s", "b", "f", "d", "z", "c", "st": - assertTrue (evp.value() instanceof AnnotationValue.OfConstant c); - assertEquals(((AnnotationValue.OfConstant) evp.value()).constantValue(), - constants.get(evp.name().stringValue())); + if (!(evp.value() instanceof AnnotationValue.OfConstant c)) + return fail(); + assertEquals(c.resolvedValue(), + constants.get(evp.name().stringValue()).getKey()); + assertEquals(c.constant().constantValue(), + constants.get(evp.name().stringValue()).getValue()); break; case "cl": assertTrue (evp.value() instanceof AnnotationValue.OfClass c @@ -105,8 +116,9 @@ private static boolean assertAnno(Annotation a, String annoClassDescriptor, bool && assertAnno(c.annotation(), "LBar;", false)); break; case "arr": - assertTrue (evp.value() instanceof AnnotationValue.OfArray); - List values = ((AnnotationValue.OfArray) evp.value()).values(); + if (!(evp.value() instanceof AnnotationValue.OfArray arr)) + return fail(); + List values = arr.values(); assertEquals(values.stream().map(v -> ((AnnotationValue.OfConstant) v).constant().constantValue()).collect(toSet()), Set.of(1, 1.0f, "1")); break; diff --git a/test/jdk/jdk/classfile/ClassPrinterTest.java b/test/jdk/jdk/classfile/ClassPrinterTest.java index 9c25ff7e13a..7668648f829 100644 --- a/test/jdk/jdk/classfile/ClassPrinterTest.java +++ b/test/jdk/jdk/classfile/ClassPrinterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ /* * @test + * @bug 8335927 * @summary Testing ClassFile ClassPrinter. * @run junit ClassPrinterTest */ @@ -249,7 +250,7 @@ record components: flags: [PROTECTED] method type: (ZLjava/lang/Throwable;)Ljava/lang/Void; attributes: [AnnotationDefault, RuntimeVisibleParameterAnnotations, RuntimeInvisibleParameterAnnotations, Exceptions, Code] - annotation default: {array: [{boolean: true}, {byte: 12}, {char: 99}, {class: LPhee;}, {double: 1.3}, {enum class: LBoo;, constant name: BOO}, {float: 3.7}, {int: 33}, {long: 3333}, {short: 25}, {string: BOO}, {annotation class: LPhoo;}]} + annotation default: {array: [{boolean: true}, {byte: 12}, {char: c}, {class: LPhee;}, {double: 1.3}, {enum class: LBoo;, constant name: BOO}, {float: 3.7}, {int: 33}, {long: 3333}, {short: 25}, {string: BOO}, {annotation class: LPhoo;}]} visible parameter annotations: parameter 1: [{annotation class: LPhoo;, values: [{name: flfl, value: {float: 22.0}}, {name: frfl, value: {float: 11.0}}]}] invisible parameter annotations: @@ -500,7 +501,7 @@ void testPrintJsonTraceAll() throws IOException { "flags": ["PROTECTED"], "method type": "(ZLjava/lang/Throwable;)Ljava/lang/Void;", "attributes": ["AnnotationDefault", "RuntimeVisibleParameterAnnotations", "RuntimeInvisibleParameterAnnotations", "Exceptions", "Code"], - "annotation default": {"array": [{"boolean": "true"}, {"byte": "12"}, {"char": "99"}, {"class": "LPhee;"}, {"double": "1.3"}, {"enum class": "LBoo;", "constant name": "BOO"}, {"float": "3.7"}, {"int": "33"}, {"long": "3333"}, {"short": "25"}, {"string": "BOO"}, {"annotation class": "LPhoo;"}]}, + "annotation default": {"array": [{"boolean": "true"}, {"byte": "12"}, {"char": "c"}, {"class": "LPhee;"}, {"double": "1.3"}, {"enum class": "LBoo;", "constant name": "BOO"}, {"float": "3.7"}, {"int": "33"}, {"long": "3333"}, {"short": "25"}, {"string": "BOO"}, {"annotation class": "LPhoo;"}]}, "visible parameter annotations": { "parameter 1": [{"annotation class": "LPhoo;", "values": [{"name": "flfl", "value": {"float": "22.0"}}, {"name": "frfl", "value": {"float": "11.0"}}]}]}, "invisible parameter annotations": { @@ -756,7 +757,7 @@ void testPrintXmlTraceAll() throws IOException { PROTECTED (ZLjava/lang/Throwable;)Ljava/lang/Void; AnnotationDefaultRuntimeVisibleParameterAnnotationsRuntimeInvisibleParameterAnnotationsExceptionsCode - true1299LPhee;1.3LBoo;BOO3.733333325BOOLPhoo; + true12cLPhee;1.3LBoo;BOO3.733333325BOOLPhoo; LPhoo;flfl22.0frfl11.0 @@ -907,6 +908,6 @@ private static void assertOut(StringBuilder out, String expected) { // System.out.println("-----------------"); // System.out.println(out.toString()); // System.out.println("-----------------"); - assertArrayEquals(out.toString().trim().split(" *\r?\n"), expected.trim().split("\n")); + assertArrayEquals(expected.trim().split("\n"), out.toString().trim().split(" *\r?\n")); } } diff --git a/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java b/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java index 2af3cd9410f..7667403aaab 100644 --- a/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java +++ b/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java @@ -165,9 +165,9 @@ static AnnotationValue transformAnnotationValue(AnnotationValue av) { case AnnotationValue.OfDouble v -> AnnotationValue.of(v.doubleValue()); case AnnotationValue.OfFloat v -> AnnotationValue.of(v.floatValue()); case AnnotationValue.OfLong v -> AnnotationValue.of(v.longValue()); - case AnnotationValue.OfInteger v -> AnnotationValue.of(v.intValue()); + case AnnotationValue.OfInt v -> AnnotationValue.of(v.intValue()); case AnnotationValue.OfShort v -> AnnotationValue.of(v.shortValue()); - case AnnotationValue.OfCharacter v -> AnnotationValue.of(v.charValue()); + case AnnotationValue.OfChar v -> AnnotationValue.of(v.charValue()); case AnnotationValue.OfByte v -> AnnotationValue.of(v.byteValue()); case AnnotationValue.OfBoolean v -> AnnotationValue.of(v.booleanValue()); case AnnotationValue.OfClass oc -> AnnotationValue.of(oc.classSymbol()); diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousClassTest.java b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousClassTest.java index 64c33ed9fd9..94610ddf055 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousClassTest.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousClassTest.java @@ -246,7 +246,7 @@ private static String annotationValueDebugString(ClassModel cm, Annotation annot private static String elementValueDebugString(AnnotationValue value) { if (value.tag() == 'I') { - return Integer.toString(((AnnotationValue.OfInteger) value).intValue()); + return Integer.toString(((AnnotationValue.OfInt) value).intValue()); } else { throw new UnsupportedOperationException(String.format("%c", value.tag())); } diff --git a/test/langtools/tools/javac/classfiles/attributes/AnnotationDefault/AnnotationDefaultVerifier.java b/test/langtools/tools/javac/classfiles/attributes/AnnotationDefault/AnnotationDefaultVerifier.java index d85b37aa3a3..8efb13ccbdf 100644 --- a/test/langtools/tools/javac/classfiles/attributes/AnnotationDefault/AnnotationDefaultVerifier.java +++ b/test/langtools/tools/javac/classfiles/attributes/AnnotationDefault/AnnotationDefaultVerifier.java @@ -103,7 +103,7 @@ public void testElementValue( case AnnotationValue.OfByte ev -> { testCase.checkEquals((int)ev.byteValue(), Integer.parseInt(values[0]), "const_value_index"); } - case AnnotationValue.OfCharacter ev -> { + case AnnotationValue.OfChar ev -> { testCase.checkEquals((int)ev.charValue(), Integer.parseInt(values[0]), "const_value_index"); } case AnnotationValue.OfShort ev -> { @@ -113,7 +113,7 @@ public void testElementValue( testCase.checkEquals(ev.booleanValue()? 1: 0, Integer.parseInt(values[0]), "const_value_index"); } default -> { - testCase.checkEquals(((AnnotationValue.OfInteger) element_value).intValue(), Integer.parseInt(values[0]), "const_value_index"); + testCase.checkEquals(((AnnotationValue.OfInt) element_value).intValue(), Integer.parseInt(values[0]), "const_value_index"); } } } diff --git a/test/langtools/tools/javac/classfiles/attributes/annotations/TestAnnotationInfo.java b/test/langtools/tools/javac/classfiles/attributes/annotations/TestAnnotationInfo.java index 5bf587d1b8b..3f422b541c0 100644 --- a/test/langtools/tools/javac/classfiles/attributes/annotations/TestAnnotationInfo.java +++ b/test/langtools/tools/javac/classfiles/attributes/annotations/TestAnnotationInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -123,7 +123,7 @@ public void testElementValue(TestResult testResult, testResult.checkEquals((int)((AnnotationValue.OfShort) element_value).shortValue(), value, "const_value_index : " + value); break; default: - testResult.checkEquals(((AnnotationValue.OfInteger) element_value).intValue(), value, "const_value_index : " + value); + testResult.checkEquals(((AnnotationValue.OfInt) element_value).intValue(), value, "const_value_index : " + value); } } @@ -169,8 +169,8 @@ public void testElementValue(TestResult testResult, ClassModel classFile, AnnotationValue element_value) { testTag(testResult, element_value.tag()); - AnnotationValue.OfCharacter ev = - (AnnotationValue.OfCharacter) element_value; + AnnotationValue.OfChar ev = + (AnnotationValue.OfChar) element_value; testResult.checkEquals(ev.charValue(), value, "const_value_index : " + value); } From 58b957054437edee7d0abc365133985ac30a6af4 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Tue, 13 Aug 2024 16:05:38 +0000 Subject: [PATCH 399/460] 8338142: (dc) DatagramChannelImpl.blockingReceive can use untimed-park when no timeout set Reviewed-by: dfuchs --- .../classes/sun/nio/ch/DatagramChannelImpl.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java index 5c06ac7d9be..06e79f416ac 100644 --- a/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java @@ -674,7 +674,6 @@ void blockingReceive(DatagramPacket p, long nanos) throws IOException { configureSocketNonBlocking(); } else { configureSocketNonBlockingIfVirtualThread(); - nanos = Long.MAX_VALUE; } // p.bufLength is the maximum size of the datagram that can be received @@ -689,7 +688,9 @@ void blockingReceive(DatagramPacket p, long nanos) throws IOException { SocketAddress remote = beginRead(true, false); boolean connected = (remote != null); do { - long remainingNanos = nanos - (System.nanoTime() - startNanos); + long remainingNanos = (nanos > 0) + ? nanos - (System.nanoTime() - startNanos) + : 0; ByteBuffer dst = tryBlockingReceive(connected, bufLength, remainingNanos); // if datagram received then get sender and copy to DatagramPacket @@ -756,11 +757,15 @@ private ByteBuffer tryBlockingReceive(boolean connected, int len, long nanos) Util.offerFirstTemporaryDirectBuffer(dst); dst = null; } - long remainingNanos = nanos - (System.nanoTime() - startNanos); - if (remainingNanos <= 0) { - throw new SocketTimeoutException("Receive timed out"); + if (nanos > 0) { + long remainingNanos = nanos - (System.nanoTime() - startNanos); + if (remainingNanos <= 0) { + throw new SocketTimeoutException("Receive timed out"); + } + park(Net.POLLIN, remainingNanos); + } else { + park(Net.POLLIN); } - park(Net.POLLIN, remainingNanos); // virtual thread needs to re-allocate temporary direct buffer after parking if (Thread.currentThread().isVirtual()) { dst = Util.getTemporaryDirectBuffer(len); From 21ca91e55dd83dc011e67a2d056e3e3bd44d40b5 Mon Sep 17 00:00:00 2001 From: Afshin Zafari Date: Tue, 13 Aug 2024 16:25:43 +0000 Subject: [PATCH 400/460] 8300800: UB: Shift exponent 32 is too large for 32-bit type 'int' Reviewed-by: kbarrett, adinn, gziemski --- src/hotspot/cpu/aarch64/immediate_aarch64.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/cpu/aarch64/immediate_aarch64.cpp b/src/hotspot/cpu/aarch64/immediate_aarch64.cpp index 7caafc19fbd..9c67a0dfead 100644 --- a/src/hotspot/cpu/aarch64/immediate_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/immediate_aarch64.cpp @@ -295,7 +295,7 @@ static int expandLogicalImmediate(uint32_t immN, uint32_t immr, uint64_t and_bits_sub = replicate(and_bit, 1, nbits); uint64_t or_bits_sub = replicate(or_bit, 1, nbits); uint64_t and_bits_top = (and_bits_sub << nbits) | ones(nbits); - uint64_t or_bits_top = (0 << nbits) | or_bits_sub; + uint64_t or_bits_top = (UCONST64(0) << nbits) | or_bits_sub; tmask = ((tmask & (replicate(and_bits_top, 2 * nbits, 32 / nbits))) From 84c3065e8004122f3455a8c28c8719b2c8111c17 Mon Sep 17 00:00:00 2001 From: Neethu Prasad Date: Tue, 13 Aug 2024 17:22:41 +0000 Subject: [PATCH 401/460] 8335865: Shenandoah: Improve THP pretouch after JDK-8315923 Reviewed-by: shade, wkemper --- .../share/gc/shenandoah/shenandoahHeap.cpp | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 0a20307abcb..7904cd5f1cd 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -283,14 +283,7 @@ jint ShenandoahHeap::initialize() { // Reserve aux bitmap for use in object_iterate(). We don't commit it here. size_t aux_bitmap_page_size = bitmap_page_size; -#ifdef LINUX - // In THP "advise" mode, we refrain from advising the system to use large pages - // since we know these commits will be short lived, and there is no reason to trash - // the THP area with this bitmap. - if (UseTransparentHugePages) { - aux_bitmap_page_size = os::vm_page_size(); - } -#endif + ReservedSpace aux_bitmap(_bitmap_size, aux_bitmap_page_size); os::trace_page_sizes_for_requested_size("Aux Bitmap", bitmap_size_orig, aux_bitmap_page_size, @@ -387,16 +380,6 @@ jint ShenandoahHeap::initialize() { _pretouch_heap_page_size = heap_page_size; _pretouch_bitmap_page_size = bitmap_page_size; -#ifdef LINUX - // UseTransparentHugePages would madvise that backing memory can be coalesced into huge - // pages. But, the kernel needs to know that every small page is used, in order to coalesce - // them into huge one. Therefore, we need to pretouch with smaller pages. - if (UseTransparentHugePages) { - _pretouch_heap_page_size = (size_t)os::vm_page_size(); - _pretouch_bitmap_page_size = (size_t)os::vm_page_size(); - } -#endif - // OS memory managers may want to coalesce back-to-back pages. Make their jobs // simpler by pre-touching continuous spaces (heap and bitmap) separately. From ca99f37f82bf59fc720babbc155502ef92d34de6 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 13 Aug 2024 18:02:24 +0000 Subject: [PATCH 402/460] 8338156: Fix -Wzero-as-null-pointer-constant warnings in jvmciCompilerToVM.cpp Reviewed-by: tschatzl, jwaters, dnsimon --- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 5a9b18fc4d3..af72322ff4b 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -549,8 +549,8 @@ C2V_END C2V_VMENTRY_NULL(jobject, getImplementor, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass))) Klass* klass = UNPACK_PAIR(Klass, klass); if (!klass->is_interface()) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), - err_msg("Expected interface type, got %s", klass->external_name())); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Expected interface type, got %s", klass->external_name())); } InstanceKlass* iklass = InstanceKlass::cast(klass); JVMCIKlassHandle handle(THREAD, iklass->implementor()); @@ -589,7 +589,7 @@ C2V_VMENTRY_NULL(jobject, lookupType, (JNIEnv* env, jobject, jstring jname, ARGU TempNewSymbol class_name = SymbolTable::new_symbol(str); if (class_name->utf8_length() <= 1) { - JVMCI_THROW_MSG_0(InternalError, err_msg("Primitive type %s should be handled in Java code", str)); + JVMCI_THROW_MSG_NULL(InternalError, err_msg("Primitive type %s should be handled in Java code", str)); } #ifdef ASSERT @@ -598,8 +598,8 @@ C2V_VMENTRY_NULL(jobject, lookupType, (JNIEnv* env, jobject, jstring jname, ARGU if (strstr(val, "") != nullptr) { tty->print_cr("CompilerToVM.lookupType: %s", str); } else if (strstr(str, val) != nullptr) { - THROW_MSG_0(vmSymbols::java_lang_Exception(), - err_msg("lookupTypeException: %s", str)); + THROW_MSG_NULL(vmSymbols::java_lang_Exception(), + err_msg("lookupTypeException: %s", str)); } } #endif @@ -617,7 +617,7 @@ C2V_VMENTRY_NULL(jobject, lookupType, (JNIEnv* env, jobject, jstring jname, ARGU case 1: class_loader = Handle(THREAD, SystemDictionary::java_platform_loader()); break; case 2: class_loader = Handle(THREAD, SystemDictionary::java_system_loader()); break; default: - JVMCI_THROW_MSG_0(InternalError, err_msg("Illegal class loader value: %d", accessing_klass_loader)); + JVMCI_THROW_MSG_NULL(InternalError, err_msg("Illegal class loader value: %d", accessing_klass_loader)); } JVMCIENV->runtime()->initialize(JVMCI_CHECK_NULL); } @@ -660,7 +660,7 @@ C2V_VMENTRY_NULL(jobject, getArrayType, (JNIEnv* env, jobject, jchar type_char, JVMCIKlassHandle array_klass(THREAD); Klass* klass = UNPACK_PAIR(Klass, klass); if (klass == nullptr) { - BasicType type = JVMCIENV->typeCharToBasicType(type_char, JVMCI_CHECK_0); + BasicType type = JVMCIENV->typeCharToBasicType(type_char, JVMCI_CHECK_NULL); if (type == T_VOID) { return nullptr; } @@ -812,7 +812,7 @@ C2V_VMENTRY_NULL(jobjectArray, resolveBootstrapMethod, (JNIEnv* env, jobject, AR bool is_indy = tag.is_invoke_dynamic(); bool is_condy = tag.is_dynamic_constant(); if (!(is_condy || is_indy)) { - JVMCI_THROW_MSG_0(IllegalArgumentException, err_msg("Unexpected constant pool tag at index %d: %d", index, tag.value())); + JVMCI_THROW_MSG_NULL(IllegalArgumentException, err_msg("Unexpected constant pool tag at index %d: %d", index, tag.value())); } // Get the indy entry based on CP index int indy_index = -1; @@ -1969,11 +1969,11 @@ C2V_END C2V_VMENTRY_NULL(jobject, getInterfaces, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass))) Klass* klass = UNPACK_PAIR(Klass, klass); if (klass == nullptr) { - JVMCI_THROW_0(NullPointerException); + JVMCI_THROW_NULL(NullPointerException); } if (!klass->is_instance_klass()) { - JVMCI_THROW_MSG_0(InternalError, err_msg("Class %s must be instance klass", klass->external_name())); + JVMCI_THROW_MSG_NULL(InternalError, err_msg("Class %s must be instance klass", klass->external_name())); } InstanceKlass* iklass = InstanceKlass::cast(klass); @@ -1993,7 +1993,7 @@ C2V_END C2V_VMENTRY_NULL(jobject, getComponentType, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass))) Klass* klass = UNPACK_PAIR(Klass, klass); if (klass == nullptr) { - JVMCI_THROW_0(NullPointerException); + JVMCI_THROW_NULL(NullPointerException); } if (!klass->is_array_klass()) { @@ -2002,8 +2002,8 @@ C2V_VMENTRY_NULL(jobject, getComponentType, (JNIEnv* env, jobject, ARGUMENT_PAIR oop mirror = klass->java_mirror(); oop component_mirror = java_lang_Class::component_mirror(mirror); if (component_mirror == nullptr) { - JVMCI_THROW_MSG_0(NullPointerException, - err_msg("Component mirror for array class %s is null", klass->external_name())) + JVMCI_THROW_MSG_NULL(NullPointerException, + err_msg("Component mirror for array class %s is null", klass->external_name())) } Klass* component_klass = java_lang_Class::as_Klass(component_mirror); @@ -2106,7 +2106,7 @@ C2V_END C2V_VMENTRY_NULL(jobject, unboxPrimitive, (JNIEnv* env, jobject, jobject object)) if (object == nullptr) { - JVMCI_THROW_0(NullPointerException); + JVMCI_THROW_NULL(NullPointerException); } Handle box = JVMCIENV->asConstant(JVMCIENV->wrap(object), JVMCI_CHECK_NULL); BasicType type = java_lang_boxing_object::basic_type(box()); @@ -2120,7 +2120,7 @@ C2V_END C2V_VMENTRY_NULL(jobject, boxPrimitive, (JNIEnv* env, jobject, jobject object)) if (object == nullptr) { - JVMCI_THROW_0(NullPointerException); + JVMCI_THROW_NULL(NullPointerException); } JVMCIObject box = JVMCIENV->wrap(object); BasicType type = JVMCIENV->get_box_type(box); @@ -2165,7 +2165,7 @@ C2V_END C2V_VMENTRY_NULL(jobjectArray, getDeclaredConstructors, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass))) Klass* klass = UNPACK_PAIR(Klass, klass); if (klass == nullptr) { - JVMCI_THROW_0(NullPointerException); + JVMCI_THROW_NULL(NullPointerException); } if (!klass->is_instance_klass()) { JVMCIObjectArray methods = JVMCIENV->new_ResolvedJavaMethod_array(0, JVMCI_CHECK_NULL); @@ -2192,7 +2192,7 @@ C2V_END C2V_VMENTRY_NULL(jobjectArray, getDeclaredMethods, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass))) Klass* klass = UNPACK_PAIR(Klass, klass); if (klass == nullptr) { - JVMCI_THROW_0(NullPointerException); + JVMCI_THROW_NULL(NullPointerException); } if (!klass->is_instance_klass()) { JVMCIObjectArray methods = JVMCIENV->new_ResolvedJavaMethod_array(0, JVMCI_CHECK_NULL); @@ -2219,7 +2219,7 @@ C2V_END C2V_VMENTRY_NULL(jobjectArray, getDeclaredFieldsInfo, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass))) Klass* klass = UNPACK_PAIR(Klass, klass); if (klass == nullptr) { - JVMCI_THROW_0(NullPointerException); + JVMCI_THROW_NULL(NullPointerException); } if (!klass->is_instance_klass()) { JVMCI_THROW_MSG_NULL(IllegalArgumentException, "not an InstanceKlass"); @@ -2346,7 +2346,7 @@ C2V_END C2V_VMENTRY_NULL(jobject, readFieldValue, (JNIEnv* env, jobject, jobject object, ARGUMENT_PAIR(expected_type), long displacement, jchar type_char)) if (object == nullptr) { - JVMCI_THROW_0(NullPointerException); + JVMCI_THROW_NULL(NullPointerException); } // asConstant will throw an NPE if a constant contains null @@ -2396,7 +2396,7 @@ C2V_END C2V_VMENTRY_NULL(jobject, asJavaType, (JNIEnv* env, jobject, jobject object)) if (object == nullptr) { - JVMCI_THROW_0(NullPointerException); + JVMCI_THROW_NULL(NullPointerException); } Handle obj = JVMCIENV->asConstant(JVMCIENV->wrap(object), JVMCI_CHECK_NULL); if (java_lang_Class::is_instance(obj())) { @@ -2416,7 +2416,7 @@ C2V_END C2V_VMENTRY_NULL(jobject, asString, (JNIEnv* env, jobject, jobject object)) if (object == nullptr) { - JVMCI_THROW_0(NullPointerException); + JVMCI_THROW_NULL(NullPointerException); } Handle obj = JVMCIENV->asConstant(JVMCIENV->wrap(object), JVMCI_CHECK_NULL); const char* str = java_lang_String::as_utf8_string(obj()); @@ -2435,7 +2435,7 @@ C2V_END C2V_VMENTRY_NULL(jobject, getJavaMirror, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass))) Klass* klass = UNPACK_PAIR(Klass, klass); if (klass == nullptr) { - JVMCI_THROW_0(NullPointerException); + JVMCI_THROW_NULL(NullPointerException); } Handle mirror(THREAD, klass->java_mirror()); JVMCIObject result = JVMCIENV->get_object_constant(mirror()); @@ -2457,7 +2457,7 @@ C2V_VMENTRY_0(jint, getArrayLength, (JNIEnv* env, jobject, jobject x)) C2V_VMENTRY_NULL(jobject, readArrayElement, (JNIEnv* env, jobject, jobject x, int index)) if (x == nullptr) { - JVMCI_THROW_0(NullPointerException); + JVMCI_THROW_NULL(NullPointerException); } Handle xobj = JVMCIENV->asConstant(JVMCIENV->wrap(x), JVMCI_CHECK_NULL); if (xobj->klass()->is_array_klass()) { @@ -2543,16 +2543,16 @@ C2V_VMENTRY_NULL(jlongArray, registerNativeMethods, (JNIEnv* env, jobject, jclas } sl_handle = JVMCI::get_shared_library(sl_path, false); if (sl_handle == nullptr) { - JVMCI_THROW_MSG_0(InternalError, err_msg("Error initializing JVMCI runtime %d", runtime->id())); + JVMCI_THROW_MSG_NULL(InternalError, err_msg("Error initializing JVMCI runtime %d", runtime->id())); } } if (mirror == nullptr) { - JVMCI_THROW_0(NullPointerException); + JVMCI_THROW_NULL(NullPointerException); } Klass* klass = java_lang_Class::as_Klass(JNIHandles::resolve(mirror)); if (klass == nullptr || !klass->is_instance_klass()) { - JVMCI_THROW_MSG_0(IllegalArgumentException, "clazz is for primitive type"); + JVMCI_THROW_MSG_NULL(IllegalArgumentException, "clazz is for primitive type"); } InstanceKlass* iklass = InstanceKlass::cast(klass); @@ -2587,14 +2587,14 @@ C2V_VMENTRY_NULL(jlongArray, registerNativeMethods, (JNIEnv* env, jobject, jclas char* jni_long_name = st.as_string(); entry = (address) os::dll_lookup(sl_handle, jni_long_name); if (entry == nullptr) { - JVMCI_THROW_MSG_0(UnsatisfiedLinkError, err_msg("%s [neither %s nor %s exist in %s]", + JVMCI_THROW_MSG_NULL(UnsatisfiedLinkError, err_msg("%s [neither %s nor %s exist in %s]", method->name_and_sig_as_C_string(), jni_name, jni_long_name, sl_path)); } } if (method->has_native_function() && entry != method->native_function()) { - JVMCI_THROW_MSG_0(UnsatisfiedLinkError, err_msg("%s [cannot re-link from " PTR_FORMAT " to " PTR_FORMAT "]", + JVMCI_THROW_MSG_NULL(UnsatisfiedLinkError, err_msg("%s [cannot re-link from " PTR_FORMAT " to " PTR_FORMAT "]", method->name_and_sig_as_C_string(), p2i(method->native_function()), p2i(entry))); } method->set_native_function(entry, Method::native_bind_event_is_interesting); @@ -2605,9 +2605,9 @@ C2V_VMENTRY_NULL(jlongArray, registerNativeMethods, (JNIEnv* env, jobject, jclas } } - typeArrayOop info_oop = oopFactory::new_longArray(4, CHECK_0); + typeArrayOop info_oop = oopFactory::new_longArray(4, CHECK_NULL); jlongArray info = (jlongArray) JNIHandles::make_local(THREAD, info_oop); - runtime->init_JavaVM_info(info, JVMCI_CHECK_0); + runtime->init_JavaVM_info(info, JVMCI_CHECK_NULL); return info; C2V_END @@ -3154,8 +3154,8 @@ C2V_VMENTRY_NULL(jobject, getThreadLocalObject, (JNIEnv* env, jobject, jint id)) if (id == 0) { return JNIHandles::make_local(thread->get_jvmci_reserved_oop0()); } - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), - err_msg("%d is not a valid thread local id", id)); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("%d is not a valid thread local id", id)); C2V_END C2V_VMENTRY(void, setThreadLocalLong, (JNIEnv* env, jobject, jint id, jlong value)) From 8e682aca24fba0803dceef513957fb2122895b87 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 13 Aug 2024 18:03:52 +0000 Subject: [PATCH 403/460] 8338158: Cleanup ShouldNotXXX uses in machnode.cpp Reviewed-by: chagedorn, kvn, dlong --- src/hotspot/share/opto/machnode.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/opto/machnode.cpp b/src/hotspot/share/opto/machnode.cpp index 39b804f7e5c..e271637893b 100644 --- a/src/hotspot/share/opto/machnode.cpp +++ b/src/hotspot/share/opto/machnode.cpp @@ -45,9 +45,9 @@ int MachOper::reg(PhaseRegAlloc *ra_, const Node *node, int idx) const { } intptr_t MachOper::constant() const { return 0x00; } relocInfo::relocType MachOper::constant_reloc() const { return relocInfo::none; } -jdouble MachOper::constantD() const { ShouldNotReachHere(); return 0.0; } -jfloat MachOper::constantF() const { ShouldNotReachHere(); return 0.0; } -jlong MachOper::constantL() const { ShouldNotReachHere(); return CONST64(0) ; } +jdouble MachOper::constantD() const { ShouldNotReachHere(); } +jfloat MachOper::constantF() const { ShouldNotReachHere(); } +jlong MachOper::constantL() const { ShouldNotReachHere(); } TypeOopPtr *MachOper::oop() const { return nullptr; } int MachOper::ccode() const { return 0x00; } // A zero, default, indicates this value is not needed. @@ -62,8 +62,8 @@ int MachOper::index_position() const { return -1; } // no index input // Check for PC-Relative displacement relocInfo::relocType MachOper::disp_reloc() const { return relocInfo::none; } // Return the label -Label* MachOper::label() const { ShouldNotReachHere(); return 0; } -intptr_t MachOper::method() const { ShouldNotReachHere(); return 0; } +Label* MachOper::label() const { ShouldNotReachHere(); } +intptr_t MachOper::method() const { ShouldNotReachHere(); } //------------------------------negate----------------------------------------- @@ -80,7 +80,6 @@ const Type *MachOper::type() const { //------------------------------in_RegMask------------------------------------- const RegMask *MachOper::in_RegMask(int index) const { ShouldNotReachHere(); - return nullptr; } //------------------------------dump_spec-------------------------------------- @@ -93,14 +92,12 @@ void MachOper::dump_spec(outputStream *st) const { } // Print any per-operand special info uint MachOper::hash() const { ShouldNotCallThis(); - return 5; } //------------------------------cmp-------------------------------------------- // Print any per-operand special info bool MachOper::cmp( const MachOper &oper ) const { ShouldNotCallThis(); - return opcode() == oper.opcode(); } //------------------------------hash------------------------------------------- @@ -207,7 +204,6 @@ void MachNode::fill_new_machnode(MachNode* node) const { // Return an equivalent instruction using memory for cisc_operand position MachNode *MachNode::cisc_version(int offset) { ShouldNotCallThis(); - return nullptr; } void MachNode::use_cisc_RegMask() { From 90527a57848f452be3be089a703cbc2af2d1657a Mon Sep 17 00:00:00 2001 From: Neethu Prasad Date: Tue, 13 Aug 2024 19:56:07 +0000 Subject: [PATCH 404/460] 8336742: Shenandoah: Add more verbose logging/stats for mark termination attempts Reviewed-by: shade, wkemper, rkennke --- .../gc/shenandoah/shenandoahConcurrentMark.cpp | 5 ++++- .../gc/shenandoah/shenandoahPhaseTimings.cpp | 16 ++++++++++------ .../gc/shenandoah/shenandoahPhaseTimings.hpp | 5 +++-- .../share/gc/shenandoah/shenandoahUtils.cpp | 6 +++--- .../share/gc/shenandoah/shenandoahUtils.hpp | 3 ++- 5 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index dde446d824b..6ed75a9d961 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -206,7 +206,10 @@ void ShenandoahConcurrentMark::concurrent_mark() { } size_t before = qset.completed_buffers_num(); - Handshake::execute(&flush_satb); + { + ShenandoahTimingsTracker t(ShenandoahPhaseTimings::conc_mark_satb_flush, true); + Handshake::execute(&flush_satb); + } size_t after = qset.completed_buffers_num(); if (before == after) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.cpp b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.cpp index 738657ac6bd..5e60cf92393 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.cpp @@ -137,17 +137,21 @@ bool ShenandoahPhaseTimings::is_root_work_phase(Phase phase) { } } -void ShenandoahPhaseTimings::set_cycle_data(Phase phase, double time) { +void ShenandoahPhaseTimings::set_cycle_data(Phase phase, double time, bool should_aggregate) { + const double cycle_data = _cycle_data[phase]; + if (should_aggregate) { + _cycle_data[phase] = (cycle_data == uninitialized()) ? time : (cycle_data + time); + } else { #ifdef ASSERT - double d = _cycle_data[phase]; - assert(d == uninitialized(), "Should not be set yet: %s, current value: %lf", phase_name(phase), d); + assert(cycle_data == uninitialized(), "Should not be set yet: %s, current value: %lf", phase_name(phase), cycle_data); #endif - _cycle_data[phase] = time; + _cycle_data[phase] = time; + } } -void ShenandoahPhaseTimings::record_phase_time(Phase phase, double time) { +void ShenandoahPhaseTimings::record_phase_time(Phase phase, double time, bool should_aggregate) { if (!_policy->is_at_shutdown()) { - set_cycle_data(phase, time); + set_cycle_data(phase, time, should_aggregate); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp index a6ca335a0d7..01c83e08d37 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp @@ -57,6 +57,7 @@ class outputStream; f(conc_mark_roots, "Concurrent Mark Roots ") \ SHENANDOAH_PAR_PHASE_DO(conc_mark_roots, " CMR: ", f) \ f(conc_mark, "Concurrent Marking") \ + f(conc_mark_satb_flush, " Flush SATB") \ \ f(final_mark_gross, "Pause Final Mark (G)") \ f(final_mark, "Pause Final Mark (N)") \ @@ -216,13 +217,13 @@ class ShenandoahPhaseTimings : public CHeapObj { ShenandoahWorkerData* worker_data(Phase phase, ParPhase par_phase); Phase worker_par_phase(Phase phase, ParPhase par_phase); - void set_cycle_data(Phase phase, double time); + void set_cycle_data(Phase phase, double time, bool should_aggregate = false); static double uninitialized() { return -1; } public: ShenandoahPhaseTimings(uint max_workers); - void record_phase_time(Phase phase, double time); + void record_phase_time(Phase phase, double time, bool should_aggregate = false); void record_workers_start(Phase phase); void record_workers_end(Phase phase); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp b/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp index 64074a9672c..ca56b06e79d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp @@ -111,8 +111,8 @@ ShenandoahConcurrentPhase::~ShenandoahConcurrentPhase() { _timer->register_gc_concurrent_end(); } -ShenandoahTimingsTracker::ShenandoahTimingsTracker(ShenandoahPhaseTimings::Phase phase) : - _timings(ShenandoahHeap::heap()->phase_timings()), _phase(phase) { +ShenandoahTimingsTracker::ShenandoahTimingsTracker(ShenandoahPhaseTimings::Phase phase, bool should_aggregate) : + _timings(ShenandoahHeap::heap()->phase_timings()), _phase(phase), _should_aggregate(should_aggregate) { assert(Thread::current()->is_VM_thread() || Thread::current()->is_ConcurrentGC_thread(), "Must be set by these threads"); _parent_phase = _current_phase; @@ -121,7 +121,7 @@ ShenandoahTimingsTracker::ShenandoahTimingsTracker(ShenandoahPhaseTimings::Phase } ShenandoahTimingsTracker::~ShenandoahTimingsTracker() { - _timings->record_phase_time(_phase, os::elapsedTime() - _start); + _timings->record_phase_time(_phase, os::elapsedTime() - _start, _should_aggregate); _current_phase = _parent_phase; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp b/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp index 15f0ee61407..ffa9d764d3c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp @@ -64,11 +64,12 @@ class ShenandoahTimingsTracker : public StackObj { ShenandoahPhaseTimings* const _timings; const ShenandoahPhaseTimings::Phase _phase; + const bool _should_aggregate; ShenandoahPhaseTimings::Phase _parent_phase; double _start; public: - ShenandoahTimingsTracker(ShenandoahPhaseTimings::Phase phase); + ShenandoahTimingsTracker(ShenandoahPhaseTimings::Phase phase, bool should_aggregate = false); ~ShenandoahTimingsTracker(); static ShenandoahPhaseTimings::Phase current_phase() { return _current_phase; } From f132b347e13a57d9654f0ab11db0636999576036 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Tue, 13 Aug 2024 22:59:13 +0000 Subject: [PATCH 405/460] 8336854: CAInterop.java#actalisauthenticationrootca conflicted with /manual and /timeout Reviewed-by: rhalade --- .../cert/CertPathValidator/certification/CAInterop.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java index 889926077a9..ab04391b1f3 100644 --- a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java +++ b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java @@ -25,14 +25,16 @@ * @test id=actalisauthenticationrootca * @bug 8189131 * @summary Interoperability tests with Actalis CA + * Before this test set to manual, the original timeout + * value if 180 * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop * @run main/othervm/manual -Djava.security.debug=certpath,ocsp * CAInterop actalisauthenticationrootca OCSP - * @run main/othervm/manual/timeout=180 -Djava.security.debug=certpath,ocsp + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp * -Dcom.sun.security.ocsp.useget=false * CAInterop actalisauthenticationrootca OCSP - * @run main/othervm/manual/timeout=180 -Djava.security.debug=certpath,ocsp + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp * CAInterop actalisauthenticationrootca CRL */ From 720b44648bcff997278af92746f942b2425298a5 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Wed, 14 Aug 2024 05:42:14 +0000 Subject: [PATCH 406/460] 8335181: Incorrect handling of HTTP/2 GOAWAY frames in HttpClient Reviewed-by: dfuchs --- .../jdk/internal/net/http/ExchangeImpl.java | 15 +- .../internal/net/http/Http2Connection.java | 58 ++- .../jdk/internal/net/http/MultiExchange.java | 27 +- .../classes/jdk/internal/net/http/Stream.java | 67 +++- .../internal/net/http/WindowController.java | 13 +- .../internal/net/http/frame/GoAwayFrame.java | 6 +- .../net/httpclient/http2/H2GoAwayTest.java | 336 ++++++++++++++++++ .../test/lib/common/HttpServerAdapters.java | 30 +- .../test/lib/http2/Http2TestExchange.java | 8 +- .../test/lib/http2/Http2TestExchangeImpl.java | 5 + .../test/lib/http2/Http2TestServer.java | 14 +- .../lib/http2/Http2TestServerConnection.java | 102 +++++- 12 files changed, 625 insertions(+), 56 deletions(-) create mode 100644 test/jdk/java/net/httpclient/http2/H2GoAwayTest.java diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/ExchangeImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/ExchangeImpl.java index 854ea73cc36..404f970cc59 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/ExchangeImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/ExchangeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,6 +58,10 @@ abstract class ExchangeImpl { final Exchange exchange; + // this will be set to true only when the peer explicitly states (through a GOAWAY frame or + // a relevant error code in reset frame) that the corresponding stream (id) wasn't processed + private volatile boolean unprocessedByPeer; + ExchangeImpl(Exchange e) { // e == null means a http/2 pushed stream this.exchange = e; @@ -265,4 +269,13 @@ void upgraded() { } // Called when server returns non 100 response to // an Expect-Continue void expectContinueFailed(int rcode) { } + + final boolean isUnprocessedByPeer() { + return this.unprocessedByPeer; + } + + // Marks the exchange as unprocessed by the peer + final void markUnprocessedByPeer() { + this.unprocessedByPeer = true; + } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java index 3321ffdfce0..9457ff69988 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,6 +47,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Flow; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.function.Function; @@ -358,6 +360,7 @@ private record PushContinuationState(HeaderDecoder pushContDecoder, PushPromiseF private final String key; // for HttpClientImpl.connections map private final FramesDecoder framesDecoder; private final FramesEncoder framesEncoder = new FramesEncoder(); + private final AtomicLong lastProcessedStreamInGoAway = new AtomicLong(-1); /** * Send Window controller for both connection and stream windows. @@ -725,7 +728,9 @@ final int maxConcurrentServerInitiatedStreams() { void close() { if (markHalfClosedLocal()) { - if (connection.channel().isOpen()) { + // we send a GOAWAY frame only if the remote side hasn't already indicated + // the intention to close the connection by previously sending a GOAWAY of its own + if (connection.channel().isOpen() && !isMarked(closedState, HALF_CLOSED_REMOTE)) { Log.logTrace("Closing HTTP/2 connection: to {0}", connection.address()); GoAwayFrame f = new GoAwayFrame(0, ErrorFrame.NO_ERROR, @@ -1205,13 +1210,46 @@ private void handlePing(PingFrame frame) sendUnorderedFrame(frame); } - private void handleGoAway(GoAwayFrame frame) - throws IOException - { - if (markHalfClosedLRemote()) { - shutdown(new IOException( - connection.channel().getLocalAddress() - + ": GOAWAY received")); + private void handleGoAway(final GoAwayFrame frame) { + final long lastProcessedStream = frame.getLastStream(); + assert lastProcessedStream >= 0 : "unexpected last stream id: " + + lastProcessedStream + " in GOAWAY frame"; + + markHalfClosedRemote(); + setFinalStream(); // don't allow any new streams on this connection + if (debug.on()) { + debug.log("processing incoming GOAWAY with last processed stream id:%s in frame %s", + lastProcessedStream, frame); + } + // see if this connection has previously received a GOAWAY from the peer and if yes + // then check if this new last processed stream id is lesser than the previous + // known last processed stream id. Only update the last processed stream id if the new + // one is lesser than the previous one. + long prevLastProcessed = lastProcessedStreamInGoAway.get(); + while (prevLastProcessed == -1 || lastProcessedStream < prevLastProcessed) { + if (lastProcessedStreamInGoAway.compareAndSet(prevLastProcessed, + lastProcessedStream)) { + break; + } + prevLastProcessed = lastProcessedStreamInGoAway.get(); + } + handlePeerUnprocessedStreams(lastProcessedStreamInGoAway.get()); + } + + private void handlePeerUnprocessedStreams(final long lastProcessedStream) { + final AtomicInteger numClosed = new AtomicInteger(); // atomic merely to allow usage within lambda + streams.forEach((id, exchange) -> { + if (id > lastProcessedStream) { + // any streams with an stream id higher than the last processed stream + // can be retried (on a new connection). we close the exchange as unprocessed + // to facilitate the retrying. + client2.client().theExecutor().ensureExecutedAsync(exchange::closeAsUnprocessed); + numClosed.incrementAndGet(); + } + }); + if (debug.on()) { + debug.log(numClosed.get() + " stream(s), with id greater than " + lastProcessedStream + + ", will be closed as unprocessed"); } } @@ -1745,7 +1783,7 @@ private boolean markHalfClosedLocal() { return markClosedState(HALF_CLOSED_LOCAL); } - private boolean markHalfClosedLRemote() { + private boolean markHalfClosedRemote() { return markClosedState(HALF_CLOSED_REMOTE); } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java b/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java index d6d03a9aa8a..2c15a704ef9 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -90,7 +90,7 @@ class MultiExchange implements Cancelable { Exchange exchange; // the current exchange Exchange previous; volatile Throwable retryCause; - volatile boolean expiredOnce; + volatile boolean retriedOnce; volatile HttpResponse response; // Maximum number of times a request will be retried/redirected @@ -469,7 +469,7 @@ private CompletableFuture responseAsyncImpl() { return exch.ignoreBody().handle((r,t) -> { previousreq = currentreq; currentreq = newrequest; - expiredOnce = false; + retriedOnce = false; setExchange(new Exchange<>(currentreq, this, acc)); return responseAsyncImpl(); }).thenCompose(Function.identity()); @@ -482,7 +482,7 @@ private CompletableFuture responseAsyncImpl() { return completedFuture(response); } // all exceptions thrown are handled here - CompletableFuture errorCF = getExceptionalCF(ex); + CompletableFuture errorCF = getExceptionalCF(ex, exch.exchImpl); if (errorCF == null) { return responseAsyncImpl(); } else { @@ -554,36 +554,39 @@ private Throwable retryCause(Throwable t) { * Takes a Throwable and returns a suitable CompletableFuture that is * completed exceptionally, or null. */ - private CompletableFuture getExceptionalCF(Throwable t) { + private CompletableFuture getExceptionalCF(Throwable t, ExchangeImpl exchImpl) { if ((t instanceof CompletionException) || (t instanceof ExecutionException)) { if (t.getCause() != null) { t = t.getCause(); } } + final boolean retryAsUnprocessed = exchImpl != null && exchImpl.isUnprocessedByPeer(); if (cancelled && !requestCancelled() && t instanceof IOException) { if (!(t instanceof HttpTimeoutException)) { t = toTimeoutException((IOException)t); } - } else if (retryOnFailure(t)) { + } else if (retryAsUnprocessed || retryOnFailure(t)) { Throwable cause = retryCause(t); if (!(t instanceof ConnectException)) { // we may need to start a new connection, and if so // we want to start with a fresh connect timeout again. if (connectTimeout != null) connectTimeout.reset(); - if (!canRetryRequest(currentreq)) { - return failedFuture(cause); // fails with original cause + if (!retryAsUnprocessed && !canRetryRequest(currentreq)) { + // a (peer) processed request which cannot be retried, fail with + // the original cause + return failedFuture(cause); } } // ConnectException: retry, but don't reset the connectTimeout. // allow the retry mechanism to do its work retryCause = cause; - if (!expiredOnce) { + if (!retriedOnce) { if (debug.on()) { debug.log(t.getClass().getSimpleName() - + " (async): retrying due to: ", t); + + " (async): retrying " + currentreq + " due to: ", t); } - expiredOnce = true; + retriedOnce = true; // The connection was abruptly closed. // We return null to retry the same request a second time. // The request filters have already been applied to the @@ -594,7 +597,7 @@ private CompletableFuture getExceptionalCF(Throwable t) { } else { if (debug.on()) { debug.log(t.getClass().getSimpleName() - + " (async): already retried once.", t); + + " (async): already retried once " + currentreq, t); } t = cause; } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java index 1bb520a6fb1..1a007e82adc 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java @@ -641,20 +641,39 @@ void handleReset(ResetFrame frame, Flow.Subscriber subscriber) { stateLock.unlock(); } try { - int error = frame.getErrorCode(); - IOException e = new IOException("Received RST_STREAM: " - + ErrorFrame.stringForCode(error)); - if (errorRef.compareAndSet(null, e)) { - if (subscriber != null) { - subscriber.onError(e); + final int error = frame.getErrorCode(); + // A REFUSED_STREAM error code implies that the stream wasn't processed by the + // peer and the client is free to retry the request afresh. + if (error == ErrorFrame.REFUSED_STREAM) { + // Here we arrange for the request to be retried. Note that we don't call + // closeAsUnprocessed() method here because the "closed" state is already set + // to true a few lines above and calling close() from within + // closeAsUnprocessed() will end up being a no-op. We instead do the additional + // bookkeeping here. + markUnprocessedByPeer(); + errorRef.compareAndSet(null, new IOException("request not processed by peer")); + if (debug.on()) { + debug.log("request unprocessed by peer (REFUSED_STREAM) " + this.request); + } + } else { + final String reason = ErrorFrame.stringForCode(error); + final IOException failureCause = new IOException("Received RST_STREAM: " + reason); + if (debug.on()) { + debug.log(streamid + " received RST_STREAM with code: " + reason); + } + if (errorRef.compareAndSet(null, failureCause)) { + if (subscriber != null) { + subscriber.onError(failureCause); + } } } - completeResponseExceptionally(e); + final Throwable failureCause = errorRef.get(); + completeResponseExceptionally(failureCause); if (!requestBodyCF.isDone()) { - requestBodyCF.completeExceptionally(errorRef.get()); // we may be sending the body.. + requestBodyCF.completeExceptionally(failureCause); // we may be sending the body.. } if (responseBodyCF != null) { - responseBodyCF.completeExceptionally(errorRef.get()); + responseBodyCF.completeExceptionally(failureCause); } } finally { connection.decrementStreamsCount(streamid); @@ -1663,7 +1682,35 @@ Throwable getCancelCause() { } final String dbgString() { - return connection.dbgString() + "/Stream("+streamid+")"; + final int id = streamid; + final String sid = id == 0 ? "?" : String.valueOf(id); + return connection.dbgString() + "/Stream(" + sid + ")"; + } + + /** + * An unprocessed exchange is one that hasn't been processed by a peer. The local end of the + * connection would be notified about such exchanges when it receives a GOAWAY frame with + * a stream id that tells which exchanges have been unprocessed. + * This method is called on such unprocessed exchanges and the implementation of this method + * will arrange for the request, corresponding to this exchange, to be retried afresh on a + * new connection. + */ + void closeAsUnprocessed() { + try { + // We arrange for the request to be retried on a new connection as allowed by the RFC-9113 + markUnprocessedByPeer(); + this.errorRef.compareAndSet(null, new IOException("request not processed by peer")); + if (debug.on()) { + debug.log("closing " + this.request + " as unprocessed by peer"); + } + // close the exchange and complete the response CF exceptionally + close(); + completeResponseExceptionally(this.errorRef.get()); + } finally { + // decrementStreamsCount isn't really needed but we do it to make sure + // the log messages, where these counts/states get reported, show the accurate state. + connection.decrementStreamsCount(streamid); + } } private class HeadersConsumer extends ValidatingHeadersConsumer { diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/WindowController.java b/src/java.net.http/share/classes/jdk/internal/net/http/WindowController.java index 1df81640345..a30c21a7a7d 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/WindowController.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/WindowController.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -100,13 +100,16 @@ void removeStream(int streamid) { controllerLock.lock(); try { Integer old = streams.remove(streamid); - // Odd stream numbers (client streams) should have been registered. + // A client initiated stream might be closed (as unprocessed, due to a + // GOAWAY received on the connection) even before the stream is + // registered with this WindowController instance (when sending out request headers). + // Thus, for client initiated streams, we don't enforce the presence of the + // stream in the registered "streams" map. + // Even stream numbers (server streams - aka Push Streams) should // not be registered final boolean isClientStream = (streamid & 0x1) == 1; - if (old == null && isClientStream) { - throw new InternalError("Expected entry for streamid: " + streamid); - } else if (old != null && !isClientStream) { + if (old != null && !isClientStream) { throw new InternalError("Unexpected entry for streamid: " + streamid); } } finally { diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/frame/GoAwayFrame.java b/src/java.net.http/share/classes/jdk/internal/net/http/frame/GoAwayFrame.java index 45ec7553f5a..662e5dd98b3 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/frame/GoAwayFrame.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/frame/GoAwayFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,7 +57,9 @@ int length() { @Override public String toString() { - return super.toString() + " Debugdata: " + new String(debugData, UTF_8); + return super.toString() + + " lastStreamId=" + lastStream + + ", Debugdata: " + new String(debugData, UTF_8); } public int getLastStream() { diff --git a/test/jdk/java/net/httpclient/http2/H2GoAwayTest.java b/test/jdk/java/net/httpclient/http2/H2GoAwayTest.java new file mode 100644 index 00000000000..755bb2e16cc --- /dev/null +++ b/test/jdk/java/net/httpclient/http2/H2GoAwayTest.java @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.IOException; +import java.io.OutputStream; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.net.http.HttpResponse.BodyHandlers; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.net.ssl.SSLContext; + +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestExchange; +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestHandler; +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestServer; +import jdk.test.lib.net.SimpleSSLContext; +import jdk.test.lib.net.URIBuilder; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import static java.net.http.HttpClient.Version.HTTP_2; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.fail; + +/* + * @test + * @bug 8335181 + * @summary verify that the HttpClient correctly handles incoming GOAWAY frames and + * retries any unprocessed requests on a new connection + * @library /test/lib /test/jdk/java/net/httpclient/lib + * @build jdk.httpclient.test.lib.common.HttpServerAdapters + * jdk.test.lib.net.SimpleSSLContext + * @run junit H2GoAwayTest + */ +public class H2GoAwayTest { + private static final String REQ_PATH = "/test"; + private static HttpTestServer server; + private static String REQ_URI_BASE; + private static SSLContext sslCtx; + + @BeforeAll + static void beforeAll() throws Exception { + sslCtx = new SimpleSSLContext().get(); + assertNotNull(sslCtx, "SSLContext couldn't be created"); + server = HttpTestServer.create(HTTP_2, sslCtx); + server.addHandler(new Handler(), REQ_PATH); + server.start(); + System.out.println("Server started at " + server.getAddress()); + REQ_URI_BASE = URIBuilder.newBuilder().scheme("https") + .loopback() + .port(server.getAddress().getPort()) + .path(REQ_PATH) + .build().toString(); + } + + @AfterAll + static void afterAll() { + if (server != null) { + System.out.println("Stopping server at " + server.getAddress()); + server.stop(); + } + } + + /** + * Verifies that when several requests are sent using send() and the server + * connection is configured to send a GOAWAY after processing only a few requests, then + * the remaining requests are retried on a different connection + */ + @Test + public void testSequential() throws Exception { + final LimitedPerConnRequestApprover reqApprover = new LimitedPerConnRequestApprover(); + server.setRequestApprover(reqApprover::allowNewRequest); + try (final HttpClient client = HttpClient.newBuilder().version(HTTP_2) + .sslContext(sslCtx).build()) { + final String[] reqMethods = {"HEAD", "GET", "POST"}; + for (final String reqMethod : reqMethods) { + final int numReqs = LimitedPerConnRequestApprover.MAX_REQS_PER_CONN + 3; + final Set connectionKeys = new LinkedHashSet<>(); + for (int i = 1; i <= numReqs; i++) { + final URI reqURI = new URI(REQ_URI_BASE + "?seq&" + reqMethod + "=" + i); + final HttpRequest req = HttpRequest.newBuilder() + .uri(reqURI) + .method(reqMethod, HttpRequest.BodyPublishers.noBody()) + .build(); + System.out.println("initiating request " + req); + final HttpResponse resp = client.send(req, BodyHandlers.ofString()); + final String respBody = resp.body(); + System.out.println("received response: " + respBody); + assertEquals(200, resp.statusCode(), + "unexpected status code for request " + resp.request()); + // response body is the logical key of the connection on which the + // request was handled + connectionKeys.add(respBody); + } + System.out.println("connections involved in handling the requests: " + + connectionKeys); + // all requests have finished, we now just do a basic check that + // more than one connection was involved in processing these requests + assertEquals(2, connectionKeys.size(), + "unexpected number of connections " + connectionKeys); + } + } finally { + server.setRequestApprover(null); // reset + } + } + + /** + * Verifies that when a server responds with a GOAWAY and then never processes the new retried + * requests on a new connection too, then the application code receives the request failure. + * This tests the send() API of the HttpClient. + */ + @Test + public void testUnprocessedRaisesException() throws Exception { + try (final HttpClient client = HttpClient.newBuilder().version(HTTP_2) + .sslContext(sslCtx).build()) { + final Random random = new Random(); + final String[] reqMethods = {"HEAD", "GET", "POST"}; + for (final String reqMethod : reqMethods) { + final int maxAllowedReqs = 2; + final int numReqs = maxAllowedReqs + 3; // 3 more requests than max allowed + // configure the approver + final LimitedRequestApprover reqApprover = new LimitedRequestApprover(maxAllowedReqs); + server.setRequestApprover(reqApprover::allowNewRequest); + try { + int numSuccess = 0; + int numFailed = 0; + for (int i = 1; i <= numReqs; i++) { + final String reqQueryPart = "?sync&" + reqMethod + "=" + i; + final URI reqURI = new URI(REQ_URI_BASE + reqQueryPart); + final HttpRequest req = HttpRequest.newBuilder() + .uri(reqURI) + .method(reqMethod, HttpRequest.BodyPublishers.noBody()) + .build(); + System.out.println("initiating request " + req); + if (i <= maxAllowedReqs) { + // expected to successfully complete + numSuccess++; + final HttpResponse resp = client.send(req, BodyHandlers.ofString()); + final String respBody = resp.body(); + System.out.println("received response: " + respBody); + assertEquals(200, resp.statusCode(), + "unexpected status code for request " + resp.request()); + } else { + // expected to fail as unprocessed + try { + final HttpResponse resp = client.send(req, BodyHandlers.ofString()); + fail("Request was expected to fail as unprocessed," + + " but got response: " + resp.body() + ", status code: " + + resp.statusCode()); + } catch (IOException ioe) { + // verify it failed for the right reason + if (ioe.getMessage() == null + || !ioe.getMessage().contains("request not processed by peer")) { + // propagate the original failure + throw ioe; + } + numFailed++; // failed due to right reason + System.out.println("received expected failure: " + ioe + + ", for request " + reqURI); + } + } + } + // verify the correct number of requests succeeded/failed + assertEquals(maxAllowedReqs, numSuccess, "unexpected number of requests succeeded"); + assertEquals((numReqs - maxAllowedReqs), numFailed, "unexpected number of requests failed"); + } finally { + server.setRequestApprover(null); // reset + } + } + } + } + + /** + * Verifies that when a server responds with a GOAWAY and then never processes the new retried + * requests on a new connection too, then the application code receives the request failure. + * This tests the sendAsync() API of the HttpClient. + */ + @Test + public void testUnprocessedRaisesExceptionAsync() throws Throwable { + try (final HttpClient client = HttpClient.newBuilder().version(HTTP_2) + .sslContext(sslCtx).build()) { + final Random random = new Random(); + final String[] reqMethods = {"HEAD", "GET", "POST"}; + for (final String reqMethod : reqMethods) { + final int maxAllowedReqs = 2; + final int numReqs = maxAllowedReqs + 3; // 3 more requests than max allowed + // configure the approver + final LimitedRequestApprover reqApprover = new LimitedRequestApprover(maxAllowedReqs); + server.setRequestApprover(reqApprover::allowNewRequest); + try { + final List>> futures = new ArrayList<>(); + for (int i = 1; i <= numReqs; i++) { + final URI reqURI = new URI(REQ_URI_BASE + "?async&" + reqMethod + "=" + i); + final HttpRequest req = HttpRequest.newBuilder() + .uri(reqURI) + .method(reqMethod, HttpRequest.BodyPublishers.noBody()) + .build(); + System.out.println("initiating request " + req); + final Future> f = client.sendAsync(req, BodyHandlers.ofString()); + futures.add(f); + } + // wait for responses + int numFailed = 0; + int numSuccess = 0; + for (int i = 1; i <= numReqs; i++) { + final String reqQueryPart = "?async&" + reqMethod + "=" + i; + try { + System.out.println("waiting response of request " + + REQ_URI_BASE + reqQueryPart); + final HttpResponse resp = futures.get(i - 1).get(); + numSuccess++; + final String respBody = resp.body(); + System.out.println("request: " + resp.request() + + ", received response: " + respBody); + assertEquals(200, resp.statusCode(), + "unexpected status code for request " + resp.request()); + } catch (ExecutionException ee) { + final Throwable cause = ee.getCause(); + if (!(cause instanceof IOException ioe)) { + throw cause; + } + // verify it failed for the right reason + if (ioe.getMessage() == null + || !ioe.getMessage().contains("request not processed by peer")) { + // propagate the original failure + throw ioe; + } + numFailed++; // failed due to the right reason + System.out.println("received expected failure: " + ioe + + ", for request " + REQ_URI_BASE + reqQueryPart); + } + } + // verify the correct number of requests succeeded/failed + assertEquals(maxAllowedReqs, numSuccess, "unexpected number of requests succeeded"); + assertEquals((numReqs - maxAllowedReqs), numFailed, "unexpected number of requests failed"); + } finally { + server.setRequestApprover(null); // reset + } + } + } + } + + // only allows fixed number of requests, irrespective of which server connection handles + // it. requests that are rejected will either be sent a GOAWAY on the connection + // or a RST_FRAME with a REFUSED_STREAM on the stream + private static final class LimitedRequestApprover { + private final int maxAllowedReqs; + private final AtomicInteger numApproved = new AtomicInteger(); + + private LimitedRequestApprover(final int maxAllowedReqs) { + this.maxAllowedReqs = maxAllowedReqs; + } + + public boolean allowNewRequest(final String serverConnKey) { + final int approved = numApproved.incrementAndGet(); + return approved <= maxAllowedReqs; + } + } + + // allows a certain number of requests per server connection. + // requests that are rejected will either be sent a GOAWAY on the connection + // or a RST_FRAME with a REFUSED_STREAM on the stream + private static final class LimitedPerConnRequestApprover { + private static final int MAX_REQS_PER_CONN = 6; + private final Map numApproved = + new ConcurrentHashMap<>(); + private final Map numDisapproved = + new ConcurrentHashMap<>(); + + public boolean allowNewRequest(final String serverConnKey) { + final AtomicInteger approved = numApproved.computeIfAbsent(serverConnKey, + (k) -> new AtomicInteger()); + int curr = approved.get(); + while (curr < MAX_REQS_PER_CONN) { + if (approved.compareAndSet(curr, curr + 1)) { + return true; // new request allowed + } + curr = approved.get(); + } + final AtomicInteger disapproved = numDisapproved.computeIfAbsent(serverConnKey, + (k) -> new AtomicInteger()); + final int numUnprocessed = disapproved.incrementAndGet(); + System.out.println(approved.get() + " processed, " + + numUnprocessed + " unprocessed requests on connection " + serverConnKey); + return false; + } + } + + private static final class Handler implements HttpTestHandler { + + @Override + public void handle(final HttpTestExchange exchange) throws IOException { + final String connectionKey = exchange.getConnectionKey(); + System.out.println("responding to request: " + exchange.getRequestURI() + + " on connection " + connectionKey); + final byte[] response = connectionKey.getBytes(UTF_8); + exchange.sendResponseHeaders(200, response.length); + try (final OutputStream os = exchange.getResponseBody()) { + os.write(response); + } + } + } +} diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/HttpServerAdapters.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/HttpServerAdapters.java index e18dd87a507..36498684a9a 100644 --- a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/HttpServerAdapters.java +++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/HttpServerAdapters.java @@ -58,6 +58,7 @@ import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutorService; +import java.util.function.Predicate; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; @@ -239,6 +240,7 @@ public static abstract class HttpTestExchange implements AutoCloseable { public abstract String getRequestMethod(); public abstract void close(); public abstract InetSocketAddress getRemoteAddress(); + public abstract String getConnectionKey(); public void serverPush(URI uri, HttpHeaders headers, byte[] body) { ByteArrayInputStream bais = new ByteArrayInputStream(body); serverPush(uri, headers, bais); @@ -253,7 +255,7 @@ public static HttpTestExchange of(HttpExchange exchange) { return new Http1TestExchange(exchange); } public static HttpTestExchange of(Http2TestExchange exchange) { - return new Http2TestExchangeImpl(exchange); + return new H2ExchangeImpl(exchange); } abstract void doFilter(Filter.Chain chain) throws IOException; @@ -306,15 +308,21 @@ public InetSocketAddress getRemoteAddress() { public URI getRequestURI() { return exchange.getRequestURI(); } @Override public String getRequestMethod() { return exchange.getRequestMethod(); } + + @Override + public String getConnectionKey() { + return exchange.getLocalAddress() + "->" + exchange.getRemoteAddress(); + } + @Override public String toString() { return this.getClass().getSimpleName() + ": " + exchange.toString(); } } - private static final class Http2TestExchangeImpl extends HttpTestExchange { + private static final class H2ExchangeImpl extends HttpTestExchange { private final Http2TestExchange exchange; - Http2TestExchangeImpl(Http2TestExchange exch) { + H2ExchangeImpl(Http2TestExchange exch) { this.exchange = exch; } @Override @@ -363,6 +371,11 @@ public InetSocketAddress getRemoteAddress() { return exchange.getRemoteAddress(); } + @Override + public String getConnectionKey() { + return exchange.getConnectionKey(); + } + @Override public URI getRequestURI() { return exchange.getRequestURI(); } @Override @@ -708,6 +721,7 @@ static void enableLogging() { public abstract HttpTestContext addHandler(HttpTestHandler handler, String root); public abstract InetSocketAddress getAddress(); public abstract Version getVersion(); + public abstract void setRequestApprover(final Predicate approver); public String serverAuthority() { InetSocketAddress address = getAddress(); @@ -856,6 +870,11 @@ public InetSocketAddress getAddress() { impl.getAddress().getPort()); } public Version getVersion() { return Version.HTTP_1_1; } + + @Override + public void setRequestApprover(final Predicate approver) { + throw new UnsupportedOperationException("not supported"); + } } private static class Http1TestContext extends HttpTestContext { @@ -907,6 +926,11 @@ public InetSocketAddress getAddress() { impl.getAddress().getPort()); } public Version getVersion() { return Version.HTTP_2; } + + @Override + public void setRequestApprover(final Predicate approver) { + this.impl.setRequestApprover(approver); + } } private static class Http2TestContext diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchange.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchange.java index 208a8d54e08..d982349dac5 100644 --- a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchange.java +++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchange.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -71,4 +71,10 @@ public interface Http2TestExchange { * It may also complete exceptionally */ CompletableFuture sendPing(); + + /** + * {@return the identification of the connection on which this exchange is being + * processed} + */ + String getConnectionKey(); } diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchangeImpl.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchangeImpl.java index 63a4de6ef90..d25019f9094 100644 --- a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchangeImpl.java +++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchangeImpl.java @@ -220,6 +220,11 @@ public void serverPush(URI uri, HttpHeaders headers, InputStream content) { } } + @Override + public String getConnectionKey() { + return conn.connectionKey(); + } + private boolean isHeadRequest() { return HEAD.equalsIgnoreCase(getRequestMethod()); } diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestServer.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestServer.java index ffa05d5c11c..ca7e7d3dc30 100644 --- a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestServer.java +++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,8 @@ import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Predicate; + import javax.net.ServerSocketFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLParameters; @@ -59,6 +61,8 @@ public class Http2TestServer implements AutoCloseable { final Set connections; final Properties properties; final String name; + // request approver which takes the server connection key as the input + private volatile Predicate newRequestApprover; private static ThreadFactory defaultThreadFac = (Runnable r) -> { @@ -285,6 +289,14 @@ public String serverName() { return serverName; } + public void setRequestApprover(final Predicate approver) { + this.newRequestApprover = approver; + } + + Predicate getRequestApprover() { + return this.newRequestApprover; + } + private synchronized void putConnection(InetSocketAddress addr, Http2TestServerConnection c) { if (!stopping) connections.add(c); diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestServerConnection.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestServerConnection.java index ff10d4087e9..1aeeee60b19 100644 --- a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestServerConnection.java +++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestServerConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,13 +75,18 @@ import java.util.Optional; import java.util.Properties; import java.util.Random; +import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ExecutorService; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiPredicate; import java.util.function.Consumer; +import java.util.function.Predicate; import static java.nio.charset.StandardCharsets.ISO_8859_1; import static java.nio.charset.StandardCharsets.UTF_8; +import static jdk.internal.net.http.frame.ErrorFrame.REFUSED_STREAM; import static jdk.internal.net.http.frame.SettingsFrame.HEADER_TABLE_SIZE; /** @@ -110,6 +115,10 @@ public class Http2TestServerConnection { volatile boolean stopping; volatile int nextPushStreamId = 2; ConcurrentLinkedQueue pings = new ConcurrentLinkedQueue<>(); + // the max stream id of a processed H2 request. -1 implies none were processed. + private final AtomicInteger maxProcessedRequestStreamId = new AtomicInteger(-1); + // the stream id that was sent in a GOAWAY frame. -1 implies no GOAWAY frame was sent. + private final AtomicInteger goAwayRequestStreamId = new AtomicInteger(-1); final static ByteBuffer EMPTY_BUFFER = ByteBuffer.allocate(0); final static byte[] EMPTY_BARRAY = new byte[0]; @@ -234,11 +243,29 @@ CompletableFuture sendPing() { return ping.response(); } - void goAway(int error) throws IOException { - int laststream = nextstream >= 3 ? nextstream - 2 : 1; - - GoAwayFrame go = new GoAwayFrame(laststream, error); - outputQ.put(go); + private void sendGoAway(final int error) throws IOException { + int maxProcessedStreamId = maxProcessedRequestStreamId.get(); + if (maxProcessedStreamId == -1) { + maxProcessedStreamId = 0; + } + boolean send = false; + int currentGoAwayReqStrmId = goAwayRequestStreamId.get(); + // update the last processed stream id and send a goaway frame if the new last processed + // stream id is lesser than the last processed stream id sent in + // a previous goaway frame (if any) + while (currentGoAwayReqStrmId == -1 || maxProcessedStreamId < currentGoAwayReqStrmId) { + if (goAwayRequestStreamId.compareAndSet(currentGoAwayReqStrmId, maxProcessedStreamId)) { + send = true; + break; + } + currentGoAwayReqStrmId = goAwayRequestStreamId.get(); + } + if (!send) { + return; + } + final GoAwayFrame frame = new GoAwayFrame(maxProcessedStreamId, error); + outputQ.put(frame); + System.err.println("Sending GOAWAY frame " + frame + " from server connection " + this); } /** @@ -331,8 +358,9 @@ void close(int error) { q.orderlyClose(); }); try { - if (error != -1) - goAway(error); + if (error != -1) { + sendGoAway(error); + } outputQ.orderlyClose(); socket.close(); } catch (Exception e) { @@ -612,6 +640,14 @@ void createPrimordialStream(Http1InitialRequest request) throws IOException { path = path + "?" + uri.getRawQuery(); headersBuilder.setHeader(":path", path); + // skip processing the request if configured to do so + final String connKey = connectionKey(); + if (!shouldProcessNewHTTPRequest(connKey)) { + System.err.println("Rejecting primordial stream 1 and sending GOAWAY" + + " on server connection " + connKey + ", for request: " + path); + sendGoAway(ErrorFrame.NO_ERROR); + return; + } Queue q = new Queue(sentinel); byte[] body = getRequestBody(request); addHeaders(getHeaders(request.headers), headersBuilder); @@ -620,11 +656,24 @@ void createPrimordialStream(Http1InitialRequest request) throws IOException { addRequestBodyToQueue(body, q); streams.put(1, q); + maxProcessedRequestStreamId.set(1); exec.submit(() -> { handleRequest(headers, q, 1, true /*complete request has been read*/); }); } + private boolean shouldProcessNewHTTPRequest(final String serverConnKey) { + final Predicate approver = this.server.getRequestApprover(); + if (approver == null) { + return true; // process the request + } + return approver.test(serverConnKey); + } + + final String connectionKey() { + return this.server.getAddress() + "->" + this.socket.getRemoteSocketAddress(); + } + // all other streams created here @SuppressWarnings({"rawtypes","unchecked"}) void createStream(HeaderFrame frame) throws IOException { @@ -632,7 +681,7 @@ void createStream(HeaderFrame frame) throws IOException { frames.add(frame); int streamid = frame.streamid(); if (streamid != nextstream) { - throw new IOException("unexpected stream id"); + throw new IOException("unexpected stream id: " + streamid); } nextstream += 2; @@ -663,12 +712,30 @@ void createStream(HeaderFrame frame) throws IOException { throw new IOException("Unexpected Upgrade in headers:" + headers); } disallowedHeader = headers.firstValue("HTTP2-Settings"); - if (disallowedHeader.isPresent()) + if (disallowedHeader.isPresent()) { throw new IOException("Unexpected HTTP2-Settings in headers:" + headers); + } - + // skip processing the request if the server is configured to do so + final String connKey = connectionKey(); + final String path = headers.firstValue(":path").orElse(""); + if (!shouldProcessNewHTTPRequest(connKey)) { + System.err.println("Rejecting stream " + streamid + + " and sending GOAWAY on server connection " + + connKey + ", for request: " + path); + sendGoAway(ErrorFrame.NO_ERROR); + return; + } Queue q = new Queue(sentinel); streams.put(streamid, q); + // keep track of the largest request id that we have processed + int currentLargest = maxProcessedRequestStreamId.get(); + while (streamid > currentLargest) { + if (maxProcessedRequestStreamId.compareAndSet(currentLargest, streamid)) { + break; + } + currentLargest = maxProcessedRequestStreamId.get(); + } exec.submit(() -> { handleRequest(headers, q, streamid, endStreamReceived); }); @@ -763,6 +830,8 @@ void readLoop() { while (!stopping) { Http2Frame frame = readFrameImpl(); if (frame == null) { + System.err.println("EOF reached on connection " + connectionKey() + + ", will no longer accept incoming frames"); closeIncoming(); return; } @@ -786,6 +855,17 @@ void readLoop() { // TODO: close connection continue; } else { + final int streamId = frame.streamid(); + final int finalProcessedStreamId = goAwayRequestStreamId.get(); + // if we already sent a goaway, then don't create new streams with + // higher stream ids. + if (finalProcessedStreamId != -1 && streamId > finalProcessedStreamId) { + System.err.println(connectionKey() + " resetting stream " + streamId + + " as REFUSED_STREAM"); + final ResetFrame rst = new ResetFrame(streamId, REFUSED_STREAM); + outputQ.put(rst); + continue; + } createStream((HeadersFrame) frame); } } else { From 3dd07b91bbf644aa867452806e9388089fa97548 Mon Sep 17 00:00:00 2001 From: Qizheng Xing Date: Wed, 14 Aug 2024 06:28:34 +0000 Subject: [PATCH 407/460] 8336163: Remove declarations of some debug-only methods in release build Reviewed-by: dholmes, eliu, kvn --- src/hotspot/share/cds/heapShared.hpp | 4 ++++ src/hotspot/share/compiler/compilationPolicy.hpp | 2 ++ src/hotspot/share/opto/node.hpp | 2 ++ src/hotspot/share/runtime/frame.hpp | 6 ++++++ src/hotspot/share/runtime/registerMap.hpp | 10 +++++----- 5 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/cds/heapShared.hpp b/src/hotspot/share/cds/heapShared.hpp index fa34289a38e..2c87b050ca6 100644 --- a/src/hotspot/share/cds/heapShared.hpp +++ b/src/hotspot/share/cds/heapShared.hpp @@ -371,7 +371,9 @@ class HeapShared: AllStatic { KlassSubGraphInfo* subgraph_info, oop orig_obj); +#ifndef PRODUCT static ResourceBitMap calculate_oopmap(MemRegion region); // marks all the oop pointers +#endif static void add_to_dumped_interned_strings(oop string); // Scratch objects for archiving Klass::java_mirror() @@ -426,7 +428,9 @@ class HeapShared: AllStatic { static void init_roots(oop roots_oop) NOT_CDS_JAVA_HEAP_RETURN; static void serialize_tables(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN; +#ifndef PRODUCT static bool is_a_test_class_in_unnamed_module(Klass* ik) NOT_CDS_JAVA_HEAP_RETURN_(false); +#endif }; #if INCLUDE_CDS_JAVA_HEAP diff --git a/src/hotspot/share/compiler/compilationPolicy.hpp b/src/hotspot/share/compiler/compilationPolicy.hpp index 3ec60cd89c7..fe33fb8cfba 100644 --- a/src/hotspot/share/compiler/compilationPolicy.hpp +++ b/src/hotspot/share/compiler/compilationPolicy.hpp @@ -179,8 +179,10 @@ class CompilationPolicy : AllStatic { // Set carry flags in the counters (in Method* and MDO). inline static void handle_counter_overflow(const methodHandle& method); +#ifdef ASSERT // Verify that a level is consistent with the compilation mode static bool verify_level(CompLevel level); +#endif // Clamp the request level according to various constraints. inline static CompLevel limit_level(CompLevel level); // Common transition function. Given a predicate determines if a method should transition to another level. diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index 10e1e7b1006..3e39e1ed2fb 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -834,7 +834,9 @@ class Node { juint _class_id; juint _flags; +#ifdef ASSERT static juint max_flags(); +#endif protected: // These methods should be called from constructors only. diff --git a/src/hotspot/share/runtime/frame.hpp b/src/hotspot/share/runtime/frame.hpp index 4113360724d..468437a6484 100644 --- a/src/hotspot/share/runtime/frame.hpp +++ b/src/hotspot/share/runtime/frame.hpp @@ -387,7 +387,9 @@ class frame { static int interpreter_frame_monitor_size(); static int interpreter_frame_monitor_size_in_bytes(); +#ifdef ASSERT void interpreter_frame_verify_monitor(BasicObjectLock* value) const; +#endif // Return/result value from this interpreter frame // If the method return type is T_OBJECT or T_ARRAY populates oop_result @@ -438,8 +440,10 @@ class frame { void print_on_error(outputStream* st, char* buf, int buflen, bool verbose = false) const; static void print_C_frame(outputStream* st, char* buf, int buflen, address pc); +#ifndef PRODUCT // Add annotated descriptions of memory locations belonging to this frame to values void describe(FrameValues& values, int frame_no, const RegisterMap* reg_map=nullptr); +#endif // Conversion from a VMReg to physical stack location template @@ -492,9 +496,11 @@ class frame { // Verification void verify(const RegisterMap* map) const; +#ifdef ASSERT static bool verify_return_pc(address x); // Usage: // assert(frame::verify_return_pc(return_address), "must be a return pc"); +#endif #include CPU_HEADER(frame) diff --git a/src/hotspot/share/runtime/registerMap.hpp b/src/hotspot/share/runtime/registerMap.hpp index 5cf68a87b71..a63a25cbb35 100644 --- a/src/hotspot/share/runtime/registerMap.hpp +++ b/src/hotspot/share/runtime/registerMap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -153,19 +153,19 @@ class RegisterMap : public StackObj { const RegisterMap* as_RegisterMap() const { return this; } RegisterMap* as_RegisterMap() { return this; } +#ifndef PRODUCT void print_on(outputStream* st) const; void print() const; - void set_async(bool value) { NOT_PRODUCT(_async = value;) } - void set_skip_missing(bool value) { NOT_PRODUCT(_skip_missing = value;) } - -#ifndef PRODUCT bool is_async() const { return _async; } bool should_skip_missing() const { return _skip_missing; } VMReg find_register_spilled_here(void* p, intptr_t* sp); #endif + void set_async(bool value) { NOT_PRODUCT(_async = value;) } + void set_skip_missing(bool value) { NOT_PRODUCT(_skip_missing = value;) } + // the following contains the definition of pd_xxx methods #include CPU_HEADER(registerMap) From 66bee2532f849cfb7ab63857ecd7d773c2566722 Mon Sep 17 00:00:00 2001 From: Ivan Walulya Date: Wed, 14 Aug 2024 09:13:21 +0000 Subject: [PATCH 408/460] 8338315: G1: G1CardTableEntryClosure:do_card_ptr remove unused parameter worker_id Reviewed-by: tschatzl --- src/hotspot/share/gc/g1/g1CardTableEntryClosure.hpp | 4 ++-- src/hotspot/share/gc/g1/g1RemSet.cpp | 4 ++-- src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CardTableEntryClosure.hpp b/src/hotspot/share/gc/g1/g1CardTableEntryClosure.hpp index 8fe0d7752eb..e2b53d69e06 100644 --- a/src/hotspot/share/gc/g1/g1CardTableEntryClosure.hpp +++ b/src/hotspot/share/gc/g1/g1CardTableEntryClosure.hpp @@ -36,7 +36,7 @@ class G1CardTableEntryClosure: public CHeapObj { typedef CardTable::CardValue CardValue; // Process the card whose card table entry is "card_ptr". - virtual void do_card_ptr(CardValue* card_ptr, uint worker_id) = 0; + virtual void do_card_ptr(CardValue* card_ptr) = 0; // Process all the card_ptrs in node. void apply_to_buffer(BufferNode* node, uint worker_id) { @@ -44,7 +44,7 @@ class G1CardTableEntryClosure: public CHeapObj { size_t capacity = node->capacity(); for (size_t i = node->index(); i < capacity; ++i) { CardValue* card_ptr = static_cast(buffer[i]); - do_card_ptr(card_ptr, worker_id); + do_card_ptr(card_ptr); } } }; diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp index f2426cdfca5..0f9b9d17df7 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.cpp +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp @@ -1230,11 +1230,10 @@ class G1MergeHeapRootsTask : public WorkerTask { _cards_skipped(0) {} - void do_card_ptr(CardValue* card_ptr, uint worker_id) { + void do_card_ptr(CardValue* card_ptr) override { // The only time we care about recording cards that // contain references that point into the collection set // is during RSet updating within an evacuation pause. - // In this case worker_id should be the id of a GC worker thread. assert(SafepointSynchronize::is_at_safepoint(), "not during an evacuation pause"); uint const region_idx = _ct->region_idx_for(card_ptr); @@ -1342,6 +1341,7 @@ class G1MergeHeapRootsTask : public WorkerTask { FREE_C_HEAP_ARRAY(Stack, _dirty_card_buffers); } } + virtual void work(uint worker_id) { G1CollectedHeap* g1h = G1CollectedHeap::heap(); G1GCPhaseTimes* p = g1h->phase_times(); diff --git a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp index c5ebdb3d22d..e1f0df05c22 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp @@ -522,7 +522,7 @@ class RedirtyLoggedCardTableEntryClosure : public G1CardTableEntryClosure { _g1_ct(g1h->card_table()), _evac_failure_regions(evac_failure_regions) { } - void do_card_ptr(CardValue* card_ptr, uint worker_id) { + void do_card_ptr(CardValue* card_ptr) override { G1HeapRegion* hr = region_for_card(card_ptr); // Should only dirty cards in regions that won't be freed. From 9fe1777fafca30cf60acb5402c7c70800137136e Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 14 Aug 2024 09:16:02 +0000 Subject: [PATCH 409/460] 8338280: Parallel: Inline ParallelCompactData::verify_clear Reviewed-by: tschatzl --- src/hotspot/share/gc/parallel/psParallelCompact.cpp | 11 +++-------- src/hotspot/share/gc/parallel/psParallelCompact.hpp | 1 - 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index 4d54f11805a..4bff8f8a7d0 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -521,19 +521,14 @@ bool ParallelCompactData::summarize(SplitInfo& split_info, } #ifdef ASSERT -void ParallelCompactData::verify_clear(const PSVirtualSpace* vspace) +void ParallelCompactData::verify_clear() { - const size_t* const beg = (const size_t*)vspace->committed_low_addr(); - const size_t* const end = (const size_t*)vspace->committed_high_addr(); + const size_t* const beg = (const size_t*) _region_vspace->committed_low_addr(); + const size_t* const end = (const size_t*) _region_vspace->committed_high_addr(); for (const size_t* p = beg; p < end; ++p) { assert(*p == 0, "not zero"); } } - -void ParallelCompactData::verify_clear() -{ - verify_clear(_region_vspace); -} #endif // #ifdef ASSERT STWGCTimer PSParallelCompact::_gc_timer; diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.hpp index 1e04beb8c66..7e71f077223 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp @@ -393,7 +393,6 @@ class ParallelCompactData inline bool is_region_aligned(HeapWord* addr) const; #ifdef ASSERT - void verify_clear(const PSVirtualSpace* vspace); void verify_clear(); #endif // #ifdef ASSERT From 38bd8a36704a962f0ad1052fd2ec150a61663256 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 14 Aug 2024 09:52:23 +0000 Subject: [PATCH 410/460] 8338236: Compile error in cgroup code on Linux when using clang Reviewed-by: mdoerr, sgehwolf --- src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp | 4 ++-- src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp index 251fbde85f0..56af87881e7 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,7 +62,7 @@ class CgroupV1Controller: public CgroupController { void set_subsystem_path(char *cgroup_path); char *subsystem_path() override { return _path; } - bool is_read_only() { return _read_only; } + bool is_read_only() override { return _read_only; } }; class CgroupV1MemoryController final : public CgroupMemoryController { diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp index 02774fb70ae..cd100f29874 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Red Hat Inc. + * Copyright (c) 2020, 2024, Red Hat Inc. * 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,8 +128,8 @@ class CgroupV2Subsystem: public CgroupSubsystem { const char * container_type() override { return "cgroupv2"; } - CachingCgroupController* memory_controller() { return _memory; } - CachingCgroupController* cpu_controller() { return _cpu; } + CachingCgroupController* memory_controller() override { return _memory; } + CachingCgroupController* cpu_controller() override { return _cpu; } }; #endif // CGROUP_V2_SUBSYSTEM_LINUX_HPP From fbe4f05636c8f692bd40bbe11fb5bb8b77b77042 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Wed, 14 Aug 2024 12:20:17 +0000 Subject: [PATCH 411/460] 8337976: Insufficient error recovery in parser for switch inside class body Reviewed-by: vromero --- .../com/sun/tools/javac/comp/Attr.java | 13 +++- .../sun/tools/javac/parser/JavacParser.java | 22 +++++- .../sun/tools/javac/parser/VirtualParser.java | 2 +- .../tools/javac/resources/compiler.properties | 3 + .../diags/examples/StatementNotExpected.java | 28 +++++++ .../tools/javac/parser/JavacParserTest.java | 78 ++++++++++++++++++- .../javac/records/RecordCompilationTests.java | 2 +- .../tools/javac/recovery/T8337976.java | 10 +++ .../tools/javac/recovery/T8337976.out | 5 ++ 9 files changed, 156 insertions(+), 7 deletions(-) create mode 100644 test/langtools/tools/javac/diags/examples/StatementNotExpected.java create mode 100644 test/langtools/tools/javac/recovery/T8337976.java create mode 100644 test/langtools/tools/javac/recovery/T8337976.out diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index 9b79846ba40..54edc19560b 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -5251,7 +5251,18 @@ public void visitAnnotatedType(JCAnnotatedType tree) { public void visitErroneous(JCErroneous tree) { if (tree.errs != null) { - Env errEnv = env.dup(env.tree, env.info.dup()); + WriteableScope newScope = env.info.scope; + + if (env.tree instanceof JCClassDecl) { + Symbol fakeOwner = + new MethodSymbol(BLOCK, names.empty, null, + env.info.scope.owner); + newScope = newScope.dupUnshared(fakeOwner); + } + + Env errEnv = + env.dup(env.tree, + env.info.dup(newScope)); errEnv.info.returnResult = unknownExprInfo; for (JCTree err : tree.errs) attribTree(err, errEnv, new ResultInfo(KindSelector.ERR, pt())); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java index f570ad54c58..6fc93fdc591 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -455,7 +455,7 @@ protected JCErroneous syntaxError(int pos, Error errorKey) { return syntaxError(pos, List.nil(), errorKey); } - protected JCErroneous syntaxError(int pos, List errs, Error errorKey) { + protected JCErroneous syntaxError(int pos, List errs, Error errorKey) { setErrorEndPos(pos); JCErroneous err = F.at(pos).Erroneous(errs); reportSyntaxError(err, errorKey); @@ -4733,6 +4733,12 @@ protected List classOrInterfaceOrRecordBodyDeclaration(JCModifiers mods, } ignoreDanglingComments(); // no declaration with which dangling comments can be associated return List.of(block(pos, mods.flags)); + } else if (isDefiniteStatementStartToken()) { + int startPos = token.pos; + List statements = blockStatement(); + return List.of(syntaxError(startPos, + statements, + Errors.StatementNotExpected)); } else { return constructorOrMethodOrFieldDeclaration(mods, className, isInterface, isRecord, dc); } @@ -4910,7 +4916,19 @@ protected boolean isDeclaration() { token.kind == INTERFACE || token.kind == ENUM || isRecordStart() && allowRecords; - } + } + + /** + * {@return true if and only if the current token is definitelly a token that + * starts a statement.} + */ + private boolean isDefiniteStatementStartToken() { + return switch (token.kind) { + case IF, WHILE, DO, SWITCH, RETURN, TRY, FOR, ASSERT, BREAK, + CONTINUE, THROW -> true; + default -> false; + }; + } protected boolean isRecordStart() { if (token.kind == IDENTIFIER && token.name() == names.record && peekToken(TokenKind.IDENTIFIER)) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/VirtualParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/VirtualParser.java index f32c1bf4756..ec3a373ab4e 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/VirtualParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/VirtualParser.java @@ -62,7 +62,7 @@ protected JCErroneous syntaxError(int pos, Error errorKey) { } @Override - protected JCErroneous syntaxError(int pos, List errs, Error errorKey) { + protected JCErroneous syntaxError(int pos, List errs, Error errorKey) { hasErrors = true; return F.Erroneous(); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties index 10f06ad7017..6fd59438220 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -1616,6 +1616,9 @@ compiler.err.file.sb.on.source.or.patch.path.for.module=\ compiler.err.no.java.lang=\ Unable to find package java.lang in platform classes +compiler.err.statement.not.expected=\ + statements not expected outside of methods and initializers + ##### # Fatal Errors diff --git a/test/langtools/tools/javac/diags/examples/StatementNotExpected.java b/test/langtools/tools/javac/diags/examples/StatementNotExpected.java new file mode 100644 index 00000000000..a6b965a8044 --- /dev/null +++ b/test/langtools/tools/javac/diags/examples/StatementNotExpected.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// key: compiler.err.statement.not.expected + +class StatementNotExpected { + return null; +} diff --git a/test/langtools/tools/javac/parser/JavacParserTest.java b/test/langtools/tools/javac/parser/JavacParserTest.java index 93b2b51a8fa..547de1088b4 100644 --- a/test/langtools/tools/javac/parser/JavacParserTest.java +++ b/test/langtools/tools/javac/parser/JavacParserTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 7073631 7159445 7156633 8028235 8065753 8205418 8205913 8228451 8237041 8253584 8246774 8256411 8256149 8259050 8266436 8267221 8271928 8275097 8293897 8295401 8304671 8310326 8312093 8312204 8315452 + * @bug 7073631 7159445 7156633 8028235 8065753 8205418 8205913 8228451 8237041 8253584 8246774 8256411 8256149 8259050 8266436 8267221 8271928 8275097 8293897 8295401 8304671 8310326 8312093 8312204 8315452 8337976 * @summary tests error and diagnostics positions * @author Jan Lahoda * @modules jdk.compiler/com.sun.tools.javac.api @@ -2409,6 +2409,80 @@ void testPartialTopLevelModifiers() throws IOException { (ERROR: public )"""); } + @Test //JDK-8337976 + void testStatementsInClass() throws IOException { + String code = """ + package test; + public class Test { + if (true); + while (true); + do {} while (true); + for ( ; ; ); + switch (0) { default: } + assert true; + break; + continue; + return ; + throw new RuntimeException(); + try { + } catch (RuntimeException ex) {} + } + """; + DiagnosticCollector coll = + new DiagnosticCollector<>(); + JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, + List.of("--enable-preview", "--source", SOURCE_VERSION), + null, Arrays.asList(new MyFileObject(code))); + CompilationUnitTree cut = ct.parse().iterator().next(); + + String result = toStringWithErrors(cut).replaceAll("\\R", "\n"); + System.out.println("RESULT\n" + result); + assertEquals("incorrect AST", + result, + """ + package test; + \n\ + public class Test { + (ERROR: if (true) ;) + (ERROR: while (true) ;) + (ERROR: do { + } while (true);) + (ERROR: for (; ; ) ;) + (ERROR: switch (0) { + default: + + }) + (ERROR: assert true;) + (ERROR: break;) + (ERROR: continue;) + (ERROR: return;) + (ERROR: throw new RuntimeException();) + (ERROR: try { + } catch (RuntimeException ex) { + }) + }"""); + + List codes = new LinkedList<>(); + + for (Diagnostic d : coll.getDiagnostics()) { + codes.add(d.getLineNumber() + ":" + d.getColumnNumber() + ":" + d.getCode()); + } + + assertEquals("testStatementsInClass: " + codes, + List.of("3:5:compiler.err.statement.not.expected", + "4:5:compiler.err.statement.not.expected", + "5:5:compiler.err.statement.not.expected", + "6:5:compiler.err.statement.not.expected", + "7:5:compiler.err.statement.not.expected", + "8:5:compiler.err.statement.not.expected", + "9:5:compiler.err.statement.not.expected", + "10:5:compiler.err.statement.not.expected", + "11:5:compiler.err.statement.not.expected", + "12:5:compiler.err.statement.not.expected", + "13:5:compiler.err.statement.not.expected"), + codes); + } + void run(String[] args) throws Exception { int passed = 0, failed = 0; final Pattern p = (args != null && args.length > 0) diff --git a/test/langtools/tools/javac/records/RecordCompilationTests.java b/test/langtools/tools/javac/records/RecordCompilationTests.java index cbd00f9c607..d80ade50a3b 100644 --- a/test/langtools/tools/javac/records/RecordCompilationTests.java +++ b/test/langtools/tools/javac/records/RecordCompilationTests.java @@ -1358,7 +1358,7 @@ void testAcceptRecordId() { try { String[] testOptions = {}; setCompileOptions(testOptions); - assertFail("compiler.err.illegal.start.of.type", + assertFail("compiler.err.statement.not.expected", "class R {\n" + " record RR(int i) {\n" + " return null;\n" + diff --git a/test/langtools/tools/javac/recovery/T8337976.java b/test/langtools/tools/javac/recovery/T8337976.java new file mode 100644 index 00000000000..cac987f4083 --- /dev/null +++ b/test/langtools/tools/javac/recovery/T8337976.java @@ -0,0 +1,10 @@ +/** + * @test /nodynamiccopyright/ + * @bug 8337976 + * @summary Verify javac does not crash and produces nice errors for certain erroneous code. + * @compile/fail/ref=T8337976.out -XDrawDiagnostics -XDshould-stop.at=FLOW -XDdev T8337976.java + */ +public class T8337976 { + switch (0) { default: undefined u;} + if (true) { undefined u; } +} diff --git a/test/langtools/tools/javac/recovery/T8337976.out b/test/langtools/tools/javac/recovery/T8337976.out new file mode 100644 index 00000000000..bae578cecf3 --- /dev/null +++ b/test/langtools/tools/javac/recovery/T8337976.out @@ -0,0 +1,5 @@ +T8337976.java:8:5: compiler.err.statement.not.expected +T8337976.java:9:5: compiler.err.statement.not.expected +T8337976.java:8:27: compiler.err.cant.resolve.location: kindname.class, undefined, , , (compiler.misc.location: kindname.class, T8337976, null) +T8337976.java:9:17: compiler.err.cant.resolve.location: kindname.class, undefined, , , (compiler.misc.location: kindname.class, T8337976, null) +4 errors From a5d948fb9841f654cccc9567c60e8d28e7d719ae Mon Sep 17 00:00:00 2001 From: John Engebretson Date: Wed, 14 Aug 2024 14:11:53 +0000 Subject: [PATCH 412/460] 8332842: Optimize empty CopyOnWriteArrayList allocations Reviewed-by: shade, alanb --- .../util/concurrent/CopyOnWriteArrayList.java | 22 ++- .../CopyOnWriteArrayListBenchmark.java | 166 ++++++++++++++++++ 2 files changed, 184 insertions(+), 4 deletions(-) create mode 100644 test/micro/org/openjdk/bench/java/util/concurrent/CopyOnWriteArrayListBenchmark.java diff --git a/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java b/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java index 7182f98706d..f0f60730eb6 100644 --- a/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java +++ b/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java @@ -100,6 +100,8 @@ public class CopyOnWriteArrayList implements List, RandomAccess, Cloneable, java.io.Serializable { private static final long serialVersionUID = 8673264195747942595L; + private static final Object[] EMPTY_ELEMENTDATA = {}; + /** * The lock protecting all mutators. (We have a mild preference * for builtin monitors over ReentrantLock when either will do.) @@ -128,7 +130,7 @@ final void setArray(Object[] a) { * Creates an empty list. */ public CopyOnWriteArrayList() { - setArray(new Object[0]); + setArray(EMPTY_ELEMENTDATA); } /** @@ -143,6 +145,8 @@ public CopyOnWriteArrayList(Collection c) { Object[] es; if (c.getClass() == CopyOnWriteArrayList.class) es = ((CopyOnWriteArrayList)c).getArray(); + else if (c.isEmpty()) + es = EMPTY_ELEMENTDATA; else { es = c.toArray(); if (c.getClass() != java.util.ArrayList.class) @@ -159,7 +163,10 @@ public CopyOnWriteArrayList(Collection c) { * @throws NullPointerException if the specified array is null */ public CopyOnWriteArrayList(E[] toCopyIn) { - setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class)); + if (toCopyIn.length == 0) + setArray(EMPTY_ELEMENTDATA); + else + setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class)); } /** @@ -533,6 +540,8 @@ public E remove(int index) { Object[] newElements; if (numMoved == 0) newElements = Arrays.copyOf(es, len - 1); + else if (len == 1) + newElements = EMPTY_ELEMENTDATA; else { newElements = new Object[len - 1]; System.arraycopy(es, 0, newElements, 0, index); @@ -618,6 +627,11 @@ private boolean remove(Object o, Object[] snapshot, int index) { if (index < 0) return false; } + if (len == 1) { + // one element exists and that element should be removed + setArray(EMPTY_ELEMENTDATA); + return true; + } Object[] newElements = new Object[len - 1]; System.arraycopy(current, 0, newElements, 0, index); System.arraycopy(current, index + 1, @@ -804,7 +818,7 @@ public int addAllAbsent(Collection c) { */ public void clear() { synchronized (lock) { - setArray(new Object[0]); + setArray(EMPTY_ELEMENTDATA); } } @@ -1022,7 +1036,7 @@ private void readObject(java.io.ObjectInputStream s) // Read in array length and allocate array int len = s.readInt(); SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, len); - Object[] es = new Object[len]; + Object[] es = (len == 0 ? EMPTY_ELEMENTDATA : new Object[len]); // Read in all elements in the proper order. for (int i = 0; i < len; i++) diff --git a/test/micro/org/openjdk/bench/java/util/concurrent/CopyOnWriteArrayListBenchmark.java b/test/micro/org/openjdk/bench/java/util/concurrent/CopyOnWriteArrayListBenchmark.java new file mode 100644 index 00000000000..0ce091d1724 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/util/concurrent/CopyOnWriteArrayListBenchmark.java @@ -0,0 +1,166 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.util.concurrent; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.TimeUnit; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +@BenchmarkMode(Mode.AverageTime) +@State(Scope.Benchmark) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Fork(1) +@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) +public class CopyOnWriteArrayListBenchmark { + + private static byte[] getSerializedBytes(CopyOnWriteArrayList list) throws IOException { + ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); + ObjectOutputStream objectOut = new ObjectOutputStream(bytesOut); + objectOut.writeObject(list); + + objectOut.close(); + return bytesOut.toByteArray(); + } + + private Collection emptyCollection = new ArrayList<>(); + private Object[] emptyArray = new Object[0]; + + private Collection oneItemCollection = Arrays.asList(""); + private Object[] oneItemArray = new Object[] { "" }; + + private CopyOnWriteArrayList emptyInstance = new CopyOnWriteArrayList<>(); + private CopyOnWriteArrayList oneItemInstance = new CopyOnWriteArrayList<>(oneItemArray); + + private byte[] emptyInstanceBytes; + private byte[] oneInstanceBytes; + + public CopyOnWriteArrayListBenchmark() { + try { + emptyInstanceBytes = getSerializedBytes(emptyInstance); + oneInstanceBytes = getSerializedBytes(oneItemInstance); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Benchmark + public void clear() { + // have to create a new instance on each execution + ((CopyOnWriteArrayList) oneItemInstance.clone()).clear(); + } + + @Benchmark + public void clearEmpty() { + emptyInstance.clear(); + } + + @Benchmark + public CopyOnWriteArrayList createInstanceArray() { + return new CopyOnWriteArrayList<>(oneItemArray); + } + + @Benchmark + public CopyOnWriteArrayList createInstanceArrayEmpty() { + return new CopyOnWriteArrayList<>(emptyArray); + } + + @Benchmark + public CopyOnWriteArrayList createInstanceCollection() { + return new CopyOnWriteArrayList<>(oneItemCollection); + } + + @Benchmark + public CopyOnWriteArrayList createInstanceCollectionEmpty() { + return new CopyOnWriteArrayList<>(emptyCollection); + } + + @Benchmark + public CopyOnWriteArrayList createInstanceDefault() { + return new CopyOnWriteArrayList(); + } + + @Benchmark + public CopyOnWriteArrayList readInstance() throws IOException, ClassNotFoundException { + try (ObjectInputStream objIn = new ObjectInputStream(new ByteArrayInputStream(oneInstanceBytes))) { + return (CopyOnWriteArrayList) objIn.readObject(); + } + } + + @Benchmark + public CopyOnWriteArrayList readInstanceEmpty() throws IOException, ClassNotFoundException { + try (ObjectInputStream objIn = new ObjectInputStream(new ByteArrayInputStream(emptyInstanceBytes))) { + return (CopyOnWriteArrayList) objIn.readObject(); + } + } + + @Benchmark + public CopyOnWriteArrayList removeObjectLastRemaining() { + CopyOnWriteArrayList list = new CopyOnWriteArrayList<>(); + list.add(""); + list.remove(""); + return list; + } + + @Benchmark + public CopyOnWriteArrayList removeIndexLastRemaining() { + CopyOnWriteArrayList list = new CopyOnWriteArrayList<>(); + list.add(""); + list.remove(0); + return list; + } + @Benchmark + public CopyOnWriteArrayList removeObject() { + CopyOnWriteArrayList list = new CopyOnWriteArrayList<>(); + list.add(""); + list.add("a"); + list.remove(""); + return list; + } + + @Benchmark + public CopyOnWriteArrayList remove() { + CopyOnWriteArrayList list = new CopyOnWriteArrayList<>(); + list.add(""); + list.add("a"); + list.remove(0); + return list; + } +} From d8e4d3f2d6c187f2487acd390a4e5fa2a99010ea Mon Sep 17 00:00:00 2001 From: Zdenek Zambersky Date: Wed, 14 Aug 2024 15:20:07 +0000 Subject: [PATCH 413/460] 8338402: GHA: some of bundles may not get removed Reviewed-by: ihse, shade --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b16335b7091..6a1b4420e3a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -371,7 +371,7 @@ jobs: -H 'Accept: application/vnd.github+json' \ -H 'Authorization: Bearer ${{ github.token }}' \ -H 'X-GitHub-Api-Version: 2022-11-28' \ - '${{ github.api_url }}/repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts')" + '${{ github.api_url }}/repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts?per_page=100')" BUNDLE_ARTIFACT_IDS="$(echo "$ALL_ARTIFACT_IDS" | jq -r -c '.artifacts | map(select(.name|startswith("bundles-"))) | .[].id')" for id in $BUNDLE_ARTIFACT_IDS; do echo "Removing $id" From 0e3903f2eb854715acee92cfc5ee2d4a2e800f61 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 14 Aug 2024 16:49:11 +0000 Subject: [PATCH 414/460] 8338393: Parallel: Remove unused ParallelCompactData::clear_range Reviewed-by: tschatzl --- src/hotspot/share/gc/parallel/psParallelCompact.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.hpp index 7e71f077223..3f487ec3ef4 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp @@ -374,9 +374,6 @@ class ParallelCompactData HeapWord** target_next); void clear_range(size_t beg_region, size_t end_region); - void clear_range(HeapWord* beg, HeapWord* end) { - clear_range(addr_to_region_idx(beg), addr_to_region_idx(end)); - } // Return the number of words between addr and the start of the region // containing addr. From 6a390147959e0fb88de6ee13204cff72cd910f09 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 14 Aug 2024 16:56:28 +0000 Subject: [PATCH 415/460] 8338110: Exclude Fingerprinter::do_type from ubsan checks Reviewed-by: jwaters, rrich --- src/hotspot/share/runtime/signature.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hotspot/share/runtime/signature.hpp b/src/hotspot/share/runtime/signature.hpp index 3f7d062ab66..25de9c0a1f0 100644 --- a/src/hotspot/share/runtime/signature.hpp +++ b/src/hotspot/share/runtime/signature.hpp @@ -28,6 +28,7 @@ #include "memory/allocation.hpp" #include "oops/method.hpp" +#include "sanitizers/ub.hpp" // Static routines and parsing loops for processing field and method @@ -338,6 +339,7 @@ class Fingerprinter: public SignatureIterator { void do_type_calling_convention(BasicType type); friend class SignatureIterator; // so do_parameters_on can call do_type + ATTRIBUTE_NO_UBSAN void do_type(BasicType type) { assert(fp_is_valid_type(type), "bad parameter type"); _accumulator |= ((fingerprint_t)type << _shift_count); From c0384b6f3584501fb3bd93854734eeacf6620a7e Mon Sep 17 00:00:00 2001 From: Phil Race Date: Wed, 14 Aug 2024 17:58:24 +0000 Subject: [PATCH 416/460] 8337237: Use FFM instead of Unsafe for Java 2D RenderBuffer class Reviewed-by: jvernee, jdv --- .../classes/sun/java2d/pipe/RenderBuffer.java | 134 ++++++++---------- 1 file changed, 60 insertions(+), 74 deletions(-) diff --git a/src/java.desktop/share/classes/sun/java2d/pipe/RenderBuffer.java b/src/java.desktop/share/classes/sun/java2d/pipe/RenderBuffer.java index 57f24a4eada..2b57d98ef40 100644 --- a/src/java.desktop/share/classes/sun/java2d/pipe/RenderBuffer.java +++ b/src/java.desktop/share/classes/sun/java2d/pipe/RenderBuffer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,58 +25,54 @@ package sun.java2d.pipe; -import jdk.internal.misc.Unsafe; +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; +import static java.lang.foreign.ValueLayout.*; /** - * The RenderBuffer class is a simplified, high-performance, Unsafe wrapper + * The RenderBuffer class is a simplified, high-performance class * used for buffering rendering operations in a single-threaded rendering - * environment. It's functionality is similar to the ByteBuffer and related + * environment. Its functionality is similar to the ByteBuffer and related * NIO classes. However, the methods in this class perform little to no * alignment or bounds checks for performance reasons. Therefore, it is * the caller's responsibility to ensure that all put() calls are properly * aligned and within bounds: * - int and float values must be aligned on 4-byte boundaries * - long and double values must be aligned on 8-byte boundaries + * Failure to do so will result in exceptions from the FFM API, or worse. * * This class only includes the bare minimum of methods to support * single-threaded rendering. For example, there is no put(double[]) method * because we currently have no need for such a method in the STR classes. */ -public class RenderBuffer { +public final class RenderBuffer { /** * These constants represent the size of various data types (in bytes). */ - protected static final long SIZEOF_BYTE = 1L; - protected static final long SIZEOF_SHORT = 2L; - protected static final long SIZEOF_INT = 4L; - protected static final long SIZEOF_FLOAT = 4L; - protected static final long SIZEOF_LONG = 8L; - protected static final long SIZEOF_DOUBLE = 8L; + private static final int SIZEOF_BYTE = Byte.BYTES; + private static final int SIZEOF_SHORT = Short.BYTES; + private static final int SIZEOF_INT = Integer.BYTES; + private static final int SIZEOF_FLOAT = Float.BYTES; + private static final int SIZEOF_LONG = Long.BYTES; + private static final int SIZEOF_DOUBLE = Double.BYTES; /** - * Represents the number of elements at which we have empirically - * determined that the average cost of a JNI call exceeds the expense - * of an element by element copy. In other words, if the number of - * elements in an array to be copied exceeds this value, then we should - * use the copyFromArray() method to complete the bulk put operation. - * (This value can be adjusted if the cost of JNI downcalls is reduced - * in a future release.) + * Measurements show that using the copy API from a segment backed by a heap + * array gets reliably faster than individual puts around a length of 10. + * However the time is miniscule in the context of what it is used for + * and much more than adequate, so no problem expected if this changes over time. */ - private static final int COPY_FROM_ARRAY_THRESHOLD = 6; - - protected final Unsafe unsafe; - protected final long baseAddress; - protected final long endAddress; - protected long curAddress; - protected final int capacity; - - protected RenderBuffer(int numBytes) { - unsafe = Unsafe.getUnsafe(); - curAddress = baseAddress = unsafe.allocateMemory(numBytes); - endAddress = baseAddress + numBytes; - capacity = numBytes; + private static final int COPY_FROM_ARRAY_THRESHOLD = 10; + + private final MemorySegment segment; + private int curOffset; + + private RenderBuffer(int numBytes) { + segment = Arena.global().allocate(numBytes, SIZEOF_DOUBLE); + curOffset = 0; } /** @@ -90,7 +86,7 @@ public static RenderBuffer allocate(int numBytes) { * Returns the base address of the underlying memory buffer. */ public final long getAddress() { - return baseAddress; + return segment.address(); } /** @@ -99,27 +95,27 @@ public final long getAddress() { */ public final int capacity() { - return capacity; + return (int)segment.byteSize(); } public final int remaining() { - return (int)(endAddress - curAddress); + return (capacity() - curOffset); } public final int position() { - return (int)(curAddress - baseAddress); + return curOffset; } - public final void position(long numBytes) { - curAddress = baseAddress + numBytes; + public final void position(int bytePos) { + curOffset = bytePos; } public final void clear() { - curAddress = baseAddress; + curOffset = 0; } - public final RenderBuffer skip(long numBytes) { - curAddress += numBytes; + public final RenderBuffer skip(int numBytes) { + curOffset += numBytes; return this; } @@ -128,8 +124,8 @@ public final RenderBuffer skip(long numBytes) { */ public final RenderBuffer putByte(byte x) { - unsafe.putByte(curAddress, x); - curAddress += SIZEOF_BYTE; + segment.set(JAVA_BYTE, curOffset, x); + curOffset += SIZEOF_BYTE; return this; } @@ -139,10 +135,8 @@ public RenderBuffer put(byte[] x) { public RenderBuffer put(byte[] x, int offset, int length) { if (length > COPY_FROM_ARRAY_THRESHOLD) { - long offsetInBytes = offset * SIZEOF_BYTE + Unsafe.ARRAY_BYTE_BASE_OFFSET; - long lengthInBytes = length * SIZEOF_BYTE; - unsafe.copyMemory(x, offsetInBytes, null, curAddress, lengthInBytes); - position(position() + lengthInBytes); + MemorySegment.copy(x, offset, segment, JAVA_BYTE, curOffset, length); + position(position() + length * SIZEOF_BYTE); } else { int end = offset + length; for (int i = offset; i < end; i++) { @@ -158,8 +152,8 @@ public RenderBuffer put(byte[] x, int offset, int length) { public final RenderBuffer putShort(short x) { // assert (position() % SIZEOF_SHORT == 0); - unsafe.putShort(curAddress, x); - curAddress += SIZEOF_SHORT; + segment.set(JAVA_SHORT, curOffset, x); + curOffset += SIZEOF_SHORT; return this; } @@ -170,10 +164,8 @@ public RenderBuffer put(short[] x) { public RenderBuffer put(short[] x, int offset, int length) { // assert (position() % SIZEOF_SHORT == 0); if (length > COPY_FROM_ARRAY_THRESHOLD) { - long offsetInBytes = offset * SIZEOF_SHORT + Unsafe.ARRAY_SHORT_BASE_OFFSET; - long lengthInBytes = length * SIZEOF_SHORT; - unsafe.copyMemory(x, offsetInBytes, null, curAddress, lengthInBytes); - position(position() + lengthInBytes); + MemorySegment.copy(x, offset, segment, JAVA_SHORT, curOffset, length); + position(position() + length * SIZEOF_SHORT); } else { int end = offset + length; for (int i = offset; i < end; i++) { @@ -188,15 +180,15 @@ public RenderBuffer put(short[] x, int offset, int length) { */ public final RenderBuffer putInt(int pos, int x) { - // assert (baseAddress + pos % SIZEOF_INT == 0); - unsafe.putInt(baseAddress + pos, x); + // assert (getAddress() + pos % SIZEOF_INT == 0); + segment.set(JAVA_INT, pos, x); return this; } public final RenderBuffer putInt(int x) { // assert (position() % SIZEOF_INT == 0); - unsafe.putInt(curAddress, x); - curAddress += SIZEOF_INT; + segment.set(JAVA_INT, curOffset, x); + curOffset += SIZEOF_INT; return this; } @@ -207,10 +199,8 @@ public RenderBuffer put(int[] x) { public RenderBuffer put(int[] x, int offset, int length) { // assert (position() % SIZEOF_INT == 0); if (length > COPY_FROM_ARRAY_THRESHOLD) { - long offsetInBytes = offset * SIZEOF_INT + Unsafe.ARRAY_INT_BASE_OFFSET; - long lengthInBytes = length * SIZEOF_INT; - unsafe.copyMemory(x, offsetInBytes, null, curAddress, lengthInBytes); - position(position() + lengthInBytes); + MemorySegment.copy(x, offset, segment, JAVA_INT, curOffset, length); + position(position() + length * SIZEOF_INT); } else { int end = offset + length; for (int i = offset; i < end; i++) { @@ -226,8 +216,8 @@ public RenderBuffer put(int[] x, int offset, int length) { public final RenderBuffer putFloat(float x) { // assert (position() % SIZEOF_FLOAT == 0); - unsafe.putFloat(curAddress, x); - curAddress += SIZEOF_FLOAT; + segment.set(JAVA_FLOAT, curOffset, x); + curOffset += SIZEOF_FLOAT; return this; } @@ -238,10 +228,8 @@ public RenderBuffer put(float[] x) { public RenderBuffer put(float[] x, int offset, int length) { // assert (position() % SIZEOF_FLOAT == 0); if (length > COPY_FROM_ARRAY_THRESHOLD) { - long offsetInBytes = offset * SIZEOF_FLOAT + Unsafe.ARRAY_FLOAT_BASE_OFFSET; - long lengthInBytes = length * SIZEOF_FLOAT; - unsafe.copyMemory(x, offsetInBytes, null, curAddress, lengthInBytes); - position(position() + lengthInBytes); + MemorySegment.copy(x, offset, segment, JAVA_FLOAT, curOffset, length); + position(position() + length * SIZEOF_FLOAT); } else { int end = offset + length; for (int i = offset; i < end; i++) { @@ -257,8 +245,8 @@ public RenderBuffer put(float[] x, int offset, int length) { public final RenderBuffer putLong(long x) { // assert (position() % SIZEOF_LONG == 0); - unsafe.putLong(curAddress, x); - curAddress += SIZEOF_LONG; + segment.set(JAVA_LONG, curOffset, x); + curOffset += SIZEOF_LONG; return this; } @@ -269,10 +257,8 @@ public RenderBuffer put(long[] x) { public RenderBuffer put(long[] x, int offset, int length) { // assert (position() % SIZEOF_LONG == 0); if (length > COPY_FROM_ARRAY_THRESHOLD) { - long offsetInBytes = offset * SIZEOF_LONG + Unsafe.ARRAY_LONG_BASE_OFFSET; - long lengthInBytes = length * SIZEOF_LONG; - unsafe.copyMemory(x, offsetInBytes, null, curAddress, lengthInBytes); - position(position() + lengthInBytes); + MemorySegment.copy(x, offset, segment, JAVA_LONG, curOffset, length); + position(position() + length * SIZEOF_LONG); } else { int end = offset + length; for (int i = offset; i < end; i++) { @@ -288,8 +274,8 @@ public RenderBuffer put(long[] x, int offset, int length) { public final RenderBuffer putDouble(double x) { // assert (position() % SIZEOF_DOUBLE == 0); - unsafe.putDouble(curAddress, x); - curAddress += SIZEOF_DOUBLE; + segment.set(JAVA_DOUBLE, curOffset, x); + curOffset += SIZEOF_DOUBLE; return this; } } From 723ac5763aed0d67516c6746f39a066efc412b48 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Wed, 14 Aug 2024 18:41:24 +0000 Subject: [PATCH 417/460] 8332488: Add JVMTI DataDumpRequest to the debug agent Reviewed-by: sspitsyn, lmesnik --- .../share/native/libjdwp/debugInit.c | 11 +- .../share/native/libjdwp/eventFilter.c | 8 +- .../share/native/libjdwp/eventFilter.h | 6 +- .../share/native/libjdwp/eventHandler.c | 59 +++++- .../share/native/libjdwp/eventHandler.h | 4 +- .../share/native/libjdwp/threadControl.c | 13 +- .../share/native/libjdwp/threadControl.h | 4 +- .../share/native/libjdwp/util.c | 4 - .../share/native/libjdwp/util.h | 3 +- test/jdk/com/sun/jdi/DataDumpTest.java | 176 ++++++++++++++++++ 10 files changed, 251 insertions(+), 37 deletions(-) create mode 100644 test/jdk/com/sun/jdi/DataDumpTest.java diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/debugInit.c b/src/jdk.jdwp.agent/share/native/libjdwp/debugInit.c index fe990e97a65..b221cf6cf25 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/debugInit.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/debugInit.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -995,6 +995,8 @@ parseOptions(char *options) gdata->includeVThreads = JNI_FALSE; gdata->rememberVThreadsWhenDisconnected = JNI_FALSE; + gdata->jvmti_data_dump = JNI_FALSE; + /* Options being NULL will end up being an error. */ if (options == NULL) { options = ""; @@ -1159,6 +1161,13 @@ parseOptions(char *options) if ( dopause ) { do_pause(); } + } else if (strcmp(buf, "datadump") == 0) { + // Enable JVMTI DATA_DUMP_REQUEST support. + // This is not a documented flag. This feature is experimental and is only intended + // to be used by debug agent developers. See comment for cbDataDump() for more details. + if ( !get_boolean(&str, &(gdata->jvmti_data_dump)) ) { + goto syntax_error; + } } else if (strcmp(buf, "coredump") == 0) { if ( !get_boolean(&str, &docoredump) ) { goto syntax_error; diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/eventFilter.c b/src/jdk.jdwp.agent/share/native/libjdwp/eventFilter.c index af56d7145c9..3ba875e88cd 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/eventFilter.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/eventFilter.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1387,9 +1387,7 @@ eventFilterRestricted_deinstall(HandlerNode *node) return error1 != JVMTI_ERROR_NONE? error1 : error2; } -/***** debugging *****/ - -#ifdef DEBUG +/***** APIs for debugging the debug agent *****/ void eventFilter_dumpHandlerFilters(HandlerNode *node) @@ -1476,5 +1474,3 @@ eventFilter_dumpHandlerFilters(HandlerNode *node) } } } - -#endif /* DEBUG */ diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/eventFilter.h b/src/jdk.jdwp.agent/share/native/libjdwp/eventFilter.h index 9d79509f0d2..984d64815d6 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/eventFilter.h +++ b/src/jdk.jdwp.agent/share/native/libjdwp/eventFilter.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,10 +76,8 @@ jvmtiError eventFilter_setPlatformThreadsOnlyFilter(HandlerNode *node, jint inde jboolean eventFilter_predictFiltering(HandlerNode *node, jclass clazz, char *classname); jboolean isBreakpointSet(jclass clazz, jmethodID method, jlocation location); -/***** debugging *****/ +/***** APIs for debugging the debug agent *****/ -#ifdef DEBUG void eventFilter_dumpHandlerFilters(HandlerNode *node); -#endif #endif /* _EVENT_FILTER_H */ diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.c b/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.c index cf2de806119..e4a9bd79943 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.c @@ -1330,6 +1330,44 @@ cbVMDeath(jvmtiEnv *jvmti_env, JNIEnv *env) LOG_MISC(("END cbVMDeath")); } +/** + * Event callback for JVMTI_EVENT_DATA_DUMP_REQUEST + * + * This callback is made when a JVMTI data dump is requested. The common way of doing + * this is with "jcmd JVMTI.data_dump". + * + * Debug agent data dumps are experimental and only intended to be used by debug agent + * developers. Data dumps are disabled by default. + * + * This callback is enabled by launching the debug agent with datadump=y. The easiest + * way to enabled data dumps with debugger tests or when using jdb is to use the + * _JAVA_JDWP_OPTIONS export. The following works well when running tests: + * + * make test TEST= \ + * JTREG='JAVA_OPTIONS=-XX:+StartAttachListener;OPTIONS=-e:_JAVA_JDWP_OPTIONS=datadump=y' + * + * Data dumps may fail to happen due to the debug agent suspending all threads. + * This causes the Signal Dispatcher and Attach Listener threads to be suspended, + * which can cause issues with jcmd attaching. Running with -XX:+StartAttachListener can + * help, but in general it is best not to try a datadump when all threads are suspended. + * + * Data dumps are also risky when the debug agent is handling events or commands from + * the debugger, due to dumping data that is not lock protected. This can cause a + * crash. + * + * Data dumps are meant to aid with post mortem debugging (debugging after a + * problem has been detected), not for ongoing periodic data gathering. + */ +static void JNICALL +cbDataDump(jvmtiEnv *jvmti_env) +{ + tty_message("Debug Agent Data Dump"); + tty_message("=== START DUMP ==="); + threadControl_dumpAllThreads(); + eventHandler_dumpAllHandlers(JNI_TRUE); + tty_message("=== END DUMP ==="); +} + /** * Delete this handler (do not delete permanent handlers): * Deinsert handler from active list, @@ -1518,6 +1556,19 @@ eventHandler_initialize(jbyte sessionID) if (error != JVMTI_ERROR_NONE) { EXIT_ERROR(error,"Can't enable garbage collection finish events"); } + + /* + * DATA_DUMP_REQUEST is special since it is not tied to any handlers or an EI, + * so it cannot be setup using threadControl_setEventMode(). Use JVMTI API directly. + */ + if (gdata->jvmti_data_dump) { + error = JVMTI_FUNC_PTR(gdata->jvmti,SetEventNotificationMode) + (gdata->jvmti, JVMTI_ENABLE, JVMTI_EVENT_DATA_DUMP_REQUEST, NULL); + if (error != JVMTI_ERROR_NONE) { + EXIT_ERROR(error,"Can't enable data dump request events"); + } + } + /* * Only enable vthread START and END events if we want to remember * vthreads when no debugger is connected. @@ -1580,6 +1631,8 @@ eventHandler_initialize(jbyte sessionID) gdata->callbacks.VirtualThreadStart = &cbVThreadStart; /* Event callback for JVMTI_EVENT_VIRTUAL_THREAD_END */ gdata->callbacks.VirtualThreadEnd = &cbVThreadEnd; + /* Event callback for JVMTI_EVENT_DATA_DUMP_REQUEST */ + gdata->callbacks.DataDumpRequest = &cbDataDump; error = JVMTI_FUNC_PTR(gdata->jvmti,SetEventCallbacks) (gdata->jvmti, &(gdata->callbacks), sizeof(gdata->callbacks)); @@ -1851,9 +1904,7 @@ eventHandler_installExternal(HandlerNode *node) JNI_TRUE); } -/***** debugging *****/ - -#ifdef DEBUG +/***** APIs for debugging the debug agent *****/ void eventHandler_dumpAllHandlers(jboolean dumpPermanent) @@ -1892,5 +1943,3 @@ eventHandler_dumpHandler(HandlerNode *node) tty_message("Handler for %s(%d)\n", eventIndex2EventName(node->ei), node->ei); eventFilter_dumpHandlerFilters(node); } - -#endif /* DEBUG */ diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.h b/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.h index 096b1ed795a..7d3684e6aa0 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.h +++ b/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.h @@ -85,12 +85,10 @@ jboolean eventHandler_synthesizeUnloadEvent(char *signature, JNIEnv *env); jclass getMethodClass(jvmtiEnv *jvmti_env, jmethodID method); -/***** debugging *****/ +/***** APIs for debugging the debug agent *****/ -#ifdef DEBUG void eventHandler_dumpAllHandlers(jboolean dumpPermanent); void eventHandler_dumpHandlers(EventIndex ei, jboolean dumpPermanent); void eventHandler_dumpHandler(HandlerNode *node); -#endif #endif /* _EVENTHANDLER_H */ diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c index 220e0040979..7e68e65e56c 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c @@ -137,11 +137,6 @@ typedef struct { static DeferredEventModeList deferredEventModes; -#ifdef DEBUG -static void dumpThreadList(ThreadList *list); -static void dumpThread(ThreadNode *node); -#endif - /* Get the state of the thread direct from JVMTI */ static jvmtiError threadState(jthread thread, jint *pstate) @@ -2561,13 +2556,15 @@ threadControl_allVThreads(jint *numVThreads) return vthreads; } -/***** debugging *****/ +/***** APIs for debugging the debug agent *****/ -#ifdef DEBUG +static void dumpThreadList(ThreadList *list); +static void dumpThread(ThreadNode *node); void threadControl_dumpAllThreads() { + tty_message("suspendAllCount: %d", suspendAllCount); tty_message("Dumping runningThreads:"); dumpThreadList(&runningThreads); tty_message("\nDumping runningVThreads:"); @@ -2652,5 +2649,3 @@ dumpThread(ThreadNode *node) { tty_message("\tobjID: %d", commonRef_refToID(getEnv(), node->thread)); #endif } - -#endif /* DEBUG */ diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.h b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.h index a314ed24bee..b7817d35981 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.h +++ b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.h @@ -76,11 +76,9 @@ jlong threadControl_getFrameGeneration(jthread thread); jthread *threadControl_allVThreads(jint *numVThreads); -/***** debugging *****/ +/***** APIs for debugging the debug agent *****/ -#ifdef DEBUG void threadControl_dumpAllThreads(); void threadControl_dumpThread(jthread thread); -#endif #endif diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/util.c b/src/jdk.jdwp.agent/share/native/libjdwp/util.c index 0bb7c8837d8..7e198be9a46 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/util.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/util.c @@ -1984,8 +1984,6 @@ eventIndex2jvmti(EventIndex ei) return event; } -#ifdef DEBUG - char* eventIndex2EventName(EventIndex ei) { @@ -2040,8 +2038,6 @@ eventIndex2EventName(EventIndex ei) } } -#endif - EventIndex jdwp2EventIndex(jdwpEvent eventType) { diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/util.h b/src/jdk.jdwp.agent/share/native/libjdwp/util.h index c5b8a2b5f51..75281813709 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/util.h +++ b/src/jdk.jdwp.agent/share/native/libjdwp/util.h @@ -90,6 +90,7 @@ typedef struct { jboolean doerrorexit; jboolean modifiedUtf8; jboolean quiet; + jboolean jvmti_data_dump; /* If true, then support JVMTI DATA_DUMP_REQUEST events. */ /* Debug flags (bit mask) */ int debugflags; @@ -389,9 +390,7 @@ void *jvmtiAllocate(jint numBytes); void jvmtiDeallocate(void *buffer); void eventIndexInit(void); -#ifdef DEBUG char* eventIndex2EventName(EventIndex ei); -#endif jdwpEvent eventIndex2jdwp(EventIndex i); jvmtiEvent eventIndex2jvmti(EventIndex i); EventIndex jdwp2EventIndex(jdwpEvent eventType); diff --git a/test/jdk/com/sun/jdi/DataDumpTest.java b/test/jdk/com/sun/jdi/DataDumpTest.java new file mode 100644 index 00000000000..f46d0d5de4f --- /dev/null +++ b/test/jdk/com/sun/jdi/DataDumpTest.java @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; + +import jdk.test.lib.dcmd.PidJcmdExecutor; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +import com.sun.jdi.Bootstrap; +import com.sun.jdi.ClassType; +import com.sun.jdi.VirtualMachine; +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.connect.AttachingConnector; +import com.sun.jdi.connect.Connector; +import com.sun.jdi.connect.IllegalConnectorArgumentsException; +import com.sun.jdi.event.ClassPrepareEvent; +import com.sun.jdi.event.Event; +import com.sun.jdi.event.EventSet; +import com.sun.jdi.request.EventRequest; +import com.sun.jdi.request.ClassPrepareRequest; + +/** + * @test + * @bug 8332488 + * @summary Unit test for testing debug agent support for JVMTI.data_dump jcmd. + * + * @library /test/lib + * @modules jdk.jdi + * @run driver DataDumpTest + */ + +class DataDumpTestTarg { + public static void main(String args[]) throws Exception { + // Write something that can be read by the driver + System.out.println("Debuggee started"); + } +} + +public class DataDumpTest { + + public static void main(String[] args) throws Exception { + System.out.println("Test 1: Debuggee start with datadump=y"); + runTest("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,datadump=y"); + } + + private static void sleep(long ms) { + try { + Thread.sleep(ms); + } catch (InterruptedException e) { + } + } + + private static void runTest(String jdwpArg) throws Exception { + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + jdwpArg, + // Probably not required by this test, but best to include when using datadump + "-XX:+StartAttachListener", + "DataDumpTestTarg"); + Process p = null; + OutputAnalyzer out = null; + try { + p = pb.start(); + InputStream is = p.getInputStream(); + out = new OutputAnalyzer(p); + + // Attach a debugger and do the data dump. The data dump output will appear + // in the debuggee output. + attachAndDump(p.pid()); + + out.waitFor(); // Wait for the debuggee to exit + + System.out.println("Deuggee output:"); + System.out.println(out.getOutput()); + + // All these strings are part of the debug agent data dump output. + out.shouldHaveExitValue(0); + out.shouldContain("Debuggee started"); + out.shouldContain("Debug Agent Data Dump"); + out.shouldContain("suspendAllCount: 0"); + out.shouldContain("ClassMatch: classPattern(DataDumpTestTarg)"); + out.shouldContain("Handlers for EI_VM_DEATH"); + } finally { + if (p != null) { + p.destroyForcibly(); + } + } + } + + private static void attachAndDump(long pid) throws IOException, + IllegalConnectorArgumentsException { + // Get the ProcessAttachingConnector, which can attach using the pid of the debuggee. + AttachingConnector ac = Bootstrap.virtualMachineManager().attachingConnectors() + .stream() + .filter(c -> c.name().equals("com.sun.jdi.ProcessAttach")) + .findFirst() + .orElseThrow(() -> new RuntimeException("Unable to locate ProcessAttachingConnector")); + + // Set the connector's "pid" argument to the pid of the debuggee. + Map args = ac.defaultArguments(); + Connector.StringArgument arg = (Connector.StringArgument)args.get("pid"); + arg.setValue("" + pid); + + // Attach to the debuggee. + System.out.println("Debugger is attaching to: " + pid + " ..."); + VirtualMachine vm = ac.attach(args); + + // List all threads as a sanity check. + System.out.println("Attached! Now listing threads ..."); + vm.allThreads().stream().forEach(System.out::println); + + // Request VM to trigger ClassPrepareRequest when DataDumpTestTarg class is prepared. + ClassPrepareRequest classPrepareRequest = vm.eventRequestManager().createClassPrepareRequest(); + classPrepareRequest.addClassFilter("DataDumpTestTarg"); + // Don't use SUSPEND_ALL here. That might prevent the data dump because the + // Signal Dispatcher and Attach Listener threads will be suspended, and they + // may be needed by the jcmd support. + classPrepareRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); + classPrepareRequest.enable(); + + try { + while (true) { // Exit when we get VMDisconnectedException + EventSet eventSet = vm.eventQueue().remove(); + if (eventSet == null) { + continue; + } + for (Event event : eventSet) { + System.out.println("Received event: " + event); + if (event instanceof ClassPrepareEvent) { + ClassPrepareEvent evt = (ClassPrepareEvent) event; + ClassType classType = (ClassType) evt.referenceType(); + + // Run JVMTI.data_dump jcmd. + OutputAnalyzer out = new PidJcmdExecutor("" + pid).execute("JVMTI.data_dump"); + out.waitFor(); + + // Verify the output of the jcmd. Note the actual dump is in the debuggee + // output, not in the jcmd output, so we don't check it here. + System.out.println("JVMTI.data_dump output:"); + System.out.println(out.getOutput()); + out.shouldContain("Command executed successfully"); + out.shouldHaveExitValue(0); + } + } + eventSet.resume(); + } + } catch (VMDisconnectedException e) { + System.out.println("VM is now disconnected."); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } +} From aff7936ff088249d1fc787a9f9ef687f987f556c Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Wed, 14 Aug 2024 18:42:59 +0000 Subject: [PATCH 418/460] 8338333: Add jls links to javax.lang.model.element.Modifier Reviewed-by: liach, iris, prappo, vromero, jlahoda --- .../javax/lang/model/element/Modifier.java | 106 ++++++++++++++++-- 1 file changed, 94 insertions(+), 12 deletions(-) diff --git a/src/java.compiler/share/classes/javax/lang/model/element/Modifier.java b/src/java.compiler/share/classes/javax/lang/model/element/Modifier.java index 9dcd8390b60..da0195b6cf2 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/Modifier.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/Modifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,25 +51,68 @@ public enum Modifier { // Note java.lang.reflect.Modifier includes INTERFACE, but that's a VMism. - /** The modifier {@code public} */ PUBLIC, - /** The modifier {@code protected} */ PROTECTED, - /** The modifier {@code private} */ PRIVATE, - /** The modifier {@code abstract} */ ABSTRACT, + /** + * The modifier {@code public} + * + * @jls 6.6 Access Control + */ + PUBLIC, + + /** + * The modifier {@code protected} + * + * @jls 6.6 Access Control + */ + PROTECTED, + + /** + * The modifier {@code private} + * + * @jls 6.6 Access Control + */ + PRIVATE, + + /** + * The modifier {@code abstract} + * + * @jls 8.1.1.1 {@code abstract} Classes + * @jls 8.4.3.1 {@code abstract} Methods + * @jls 9.1.1.1 {@code abstract} Interfaces + */ + ABSTRACT, + /** * The modifier {@code default} + * + * @jls 9.4 Method Declarations * @since 1.8 */ DEFAULT, - /** The modifier {@code static} */ STATIC, + + /** + * The modifier {@code static} + * + * @jls 8.1.1.4 {@code static} Classes + * @jls 8.3.1.1 {@code static} Fields + * @jls 8.4.3.2 {@code static} Methods + * @jls 9.1.1.3 {@code static} Interfaces + */ + STATIC, /** * The modifier {@code sealed} + * + * @jls 8.1.1.2 {@code sealed}, {@code non-sealed}, and {@code final} Classes + * @jls 9.1.1.4 {@code sealed} and {@code non-sealed} Interfaces * @since 17 */ SEALED, /** * The modifier {@code non-sealed} + * + * @jls 8.1.1.2 {@code sealed}, {@code non-sealed}, and {@code final} Classes + * @jls 9.1.1.4 {@code sealed} and {@code non-sealed} Interfaces * @since 17 */ NON_SEALED { @@ -77,12 +120,51 @@ public String toString() { return "non-sealed"; } }, - /** The modifier {@code final} */ FINAL, - /** The modifier {@code transient} */ TRANSIENT, - /** The modifier {@code volatile} */ VOLATILE, - /** The modifier {@code synchronized} */ SYNCHRONIZED, - /** The modifier {@code native} */ NATIVE, - /** The modifier {@code strictfp} */ STRICTFP; + /** + * The modifier {@code final} + * + * @jls 8.1.1.2 {@code sealed}, {@code non-sealed}, and {@code final} Classes + * @jls 8.3.1.2 {@code final} Fields + * @jls 8.4.3.3 {@code final} Methods + */ + FINAL, + + /** + * The modifier {@code transient} + * + * @jls 8.3.1.3 {@code transient} Fields + */ + TRANSIENT, + + /** + * The modifier {@code volatile} + * + * @jls 8.3.1.4 {@code volatile} Fields + */ + VOLATILE, + + /** + * The modifier {@code synchronized} + * + * @jls 8.4.3.6 {@code synchronized} Methods + */ + SYNCHRONIZED, + + /** + * The modifier {@code native} + * + * @jls 8.4.3.4 {@code native} Methods + */ + NATIVE, + + /** + * The modifier {@code strictfp} + * + * @jls 8.1.1.3 {@code strictfp} Classes + * @jls 8.4.3.5 {@code strictfp} Methods + * @jls 9.1.1.2 {@code strictfp} Interfaces + */ + STRICTFP; /** * Returns this modifier's name as defined in The From e3a5e265a7747b02b8f828fbedea0dda7246fc51 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Wed, 14 Aug 2024 18:55:58 +0000 Subject: [PATCH 419/460] 8338344: Test TestPrivilegedMode.java intermittent fails java.lang.NoClassDefFoundError: jdk/test/lib/Platform Reviewed-by: chagedorn, shade --- .../jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java index 8c168b73260..feb8fe9e530 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -100,7 +100,7 @@ private void prepareTestVMFlags(List additionalFlags, TestFrameworkSocke String bootClassPath = "-Xbootclasspath/a:."; if (testClassesOnBootClassPath) { // Add test classes themselves to boot classpath to make them privileged. - bootClassPath += File.pathSeparator + Utils.TEST_CLASSES; + bootClassPath += File.pathSeparator + Utils.TEST_CLASS_PATH; } cmds.add(bootClassPath); cmds.add("-XX:+UnlockDiagnosticVMOptions"); From 4669e7b7b02636a8bd7381a9d401aaaf0c1d7294 Mon Sep 17 00:00:00 2001 From: Evgeny Nikitin Date: Thu, 15 Aug 2024 05:36:11 +0000 Subject: [PATCH 420/460] 8337102: JITTester: Fix breaks in static initialization blocks Reviewed-by: kvn, iveresov --- .../jtreg/testlibrary/jittester/conf/default.properties | 2 +- .../factories/StaticConstructorDefinitionFactory.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/hotspot/jtreg/testlibrary/jittester/conf/default.properties b/test/hotspot/jtreg/testlibrary/jittester/conf/default.properties index cd559e59120..4b0bb7bd334 100644 --- a/test/hotspot/jtreg/testlibrary/jittester/conf/default.properties +++ b/test/hotspot/jtreg/testlibrary/jittester/conf/default.properties @@ -8,6 +8,6 @@ classes-file=conf/classes.lst exclude-methods-file=conf/exclude.methods.lst print-complexity=true print-hierarchy=true -disable-static=true +disable-static=false generatorsFactories=jdk.test.lib.jittester.TestGeneratorsFactory generators=JavaCode,ByteCode diff --git a/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/factories/StaticConstructorDefinitionFactory.java b/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/factories/StaticConstructorDefinitionFactory.java index 0a77fbb7d2c..0354559bf67 100644 --- a/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/factories/StaticConstructorDefinitionFactory.java +++ b/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/factories/StaticConstructorDefinitionFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -63,7 +63,7 @@ public StaticConstructorDefinition produce() throws ProductionFailedException { .setOperatorLimit(operatorLimit) .setLevel(level) .setSubBlock(true) - .setCanHaveBreaks(true) + .setCanHaveBreaks(false) .setCanHaveContinues(false) .setCanHaveReturn(false) .getBlockFactory() From 4c344335fe0abc04308f4bfc62c6b3afc110240c Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 15 Aug 2024 07:39:31 +0000 Subject: [PATCH 421/460] 8338304: clang on Linux - check for lld presence after JDK-8333189 Reviewed-by: erikj, ihse --- make/autoconf/flags-ldflags.m4 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/make/autoconf/flags-ldflags.m4 b/make/autoconf/flags-ldflags.m4 index a2d0d4e606a..fab8bec789b 100644 --- a/make/autoconf/flags-ldflags.m4 +++ b/make/autoconf/flags-ldflags.m4 @@ -71,7 +71,9 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER], LDFLAGS_CXX_PARTIAL_LINKING="$MACHINE_FLAG -r" if test "x$OPENJDK_TARGET_OS" = xlinux; then + # Clang needs the lld linker to work correctly BASIC_LDFLAGS="-fuse-ld=lld -Wl,--exclude-libs,ALL" + UTIL_REQUIRE_PROGS(LLD, lld) fi if test "x$OPENJDK_TARGET_OS" = xaix; then BASIC_LDFLAGS="-Wl,-b64 -Wl,-brtl -Wl,-bnorwexec -Wl,-bnolibpath -Wl,-bnoexpall \ From f536f5ab68235d27e9708674f707bcbff7840730 Mon Sep 17 00:00:00 2001 From: Ivan Walulya Date: Thu, 15 Aug 2024 08:26:22 +0000 Subject: [PATCH 422/460] 8336086: G1: Use one G1CardSet instance for all young regions Reviewed-by: tschatzl, ayang --- src/hotspot/share/gc/g1/g1CardSet.cpp | 18 +++++++++- src/hotspot/share/gc/g1/g1CardSet.hpp | 2 ++ src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 9 +++++ src/hotspot/share/gc/g1/g1CollectedHeap.hpp | 12 +++++++ src/hotspot/share/gc/g1/g1CollectionSet.cpp | 2 +- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 12 +++++++ src/hotspot/share/gc/g1/g1ConcurrentMark.hpp | 2 ++ .../share/gc/g1/g1ConcurrentRefine.cpp | 14 ++++---- src/hotspot/share/gc/g1/g1FullCollector.cpp | 3 ++ src/hotspot/share/gc/g1/g1HeapRegion.cpp | 4 +++ src/hotspot/share/gc/g1/g1HeapRegion.hpp | 4 +++ .../share/gc/g1/g1HeapRegion.inline.hpp | 8 +++++ .../share/gc/g1/g1HeapRegionRemSet.cpp | 15 +++++++-- .../share/gc/g1/g1HeapRegionRemSet.hpp | 33 +++++++++++++++---- .../share/gc/g1/g1HeapRegionRemSet.inline.hpp | 22 ++++++++----- src/hotspot/share/gc/g1/g1Policy.cpp | 5 +++ src/hotspot/share/gc/g1/g1Policy.hpp | 2 ++ src/hotspot/share/gc/g1/g1RemSet.cpp | 4 +++ src/hotspot/share/gc/g1/g1RemSetSummary.cpp | 11 ++++++- src/hotspot/share/gc/g1/g1YoungCollector.cpp | 15 ++++++--- .../gc/g1/g1YoungGCPostEvacuateTasks.cpp | 9 ++++- 21 files changed, 173 insertions(+), 33 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CardSet.cpp b/src/hotspot/share/gc/g1/g1CardSet.cpp index 7ab739e0196..5c11a1a9677 100644 --- a/src/hotspot/share/gc/g1/g1CardSet.cpp +++ b/src/hotspot/share/gc/g1/g1CardSet.cpp @@ -244,6 +244,10 @@ class G1CardSetHashTable : public CHeapObj { using CHTScanTask = CardSetHash::ScanTask; const static uint BucketClaimSize = 16; + // The claim size for group cardsets should be smaller to facilitate + // better work distribution. The group cardsets should be larger than + // the per region cardsets. + const static uint GroupBucketClaimSize = 4; // Did we insert at least one card in the table? bool volatile _inserted_card; @@ -347,7 +351,15 @@ class G1CardSetHashTable : public CHeapObj { } void reset_table_scanner() { - _table_scanner.set(&_table, BucketClaimSize); + reset_table_scanner(BucketClaimSize); + } + + void reset_table_scanner_for_groups() { + reset_table_scanner(GroupBucketClaimSize); + } + + void reset_table_scanner(uint claim_size) { + _table_scanner.set(&_table, claim_size); } void grow() { @@ -1042,3 +1054,7 @@ void G1CardSet::clear() { void G1CardSet::reset_table_scanner() { _table->reset_table_scanner(); } + +void G1CardSet::reset_table_scanner_for_groups() { + _table->reset_table_scanner_for_groups(); +} diff --git a/src/hotspot/share/gc/g1/g1CardSet.hpp b/src/hotspot/share/gc/g1/g1CardSet.hpp index a9f1859d5c7..22530ddadaf 100644 --- a/src/hotspot/share/gc/g1/g1CardSet.hpp +++ b/src/hotspot/share/gc/g1/g1CardSet.hpp @@ -380,6 +380,8 @@ class G1CardSet : public CHeapObj { void reset_table_scanner(); + void reset_table_scanner_for_groups(); + // Iterate over the container, calling a method on every card or card range contained // in the card container. // For every container, first calls diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index aa99fbecbee..fd73b725a12 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -1159,6 +1159,8 @@ G1CollectedHeap::G1CollectedHeap() : _rem_set(nullptr), _card_set_config(), _card_set_freelist_pool(G1CardSetConfiguration::num_mem_object_types()), + _young_regions_cardset_mm(card_set_config(), card_set_freelist_pool()), + _young_regions_cardset(card_set_config(), &_young_regions_cardset_mm), _cm(nullptr), _cm_thread(nullptr), _cr(nullptr), @@ -2693,6 +2695,7 @@ bool G1CollectedHeap::is_old_gc_alloc_region(G1HeapRegion* hr) { void G1CollectedHeap::set_region_short_lived_locked(G1HeapRegion* hr) { _eden.add(hr); _policy->set_region_eden(hr); + hr->install_group_cardset(young_regions_cardset()); } #ifdef ASSERT @@ -2902,6 +2905,8 @@ G1HeapRegion* G1CollectedHeap::new_gc_alloc_region(size_t word_size, G1HeapRegio new_alloc_region->set_survivor(); _survivor.add(new_alloc_region); register_new_survivor_region_with_region_attr(new_alloc_region); + // Install the group cardset. + new_alloc_region->install_group_cardset(young_regions_cardset()); } else { new_alloc_region->set_old(); } @@ -3043,3 +3048,7 @@ void G1CollectedHeap::finish_codecache_marking_cycle() { CodeCache::on_gc_marking_cycle_finish(); CodeCache::arm_all_nmethods(); } + +void G1CollectedHeap::prepare_group_cardsets_for_scan () { + _young_regions_cardset.reset_table_scanner_for_groups(); +} diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index ea087aae662..0f8bf9ffd2b 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -779,7 +779,19 @@ class G1CollectedHeap : public CollectedHeap { G1MonotonicArenaFreePool _card_set_freelist_pool; + // Group cardsets + G1CardSetMemoryManager _young_regions_cardset_mm; + G1CardSet _young_regions_cardset; + public: + G1CardSetConfiguration* card_set_config() { return &_card_set_config; } + + G1CardSet* young_regions_cardset() { return &_young_regions_cardset; }; + + G1CardSetMemoryManager* young_regions_card_set_mm() { return &_young_regions_cardset_mm; } + + void prepare_group_cardsets_for_scan(); + // After a collection pause, reset eden and the collection set. void clear_eden(); void clear_collection_set(); diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index fe4dfafee97..d315497268f 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -297,7 +297,7 @@ double G1CollectionSet::finalize_young_part(double target_pause_time_ms, G1Survi verify_young_cset_indices(); - double predicted_base_time_ms = _policy->predict_base_time_ms(pending_cards); + double predicted_base_time_ms = _policy->predict_base_time_ms(pending_cards, _g1h->young_regions_cardset()->occupied()); // Base time already includes the whole remembered set related time, so do not add that here // again. double predicted_eden_time = _policy->predict_young_region_other_time_ms(eden_region_length) + diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index 3d56973299e..52d26418af6 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -2980,6 +2980,7 @@ G1PrintRegionLivenessInfoClosure::G1PrintRegionLivenessInfoClosure(const char* p _total_capacity_bytes(0), _total_live_bytes(0), _total_remset_bytes(0), + _young_cardset_bytes_per_region(0), _total_code_roots_bytes(0) { if (!log_is_enabled(Trace, gc, liveness)) { @@ -2990,6 +2991,13 @@ G1PrintRegionLivenessInfoClosure::G1PrintRegionLivenessInfoClosure(const char* p MemRegion reserved = g1h->reserved(); double now = os::elapsedTime(); + uint num_young_regions = g1h->young_regions_count(); + size_t young_cardset_bytes = g1h->young_regions_cardset()->mem_size(); + + if (num_young_regions > 0) { + _young_cardset_bytes_per_region = young_cardset_bytes / num_young_regions; + } + // Print the header of the output. log_trace(gc, liveness)(G1PPRL_LINE_PREFIX" PHASE %s @ %1.3f", phase_name, now); log_trace(gc, liveness)(G1PPRL_LINE_PREFIX" HEAP" @@ -3041,6 +3049,10 @@ bool G1PrintRegionLivenessInfoClosure::do_heap_region(G1HeapRegion* r) { const char* remset_type = r->rem_set()->get_short_state_str(); FormatBuffer<16> gc_efficiency(""); + if (r->is_young()) { + remset_bytes = _young_cardset_bytes_per_region; + } + _total_used_bytes += used_bytes; _total_capacity_bytes += capacity_bytes; _total_live_bytes += live_bytes; diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp index 918384372bb..b197afc65ee 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp @@ -958,6 +958,8 @@ class G1PrintRegionLivenessInfoClosure : public G1HeapRegionClosure { // Accumulator for the remembered set size size_t _total_remset_bytes; + size_t _young_cardset_bytes_per_region; + // Accumulator for code roots memory size size_t _total_code_roots_bytes; diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp b/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp index 7d6cc9a41cb..8357737ef6a 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp @@ -254,21 +254,18 @@ uint64_t G1ConcurrentRefine::adjust_threads_wait_ms() const { } class G1ConcurrentRefine::RemSetSamplingClosure : public G1HeapRegionClosure { - size_t _sampled_card_rs_length; size_t _sampled_code_root_rs_length; public: RemSetSamplingClosure() : - _sampled_card_rs_length(0), _sampled_code_root_rs_length(0) {} + _sampled_code_root_rs_length(0) {} bool do_heap_region(G1HeapRegion* r) override { G1HeapRegionRemSet* rem_set = r->rem_set(); - _sampled_card_rs_length += rem_set->occupied(); _sampled_code_root_rs_length += rem_set->code_roots_list_length(); return false; } - size_t sampled_card_rs_length() const { return _sampled_card_rs_length; } size_t sampled_code_root_rs_length() const { return _sampled_code_root_rs_length; } }; @@ -286,10 +283,15 @@ class G1ConcurrentRefine::RemSetSamplingClosure : public G1HeapRegionClosure { // gen size to keep pause time length goal. void G1ConcurrentRefine::adjust_young_list_target_length() { if (_policy->use_adaptive_young_list_length()) { + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + G1CollectionSet* cset = g1h->collection_set(); RemSetSamplingClosure cl; - G1CollectionSet* cset = G1CollectedHeap::heap()->collection_set(); cset->iterate(&cl); - _policy->revise_young_list_target_length(cl.sampled_card_rs_length(), cl.sampled_code_root_rs_length()); + + size_t card_rs_length = g1h->young_regions_cardset()->occupied(); + + size_t sampled_code_root_rs_length = cl.sampled_code_root_rs_length(); + _policy->revise_young_list_target_length(card_rs_length, sampled_code_root_rs_length); } } diff --git a/src/hotspot/share/gc/g1/g1FullCollector.cpp b/src/hotspot/share/gc/g1/g1FullCollector.cpp index 219480227d3..4c66c526151 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.cpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.cpp @@ -172,6 +172,7 @@ class PrepareRegionsClosure : public G1HeapRegionClosure { bool do_heap_region(G1HeapRegion* hr) { hr->prepare_for_full_gc(); + hr->uninstall_group_cardset(); G1CollectedHeap::heap()->prepare_region_for_full_compaction(hr); _collector->before_marking_update_attribute_table(hr); return false; @@ -247,6 +248,8 @@ void G1FullCollector::complete_collection() { _heap->resize_all_tlabs(); + _heap->young_regions_cardset()->clear(); + _heap->policy()->record_full_collection_end(); _heap->gc_epilogue(true); diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.cpp b/src/hotspot/share/gc/g1/g1HeapRegion.cpp index 9851b1df9c9..9cb2650f820 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.cpp @@ -119,6 +119,7 @@ void G1HeapRegion::hr_clear(bool clear_space) { clear_young_index_in_cset(); clear_index_in_opt_cset(); uninstall_surv_rate_group(); + uninstall_group_cardset(); set_free(); reset_pre_dummy_top(); @@ -215,6 +216,9 @@ void G1HeapRegion::clear_humongous() { } void G1HeapRegion::prepare_remset_for_scan() { + if (is_young()) { + uninstall_group_cardset(); + } _rem_set->reset_table_scanner(); } diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.hpp b/src/hotspot/share/gc/g1/g1HeapRegion.hpp index ed953094a67..c17183d4034 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.hpp @@ -36,6 +36,7 @@ #include "runtime/mutex.hpp" #include "utilities/macros.hpp" +class G1CardSet; class G1CardSetConfiguration; class G1CollectedHeap; class G1CMBitMap; @@ -508,6 +509,9 @@ class G1HeapRegion : public CHeapObj { void install_surv_rate_group(G1SurvRateGroup* surv_rate_group); void uninstall_surv_rate_group(); + void install_group_cardset(G1CardSet* group_cardset); + void uninstall_group_cardset(); + void record_surv_words_in_group(size_t words_survived); // Determine if an address is in the parsable or the to-be-scrubbed area. diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp b/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp index f31c5fb553e..4a87c5f2514 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp @@ -511,4 +511,12 @@ inline void G1HeapRegion::add_pinned_object_count(size_t value) { Atomic::add(&_pinned_object_count, value, memory_order_relaxed); } +inline void G1HeapRegion::install_group_cardset(G1CardSet* group_cardset) { + _rem_set->install_group_cardset(group_cardset); +} + +inline void G1HeapRegion::uninstall_group_cardset() { + _rem_set->uninstall_group_cardset(); +} + #endif // SHARE_GC_G1_G1HEAPREGION_INLINE_HPP diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp index 6e98b64adbc..fe1590b94a8 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp @@ -55,11 +55,19 @@ void G1HeapRegionRemSet::initialize(MemRegion reserved) { _heap_base_address = reserved.start(); } +void G1HeapRegionRemSet::uninstall_group_cardset() { + if (_saved_card_set != nullptr) { + _card_set = _saved_card_set; + _saved_card_set = nullptr; + } +} + G1HeapRegionRemSet::G1HeapRegionRemSet(G1HeapRegion* hr, G1CardSetConfiguration* config) : _code_roots(), _card_set_mm(config, G1CollectedHeap::heap()->card_set_freelist_pool()), - _card_set(config, &_card_set_mm), + _card_set(new G1CardSet(config, &_card_set_mm)), + _saved_card_set(nullptr), _hr(hr), _state(Untracked) { } @@ -68,11 +76,12 @@ void G1HeapRegionRemSet::clear_fcc() { } void G1HeapRegionRemSet::clear(bool only_cardset, bool keep_tracked) { + assert(_saved_card_set == nullptr, "pre-condition"); if (!only_cardset) { _code_roots.clear(); } clear_fcc(); - _card_set.clear(); + _card_set->clear(); if (!keep_tracked) { set_state_untracked(); } else { @@ -83,7 +92,7 @@ void G1HeapRegionRemSet::clear(bool only_cardset, bool keep_tracked) { void G1HeapRegionRemSet::reset_table_scanner() { _code_roots.reset_table_scanner(); - _card_set.reset_table_scanner(); + _card_set->reset_table_scanner(); } G1MonotonicArenaMemoryStats G1HeapRegionRemSet::card_set_memory_stats() const { diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp index e92ecdc9cf9..843eb76bbc9 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp @@ -47,7 +47,8 @@ class G1HeapRegionRemSet : public CHeapObj { G1CardSetMemoryManager _card_set_mm; // The set of cards in the Java heap - G1CardSet _card_set; + G1CardSet* _card_set; + G1CardSet* _saved_card_set; G1HeapRegion* _hr; @@ -58,9 +59,24 @@ class G1HeapRegionRemSet : public CHeapObj { public: G1HeapRegionRemSet(G1HeapRegion* hr, G1CardSetConfiguration* config); + ~G1HeapRegionRemSet() { delete _card_set; } bool cardset_is_empty() const { - return _card_set.is_empty(); + return _card_set->is_empty(); + } + + void install_group_cardset(G1CardSet* group_cardset) { + assert(group_cardset != nullptr, "pre-condition"); + assert(_saved_card_set == nullptr, "pre-condition"); + + _saved_card_set = _card_set; + _card_set = group_cardset; + } + + void uninstall_group_cardset(); + + bool has_group_cardset() { + return _saved_card_set != nullptr; } bool is_empty() const { @@ -68,7 +84,7 @@ class G1HeapRegionRemSet : public CHeapObj { } bool occupancy_less_or_equal_than(size_t occ) const { - return (code_roots_list_length() == 0) && _card_set.occupancy_less_or_equal_to(occ); + return (code_roots_list_length() == 0) && _card_set->occupancy_less_or_equal_to(occ); } // Iterate the card based remembered set for merging them into the card table. @@ -77,10 +93,15 @@ class G1HeapRegionRemSet : public CHeapObj { template inline void iterate_for_merge(CardOrRangeVisitor& cl); + template + inline static void iterate_for_merge(G1CardSet* card_set, CardOrRangeVisitor& cl); + size_t occupied() { - return _card_set.occupied(); + return _card_set->occupied(); } + G1CardSet* card_set() { return _card_set; } + static void initialize(MemRegion reserved); // Coarsening statistics since VM start. @@ -125,13 +146,13 @@ class G1HeapRegionRemSet : public CHeapObj { // The actual # of bytes this hr_remset takes up. Also includes the code // root set. size_t mem_size() { - return _card_set.mem_size() + return _card_set->mem_size() + (sizeof(G1HeapRegionRemSet) - sizeof(G1CardSet)) // Avoid double-counting G1CardSet. + code_roots_mem_size(); } size_t unused_mem_size() { - return _card_set.unused_mem_size(); + return _card_set->unused_mem_size(); } // Returns the memory occupancy of all static data structures associated diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp index 457027ad126..0df9874e9dd 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp @@ -108,13 +108,17 @@ class G1HeapRegionRemSetMergeCardClosure : public G1CardSet::ContainerPtrClosure template inline void G1HeapRegionRemSet::iterate_for_merge(CardOrRangeVisitor& cl) { - G1HeapRegionRemSetMergeCardClosure cl2(&_card_set, - cl, - _card_set.config()->log2_card_regions_per_heap_region(), - _card_set.config()->log2_cards_per_card_region()); - _card_set.iterate_containers(&cl2, true /* at_safepoint */); + iterate_for_merge(_card_set, cl); } +template +void G1HeapRegionRemSet::iterate_for_merge(G1CardSet* card_set, CardOrRangeVisitor& cl) { + G1HeapRegionRemSetMergeCardClosure cl2(card_set, + cl, + card_set->config()->log2_card_regions_per_heap_region(), + card_set->config()->log2_cards_per_card_region()); + card_set->iterate_containers(&cl2, true /* at_safepoint */); +} uintptr_t G1HeapRegionRemSet::to_card(OopOrNarrowOopStar from) const { return pointer_delta(from, _heap_base_address, 1) >> CardTable::card_shift(); @@ -130,18 +134,18 @@ void G1HeapRegionRemSet::add_reference(OopOrNarrowOopStar from, uint tid) { // We can't check whether the card is in the remembered set - the card container // may be coarsened just now. //assert(contains_reference(from), "We just found " PTR_FORMAT " in the FromCardCache", p2i(from)); - return; + return; } - _card_set.add_card(to_card(from)); + _card_set->add_card(to_card(from)); } bool G1HeapRegionRemSet::contains_reference(OopOrNarrowOopStar from) { - return _card_set.contains_card(to_card(from)); + return _card_set->contains_card(to_card(from)); } void G1HeapRegionRemSet::print_info(outputStream* st, OopOrNarrowOopStar from) { - _card_set.print_info(st, to_card(from)); + _card_set->print_info(st, to_card(from)); } #endif // SHARE_VM_GC_G1_G1HEAPREGIONREMSET_INLINE_HPP diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index 7d0acd3a326..e7e57c962c7 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -1089,6 +1089,11 @@ double G1Policy::predict_base_time_ms(size_t pending_cards, double G1Policy::predict_base_time_ms(size_t pending_cards) const { bool for_young_only_phase = collector_state()->in_young_only_phase(); size_t card_rs_length = _analytics->predict_card_rs_length(for_young_only_phase); + return predict_base_time_ms(pending_cards, card_rs_length); +} + +double G1Policy::predict_base_time_ms(size_t pending_cards, size_t card_rs_length) const { + bool for_young_only_phase = collector_state()->in_young_only_phase(); size_t code_root_rs_length = _analytics->predict_code_root_rs_length(for_young_only_phase); return predict_base_time_ms(pending_cards, card_rs_length, code_root_rs_length); } diff --git a/src/hotspot/share/gc/g1/g1Policy.hpp b/src/hotspot/share/gc/g1/g1Policy.hpp index 9de27e76d96..98d44408467 100644 --- a/src/hotspot/share/gc/g1/g1Policy.hpp +++ b/src/hotspot/share/gc/g1/g1Policy.hpp @@ -138,6 +138,8 @@ class G1Policy: public CHeapObj { double predict_base_time_ms(size_t pending_cards) const; + double predict_base_time_ms(size_t pending_cards, size_t card_rs_length) const; + private: // Base time contains handling remembered sets and constant other time of the // whole young gen, refinement buffers, and copying survivors. diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp index 0f9b9d17df7..f5f65cf1c48 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.cpp +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp @@ -1379,6 +1379,10 @@ class G1MergeHeapRootsTask : public WorkerTask { G1ClearBitmapClosure clear(g1h); G1CombinedClosure combined(&merge, &clear); + if (_initial_evacuation) { + G1HeapRegionRemSet::iterate_for_merge(g1h->young_regions_cardset(), merge); + } + g1h->collection_set_iterate_increment_from(&combined, nullptr, worker_id); G1MergeCardSetStats stats = merge.stats(); diff --git a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp index 14fb8c0b8d2..5ea3500a7b0 100644 --- a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp +++ b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp @@ -218,15 +218,24 @@ class HRRSStatsIter: public G1HeapRegionClosure { bool do_heap_region(G1HeapRegion* r) { G1HeapRegionRemSet* hrrs = r->rem_set(); + size_t occupied_cards = hrrs->occupied(); // G1HeapRegionRemSet::mem_size() includes the // size of the code roots size_t rs_unused_mem_sz = hrrs->unused_mem_size(); size_t rs_mem_sz = hrrs->mem_size(); + + if (r->is_young()) { + uint num_young = G1CollectedHeap::heap()->young_regions_count(); + occupied_cards /= num_young; + rs_unused_mem_sz /= num_young; + rs_mem_sz /= num_young; + } + if (rs_mem_sz > _max_rs_mem_sz) { _max_rs_mem_sz = rs_mem_sz; _max_rs_mem_sz_region = r; } - size_t occupied_cards = hrrs->occupied(); + size_t code_root_mem_sz = hrrs->code_roots_mem_size(); if (code_root_mem_sz > max_code_root_mem_sz()) { _max_code_root_mem_sz = code_root_mem_sz; diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.cpp b/src/hotspot/share/gc/g1/g1YoungCollector.cpp index cadab2fbc48..f2fe93015c5 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.cpp @@ -295,10 +295,9 @@ class G1PrepareEvacuationTask : public WorkerTask { G1MonotonicArenaMemoryStats _card_set_stats; void sample_card_set_size(G1HeapRegion* hr) { - // Sample card set sizes for young gen and humongous before GC: this makes - // the policy to give back memory to the OS keep the most recent amount of - // memory for these regions. - if (hr->is_young() || hr->is_starts_humongous()) { + // Sample card set sizes for humongous before GC: this makes the policy to give + // back memory to the OS keep the most recent amount of memory for these regions. + if (hr->is_starts_humongous()) { _card_set_stats.add(hr->rem_set()->card_set_memory_stats()); } } @@ -507,6 +506,9 @@ void G1YoungCollector::pre_evacuate_collection_set(G1EvacInfo* evacuation_info) { Ticks start = Ticks::now(); rem_set()->prepare_for_scan_heap_roots(); + + _g1h->prepare_group_cardsets_for_scan(); + phase_times()->record_prepare_heap_roots_time_ms((Ticks::now() - start).seconds() * 1000.0); } @@ -514,7 +516,10 @@ void G1YoungCollector::pre_evacuate_collection_set(G1EvacInfo* evacuation_info) G1PrepareEvacuationTask g1_prep_task(_g1h); Tickspan task_time = run_task_timed(&g1_prep_task); - _g1h->set_young_gen_card_set_stats(g1_prep_task.all_card_set_stats()); + G1MonotonicArenaMemoryStats sampled_card_set_stats = g1_prep_task.all_card_set_stats(); + sampled_card_set_stats.add(_g1h->young_regions_card_set_mm()->memory_stats()); + _g1h->set_young_gen_card_set_stats(sampled_card_set_stats); + _g1h->set_humongous_stats(g1_prep_task.humongous_total(), g1_prep_task.humongous_candidates()); phase_times()->record_register_regions(task_time.seconds() * 1000.0); diff --git a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp index e1f0df05c22..a0e9a9b1569 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp @@ -673,6 +673,10 @@ class FreeCSetStats { G1Policy *policy = g1h->policy(); policy->old_gen_alloc_tracker()->add_allocated_bytes_since_last_gc(_bytes_allocated_in_old_since_last_gc); + + // Add the cards from the group cardsets. + _card_rs_length += g1h->young_regions_cardset()->occupied(); + policy->record_card_rs_length(_card_rs_length); policy->cset_regions_freed(); } @@ -822,9 +826,10 @@ class FreeCSetClosure : public G1HeapRegionClosure { JFREventForRegion event(r, _worker_id); TimerForRegion timer(timer_for_region(r)); - stats()->account_card_rs_length(r); if (r->is_young()) { + // We only use card_rs_length statistics to estimate young regions length. + stats()->account_card_rs_length(r); assert_tracks_surviving_words(r); r->record_surv_words_in_group(_surviving_young_words[r->young_index_in_cset()]); } @@ -911,6 +916,8 @@ class G1PostEvacuateCollectionSetCleanupTask2::FreeCollectionSetTask : public G1 p->record_serial_free_cset_time_ms((Ticks::now() - serial_time).seconds() * 1000.0); _g1h->clear_collection_set(); + + _g1h->young_regions_cardset()->clear(); } double worker_cost() const override { return G1CollectedHeap::heap()->collection_set()->region_length(); } From da7311bbe37c2b9632b117d52a77c659047820b7 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Thu, 15 Aug 2024 08:50:29 +0000 Subject: [PATCH 423/460] 8338286: GHA: Demote x86_32 to hotspot build only Reviewed-by: ihse --- .github/workflows/main.yml | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6a1b4420e3a..1dc0b25c345 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -36,7 +36,7 @@ on: platforms: description: 'Platform(s) to execute on (comma separated, e.g. "linux-x64, macos, aarch64")' required: true - default: 'linux-x64, linux-x86, linux-x64-variants, linux-cross-compile, macos-x64, macos-aarch64, windows-x64, windows-aarch64, docs' + default: 'linux-x64, linux-x86-hs, linux-x64-variants, linux-cross-compile, macos-x64, macos-aarch64, windows-x64, windows-aarch64, docs' configure-arguments: description: 'Additional configure arguments' required: false @@ -59,7 +59,7 @@ jobs: runs-on: ubuntu-22.04 outputs: linux-x64: ${{ steps.include.outputs.linux-x64 }} - linux-x86: ${{ steps.include.outputs.linux-x86 }} + linux-x86-hs: ${{ steps.include.outputs.linux-x86-hs }} linux-x64-variants: ${{ steps.include.outputs.linux-x64-variants }} linux-cross-compile: ${{ steps.include.outputs.linux-cross-compile }} macos-x64: ${{ steps.include.outputs.macos-x64 }} @@ -111,7 +111,7 @@ jobs: } echo "linux-x64=$(check_platform linux-x64 linux x64)" >> $GITHUB_OUTPUT - echo "linux-x86=$(check_platform linux-x86 linux x86)" >> $GITHUB_OUTPUT + echo "linux-x86-hs=$(check_platform linux-x86-hs linux x86)" >> $GITHUB_OUTPUT echo "linux-x64-variants=$(check_platform linux-x64-variants variants)" >> $GITHUB_OUTPUT echo "linux-cross-compile=$(check_platform linux-cross-compile cross-compile)" >> $GITHUB_OUTPUT echo "macos-x64=$(check_platform macos-x64 macos x64)" >> $GITHUB_OUTPUT @@ -135,12 +135,13 @@ jobs: make-arguments: ${{ github.event.inputs.make-arguments }} if: needs.select.outputs.linux-x64 == 'true' - build-linux-x86: - name: linux-x86 + build-linux-x86-hs: + name: linux-x86-hs needs: select uses: ./.github/workflows/build-linux.yml with: platform: linux-x86 + make-target: 'hotspot' gcc-major-version: '10' gcc-package-suffix: '-multilib' apt-architecture: 'i386' @@ -150,7 +151,7 @@ jobs: extra-conf-options: '--with-target-bits=32 --enable-fallback-linker --enable-libffi-bundling' configure-arguments: ${{ github.event.inputs.configure-arguments }} make-arguments: ${{ github.event.inputs.make-arguments }} - if: needs.select.outputs.linux-x86 == 'true' + if: needs.select.outputs.linux-x86-hs == 'true' build-linux-x64-hs-nopch: name: linux-x64-hs-nopch @@ -300,16 +301,6 @@ jobs: bootjdk-platform: linux-x64 runs-on: ubuntu-22.04 - test-linux-x86: - name: linux-x86 - needs: - - build-linux-x86 - uses: ./.github/workflows/test.yml - with: - platform: linux-x86 - bootjdk-platform: linux-x64 - runs-on: ubuntu-22.04 - test-macos-x64: name: macos-x64 needs: @@ -347,7 +338,7 @@ jobs: if: always() needs: - build-linux-x64 - - build-linux-x86 + - build-linux-x86-hs - build-linux-x64-hs-nopch - build-linux-x64-hs-zero - build-linux-x64-hs-minimal @@ -358,7 +349,6 @@ jobs: - build-windows-x64 - build-windows-aarch64 - test-linux-x64 - - test-linux-x86 - test-macos-x64 - test-windows-x64 From 74fdd6868d3f71d44ef9f71a0ca9506c04d39148 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Thu, 15 Aug 2024 11:24:22 +0000 Subject: [PATCH 424/460] 8333791: Fix memory barriers for @Stable fields Reviewed-by: liach, vlivanov --- src/hotspot/share/c1/c1_GraphBuilder.cpp | 12 +- src/hotspot/share/c1/c1_IR.cpp | 1 + src/hotspot/share/c1/c1_IR.hpp | 3 + src/hotspot/share/opto/parse.hpp | 10 +- src/hotspot/share/opto/parse1.cpp | 29 +-- src/hotspot/share/opto/parse3.cpp | 21 +- .../irTests/stable/StablePrimArrayTest.java | 170 +++++++++++++++++ .../irTests/stable/StablePrimFinalTest.java | 100 ++++++++++ .../irTests/stable/StablePrimPlainTest.java | 114 +++++++++++ .../stable/StablePrimVolatileTest.java | 114 +++++++++++ .../c2/irTests/stable/StableRefArrayTest.java | 179 ++++++++++++++++++ .../c2/irTests/stable/StableRefFinalTest.java | 97 ++++++++++ .../c2/irTests/stable/StableRefPlainTest.java | 118 ++++++++++++ .../irTests/stable/StableRefVolatileTest.java | 118 ++++++++++++ 14 files changed, 1047 insertions(+), 39 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimArrayTest.java create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimFinalTest.java create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimPlainTest.java create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimVolatileTest.java create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefArrayTest.java create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefFinalTest.java create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefPlainTest.java create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefVolatileTest.java diff --git a/src/hotspot/share/c1/c1_GraphBuilder.cpp b/src/hotspot/share/c1/c1_GraphBuilder.cpp index 0493b0458cd..780ced7f433 100644 --- a/src/hotspot/share/c1/c1_GraphBuilder.cpp +++ b/src/hotspot/share/c1/c1_GraphBuilder.cpp @@ -1563,7 +1563,7 @@ void GraphBuilder::method_return(Value x, bool ignore_return) { // The conditions for a memory barrier are described in Parse::do_exits(). bool need_mem_bar = false; if (method()->name() == ciSymbols::object_initializer_name() && - (scope()->wrote_final() || + (scope()->wrote_final() || scope()->wrote_stable() || (AlwaysSafeConstructors && scope()->wrote_fields()) || (support_IRIW_for_not_multiple_copy_atomic_cpu && scope()->wrote_volatile()))) { need_mem_bar = true; @@ -1741,15 +1741,17 @@ void GraphBuilder::access_field(Bytecodes::Code code) { } } - if (field->is_final() && (code == Bytecodes::_putfield)) { - scope()->set_wrote_final(); - } - if (code == Bytecodes::_putfield) { scope()->set_wrote_fields(); if (field->is_volatile()) { scope()->set_wrote_volatile(); } + if (field->is_final()) { + scope()->set_wrote_final(); + } + if (field->is_stable()) { + scope()->set_wrote_stable(); + } } const int offset = !needs_patching ? field->offset_in_bytes() : -1; diff --git a/src/hotspot/share/c1/c1_IR.cpp b/src/hotspot/share/c1/c1_IR.cpp index e375d16aafb..b3faa54cc69 100644 --- a/src/hotspot/share/c1/c1_IR.cpp +++ b/src/hotspot/share/c1/c1_IR.cpp @@ -146,6 +146,7 @@ IRScope::IRScope(Compilation* compilation, IRScope* caller, int caller_bci, ciMe _wrote_final = false; _wrote_fields = false; _wrote_volatile = false; + _wrote_stable = false; _start = nullptr; if (osr_bci != -1) { diff --git a/src/hotspot/share/c1/c1_IR.hpp b/src/hotspot/share/c1/c1_IR.hpp index 3035643708a..e2582c77b39 100644 --- a/src/hotspot/share/c1/c1_IR.hpp +++ b/src/hotspot/share/c1/c1_IR.hpp @@ -149,6 +149,7 @@ class IRScope: public CompilationResourceObj { bool _wrote_final; // has written final field bool _wrote_fields; // has written fields bool _wrote_volatile; // has written volatile field + bool _wrote_stable; // has written @Stable field BlockBegin* _start; // the start block, successsors are method entries ResourceBitMap _requires_phi_function; // bit is set if phi functions at loop headers are necessary for a local variable @@ -187,6 +188,8 @@ class IRScope: public CompilationResourceObj { bool wrote_fields () const { return _wrote_fields; } void set_wrote_volatile() { _wrote_volatile = true; } bool wrote_volatile () const { return _wrote_volatile; } + void set_wrote_stable() { _wrote_stable = true; } + bool wrote_stable() const { return _wrote_stable; } }; diff --git a/src/hotspot/share/opto/parse.hpp b/src/hotspot/share/opto/parse.hpp index a55c9cb0cb1..a2690aa6704 100644 --- a/src/hotspot/share/opto/parse.hpp +++ b/src/hotspot/share/opto/parse.hpp @@ -358,7 +358,7 @@ class Parse : public GraphKit { bool _wrote_volatile; // Did we write a volatile field? bool _wrote_stable; // Did we write a @Stable field? bool _wrote_fields; // Did we write any field? - Node* _alloc_with_final; // An allocation node with final field + Node* _alloc_with_final_or_stable; // An allocation node with final or @Stable field // Variables which track Java semantics during bytecode parsing: @@ -403,10 +403,10 @@ class Parse : public GraphKit { void set_wrote_stable(bool z) { _wrote_stable = z; } bool wrote_fields() const { return _wrote_fields; } void set_wrote_fields(bool z) { _wrote_fields = z; } - Node* alloc_with_final() const { return _alloc_with_final; } - void set_alloc_with_final(Node* n) { - assert((_alloc_with_final == nullptr) || (_alloc_with_final == n), "different init objects?"); - _alloc_with_final = n; + Node* alloc_with_final_or_stable() const { return _alloc_with_final_or_stable; } + void set_alloc_with_final_or_stable(Node* n) { + assert((_alloc_with_final_or_stable == nullptr) || (_alloc_with_final_or_stable == n), "different init objects?"); + _alloc_with_final_or_stable = n; } Block* block() const { return _block; } diff --git a/src/hotspot/share/opto/parse1.cpp b/src/hotspot/share/opto/parse1.cpp index 14ef93a5eed..05627450585 100644 --- a/src/hotspot/share/opto/parse1.cpp +++ b/src/hotspot/share/opto/parse1.cpp @@ -412,7 +412,7 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses) _wrote_volatile = false; _wrote_stable = false; _wrote_fields = false; - _alloc_with_final = nullptr; + _alloc_with_final_or_stable = nullptr; _block = nullptr; _first_return = true; _replaced_nodes_for_exceptions = false; @@ -988,8 +988,8 @@ void Parse::do_exits() { // Figure out if we need to emit the trailing barrier. The barrier is only // needed in the constructors, and only in three cases: // - // 1. The constructor wrote a final. The effects of all initializations - // must be committed to memory before any code after the constructor + // 1. The constructor wrote a final or a @Stable field. All these + // initializations must be ordered before any code after the constructor // publishes the reference to the newly constructed object. Rather // than wait for the publication, we simply block the writes here. // Rather than put a barrier on only those writes which are required @@ -1014,34 +1014,23 @@ void Parse::do_exits() { // exceptional returns, since they cannot publish normally. // if (method()->is_object_initializer() && - (wrote_final() || + (wrote_final() || wrote_stable() || (AlwaysSafeConstructors && wrote_fields()) || (support_IRIW_for_not_multiple_copy_atomic_cpu && wrote_volatile()))) { + Node* recorded_alloc = alloc_with_final_or_stable(); _exits.insert_mem_bar(UseStoreStoreForCtor ? Op_MemBarStoreStore : Op_MemBarRelease, - alloc_with_final()); + recorded_alloc); // If Memory barrier is created for final fields write // and allocation node does not escape the initialize method, // then barrier introduced by allocation node can be removed. - if (DoEscapeAnalysis && alloc_with_final()) { - AllocateNode* alloc = AllocateNode::Ideal_allocation(alloc_with_final()); + if (DoEscapeAnalysis && (recorded_alloc != nullptr)) { + AllocateNode* alloc = AllocateNode::Ideal_allocation(recorded_alloc); alloc->compute_MemBar_redundancy(method()); } if (PrintOpto && (Verbose || WizardMode)) { method()->print_name(); - tty->print_cr(" writes finals and needs a memory barrier"); - } - } - - // Any method can write a @Stable field; insert memory barriers - // after those also. Can't bind predecessor allocation node (if any) - // with barrier because allocation doesn't always dominate - // MemBarRelease. - if (wrote_stable()) { - _exits.insert_mem_bar(Op_MemBarRelease); - if (PrintOpto && (Verbose || WizardMode)) { - method()->print_name(); - tty->print_cr(" writes @Stable and needs a memory barrier"); + tty->print_cr(" writes finals/@Stable and needs a memory barrier"); } } diff --git a/src/hotspot/share/opto/parse3.cpp b/src/hotspot/share/opto/parse3.cpp index a2bf653b176..a9fad4e3633 100644 --- a/src/hotspot/share/opto/parse3.cpp +++ b/src/hotspot/share/opto/parse3.cpp @@ -236,22 +236,25 @@ void Parse::do_put_xxx(Node* obj, ciField* field, bool is_field) { set_wrote_fields(true); // If the field is final, the rules of Java say we are in or . - // Note the presence of writes to final non-static fields, so that we + // If the field is @Stable, we can be in any method, but we only care about + // constructors at this point. + // + // Note the presence of writes to final/@Stable non-static fields, so that we // can insert a memory barrier later on to keep the writes from floating // out of the constructor. - // Any method can write a @Stable field; insert memory barriers after those also. - if (field->is_final()) { - set_wrote_final(true); + if (field->is_final() || field->is_stable()) { + if (field->is_final()) { + set_wrote_final(true); + } + if (field->is_stable()) { + set_wrote_stable(true); + } if (AllocateNode::Ideal_allocation(obj) != nullptr) { // Preserve allocation ptr to create precedent edge to it in membar // generated on exit from constructor. - // Can't bind stable with its allocation, only record allocation for final field. - set_alloc_with_final(obj); + set_alloc_with_final_or_stable(obj); } } - if (field->is_stable()) { - set_wrote_stable(true); - } } } diff --git a/test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimArrayTest.java b/test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimArrayTest.java new file mode 100644 index 00000000000..24733700f81 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimArrayTest.java @@ -0,0 +1,170 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8333791 + * @requires os.arch=="aarch64" | os.arch=="riscv64" | os.arch=="x86_64" | os.arch=="amd64" + * @requires vm.gc.Parallel + * @requires vm.compiler2.enabled + * @summary Check stable field folding and barriers + * @modules java.base/jdk.internal.vm.annotation + * @library /test/lib / + * @run driver compiler.c2.irTests.stable.StablePrimArrayTest + */ + +package compiler.c2.irTests.stable; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; + +import jdk.internal.vm.annotation.Stable; + +public class StablePrimArrayTest { + + public static void main(String[] args) { + TestFramework tf = new TestFramework(); + tf.addTestClassesToBootClassPath(); + tf.addFlags( + "-XX:+UnlockExperimentalVMOptions", + "-XX:CompileThreshold=100", + "-XX:-TieredCompilation", + "-XX:+UseParallelGC" + ); + tf.start(); + } + + static final int[] EMPTY_INTEGER = new int[] { 0 }; + static final int[] FULL_INTEGER = new int[] { 42 }; + + static class Carrier { + @Stable + int[] field; + + @ForceInline + public Carrier(int initLevel) { + switch (initLevel) { + case 0: + // Do nothing. + break; + case 1: + field = EMPTY_INTEGER; + break; + case 2: + field = FULL_INTEGER; + break; + default: + throw new IllegalStateException("Unknown level"); + } + } + + @ForceInline + public void initEmpty() { + field = EMPTY_INTEGER; + } + + @ForceInline + public void initFull() { + field = FULL_INTEGER; + } + + } + + static final Carrier BLANK_CARRIER = new Carrier(0); + static final Carrier INIT_EMPTY_CARRIER = new Carrier(1); + static final Carrier INIT_FULL_CARRIER = new Carrier(2); + + @Test + @IR(counts = { IRNode.LOAD, ">0" }) + @IR(failOn = { IRNode.MEMBAR }) + static int testNoFold() { + // Access should not be folded. + // No barriers expected for plain fields. + int[] is = BLANK_CARRIER.field; + if (is != null) { + return is[0]; + } + return 0; + } + + @Test + @IR(counts = { IRNode.LOAD, ">0" }) + @IR(failOn = { IRNode.MEMBAR }) + static int testPartialFold() { + // Access should not be folded. + // No barriers expected for plain fields. + int[] is = INIT_EMPTY_CARRIER.field; + if (is != null) { + return is[0]; + } + return 0; + } + + + @Test + @IR(failOn = { IRNode.LOAD, IRNode.MEMBAR }) + static int testFold() { + // Access should be completely folded. + int[] is = INIT_FULL_CARRIER.field; + if (is != null) { + return is[0]; + } + return 0; + } + + @Test + @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" }) + static Carrier testConstructorBlankInit() { + // Only the header barrier. + return new Carrier(0); + } + + @Test + @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" }) + static Carrier testConstructorEmptyInit() { + // Only the header barrier. + return new Carrier(1); + } + + @Test + @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" }) + static Carrier testConstructorFullInit() { + // Only the header barrier. + return new Carrier(2); + } + + @Test + @IR(failOn = { IRNode.MEMBAR }) + static void testMethodEmptyInit() { + // Reference inits do not have membars. + INIT_EMPTY_CARRIER.initEmpty(); + } + + @Test + @IR(failOn = { IRNode.MEMBAR }) + static void testMethodFullInit() { + // Reference inits do not have membars. + INIT_FULL_CARRIER.initFull(); + } + +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimFinalTest.java b/test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimFinalTest.java new file mode 100644 index 00000000000..355fadf6cc1 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimFinalTest.java @@ -0,0 +1,100 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8333791 + * @requires os.arch=="aarch64" | os.arch=="riscv64" | os.arch=="x86_64" | os.arch=="amd64" + * @requires vm.gc.Parallel + * @requires vm.compiler2.enabled + * @summary Check stable field folding and barriers + * @modules java.base/jdk.internal.vm.annotation + * @library /test/lib / + * @run driver compiler.c2.irTests.stable.StablePrimFinalTest + */ + +package compiler.c2.irTests.stable; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; + +import jdk.internal.vm.annotation.Stable; + +public class StablePrimFinalTest { + + public static void main(String[] args) { + TestFramework tf = new TestFramework(); + tf.addTestClassesToBootClassPath(); + tf.addFlags( + "-XX:+UnlockExperimentalVMOptions", + "-XX:CompileThreshold=100", + "-XX:-TieredCompilation", + "-XX:+UseParallelGC" + ); + tf.start(); + } + + static class Carrier { + @Stable + final int field; + + @ForceInline + public Carrier(boolean init) { + field = init ? 42 : 0; + } + } + + static final Carrier BLANK_CARRIER = new Carrier(false); + static final Carrier INIT_CARRIER = new Carrier(true); + + @Test + @IR(counts = { IRNode.LOAD, "1" }) + @IR(failOn = { IRNode.MEMBAR }) + static int testNoFold() { + // Access should not be folded. + // No barriers expected for final fields. + return BLANK_CARRIER.field; + } + + @Test + @IR(failOn = { IRNode.LOAD, IRNode.MEMBAR }) + static int testFold() { + // Access should be completely folded. + return INIT_CARRIER.field; + } + + @Test + @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" }) + static Carrier testConstructorBlankInit() { + // Single header+final barrier. + return new Carrier(false); + } + + @Test + @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" }) + static Carrier testConstructorFullInit() { + // Single header+final barrier. + return new Carrier(true); + } + +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimPlainTest.java b/test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimPlainTest.java new file mode 100644 index 00000000000..38cc8bfad4e --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimPlainTest.java @@ -0,0 +1,114 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8333791 + * @requires os.arch=="aarch64" | os.arch=="riscv64" | os.arch=="x86_64" | os.arch=="amd64" + * @requires vm.gc.Parallel + * @requires vm.compiler2.enabled + * @summary Check stable field folding and barriers + * @modules java.base/jdk.internal.vm.annotation + * @library /test/lib / + * @run driver compiler.c2.irTests.stable.StablePrimPlainTest + */ + +package compiler.c2.irTests.stable; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; + +import jdk.internal.vm.annotation.Stable; + +public class StablePrimPlainTest { + + public static void main(String[] args) { + TestFramework tf = new TestFramework(); + tf.addTestClassesToBootClassPath(); + tf.addFlags( + "-XX:+UnlockExperimentalVMOptions", + "-XX:CompileThreshold=100", + "-XX:-TieredCompilation", + "-XX:+UseParallelGC" + ); + tf.start(); + } + + static class Carrier { + @Stable + int field; + + @ForceInline + public Carrier(boolean init) { + if (init) { + field = 42; + } + } + + @ForceInline + public void init() { + field = 42; + } + } + + static final Carrier BLANK_CARRIER = new Carrier(false); + static final Carrier INIT_CARRIER = new Carrier(true); + + @Test + @IR(counts = { IRNode.LOAD, "1" }) + @IR(failOn = { IRNode.MEMBAR }) + static int testNoFold() { + // Access should not be folded. + // No barriers expected for plain fields. + return BLANK_CARRIER.field; + } + + @Test + @IR(failOn = { IRNode.LOAD, IRNode.MEMBAR }) + static int testFold() { + // Access should be completely folded. + return INIT_CARRIER.field; + } + + @Test + @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" }) + static Carrier testConstructorBlankInit() { + // Only the header barrier. + return new Carrier(false); + } + + @Test + @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" }) + static Carrier testConstructorFullInit() { + // Only the header barrier. + return new Carrier(true); + } + + @Test + @IR(failOn = { IRNode.MEMBAR }) + static void testMethodInit() { + // Primitive inits have no membars. + INIT_CARRIER.init(); + } + +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimVolatileTest.java b/test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimVolatileTest.java new file mode 100644 index 00000000000..159c2f7321d --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimVolatileTest.java @@ -0,0 +1,114 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8333791 + * @requires os.arch=="aarch64" | os.arch=="riscv64" | os.arch=="x86_64" | os.arch=="amd64" + * @requires vm.gc.Parallel + * @requires vm.compiler2.enabled + * @summary Check stable field folding and barriers + * @modules java.base/jdk.internal.vm.annotation + * @library /test/lib / + * @run driver compiler.c2.irTests.stable.StablePrimVolatileTest + */ + +package compiler.c2.irTests.stable; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; + +import jdk.internal.vm.annotation.Stable; + +public class StablePrimVolatileTest { + + public static void main(String[] args) { + TestFramework tf = new TestFramework(); + tf.addTestClassesToBootClassPath(); + tf.addFlags( + "-XX:+UnlockExperimentalVMOptions", + "-XX:CompileThreshold=100", + "-XX:-TieredCompilation", + "-XX:+UseParallelGC" + ); + tf.start(); + } + + static class Carrier { + @Stable + volatile int field; + + @ForceInline + public Carrier(boolean init) { + if (init) { + field = 42; + } + } + + @ForceInline + public void init() { + field = 42; + } + } + + static final Carrier BLANK_CARRIER = new Carrier(false); + static final Carrier INIT_CARRIER = new Carrier(true); + + @Test + @IR(counts = { IRNode.LOAD, "1" }) + @IR(counts = { IRNode.MEMBAR, ">0" }) + static int testNoFold() { + // Access should not be folded. + // Barriers expected for volatile fields. + return BLANK_CARRIER.field; + } + + @Test + @IR(failOn = { IRNode.LOAD, IRNode.MEMBAR }) + static int testFold() { + // Access should be completely folded. + return INIT_CARRIER.field; + } + + @Test + @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" }) + static Carrier testConstructorBlankInit() { + // Expect only the header barrier. + return new Carrier(false); + } + + @Test + @IR(counts = { IRNode.MEMBAR, ">0" }) + static Carrier testConstructorFullInit() { + // Volatile barriers expected. + return new Carrier(true); + } + + @Test + @IR(counts = { IRNode.MEMBAR, ">0" }) + static void testMethodInit() { + // Volatile barriers expected. + INIT_CARRIER.init(); + } + +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefArrayTest.java b/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefArrayTest.java new file mode 100644 index 00000000000..027bd2dce30 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefArrayTest.java @@ -0,0 +1,179 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8333791 + * @requires os.arch=="aarch64" | os.arch=="riscv64" | os.arch=="x86_64" | os.arch=="amd64" + * @requires vm.gc.Parallel + * @requires vm.compiler2.enabled + * @summary Check stable field folding and barriers + * @modules java.base/jdk.internal.vm.annotation + * @library /test/lib / + * @run driver compiler.c2.irTests.stable.StableRefArrayTest + */ + +package compiler.c2.irTests.stable; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; + +import jdk.internal.vm.annotation.Stable; + +public class StableRefArrayTest { + + public static void main(String[] args) { + TestFramework tf = new TestFramework(); + tf.addTestClassesToBootClassPath(); + tf.addFlags( + "-XX:+UnlockExperimentalVMOptions", + "-XX:CompileThreshold=100", + "-XX:-TieredCompilation", + "-XX:+UseParallelGC" + ); + tf.start(); + } + + static final Integer[] EMPTY_INTEGER = new Integer[] { null }; + static final Integer[] FULL_INTEGER = new Integer[] { 42 }; + + static class Carrier { + @Stable + Integer[] field; + + @ForceInline + public Carrier(int initLevel) { + switch (initLevel) { + case 0: + // Do nothing. + break; + case 1: + field = EMPTY_INTEGER; + break; + case 2: + field = FULL_INTEGER; + break; + default: + throw new IllegalStateException("Unknown level"); + } + } + + @ForceInline + public void initEmpty() { + field = EMPTY_INTEGER; + } + + @ForceInline + public void initFull() { + field = FULL_INTEGER; + } + + } + + static final Carrier BLANK_CARRIER = new Carrier(0); + static final Carrier INIT_EMPTY_CARRIER = new Carrier(1); + static final Carrier INIT_FULL_CARRIER = new Carrier(2); + + @Test + @IR(counts = { IRNode.LOAD, ">0" }) + @IR(failOn = { IRNode.MEMBAR }) + static int testNoFold() { + // Access should not be folded. + // No barriers expected for plain fields. + Integer[] is = BLANK_CARRIER.field; + if (is != null) { + Integer i = is[0]; + if (i != null) { + return i; + } + } + return 0; + } + + @Test + @IR(counts = { IRNode.LOAD, ">0" }) + @IR(failOn = { IRNode.MEMBAR }) + static int testPartialFold() { + // Access should not be folded. + // No barriers expected for plain fields. + Integer[] is = INIT_EMPTY_CARRIER.field; + if (is != null) { + Integer i = is[0]; + if (i != null) { + return i; + } + } + return 0; + } + + + @Test + @IR(failOn = { IRNode.LOAD, IRNode.MEMBAR }) + static int testFold() { + // Access should be completely folded. + Integer[] is = INIT_FULL_CARRIER.field; + if (is != null) { + Integer i = is[0]; + if (i != null) { + return i; + } + } + return 0; + } + + @Test + @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" }) + static Carrier testConstructorBlankInit() { + // Only the header barrier. + return new Carrier(0); + } + + @Test + @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" }) + static Carrier testConstructorEmptyInit() { + // Only the header barrier. + return new Carrier(1); + } + + @Test + @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" }) + static Carrier testConstructorFullInit() { + // Only the header barrier. + return new Carrier(2); + } + + @Test + @IR(failOn = { IRNode.MEMBAR }) + static void testMethodEmptyInit() { + // Reference inits do not have membars. + INIT_EMPTY_CARRIER.initEmpty(); + } + + @Test + @IR(failOn = { IRNode.MEMBAR }) + static void testMethodFullInit() { + // Reference inits do not have membars. + INIT_FULL_CARRIER.initFull(); + } + +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefFinalTest.java b/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefFinalTest.java new file mode 100644 index 00000000000..405c86a5fc9 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefFinalTest.java @@ -0,0 +1,97 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8333791 + * @requires os.arch=="aarch64" | os.arch=="riscv64" | os.arch=="x86_64" | os.arch=="amd64" + * @requires vm.gc.Parallel + * @requires vm.compiler2.enabled + * @summary Check stable field folding and barriers + * @modules java.base/jdk.internal.vm.annotation + * @library /test/lib / + * @run driver compiler.c2.irTests.stable.StableRefFinalTest + */ + +package compiler.c2.irTests.stable; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; + +import jdk.internal.vm.annotation.Stable; + +public class StableRefFinalTest { + + public static void main(String[] args) { + TestFramework tf = new TestFramework(); + tf.addTestClassesToBootClassPath(); + tf.addFlags( + "-XX:+UnlockExperimentalVMOptions", + "-XX:CompileThreshold=100", + "-XX:-TieredCompilation", + "-XX:+UseParallelGC" + ); + tf.start(); + } + + static final Integer INTEGER = 42; + + static class Carrier { + @Stable + final Integer field; + + @ForceInline + public Carrier(boolean init) { + field = init ? INTEGER : null; + } + } + + static final Carrier BLANK_CARRIER = new Carrier(false); + static final Carrier INIT_CARRIER = new Carrier(true); + + @Test + @IR(counts = { IRNode.LOAD, ">0" }) + @IR(failOn = { IRNode.MEMBAR }) + static int testNoFold() { + // Access should not be folded. + // No barriers expected for plain fields. + Integer i = BLANK_CARRIER.field; + return i != null ? i : 0; + } + + @Test + @IR(failOn = { IRNode.LOAD, IRNode.MEMBAR }) + static int testFold() { + // Access should be completely folded. + Integer i = INIT_CARRIER.field; + return i != null ? i : 0; + } + + @Test + @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" }) + static Carrier testConstructorInit() { + // Only the header+final barrier. + return new Carrier(true); + } + +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefPlainTest.java b/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefPlainTest.java new file mode 100644 index 00000000000..bd5be32459d --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefPlainTest.java @@ -0,0 +1,118 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8333791 + * @requires os.arch=="aarch64" | os.arch=="riscv64" | os.arch=="x86_64" | os.arch=="amd64" + * @requires vm.gc.Parallel + * @requires vm.compiler2.enabled + * @summary Check stable field folding and barriers + * @modules java.base/jdk.internal.vm.annotation + * @library /test/lib / + * @run driver compiler.c2.irTests.stable.StableRefPlainTest + */ + +package compiler.c2.irTests.stable; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; + +import jdk.internal.vm.annotation.Stable; + +public class StableRefPlainTest { + + public static void main(String[] args) { + TestFramework tf = new TestFramework(); + tf.addTestClassesToBootClassPath(); + tf.addFlags( + "-XX:+UnlockExperimentalVMOptions", + "-XX:CompileThreshold=100", + "-XX:-TieredCompilation", + "-XX:+UseParallelGC" + ); + tf.start(); + } + + static final Integer INTEGER = 42; + + static class Carrier { + @Stable + Integer field; + + @ForceInline + public Carrier(boolean init) { + if (init) { + field = INTEGER; + } + } + + @ForceInline + public void init() { + field = INTEGER; + } + } + + static final Carrier BLANK_CARRIER = new Carrier(false); + static final Carrier INIT_CARRIER = new Carrier(true); + + @Test + @IR(counts = { IRNode.LOAD, ">0" }) + @IR(failOn = { IRNode.MEMBAR }) + static int testNoFold() { + // Access should not be folded. + // No barriers expected for plain fields. + Integer i = BLANK_CARRIER.field; + return i != null ? i : 0; + } + + @Test + @IR(failOn = { IRNode.LOAD, IRNode.MEMBAR }) + static int testFold() { + // Access should be completely folded. + Integer i = INIT_CARRIER.field; + return i != null ? i : 0; + } + + @Test + @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" }) + static Carrier testConstructorBlankInit() { + // Only the header barrier. + return new Carrier(false); + } + + @Test + @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" }) + static Carrier testConstructorFullInit() { + // Only the header barrier. + return new Carrier(true); + } + + @Test + @IR(failOn = { IRNode.MEMBAR }) + static void testMethodInit() { + // Reference inits do not have membars. + INIT_CARRIER.init(); + } + +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefVolatileTest.java b/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefVolatileTest.java new file mode 100644 index 00000000000..7d7d7fcad77 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefVolatileTest.java @@ -0,0 +1,118 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8333791 + * @requires os.arch=="aarch64" | os.arch=="riscv64" | os.arch=="x86_64" | os.arch=="amd64" + * @requires vm.gc.Parallel + * @requires vm.compiler2.enabled + * @summary Check stable field folding and barriers + * @modules java.base/jdk.internal.vm.annotation + * @library /test/lib / + * @run driver compiler.c2.irTests.stable.StableRefVolatileTest + */ + +package compiler.c2.irTests.stable; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; + +import jdk.internal.vm.annotation.Stable; + +public class StableRefVolatileTest { + + public static void main(String[] args) { + TestFramework tf = new TestFramework(); + tf.addTestClassesToBootClassPath(); + tf.addFlags( + "-XX:+UnlockExperimentalVMOptions", + "-XX:CompileThreshold=100", + "-XX:-TieredCompilation", + "-XX:+UseParallelGC" + ); + tf.start(); + } + + static final Integer INTEGER = 42; + + static class Carrier { + @Stable + volatile Integer field; + + @ForceInline + public Carrier(boolean init) { + if (init) { + field = INTEGER; + } + } + + @ForceInline + public void init() { + field = INTEGER; + } + } + + static final Carrier BLANK_CARRIER = new Carrier(false); + static final Carrier INIT_CARRIER = new Carrier(true); + + @Test + @IR(counts = { IRNode.LOAD, ">0" }) + @IR(counts = { IRNode.MEMBAR, ">0" }) + static int testNoFold() { + // Access should not be folded. + // Barriers are expected for volatile field. + Integer i = BLANK_CARRIER.field; + return i != null ? i : 0; + } + + @Test + @IR(failOn = { IRNode.LOAD, IRNode.MEMBAR }) + static int testFold() { + // Access should be completely folded. + Integer i = INIT_CARRIER.field; + return i != null ? i : 0; + } + + @Test + @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" }) + static Carrier testConstructorBlankInit() { + // Only the header barrier. + return new Carrier(false); + } + + @Test + @IR(counts = { IRNode.MEMBAR, ">0" }) + static Carrier testConstructorFullInit() { + // Volatile writes, expect more barriers. + return new Carrier(true); + } + + @Test + @IR(counts = { IRNode.MEMBAR, ">0" }) + static void testMethodInit() { + // Barriers are expected for volatile fields. + INIT_CARRIER.init(); + } + +} From 56dec215b0d056fc23137372ecb3376af2a7b891 Mon Sep 17 00:00:00 2001 From: Sonia Zaldana Calles Date: Thu, 15 Aug 2024 13:28:25 +0000 Subject: [PATCH 425/460] 8338014: Improve usage of @jvms tags in class file API Reviewed-by: darcy, liach, asotona --- .../classes/java/lang/classfile/AnnotationValue.java | 2 +- .../share/classes/java/lang/classfile/Attribute.java | 4 ++-- .../classes/java/lang/classfile/ClassSignature.java | 2 +- .../classes/java/lang/classfile/MethodSignature.java | 2 +- .../share/classes/java/lang/classfile/Opcode.java | 4 ++-- .../share/classes/java/lang/classfile/Signature.java | 2 +- .../classes/java/lang/classfile/TypeAnnotation.java | 10 +++++----- .../attribute/AnnotationDefaultAttribute.java | 4 ++-- .../classfile/attribute/BootstrapMethodsAttribute.java | 4 ++-- .../java/lang/classfile/attribute/CodeAttribute.java | 2 +- .../classfile/attribute/ConstantValueAttribute.java | 4 ++-- .../lang/classfile/attribute/DeprecatedAttribute.java | 4 ++-- .../classfile/attribute/EnclosingMethodAttribute.java | 4 ++-- .../lang/classfile/attribute/ExceptionsAttribute.java | 4 ++-- .../classfile/attribute/InnerClassesAttribute.java | 4 ++-- .../classfile/attribute/LineNumberTableAttribute.java | 4 ++-- .../attribute/LocalVariableTableAttribute.java | 4 ++-- .../attribute/LocalVariableTypeTableAttribute.java | 4 ++-- .../classfile/attribute/MethodParametersAttribute.java | 4 ++-- .../java/lang/classfile/attribute/ModuleAttribute.java | 2 +- .../classfile/attribute/ModuleMainClassAttribute.java | 4 ++-- .../classfile/attribute/ModulePackagesAttribute.java | 4 ++-- .../lang/classfile/attribute/NestHostAttribute.java | 4 ++-- .../lang/classfile/attribute/NestMembersAttribute.java | 4 ++-- .../attribute/PermittedSubclassesAttribute.java | 4 ++-- .../java/lang/classfile/attribute/RecordAttribute.java | 4 ++-- .../RuntimeInvisibleAnnotationsAttribute.java | 4 ++-- .../RuntimeInvisibleParameterAnnotationsAttribute.java | 4 ++-- .../RuntimeInvisibleTypeAnnotationsAttribute.java | 4 ++-- .../attribute/RuntimeVisibleAnnotationsAttribute.java | 4 ++-- .../RuntimeVisibleParameterAnnotationsAttribute.java | 4 ++-- .../RuntimeVisibleTypeAnnotationsAttribute.java | 4 ++-- .../lang/classfile/attribute/SignatureAttribute.java | 4 ++-- .../lang/classfile/attribute/SourceFileAttribute.java | 4 ++-- .../lang/classfile/attribute/StackMapFrameInfo.java | 4 ++-- .../classfile/attribute/StackMapTableAttribute.java | 4 ++-- .../lang/classfile/attribute/SyntheticAttribute.java | 4 ++-- .../classfile/constantpool/ConstantPoolBuilder.java | 2 +- .../lang/classfile/constantpool/MethodHandleEntry.java | 4 ++-- .../lang/classfile/instruction/InvokeInstruction.java | 4 ++-- 40 files changed, 76 insertions(+), 76 deletions(-) diff --git a/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java b/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java index a4a1c218ac1..04bbcffb8bc 100644 --- a/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java +++ b/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java @@ -426,7 +426,7 @@ default ClassDesc classSymbol() { } /** - * {@return the tag character for this type as per {@jvms 4.7.16.1}} + * {@return the tag character for this type as per JVMS {@jvms 4.7.16.1}} */ char tag(); diff --git a/src/java.base/share/classes/java/lang/classfile/Attribute.java b/src/java.base/share/classes/java/lang/classfile/Attribute.java index 718f164e8ef..b9e3df8d2a2 100644 --- a/src/java.base/share/classes/java/lang/classfile/Attribute.java +++ b/src/java.base/share/classes/java/lang/classfile/Attribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -66,7 +66,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models a classfile attribute {@jvms 4.7}. Many, though not all, subtypes of + * Models a classfile attribute (JVMS {@jvms 4.7}). Many, though not all, subtypes of * {@linkplain Attribute} will implement {@link ClassElement}, {@link * MethodElement}, {@link FieldElement}, or {@link CodeElement}; attributes that * are also elements will be delivered when traversing the elements of the diff --git a/src/java.base/share/classes/java/lang/classfile/ClassSignature.java b/src/java.base/share/classes/java/lang/classfile/ClassSignature.java index 5c55950547e..3b6b15f59f8 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassSignature.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassSignature.java @@ -30,7 +30,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the generic signature of a class file, as defined by {@jvms 4.7.9}. + * Models the generic signature of a class file, as defined by JVMS {@jvms 4.7.9}. * * @since 22 */ diff --git a/src/java.base/share/classes/java/lang/classfile/MethodSignature.java b/src/java.base/share/classes/java/lang/classfile/MethodSignature.java index 0d5a77faa6c..5e758b64be3 100644 --- a/src/java.base/share/classes/java/lang/classfile/MethodSignature.java +++ b/src/java.base/share/classes/java/lang/classfile/MethodSignature.java @@ -32,7 +32,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the generic signature of a method, as defined by {@jvms 4.7.9}. + * Models the generic signature of a method, as defined by JVMS {@jvms 4.7.9}. * * @since 22 */ diff --git a/src/java.base/share/classes/java/lang/classfile/Opcode.java b/src/java.base/share/classes/java/lang/classfile/Opcode.java index 6ce231d43d0..9128a0e79d3 100644 --- a/src/java.base/share/classes/java/lang/classfile/Opcode.java +++ b/src/java.base/share/classes/java/lang/classfile/Opcode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Describes the opcodes of the JVM instruction set, as described in {@jvms 6.5}. + * Describes the opcodes of the JVM instruction set, as described in JVMS {@jvms 6.5}. * As well as a number of pseudo-instructions that may be encountered when * traversing the instructions of a method. * diff --git a/src/java.base/share/classes/java/lang/classfile/Signature.java b/src/java.base/share/classes/java/lang/classfile/Signature.java index 22ca477f4e6..739c3f1f3f3 100644 --- a/src/java.base/share/classes/java/lang/classfile/Signature.java +++ b/src/java.base/share/classes/java/lang/classfile/Signature.java @@ -34,7 +34,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models generic Java type signatures, as defined in {@jvms 4.7.9.1}. + * Models generic Java type signatures, as defined in JVMS {@jvms 4.7.9.1}. * * @sealedGraph * @since 22 diff --git a/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java b/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java index add1872f641..01a2f5fc696 100644 --- a/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java +++ b/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,7 +60,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models an annotation on a type use, as defined in {@jvms 4.7.19} and {@jvms 4.7.20}. + * Models an annotation on a type use, as defined in JVMS {@jvms 4.7.19} and {@jvms 4.7.20}. * * @see RuntimeVisibleTypeAnnotationsAttribute * @see RuntimeInvisibleTypeAnnotationsAttribute @@ -73,7 +73,7 @@ public sealed interface TypeAnnotation permits UnboundAttribute.UnboundTypeAnnotation { /** - * The kind of target on which the annotation appears, as defined in {@jvms 4.7.20.1}. + * The kind of target on which the annotation appears, as defined in JVMS {@jvms 4.7.20.1}. * * @since 22 */ @@ -773,7 +773,7 @@ sealed interface TypeArgumentTarget extends TargetInfo /** * JVMS: Type_path structure identifies which part of the type is annotated, - * as defined in {@jvms 4.7.20.2} + * as defined in JVMS {@jvms 4.7.20.2} * * @since 22 */ @@ -782,7 +782,7 @@ sealed interface TypePathComponent permits UnboundAttribute.TypePathComponentImpl { /** - * Type path kind, as defined in {@jvms 4.7.20.2} + * Type path kind, as defined in JVMS {@jvms 4.7.20.2} * * @since 22 */ diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/AnnotationDefaultAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/AnnotationDefaultAttribute.java index 16149ff66c5..018fcd65a34 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/AnnotationDefaultAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/AnnotationDefaultAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code AnnotationDefault} attribute {@jvms 4.7.22}, which can + * Models the {@code AnnotationDefault} attribute (JVMS {@jvms 4.7.22}), which can * appear on methods of annotation types, and records the default value * {@jls 9.6.2} for the element corresponding to this method. Delivered as a * {@link MethodElement} when traversing the elements of a {@link MethodModel}. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/BootstrapMethodsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/BootstrapMethodsAttribute.java index 436a7f80b1c..7cc784af1f4 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/BootstrapMethodsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/BootstrapMethodsAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code BootstrapMethods} attribute {@jvms 4.7.23}, which serves as + * Models the {@code BootstrapMethods} attribute (JVMS {@jvms 4.7.23}), which serves as * an extension to the constant pool of a classfile. Elements of the bootstrap * method table are accessed through {@link ConstantPool}. *

diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/CodeAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/CodeAttribute.java index 7a4f5886580..f0bab0fde11 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/CodeAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/CodeAttribute.java @@ -32,7 +32,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code Code} attribute {@jvms 4.7.3}, appears on non-native, + * Models the {@code Code} attribute (JVMS {@jvms 4.7.3}), appears on non-native, * non-abstract methods and contains the bytecode of the method body. Delivered * as a {@link java.lang.classfile.MethodElement} when traversing the elements of a * {@link java.lang.classfile.MethodModel}. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ConstantValueAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ConstantValueAttribute.java index c53b438f35f..390320c679c 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ConstantValueAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ConstantValueAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code ConstantValue} attribute {@jvms 4.7.2}, which can appear on + * Models the {@code ConstantValue} attribute (JVMS {@jvms 4.7.2}), which can appear on * fields and indicates that the field's value is a constant. Delivered as a * {@link java.lang.classfile.FieldElement} when traversing the elements of a * {@link java.lang.classfile.FieldModel}. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/DeprecatedAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/DeprecatedAttribute.java index 441271d55ef..f65f01f4e2a 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/DeprecatedAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/DeprecatedAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code Deprecated} attribute {@jvms 4.7.15}, which can appear on + * Models the {@code Deprecated} attribute (JVMS {@jvms 4.7.15}), which can appear on * classes, methods, and fields. Delivered as a {@link ClassElement}, * {@link MethodElement}, or {@link FieldElement} when traversing the elements * of a corresponding model. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/EnclosingMethodAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/EnclosingMethodAttribute.java index 3079acee89b..768019fa1d3 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/EnclosingMethodAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/EnclosingMethodAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code EnclosingMethod} attribute {@jvms 4.7.7}, which can appear + * Models the {@code EnclosingMethod} attribute (JVMS {@jvms 4.7.7}), which can appear * on classes, and indicates that the class is a local or anonymous class. * Delivered as a {@link ClassElement} when traversing the elements of a {@link * java.lang.classfile.ClassModel}. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ExceptionsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ExceptionsAttribute.java index 5af4476c923..e12b9eb9fc3 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ExceptionsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ExceptionsAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code Exceptions} attribute {@jvms 4.7.5}, which can appear on + * Models the {@code Exceptions} attribute (JVMS {@jvms 4.7.5}), which can appear on * methods, and records the exceptions declared to be thrown by this method. * Delivered as a {@link MethodElement} when traversing the elements of a * {@link java.lang.classfile.MethodModel}. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassesAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassesAttribute.java index 2089b601e3b..0746d20b5b8 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassesAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassesAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code InnerClasses} attribute {@jvms 4.7.6}, which can + * Models the {@code InnerClasses} attribute (JVMS {@jvms 4.7.6}), which can * appear on classes, and records which classes referenced by this classfile * are inner classes. Delivered as a {@link java.lang.classfile.ClassElement} when * traversing the elements of a {@link java.lang.classfile.ClassModel}. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberTableAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberTableAttribute.java index 5b211487c06..a31f4919688 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberTableAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberTableAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code LineNumberTable} attribute {@jvms 4.7.12}, which can appear + * Models the {@code LineNumberTable} attribute (JVMS {@jvms 4.7.12}), which can appear * on a {@code Code} attribute, and records the mapping between indexes into * the code table and line numbers in the source file. * Delivered as a {@link java.lang.classfile.instruction.LineNumber} when traversing the diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTableAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTableAttribute.java index 2bcdaddaea9..745b6d8e8e2 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTableAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTableAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code LocalVariableTable} attribute {@jvms 4.7.13}, which can appear + * Models the {@code LocalVariableTable} attribute (JVMS {@jvms 4.7.13}), which can appear * on a {@code Code} attribute, and records debug information about local * variables. * Delivered as a {@link java.lang.classfile.instruction.LocalVariable} when traversing the diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeTableAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeTableAttribute.java index abd3d480b9f..c2475530e6c 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeTableAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeTableAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code LocalVariableTypeTable} attribute {@jvms 4.7.14}, which can appear + * Models the {@code LocalVariableTypeTable} attribute (JVMS {@jvms 4.7.14}), which can appear * on a {@code Code} attribute, and records debug information about local * variables. * Delivered as a {@link java.lang.classfile.instruction.LocalVariable} when traversing the diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/MethodParametersAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/MethodParametersAttribute.java index d38e5e59797..81530086cdf 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/MethodParametersAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/MethodParametersAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code MethodParameters} attribute {@jvms 4.7.24}, which can + * Models the {@code MethodParameters} attribute (JVMS {@jvms 4.7.24}), which can * appear on methods, and records optional information about the method's * parameters. Delivered as a {@link java.lang.classfile.MethodElement} when * traversing the elements of a {@link java.lang.classfile.MethodModel}. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java index 9a4c58478ad..ec258611c70 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java @@ -46,7 +46,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code Module} attribute {@jvms 4.7.25}, which can + * Models the {@code Module} attribute (JVMS {@jvms 4.7.25}), which can * appear on classes that represent module descriptors. * Delivered as a {@link java.lang.classfile.ClassElement} when * traversing the elements of a {@link java.lang.classfile.ClassModel}. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleMainClassAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleMainClassAttribute.java index 086017ba9aa..91fe3c8f2d7 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleMainClassAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleMainClassAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code ModuleMainClass} attribute {@jvms 4.7.27}, which can + * Models the {@code ModuleMainClass} attribute (JVMS {@jvms 4.7.27}), which can * appear on classes that represent module descriptors. * Delivered as a {@link java.lang.classfile.ClassElement} when * traversing the elements of a {@link java.lang.classfile.ClassModel}. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModulePackagesAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModulePackagesAttribute.java index 7bf2ac8ce62..30bc0e9827b 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModulePackagesAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModulePackagesAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code ModulePackages} attribute {@jvms 4.7.26}, which can + * Models the {@code ModulePackages} attribute (JVMS {@jvms 4.7.26}), which can * appear on classes that represent module descriptors. * Delivered as a {@link java.lang.classfile.ClassElement} when * traversing the elements of a {@link java.lang.classfile.ClassModel}. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/NestHostAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/NestHostAttribute.java index 7c60835385a..0961601e5d4 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/NestHostAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/NestHostAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code NestHost} attribute {@jvms 4.7.28}, which can + * Models the {@code NestHost} attribute (JVMS {@jvms 4.7.28}), which can * appear on classes to indicate that this class is a member of a nest. * Delivered as a {@link java.lang.classfile.ClassElement} when * traversing the elements of a {@link java.lang.classfile.ClassModel}. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/NestMembersAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/NestMembersAttribute.java index 72d4e8cca7d..f184df7fff5 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/NestMembersAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/NestMembersAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code NestMembers} attribute {@jvms 4.7.29}, which can + * Models the {@code NestMembers} attribute (JVMS {@jvms 4.7.29}), which can * appear on classes to indicate that this class is the host of a nest. * Delivered as a {@link java.lang.classfile.ClassElement} when * traversing the elements of a {@link java.lang.classfile.ClassModel}. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/PermittedSubclassesAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/PermittedSubclassesAttribute.java index e6aaa6ad4a6..2d86d4d26e0 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/PermittedSubclassesAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/PermittedSubclassesAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code PermittedSubclasses} attribute {@jvms 4.7.31}, which can + * Models the {@code PermittedSubclasses} attribute (JVMS {@jvms 4.7.31}), which can * appear on classes to indicate which classes may extend this class. * Delivered as a {@link java.lang.classfile.ClassElement} when * traversing the elements of a {@link java.lang.classfile.ClassModel}. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RecordAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RecordAttribute.java index 16d01943bc3..f79538a135c 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RecordAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RecordAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code Record} attribute {@jvms 4.7.30}, which can + * Models the {@code Record} attribute (JVMS {@jvms 4.7.30}), which can * appear on classes to indicate that this class is a record class. * Delivered as a {@link java.lang.classfile.ClassElement} when * traversing the elements of a {@link java.lang.classfile.ClassModel}. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java index 485e4d2af59..b467e8504fe 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code RuntimeInvisibleAnnotations} attribute {@jvms 4.7.17}, which + * Models the {@code RuntimeInvisibleAnnotations} attribute (JVMS {@jvms 4.7.17}), which * can appear on classes, methods, and fields. Delivered as a * {@link java.lang.classfile.ClassElement}, {@link java.lang.classfile.FieldElement}, or * {@link java.lang.classfile.MethodElement} when traversing the corresponding model type. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java index 4865dde3411..af495788afa 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ /** * Models the {@code RuntimeInvisibleParameterAnnotations} attribute - * {@jvms 4.7.19}, which can appear on methods. Delivered as a {@link + * (JVMS {@jvms 4.7.19}), which can appear on methods. Delivered as a {@link * java.lang.classfile.MethodElement} when traversing a {@link MethodModel}. *

* The attribute does not permit multiple instances in a given location. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java index 830e9778a47..46dd2167541 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code RuntimeInvisibleTypeAnnotations} attribute {@jvms 4.7.21}, which + * Models the {@code RuntimeInvisibleTypeAnnotations} attribute (JVMS {@jvms 4.7.21}), which * can appear on classes, methods, fields, and code attributes. Delivered as a * {@link java.lang.classfile.ClassElement}, {@link java.lang.classfile.FieldElement}, * {@link java.lang.classfile.MethodElement}, or {@link CodeElement} when traversing diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java index 77a49b8d13b..4454dac62a9 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code RuntimeVisibleAnnotations} attribute {@jvms 4.7.16}, which + * Models the {@code RuntimeVisibleAnnotations} attribute (JVMS {@jvms 4.7.16}), which * can appear on classes, methods, and fields. Delivered as a * {@link java.lang.classfile.ClassElement}, {@link java.lang.classfile.FieldElement}, or * {@link java.lang.classfile.MethodElement} when traversing the corresponding model type. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java index 7923493499a..59f648199ca 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code RuntimeVisibleParameterAnnotations} attribute {@jvms 4.7.18}, which + * Models the {@code RuntimeVisibleParameterAnnotations} attribute (JVMS {@jvms 4.7.18}), which * can appear on methods. Delivered as a {@link java.lang.classfile.MethodElement} * when traversing a {@link MethodModel}. * diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java index 3cf38811d5a..8bdf322803d 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code RuntimeVisibleTypeAnnotations} attribute {@jvms 4.7.20}, which + * Models the {@code RuntimeVisibleTypeAnnotations} attribute (JVMS {@jvms 4.7.20}), which * can appear on classes, methods, fields, and code attributes. Delivered as a * {@link java.lang.classfile.ClassElement}, {@link java.lang.classfile.FieldElement}, * {@link java.lang.classfile.MethodElement}, or {@link CodeElement} when traversing diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/SignatureAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/SignatureAttribute.java index e77382f2fd4..783b068c4e6 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/SignatureAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/SignatureAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code Signature} attribute {@jvms 4.7.9}, which + * Models the {@code Signature} attribute (JVMS {@jvms 4.7.9}), which * can appear on classes, methods, or fields. Delivered as a * {@link java.lang.classfile.ClassElement}, {@link java.lang.classfile.FieldElement}, or * {@link java.lang.classfile.MethodElement} when traversing diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/SourceFileAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/SourceFileAttribute.java index 58e1ab47418..abfa4eb05ff 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/SourceFileAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/SourceFileAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code SourceFile} attribute {@jvms 4.7.10}, which + * Models the {@code SourceFile} attribute (JVMS {@jvms 4.7.10}), which * can appear on classes. Delivered as a {@link java.lang.classfile.ClassElement} * when traversing a {@link ClassModel}. *

diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java index 08736444442..46caa66ef9a 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models stack map frame of {@code StackMapTable} attribute {@jvms 4.7.4}. + * Models stack map frame of {@code StackMapTable} attribute (JVMS {@jvms 4.7.4}). * * @since 22 */ diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapTableAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapTableAttribute.java index d3ec67cab63..74dd567060e 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapTableAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapTableAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code StackMapTable} attribute {@jvms 4.7.4}, which can appear + * Models the {@code StackMapTable} attribute (JVMS {@jvms 4.7.4}), which can appear * on a {@code Code} attribute. *

* The attribute does not permit multiple instances in a given location. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/SyntheticAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/SyntheticAttribute.java index 6bc9c19b851..d1b7b8f0384 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/SyntheticAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/SyntheticAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code Synthetic} attribute {@jvms 4.7.8}, which can appear on + * Models the {@code Synthetic} attribute (JVMS {@jvms 4.7.8}), which can appear on * classes, methods, and fields. Delivered as a {@link ClassElement}, * {@link MethodElement}, or {@link FieldElement} when traversing the elements * of a corresponding model. diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java index db77f8e2e8a..7334d8e5460 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java @@ -365,7 +365,7 @@ default MethodHandleEntry methodHandleEntry(DirectMethodHandleDesc descriptor) { * it is returned; otherwise, a new entry is added and the new entry is * returned. * - * @param refKind the reference kind of the method handle {@jvms 4.4.8} + * @param refKind the reference kind of the method handle (JVMS {@jvms 4.4.8}) * @param reference the constant pool entry describing the field or method */ MethodHandleEntry methodHandleEntry(int refKind, MemberRefEntry reference); diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/MethodHandleEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/MethodHandleEntry.java index 76899100027..37ec30648ab 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/MethodHandleEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/MethodHandleEntry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,7 +48,7 @@ default ConstantDesc constantValue() { } /** - * {@return the reference kind of this method handle {@jvms 4.4.8}} + * {@return the reference kind of this method handle (JVMS {@jvms 4.4.8})} * @see java.lang.invoke.MethodHandleInfo */ int kind(); diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/InvokeInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/InvokeInstruction.java index 79a2142eb65..ff68abce3d2 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/InvokeInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/InvokeInstruction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,7 +64,7 @@ public sealed interface InvokeInstruction extends Instruction boolean isInterface(); /** - * {@return the {@code count} value of an {@code invokeinterface} instruction, as defined in {@jvms 6.5} + * {@return the {@code count} value of an {@code invokeinterface} instruction, as defined in JVMS {@jvms 6.5} * or {@code 0} for {@code invokespecial}, {@code invokestatic} and {@code invokevirtual} instructions} */ int count(); From 38591315058e6d3b764ca325facc5bf46bf7b16b Mon Sep 17 00:00:00 2001 From: Fei Gao Date: Thu, 15 Aug 2024 15:16:14 +0000 Subject: [PATCH 426/460] 8338442: AArch64: Clean up IndOffXX type and let legitimize_address() fix out-of-range operands Reviewed-by: aph, dlong --- src/hotspot/cpu/aarch64/aarch64.ad | 393 ++++-------------- src/hotspot/cpu/aarch64/aarch64_vector.ad | 16 +- src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 | 2 +- src/hotspot/cpu/aarch64/ad_encode.m4 | 8 +- src/hotspot/cpu/aarch64/gc/x/x_aarch64.ad | 2 +- src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad | 2 +- .../compiler/c2/TestUnalignedAccess.java | 61 ++- 7 files changed, 123 insertions(+), 361 deletions(-) diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 66a24a61f29..a96c47051f2 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -2720,7 +2720,7 @@ typedef void (MacroAssembler::* mem_vector_insn)(FloatRegister Rt, { Address addr = mem2address(opcode, base, index, scale, disp); if (addr.getMode() == Address::base_plus_offset) { - /* Fix up any out-of-range offsets. */ + // Fix up any out-of-range offsets. assert_different_registers(rscratch1, base); assert_different_registers(rscratch1, reg); addr = __ legitimize_address(addr, size_in_memory, rscratch1); @@ -2761,7 +2761,11 @@ typedef void (MacroAssembler::* mem_vector_insn)(FloatRegister Rt, int opcode, Register base, int index, int size, int disp) { if (index == -1) { - (masm->*insn)(reg, T, Address(base, disp)); + // Fix up any out-of-range offsets. + assert_different_registers(rscratch1, base); + Address addr = Address(base, disp); + addr = __ legitimize_address(addr, (1 << T), rscratch1); + (masm->*insn)(reg, T, addr); } else { assert(disp == 0, "unsupported address mode"); (masm->*insn)(reg, T, Address(base, as_Register(index), Address::lsl(size))); @@ -2816,7 +2820,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrsbw(iRegI dst, memory1 mem) %{ + enc_class aarch64_enc_ldrsbw(iRegI dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrsbw, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); @@ -2824,7 +2828,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrsb(iRegI dst, memory1 mem) %{ + enc_class aarch64_enc_ldrsb(iRegI dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrsb, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); @@ -2832,7 +2836,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrb(iRegI dst, memory1 mem) %{ + enc_class aarch64_enc_ldrb(iRegI dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrb, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); @@ -2840,7 +2844,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrb(iRegL dst, memory1 mem) %{ + enc_class aarch64_enc_ldrb(iRegL dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrb, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); @@ -2848,7 +2852,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrshw(iRegI dst, memory2 mem) %{ + enc_class aarch64_enc_ldrshw(iRegI dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrshw, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 2); @@ -2856,7 +2860,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrsh(iRegI dst, memory2 mem) %{ + enc_class aarch64_enc_ldrsh(iRegI dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrsh, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 2); @@ -2864,7 +2868,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrh(iRegI dst, memory2 mem) %{ + enc_class aarch64_enc_ldrh(iRegI dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrh, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 2); @@ -2872,7 +2876,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrh(iRegL dst, memory2 mem) %{ + enc_class aarch64_enc_ldrh(iRegL dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrh, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 2); @@ -2880,7 +2884,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrw(iRegI dst, memory4 mem) %{ + enc_class aarch64_enc_ldrw(iRegI dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrw, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); @@ -2888,7 +2892,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrw(iRegL dst, memory4 mem) %{ + enc_class aarch64_enc_ldrw(iRegL dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrw, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); @@ -2896,7 +2900,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrsw(iRegL dst, memory4 mem) %{ + enc_class aarch64_enc_ldrsw(iRegL dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrsw, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); @@ -2904,7 +2908,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldr(iRegL dst, memory8 mem) %{ + enc_class aarch64_enc_ldr(iRegL dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldr, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 8); @@ -2912,7 +2916,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrs(vRegF dst, memory4 mem) %{ + enc_class aarch64_enc_ldrs(vRegF dst, memory mem) %{ FloatRegister dst_reg = as_FloatRegister($dst$$reg); loadStore(masm, &MacroAssembler::ldrs, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); @@ -2920,7 +2924,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrd(vRegD dst, memory8 mem) %{ + enc_class aarch64_enc_ldrd(vRegD dst, memory mem) %{ FloatRegister dst_reg = as_FloatRegister($dst$$reg); loadStore(masm, &MacroAssembler::ldrd, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 8); @@ -2928,7 +2932,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strb(iRegI src, memory1 mem) %{ + enc_class aarch64_enc_strb(iRegI src, memory mem) %{ Register src_reg = as_Register($src$$reg); loadStore(masm, &MacroAssembler::strb, src_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); @@ -2936,14 +2940,14 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strb0(memory1 mem) %{ + enc_class aarch64_enc_strb0(memory mem) %{ loadStore(masm, &MacroAssembler::strb, zr, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strh(iRegI src, memory2 mem) %{ + enc_class aarch64_enc_strh(iRegI src, memory mem) %{ Register src_reg = as_Register($src$$reg); loadStore(masm, &MacroAssembler::strh, src_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 2); @@ -2951,14 +2955,14 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strh0(memory2 mem) %{ + enc_class aarch64_enc_strh0(memory mem) %{ loadStore(masm, &MacroAssembler::strh, zr, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 2); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strw(iRegI src, memory4 mem) %{ + enc_class aarch64_enc_strw(iRegI src, memory mem) %{ Register src_reg = as_Register($src$$reg); loadStore(masm, &MacroAssembler::strw, src_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); @@ -2966,14 +2970,14 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strw0(memory4 mem) %{ + enc_class aarch64_enc_strw0(memory mem) %{ loadStore(masm, &MacroAssembler::strw, zr, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_str(iRegL src, memory8 mem) %{ + enc_class aarch64_enc_str(iRegL src, memory mem) %{ Register src_reg = as_Register($src$$reg); // we sometimes get asked to store the stack pointer into the // current thread -- we cannot do that directly on AArch64 @@ -2988,14 +2992,14 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_str0(memory8 mem) %{ + enc_class aarch64_enc_str0(memory mem) %{ loadStore(masm, &MacroAssembler::str, zr, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 8); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strs(vRegF src, memory4 mem) %{ + enc_class aarch64_enc_strs(vRegF src, memory mem) %{ FloatRegister src_reg = as_FloatRegister($src$$reg); loadStore(masm, &MacroAssembler::strs, src_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); @@ -3003,7 +3007,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strd(vRegD src, memory8 mem) %{ + enc_class aarch64_enc_strd(vRegD src, memory mem) %{ FloatRegister src_reg = as_FloatRegister($src$$reg); loadStore(masm, &MacroAssembler::strd, src_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 8); @@ -3011,7 +3015,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strb0_ordered(memory4 mem) %{ + enc_class aarch64_enc_strb0_ordered(memory mem) %{ __ membar(Assembler::StoreStore); loadStore(masm, &MacroAssembler::strb, zr, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); @@ -3213,7 +3217,7 @@ encode %{ // synchronized read/update encodings - enc_class aarch64_enc_ldaxr(iRegL dst, memory8 mem) %{ + enc_class aarch64_enc_ldaxr(iRegL dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); Register base = as_Register($mem$$base); int index = $mem$$index; @@ -3241,7 +3245,7 @@ encode %{ } %} - enc_class aarch64_enc_stlxr(iRegLNoSp src, memory8 mem) %{ + enc_class aarch64_enc_stlxr(iRegLNoSp src, memory mem) %{ Register src_reg = as_Register($src$$reg); Register base = as_Register($mem$$base); int index = $mem$$index; @@ -4169,60 +4173,10 @@ operand immIU7() interface(CONST_INTER); %} -// Offset for scaled or unscaled immediate loads and stores +// Offset for immediate loads and stores operand immIOffset() %{ - predicate(Address::offset_ok_for_immed(n->get_int(), 0)); - match(ConI); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -operand immIOffset1() -%{ - predicate(Address::offset_ok_for_immed(n->get_int(), 0)); - match(ConI); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -operand immIOffset2() -%{ - predicate(Address::offset_ok_for_immed(n->get_int(), 1)); - match(ConI); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -operand immIOffset4() -%{ - predicate(Address::offset_ok_for_immed(n->get_int(), 2)); - match(ConI); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -operand immIOffset8() -%{ - predicate(Address::offset_ok_for_immed(n->get_int(), 3)); - match(ConI); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -operand immIOffset16() -%{ - predicate(Address::offset_ok_for_immed(n->get_int(), 4)); + predicate(n->get_int() >= -256 && n->get_int() <= 65520); match(ConI); op_cost(0); @@ -4240,56 +4194,6 @@ operand immLOffset() interface(CONST_INTER); %} -operand immLoffset1() -%{ - predicate(Address::offset_ok_for_immed(n->get_long(), 0)); - match(ConL); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -operand immLoffset2() -%{ - predicate(Address::offset_ok_for_immed(n->get_long(), 1)); - match(ConL); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -operand immLoffset4() -%{ - predicate(Address::offset_ok_for_immed(n->get_long(), 2)); - match(ConL); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -operand immLoffset8() -%{ - predicate(Address::offset_ok_for_immed(n->get_long(), 3)); - match(ConL); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -operand immLoffset16() -%{ - predicate(Address::offset_ok_for_immed(n->get_long(), 4)); - match(ConL); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - // 5 bit signed long integer operand immL5() %{ @@ -5202,21 +5106,7 @@ operand indIndex(iRegP reg, iRegL lreg) %} %} -operand indOffI1(iRegP reg, immIOffset1 off) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP reg off); - op_cost(0); - format %{ "[$reg, $off]" %} - interface(MEMORY_INTER) %{ - base($reg); - index(0xffffffff); - scale(0x0); - disp($off); - %} -%} - -operand indOffI2(iRegP reg, immIOffset2 off) +operand indOffI(iRegP reg, immIOffset off) %{ constraint(ALLOC_IN_RC(ptr_reg)); match(AddP reg off); @@ -5230,105 +5120,7 @@ operand indOffI2(iRegP reg, immIOffset2 off) %} %} -operand indOffI4(iRegP reg, immIOffset4 off) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP reg off); - op_cost(0); - format %{ "[$reg, $off]" %} - interface(MEMORY_INTER) %{ - base($reg); - index(0xffffffff); - scale(0x0); - disp($off); - %} -%} - -operand indOffI8(iRegP reg, immIOffset8 off) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP reg off); - op_cost(0); - format %{ "[$reg, $off]" %} - interface(MEMORY_INTER) %{ - base($reg); - index(0xffffffff); - scale(0x0); - disp($off); - %} -%} - -operand indOffI16(iRegP reg, immIOffset16 off) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP reg off); - op_cost(0); - format %{ "[$reg, $off]" %} - interface(MEMORY_INTER) %{ - base($reg); - index(0xffffffff); - scale(0x0); - disp($off); - %} -%} - -operand indOffL1(iRegP reg, immLoffset1 off) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP reg off); - op_cost(0); - format %{ "[$reg, $off]" %} - interface(MEMORY_INTER) %{ - base($reg); - index(0xffffffff); - scale(0x0); - disp($off); - %} -%} - -operand indOffL2(iRegP reg, immLoffset2 off) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP reg off); - op_cost(0); - format %{ "[$reg, $off]" %} - interface(MEMORY_INTER) %{ - base($reg); - index(0xffffffff); - scale(0x0); - disp($off); - %} -%} - -operand indOffL4(iRegP reg, immLoffset4 off) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP reg off); - op_cost(0); - format %{ "[$reg, $off]" %} - interface(MEMORY_INTER) %{ - base($reg); - index(0xffffffff); - scale(0x0); - disp($off); - %} -%} - -operand indOffL8(iRegP reg, immLoffset8 off) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP reg off); - op_cost(0); - format %{ "[$reg, $off]" %} - interface(MEMORY_INTER) %{ - base($reg); - index(0xffffffff); - scale(0x0); - disp($off); - %} -%} - -operand indOffL16(iRegP reg, immLoffset16 off) +operand indOffL(iRegP reg, immLOffset off) %{ constraint(ALLOC_IN_RC(ptr_reg)); match(AddP reg off); @@ -5704,10 +5496,7 @@ operand iRegL2P(iRegL reg) %{ interface(REG_INTER) %} -opclass vmem2(indirect, indIndex, indOffI2, indOffL2); -opclass vmem4(indirect, indIndex, indOffI4, indOffL4); -opclass vmem8(indirect, indIndex, indOffI8, indOffL8); -opclass vmem16(indirect, indIndex, indOffI16, indOffL16); +opclass vmem(indirect, indIndex, indOffI, indOffL, indOffIN, indOffLN); //----------OPERAND CLASSES---------------------------------------------------- // Operand Classes are groups of operands that are used as to simplify @@ -5719,23 +5508,9 @@ opclass vmem16(indirect, indIndex, indOffI16, indOffL16); // memory is used to define read/write location for load/store // instruction defs. we can turn a memory op into an Address -opclass memory1(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI1, indOffL1, - indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indirectX2P, indOffX2P); - -opclass memory2(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI2, indOffL2, - indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indirectX2P, indOffX2P); - -opclass memory4(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI4, indOffL4, - indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN, indOffLN, indirectX2P, indOffX2P); - -opclass memory8(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI8, indOffL8, - indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN, indOffLN, indirectX2P, indOffX2P); - -// All of the memory operands. For the pipeline description. -opclass memory(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, - indOffI1, indOffL1, indOffI2, indOffL2, indOffI4, indOffL4, indOffI8, indOffL8, - indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN, indOffLN, indirectX2P, indOffX2P); - +opclass memory(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI, indOffL, + indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN, + indOffLN, indirectX2P, indOffX2P); // iRegIorL2I is used for src inputs in rules for 32 bit int (I) // operations. it allows the src to be either an iRegI or a (ConvL2I @@ -6437,7 +6212,7 @@ define %{ // Load Instructions // Load Byte (8 bit signed) -instruct loadB(iRegINoSp dst, memory1 mem) +instruct loadB(iRegINoSp dst, memory mem) %{ match(Set dst (LoadB mem)); predicate(!needs_acquiring_load(n)); @@ -6451,7 +6226,7 @@ instruct loadB(iRegINoSp dst, memory1 mem) %} // Load Byte (8 bit signed) into long -instruct loadB2L(iRegLNoSp dst, memory1 mem) +instruct loadB2L(iRegLNoSp dst, memory mem) %{ match(Set dst (ConvI2L (LoadB mem))); predicate(!needs_acquiring_load(n->in(1))); @@ -6465,7 +6240,7 @@ instruct loadB2L(iRegLNoSp dst, memory1 mem) %} // Load Byte (8 bit unsigned) -instruct loadUB(iRegINoSp dst, memory1 mem) +instruct loadUB(iRegINoSp dst, memory mem) %{ match(Set dst (LoadUB mem)); predicate(!needs_acquiring_load(n)); @@ -6479,7 +6254,7 @@ instruct loadUB(iRegINoSp dst, memory1 mem) %} // Load Byte (8 bit unsigned) into long -instruct loadUB2L(iRegLNoSp dst, memory1 mem) +instruct loadUB2L(iRegLNoSp dst, memory mem) %{ match(Set dst (ConvI2L (LoadUB mem))); predicate(!needs_acquiring_load(n->in(1))); @@ -6493,7 +6268,7 @@ instruct loadUB2L(iRegLNoSp dst, memory1 mem) %} // Load Short (16 bit signed) -instruct loadS(iRegINoSp dst, memory2 mem) +instruct loadS(iRegINoSp dst, memory mem) %{ match(Set dst (LoadS mem)); predicate(!needs_acquiring_load(n)); @@ -6507,7 +6282,7 @@ instruct loadS(iRegINoSp dst, memory2 mem) %} // Load Short (16 bit signed) into long -instruct loadS2L(iRegLNoSp dst, memory2 mem) +instruct loadS2L(iRegLNoSp dst, memory mem) %{ match(Set dst (ConvI2L (LoadS mem))); predicate(!needs_acquiring_load(n->in(1))); @@ -6521,7 +6296,7 @@ instruct loadS2L(iRegLNoSp dst, memory2 mem) %} // Load Char (16 bit unsigned) -instruct loadUS(iRegINoSp dst, memory2 mem) +instruct loadUS(iRegINoSp dst, memory mem) %{ match(Set dst (LoadUS mem)); predicate(!needs_acquiring_load(n)); @@ -6535,7 +6310,7 @@ instruct loadUS(iRegINoSp dst, memory2 mem) %} // Load Short/Char (16 bit unsigned) into long -instruct loadUS2L(iRegLNoSp dst, memory2 mem) +instruct loadUS2L(iRegLNoSp dst, memory mem) %{ match(Set dst (ConvI2L (LoadUS mem))); predicate(!needs_acquiring_load(n->in(1))); @@ -6549,7 +6324,7 @@ instruct loadUS2L(iRegLNoSp dst, memory2 mem) %} // Load Integer (32 bit signed) -instruct loadI(iRegINoSp dst, memory4 mem) +instruct loadI(iRegINoSp dst, memory mem) %{ match(Set dst (LoadI mem)); predicate(!needs_acquiring_load(n)); @@ -6563,7 +6338,7 @@ instruct loadI(iRegINoSp dst, memory4 mem) %} // Load Integer (32 bit signed) into long -instruct loadI2L(iRegLNoSp dst, memory4 mem) +instruct loadI2L(iRegLNoSp dst, memory mem) %{ match(Set dst (ConvI2L (LoadI mem))); predicate(!needs_acquiring_load(n->in(1))); @@ -6577,7 +6352,7 @@ instruct loadI2L(iRegLNoSp dst, memory4 mem) %} // Load Integer (32 bit unsigned) into long -instruct loadUI2L(iRegLNoSp dst, memory4 mem, immL_32bits mask) +instruct loadUI2L(iRegLNoSp dst, memory mem, immL_32bits mask) %{ match(Set dst (AndL (ConvI2L (LoadI mem)) mask)); predicate(!needs_acquiring_load(n->in(1)->in(1)->as_Load())); @@ -6591,7 +6366,7 @@ instruct loadUI2L(iRegLNoSp dst, memory4 mem, immL_32bits mask) %} // Load Long (64 bit signed) -instruct loadL(iRegLNoSp dst, memory8 mem) +instruct loadL(iRegLNoSp dst, memory mem) %{ match(Set dst (LoadL mem)); predicate(!needs_acquiring_load(n)); @@ -6605,7 +6380,7 @@ instruct loadL(iRegLNoSp dst, memory8 mem) %} // Load Range -instruct loadRange(iRegINoSp dst, memory4 mem) +instruct loadRange(iRegINoSp dst, memory mem) %{ match(Set dst (LoadRange mem)); @@ -6618,7 +6393,7 @@ instruct loadRange(iRegINoSp dst, memory4 mem) %} // Load Pointer -instruct loadP(iRegPNoSp dst, memory8 mem) +instruct loadP(iRegPNoSp dst, memory mem) %{ match(Set dst (LoadP mem)); predicate(!needs_acquiring_load(n) && (n->as_Load()->barrier_data() == 0)); @@ -6632,7 +6407,7 @@ instruct loadP(iRegPNoSp dst, memory8 mem) %} // Load Compressed Pointer -instruct loadN(iRegNNoSp dst, memory4 mem) +instruct loadN(iRegNNoSp dst, memory mem) %{ match(Set dst (LoadN mem)); predicate(!needs_acquiring_load(n)); @@ -6646,7 +6421,7 @@ instruct loadN(iRegNNoSp dst, memory4 mem) %} // Load Klass Pointer -instruct loadKlass(iRegPNoSp dst, memory8 mem) +instruct loadKlass(iRegPNoSp dst, memory mem) %{ match(Set dst (LoadKlass mem)); predicate(!needs_acquiring_load(n)); @@ -6660,7 +6435,7 @@ instruct loadKlass(iRegPNoSp dst, memory8 mem) %} // Load Narrow Klass Pointer -instruct loadNKlass(iRegNNoSp dst, memory4 mem) +instruct loadNKlass(iRegNNoSp dst, memory mem) %{ match(Set dst (LoadNKlass mem)); predicate(!needs_acquiring_load(n)); @@ -6674,7 +6449,7 @@ instruct loadNKlass(iRegNNoSp dst, memory4 mem) %} // Load Float -instruct loadF(vRegF dst, memory4 mem) +instruct loadF(vRegF dst, memory mem) %{ match(Set dst (LoadF mem)); predicate(!needs_acquiring_load(n)); @@ -6688,7 +6463,7 @@ instruct loadF(vRegF dst, memory4 mem) %} // Load Double -instruct loadD(vRegD dst, memory8 mem) +instruct loadD(vRegD dst, memory mem) %{ match(Set dst (LoadD mem)); predicate(!needs_acquiring_load(n)); @@ -6892,7 +6667,7 @@ instruct loadConD(vRegD dst, immD con) %{ // Store Instructions // Store CMS card-mark Immediate -instruct storeimmCM0(immI0 zero, memory1 mem) +instruct storeimmCM0(immI0 zero, memory mem) %{ match(Set mem (StoreCM mem zero)); @@ -6907,7 +6682,7 @@ instruct storeimmCM0(immI0 zero, memory1 mem) // Store CMS card-mark Immediate with intervening StoreStore // needed when using CMS with no conditional card marking -instruct storeimmCM0_ordered(immI0 zero, memory1 mem) +instruct storeimmCM0_ordered(immI0 zero, memory mem) %{ match(Set mem (StoreCM mem zero)); @@ -6922,7 +6697,7 @@ instruct storeimmCM0_ordered(immI0 zero, memory1 mem) %} // Store Byte -instruct storeB(iRegIorL2I src, memory1 mem) +instruct storeB(iRegIorL2I src, memory mem) %{ match(Set mem (StoreB mem src)); predicate(!needs_releasing_store(n)); @@ -6936,7 +6711,7 @@ instruct storeB(iRegIorL2I src, memory1 mem) %} -instruct storeimmB0(immI0 zero, memory1 mem) +instruct storeimmB0(immI0 zero, memory mem) %{ match(Set mem (StoreB mem zero)); predicate(!needs_releasing_store(n)); @@ -6950,7 +6725,7 @@ instruct storeimmB0(immI0 zero, memory1 mem) %} // Store Char/Short -instruct storeC(iRegIorL2I src, memory2 mem) +instruct storeC(iRegIorL2I src, memory mem) %{ match(Set mem (StoreC mem src)); predicate(!needs_releasing_store(n)); @@ -6963,7 +6738,7 @@ instruct storeC(iRegIorL2I src, memory2 mem) ins_pipe(istore_reg_mem); %} -instruct storeimmC0(immI0 zero, memory2 mem) +instruct storeimmC0(immI0 zero, memory mem) %{ match(Set mem (StoreC mem zero)); predicate(!needs_releasing_store(n)); @@ -6978,7 +6753,7 @@ instruct storeimmC0(immI0 zero, memory2 mem) // Store Integer -instruct storeI(iRegIorL2I src, memory4 mem) +instruct storeI(iRegIorL2I src, memory mem) %{ match(Set mem(StoreI mem src)); predicate(!needs_releasing_store(n)); @@ -6991,7 +6766,7 @@ instruct storeI(iRegIorL2I src, memory4 mem) ins_pipe(istore_reg_mem); %} -instruct storeimmI0(immI0 zero, memory4 mem) +instruct storeimmI0(immI0 zero, memory mem) %{ match(Set mem(StoreI mem zero)); predicate(!needs_releasing_store(n)); @@ -7005,7 +6780,7 @@ instruct storeimmI0(immI0 zero, memory4 mem) %} // Store Long (64 bit signed) -instruct storeL(iRegL src, memory8 mem) +instruct storeL(iRegL src, memory mem) %{ match(Set mem (StoreL mem src)); predicate(!needs_releasing_store(n)); @@ -7019,7 +6794,7 @@ instruct storeL(iRegL src, memory8 mem) %} // Store Long (64 bit signed) -instruct storeimmL0(immL0 zero, memory8 mem) +instruct storeimmL0(immL0 zero, memory mem) %{ match(Set mem (StoreL mem zero)); predicate(!needs_releasing_store(n)); @@ -7033,7 +6808,7 @@ instruct storeimmL0(immL0 zero, memory8 mem) %} // Store Pointer -instruct storeP(iRegP src, memory8 mem) +instruct storeP(iRegP src, memory mem) %{ match(Set mem (StoreP mem src)); predicate(!needs_releasing_store(n) && n->as_Store()->barrier_data() == 0); @@ -7047,7 +6822,7 @@ instruct storeP(iRegP src, memory8 mem) %} // Store Pointer -instruct storeimmP0(immP0 zero, memory8 mem) +instruct storeimmP0(immP0 zero, memory mem) %{ match(Set mem (StoreP mem zero)); predicate(!needs_releasing_store(n) && n->as_Store()->barrier_data() == 0); @@ -7061,7 +6836,7 @@ instruct storeimmP0(immP0 zero, memory8 mem) %} // Store Compressed Pointer -instruct storeN(iRegN src, memory4 mem) +instruct storeN(iRegN src, memory mem) %{ match(Set mem (StoreN mem src)); predicate(!needs_releasing_store(n)); @@ -7074,7 +6849,7 @@ instruct storeN(iRegN src, memory4 mem) ins_pipe(istore_reg_mem); %} -instruct storeImmN0(immN0 zero, memory4 mem) +instruct storeImmN0(immN0 zero, memory mem) %{ match(Set mem (StoreN mem zero)); predicate(!needs_releasing_store(n)); @@ -7088,7 +6863,7 @@ instruct storeImmN0(immN0 zero, memory4 mem) %} // Store Float -instruct storeF(vRegF src, memory4 mem) +instruct storeF(vRegF src, memory mem) %{ match(Set mem (StoreF mem src)); predicate(!needs_releasing_store(n)); @@ -7105,7 +6880,7 @@ instruct storeF(vRegF src, memory4 mem) // implement storeImmF0 and storeFImmPacked // Store Double -instruct storeD(vRegD src, memory8 mem) +instruct storeD(vRegD src, memory mem) %{ match(Set mem (StoreD mem src)); predicate(!needs_releasing_store(n)); @@ -7119,7 +6894,7 @@ instruct storeD(vRegD src, memory8 mem) %} // Store Compressed Klass Pointer -instruct storeNKlass(iRegN src, memory4 mem) +instruct storeNKlass(iRegN src, memory mem) %{ predicate(!needs_releasing_store(n)); match(Set mem (StoreNKlass mem src)); @@ -7138,7 +6913,7 @@ instruct storeNKlass(iRegN src, memory4 mem) // prefetch instructions // Must be safe to execute with invalid address (cannot fault). -instruct prefetchalloc( memory8 mem ) %{ +instruct prefetchalloc( memory mem ) %{ match(PrefetchAllocation mem); ins_cost(INSN_COST); @@ -7707,7 +7482,7 @@ instruct popCountI(iRegINoSp dst, iRegIorL2I src, vRegF tmp) %{ ins_pipe(pipe_class_default); %} -instruct popCountI_mem(iRegINoSp dst, memory4 mem, vRegF tmp) %{ +instruct popCountI_mem(iRegINoSp dst, memory mem, vRegF tmp) %{ match(Set dst (PopCountI (LoadI mem))); effect(TEMP tmp); ins_cost(INSN_COST * 13); @@ -7748,7 +7523,7 @@ instruct popCountL(iRegINoSp dst, iRegL src, vRegD tmp) %{ ins_pipe(pipe_class_default); %} -instruct popCountL_mem(iRegINoSp dst, memory8 mem, vRegD tmp) %{ +instruct popCountL_mem(iRegINoSp dst, memory mem, vRegD tmp) %{ match(Set dst (PopCountL (LoadL mem))); effect(TEMP tmp); ins_cost(INSN_COST * 13); @@ -16897,7 +16672,7 @@ instruct compressBitsI_reg(iRegINoSp dst, iRegIorL2I src, iRegIorL2I mask, ins_pipe(pipe_slow); %} -instruct compressBitsI_memcon(iRegINoSp dst, memory4 mem, immI mask, +instruct compressBitsI_memcon(iRegINoSp dst, memory mem, immI mask, vRegF tdst, vRegF tsrc, vRegF tmask) %{ match(Set dst (CompressBits (LoadI mem) mask)); effect(TEMP tdst, TEMP tsrc, TEMP tmask); @@ -16934,7 +16709,7 @@ instruct compressBitsL_reg(iRegLNoSp dst, iRegL src, iRegL mask, ins_pipe(pipe_slow); %} -instruct compressBitsL_memcon(iRegLNoSp dst, memory8 mem, immL mask, +instruct compressBitsL_memcon(iRegLNoSp dst, memory mem, immL mask, vRegF tdst, vRegF tsrc, vRegF tmask) %{ match(Set dst (CompressBits (LoadL mem) mask)); effect(TEMP tdst, TEMP tsrc, TEMP tmask); @@ -16971,7 +16746,7 @@ instruct expandBitsI_reg(iRegINoSp dst, iRegIorL2I src, iRegIorL2I mask, ins_pipe(pipe_slow); %} -instruct expandBitsI_memcon(iRegINoSp dst, memory4 mem, immI mask, +instruct expandBitsI_memcon(iRegINoSp dst, memory mem, immI mask, vRegF tdst, vRegF tsrc, vRegF tmask) %{ match(Set dst (ExpandBits (LoadI mem) mask)); effect(TEMP tdst, TEMP tsrc, TEMP tmask); @@ -17009,7 +16784,7 @@ instruct expandBitsL_reg(iRegLNoSp dst, iRegL src, iRegL mask, %} -instruct expandBitsL_memcon(iRegINoSp dst, memory8 mem, immL mask, +instruct expandBitsL_memcon(iRegINoSp dst, memory mem, immL mask, vRegF tdst, vRegF tsrc, vRegF tmask) %{ match(Set dst (ExpandBits (LoadL mem) mask)); effect(TEMP tdst, TEMP tsrc, TEMP tmask); diff --git a/src/hotspot/cpu/aarch64/aarch64_vector.ad b/src/hotspot/cpu/aarch64/aarch64_vector.ad index 1ebc6408a60..637d3de73af 100644 --- a/src/hotspot/cpu/aarch64/aarch64_vector.ad +++ b/src/hotspot/cpu/aarch64/aarch64_vector.ad @@ -345,7 +345,7 @@ source %{ // ------------------------------ Vector load/store ---------------------------- // Load Vector (16 bits) -instruct loadV2(vReg dst, vmem2 mem) %{ +instruct loadV2(vReg dst, vmem mem) %{ predicate(n->as_LoadVector()->memory_size() == 2); match(Set dst (LoadVector mem)); format %{ "loadV2 $dst, $mem\t# vector (16 bits)" %} @@ -354,7 +354,7 @@ instruct loadV2(vReg dst, vmem2 mem) %{ %} // Store Vector (16 bits) -instruct storeV2(vReg src, vmem2 mem) %{ +instruct storeV2(vReg src, vmem mem) %{ predicate(n->as_StoreVector()->memory_size() == 2); match(Set mem (StoreVector mem src)); format %{ "storeV2 $mem, $src\t# vector (16 bits)" %} @@ -363,7 +363,7 @@ instruct storeV2(vReg src, vmem2 mem) %{ %} // Load Vector (32 bits) -instruct loadV4(vReg dst, vmem4 mem) %{ +instruct loadV4(vReg dst, vmem mem) %{ predicate(n->as_LoadVector()->memory_size() == 4); match(Set dst (LoadVector mem)); format %{ "loadV4 $dst, $mem\t# vector (32 bits)" %} @@ -372,7 +372,7 @@ instruct loadV4(vReg dst, vmem4 mem) %{ %} // Store Vector (32 bits) -instruct storeV4(vReg src, vmem4 mem) %{ +instruct storeV4(vReg src, vmem mem) %{ predicate(n->as_StoreVector()->memory_size() == 4); match(Set mem (StoreVector mem src)); format %{ "storeV4 $mem, $src\t# vector (32 bits)" %} @@ -381,7 +381,7 @@ instruct storeV4(vReg src, vmem4 mem) %{ %} // Load Vector (64 bits) -instruct loadV8(vReg dst, vmem8 mem) %{ +instruct loadV8(vReg dst, vmem mem) %{ predicate(n->as_LoadVector()->memory_size() == 8); match(Set dst (LoadVector mem)); format %{ "loadV8 $dst, $mem\t# vector (64 bits)" %} @@ -390,7 +390,7 @@ instruct loadV8(vReg dst, vmem8 mem) %{ %} // Store Vector (64 bits) -instruct storeV8(vReg src, vmem8 mem) %{ +instruct storeV8(vReg src, vmem mem) %{ predicate(n->as_StoreVector()->memory_size() == 8); match(Set mem (StoreVector mem src)); format %{ "storeV8 $mem, $src\t# vector (64 bits)" %} @@ -399,7 +399,7 @@ instruct storeV8(vReg src, vmem8 mem) %{ %} // Load Vector (128 bits) -instruct loadV16(vReg dst, vmem16 mem) %{ +instruct loadV16(vReg dst, vmem mem) %{ predicate(n->as_LoadVector()->memory_size() == 16); match(Set dst (LoadVector mem)); format %{ "loadV16 $dst, $mem\t# vector (128 bits)" %} @@ -408,7 +408,7 @@ instruct loadV16(vReg dst, vmem16 mem) %{ %} // Store Vector (128 bits) -instruct storeV16(vReg src, vmem16 mem) %{ +instruct storeV16(vReg src, vmem mem) %{ predicate(n->as_StoreVector()->memory_size() == 16); match(Set mem (StoreVector mem src)); format %{ "storeV16 $mem, $src\t# vector (128 bits)" %} diff --git a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 index 29f92772368..b3403ec82a1 100644 --- a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 +++ b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 @@ -338,7 +338,7 @@ dnl VECTOR_LOAD_STORE($1, $2, $3, $4, $5 ) dnl VECTOR_LOAD_STORE(type, nbytes, arg_name, nbits, size) define(`VECTOR_LOAD_STORE', ` // ifelse(load, $1, Load, Store) Vector ($4 bits) -instruct $1V$2(vReg $3, vmem$2 mem) %{ +instruct $1V$2(vReg $3, vmem mem) %{ predicate(`n->as_'ifelse(load, $1, Load, Store)Vector()->memory_size() == $2); match(Set ifelse(load, $1, dst (LoadVector mem), mem (StoreVector mem src))); format %{ "$1V$2 ifelse(load, $1, `$dst, $mem', `$mem, $src')\t# vector ($4 bits)" %} diff --git a/src/hotspot/cpu/aarch64/ad_encode.m4 b/src/hotspot/cpu/aarch64/ad_encode.m4 index 008dbd2c936..e3d8ea661b6 100644 --- a/src/hotspot/cpu/aarch64/ad_encode.m4 +++ b/src/hotspot/cpu/aarch64/ad_encode.m4 @@ -34,7 +34,7 @@ define(access, ` define(load,` // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_$2($1 dst, memory$5 mem) %{dnl + enc_class aarch64_enc_$2($1 dst, memory mem) %{dnl access(dst,$2,$3,$4,$5)')dnl load(iRegI,ldrsbw,,,1) load(iRegI,ldrsb,,,1) @@ -53,12 +53,12 @@ load(vRegD,ldrd,Float,,8) define(STORE,` // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_$2($1 src, memory$5 mem) %{dnl + enc_class aarch64_enc_$2($1 src, memory mem) %{dnl access(src,$2,$3,$4,$5)')dnl define(STORE0,` // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_$2`'0(memory$4 mem) %{ + enc_class aarch64_enc_$2`'0(memory mem) %{ choose(masm,zr,$2,$mem->opcode(), as_$3Register($mem$$base),$mem$$index,$mem$$scale,$mem$$disp,$4)')dnl STORE(iRegI,strb,,,1) @@ -82,7 +82,7 @@ STORE(vRegD,strd,Float,,8) // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strb0_ordered(memory4 mem) %{ + enc_class aarch64_enc_strb0_ordered(memory mem) %{ __ membar(Assembler::StoreStore); loadStore(masm, &MacroAssembler::strb, zr, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); diff --git a/src/hotspot/cpu/aarch64/gc/x/x_aarch64.ad b/src/hotspot/cpu/aarch64/gc/x/x_aarch64.ad index 6e401724baa..5e690a8e47b 100644 --- a/src/hotspot/cpu/aarch64/gc/x/x_aarch64.ad +++ b/src/hotspot/cpu/aarch64/gc/x/x_aarch64.ad @@ -51,7 +51,7 @@ static void x_load_barrier_slow_path(MacroAssembler* masm, const MachNode* node, %} // Load Pointer -instruct xLoadP(iRegPNoSp dst, memory8 mem, rFlagsReg cr) +instruct xLoadP(iRegPNoSp dst, memory mem, rFlagsReg cr) %{ match(Set dst (LoadP mem)); predicate(UseZGC && !ZGenerational && !needs_acquiring_load(n) && (n->as_Load()->barrier_data() != 0)); diff --git a/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad b/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad index 56d45384779..1510b42bfe9 100644 --- a/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad +++ b/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad @@ -100,7 +100,7 @@ static void z_store_barrier(MacroAssembler* masm, const MachNode* node, Address %} // Load Pointer -instruct zLoadP(iRegPNoSp dst, memory8 mem, rFlagsReg cr) +instruct zLoadP(iRegPNoSp dst, memory mem, rFlagsReg cr) %{ match(Set dst (LoadP mem)); predicate(UseZGC && ZGenerational && !needs_acquiring_load(n) && n->as_Load()->barrier_data() != 0); diff --git a/test/hotspot/jtreg/compiler/c2/TestUnalignedAccess.java b/test/hotspot/jtreg/compiler/c2/TestUnalignedAccess.java index d05dbad4a73..033ea49e609 100644 --- a/test/hotspot/jtreg/compiler/c2/TestUnalignedAccess.java +++ b/test/hotspot/jtreg/compiler/c2/TestUnalignedAccess.java @@ -46,20 +46,11 @@ public class TestUnalignedAccess { static final Unsafe UNSAFE = Unsafe.getUnsafe(); static void sink(int x) {} - public static long lseed = 1; - public static int iseed = 2; - public static short sseed = 3; - public static byte bseed = 4; - public static long lres = lseed; - public static int ires = iseed; - public static short sres = sseed; - public static byte bres = bseed; - public static class TestLong { private static final byte[] BYTES = new byte[LEN]; private static final long rawdata = 0xbeef; - private static final long data; + private static final long lseed = 1; static { sink(2); @@ -69,13 +60,10 @@ public static class TestLong { // 1030 can't be encoded as "base + offset" mode into the instruction field. UNSAFE.putLongUnaligned(BYTES, 1030, rawdata); - lres += UNSAFE.getLongUnaligned(BYTES, 1030); // 127 can be encoded into simm9 field. - UNSAFE.putLongUnaligned(BYTES, 127, lres); - lres += UNSAFE.getLongUnaligned(BYTES, 127); + UNSAFE.putLongUnaligned(BYTES, 127, rawdata+lseed); // 1096 can be encoded into uimm12 field. - UNSAFE.putLongUnaligned(BYTES, 1096, lres); - data = UNSAFE.getLongUnaligned(BYTES, 1096); + UNSAFE.putLongUnaligned(BYTES, 1096, rawdata-lseed); } } @@ -84,7 +72,7 @@ public static class TestInt { private static final byte[] BYTES = new byte[LEN]; private static final int rawdata = 0xbeef; - private static final int data; + private static final int iseed = 2; static { sink(2); // Signed immediate byte offset: range -256 to 255 @@ -93,13 +81,10 @@ public static class TestInt { // 274 can't be encoded as "base + offset" mode into the instruction field. UNSAFE.putIntUnaligned(BYTES, 274, rawdata); - ires += UNSAFE.getIntUnaligned(BYTES, 274); // 255 can be encoded into simm9 field. - UNSAFE.putIntUnaligned(BYTES, 255, ires); - ires += UNSAFE.getIntUnaligned(BYTES, 255); + UNSAFE.putIntUnaligned(BYTES, 255, rawdata + iseed); // 528 can be encoded into uimm12 field. - UNSAFE.putIntUnaligned(BYTES, 528, ires); - data = UNSAFE.getIntUnaligned(BYTES, 528); + UNSAFE.putIntUnaligned(BYTES, 528, rawdata - iseed); } } @@ -108,7 +93,7 @@ public static class TestShort { private static final byte[] BYTES = new byte[LEN]; private static final short rawdata = (short)0xbeef; - private static final short data; + private static final short sseed = 3; static { sink(2); // Signed immediate byte offset: range -256 to 255 @@ -117,13 +102,10 @@ public static class TestShort { // 257 can't be encoded as "base + offset" mode into the instruction field. UNSAFE.putShortUnaligned(BYTES, 257, rawdata); - sres = (short) (sres + UNSAFE.getShortUnaligned(BYTES, 257)); // 253 can be encoded into simm9 field. - UNSAFE.putShortUnaligned(BYTES, 253, sres); - sres = (short) (sres + UNSAFE.getShortUnaligned(BYTES, 253)); + UNSAFE.putShortUnaligned(BYTES, 253, (short) (rawdata + sseed)); // 272 can be encoded into uimm12 field. - UNSAFE.putShortUnaligned(BYTES, 272, sres); - data = UNSAFE.getShortUnaligned(BYTES, 272); + UNSAFE.putShortUnaligned(BYTES, 272, (short) (rawdata - sseed)); } } @@ -132,7 +114,7 @@ public static class TestByte { private static final byte[] BYTES = new byte[LEN]; private static final byte rawdata = (byte)0x3f; - private static final byte data; + private static final byte bseed = 4; static { sink(2); // Signed immediate byte offset: range -256 to 255 @@ -141,29 +123,34 @@ public static class TestByte { // 272 can be encoded into simm9 field. UNSAFE.putByte(BYTES, 272, rawdata); - bres = (byte) (bres + UNSAFE.getByte(BYTES, 272)); // 53 can be encoded into simm9 field. - UNSAFE.putByte(BYTES, 53, bres); - bres = (byte) (bres + UNSAFE.getByte(BYTES, 53)); + UNSAFE.putByte(BYTES, 53, (byte) (rawdata + bseed)); // 1027 can be encoded into uimm12 field. - UNSAFE.putByte(BYTES, 1027, bres); - data = UNSAFE.getByte(BYTES, 1027); + UNSAFE.putByte(BYTES, 1027, (byte) (rawdata - bseed)); } } static void test() { TestLong ta = new TestLong(); - Asserts.assertEquals(ta.data, (ta.rawdata + lseed) * 2, "putUnaligned long failed!"); + Asserts.assertEquals(UNSAFE.getLongUnaligned(ta.BYTES, 1030), ta.rawdata, "putUnaligned long failed!"); + Asserts.assertEquals(UNSAFE.getLongUnaligned(ta.BYTES, 127), ta.rawdata + ta.lseed, "putUnaligned long failed!"); + Asserts.assertEquals(UNSAFE.getLongUnaligned(ta.BYTES, 1096), ta.rawdata - ta.lseed, "putUnaligned long failed!"); TestInt tb = new TestInt(); - Asserts.assertEquals(tb.data, (tb.rawdata + iseed) * 2, "putUnaligned int failed!"); + Asserts.assertEquals(UNSAFE.getIntUnaligned(tb.BYTES, 274), tb.rawdata, "putUnaligned int failed!"); + Asserts.assertEquals(UNSAFE.getIntUnaligned(tb.BYTES, 255), tb.rawdata + tb.iseed, "putUnaligned int failed!"); + Asserts.assertEquals(UNSAFE.getIntUnaligned(tb.BYTES, 528), tb.rawdata - tb.iseed, "putUnaligned int failed!"); TestShort tc = new TestShort(); - Asserts.assertEquals(tc.data, (short) (((short) (tc.rawdata + sseed)) * 2), "putUnaligned short failed!"); + Asserts.assertEquals(UNSAFE.getShortUnaligned(tc.BYTES, 257), tc.rawdata, "putUnaligned short failed!"); + Asserts.assertEquals(UNSAFE.getShortUnaligned(tc.BYTES, 253), (short) (tc.rawdata + tc.sseed), "putUnaligned short failed!"); + Asserts.assertEquals(UNSAFE.getShortUnaligned(tc.BYTES, 272), (short) (tc.rawdata - tc.sseed), "putUnaligned short failed!"); TestByte td = new TestByte(); - Asserts.assertEquals(td.data, (byte) (((byte) (td.rawdata + bseed)) * 2), "put byte failed!"); + Asserts.assertEquals(UNSAFE.getByte(td.BYTES, 272), td.rawdata, "put byte failed!"); + Asserts.assertEquals(UNSAFE.getByte(td.BYTES, 53), (byte) (td.rawdata + td.bseed), "put byte failed!"); + Asserts.assertEquals(UNSAFE.getByte(td.BYTES, 1027), (byte) (td.rawdata - td.bseed), "put byte failed!"); } public static void main(String[] strArr) { From 6169613d9f3f0bf019d04a37a1d8f28f1463c17c Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Thu, 15 Aug 2024 15:34:08 +0000 Subject: [PATCH 427/460] 8336655: java/net/httpclient/DigestEchoClient.java IOException: HTTP/1.1 header parser received no bytes Reviewed-by: jpai --- .../jdk/internal/net/http/ConnectionPool.java | 36 +++++++++++++++---- .../jdk/internal/net/http/SocketTube.java | 23 ++++++++++-- .../java/net/httpclient/DigestEchoClient.java | 4 +-- 3 files changed, 52 insertions(+), 11 deletions(-) diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java b/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java index 0ad7b9d5992..edaf53a8a0d 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,6 +44,7 @@ import jdk.internal.net.http.common.Deadline; import jdk.internal.net.http.common.FlowTube; +import jdk.internal.net.http.common.Log; import jdk.internal.net.http.common.Logger; import jdk.internal.net.http.common.TimeLine; import jdk.internal.net.http.common.TimeSource; @@ -492,13 +493,13 @@ void clear() { // Remove a connection from the pool. // should only be called while holding the ConnectionPool stateLock. - private void removeFromPool(HttpConnection c) { + private boolean removeFromPool(HttpConnection c) { assert stateLock.isHeldByCurrentThread(); if (c instanceof PlainHttpConnection) { - removeFromPool(c, plainPool); + return removeFromPool(c, plainPool); } else { assert c.isSecure() : "connection " + c + " is not secure!"; - removeFromPool(c, sslPool); + return removeFromPool(c, sslPool); } } @@ -529,13 +530,29 @@ void cleanup(HttpConnection c, Throwable error) { debug.log("%s : ConnectionPool.cleanup(%s)", String.valueOf(c.getConnectionFlow()), error); stateLock.lock(); + boolean removed; try { - removeFromPool(c); + removed = removeFromPool(c); expiryList.remove(c); } finally { stateLock.unlock(); } - c.close(); + if (!removed) { + // this should not happen; the cleanup may have consumed + // some data that wasn't supposed to be consumed, so + // the only thing we can do is log it and close the + // connection. + if (Log.errors()) { + Log.logError("WARNING: CleanupTrigger triggered for" + + " a connection not found in the pool: closing {0}", c); + } else if (debug.on()) { + debug.log("WARNING: CleanupTrigger triggered for" + + " a connection not found in the pool: closing %s", c); + } + c.close(new IOException("Unexpected cleanup triggered for non pooled connection")); + } else { + c.close(); + } } /** @@ -549,6 +566,7 @@ private final class CleanupTrigger implements private final HttpConnection connection; private volatile boolean done; + private volatile boolean dropped; public CleanupTrigger(HttpConnection connection) { this.connection = connection; @@ -566,6 +584,7 @@ private void triggerCleanup(Throwable error) { @Override public void onSubscribe(Flow.Subscription subscription) { + if (dropped || done) return; subscription.request(1); } @Override @@ -586,5 +605,10 @@ public void subscribe(Flow.Subscriber> subscriber) { public String toString() { return "CleanupTrigger(" + connection.getConnectionFlow() + ")"; } + + @Override + public void dropSubscription() { + dropped = true; + } } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/SocketTube.java b/src/java.net.http/share/classes/jdk/internal/net/http/SocketTube.java index cbdf6633576..9317bdf442a 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/SocketTube.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/SocketTube.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -573,6 +573,8 @@ public void subscribe(Flow.Subscriber> s) { debug.log("read publisher: dropping pending subscriber: " + previous.subscriber); previous.errorRef.compareAndSet(null, errorRef.get()); + // make sure no data will be routed to the old subscriber. + previous.stopReading(); previous.signalOnSubscribe(); if (subscriptionImpl.completed) { previous.signalCompletion(); @@ -606,6 +608,7 @@ final class ReadSubscription implements Flow.Subscription { volatile boolean subscribed; volatile boolean cancelled; volatile boolean completed; + volatile boolean stopped; public ReadSubscription(InternalReadSubscription impl, TubeSubscriber subscriber) { @@ -623,11 +626,11 @@ public void cancel() { @Override public void request(long n) { - if (!cancelled) { + if (!cancelled && !stopped) { impl.request(n); } else { if (debug.on()) - debug.log("subscription cancelled, ignoring request %d", n); + debug.log("subscription stopped or cancelled, ignoring request %d", n); } } @@ -661,6 +664,20 @@ void signalOnSubscribe() { signalCompletion(); } } + + /** + * Called when switching subscriber on the {@link InternalReadSubscription}. + * This subscriber is the old subscriber. Demand on the internal + * subscription will be reset and reading will be paused until the + * new subscriber is subscribed. + * This should ensure that no data is routed to this subscriber + * until the new subscriber is subscribed. + */ + void stopReading() { + stopped = true; + impl.demand.reset(); + impl.pauseReadEvent(); + } } final class InternalReadSubscription implements Flow.Subscription { diff --git a/test/jdk/java/net/httpclient/DigestEchoClient.java b/test/jdk/java/net/httpclient/DigestEchoClient.java index 3b6d1a1773f..1450bf09b2d 100644 --- a/test/jdk/java/net/httpclient/DigestEchoClient.java +++ b/test/jdk/java/net/httpclient/DigestEchoClient.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,7 +64,7 @@ * @test * @summary this test verifies that a client may provides authorization * headers directly when connecting with a server. - * @bug 8087112 + * @bug 8087112 8336655 * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.common.HttpServerAdapters jdk.test.lib.net.SimpleSSLContext * DigestEchoServer ReferenceTracker DigestEchoClient From 7d1bbff076c063d066951eedb21de7e694e588b3 Mon Sep 17 00:00:00 2001 From: "lawrence.andrews" Date: Thu, 15 Aug 2024 16:36:15 +0000 Subject: [PATCH 428/460] 8328553: Get rid of JApplet in test/jdk/sanity/client/lib/SwingSet2/src/DemoModule.java Reviewed-by: honkar, prr --- .../client/lib/SwingSet2/src/DemoModule.java | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/test/jdk/sanity/client/lib/SwingSet2/src/DemoModule.java b/test/jdk/sanity/client/lib/SwingSet2/src/DemoModule.java index 3511583e932..0e7c71083dc 100644 --- a/test/jdk/sanity/client/lib/SwingSet2/src/DemoModule.java +++ b/test/jdk/sanity/client/lib/SwingSet2/src/DemoModule.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,6 @@ import javax.swing.BoxLayout; import javax.swing.Icon; import javax.swing.ImageIcon; -import javax.swing.JApplet; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.UIManager; @@ -42,10 +41,8 @@ /** * A generic SwingSet2 demo module - * - * @author Jeff Dinkins */ -public class DemoModule extends JApplet { +public class DemoModule extends JPanel { // The preferred size of the demo private int PREFERRED_WIDTH = 680; @@ -214,10 +211,6 @@ public static void main(String[] args) { demo.mainImpl(); } - public void init() { - getContentPane().setLayout(new BorderLayout()); - getContentPane().add(getDemoPanel(), BorderLayout.CENTER); - } - void updateDragEnabled(boolean dragEnabled) {} -} \ No newline at end of file +} + From ef54af39883e76c80a3e012ed91b90973da51bb4 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Thu, 15 Aug 2024 16:45:43 +0000 Subject: [PATCH 429/460] 8338444: Shenandoah: Remove ShenandoahHumongousThreshold tunable Reviewed-by: rkennke, wkemper, ysr --- .../share/gc/shenandoah/shenandoahAsserts.cpp | 2 +- .../gc/shenandoah/shenandoahController.cpp | 4 +- .../share/gc/shenandoah/shenandoahFreeSet.cpp | 5 +- .../share/gc/shenandoah/shenandoahFreeSet.hpp | 4 +- .../gc/shenandoah/shenandoahHeapRegion.cpp | 14 +- .../gc/shenandoah/shenandoahHeapRegion.hpp | 14 +- .../gc/shenandoah/shenandoahInitLogger.cpp | 1 - .../gc/shenandoah/shenandoah_globals.hpp | 7 - .../gc/shenandoah/TestHumongousThreshold.java | 131 ------------------ .../options/TestHumongousThresholdArgs.java | 72 ---------- 10 files changed, 12 insertions(+), 242 deletions(-) delete mode 100644 test/hotspot/jtreg/gc/shenandoah/TestHumongousThreshold.java delete mode 100644 test/hotspot/jtreg/gc/shenandoah/options/TestHumongousThresholdArgs.java diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp index 5215aa749ae..5abd7b805f9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp @@ -283,7 +283,7 @@ void ShenandoahAsserts::assert_in_correct_region(void* interior_loc, oop obj, co } size_t alloc_size = obj->size(); - if (alloc_size > ShenandoahHeapRegion::humongous_threshold_words()) { + if (ShenandoahHeapRegion::requires_humongous(alloc_size)) { size_t idx = r->index(); size_t num_regions = ShenandoahHeapRegion::required_regions(alloc_size * HeapWordSize); for (size_t i = idx; i < idx + num_regions; i++) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahController.cpp b/src/hotspot/share/gc/shenandoah/shenandoahController.cpp index 6d6d21c4066..effa4a8f1fc 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahController.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahController.cpp @@ -57,7 +57,7 @@ void ShenandoahController::handle_alloc_failure(ShenandoahAllocRequest& req, boo ShenandoahHeap* heap = ShenandoahHeap::heap(); assert(current()->is_Java_thread(), "expect Java thread here"); - bool is_humongous = req.size() > ShenandoahHeapRegion::humongous_threshold_words(); + bool is_humongous = ShenandoahHeapRegion::requires_humongous(req.size()); if (try_set_alloc_failure_gc(is_humongous)) { // Only report the first allocation failure @@ -80,7 +80,7 @@ void ShenandoahController::handle_alloc_failure(ShenandoahAllocRequest& req, boo void ShenandoahController::handle_alloc_failure_evac(size_t words) { ShenandoahHeap* heap = ShenandoahHeap::heap(); - bool is_humongous = (words > ShenandoahHeapRegion::region_size_words()); + bool is_humongous = ShenandoahHeapRegion::requires_humongous(words); if (try_set_alloc_failure_gc(is_humongous)) { // Only report the first allocation failure diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp index b47bb109031..3dfc6a79665 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp @@ -1308,7 +1308,7 @@ void ShenandoahFreeSet::log_status() { HeapWord* ShenandoahFreeSet::allocate(ShenandoahAllocRequest& req, bool& in_new_region) { shenandoah_assert_heaplocked(); - if (req.size() > ShenandoahHeapRegion::humongous_threshold_words()) { + if (ShenandoahHeapRegion::requires_humongous(req.size())) { switch (req.type()) { case ShenandoahAllocRequest::_alloc_shared: case ShenandoahAllocRequest::_alloc_shared_gc: @@ -1317,8 +1317,7 @@ HeapWord* ShenandoahFreeSet::allocate(ShenandoahAllocRequest& req, bool& in_new_ case ShenandoahAllocRequest::_alloc_gclab: case ShenandoahAllocRequest::_alloc_tlab: in_new_region = false; - assert(false, "Trying to allocate TLAB larger than the humongous threshold: " SIZE_FORMAT " > " SIZE_FORMAT, - req.size(), ShenandoahHeapRegion::humongous_threshold_words()); + assert(false, "Trying to allocate TLAB in humongous region: " SIZE_FORMAT, req.size()); return nullptr; default: ShouldNotReachHere(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp index 1975174b784..e4e2bb4d6e6 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp @@ -277,14 +277,14 @@ class ShenandoahFreeSet : public CHeapObj { // While holding the heap lock, allocate memory for a single object or LAB which is to be entirely contained // within a single HeapRegion as characterized by req. // - // Precondition: req.size() <= ShenandoahHeapRegion::humongous_threshold_words(). + // Precondition: !ShenandoahHeapRegion::requires_humongous(req.size()) HeapWord* allocate_single(ShenandoahAllocRequest& req, bool& in_new_region); // While holding the heap lock, allocate memory for a humongous object which spans one or more regions that // were previously empty. Regions that represent humongous objects are entirely dedicated to the humongous // object. No other objects are packed into these regions. // - // Precondition: req.size() > ShenandoahHeapRegion::humongous_threshold_words(). + // Precondition: ShenandoahHeapRegion::requires_humongous(req.size()) HeapWord* allocate_contiguous(ShenandoahAllocRequest& req); // Change region r from the Mutator partition to the GC's Collector partition. This requires that the region is entirely empty. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp index 8a94b20670a..eceed8dbe43 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp @@ -51,8 +51,6 @@ size_t ShenandoahHeapRegion::RegionSizeBytesShift = 0; size_t ShenandoahHeapRegion::RegionSizeWordsShift = 0; size_t ShenandoahHeapRegion::RegionSizeBytesMask = 0; size_t ShenandoahHeapRegion::RegionSizeWordsMask = 0; -size_t ShenandoahHeapRegion::HumongousThresholdBytes = 0; -size_t ShenandoahHeapRegion::HumongousThresholdWords = 0; size_t ShenandoahHeapRegion::MaxTLABSizeBytes = 0; size_t ShenandoahHeapRegion::MaxTLABSizeWords = 0; @@ -598,18 +596,8 @@ size_t ShenandoahHeapRegion::setup_sizes(size_t max_heap_size) { RegionCount = align_up(max_heap_size, RegionSizeBytes) / RegionSizeBytes; guarantee(RegionCount >= MIN_NUM_REGIONS, "Should have at least minimum regions"); - guarantee(HumongousThresholdWords == 0, "we should only set it once"); - HumongousThresholdWords = RegionSizeWords * ShenandoahHumongousThreshold / 100; - HumongousThresholdWords = align_down(HumongousThresholdWords, MinObjAlignment); - assert (HumongousThresholdWords <= RegionSizeWords, "sanity"); - - guarantee(HumongousThresholdBytes == 0, "we should only set it once"); - HumongousThresholdBytes = HumongousThresholdWords * HeapWordSize; - assert (HumongousThresholdBytes <= RegionSizeBytes, "sanity"); - guarantee(MaxTLABSizeWords == 0, "we should only set it once"); - MaxTLABSizeWords = MIN2(RegionSizeWords, HumongousThresholdWords); - MaxTLABSizeWords = align_down(MaxTLABSizeWords, MinObjAlignment); + MaxTLABSizeWords = align_down(RegionSizeWords, MinObjAlignment); guarantee(MaxTLABSizeBytes == 0, "we should only set it once"); MaxTLABSizeBytes = MaxTLABSizeWords * HeapWordSize; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp index c5763608582..c34c4c232e4 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp @@ -217,8 +217,6 @@ class ShenandoahHeapRegion { static size_t RegionSizeWordsShift; static size_t RegionSizeBytesMask; static size_t RegionSizeWordsMask; - static size_t HumongousThresholdBytes; - static size_t HumongousThresholdWords; static size_t MaxTLABSizeBytes; static size_t MaxTLABSizeWords; @@ -261,6 +259,10 @@ class ShenandoahHeapRegion { return (bytes + ShenandoahHeapRegion::region_size_bytes() - 1) >> ShenandoahHeapRegion::region_size_bytes_shift(); } + inline static bool requires_humongous(size_t words) { + return words > ShenandoahHeapRegion::RegionSizeWords; + } + inline static size_t region_count() { return ShenandoahHeapRegion::RegionCount; } @@ -313,14 +315,6 @@ class ShenandoahHeapRegion { return (jint)ShenandoahHeapRegion::RegionSizeWordsShift; } - inline static size_t humongous_threshold_bytes() { - return ShenandoahHeapRegion::HumongousThresholdBytes; - } - - inline static size_t humongous_threshold_words() { - return ShenandoahHeapRegion::HumongousThresholdWords; - } - inline static size_t max_tlab_size_bytes() { return ShenandoahHeapRegion::MaxTLABSizeBytes; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahInitLogger.cpp b/src/hotspot/share/gc/shenandoah/shenandoahInitLogger.cpp index db5a68d584e..baf95a5bdf7 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahInitLogger.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahInitLogger.cpp @@ -43,7 +43,6 @@ void ShenandoahInitLogger::print_heap() { log_info(gc, init)("Heap Region Count: " SIZE_FORMAT, ShenandoahHeapRegion::region_count()); log_info(gc, init)("Heap Region Size: " EXACTFMT, EXACTFMTARGS(ShenandoahHeapRegion::region_size_bytes())); log_info(gc, init)("TLAB Size Max: " EXACTFMT, EXACTFMTARGS(ShenandoahHeapRegion::max_tlab_size_bytes())); - log_info(gc, init)("Humongous Object Threshold: " EXACTFMT, EXACTFMTARGS(ShenandoahHeapRegion::humongous_threshold_bytes())); } void ShenandoahInitLogger::print_gc_specific() { diff --git a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp index 87702afe98e..c66e5839d58 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp @@ -49,13 +49,6 @@ "With automatic region sizing, the regions would be at most " \ "this large.") \ \ - product(intx, ShenandoahHumongousThreshold, 100, EXPERIMENTAL, \ - "Humongous objects are allocated in separate regions. " \ - "This setting defines how large the object should be to be " \ - "deemed humongous. Value is in percents of heap region size. " \ - "This also caps the maximum TLAB size.") \ - range(1, 100) \ - \ product(ccstr, ShenandoahGCMode, "satb", \ "GC mode to use. Among other things, this defines which " \ "barriers are in in use. Possible values are:" \ diff --git a/test/hotspot/jtreg/gc/shenandoah/TestHumongousThreshold.java b/test/hotspot/jtreg/gc/shenandoah/TestHumongousThreshold.java deleted file mode 100644 index 845a6617ebd..00000000000 --- a/test/hotspot/jtreg/gc/shenandoah/TestHumongousThreshold.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (c) 2017, 2018, 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 id=default - * @key randomness - * @requires vm.gc.Shenandoah - * @library /test/lib - * - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:+ShenandoahVerify - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=50 - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=90 - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=99 - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=100 - * TestHumongousThreshold - * - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:-UseTLAB -XX:+ShenandoahVerify - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:-UseTLAB -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=50 - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:-UseTLAB -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=90 - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:-UseTLAB -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=99 - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:-UseTLAB -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=100 - * TestHumongousThreshold - * - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:ShenandoahHumongousThreshold=90 -XX:ShenandoahGCHeuristics=aggressive - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:-UseTLAB -XX:ShenandoahHumongousThreshold=90 -XX:ShenandoahGCHeuristics=aggressive - * TestHumongousThreshold - */ - -/* - * @test id=16b - * @key randomness - * @requires vm.gc.Shenandoah - * @requires vm.bits == "64" - * @library /test/lib - * - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:ObjectAlignmentInBytes=16 -XX:+ShenandoahVerify - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:ObjectAlignmentInBytes=16 -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=50 - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:ObjectAlignmentInBytes=16 -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=90 - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:ObjectAlignmentInBytes=16 -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=99 - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:ObjectAlignmentInBytes=16 -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=100 - * TestHumongousThreshold - * - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:-UseTLAB -XX:ObjectAlignmentInBytes=16 -XX:+ShenandoahVerify - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:-UseTLAB -XX:ObjectAlignmentInBytes=16 -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=50 - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:-UseTLAB -XX:ObjectAlignmentInBytes=16 -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=90 - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:-UseTLAB -XX:ObjectAlignmentInBytes=16 -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=99 - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:-UseTLAB -XX:ObjectAlignmentInBytes=16 -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=100 - * TestHumongousThreshold - */ - -import java.util.Random; -import jdk.test.lib.Utils; - -public class TestHumongousThreshold { - - static final long TARGET_MB = Long.getLong("target", 20_000); // 20 Gb allocation - - static volatile Object sink; - - public static void main(String[] args) throws Exception { - final int min = 0; - final int max = 384 * 1024; - long count = TARGET_MB * 1024 * 1024 / (16 + 4 * (min + (max - min) / 2)); - - Random r = Utils.getRandomInstance(); - for (long c = 0; c < count; c++) { - sink = new int[min + r.nextInt(max - min)]; - } - } - -} diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestHumongousThresholdArgs.java b/test/hotspot/jtreg/gc/shenandoah/options/TestHumongousThresholdArgs.java deleted file mode 100644 index 47d4115ce74..00000000000 --- a/test/hotspot/jtreg/gc/shenandoah/options/TestHumongousThresholdArgs.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2017, 2018, 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 - * @summary Test that Shenandoah humongous threshold args are checked - * @requires vm.gc.Shenandoah - * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.management - * @run driver TestHumongousThresholdArgs - */ - -import jdk.test.lib.process.ProcessTools; -import jdk.test.lib.process.OutputAnalyzer; - -public class TestHumongousThresholdArgs { - public static void main(String[] args) throws Exception { - { - OutputAnalyzer output = ProcessTools.executeLimitedTestJava( - "-Xmx128m", - "-XX:+UnlockExperimentalVMOptions", - "-XX:+UseShenandoahGC", - "-version"); - output.shouldHaveExitValue(0); - } - - int[] valid = new int[] {1, 10, 50, 90, 100}; - int[] invalid = new int[] {-100, -1, 0, 101, 1000}; - - for (int v : valid) { - OutputAnalyzer output = ProcessTools.executeLimitedTestJava( - "-Xmx128m", - "-XX:+UnlockExperimentalVMOptions", - "-XX:+UseShenandoahGC", - "-XX:ShenandoahHumongousThreshold=" + v, - "-version"); - output.shouldHaveExitValue(0); - } - - for (int v : invalid) { - OutputAnalyzer output = ProcessTools.executeLimitedTestJava( - "-Xmx128m", - "-XX:+UnlockExperimentalVMOptions", - "-XX:+UseShenandoahGC", - "-XX:ShenandoahHumongousThreshold=" + v, - "-version"); - output.shouldHaveExitValue(1); - } - } -} From e51e40c2b9f51d012c01407e0b8dadaab464753e Mon Sep 17 00:00:00 2001 From: Satyen Subramaniam Date: Thu, 15 Aug 2024 16:47:08 +0000 Subject: [PATCH 430/460] 8336914: Shenandoah: Missing verification steps after JDK-8255765 Reviewed-by: shade --- src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index 86d6d91f72c..0301ef422a6 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -921,8 +921,11 @@ void ShenandoahConcurrentGC::op_init_updaterefs() { heap->set_evacuation_in_progress(false); heap->set_concurrent_weak_root_in_progress(false); heap->prepare_update_heap_references(true /*concurrent*/); - heap->set_update_refs_in_progress(true); + if (ShenandoahVerify) { + heap->verifier()->verify_before_updaterefs(); + } + heap->set_update_refs_in_progress(true); if (ShenandoahPacing) { heap->pacer()->setup_for_updaterefs(); } From f308b2d59672b39ddca502baff50ab20ab781047 Mon Sep 17 00:00:00 2001 From: Satyen Subramaniam Date: Thu, 15 Aug 2024 16:47:45 +0000 Subject: [PATCH 431/460] 8336915: Shenandoah: Remove unused ShenandoahVerifier::verify_after_evacuation Reviewed-by: shade --- .../share/gc/shenandoah/shenandoahVerifier.cpp | 12 ------------ .../share/gc/shenandoah/shenandoahVerifier.hpp | 1 - 2 files changed, 13 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp index 694736cea42..23da3d7f637 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp @@ -856,18 +856,6 @@ void ShenandoahVerifier::verify_during_evacuation() { ); } -void ShenandoahVerifier::verify_after_evacuation() { - verify_at_safepoint( - "After Evacuation", - _verify_forwarded_allow, // objects are still forwarded - _verify_marked_complete, // bitmaps might be stale, but alloc-after-mark should be well - _verify_cset_forwarded, // all cset refs are fully forwarded - _verify_liveness_disable, // no reliable liveness data anymore - _verify_regions_notrash, // trash regions have been recycled already - _verify_gcstate_forwarded // evacuation produced some forwarded objects - ); -} - void ShenandoahVerifier::verify_before_updaterefs() { verify_at_safepoint( "Before Updating References", diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp index 2bbe5ae68b2..dd4eb901a33 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp @@ -176,7 +176,6 @@ class ShenandoahVerifier : public CHeapObj { void verify_after_concmark(); void verify_before_evacuation(); void verify_during_evacuation(); - void verify_after_evacuation(); void verify_before_updaterefs(); void verify_after_updaterefs(); void verify_before_fullgc(); From 965508270ecd092019f7bea3a1605c5d9f19d81e Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Thu, 15 Aug 2024 17:43:09 +0000 Subject: [PATCH 432/460] 8338330: Fix -Wzero-as-null-pointer-constant warnings from THROW_XXX_0 Reviewed-by: dlong, dholmes, shade --- src/hotspot/share/prims/jvm.cpp | 2 +- src/hotspot/share/runtime/reflection.cpp | 18 +++++++++--------- src/hotspot/share/utilities/exceptions.hpp | 5 ++++- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index e40c1128966..a26a82debe7 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -3403,7 +3403,7 @@ JVM_ENTRY_NO_ENV(void*, JVM_LoadLibrary(const char* name, jboolean throwExceptio vmSymbols::java_lang_UnsatisfiedLinkError(), msg, Exceptions::unsafe_to_utf8); - THROW_HANDLE_0(h_exception); + THROW_HANDLE_NULL(h_exception); } else { log_info(library)("Failed to load library %s", name); return load_result; diff --git a/src/hotspot/share/runtime/reflection.cpp b/src/hotspot/share/runtime/reflection.cpp index 865d25fa06b..ab3d82ad7e2 100644 --- a/src/hotspot/share/runtime/reflection.cpp +++ b/src/hotspot/share/runtime/reflection.cpp @@ -1004,9 +1004,9 @@ static oop invoke(InstanceKlass* klass, // JVMTI internal flag reset is needed in order to report InvocationTargetException JvmtiExport::clear_detected_exception(THREAD); JavaCallArguments args(Handle(THREAD, resolution_exception)); - THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(), - vmSymbols::throwable_void_signature(), - &args); + THROW_ARG_NULL(vmSymbols::java_lang_reflect_InvocationTargetException(), + vmSymbols::throwable_void_signature(), + &args); } } else { // if the method can be overridden, we resolve using the vtable index. @@ -1028,9 +1028,9 @@ static oop invoke(InstanceKlass* klass, Handle h_origexception = Exceptions::new_exception(THREAD, vmSymbols::java_lang_AbstractMethodError(), ss.as_string()); JavaCallArguments args(h_origexception); - THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(), - vmSymbols::throwable_void_signature(), - &args); + THROW_ARG_NULL(vmSymbols::java_lang_reflect_InvocationTargetException(), + vmSymbols::throwable_void_signature(), + &args); } } } @@ -1117,9 +1117,9 @@ static oop invoke(InstanceKlass* klass, JvmtiExport::clear_detected_exception(THREAD); JavaCallArguments args(Handle(THREAD, target_exception)); - THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(), - vmSymbols::throwable_void_signature(), - &args); + THROW_ARG_NULL(vmSymbols::java_lang_reflect_InvocationTargetException(), + vmSymbols::throwable_void_signature(), + &args); } else { if (rtype == T_BOOLEAN || rtype == T_BYTE || rtype == T_CHAR || rtype == T_SHORT) { narrow((jvalue*)result.get_value_addr(), rtype, CHECK_NULL); diff --git a/src/hotspot/share/utilities/exceptions.hpp b/src/hotspot/share/utilities/exceptions.hpp index bddb8d79c1e..33eba68d6d9 100644 --- a/src/hotspot/share/utilities/exceptions.hpp +++ b/src/hotspot/share/utilities/exceptions.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -311,6 +311,9 @@ class Exceptions { #define THROW_NULL(name) THROW_(name, nullptr) #define THROW_MSG_NULL(name, message) THROW_MSG_(name, message, nullptr) +#define THROW_HANDLE_NULL(e) THROW_HANDLE_(e, nullptr) +#define THROW_ARG_NULL(name, signature, arg) THROW_ARG_(name, signature, arg, nullptr) + // The CATCH macro checks that no exception has been thrown by a function; it is used at // call sites about which is statically known that the callee cannot throw an exception // even though it is declared with TRAPS. From ace496515f4f91e802a51cec43d387eed61bd935 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Thu, 15 Aug 2024 17:50:34 +0000 Subject: [PATCH 433/460] 8338406: BytecodeHelpers using wrong bootstrap method descriptor for condy Reviewed-by: asotona --- .../classfile/impl/BytecodeHelpers.java | 12 +---- ...Test.java => ConstantDescSymbolsTest.java} | 52 ++++++++++++++----- 2 files changed, 41 insertions(+), 23 deletions(-) rename test/jdk/jdk/classfile/{PrimitiveClassConstantTest.java => ConstantDescSymbolsTest.java} (53%) diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java index f7aa0902bc3..474189121fd 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -275,15 +275,7 @@ static ConstantDynamicEntry handleConstantDescToHandleInfo(ConstantPoolBuilder c List staticArgs = new ArrayList<>(bootstrapArgs.length); for (ConstantDesc bootstrapArg : bootstrapArgs) staticArgs.add(constantPool.loadableConstantEntry(bootstrapArg)); - - var bootstrapDesc = desc.bootstrapMethod(); - ClassEntry bsOwner = constantPool.classEntry(bootstrapDesc.owner()); - NameAndTypeEntry bsNameAndType = constantPool.nameAndTypeEntry(bootstrapDesc.methodName(), - bootstrapDesc.invocationType()); - int bsRefKind = bootstrapDesc.refKind(); - - MemberRefEntry memberRefEntry = toBootstrapMemberRef(constantPool, bsRefKind, bsOwner, bsNameAndType, bootstrapDesc.isOwnerInterface()); - MethodHandleEntry methodHandleEntry = constantPool.methodHandleEntry(bsRefKind, memberRefEntry); + MethodHandleEntry methodHandleEntry = handleDescToHandleInfo(constantPool, desc.bootstrapMethod()); BootstrapMethodEntry bme = constantPool.bsmEntry(methodHandleEntry, staticArgs); return constantPool.constantDynamicEntry(bme, constantPool.nameAndTypeEntry(desc.constantName(), diff --git a/test/jdk/jdk/classfile/PrimitiveClassConstantTest.java b/test/jdk/jdk/classfile/ConstantDescSymbolsTest.java similarity index 53% rename from test/jdk/jdk/classfile/PrimitiveClassConstantTest.java rename to test/jdk/jdk/classfile/ConstantDescSymbolsTest.java index 89cf43751f8..7c97c9dd5a9 100644 --- a/test/jdk/jdk/classfile/PrimitiveClassConstantTest.java +++ b/test/jdk/jdk/classfile/ConstantDescSymbolsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,12 +23,14 @@ /* * @test - * @bug 8304031 - * @summary Testing that primitive class descs are encoded properly as loadable constants. - * @run junit PrimitiveClassConstantTest + * @bug 8304031 8338406 + * @summary Testing handling of various constant descriptors in ClassFile API. + * @run junit ConstantDescSymbolsTest */ import java.lang.constant.ClassDesc; +import java.lang.constant.DynamicConstantDesc; +import java.lang.constant.MethodHandleDesc; import java.lang.constant.MethodTypeDesc; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; @@ -37,18 +39,16 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import static java.lang.constant.ConstantDescs.CD_Class; -import static java.lang.constant.ConstantDescs.CD_Object; -import static java.lang.constant.ConstantDescs.CD_int; -import static java.lang.constant.ConstantDescs.CD_long; -import static java.lang.constant.ConstantDescs.INIT_NAME; -import static java.lang.constant.ConstantDescs.MTD_void; import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.constant.ConstantDescs.*; -public final class PrimitiveClassConstantTest { +import static org.junit.jupiter.api.Assertions.*; +final class ConstantDescSymbolsTest { + + // Testing that primitive class descs are encoded properly as loadable constants. @Test - public void test() throws Throwable { + void testPrimitiveClassDesc() throws Throwable { ClassDesc ape = ClassDesc.of("Ape"); var lookup = MethodHandles.lookup(); Class a = lookup.defineClass(ClassFile.of().build(ape, clb -> { @@ -73,7 +73,33 @@ public void test() throws Throwable { Supplier t = (Supplier) lookup.findConstructor(a, MethodType.methodType(void.class)) .asType(MethodType.methodType(Supplier.class)) .invokeExact(); - Assertions.assertSame(int.class, t.get()); + assertSame(int.class, t.get()); } + // Tests that condy symbols with non-static-method bootstraps are using the right lookup descriptor. + @Test + void testConstantDynamicNonStaticBootstrapMethod() throws Throwable { + record CondyBoot(MethodHandles.Lookup lookup, String name, Class type) {} + var bootClass = CondyBoot.class.describeConstable().orElseThrow(); + var bootMhDesc = MethodHandleDesc.ofConstructor(bootClass, CD_MethodHandles_Lookup, CD_String, CD_Class); + var condyDesc = DynamicConstantDesc.of(bootMhDesc); + + var targetCd = ClassDesc.of("Bat"); + var lookup = MethodHandles.lookup(); + Class a = lookup.defineClass(ClassFile.of().build(targetCd, clb -> { + clb.withInterfaceSymbols(Supplier.class.describeConstable().orElseThrow()) + .withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, cob -> cob + .aload(0).invokespecial(CD_Object, INIT_NAME, MTD_void).return_()) + .withMethodBody("get", MethodTypeDesc.of(CD_Object), ACC_PUBLIC, cob -> cob + .loadConstant(condyDesc).areturn()); + })); + @SuppressWarnings("unchecked") + Supplier t = (Supplier) lookup.findConstructor(a, MethodType.methodType(void.class)) + .asType(MethodType.methodType(Supplier.class)).invokeExact(); + var cb = t.get(); + assertEquals(MethodHandles.Lookup.ORIGINAL, cb.lookup.lookupModes() & MethodHandles.Lookup.ORIGINAL); + assertSame(a, cb.lookup.lookupClass()); + assertEquals(DEFAULT_NAME, cb.name); + assertEquals(CondyBoot.class, cb.type); + } } From 52d9d69db5c1853445a95794c5bf21243aefa852 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Thu, 15 Aug 2024 17:50:44 +0000 Subject: [PATCH 434/460] 8338331: Fix -Wzero-as-null-pointer-constant warnings from CHECK_0 in jni.cpp Reviewed-by: dholmes, shade --- src/hotspot/share/prims/jni.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index 12eba0ff623..c9357fe0216 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -1156,7 +1156,7 @@ JNI_ENTRY(ResultType, \ va_start(args, methodID); \ JavaValue jvalue(Tag); \ JNI_ArgumentPusherVaArg ap(methodID, args); \ - jni_invoke_nonstatic(env, &jvalue, obj, JNI_VIRTUAL, methodID, &ap, CHECK_0); \ + jni_invoke_nonstatic(env, &jvalue, obj, JNI_VIRTUAL, methodID, &ap, CHECK_(ResultType{})); \ va_end(args); \ ret = jvalue.get_##ResultType(); \ return ret;\ @@ -1209,7 +1209,7 @@ JNI_ENTRY(ResultType, \ \ JavaValue jvalue(Tag); \ JNI_ArgumentPusherVaArg ap(methodID, args); \ - jni_invoke_nonstatic(env, &jvalue, obj, JNI_VIRTUAL, methodID, &ap, CHECK_0); \ + jni_invoke_nonstatic(env, &jvalue, obj, JNI_VIRTUAL, methodID, &ap, CHECK_(ResultType{})); \ ret = jvalue.get_##ResultType(); \ return ret;\ JNI_END @@ -1260,7 +1260,7 @@ JNI_ENTRY(ResultType, \ \ JavaValue jvalue(Tag); \ JNI_ArgumentPusherArray ap(methodID, args); \ - jni_invoke_nonstatic(env, &jvalue, obj, JNI_VIRTUAL, methodID, &ap, CHECK_0); \ + jni_invoke_nonstatic(env, &jvalue, obj, JNI_VIRTUAL, methodID, &ap, CHECK_(ResultType{})); \ ret = jvalue.get_##ResultType(); \ return ret;\ JNI_END @@ -1353,7 +1353,7 @@ JNI_ENTRY(ResultType, \ va_start(args, methodID); \ JavaValue jvalue(Tag); \ JNI_ArgumentPusherVaArg ap(methodID, args); \ - jni_invoke_nonstatic(env, &jvalue, obj, JNI_NONVIRTUAL, methodID, &ap, CHECK_0); \ + jni_invoke_nonstatic(env, &jvalue, obj, JNI_NONVIRTUAL, methodID, &ap, CHECK_(ResultType{})); \ va_end(args); \ ret = jvalue.get_##ResultType(); \ return ret;\ @@ -1406,7 +1406,7 @@ JNI_ENTRY(ResultType, \ \ JavaValue jvalue(Tag); \ JNI_ArgumentPusherVaArg ap(methodID, args); \ - jni_invoke_nonstatic(env, &jvalue, obj, JNI_NONVIRTUAL, methodID, &ap, CHECK_0); \ + jni_invoke_nonstatic(env, &jvalue, obj, JNI_NONVIRTUAL, methodID, &ap, CHECK_(ResultType{})); \ ret = jvalue.get_##ResultType(); \ return ret;\ JNI_END @@ -1458,7 +1458,7 @@ JNI_ENTRY(ResultType, \ \ JavaValue jvalue(Tag); \ JNI_ArgumentPusherArray ap(methodID, args); \ - jni_invoke_nonstatic(env, &jvalue, obj, JNI_NONVIRTUAL, methodID, &ap, CHECK_0); \ + jni_invoke_nonstatic(env, &jvalue, obj, JNI_NONVIRTUAL, methodID, &ap, CHECK_(ResultType{})); \ ret = jvalue.get_##ResultType(); \ return ret;\ JNI_END @@ -1554,7 +1554,7 @@ JNI_ENTRY(ResultType, \ va_start(args, methodID); \ JavaValue jvalue(Tag); \ JNI_ArgumentPusherVaArg ap(methodID, args); \ - jni_invoke_static(env, &jvalue, nullptr, JNI_STATIC, methodID, &ap, CHECK_0); \ + jni_invoke_static(env, &jvalue, nullptr, JNI_STATIC, methodID, &ap, CHECK_(ResultType{})); \ va_end(args); \ ret = jvalue.get_##ResultType(); \ return ret;\ @@ -1609,8 +1609,8 @@ JNI_ENTRY(ResultType, \ JNI_ArgumentPusherVaArg ap(methodID, args); \ /* Make sure class is initialized before trying to invoke its method */ \ Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(cls)); \ - k->initialize(CHECK_0); \ - jni_invoke_static(env, &jvalue, nullptr, JNI_STATIC, methodID, &ap, CHECK_0); \ + k->initialize(CHECK_(ResultType{})); \ + jni_invoke_static(env, &jvalue, nullptr, JNI_STATIC, methodID, &ap, CHECK_(ResultType{})); \ va_end(args); \ ret = jvalue.get_##ResultType(); \ return ret;\ @@ -1663,7 +1663,7 @@ JNI_ENTRY(ResultType, \ \ JavaValue jvalue(Tag); \ JNI_ArgumentPusherArray ap(methodID, args); \ - jni_invoke_static(env, &jvalue, nullptr, JNI_STATIC, methodID, &ap, CHECK_0); \ + jni_invoke_static(env, &jvalue, nullptr, JNI_STATIC, methodID, &ap, CHECK_(ResultType{})); \ ret = jvalue.get_##ResultType(); \ return ret;\ JNI_END From 1cd488436880b00c55fa91f44c115999cf686afd Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Thu, 15 Aug 2024 18:20:20 +0000 Subject: [PATCH 435/460] 8338447: Remove InstanceKlass::_is_marked_dependent Reviewed-by: shade --- src/hotspot/share/oops/instanceKlass.hpp | 4 ---- src/hotspot/share/runtime/vmStructs.cpp | 1 - 2 files changed, 5 deletions(-) diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index 6e5d4ac8e7f..b639b820d10 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -225,10 +225,6 @@ class InstanceKlass: public Klass { volatile u2 _idnum_allocated_count; // JNI/JVMTI: increments with the addition of methods, old ids don't change - // _is_marked_dependent can be set concurrently, thus cannot be part of the - // _misc_flags. - bool _is_marked_dependent; // used for marking during flushing and deoptimization - // Class states are defined as ClassState (see above). // Place the _init_state here to utilize the unused 2-byte after // _idnum_allocated_count. diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 27dc10d2adb..913f988e48b 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -246,7 +246,6 @@ nonstatic_field(InstanceKlass, _nonstatic_oop_map_size, int) \ volatile_nonstatic_field(InstanceKlass, _init_state, InstanceKlass::ClassState) \ volatile_nonstatic_field(InstanceKlass, _init_thread, JavaThread*) \ - nonstatic_field(InstanceKlass, _is_marked_dependent, bool) \ nonstatic_field(InstanceKlass, _itable_len, int) \ nonstatic_field(InstanceKlass, _nest_host_index, u2) \ nonstatic_field(InstanceKlass, _reference_type, u1) \ From d86e99c3ca94ee8705e44fe2830edd3ceb0a7f64 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Thu, 15 Aug 2024 20:52:07 +0000 Subject: [PATCH 436/460] 8293650: Shenandoah: Support archived heap objects Reviewed-by: rkennke, wkemper, iklam --- src/hotspot/share/cds/archiveHeapWriter.hpp | 12 +-- src/hotspot/share/cds/filemap.cpp | 2 +- .../share/gc/shenandoah/shenandoahAsserts.cpp | 14 ++- .../share/gc/shenandoah/shenandoahHeap.cpp | 78 ++++++++++++++++ .../share/gc/shenandoah/shenandoahHeap.hpp | 6 ++ .../gc/shenandoah/shenandoahHeapRegion.cpp | 6 +- .../cds/appcds/TestShenandoahWithCDS.java | 89 +++++++++++++++++++ 7 files changed, 195 insertions(+), 12 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/TestShenandoahWithCDS.java diff --git a/src/hotspot/share/cds/archiveHeapWriter.hpp b/src/hotspot/share/cds/archiveHeapWriter.hpp index 99d5294007f..352aeb9a08f 100644 --- a/src/hotspot/share/cds/archiveHeapWriter.hpp +++ b/src/hotspot/share/cds/archiveHeapWriter.hpp @@ -112,6 +112,12 @@ class ArchiveHeapWriter : AllStatic { public: static const intptr_t NOCOOPS_REQUESTED_BASE = 0x10000000; + // The minimum region size of all collectors that are supported by CDS in + // ArchiveHeapLoader::can_map() mode. Currently only G1 is supported. G1's region size + // depends on -Xmx, but can never be smaller than 1 * M. + // (TODO: Perhaps change to 256K to be compatible with Shenandoah) + static constexpr int MIN_GC_REGION_ALIGNMENT = 1 * M; + private: class EmbeddedOopRelocator; struct NativePointerInfo { @@ -119,12 +125,6 @@ class ArchiveHeapWriter : AllStatic { int _field_offset; }; - // The minimum region size of all collectors that are supported by CDS in - // ArchiveHeapLoader::can_map() mode. Currently only G1 is supported. G1's region size - // depends on -Xmx, but can never be smaller than 1 * M. - // (TODO: Perhaps change to 256K to be compatible with Shenandoah) - static constexpr int MIN_GC_REGION_ALIGNMENT = 1 * M; - static GrowableArrayCHeap* _buffer; // The number of bytes that have written into _buffer (may be smaller than _buffer->length()). diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index c5a9d5cceed..dc6c7ea097c 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -2025,7 +2025,7 @@ void FileMapInfo::map_or_load_heap_region() { // TODO - remove implicit knowledge of G1 log_info(cds)("Cannot use CDS heap data. UseG1GC is required for -XX:-UseCompressedOops"); } else { - log_info(cds)("Cannot use CDS heap data. UseEpsilonGC, UseG1GC, UseSerialGC or UseParallelGC are required."); + log_info(cds)("Cannot use CDS heap data. UseEpsilonGC, UseG1GC, UseSerialGC, UseParallelGC, or UseShenandoahGC are required."); } } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp index 5abd7b805f9..8235b59b80e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp @@ -254,7 +254,7 @@ void ShenandoahAsserts::assert_correct(void* interior_loc, oop obj, const char* // Do additional checks for special objects: their fields can hold metadata as well. // We want to check class loading/unloading did not corrupt them. - if (java_lang_Class::is_instance(obj)) { + if (Universe::is_fully_initialized() && java_lang_Class::is_instance(obj)) { Metadata* klass = obj->metadata_field(java_lang_Class::klass_offset()); if (klass != nullptr && !Metaspace::contains(klass)) { print_failure(_safe_all, obj, interior_loc, nullptr, "Shenandoah assert_correct failed", @@ -283,10 +283,12 @@ void ShenandoahAsserts::assert_in_correct_region(void* interior_loc, oop obj, co } size_t alloc_size = obj->size(); + HeapWord* obj_end = cast_from_oop(obj) + alloc_size; + if (ShenandoahHeapRegion::requires_humongous(alloc_size)) { size_t idx = r->index(); - size_t num_regions = ShenandoahHeapRegion::required_regions(alloc_size * HeapWordSize); - for (size_t i = idx; i < idx + num_regions; i++) { + size_t end_idx = heap->heap_region_index_containing(obj_end - 1); + for (size_t i = idx; i < end_idx; i++) { ShenandoahHeapRegion* chain_reg = heap->get_region(i); if (i == idx && !chain_reg->is_humongous_start()) { print_failure(_safe_unknown, obj, interior_loc, nullptr, "Shenandoah assert_in_correct_region failed", @@ -299,6 +301,12 @@ void ShenandoahAsserts::assert_in_correct_region(void* interior_loc, oop obj, co file, line); } } + } else { + if (obj_end > r->top()) { + print_failure(_safe_unknown, obj, interior_loc, nullptr, "Shenandoah assert_in_correct_region failed", + "Object end should be within the active area of the region", + file, line); + } } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 7904cd5f1cd..6f5fce53f85 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -72,6 +72,7 @@ #include "gc/shenandoah/shenandoahJfrSupport.hpp" #endif +#include "cds/archiveHeapWriter.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" #include "memory/classLoaderMetaspace.hpp" @@ -2482,3 +2483,80 @@ bool ShenandoahHeap::requires_barriers(stackChunkOop obj) const { return false; } + +HeapWord* ShenandoahHeap::allocate_loaded_archive_space(size_t size) { +#if INCLUDE_CDS_JAVA_HEAP + // CDS wants a continuous memory range to load a bunch of objects. + // This effectively bypasses normal allocation paths, and requires + // a bit of massaging to unbreak GC invariants. + + ShenandoahAllocRequest req = ShenandoahAllocRequest::for_shared(size); + + // Easy case: a single regular region, no further adjustments needed. + if (!ShenandoahHeapRegion::requires_humongous(size)) { + return allocate_memory(req); + } + + // Hard case: the requested size would cause a humongous allocation. + // We need to make sure it looks like regular allocation to the rest of GC. + + // CDS code would guarantee no objects straddle multiple regions, as long as + // regions are as large as MIN_GC_REGION_ALIGNMENT. It is impractical at this + // point to deal with case when Shenandoah runs with smaller regions. + // TODO: This check can be dropped once MIN_GC_REGION_ALIGNMENT agrees more with Shenandoah. + if (ShenandoahHeapRegion::region_size_bytes() < ArchiveHeapWriter::MIN_GC_REGION_ALIGNMENT) { + return nullptr; + } + + HeapWord* mem = allocate_memory(req); + size_t start_idx = heap_region_index_containing(mem); + size_t num_regions = ShenandoahHeapRegion::required_regions(size * HeapWordSize); + + // Flip humongous -> regular. + { + ShenandoahHeapLocker locker(lock(), false); + for (size_t c = start_idx; c < start_idx + num_regions; c++) { + get_region(c)->make_regular_bypass(); + } + } + + return mem; +#else + assert(false, "Archive heap loader should not be available, should not be here"); + return nullptr; +#endif // INCLUDE_CDS_JAVA_HEAP +} + +void ShenandoahHeap::complete_loaded_archive_space(MemRegion archive_space) { + // Nothing to do here, except checking that heap looks fine. +#ifdef ASSERT + HeapWord* start = archive_space.start(); + HeapWord* end = archive_space.end(); + + // No unclaimed space between the objects. + // Objects are properly allocated in correct regions. + HeapWord* cur = start; + while (cur < end) { + oop oop = cast_to_oop(cur); + shenandoah_assert_in_correct_region(nullptr, oop); + cur += oop->size(); + } + + // No unclaimed tail at the end of archive space. + assert(cur == end, + "Archive space should be fully used: " PTR_FORMAT " " PTR_FORMAT, + p2i(cur), p2i(end)); + + // Region bounds are good. + ShenandoahHeapRegion* begin_reg = heap_region_containing(start); + ShenandoahHeapRegion* end_reg = heap_region_containing(end); + assert(begin_reg->is_regular(), "Must be"); + assert(end_reg->is_regular(), "Must be"); + assert(begin_reg->bottom() == start, + "Must agree: archive-space-start: " PTR_FORMAT ", begin-region-bottom: " PTR_FORMAT, + p2i(start), p2i(begin_reg->bottom())); + assert(end_reg->top() == end, + "Must agree: archive-space-end: " PTR_FORMAT ", end-region-top: " PTR_FORMAT, + p2i(end), p2i(end_reg->top())); +#endif +} diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index 86bd7b83bbe..81b1c3df6f4 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -539,6 +539,12 @@ class ShenandoahHeap : public CollectedHeap, public ShenandoahSpaceInfo { void sync_pinned_region_status(); void assert_pinned_region_status() NOT_DEBUG_RETURN; +// ---------- CDS archive support + + bool can_load_archived_objects() const override { return UseCompressedOops; } + HeapWord* allocate_loaded_archive_space(size_t size) override; + void complete_loaded_archive_space(MemRegion archive_space) override; + // ---------- Allocation support // private: diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp index eceed8dbe43..92602871ccd 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp @@ -100,8 +100,10 @@ void ShenandoahHeapRegion::make_regular_allocation() { void ShenandoahHeapRegion::make_regular_bypass() { shenandoah_assert_heaplocked(); - assert (ShenandoahHeap::heap()->is_full_gc_in_progress() || ShenandoahHeap::heap()->is_degenerated_gc_in_progress(), - "only for full or degen GC"); + assert (!Universe::is_fully_initialized() || + ShenandoahHeap::heap()->is_full_gc_in_progress() || + ShenandoahHeap::heap()->is_degenerated_gc_in_progress(), + "Only for STW GC or when Universe is initializing (CDS)"); switch (_state) { case _empty_uncommitted: diff --git a/test/hotspot/jtreg/runtime/cds/appcds/TestShenandoahWithCDS.java b/test/hotspot/jtreg/runtime/cds/appcds/TestShenandoahWithCDS.java new file mode 100644 index 00000000000..83442c1e159 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/TestShenandoahWithCDS.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8293650 + * @requires vm.cds + * @requires vm.bits == 64 + * @requires vm.gc.Shenandoah + * @requires vm.gc.G1 + * @requires vm.gc == null + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds + * @compile test-classes/Hello.java + * @run driver TestShenandoahWithCDS + */ + +import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; + +public class TestShenandoahWithCDS { + public final static String HELLO = "Hello World"; + static String helloJar; + + public static void main(String... args) throws Exception { + helloJar = JarBuilder.build("hello", "Hello"); + + // Run with the variety of region sizes, and combinations + // of G1/Shenandoah at dump/exec times. "-1" means to use G1. + final int[] regionSizes = { -1, 256, 512, 1024, 2048 }; + + for (int dumpRegionSize : regionSizes) { + for (int execRegionSize : regionSizes) { + test(dumpRegionSize, execRegionSize); + } + } + } + + static void test(int dumpRegionSize, int execRegionSize) throws Exception { + String exp = "-XX:+UnlockExperimentalVMOptions"; + String optDumpGC = (dumpRegionSize != -1) ? "-XX:+UseShenandoahGC" : "-XX:+UseG1GC"; + String optExecGC = (execRegionSize != -1) ? "-XX:+UseShenandoahGC" : "-XX:+UseG1GC"; + String optDumpRegionSize = (dumpRegionSize != -1) ? "-XX:ShenandoahRegionSize=" + dumpRegionSize + "K" : exp; + String optExecRegionSize = (execRegionSize != -1) ? "-XX:ShenandoahRegionSize=" + execRegionSize + "K" : exp; + OutputAnalyzer out; + + System.out.println("0. Dump with " + optDumpGC + " and " + optDumpRegionSize); + out = TestCommon.dump(helloJar, + new String[] {"Hello"}, + exp, + "-Xmx1g", + optDumpGC, + optDumpRegionSize, + "-Xlog:cds"); + out.shouldContain("Dumping shared data to file:"); + out.shouldHaveExitValue(0); + + System.out.println("1. Exec with " + optExecGC + " and " + optExecRegionSize); + out = TestCommon.exec(helloJar, + exp, + "-Xmx1g", + optExecGC, + optExecRegionSize, + "-Xlog:cds", + "Hello"); + out.shouldContain(HELLO); + out.shouldHaveExitValue(0); + } +} From 74066bcca82749722e6fee57469520d418bf3430 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Thu, 15 Aug 2024 22:57:33 +0000 Subject: [PATCH 437/460] 8338409: Use record to simplify code Reviewed-by: redestad, liach --- src/java.base/share/classes/java/util/Formatter.java | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/java.base/share/classes/java/util/Formatter.java b/src/java.base/share/classes/java/util/Formatter.java index dfdb77cc6ac..1404892ff2a 100644 --- a/src/java.base/share/classes/java/util/Formatter.java +++ b/src/java.base/share/classes/java/util/Formatter.java @@ -3021,15 +3021,7 @@ interface FormatString { String toString(); } - private static class FixedString implements FormatString { - private final String s; - private final int start; - private final int end; - FixedString(String s, int start, int end) { - this.s = s; - this.start = start; - this.end = end; - } + private record FixedString(String s, int start, int end) implements FormatString { public int index() { return -2; } public void print(Formatter fmt, Object arg, Locale l) throws IOException { fmt.a.append(s, start, end); } From bd4160cea8b6b0fcf0507199ed76a12f5d0aaba9 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Fri, 16 Aug 2024 06:20:17 +0000 Subject: [PATCH 438/460] 8315884: New Object to ObjectMonitor mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Erik Österlund Co-authored-by: Stefan Karlsson Co-authored-by: Coleen Phillimore Reviewed-by: rkennke, coleenp, dcubed --- src/hotspot/cpu/aarch64/aarch64.ad | 4 +- .../cpu/aarch64/c1_MacroAssembler_aarch64.cpp | 2 +- .../cpu/aarch64/c2_MacroAssembler_aarch64.cpp | 105 +- .../cpu/aarch64/c2_MacroAssembler_aarch64.hpp | 4 +- .../cpu/aarch64/interp_masm_aarch64.cpp | 14 +- .../cpu/aarch64/macroAssembler_aarch64.cpp | 9 +- .../cpu/aarch64/macroAssembler_aarch64.hpp | 2 +- .../cpu/aarch64/sharedRuntime_aarch64.cpp | 2 +- src/hotspot/cpu/arm/interp_masm_arm.cpp | 10 +- src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp | 6 +- src/hotspot/cpu/ppc/macroAssembler_ppc.cpp | 152 +- .../cpu/riscv/c2_MacroAssembler_riscv.cpp | 114 +- src/hotspot/cpu/riscv/interp_masm_riscv.cpp | 12 +- src/hotspot/cpu/s390/interp_masm_s390.cpp | 13 +- src/hotspot/cpu/s390/macroAssembler_s390.cpp | 108 +- src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp | 14 +- src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp | 13 +- src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp | 128 +- src/hotspot/cpu/x86/interp_masm_x86.cpp | 24 +- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 19 +- src/hotspot/cpu/x86/macroAssembler_x86.hpp | 2 +- src/hotspot/cpu/x86/sharedRuntime_x86.cpp | 8 +- src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp | 3 +- src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp | 2 +- src/hotspot/cpu/zero/zeroInterpreter_zero.cpp | 36 +- src/hotspot/share/c1/c1_Runtime1.cpp | 4 +- .../share/interpreter/interpreterRuntime.cpp | 20 +- .../interpreter/zero/bytecodeInterpreter.cpp | 170 ++- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 5 +- src/hotspot/share/logging/logTag.hpp | 1 + src/hotspot/share/oops/markWord.cpp | 3 +- src/hotspot/share/oops/markWord.hpp | 13 +- src/hotspot/share/opto/c2_CodeStubs.hpp | 2 + src/hotspot/share/opto/library_call.cpp | 30 +- src/hotspot/share/prims/jvmtiEnvBase.cpp | 10 +- src/hotspot/share/runtime/arguments.cpp | 10 + src/hotspot/share/runtime/basicLock.cpp | 27 +- src/hotspot/share/runtime/basicLock.hpp | 34 +- .../share/runtime/basicLock.inline.hpp | 62 + src/hotspot/share/runtime/deoptimization.cpp | 34 +- src/hotspot/share/runtime/globals.hpp | 11 + src/hotspot/share/runtime/javaThread.cpp | 5 +- src/hotspot/share/runtime/javaThread.hpp | 9 + .../share/runtime/javaThread.inline.hpp | 23 + .../share/runtime/lightweightSynchronizer.cpp | 1223 +++++++++++++++++ .../share/runtime/lightweightSynchronizer.hpp | 80 ++ src/hotspot/share/runtime/lockStack.cpp | 11 + src/hotspot/share/runtime/lockStack.hpp | 33 +- .../share/runtime/lockStack.inline.hpp | 52 + src/hotspot/share/runtime/objectMonitor.cpp | 225 +-- src/hotspot/share/runtime/objectMonitor.hpp | 99 +- .../share/runtime/objectMonitor.inline.hpp | 63 +- src/hotspot/share/runtime/safepoint.cpp | 5 + src/hotspot/share/runtime/serviceThread.cpp | 19 +- src/hotspot/share/runtime/sharedRuntime.cpp | 8 +- src/hotspot/share/runtime/synchronizer.cpp | 496 +++---- src/hotspot/share/runtime/synchronizer.hpp | 17 +- .../share/runtime/synchronizer.inline.hpp | 81 ++ src/hotspot/share/runtime/vframe.cpp | 17 +- src/hotspot/share/runtime/vmStructs.cpp | 4 +- .../classes/sun/jvm/hotspot/oops/Mark.java | 10 + .../sun/jvm/hotspot/runtime/BasicLock.java | 2 +- .../jvm/hotspot/runtime/ObjectMonitor.java | 8 +- .../hotspot/runtime/ObjectSynchronizer.java | 3 + .../gtest/runtime/test_objectMonitor.cpp | 24 +- .../Monitor/UseObjectMonitorTableTest.java | 244 ++++ .../runtime/logging/MonitorInflationTest.java | 2 +- .../org/openjdk/bench/vm/lang/LockUnlock.java | 190 ++- 68 files changed, 3284 insertions(+), 911 deletions(-) create mode 100644 src/hotspot/share/runtime/basicLock.inline.hpp create mode 100644 src/hotspot/share/runtime/lightweightSynchronizer.cpp create mode 100644 src/hotspot/share/runtime/lightweightSynchronizer.hpp create mode 100644 src/hotspot/share/runtime/synchronizer.inline.hpp create mode 100644 test/hotspot/jtreg/runtime/Monitor/UseObjectMonitorTableTest.java diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index a96c47051f2..8eb2821cc57 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -15793,7 +15793,7 @@ instruct cmpFastLockLightweight(rFlagsReg cr, iRegP object, iRegP box, iRegPNoSp format %{ "fastlock $object,$box\t! kills $tmp,$tmp2,$tmp3" %} ins_encode %{ - __ fast_lock_lightweight($object$$Register, $tmp$$Register, $tmp2$$Register, $tmp3$$Register); + __ fast_lock_lightweight($object$$Register, $box$$Register, $tmp$$Register, $tmp2$$Register, $tmp3$$Register); %} ins_pipe(pipe_serial); @@ -15809,7 +15809,7 @@ instruct cmpFastUnlockLightweight(rFlagsReg cr, iRegP object, iRegP box, iRegPNo format %{ "fastunlock $object,$box\t! kills $tmp, $tmp2, $tmp3" %} ins_encode %{ - __ fast_unlock_lightweight($object$$Register, $tmp$$Register, $tmp2$$Register, $tmp3$$Register); + __ fast_unlock_lightweight($object$$Register, $box$$Register, $tmp$$Register, $tmp2$$Register, $tmp3$$Register); %} ins_pipe(pipe_serial); diff --git a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp index c0455ad1bff..89624aeffdd 100644 --- a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp @@ -81,7 +81,7 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr } if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_lock(obj, hdr, temp, rscratch2, slow_case); + lightweight_lock(disp_hdr, obj, hdr, temp, rscratch2, slow_case); } else if (LockingMode == LM_LEGACY) { Label done; // Load object header diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp index 251ea3813ff..19af03d3488 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp @@ -224,10 +224,10 @@ void C2_MacroAssembler::fast_unlock(Register objectReg, Register boxReg, Registe bind(no_count); } -void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register t1, +void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Register t1, Register t2, Register t3) { assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - assert_different_registers(obj, t1, t2, t3); + assert_different_registers(obj, box, t1, t2, t3); // Handle inflated monitor. Label inflated; @@ -236,6 +236,11 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register t1, // Finish fast lock unsuccessfully. MUST branch to with flag == NE Label slow_path; + if (UseObjectMonitorTable) { + // Clear cache in case fast locking succeeds. + str(zr, Address(box, BasicLock::object_monitor_cache_offset_in_bytes())); + } + if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(t1, obj); ldrw(t1, Address(t1, Klass::access_flags_offset())); @@ -244,6 +249,7 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register t1, } const Register t1_mark = t1; + const Register t3_t = t3; { // Lightweight locking @@ -251,7 +257,6 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register t1, Label push; const Register t2_top = t2; - const Register t3_t = t3; // Check if lock-stack is full. ldrw(t2_top, Address(rthread, JavaThread::lock_stack_top_offset())); @@ -289,26 +294,71 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register t1, { // Handle inflated monitor. bind(inflated); - // mark contains the tagged ObjectMonitor*. - const Register t1_tagged_monitor = t1_mark; - const uintptr_t monitor_tag = markWord::monitor_value; + const Register t1_monitor = t1; + + if (!UseObjectMonitorTable) { + assert(t1_monitor == t1_mark, "should be the same here"); + } else { + Label monitor_found; + + // Load cache address + lea(t3_t, Address(rthread, JavaThread::om_cache_oops_offset())); + + const int num_unrolled = 2; + for (int i = 0; i < num_unrolled; i++) { + ldr(t1, Address(t3_t)); + cmp(obj, t1); + br(Assembler::EQ, monitor_found); + increment(t3_t, in_bytes(OMCache::oop_to_oop_difference())); + } + + Label loop; + + // Search for obj in cache. + bind(loop); + + // Check for match. + ldr(t1, Address(t3_t)); + cmp(obj, t1); + br(Assembler::EQ, monitor_found); + + // Search until null encountered, guaranteed _null_sentinel at end. + increment(t3_t, in_bytes(OMCache::oop_to_oop_difference())); + cbnz(t1, loop); + // Cache Miss, NE set from cmp above, cbnz does not set flags + b(slow_path); + + bind(monitor_found); + ldr(t1_monitor, Address(t3_t, OMCache::oop_to_monitor_difference())); + } + const Register t2_owner_addr = t2; const Register t3_owner = t3; + const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast(markWord::monitor_value)); + const Address owner_address(t1_monitor, ObjectMonitor::owner_offset() - monitor_tag); + const Address recursions_address(t1_monitor, ObjectMonitor::recursions_offset() - monitor_tag); + + Label monitor_locked; // Compute owner address. - lea(t2_owner_addr, Address(t1_tagged_monitor, (in_bytes(ObjectMonitor::owner_offset()) - monitor_tag))); + lea(t2_owner_addr, owner_address); // CAS owner (null => current thread). cmpxchg(t2_owner_addr, zr, rthread, Assembler::xword, /*acquire*/ true, /*release*/ false, /*weak*/ false, t3_owner); - br(Assembler::EQ, locked); + br(Assembler::EQ, monitor_locked); // Check if recursive. cmp(t3_owner, rthread); br(Assembler::NE, slow_path); // Recursive. - increment(Address(t1_tagged_monitor, in_bytes(ObjectMonitor::recursions_offset()) - monitor_tag), 1); + increment(recursions_address, 1); + + bind(monitor_locked); + if (UseObjectMonitorTable) { + str(t1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes())); + } } bind(locked); @@ -331,13 +381,13 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register t1, // C2 uses the value of Flags (NE vs EQ) to determine the continuation. } -void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register t1, Register t2, - Register t3) { +void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register box, Register t1, + Register t2, Register t3) { assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - assert_different_registers(obj, t1, t2, t3); + assert_different_registers(obj, box, t1, t2, t3); // Handle inflated monitor. - Label inflated, inflated_load_monitor; + Label inflated, inflated_load_mark; // Finish fast unlock successfully. MUST branch to with flag == EQ Label unlocked; // Finish fast unlock unsuccessfully. MUST branch to with flag == NE @@ -349,13 +399,15 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register t1, Regis { // Lightweight unlock + Label push_and_slow_path; + // Check if obj is top of lock-stack. ldrw(t2_top, Address(rthread, JavaThread::lock_stack_top_offset())); subw(t2_top, t2_top, oopSize); ldr(t3_t, Address(rthread, t2_top)); cmp(obj, t3_t); // Top of lock stack was not obj. Must be monitor. - br(Assembler::NE, inflated_load_monitor); + br(Assembler::NE, inflated_load_mark); // Pop lock-stack. DEBUG_ONLY(str(zr, Address(rthread, t2_top));) @@ -372,7 +424,10 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register t1, Regis ldr(t1_mark, Address(obj, oopDesc::mark_offset_in_bytes())); // Check header for monitor (0b10). - tbnz(t1_mark, exact_log2(markWord::monitor_value), inflated); + // Because we got here by popping (meaning we pushed in locked) + // there will be no monitor in the box. So we need to push back the obj + // so that the runtime can fix any potential anonymous owner. + tbnz(t1_mark, exact_log2(markWord::monitor_value), UseObjectMonitorTable ? push_and_slow_path : inflated); // Try to unlock. Transition lock bits 0b00 => 0b01 assert(oopDesc::mark_offset_in_bytes() == 0, "required to avoid lea"); @@ -381,6 +436,7 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register t1, Regis /*acquire*/ false, /*release*/ true, /*weak*/ false, noreg); br(Assembler::EQ, unlocked); + bind(push_and_slow_path); // Compare and exchange failed. // Restore lock-stack and handle the unlock in runtime. DEBUG_ONLY(str(obj, Address(rthread, t2_top));) @@ -391,7 +447,7 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register t1, Regis { // Handle inflated monitor. - bind(inflated_load_monitor); + bind(inflated_load_mark); ldr(t1_mark, Address(obj, oopDesc::mark_offset_in_bytes())); #ifdef ASSERT tbnz(t1_mark, exact_log2(markWord::monitor_value), inflated); @@ -412,12 +468,19 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register t1, Regis bind(check_done); #endif - // mark contains the tagged ObjectMonitor*. - const Register t1_monitor = t1_mark; - const uintptr_t monitor_tag = markWord::monitor_value; + const Register t1_monitor = t1; + + if (!UseObjectMonitorTable) { + assert(t1_monitor == t1_mark, "should be the same here"); - // Untag the monitor. - sub(t1_monitor, t1_mark, monitor_tag); + // Untag the monitor. + add(t1_monitor, t1_mark, -(int)markWord::monitor_value); + } else { + ldr(t1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes())); + // null check with Flags == NE, no valid pointer below alignof(ObjectMonitor*) + cmp(t1_monitor, checked_cast(alignof(ObjectMonitor*))); + br(Assembler::LO, slow_path); + } const Register t2_recursions = t2; Label not_recursive; diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp index 1481f975020..43e60ae5a48 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp @@ -39,8 +39,8 @@ void fast_lock(Register object, Register box, Register tmp, Register tmp2, Register tmp3); void fast_unlock(Register object, Register box, Register tmp, Register tmp2); // Code used by cmpFastLockLightweight and cmpFastUnlockLightweight mach instructions in .ad file. - void fast_lock_lightweight(Register object, Register t1, Register t2, Register t3); - void fast_unlock_lightweight(Register object, Register t1, Register t2, Register t3); + void fast_lock_lightweight(Register object, Register box, Register t1, Register t2, Register t3); + void fast_unlock_lightweight(Register object, Register box, Register t1, Register t2, Register t3); void string_compare(Register str1, Register str2, Register cnt1, Register cnt2, Register result, diff --git a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp index ca359fea9da..117168de0c5 100644 --- a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp @@ -696,7 +696,7 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) } if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_lock(obj_reg, tmp, tmp2, tmp3, slow_case); + lightweight_lock(lock_reg, obj_reg, tmp, tmp2, tmp3, slow_case); b(count); } else if (LockingMode == LM_LEGACY) { // Load (object->mark() | 1) into swap_reg @@ -752,15 +752,9 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) bind(slow_case); // Call the runtime routine for slow case - if (LockingMode == LM_LIGHTWEIGHT) { - call_VM(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter_obj), - obj_reg); - } else { - call_VM(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), - lock_reg); - } + call_VM(noreg, + CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), + lock_reg); b(done); bind(count); diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 9dd4371cf69..ead4220add0 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -6750,9 +6750,9 @@ void MacroAssembler::double_move(VMRegPair src, VMRegPair dst, Register tmp) { // - obj: the object to be locked // - t1, t2, t3: temporary registers, will be destroyed // - slow: branched to if locking fails, absolute offset may larger than 32KB (imm14 encoding). -void MacroAssembler::lightweight_lock(Register obj, Register t1, Register t2, Register t3, Label& slow) { +void MacroAssembler::lightweight_lock(Register basic_lock, Register obj, Register t1, Register t2, Register t3, Label& slow) { assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking"); - assert_different_registers(obj, t1, t2, t3, rscratch1); + assert_different_registers(basic_lock, obj, t1, t2, t3, rscratch1); Label push; const Register top = t1; @@ -6763,6 +6763,11 @@ void MacroAssembler::lightweight_lock(Register obj, Register t1, Register t2, Re // instruction emitted as it is part of C1's null check semantics. ldr(mark, Address(obj, oopDesc::mark_offset_in_bytes())); + if (UseObjectMonitorTable) { + // Clear cache in case fast locking succeeds. + str(zr, Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes())))); + } + // Check if the lock-stack is full. ldrw(top, Address(rthread, JavaThread::lock_stack_top_offset())); cmpw(top, (unsigned)LockStack::end_offset()); diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index 3bfd6e70872..e49f0c49ef6 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -1639,7 +1639,7 @@ class MacroAssembler: public Assembler { // Code for java.lang.Thread::onSpinWait() intrinsic. void spin_wait(); - void lightweight_lock(Register obj, Register t1, Register t2, Register t3, Label& slow); + void lightweight_lock(Register basic_lock, Register obj, Register t1, Register t2, Register t3, Label& slow); void lightweight_unlock(Register obj, Register t1, Register t2, Register t3, Label& slow); private: diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index 8ce4230baa2..a4dac0ccf6d 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -1811,7 +1811,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ br(Assembler::NE, slow_path_lock); } else { assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - __ lightweight_lock(obj_reg, swap_reg, tmp, lock_tmp, slow_path_lock); + __ lightweight_lock(lock_reg, obj_reg, swap_reg, tmp, lock_tmp, slow_path_lock); } __ bind(count); __ increment(Address(rthread, JavaThread::held_monitor_count_offset())); diff --git a/src/hotspot/cpu/arm/interp_masm_arm.cpp b/src/hotspot/cpu/arm/interp_masm_arm.cpp index ba161e360be..2874abafc4f 100644 --- a/src/hotspot/cpu/arm/interp_masm_arm.cpp +++ b/src/hotspot/cpu/arm/interp_masm_arm.cpp @@ -985,15 +985,7 @@ void InterpreterMacroAssembler::lock_object(Register Rlock) { bind(slow_case); // Call the runtime routine for slow case - if (LockingMode == LM_LIGHTWEIGHT) { - // Pass oop, not lock, in fast lock case. call_VM wants R1 though. - push(R1); - mov(R1, Robj); - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter_obj), R1); - pop(R1); - } else { - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), Rlock); - } + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), Rlock); bind(done); } } diff --git a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp index cdb8a742dcd..3acee737a3a 100644 --- a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp @@ -1043,11 +1043,7 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { // None of the above fast optimizations worked so we have to get into the // slow case of monitor enter. bind(slow_case); - if (LockingMode == LM_LIGHTWEIGHT) { - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter_obj), object); - } else { - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), monitor); - } + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), monitor); b(done); // } align(32, 12); diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index f9e584a1e6b..544c0d120d0 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -2804,32 +2804,39 @@ void MacroAssembler::compiler_fast_lock_lightweight_object(ConditionRegister fla { // Handle inflated monitor. bind(inflated); - // mark contains the tagged ObjectMonitor*. - const Register tagged_monitor = mark; - const uintptr_t monitor_tag = markWord::monitor_value; - const Register owner_addr = tmp2; - - // Compute owner address. - addi(owner_addr, tagged_monitor, in_bytes(ObjectMonitor::owner_offset()) - monitor_tag); - - // CAS owner (null => current thread). - cmpxchgd(/*flag=*/flag, - /*current_value=*/t, - /*compare_value=*/(intptr_t)0, - /*exchange_value=*/R16_thread, - /*where=*/owner_addr, - MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq, - MacroAssembler::cmpxchgx_hint_acquire_lock()); - beq(flag, locked); - - // Check if recursive. - cmpd(flag, t, R16_thread); - bne(flag, slow_path); - - // Recursive. - ld(tmp1, in_bytes(ObjectMonitor::recursions_offset() - ObjectMonitor::owner_offset()), owner_addr); - addi(tmp1, tmp1, 1); - std(tmp1, in_bytes(ObjectMonitor::recursions_offset() - ObjectMonitor::owner_offset()), owner_addr); + if (!UseObjectMonitorTable) { + // mark contains the tagged ObjectMonitor*. + const Register tagged_monitor = mark; + const uintptr_t monitor_tag = markWord::monitor_value; + const Register owner_addr = tmp2; + + // Compute owner address. + addi(owner_addr, tagged_monitor, in_bytes(ObjectMonitor::owner_offset()) - monitor_tag); + + // CAS owner (null => current thread). + cmpxchgd(/*flag=*/flag, + /*current_value=*/t, + /*compare_value=*/(intptr_t)0, + /*exchange_value=*/R16_thread, + /*where=*/owner_addr, + MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq, + MacroAssembler::cmpxchgx_hint_acquire_lock()); + beq(flag, locked); + + // Check if recursive. + cmpd(flag, t, R16_thread); + bne(flag, slow_path); + + // Recursive. + ld(tmp1, in_bytes(ObjectMonitor::recursions_offset() - ObjectMonitor::owner_offset()), owner_addr); + addi(tmp1, tmp1, 1); + std(tmp1, in_bytes(ObjectMonitor::recursions_offset() - ObjectMonitor::owner_offset()), owner_addr); + } else { + // OMCache lookup not supported yet. Take the slowpath. + // Set flag to NE + crxor(flag, Assembler::equal, flag, Assembler::equal); + b(slow_path); + } } bind(locked); @@ -2943,49 +2950,56 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(ConditionRegister f bind(check_done); #endif - // mark contains the tagged ObjectMonitor*. - const Register monitor = mark; - const uintptr_t monitor_tag = markWord::monitor_value; - - // Untag the monitor. - subi(monitor, mark, monitor_tag); - - const Register recursions = tmp2; - Label not_recursive; - - // Check if recursive. - ld(recursions, in_bytes(ObjectMonitor::recursions_offset()), monitor); - addic_(recursions, recursions, -1); - blt(CCR0, not_recursive); - - // Recursive unlock. - std(recursions, in_bytes(ObjectMonitor::recursions_offset()), monitor); - crorc(CCR0, Assembler::equal, CCR0, Assembler::equal); - b(unlocked); - - bind(not_recursive); - - Label release_; - const Register t2 = tmp2; - - // Check if the entry lists are empty. - ld(t, in_bytes(ObjectMonitor::EntryList_offset()), monitor); - ld(t2, in_bytes(ObjectMonitor::cxq_offset()), monitor); - orr(t, t, t2); - cmpdi(flag, t, 0); - beq(flag, release_); - - // The owner may be anonymous and we removed the last obj entry in - // the lock-stack. This loses the information about the owner. - // Write the thread to the owner field so the runtime knows the owner. - std(R16_thread, in_bytes(ObjectMonitor::owner_offset()), monitor); - b(slow_path); - - bind(release_); - // Set owner to null. - release(); - // t contains 0 - std(t, in_bytes(ObjectMonitor::owner_offset()), monitor); + if (!UseObjectMonitorTable) { + // mark contains the tagged ObjectMonitor*. + const Register monitor = mark; + const uintptr_t monitor_tag = markWord::monitor_value; + + // Untag the monitor. + subi(monitor, mark, monitor_tag); + + const Register recursions = tmp2; + Label not_recursive; + + // Check if recursive. + ld(recursions, in_bytes(ObjectMonitor::recursions_offset()), monitor); + addic_(recursions, recursions, -1); + blt(CCR0, not_recursive); + + // Recursive unlock. + std(recursions, in_bytes(ObjectMonitor::recursions_offset()), monitor); + crorc(CCR0, Assembler::equal, CCR0, Assembler::equal); + b(unlocked); + + bind(not_recursive); + + Label release_; + const Register t2 = tmp2; + + // Check if the entry lists are empty. + ld(t, in_bytes(ObjectMonitor::EntryList_offset()), monitor); + ld(t2, in_bytes(ObjectMonitor::cxq_offset()), monitor); + orr(t, t, t2); + cmpdi(flag, t, 0); + beq(flag, release_); + + // The owner may be anonymous and we removed the last obj entry in + // the lock-stack. This loses the information about the owner. + // Write the thread to the owner field so the runtime knows the owner. + std(R16_thread, in_bytes(ObjectMonitor::owner_offset()), monitor); + b(slow_path); + + bind(release_); + // Set owner to null. + release(); + // t contains 0 + std(t, in_bytes(ObjectMonitor::owner_offset()), monitor); + } else { + // OMCache lookup not supported yet. Take the slowpath. + // Set flag to NE + crxor(flag, Assembler::equal, flag, Assembler::equal); + b(slow_path); + } } bind(unlocked); diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index d88e4bf320d..8322b35e205 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -323,25 +323,30 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register tmp1, Regis { // Handle inflated monitor. bind(inflated); - // mark contains the tagged ObjectMonitor*. - const Register tmp1_tagged_monitor = tmp1_mark; - const uintptr_t monitor_tag = markWord::monitor_value; - const Register tmp2_owner_addr = tmp2; - const Register tmp3_owner = tmp3; - - // Compute owner address. - la(tmp2_owner_addr, Address(tmp1_tagged_monitor, (in_bytes(ObjectMonitor::owner_offset()) - monitor_tag))); - - // CAS owner (null => current thread). - cmpxchg(/*addr*/ tmp2_owner_addr, /*expected*/ zr, /*new*/ xthread, Assembler::int64, - /*acquire*/ Assembler::aq, /*release*/ Assembler::relaxed, /*result*/ tmp3_owner); - beqz(tmp3_owner, locked); - - // Check if recursive. - bne(tmp3_owner, xthread, slow_path); - - // Recursive. - increment(Address(tmp1_tagged_monitor, in_bytes(ObjectMonitor::recursions_offset()) - monitor_tag), 1, tmp2, tmp3); + if (!UseObjectMonitorTable) { + // mark contains the tagged ObjectMonitor*. + const Register tmp1_tagged_monitor = tmp1_mark; + const uintptr_t monitor_tag = markWord::monitor_value; + const Register tmp2_owner_addr = tmp2; + const Register tmp3_owner = tmp3; + + // Compute owner address. + la(tmp2_owner_addr, Address(tmp1_tagged_monitor, (in_bytes(ObjectMonitor::owner_offset()) - monitor_tag))); + + // CAS owner (null => current thread). + cmpxchg(/*addr*/ tmp2_owner_addr, /*expected*/ zr, /*new*/ xthread, Assembler::int64, + /*acquire*/ Assembler::aq, /*release*/ Assembler::relaxed, /*result*/ tmp3_owner); + beqz(tmp3_owner, locked); + + // Check if recursive. + bne(tmp3_owner, xthread, slow_path); + + // Recursive. + increment(Address(tmp1_tagged_monitor, in_bytes(ObjectMonitor::recursions_offset()) - monitor_tag), 1, tmp2, tmp3); + } else { + // OMCache lookup not supported yet. Take the slowpath. + j(slow_path); + } } bind(locked); @@ -453,49 +458,54 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register tmp1, Reg bind(check_done); #endif - // mark contains the tagged ObjectMonitor*. - const Register tmp1_monitor = tmp1_mark; - const uintptr_t monitor_tag = markWord::monitor_value; + if (!UseObjectMonitorTable) { + // mark contains the tagged ObjectMonitor*. + const Register tmp1_monitor = tmp1_mark; + const uintptr_t monitor_tag = markWord::monitor_value; - // Untag the monitor. - sub(tmp1_monitor, tmp1_mark, monitor_tag); + // Untag the monitor. + sub(tmp1_monitor, tmp1_mark, monitor_tag); - const Register tmp2_recursions = tmp2; - Label not_recursive; + const Register tmp2_recursions = tmp2; + Label not_recursive; - // Check if recursive. - ld(tmp2_recursions, Address(tmp1_monitor, ObjectMonitor::recursions_offset())); - beqz(tmp2_recursions, not_recursive); + // Check if recursive. + ld(tmp2_recursions, Address(tmp1_monitor, ObjectMonitor::recursions_offset())); + beqz(tmp2_recursions, not_recursive); - // Recursive unlock. - addi(tmp2_recursions, tmp2_recursions, -1); - sd(tmp2_recursions, Address(tmp1_monitor, ObjectMonitor::recursions_offset())); - j(unlocked); + // Recursive unlock. + addi(tmp2_recursions, tmp2_recursions, -1); + sd(tmp2_recursions, Address(tmp1_monitor, ObjectMonitor::recursions_offset())); + j(unlocked); - bind(not_recursive); + bind(not_recursive); - Label release; - const Register tmp2_owner_addr = tmp2; + Label release; + const Register tmp2_owner_addr = tmp2; - // Compute owner address. - la(tmp2_owner_addr, Address(tmp1_monitor, ObjectMonitor::owner_offset())); + // Compute owner address. + la(tmp2_owner_addr, Address(tmp1_monitor, ObjectMonitor::owner_offset())); - // Check if the entry lists are empty. - ld(t0, Address(tmp1_monitor, ObjectMonitor::EntryList_offset())); - ld(tmp3_t, Address(tmp1_monitor, ObjectMonitor::cxq_offset())); - orr(t0, t0, tmp3_t); - beqz(t0, release); + // Check if the entry lists are empty. + ld(t0, Address(tmp1_monitor, ObjectMonitor::EntryList_offset())); + ld(tmp3_t, Address(tmp1_monitor, ObjectMonitor::cxq_offset())); + orr(t0, t0, tmp3_t); + beqz(t0, release); - // The owner may be anonymous and we removed the last obj entry in - // the lock-stack. This loses the information about the owner. - // Write the thread to the owner field so the runtime knows the owner. - sd(xthread, Address(tmp2_owner_addr)); - j(slow_path); + // The owner may be anonymous and we removed the last obj entry in + // the lock-stack. This loses the information about the owner. + // Write the thread to the owner field so the runtime knows the owner. + sd(xthread, Address(tmp2_owner_addr)); + j(slow_path); - bind(release); - // Set owner to null. - membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); - sd(zr, Address(tmp2_owner_addr)); + bind(release); + // Set owner to null. + membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); + sd(zr, Address(tmp2_owner_addr)); + } else { + // OMCache lookup not supported yet. Take the slowpath. + j(slow_path); + } } bind(unlocked); diff --git a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp index af6d043d1d6..17b75b30264 100644 --- a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp +++ b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp @@ -792,15 +792,9 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) bind(slow_case); // Call the runtime routine for slow case - if (LockingMode == LM_LIGHTWEIGHT) { - call_VM(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter_obj), - obj_reg); - } else { - call_VM(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), - lock_reg); - } + call_VM(noreg, + CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), + lock_reg); j(done); bind(count); diff --git a/src/hotspot/cpu/s390/interp_masm_s390.cpp b/src/hotspot/cpu/s390/interp_masm_s390.cpp index 14bb98cea6a..0b29c31ec96 100644 --- a/src/hotspot/cpu/s390/interp_masm_s390.cpp +++ b/src/hotspot/cpu/s390/interp_masm_s390.cpp @@ -1072,16 +1072,9 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { // None of the above fast optimizations worked so we have to get into the // slow case of monitor enter. bind(slow_case); - if (LockingMode == LM_LIGHTWEIGHT) { - // for lightweight locking we need to use monitorenter_obj, see interpreterRuntime.cpp - call_VM(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter_obj), - object); - } else { - call_VM(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), - monitor); - } + call_VM(noreg, + CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), + monitor); // } bind(done); diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp index 72d10ee80aa..b72b36eef53 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp @@ -6218,26 +6218,33 @@ void MacroAssembler::compiler_fast_lock_lightweight_object(Register obj, Registe { // Handle inflated monitor. bind(inflated); - // mark contains the tagged ObjectMonitor*. - const Register tagged_monitor = mark; - const Register zero = tmp2; - - // Try to CAS m->owner from null to current thread. - // If m->owner is null, then csg succeeds and sets m->owner=THREAD and CR=EQ. - // Otherwise, register zero is filled with the current owner. - z_lghi(zero, 0); - z_csg(zero, Z_thread, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), tagged_monitor); - z_bre(locked); - - // Check if recursive. - z_cgr(Z_thread, zero); // zero contains the owner from z_csg instruction - z_brne(slow_path); - - // Recursive - z_agsi(Address(tagged_monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), 1ll); - z_cgr(zero, zero); - // z_bru(locked); - // Uncomment above line in the future, for now jump address is right next to us. + if (!UseObjectMonitorTable) { + // mark contains the tagged ObjectMonitor*. + const Register tagged_monitor = mark; + const Register zero = tmp2; + + // Try to CAS m->owner from null to current thread. + // If m->owner is null, then csg succeeds and sets m->owner=THREAD and CR=EQ. + // Otherwise, register zero is filled with the current owner. + z_lghi(zero, 0); + z_csg(zero, Z_thread, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), tagged_monitor); + z_bre(locked); + + // Check if recursive. + z_cgr(Z_thread, zero); // zero contains the owner from z_csg instruction + z_brne(slow_path); + + // Recursive + z_agsi(Address(tagged_monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), 1ll); + z_cgr(zero, zero); + // z_bru(locked); + // Uncomment above line in the future, for now jump address is right next to us. + } else { + // OMCache lookup not supported yet. Take the slowpath. + // Set flag to NE + z_ltgr(obj, obj); + z_bru(slow_path); + } } BLOCK_COMMENT("} handle_inflated_monitor_lightweight_locking"); @@ -6364,42 +6371,49 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(Register obj, Regis bind(check_done); #endif // ASSERT - // mark contains the tagged ObjectMonitor*. - const Register monitor = mark; + if (!UseObjectMonitorTable) { + // mark contains the tagged ObjectMonitor*. + const Register monitor = mark; - NearLabel not_recursive; - const Register recursions = tmp2; + NearLabel not_recursive; + const Register recursions = tmp2; - // Check if recursive. - load_and_test_long(recursions, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); - z_bre(not_recursive); // if 0 then jump, it's not recursive locking + // Check if recursive. + load_and_test_long(recursions, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); + z_bre(not_recursive); // if 0 then jump, it's not recursive locking - // Recursive unlock - z_agsi(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), -1ll); - z_cgr(monitor, monitor); // set the CC to EQUAL - z_bru(unlocked); + // Recursive unlock + z_agsi(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), -1ll); + z_cgr(monitor, monitor); // set the CC to EQUAL + z_bru(unlocked); - bind(not_recursive); + bind(not_recursive); - NearLabel not_ok; - // Check if the entry lists are empty. - load_and_test_long(tmp2, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); - z_brne(not_ok); - load_and_test_long(tmp2, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); - z_brne(not_ok); + NearLabel not_ok; + // Check if the entry lists are empty. + load_and_test_long(tmp2, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); + z_brne(not_ok); + load_and_test_long(tmp2, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); + z_brne(not_ok); - z_release(); - z_stg(tmp2 /*=0*/, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), monitor); + z_release(); + z_stg(tmp2 /*=0*/, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), monitor); - z_bru(unlocked); // CC = EQ here + z_bru(unlocked); // CC = EQ here - bind(not_ok); + bind(not_ok); - // The owner may be anonymous, and we removed the last obj entry in - // the lock-stack. This loses the information about the owner. - // Write the thread to the owner field so the runtime knows the owner. - z_stg(Z_thread, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), monitor); - z_bru(slow_path); // CC = NE here + // The owner may be anonymous, and we removed the last obj entry in + // the lock-stack. This loses the information about the owner. + // Write the thread to the owner field so the runtime knows the owner. + z_stg(Z_thread, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), monitor); + z_bru(slow_path); // CC = NE here + } else { + // OMCache lookup not supported yet. Take the slowpath. + // Set flag to NE + z_ltgr(obj, obj); + z_bru(slow_path); + } } bind(unlocked); diff --git a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp index 2374324ca7c..576592d05aa 100644 --- a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp @@ -66,11 +66,13 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr if (LockingMode == LM_LIGHTWEIGHT) { #ifdef _LP64 const Register thread = r15_thread; + lightweight_lock(disp_hdr, obj, hdr, thread, tmp, slow_case); #else - const Register thread = disp_hdr; - get_thread(thread); + // Implicit null check. + movptr(hdr, Address(obj, oopDesc::mark_offset_in_bytes())); + // Lacking registers and thread on x86_32. Always take slow path. + jmp(slow_case); #endif - lightweight_lock(obj, hdr, thread, tmp, slow_case); } else if (LockingMode == LM_LEGACY) { Label done; // Load object header @@ -139,10 +141,8 @@ void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_ #ifdef _LP64 lightweight_unlock(obj, disp_hdr, r15_thread, hdr, slow_case); #else - // This relies on the implementation of lightweight_unlock being able to handle - // that the reg_rax and thread Register parameters may alias each other. - get_thread(disp_hdr); - lightweight_unlock(obj, disp_hdr, disp_hdr, hdr, slow_case); + // Lacking registers and thread on x86_32. Always take slow path. + jmp(slow_case); #endif } else if (LockingMode == LM_LEGACY) { // test if object header is pointing to the displaced header, and if so, restore diff --git a/src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp b/src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp index 6dc8d14064a..1990488d8a0 100644 --- a/src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp +++ b/src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp @@ -96,6 +96,7 @@ void C2FastUnlockLightweightStub::emit(C2_MacroAssembler& masm) { { // Restore held monitor count and slow path. __ bind(restore_held_monitor_count_and_slow_path); + __ bind(_slow_path); // Restore held monitor count. __ increment(Address(_thread, JavaThread::held_monitor_count_offset())); // increment will always result in ZF = 0 (no overflows). @@ -112,19 +113,23 @@ void C2FastUnlockLightweightStub::emit(C2_MacroAssembler& masm) { #ifndef _LP64 __ jmpb(restore_held_monitor_count_and_slow_path); #else // _LP64 + const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast(markWord::monitor_value)); + const Address succ_address(monitor, ObjectMonitor::succ_offset() - monitor_tag); + const Address owner_address(monitor, ObjectMonitor::owner_offset() - monitor_tag); + // successor null check. - __ cmpptr(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), NULL_WORD); + __ cmpptr(succ_address, NULL_WORD); __ jccb(Assembler::equal, restore_held_monitor_count_and_slow_path); // Release lock. - __ movptr(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), NULL_WORD); + __ movptr(owner_address, NULL_WORD); // Fence. // Instead of MFENCE we use a dummy locked add of 0 to the top-of-stack. __ lock(); __ addl(Address(rsp, 0), 0); // Recheck successor. - __ cmpptr(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), NULL_WORD); + __ cmpptr(succ_address, NULL_WORD); // Observed a successor after the release -> fence we have handed off the monitor __ jccb(Assembler::notEqual, fix_zf_and_unlocked); @@ -133,7 +138,7 @@ void C2FastUnlockLightweightStub::emit(C2_MacroAssembler& masm) { // not handle the monitor handoff. Currently only works // due to the responsible thread. __ xorptr(rax, rax); - __ lock(); __ cmpxchgptr(_thread, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); + __ lock(); __ cmpxchgptr(_thread, owner_address); __ jccb (Assembler::equal, restore_held_monitor_count_and_slow_path); #endif diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index faab09b7c17..5dbfdbc225d 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -590,6 +590,11 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Regist // Finish fast lock unsuccessfully. MUST jump with ZF == 0 Label slow_path; + if (UseObjectMonitorTable) { + // Clear cache in case fast locking succeeds. + movptr(Address(box, BasicLock::object_monitor_cache_offset_in_bytes()), 0); + } + if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(rax_reg, obj, t); movl(rax_reg, Address(rax_reg, Klass::access_flags_offset())); @@ -603,7 +608,7 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Regist Label push; - const Register top = box; + const Register top = UseObjectMonitorTable ? rax_reg : box; // Load the mark. movptr(mark, Address(obj, oopDesc::mark_offset_in_bytes())); @@ -630,6 +635,10 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Regist lock(); cmpxchgptr(mark, Address(obj, oopDesc::mark_offset_in_bytes())); jcc(Assembler::notEqual, slow_path); + if (UseObjectMonitorTable) { + // Need to reload top, clobbered by CAS. + movl(top, Address(thread, JavaThread::lock_stack_top_offset())); + } bind(push); // After successful lock, push object on lock-stack. movptr(Address(thread, top), obj); @@ -640,19 +649,68 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Regist { // Handle inflated monitor. bind(inflated); - const Register tagged_monitor = mark; + const Register monitor = t; + + if (!UseObjectMonitorTable) { + assert(mark == monitor, "should be the same here"); + } else { + // Uses ObjectMonitorTable. Look for the monitor in the om_cache. + // Fetch ObjectMonitor* from the cache or take the slow-path. + Label monitor_found; + + // Load cache address + lea(t, Address(thread, JavaThread::om_cache_oops_offset())); + + const int num_unrolled = 2; + for (int i = 0; i < num_unrolled; i++) { + cmpptr(obj, Address(t)); + jccb(Assembler::equal, monitor_found); + increment(t, in_bytes(OMCache::oop_to_oop_difference())); + } + + Label loop; + + // Search for obj in cache. + bind(loop); + + // Check for match. + cmpptr(obj, Address(t)); + jccb(Assembler::equal, monitor_found); + + // Search until null encountered, guaranteed _null_sentinel at end. + cmpptr(Address(t), 1); + jcc(Assembler::below, slow_path); // 0 check, but with ZF=0 when *t == 0 + increment(t, in_bytes(OMCache::oop_to_oop_difference())); + jmpb(loop); + + // Cache hit. + bind(monitor_found); + movptr(monitor, Address(t, OMCache::oop_to_monitor_difference())); + } + const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast(markWord::monitor_value)); + const Address recursions_address(monitor, ObjectMonitor::recursions_offset() - monitor_tag); + const Address owner_address(monitor, ObjectMonitor::owner_offset() - monitor_tag); + + Label monitor_locked; + // Lock the monitor. // CAS owner (null => current thread). xorptr(rax_reg, rax_reg); - lock(); cmpxchgptr(thread, Address(tagged_monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); - jccb(Assembler::equal, locked); + lock(); cmpxchgptr(thread, owner_address); + jccb(Assembler::equal, monitor_locked); // Check if recursive. cmpptr(thread, rax_reg); jccb(Assembler::notEqual, slow_path); // Recursive. - increment(Address(tagged_monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); + increment(recursions_address); + + bind(monitor_locked); + if (UseObjectMonitorTable) { + // Cache the monitor for unlock + movptr(Address(box, BasicLock::object_monitor_cache_offset_in_bytes()), monitor); + } } bind(locked); @@ -694,7 +752,9 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax, decrement(Address(thread, JavaThread::held_monitor_count_offset())); const Register mark = t; - const Register top = reg_rax; + const Register monitor = t; + const Register top = UseObjectMonitorTable ? t : reg_rax; + const Register box = reg_rax; Label dummy; C2FastUnlockLightweightStub* stub = nullptr; @@ -706,14 +766,17 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax, Label& push_and_slow_path = stub == nullptr ? dummy : stub->push_and_slow_path(); Label& check_successor = stub == nullptr ? dummy : stub->check_successor(); + Label& slow_path = stub == nullptr ? dummy : stub->slow_path(); { // Lightweight Unlock // Load top. movl(top, Address(thread, JavaThread::lock_stack_top_offset())); - // Prefetch mark. - movptr(mark, Address(obj, oopDesc::mark_offset_in_bytes())); + if (!UseObjectMonitorTable) { + // Prefetch mark. + movptr(mark, Address(obj, oopDesc::mark_offset_in_bytes())); + } // Check if obj is top of lock-stack. cmpptr(obj, Address(thread, top, Address::times_1, -oopSize)); @@ -730,6 +793,11 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax, // We elide the monitor check, let the CAS fail instead. + if (UseObjectMonitorTable) { + // Load mark. + movptr(mark, Address(obj, oopDesc::mark_offset_in_bytes())); + } + // Try to unlock. Transition lock bits 0b00 => 0b01 movptr(reg_rax, mark); andptr(reg_rax, ~(int32_t)markWord::lock_mask); @@ -751,6 +819,9 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax, jccb(Assembler::notEqual, inflated_check_lock_stack); stop("Fast Unlock lock on stack"); bind(check_done); + if (UseObjectMonitorTable) { + movptr(mark, Address(obj, oopDesc::mark_offset_in_bytes())); + } testptr(mark, markWord::monitor_value); jccb(Assembler::notZero, inflated); stop("Fast Unlock not monitor"); @@ -758,43 +829,40 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax, bind(inflated); - // mark contains the tagged ObjectMonitor*. - const Register monitor = mark; - -#ifndef _LP64 - // Check if recursive. - xorptr(reg_rax, reg_rax); - orptr(reg_rax, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); - jcc(Assembler::notZero, check_successor); - - // Check if the entry lists are empty. - movptr(reg_rax, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); - orptr(reg_rax, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); - jcc(Assembler::notZero, check_successor); + if (!UseObjectMonitorTable) { + assert(mark == monitor, "should be the same here"); + } else { + // Uses ObjectMonitorTable. Look for the monitor in our BasicLock on the stack. + movptr(monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes())); + // null check with ZF == 0, no valid pointer below alignof(ObjectMonitor*) + cmpptr(monitor, alignof(ObjectMonitor*)); + jcc(Assembler::below, slow_path); + } + const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast(markWord::monitor_value)); + const Address recursions_address{monitor, ObjectMonitor::recursions_offset() - monitor_tag}; + const Address cxq_address{monitor, ObjectMonitor::cxq_offset() - monitor_tag}; + const Address EntryList_address{monitor, ObjectMonitor::EntryList_offset() - monitor_tag}; + const Address owner_address{monitor, ObjectMonitor::owner_offset() - monitor_tag}; - // Release lock. - movptr(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), NULL_WORD); -#else // _LP64 Label recursive; // Check if recursive. - cmpptr(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), 0); + cmpptr(recursions_address, 0); jccb(Assembler::notEqual, recursive); // Check if the entry lists are empty. - movptr(reg_rax, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); - orptr(reg_rax, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); + movptr(reg_rax, cxq_address); + orptr(reg_rax, EntryList_address); jcc(Assembler::notZero, check_successor); // Release lock. - movptr(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), NULL_WORD); + movptr(owner_address, NULL_WORD); jmpb(unlocked); // Recursive unlock. bind(recursive); - decrement(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); + decrement(recursions_address); xorl(t, t); -#endif } bind(unlocked); diff --git a/src/hotspot/cpu/x86/interp_masm_x86.cpp b/src/hotspot/cpu/x86/interp_masm_x86.cpp index 57d77bafd4b..249506c13ff 100644 --- a/src/hotspot/cpu/x86/interp_masm_x86.cpp +++ b/src/hotspot/cpu/x86/interp_masm_x86.cpp @@ -1183,11 +1183,11 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) { if (LockingMode == LM_LIGHTWEIGHT) { #ifdef _LP64 const Register thread = r15_thread; + lightweight_lock(lock_reg, obj_reg, swap_reg, thread, tmp_reg, slow_case); #else - const Register thread = lock_reg; - get_thread(thread); + // Lacking registers and thread on x86_32. Always take slow path. + jmp(slow_case); #endif - lightweight_lock(obj_reg, swap_reg, thread, tmp_reg, slow_case); } else if (LockingMode == LM_LEGACY) { // Load immediate 1 into swap_reg %rax movl(swap_reg, 1); @@ -1249,15 +1249,9 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) { bind(slow_case); // Call the runtime routine for slow case - if (LockingMode == LM_LIGHTWEIGHT) { - call_VM(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter_obj), - obj_reg); - } else { - call_VM(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), - lock_reg); - } + call_VM(noreg, + CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), + lock_reg); bind(done); } } @@ -1306,10 +1300,8 @@ void InterpreterMacroAssembler::unlock_object(Register lock_reg) { #ifdef _LP64 lightweight_unlock(obj_reg, swap_reg, r15_thread, header_reg, slow_case); #else - // This relies on the implementation of lightweight_unlock being able to handle - // that the reg_rax and thread Register parameters may alias each other. - get_thread(swap_reg); - lightweight_unlock(obj_reg, swap_reg, swap_reg, header_reg, slow_case); + // Lacking registers and thread on x86_32. Always take slow path. + jmp(slow_case); #endif } else if (LockingMode == LM_LEGACY) { // Load the old header from BasicLock structure diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 78bcabb2000..a5ad19806ea 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -10275,9 +10275,9 @@ void MacroAssembler::check_stack_alignment(Register sp, const char* msg, unsigne // reg_rax: rax // thread: the thread which attempts to lock obj // tmp: a temporary register -void MacroAssembler::lightweight_lock(Register obj, Register reg_rax, Register thread, Register tmp, Label& slow) { +void MacroAssembler::lightweight_lock(Register basic_lock, Register obj, Register reg_rax, Register thread, Register tmp, Label& slow) { assert(reg_rax == rax, ""); - assert_different_registers(obj, reg_rax, thread, tmp); + assert_different_registers(basic_lock, obj, reg_rax, thread, tmp); Label push; const Register top = tmp; @@ -10286,6 +10286,11 @@ void MacroAssembler::lightweight_lock(Register obj, Register reg_rax, Register t // instruction emitted as it is part of C1's null check semantics. movptr(reg_rax, Address(obj, oopDesc::mark_offset_in_bytes())); + if (UseObjectMonitorTable) { + // Clear cache in case fast locking succeeds. + movptr(Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes()))), 0); + } + // Load top. movl(top, Address(thread, JavaThread::lock_stack_top_offset())); @@ -10324,13 +10329,9 @@ void MacroAssembler::lightweight_lock(Register obj, Register reg_rax, Register t // reg_rax: rax // thread: the thread // tmp: a temporary register -// -// x86_32 Note: reg_rax and thread may alias each other due to limited register -// availiability. void MacroAssembler::lightweight_unlock(Register obj, Register reg_rax, Register thread, Register tmp, Label& slow) { assert(reg_rax == rax, ""); - assert_different_registers(obj, reg_rax, tmp); - LP64_ONLY(assert_different_registers(obj, reg_rax, thread, tmp);) + assert_different_registers(obj, reg_rax, thread, tmp); Label unlocked, push_and_slow; const Register top = tmp; @@ -10370,10 +10371,6 @@ void MacroAssembler::lightweight_unlock(Register obj, Register reg_rax, Register bind(push_and_slow); // Restore lock-stack and handle the unlock in runtime. - if (thread == reg_rax) { - // On x86_32 we may lose the thread. - get_thread(thread); - } #ifdef ASSERT movl(top, Address(thread, JavaThread::lock_stack_top_offset())); movptr(Address(thread, top), obj); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index 2ecd2bbe96d..594f0b95ca3 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -2148,7 +2148,7 @@ class MacroAssembler: public Assembler { void check_stack_alignment(Register sp, const char* msg, unsigned bias = 0, Register tmp = noreg); - void lightweight_lock(Register obj, Register reg_rax, Register thread, Register tmp, Label& slow); + void lightweight_lock(Register basic_lock, Register obj, Register reg_rax, Register thread, Register tmp, Label& slow); void lightweight_unlock(Register obj, Register reg_rax, Register thread, Register tmp, Label& slow); #ifdef _LP64 diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86.cpp index 3ecbb43f7f5..78330962d1a 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86.cpp @@ -62,9 +62,11 @@ void SharedRuntime::inline_check_hashcode_from_object_header(MacroAssembler* mas if (LockingMode == LM_LIGHTWEIGHT) { - // check if monitor - __ testptr(result, markWord::monitor_value); - __ jcc(Assembler::notZero, slowCase); + if (!UseObjectMonitorTable) { + // check if monitor + __ testptr(result, markWord::monitor_value); + __ jcc(Assembler::notZero, slowCase); + } } else { // check if locked __ testptr(result, markWord::unlocked_value); diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp index d313c1b216a..85c9125a97d 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp @@ -1686,7 +1686,8 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ jcc(Assembler::notEqual, slow_path_lock); } else { assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - __ lightweight_lock(obj_reg, swap_reg, thread, lock_reg, slow_path_lock); + // Lacking registers and thread on x86_32. Always take slow path. + __ jmp(slow_path_lock); } __ bind(count_mon); __ inc_held_monitor_count(); diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index d27b1d141fc..b5362a9942c 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -2266,7 +2266,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ jcc(Assembler::notEqual, slow_path_lock); } else { assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - __ lightweight_lock(obj_reg, swap_reg, r15_thread, rscratch1, slow_path_lock); + __ lightweight_lock(lock_reg, obj_reg, swap_reg, r15_thread, rscratch1, slow_path_lock); } __ bind(count_mon); __ inc_held_monitor_count(); diff --git a/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp b/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp index 9e00b1c5b04..2b53042ef10 100644 --- a/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp +++ b/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp @@ -37,6 +37,7 @@ #include "oops/method.hpp" #include "oops/oop.inline.hpp" #include "prims/jvmtiExport.hpp" +#include "runtime/basicLock.inline.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" @@ -44,6 +45,7 @@ #include "runtime/timer.hpp" #include "runtime/timerTrace.hpp" #include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include "entry_zero.hpp" @@ -331,23 +333,27 @@ int ZeroInterpreter::native_entry(Method* method, intptr_t UNUSED, TRAPS) { if (method->is_synchronized()) { monitor = (BasicObjectLock*) istate->stack_base(); oop lockee = monitor->obj(); - markWord disp = lockee->mark().set_unlocked(); - monitor->lock()->set_displaced_header(disp); - bool call_vm = (LockingMode == LM_MONITOR); - bool inc_monitor_count = true; - if (call_vm || lockee->cas_set_mark(markWord::from_pointer(monitor), disp) != disp) { - // Is it simple recursive case? - if (!call_vm && thread->is_lock_owned((address) disp.clear_lock_bits().to_pointer())) { - monitor->lock()->set_displaced_header(markWord::from_pointer(nullptr)); - } else { - inc_monitor_count = false; - CALL_VM_NOCHECK(InterpreterRuntime::monitorenter(thread, monitor)); - if (HAS_PENDING_EXCEPTION) - goto unwind_and_return; + bool success = false; + if (LockingMode == LM_LEGACY) { + markWord disp = lockee->mark().set_unlocked(); + monitor->lock()->set_displaced_header(disp); + success = true; + if (lockee->cas_set_mark(markWord::from_pointer(monitor), disp) != disp) { + // Is it simple recursive case? + if (thread->is_lock_owned((address) disp.clear_lock_bits().to_pointer())) { + monitor->lock()->set_displaced_header(markWord::from_pointer(nullptr)); + } else { + success = false; + } + } + if (success) { + THREAD->inc_held_monitor_count(); } } - if (inc_monitor_count) { - THREAD->inc_held_monitor_count(); + if (!success) { + CALL_VM_NOCHECK(InterpreterRuntime::monitorenter(thread, monitor)); + if (HAS_PENDING_EXCEPTION) + goto unwind_and_return; } } diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp index 31ae3f6bee0..8524f37177b 100644 --- a/src/hotspot/share/c1/c1_Runtime1.cpp +++ b/src/hotspot/share/c1/c1_Runtime1.cpp @@ -757,8 +757,8 @@ JRT_BLOCK_ENTRY(void, Runtime1::monitorenter(JavaThread* current, oopDesc* obj, if (LockingMode == LM_MONITOR) { lock->set_obj(obj); } - assert(LockingMode == LM_LIGHTWEIGHT || obj == lock->obj(), "must match"); - SharedRuntime::monitor_enter_helper(obj, LockingMode == LM_LIGHTWEIGHT ? nullptr : lock->lock(), current); + assert(obj == lock->obj(), "must match"); + SharedRuntime::monitor_enter_helper(obj, lock->lock(), current); JRT_END diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp index 4f2eae023f6..525258b1ebd 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp @@ -71,7 +71,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/stackWatermarkSet.hpp" #include "runtime/stubRoutines.hpp" -#include "runtime/synchronizer.hpp" +#include "runtime/synchronizer.inline.hpp" #include "runtime/threadCritical.hpp" #include "utilities/align.hpp" #include "utilities/checkedCast.hpp" @@ -725,7 +725,6 @@ void InterpreterRuntime::resolve_get_put(Bytecodes::Code bytecode, int field_ind //%note monitor_1 JRT_ENTRY_NO_ASYNC(void, InterpreterRuntime::monitorenter(JavaThread* current, BasicObjectLock* elem)) - assert(LockingMode != LM_LIGHTWEIGHT, "Should call monitorenter_obj() when using the new lightweight locking"); #ifdef ASSERT current->last_frame().interpreter_frame_verify_monitor(elem); #endif @@ -740,23 +739,6 @@ JRT_ENTRY_NO_ASYNC(void, InterpreterRuntime::monitorenter(JavaThread* current, B #endif JRT_END -// NOTE: We provide a separate implementation for the new lightweight locking to workaround a limitation -// of registers in x86_32. This entry point accepts an oop instead of a BasicObjectLock*. -// The problem is that we would need to preserve the register that holds the BasicObjectLock, -// but we are using that register to hold the thread. We don't have enough registers to -// also keep the BasicObjectLock, but we don't really need it anyway, we only need -// the object. See also InterpreterMacroAssembler::lock_object(). -// As soon as legacy stack-locking goes away we could remove the other monitorenter() entry -// point, and only use oop-accepting entries (same for monitorexit() below). -JRT_ENTRY_NO_ASYNC(void, InterpreterRuntime::monitorenter_obj(JavaThread* current, oopDesc* obj)) - assert(LockingMode == LM_LIGHTWEIGHT, "Should call monitorenter() when not using the new lightweight locking"); - Handle h_obj(current, cast_to_oop(obj)); - assert(Universe::heap()->is_in_or_null(h_obj()), - "must be null or an object"); - ObjectSynchronizer::enter(h_obj, nullptr, current); - return; -JRT_END - JRT_LEAF(void, InterpreterRuntime::monitorexit(BasicObjectLock* elem)) oop obj = elem->obj(); assert(Universe::heap()->is_in(obj), "must be an object"); diff --git a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp index 36b01bb0802..fbdf8f9ca71 100644 --- a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp +++ b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp @@ -53,7 +53,9 @@ #include "prims/jvmtiExport.hpp" #include "prims/jvmtiThreadState.hpp" #include "runtime/atomic.hpp" +#include "runtime/basicLock.inline.hpp" #include "runtime/frame.inline.hpp" +#include "runtime/globals.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/orderAccess.hpp" @@ -61,6 +63,7 @@ #include "runtime/threadCritical.hpp" #include "utilities/debug.hpp" #include "utilities/exceptions.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" /* @@ -624,23 +627,28 @@ void BytecodeInterpreter::run(interpreterState istate) { BasicObjectLock* mon = &istate->monitor_base()[-1]; mon->set_obj(rcvr); - // Traditional lightweight locking. - markWord displaced = rcvr->mark().set_unlocked(); - mon->lock()->set_displaced_header(displaced); - bool call_vm = (LockingMode == LM_MONITOR); - bool inc_monitor_count = true; - if (call_vm || rcvr->cas_set_mark(markWord::from_pointer(mon), displaced) != displaced) { - // Is it simple recursive case? - if (!call_vm && THREAD->is_lock_owned((address) displaced.clear_lock_bits().to_pointer())) { - mon->lock()->set_displaced_header(markWord::from_pointer(nullptr)); - } else { - inc_monitor_count = false; - CALL_VM(InterpreterRuntime::monitorenter(THREAD, mon), handle_exception); + bool success = false; + if (LockingMode == LM_LEGACY) { + // Traditional fast locking. + markWord displaced = rcvr->mark().set_unlocked(); + mon->lock()->set_displaced_header(displaced); + success = true; + if (rcvr->cas_set_mark(markWord::from_pointer(mon), displaced) != displaced) { + // Is it simple recursive case? + if (THREAD->is_lock_owned((address) displaced.clear_lock_bits().to_pointer())) { + mon->lock()->set_displaced_header(markWord::from_pointer(nullptr)); + } else { + success = false; + } + } + if (success) { + THREAD->inc_held_monitor_count(); } } - if (inc_monitor_count) { - THREAD->inc_held_monitor_count(); + if (!success) { + CALL_VM(InterpreterRuntime::monitorenter(THREAD, mon), handle_exception); } + } THREAD->set_do_not_unlock_if_synchronized(false); @@ -723,23 +731,28 @@ void BytecodeInterpreter::run(interpreterState istate) { assert(entry->obj() == nullptr, "Frame manager didn't allocate the monitor"); entry->set_obj(lockee); - // traditional lightweight locking - markWord displaced = lockee->mark().set_unlocked(); - entry->lock()->set_displaced_header(displaced); - bool call_vm = (LockingMode == LM_MONITOR); - bool inc_monitor_count = true; - if (call_vm || lockee->cas_set_mark(markWord::from_pointer(entry), displaced) != displaced) { - // Is it simple recursive case? - if (!call_vm && THREAD->is_lock_owned((address) displaced.clear_lock_bits().to_pointer())) { - entry->lock()->set_displaced_header(markWord::from_pointer(nullptr)); - } else { - inc_monitor_count = false; - CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); + bool success = false; + if (LockingMode == LM_LEGACY) { + // Traditional fast locking. + markWord displaced = lockee->mark().set_unlocked(); + entry->lock()->set_displaced_header(displaced); + success = true; + if (lockee->cas_set_mark(markWord::from_pointer(entry), displaced) != displaced) { + // Is it simple recursive case? + if (THREAD->is_lock_owned((address) displaced.clear_lock_bits().to_pointer())) { + entry->lock()->set_displaced_header(markWord::from_pointer(nullptr)); + } else { + success = false; + } + } + if (success) { + THREAD->inc_held_monitor_count(); } } - if (inc_monitor_count) { - THREAD->inc_held_monitor_count(); + if (!success) { + CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); } + UPDATE_PC_AND_TOS(1, -1); goto run; } @@ -1653,23 +1666,28 @@ void BytecodeInterpreter::run(interpreterState istate) { if (entry != nullptr) { entry->set_obj(lockee); - // traditional lightweight locking - markWord displaced = lockee->mark().set_unlocked(); - entry->lock()->set_displaced_header(displaced); - bool call_vm = (LockingMode == LM_MONITOR); - bool inc_monitor_count = true; - if (call_vm || lockee->cas_set_mark(markWord::from_pointer(entry), displaced) != displaced) { - // Is it simple recursive case? - if (!call_vm && THREAD->is_lock_owned((address) displaced.clear_lock_bits().to_pointer())) { - entry->lock()->set_displaced_header(markWord::from_pointer(nullptr)); - } else { - inc_monitor_count = false; - CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); + bool success = false; + if (LockingMode == LM_LEGACY) { + // Traditional fast locking. + markWord displaced = lockee->mark().set_unlocked(); + entry->lock()->set_displaced_header(displaced); + success = true; + if (lockee->cas_set_mark(markWord::from_pointer(entry), displaced) != displaced) { + // Is it simple recursive case? + if (THREAD->is_lock_owned((address) displaced.clear_lock_bits().to_pointer())) { + entry->lock()->set_displaced_header(markWord::from_pointer(nullptr)); + } else { + success = false; + } + } + if (success) { + THREAD->inc_held_monitor_count(); } } - if (inc_monitor_count) { - THREAD->inc_held_monitor_count(); + if (!success) { + CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); } + UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1); } else { istate->set_msg(more_monitors); @@ -1687,23 +1705,27 @@ void BytecodeInterpreter::run(interpreterState istate) { while (most_recent != limit ) { if ((most_recent)->obj() == lockee) { BasicLock* lock = most_recent->lock(); - markWord header = lock->displaced_header(); - most_recent->set_obj(nullptr); - // If it isn't recursive we either must swap old header or call the runtime - bool dec_monitor_count = true; - bool call_vm = (LockingMode == LM_MONITOR); - if (header.to_pointer() != nullptr || call_vm) { - markWord old_header = markWord::encode(lock); - if (call_vm || lockee->cas_set_mark(header, old_header) != old_header) { - // restore object for the slow case - most_recent->set_obj(lockee); - dec_monitor_count = false; - InterpreterRuntime::monitorexit(most_recent); + bool success = false; + if (LockingMode == LM_LEGACY) { + // If it isn't recursive we either must swap old header or call the runtime + most_recent->set_obj(nullptr); + success = true; + markWord header = lock->displaced_header(); + if (header.to_pointer() != nullptr) { + markWord old_header = markWord::encode(lock); + if (lockee->cas_set_mark(header, old_header) != old_header) { + // restore object for the slow case + most_recent->set_obj(lockee); + success = false; + } + } + if (success) { + THREAD->dec_held_monitor_count(); } } - if (dec_monitor_count) { - THREAD->dec_held_monitor_count(); + if (!success) { + InterpreterRuntime::monitorexit(most_recent); } UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1); } @@ -3125,22 +3147,28 @@ void BytecodeInterpreter::run(interpreterState istate) { oop lockee = end->obj(); if (lockee != nullptr) { BasicLock* lock = end->lock(); - markWord header = lock->displaced_header(); - end->set_obj(nullptr); - - // If it isn't recursive we either must swap old header or call the runtime - bool dec_monitor_count = true; - if (header.to_pointer() != nullptr) { - markWord old_header = markWord::encode(lock); - if (lockee->cas_set_mark(header, old_header) != old_header) { - // restore object for the slow case - end->set_obj(lockee); - dec_monitor_count = false; - InterpreterRuntime::monitorexit(end); + + bool success = false; + if (LockingMode == LM_LEGACY) { + markWord header = lock->displaced_header(); + end->set_obj(nullptr); + + // If it isn't recursive we either must swap old header or call the runtime + success = true; + if (header.to_pointer() != nullptr) { + markWord old_header = markWord::encode(lock); + if (lockee->cas_set_mark(header, old_header) != old_header) { + // restore object for the slow case + end->set_obj(lockee); + success = false; + } + } + if (success) { + THREAD->dec_held_monitor_count(); } } - if (dec_monitor_count) { - THREAD->dec_held_monitor_count(); + if (!success) { + InterpreterRuntime::monitorexit(end); } // One error is plenty @@ -3188,7 +3216,7 @@ void BytecodeInterpreter::run(interpreterState istate) { illegal_state_oop = Handle(THREAD, THREAD->pending_exception()); THREAD->clear_pending_exception(); } - } else if (LockingMode == LM_MONITOR) { + } else if (LockingMode != LM_LEGACY) { InterpreterRuntime::monitorexit(base); if (THREAD->has_pending_exception()) { if (!suppress_error) illegal_state_oop = Handle(THREAD, THREAD->pending_exception()); diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index ac895cc93f2..5870e49ac94 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -151,7 +151,7 @@ nonstatic_field(Array, _length, int) \ nonstatic_field(Array, _data[0], Klass*) \ \ - volatile_nonstatic_field(BasicLock, _displaced_header, markWord) \ + volatile_nonstatic_field(BasicLock, _metadata, uintptr_t) \ \ static_field(CodeCache, _low_bound, address) \ static_field(CodeCache, _high_bound, address) \ @@ -241,6 +241,7 @@ nonstatic_field(JavaThread, _stack_overflow_state._reserved_stack_activation, address) \ nonstatic_field(JavaThread, _held_monitor_count, intx) \ nonstatic_field(JavaThread, _lock_stack, LockStack) \ + nonstatic_field(JavaThread, _om_cache, OMCache) \ JVMTI_ONLY(nonstatic_field(JavaThread, _is_in_VTMS_transition, bool)) \ JVMTI_ONLY(nonstatic_field(JavaThread, _is_in_tmp_VTMS_transition, bool)) \ JVMTI_ONLY(nonstatic_field(JavaThread, _is_disable_suspend, bool)) \ @@ -531,6 +532,8 @@ \ declare_constant_with_value("CardTable::dirty_card", CardTable::dirty_card_val()) \ declare_constant_with_value("LockStack::_end_offset", LockStack::end_offset()) \ + declare_constant_with_value("OMCache::oop_to_oop_difference", OMCache::oop_to_oop_difference()) \ + declare_constant_with_value("OMCache::oop_to_monitor_difference", OMCache::oop_to_monitor_difference()) \ \ declare_constant(CodeInstaller::VERIFIED_ENTRY) \ declare_constant(CodeInstaller::UNVERIFIED_ENTRY) \ diff --git a/src/hotspot/share/logging/logTag.hpp b/src/hotspot/share/logging/logTag.hpp index b64097311a4..b53a015b0f2 100644 --- a/src/hotspot/share/logging/logTag.hpp +++ b/src/hotspot/share/logging/logTag.hpp @@ -130,6 +130,7 @@ class outputStream; LOG_TAG(module) \ LOG_TAG(monitorinflation) \ LOG_TAG(monitormismatch) \ + LOG_TAG(monitortable) \ LOG_TAG(native) \ LOG_TAG(nestmates) \ LOG_TAG(nmethod) \ diff --git a/src/hotspot/share/oops/markWord.cpp b/src/hotspot/share/oops/markWord.cpp index e861ab87182..2bbec570fa8 100644 --- a/src/hotspot/share/oops/markWord.cpp +++ b/src/hotspot/share/oops/markWord.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "oops/markWord.hpp" +#include "runtime/basicLock.inline.hpp" #include "runtime/javaThread.hpp" #include "runtime/objectMonitor.inline.hpp" #include "utilities/ostream.hpp" @@ -67,7 +68,7 @@ void markWord::print_on(outputStream* st, bool print_monitor_info) const { } else if (has_monitor()) { // last bits = 10 // have to check has_monitor() before is_locked() st->print(" monitor(" INTPTR_FORMAT ")=", value()); - if (print_monitor_info) { + if (print_monitor_info && !UseObjectMonitorTable) { ObjectMonitor* mon = monitor(); if (mon == nullptr) { st->print("null (this should never be seen!)"); diff --git a/src/hotspot/share/oops/markWord.hpp b/src/hotspot/share/oops/markWord.hpp index 12d6ee73acf..92577a8b40b 100644 --- a/src/hotspot/share/oops/markWord.hpp +++ b/src/hotspot/share/oops/markWord.hpp @@ -197,13 +197,17 @@ class markWord { } ObjectMonitor* monitor() const { assert(has_monitor(), "check"); + assert(!UseObjectMonitorTable, "Lightweight locking with OM table does not use markWord for monitors"); // Use xor instead of &~ to provide one extra tag-bit check. return (ObjectMonitor*) (value() ^ monitor_value); } bool has_displaced_mark_helper() const { intptr_t lockbits = value() & lock_mask_in_place; - return LockingMode == LM_LIGHTWEIGHT ? lockbits == monitor_value // monitor? - : (lockbits & unlocked_value) == 0; // monitor | stack-locked? + if (LockingMode == LM_LIGHTWEIGHT) { + return !UseObjectMonitorTable && lockbits == monitor_value; + } + // monitor (0b10) | stack-locked (0b00)? + return (lockbits & unlocked_value) == 0; } markWord displaced_mark_helper() const; void set_displaced_mark_helper(markWord m) const; @@ -223,10 +227,15 @@ class markWord { return from_pointer(lock); } static markWord encode(ObjectMonitor* monitor) { + assert(!UseObjectMonitorTable, "Lightweight locking with OM table does not use markWord for monitors"); uintptr_t tmp = (uintptr_t) monitor; return markWord(tmp | monitor_value); } + markWord set_has_monitor() const { + return markWord((value() & ~lock_mask_in_place) | monitor_value); + } + // used to encode pointers during GC markWord clear_lock_bits() const { return markWord(value() & ~lock_mask_in_place); } diff --git a/src/hotspot/share/opto/c2_CodeStubs.hpp b/src/hotspot/share/opto/c2_CodeStubs.hpp index 1316fa68ed4..5db7596e072 100644 --- a/src/hotspot/share/opto/c2_CodeStubs.hpp +++ b/src/hotspot/share/opto/c2_CodeStubs.hpp @@ -103,6 +103,7 @@ class C2FastUnlockLightweightStub : public C2CodeStub { Register _mark; Register _t; Register _thread; + Label _slow_path; Label _push_and_slow_path; Label _check_successor; Label _unlocked_continuation; @@ -111,6 +112,7 @@ class C2FastUnlockLightweightStub : public C2CodeStub { _obj(obj), _mark(mark), _t(t), _thread(thread) {} int max_size() const; void emit(C2_MacroAssembler& masm); + Label& slow_path() { return _slow_path; } Label& push_and_slow_path() { return _push_and_slow_path; } Label& check_successor() { return _check_successor; } Label& unlocked_continuation() { return _unlocked_continuation; } diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 9660413dd19..542514b1f7e 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -4604,21 +4604,23 @@ bool LibraryCallKit::inline_native_hashcode(bool is_virtual, bool is_static) { Node* no_ctrl = nullptr; Node* header = make_load(no_ctrl, header_addr, TypeX_X, TypeX_X->basic_type(), MemNode::unordered); - // Test the header to see if it is safe to read w.r.t. locking. - Node *lock_mask = _gvn.MakeConX(markWord::lock_mask_in_place); - Node *lmasked_header = _gvn.transform(new AndXNode(header, lock_mask)); - if (LockingMode == LM_LIGHTWEIGHT) { - Node *monitor_val = _gvn.MakeConX(markWord::monitor_value); - Node *chk_monitor = _gvn.transform(new CmpXNode(lmasked_header, monitor_val)); - Node *test_monitor = _gvn.transform(new BoolNode(chk_monitor, BoolTest::eq)); - - generate_slow_guard(test_monitor, slow_region); - } else { - Node *unlocked_val = _gvn.MakeConX(markWord::unlocked_value); - Node *chk_unlocked = _gvn.transform(new CmpXNode(lmasked_header, unlocked_val)); - Node *test_not_unlocked = _gvn.transform(new BoolNode(chk_unlocked, BoolTest::ne)); + if (!UseObjectMonitorTable) { + // Test the header to see if it is safe to read w.r.t. locking. + Node *lock_mask = _gvn.MakeConX(markWord::lock_mask_in_place); + Node *lmasked_header = _gvn.transform(new AndXNode(header, lock_mask)); + if (LockingMode == LM_LIGHTWEIGHT) { + Node *monitor_val = _gvn.MakeConX(markWord::monitor_value); + Node *chk_monitor = _gvn.transform(new CmpXNode(lmasked_header, monitor_val)); + Node *test_monitor = _gvn.transform(new BoolNode(chk_monitor, BoolTest::eq)); + + generate_slow_guard(test_monitor, slow_region); + } else { + Node *unlocked_val = _gvn.MakeConX(markWord::unlocked_value); + Node *chk_unlocked = _gvn.transform(new CmpXNode(lmasked_header, unlocked_val)); + Node *test_not_unlocked = _gvn.transform(new BoolNode(chk_unlocked, BoolTest::ne)); - generate_slow_guard(test_not_unlocked, slow_region); + generate_slow_guard(test_not_unlocked, slow_region); + } } // Get the hash value and check to see that it has been properly assigned. diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp index 1a6aec4e438..a05d6998093 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.cpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp @@ -56,6 +56,7 @@ #include "runtime/osThread.hpp" #include "runtime/signature.hpp" #include "runtime/stackWatermarkSet.inline.hpp" +#include "runtime/synchronizer.inline.hpp" #include "runtime/threads.hpp" #include "runtime/threadSMR.inline.hpp" #include "runtime/vframe.inline.hpp" @@ -1465,7 +1466,6 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec ThreadsListHandle tlh(current_thread); JavaThread *owning_thread = nullptr; - ObjectMonitor *mon = nullptr; jvmtiMonitorUsage ret = { nullptr, 0, 0, nullptr, 0, nullptr }; @@ -1495,9 +1495,11 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec ResourceMark rm(current_thread); GrowableArray* wantList = nullptr; - if (mark.has_monitor()) { - mon = mark.monitor(); - assert(mon != nullptr, "must have monitor"); + ObjectMonitor* mon = mark.has_monitor() + ? ObjectSynchronizer::read_monitor(current_thread, hobj(), mark) + : nullptr; + + if (mon != nullptr) { // this object has a heavyweight monitor nWant = mon->contentions(); // # of threads contending for monitor entry, but not re-entry nWait = mon->waiters(); // # of threads waiting for notification, diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 9086a5f6c71..81b40e76a31 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -1816,8 +1816,18 @@ bool Arguments::check_vm_args_consistency() { FLAG_SET_CMDLINE(LockingMode, LM_LEGACY); warning("New lightweight locking not supported on this platform"); } + if (UseObjectMonitorTable) { + FLAG_SET_CMDLINE(UseObjectMonitorTable, false); + warning("UseObjectMonitorTable not supported on this platform"); + } #endif + if (UseObjectMonitorTable && LockingMode != LM_LIGHTWEIGHT) { + // ObjectMonitorTable requires lightweight locking. + FLAG_SET_CMDLINE(UseObjectMonitorTable, false); + warning("UseObjectMonitorTable requires LM_LIGHTWEIGHT"); + } + #if !defined(X86) && !defined(AARCH64) && !defined(PPC64) && !defined(RISCV64) && !defined(S390) if (LockingMode == LM_MONITOR) { jio_fprintf(defaultStream::error_stream(), diff --git a/src/hotspot/share/runtime/basicLock.cpp b/src/hotspot/share/runtime/basicLock.cpp index 704bea85576..ec2e66a7d5d 100644 --- a/src/hotspot/share/runtime/basicLock.cpp +++ b/src/hotspot/share/runtime/basicLock.cpp @@ -24,16 +24,24 @@ #include "precompiled.hpp" #include "oops/oop.inline.hpp" -#include "runtime/basicLock.hpp" +#include "runtime/basicLock.inline.hpp" +#include "runtime/objectMonitor.hpp" #include "runtime/synchronizer.hpp" void BasicLock::print_on(outputStream* st, oop owner) const { st->print("monitor"); - markWord mark_word = displaced_header(); - if (mark_word.value() != 0) { - // Print monitor info if there's an owning oop and it refers to this BasicLock. - bool print_monitor_info = (owner != nullptr) && (owner->mark() == markWord::from_pointer((void*)this)); - mark_word.print_on(st, print_monitor_info); + if (UseObjectMonitorTable) { + ObjectMonitor* mon = object_monitor_cache(); + if (mon != nullptr) { + mon->print_on(st); + } + } else if (LockingMode == LM_LEGACY) { + markWord mark_word = displaced_header(); + if (mark_word.value() != 0) { + // Print monitor info if there's an owning oop and it refers to this BasicLock. + bool print_monitor_info = (owner != nullptr) && (owner->mark() == markWord::from_pointer((void*)this)); + mark_word.print_on(st, print_monitor_info); + } } } @@ -82,10 +90,15 @@ void BasicLock::move_to(oop obj, BasicLock* dest) { // we can find any flavor mark in the displaced mark. } dest->set_displaced_header(displaced_header()); + } else if (UseObjectMonitorTable) { + // Preserve the ObjectMonitor*, the cache is cleared when a box is reused + // and only read while the lock is held, so no stale ObjectMonitor* is + // encountered. + dest->set_object_monitor_cache(object_monitor_cache()); } #ifdef ASSERT else { - dest->set_displaced_header(markWord(badDispHeaderDeopt)); + dest->set_bad_metadata_deopt(); } #endif } diff --git a/src/hotspot/share/runtime/basicLock.hpp b/src/hotspot/share/runtime/basicLock.hpp index c348fa7f9a2..193aa63cf8f 100644 --- a/src/hotspot/share/runtime/basicLock.hpp +++ b/src/hotspot/share/runtime/basicLock.hpp @@ -28,30 +28,46 @@ #include "oops/markWord.hpp" #include "runtime/atomic.hpp" #include "runtime/handles.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/sizes.hpp" class BasicLock { friend class VMStructs; friend class JVMCIVMStructs; private: + // * For LM_MONITOR + // Unused. + // * For LM_LEGACY // This is either the actual displaced header from a locked object, or // a sentinel zero value indicating a recursive stack-lock. - volatile markWord _displaced_header; + // * For LM_LIGHTWEIGHT + // Used as a cache of the ObjectMonitor* used when locking. Must either + // be nullptr or the ObjectMonitor* used when locking. + volatile uintptr_t _metadata; + + uintptr_t get_metadata() const { return Atomic::load(&_metadata); } + void set_metadata(uintptr_t value) { Atomic::store(&_metadata, value); } + static int metadata_offset_in_bytes() { return (int)offset_of(BasicLock, _metadata); } + public: - markWord displaced_header() const { - return Atomic::load(&_displaced_header); - } + // LM_MONITOR + void set_bad_metadata_deopt() { set_metadata(badDispHeaderDeopt); } - void set_displaced_header(markWord header) { - Atomic::store(&_displaced_header, header); - } + // LM_LEGACY + inline markWord displaced_header() const; + inline void set_displaced_header(markWord header); + static int displaced_header_offset_in_bytes() { return metadata_offset_in_bytes(); } + + // LM_LIGHTWEIGHT + inline ObjectMonitor* object_monitor_cache() const; + inline void clear_object_monitor_cache(); + inline void set_object_monitor_cache(ObjectMonitor* mon); + static int object_monitor_cache_offset_in_bytes() { return metadata_offset_in_bytes(); } void print_on(outputStream* st, oop owner) const; // move a basic lock (used during deoptimization) void move_to(oop obj, BasicLock* dest); - - static int displaced_header_offset_in_bytes() { return (int)offset_of(BasicLock, _displaced_header); } }; // A BasicObjectLock associates a specific Java object with a BasicLock. diff --git a/src/hotspot/share/runtime/basicLock.inline.hpp b/src/hotspot/share/runtime/basicLock.inline.hpp new file mode 100644 index 00000000000..fb1cee8de8f --- /dev/null +++ b/src/hotspot/share/runtime/basicLock.inline.hpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_RUNTIME_BASICLOCK_INLINE_HPP +#define SHARE_RUNTIME_BASICLOCK_INLINE_HPP + +#include "runtime/basicLock.hpp" + +inline markWord BasicLock::displaced_header() const { + assert(LockingMode == LM_LEGACY, "must be"); + return markWord(get_metadata()); +} + +inline void BasicLock::set_displaced_header(markWord header) { + assert(LockingMode == LM_LEGACY, "must be"); + Atomic::store(&_metadata, header.value()); +} + +inline ObjectMonitor* BasicLock::object_monitor_cache() const { + assert(UseObjectMonitorTable, "must be"); +#if defined(X86) || defined(AARCH64) + return reinterpret_cast(get_metadata()); +#else + // Other platforms do not make use of the cache yet, + // and are not as careful with maintaining the invariant + // that the metadata either is nullptr or ObjectMonitor*. + return nullptr; +#endif +} + +inline void BasicLock::clear_object_monitor_cache() { + assert(UseObjectMonitorTable, "must be"); + set_metadata(0); +} + +inline void BasicLock::set_object_monitor_cache(ObjectMonitor* mon) { + assert(UseObjectMonitorTable, "must be"); + set_metadata(reinterpret_cast(mon)); +} + +#endif // SHARE_RUNTIME_BASICLOCK_INLINE_HPP diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index cf82ad7c027..7961e56598f 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -63,6 +63,7 @@ #include "prims/methodHandles.hpp" #include "prims/vectorSupport.hpp" #include "runtime/atomic.hpp" +#include "runtime/basicLock.inline.hpp" #include "runtime/continuation.hpp" #include "runtime/continuationEntry.inline.hpp" #include "runtime/deoptimization.hpp" @@ -75,6 +76,8 @@ #include "runtime/javaThread.hpp" #include "runtime/jniHandles.inline.hpp" #include "runtime/keepStackGCProcessed.hpp" +#include "runtime/lightweightSynchronizer.hpp" +#include "runtime/lockStack.inline.hpp" #include "runtime/objectMonitor.inline.hpp" #include "runtime/osThread.hpp" #include "runtime/safepointVerifiers.hpp" @@ -84,7 +87,7 @@ #include "runtime/stackValue.hpp" #include "runtime/stackWatermarkSet.hpp" #include "runtime/stubRoutines.hpp" -#include "runtime/synchronizer.hpp" +#include "runtime/synchronizer.inline.hpp" #include "runtime/threadSMR.hpp" #include "runtime/threadWXSetters.inline.hpp" #include "runtime/vframe.hpp" @@ -1634,22 +1637,37 @@ bool Deoptimization::relock_objects(JavaThread* thread, GrowableArraycurrent_waiting_monitor(); if (waiting_monitor != nullptr && waiting_monitor->object() == obj()) { assert(fr.is_deoptimized_frame(), "frame must be scheduled for deoptimization"); - mon_info->lock()->set_displaced_header(markWord::unused_mark()); + if (LockingMode == LM_LEGACY) { + mon_info->lock()->set_displaced_header(markWord::unused_mark()); + } else if (UseObjectMonitorTable) { + mon_info->lock()->clear_object_monitor_cache(); + } +#ifdef ASSERT + else { + assert(LockingMode == LM_MONITOR || !UseObjectMonitorTable, "must be"); + mon_info->lock()->set_bad_metadata_deopt(); + } +#endif JvmtiDeferredUpdates::inc_relock_count_after_wait(deoptee_thread); continue; } } } + BasicLock* lock = mon_info->lock(); if (LockingMode == LM_LIGHTWEIGHT) { // We have lost information about the correct state of the lock stack. - // Inflate the locks instead. Enter then inflate to avoid races with - // deflation. - ObjectSynchronizer::enter_for(obj, nullptr, deoptee_thread); + // Entering may create an invalid lock stack. Inflate the lock if it + // was fast_locked to restore the valid lock stack. + ObjectSynchronizer::enter_for(obj, lock, deoptee_thread); + if (deoptee_thread->lock_stack().contains(obj())) { + LightweightSynchronizer::inflate_fast_locked_object(obj(), ObjectSynchronizer::InflateCause::inflate_cause_vm_internal, + deoptee_thread, thread); + } assert(mon_info->owner()->is_locked(), "object must be locked now"); - ObjectMonitor* mon = ObjectSynchronizer::inflate_for(deoptee_thread, obj(), ObjectSynchronizer::inflate_cause_vm_internal); - assert(mon->owner() == deoptee_thread, "must be"); + assert(obj->mark().has_monitor(), "must be"); + assert(!deoptee_thread->lock_stack().contains(obj()), "must be"); + assert(ObjectSynchronizer::read_monitor(thread, obj(), obj->mark())->owner() == deoptee_thread, "must be"); } else { - BasicLock* lock = mon_info->lock(); ObjectSynchronizer::enter_for(obj, lock, deoptee_thread); assert(mon_info->owner()->is_locked(), "object must be locked now"); } diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 61efc0b9376..d442894798b 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1956,6 +1956,17 @@ const int ObjectAlignmentInBytes = 8; "2: monitors & new lightweight locking (LM_LIGHTWEIGHT, default)") \ range(0, 2) \ \ + product(bool, UseObjectMonitorTable, false, DIAGNOSTIC, \ + "With Lightweight Locking mode, use a table to record inflated " \ + "monitors rather than the first word of the object.") \ + \ + product(int, LightweightFastLockingSpins, 13, DIAGNOSTIC, \ + "Specifies the number of times lightweight fast locking will " \ + "attempt to CAS the markWord before inflating. Between each " \ + "CAS it will spin for exponentially more time, resulting in " \ + "a total number of spins on the order of O(2^value)") \ + range(1, 30) \ + \ product(uint, TrimNativeHeapInterval, 0, \ "Interval, in ms, at which the JVM will trim the native heap if " \ "the platform supports that. Lower values will reclaim memory " \ diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index b69ab708afa..0c00ef75c92 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -504,7 +504,8 @@ JavaThread::JavaThread(MEMFLAGS flags) : _SleepEvent(ParkEvent::Allocate(this)), - _lock_stack(this) { + _lock_stack(this), + _om_cache(this) { set_jni_functions(jni_functions()); #if INCLUDE_JVMCI @@ -803,6 +804,8 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) { elapsedTimer _timer_exit_phase3; elapsedTimer _timer_exit_phase4; + om_clear_monitor_cache(); + if (log_is_enabled(Debug, os, thread, timer)) { _timer_exit_phase1.start(); } diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp index 755a8268864..54a11dad9b8 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -61,6 +61,7 @@ class JvmtiSampledObjectAllocEventCollector; class JvmtiThreadState; class Metadata; +class ObjectMonitor; class OopHandleList; class OopStorage; class OSThread; @@ -1165,6 +1166,7 @@ class JavaThread: public Thread { private: LockStack _lock_stack; + OMCache _om_cache; public: LockStack& lock_stack() { return _lock_stack; } @@ -1176,6 +1178,13 @@ class JavaThread: public Thread { static ByteSize lock_stack_top_offset() { return lock_stack_offset() + LockStack::top_offset(); } static ByteSize lock_stack_base_offset() { return lock_stack_offset() + LockStack::base_offset(); } + static ByteSize om_cache_offset() { return byte_offset_of(JavaThread, _om_cache); } + static ByteSize om_cache_oops_offset() { return om_cache_offset() + OMCache::entries_offset(); } + + void om_set_monitor_cache(ObjectMonitor* monitor); + void om_clear_monitor_cache(); + ObjectMonitor* om_get_from_monitor_cache(oop obj); + static OopStorage* thread_oop_storage(); static void verify_cross_modify_fence_failure(JavaThread *thread) PRODUCT_RETURN; diff --git a/src/hotspot/share/runtime/javaThread.inline.hpp b/src/hotspot/share/runtime/javaThread.inline.hpp index a51a30ae577..fabb589c2b5 100644 --- a/src/hotspot/share/runtime/javaThread.inline.hpp +++ b/src/hotspot/share/runtime/javaThread.inline.hpp @@ -36,7 +36,9 @@ #include "runtime/atomic.hpp" #include "runtime/continuation.hpp" #include "runtime/continuationEntry.inline.hpp" +#include "runtime/lockStack.inline.hpp" #include "runtime/nonJavaThread.hpp" +#include "runtime/objectMonitor.inline.hpp" #include "runtime/orderAccess.hpp" #include "runtime/safepoint.hpp" @@ -239,4 +241,25 @@ inline InstanceKlass* JavaThread::class_to_be_initialized() const { return _class_to_be_initialized; } +inline void JavaThread::om_set_monitor_cache(ObjectMonitor* monitor) { + assert(UseObjectMonitorTable, "must be"); + assert(monitor != nullptr, "use om_clear_monitor_cache to clear"); + assert(this == current() || monitor->owner_raw() == this, "only add owned monitors for other threads"); + assert(this == current() || is_obj_deopt_suspend(), "thread must not run concurrently"); + + _om_cache.set_monitor(monitor); +} + +inline void JavaThread::om_clear_monitor_cache() { + if (UseObjectMonitorTable) { + _om_cache.clear(); + } +} + +inline ObjectMonitor* JavaThread::om_get_from_monitor_cache(oop obj) { + assert(obj != nullptr, "do not look for null objects"); + assert(this == current(), "only get own thread locals"); + return _om_cache.get_monitor(obj); +} + #endif // SHARE_RUNTIME_JAVATHREAD_INLINE_HPP diff --git a/src/hotspot/share/runtime/lightweightSynchronizer.cpp b/src/hotspot/share/runtime/lightweightSynchronizer.cpp new file mode 100644 index 00000000000..0e360dba97b --- /dev/null +++ b/src/hotspot/share/runtime/lightweightSynchronizer.cpp @@ -0,0 +1,1223 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" + +#include "classfile/vmSymbols.hpp" +#include "jfrfiles/jfrEventClasses.hpp" +#include "logging/log.hpp" +#include "memory/allStatic.hpp" +#include "memory/resourceArea.hpp" +#include "nmt/memflags.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/atomic.hpp" +#include "runtime/basicLock.inline.hpp" +#include "runtime/globals_extension.hpp" +#include "runtime/interfaceSupport.inline.hpp" +#include "runtime/javaThread.inline.hpp" +#include "runtime/lightweightSynchronizer.hpp" +#include "runtime/lockStack.inline.hpp" +#include "runtime/mutexLocker.hpp" +#include "runtime/objectMonitor.inline.hpp" +#include "runtime/os.hpp" +#include "runtime/perfData.inline.hpp" +#include "runtime/safepointMechanism.inline.hpp" +#include "runtime/safepointVerifiers.hpp" +#include "runtime/synchronizer.inline.hpp" +#include "runtime/timerTrace.hpp" +#include "runtime/trimNativeHeap.hpp" +#include "utilities/concurrentHashTable.inline.hpp" +#include "utilities/concurrentHashTableTasks.inline.hpp" +#include "utilities/globalDefinitions.hpp" + +// ConcurrentHashTable storing links from objects to ObjectMonitors +class ObjectMonitorTable : AllStatic { + struct Config { + using Value = ObjectMonitor*; + static uintx get_hash(Value const& value, bool* is_dead) { + return (uintx)value->hash(); + } + static void* allocate_node(void* context, size_t size, Value const& value) { + ObjectMonitorTable::inc_items_count(); + return AllocateHeap(size, MEMFLAGS::mtObjectMonitor); + }; + static void free_node(void* context, void* memory, Value const& value) { + ObjectMonitorTable::dec_items_count(); + FreeHeap(memory); + } + }; + using ConcurrentTable = ConcurrentHashTable; + + static ConcurrentTable* _table; + static volatile size_t _items_count; + static size_t _table_size; + static volatile bool _resize; + + class Lookup : public StackObj { + oop _obj; + + public: + explicit Lookup(oop obj) : _obj(obj) {} + + uintx get_hash() const { + uintx hash = _obj->mark().hash(); + assert(hash != 0, "should have a hash"); + return hash; + } + + bool equals(ObjectMonitor** value) { + assert(*value != nullptr, "must be"); + return (*value)->object_refers_to(_obj); + } + + bool is_dead(ObjectMonitor** value) { + assert(*value != nullptr, "must be"); + return false; + } + }; + + class LookupMonitor : public StackObj { + ObjectMonitor* _monitor; + + public: + explicit LookupMonitor(ObjectMonitor* monitor) : _monitor(monitor) {} + + uintx get_hash() const { + return _monitor->hash(); + } + + bool equals(ObjectMonitor** value) { + return (*value) == _monitor; + } + + bool is_dead(ObjectMonitor** value) { + assert(*value != nullptr, "must be"); + return (*value)->object_is_dead(); + } + }; + + static void inc_items_count() { + Atomic::inc(&_items_count); + } + + static void dec_items_count() { + Atomic::dec(&_items_count); + } + + static double get_load_factor() { + return (double)_items_count / (double)_table_size; + } + + static size_t table_size(Thread* current = Thread::current()) { + return ((size_t)1) << _table->get_size_log2(current); + } + + static size_t max_log_size() { + // TODO[OMTable]: Evaluate the max size. + // TODO[OMTable]: Need to fix init order to use Universe::heap()->max_capacity(); + // Using MaxHeapSize directly this early may be wrong, and there + // are definitely rounding errors (alignment). + const size_t max_capacity = MaxHeapSize; + const size_t min_object_size = CollectedHeap::min_dummy_object_size() * HeapWordSize; + const size_t max_objects = max_capacity / MAX2(MinObjAlignmentInBytes, checked_cast(min_object_size)); + const size_t log_max_objects = log2i_graceful(max_objects); + + return MAX2(MIN2(SIZE_BIG_LOG2, log_max_objects), min_log_size()); + } + + static size_t min_log_size() { + // ~= log(AvgMonitorsPerThreadEstimate default) + return 10; + } + + template + static size_t clamp_log_size(V log_size) { + return MAX2(MIN2(log_size, checked_cast(max_log_size())), checked_cast(min_log_size())); + } + + static size_t initial_log_size() { + const size_t estimate = log2i(MAX2(os::processor_count(), 1)) + log2i(MAX2(AvgMonitorsPerThreadEstimate, size_t(1))); + return clamp_log_size(estimate); + } + + static size_t grow_hint () { + return ConcurrentTable::DEFAULT_GROW_HINT; + } + + public: + static void create() { + _table = new ConcurrentTable(initial_log_size(), max_log_size(), grow_hint()); + _items_count = 0; + _table_size = table_size(); + _resize = false; + } + + static void verify_monitor_get_result(oop obj, ObjectMonitor* monitor) { +#ifdef ASSERT + if (SafepointSynchronize::is_at_safepoint()) { + bool has_monitor = obj->mark().has_monitor(); + assert(has_monitor == (monitor != nullptr), + "Inconsistency between markWord and ObjectMonitorTable has_monitor: %s monitor: " PTR_FORMAT, + BOOL_TO_STR(has_monitor), p2i(monitor)); + } +#endif + } + + static ObjectMonitor* monitor_get(Thread* current, oop obj) { + ObjectMonitor* result = nullptr; + Lookup lookup_f(obj); + auto found_f = [&](ObjectMonitor** found) { + assert((*found)->object_peek() == obj, "must be"); + result = *found; + }; + _table->get(current, lookup_f, found_f); + verify_monitor_get_result(obj, result); + return result; + } + + static void try_notify_grow() { + if (!_table->is_max_size_reached() && !Atomic::load(&_resize)) { + Atomic::store(&_resize, true); + if (Service_lock->try_lock()) { + Service_lock->notify(); + Service_lock->unlock(); + } + } + } + + static bool should_shrink() { + // Not implemented; + return false; + } + + static constexpr double GROW_LOAD_FACTOR = 0.75; + + static bool should_grow() { + return get_load_factor() > GROW_LOAD_FACTOR && !_table->is_max_size_reached(); + } + + static bool should_resize() { + return should_grow() || should_shrink() || Atomic::load(&_resize); + } + + template + static bool run_task(JavaThread* current, Task& task, const char* task_name, Args&... args) { + if (task.prepare(current)) { + log_trace(monitortable)("Started to %s", task_name); + TraceTime timer(task_name, TRACETIME_LOG(Debug, monitortable, perf)); + while (task.do_task(current, args...)) { + task.pause(current); + { + ThreadBlockInVM tbivm(current); + } + task.cont(current); + } + task.done(current); + return true; + } + return false; + } + + static bool grow(JavaThread* current) { + ConcurrentTable::GrowTask grow_task(_table); + if (run_task(current, grow_task, "Grow")) { + _table_size = table_size(current); + log_info(monitortable)("Grown to size: %zu", _table_size); + return true; + } + return false; + } + + static bool clean(JavaThread* current) { + ConcurrentTable::BulkDeleteTask clean_task(_table); + auto is_dead = [&](ObjectMonitor** monitor) { + return (*monitor)->object_is_dead(); + }; + auto do_nothing = [&](ObjectMonitor** monitor) {}; + NativeHeapTrimmer::SuspendMark sm("ObjectMonitorTable"); + return run_task(current, clean_task, "Clean", is_dead, do_nothing); + } + + static bool resize(JavaThread* current) { + LogTarget(Info, monitortable) lt; + bool success = false; + + if (should_grow()) { + lt.print("Start growing with load factor %f", get_load_factor()); + success = grow(current); + } else { + if (!_table->is_max_size_reached() && Atomic::load(&_resize)) { + lt.print("WARNING: Getting resize hints with load factor %f", get_load_factor()); + } + lt.print("Start cleaning with load factor %f", get_load_factor()); + success = clean(current); + } + + Atomic::store(&_resize, false); + + return success; + } + + static ObjectMonitor* monitor_put_get(Thread* current, ObjectMonitor* monitor, oop obj) { + // Enter the monitor into the concurrent hashtable. + ObjectMonitor* result = monitor; + Lookup lookup_f(obj); + auto found_f = [&](ObjectMonitor** found) { + assert((*found)->object_peek() == obj, "must be"); + result = *found; + }; + bool grow; + _table->insert_get(current, lookup_f, monitor, found_f, &grow); + verify_monitor_get_result(obj, result); + if (grow) { + try_notify_grow(); + } + return result; + } + + static bool remove_monitor_entry(Thread* current, ObjectMonitor* monitor) { + LookupMonitor lookup_f(monitor); + return _table->remove(current, lookup_f); + } + + static bool contains_monitor(Thread* current, ObjectMonitor* monitor) { + LookupMonitor lookup_f(monitor); + bool result = false; + auto found_f = [&](ObjectMonitor** found) { + result = true; + }; + _table->get(current, lookup_f, found_f); + return result; + } + + static void print_on(outputStream* st) { + auto printer = [&] (ObjectMonitor** entry) { + ObjectMonitor* om = *entry; + oop obj = om->object_peek(); + st->print("monitor=" PTR_FORMAT ", ", p2i(om)); + st->print("object=" PTR_FORMAT, p2i(obj)); + assert(obj->mark().hash() == om->hash(), "hash must match"); + st->cr(); + return true; + }; + if (SafepointSynchronize::is_at_safepoint()) { + _table->do_safepoint_scan(printer); + } else { + _table->do_scan(Thread::current(), printer); + } + } +}; + +ObjectMonitorTable::ConcurrentTable* ObjectMonitorTable::_table = nullptr; +volatile size_t ObjectMonitorTable::_items_count = 0; +size_t ObjectMonitorTable::_table_size = 0; +volatile bool ObjectMonitorTable::_resize = false; + +ObjectMonitor* LightweightSynchronizer::get_or_insert_monitor_from_table(oop object, JavaThread* current, bool* inserted) { + assert(LockingMode == LM_LIGHTWEIGHT, "must be"); + + ObjectMonitor* monitor = get_monitor_from_table(current, object); + if (monitor != nullptr) { + *inserted = false; + return monitor; + } + + ObjectMonitor* alloced_monitor = new ObjectMonitor(object); + alloced_monitor->set_owner_anonymous(); + + // Try insert monitor + monitor = add_monitor(current, alloced_monitor, object); + + *inserted = alloced_monitor == monitor; + if (!*inserted) { + delete alloced_monitor; + } + + return monitor; +} + +static void log_inflate(Thread* current, oop object, ObjectSynchronizer::InflateCause cause) { + if (log_is_enabled(Trace, monitorinflation)) { + ResourceMark rm(current); + log_trace(monitorinflation)("inflate: object=" INTPTR_FORMAT ", mark=" + INTPTR_FORMAT ", type='%s' cause=%s", p2i(object), + object->mark().value(), object->klass()->external_name(), + ObjectSynchronizer::inflate_cause_name(cause)); + } +} + +static void post_monitor_inflate_event(EventJavaMonitorInflate* event, + const oop obj, + ObjectSynchronizer::InflateCause cause) { + assert(event != nullptr, "invariant"); + event->set_monitorClass(obj->klass()); + event->set_address((uintptr_t)(void*)obj); + event->set_cause((u1)cause); + event->commit(); +} + +ObjectMonitor* LightweightSynchronizer::get_or_insert_monitor(oop object, JavaThread* current, ObjectSynchronizer::InflateCause cause) { + assert(UseObjectMonitorTable, "must be"); + + EventJavaMonitorInflate event; + + bool inserted; + ObjectMonitor* monitor = get_or_insert_monitor_from_table(object, current, &inserted); + + if (inserted) { + // Hopefully the performance counters are allocated on distinct + // cache lines to avoid false sharing on MP systems ... + OM_PERFDATA_OP(Inflations, inc()); + log_inflate(current, object, cause); + if (event.should_commit()) { + post_monitor_inflate_event(&event, object, cause); + } + + // The monitor has an anonymous owner so it is safe from async deflation. + ObjectSynchronizer::_in_use_list.add(monitor); + } + + return monitor; +} + +// Add the hashcode to the monitor to match the object and put it in the hashtable. +ObjectMonitor* LightweightSynchronizer::add_monitor(JavaThread* current, ObjectMonitor* monitor, oop obj) { + assert(UseObjectMonitorTable, "must be"); + assert(obj == monitor->object(), "must be"); + + intptr_t hash = obj->mark().hash(); + assert(hash != 0, "must be set when claiming the object monitor"); + monitor->set_hash(hash); + + return ObjectMonitorTable::monitor_put_get(current, monitor, obj); +} + +bool LightweightSynchronizer::remove_monitor(Thread* current, ObjectMonitor* monitor, oop obj) { + assert(UseObjectMonitorTable, "must be"); + assert(monitor->object_peek() == obj, "must be, cleared objects are removed by is_dead"); + + return ObjectMonitorTable::remove_monitor_entry(current, monitor); +} + +void LightweightSynchronizer::deflate_mark_word(oop obj) { + assert(UseObjectMonitorTable, "must be"); + + markWord mark = obj->mark_acquire(); + assert(!mark.has_no_hash(), "obj with inflated monitor must have had a hash"); + + while (mark.has_monitor()) { + const markWord new_mark = mark.clear_lock_bits().set_unlocked(); + mark = obj->cas_set_mark(new_mark, mark); + } +} + +void LightweightSynchronizer::initialize() { + if (!UseObjectMonitorTable) { + return; + } + ObjectMonitorTable::create(); +} + +bool LightweightSynchronizer::needs_resize() { + if (!UseObjectMonitorTable) { + return false; + } + return ObjectMonitorTable::should_resize(); +} + +bool LightweightSynchronizer::resize_table(JavaThread* current) { + if (!UseObjectMonitorTable) { + return true; + } + return ObjectMonitorTable::resize(current); +} + +class LightweightSynchronizer::LockStackInflateContendedLocks : private OopClosure { + private: + oop _contended_oops[LockStack::CAPACITY]; + int _length; + + void do_oop(oop* o) final { + oop obj = *o; + if (obj->mark_acquire().has_monitor()) { + if (_length > 0 && _contended_oops[_length - 1] == obj) { + // Recursive + return; + } + _contended_oops[_length++] = obj; + } + } + + void do_oop(narrowOop* o) final { + ShouldNotReachHere(); + } + + public: + LockStackInflateContendedLocks() : + _contended_oops(), + _length(0) {}; + + void inflate(JavaThread* current) { + assert(current == JavaThread::current(), "must be"); + current->lock_stack().oops_do(this); + for (int i = 0; i < _length; i++) { + LightweightSynchronizer:: + inflate_fast_locked_object(_contended_oops[i], ObjectSynchronizer::inflate_cause_vm_internal, current, current); + } + } +}; + +void LightweightSynchronizer::ensure_lock_stack_space(JavaThread* current) { + assert(current == JavaThread::current(), "must be"); + LockStack& lock_stack = current->lock_stack(); + + // Make room on lock_stack + if (lock_stack.is_full()) { + // Inflate contended objects + LockStackInflateContendedLocks().inflate(current); + if (lock_stack.is_full()) { + // Inflate the oldest object + inflate_fast_locked_object(lock_stack.bottom(), ObjectSynchronizer::inflate_cause_vm_internal, current, current); + } + } +} + +class LightweightSynchronizer::CacheSetter : StackObj { + JavaThread* const _thread; + BasicLock* const _lock; + ObjectMonitor* _monitor; + + NONCOPYABLE(CacheSetter); + + public: + CacheSetter(JavaThread* thread, BasicLock* lock) : + _thread(thread), + _lock(lock), + _monitor(nullptr) {} + + ~CacheSetter() { + // Only use the cache if using the table. + if (UseObjectMonitorTable) { + if (_monitor != nullptr) { + _thread->om_set_monitor_cache(_monitor); + _lock->set_object_monitor_cache(_monitor); + } else { + _lock->clear_object_monitor_cache(); + } + } + } + + void set_monitor(ObjectMonitor* monitor) { + assert(_monitor == nullptr, "only set once"); + _monitor = monitor; + } + +}; + +class LightweightSynchronizer::VerifyThreadState { + bool _no_safepoint; + + public: + VerifyThreadState(JavaThread* locking_thread, JavaThread* current) : _no_safepoint(locking_thread != current) { + assert(current == Thread::current(), "must be"); + assert(locking_thread == current || locking_thread->is_obj_deopt_suspend(), "locking_thread may not run concurrently"); + if (_no_safepoint) { + DEBUG_ONLY(JavaThread::current()->inc_no_safepoint_count();) + } + } + ~VerifyThreadState() { + if (_no_safepoint){ + DEBUG_ONLY(JavaThread::current()->dec_no_safepoint_count();) + } + } +}; + +inline bool LightweightSynchronizer::fast_lock_try_enter(oop obj, LockStack& lock_stack, JavaThread* current) { + markWord mark = obj->mark(); + while (mark.is_unlocked()) { + ensure_lock_stack_space(current); + assert(!lock_stack.is_full(), "must have made room on the lock stack"); + assert(!lock_stack.contains(obj), "thread must not already hold the lock"); + // Try to swing into 'fast-locked' state. + markWord locked_mark = mark.set_fast_locked(); + markWord old_mark = mark; + mark = obj->cas_set_mark(locked_mark, old_mark); + if (old_mark == mark) { + // Successfully fast-locked, push object to lock-stack and return. + lock_stack.push(obj); + return true; + } + } + return false; +} + +bool LightweightSynchronizer::fast_lock_spin_enter(oop obj, LockStack& lock_stack, JavaThread* current, bool observed_deflation) { + assert(UseObjectMonitorTable, "must be"); + // Will spin with exponential backoff with an accumulative O(2^spin_limit) spins. + const int log_spin_limit = os::is_MP() ? LightweightFastLockingSpins : 1; + const int log_min_safepoint_check_interval = 10; + + markWord mark = obj->mark(); + const auto should_spin = [&]() { + if (!mark.has_monitor()) { + // Spin while not inflated. + return true; + } else if (observed_deflation) { + // Spin while monitor is being deflated. + ObjectMonitor* monitor = ObjectSynchronizer::read_monitor(current, obj, mark); + return monitor == nullptr || monitor->is_being_async_deflated(); + } + // Else stop spinning. + return false; + }; + // Always attempt to lock once even when safepoint synchronizing. + bool should_process = false; + for (int i = 0; should_spin() && !should_process && i < log_spin_limit; i++) { + // Spin with exponential backoff. + const int total_spin_count = 1 << i; + const int inner_spin_count = MIN2(1 << log_min_safepoint_check_interval, total_spin_count); + const int outer_spin_count = total_spin_count / inner_spin_count; + for (int outer = 0; outer < outer_spin_count; outer++) { + should_process = SafepointMechanism::should_process(current); + if (should_process) { + // Stop spinning for safepoint. + break; + } + for (int inner = 1; inner < inner_spin_count; inner++) { + SpinPause(); + } + } + + if (fast_lock_try_enter(obj, lock_stack, current)) return true; + } + return false; +} + +void LightweightSynchronizer::enter_for(Handle obj, BasicLock* lock, JavaThread* locking_thread) { + assert(LockingMode == LM_LIGHTWEIGHT, "must be"); + JavaThread* current = JavaThread::current(); + VerifyThreadState vts(locking_thread, current); + + if (obj->klass()->is_value_based()) { + ObjectSynchronizer::handle_sync_on_value_based_class(obj, locking_thread); + } + + locking_thread->inc_held_monitor_count(); + + CacheSetter cache_setter(locking_thread, lock); + + LockStack& lock_stack = locking_thread->lock_stack(); + + ObjectMonitor* monitor = nullptr; + if (lock_stack.contains(obj())) { + monitor = inflate_fast_locked_object(obj(), ObjectSynchronizer::inflate_cause_monitor_enter, locking_thread, current); + bool entered = monitor->enter_for(locking_thread); + assert(entered, "recursive ObjectMonitor::enter_for must succeed"); + } else { + // It is assumed that enter_for must enter on an object without contention. + monitor = inflate_and_enter(obj(), ObjectSynchronizer::inflate_cause_monitor_enter, locking_thread, current); + } + + assert(monitor != nullptr, "LightweightSynchronizer::enter_for must succeed"); + cache_setter.set_monitor(monitor); +} + +void LightweightSynchronizer::enter(Handle obj, BasicLock* lock, JavaThread* current) { + assert(LockingMode == LM_LIGHTWEIGHT, "must be"); + assert(current == JavaThread::current(), "must be"); + + if (obj->klass()->is_value_based()) { + ObjectSynchronizer::handle_sync_on_value_based_class(obj, current); + } + + current->inc_held_monitor_count(); + + CacheSetter cache_setter(current, lock); + + // Used when deflation is observed. Progress here requires progress + // from the deflator. After observing that the deflator is not + // making progress (after two yields), switch to sleeping. + SpinYield spin_yield(0, 2); + bool observed_deflation = false; + + LockStack& lock_stack = current->lock_stack(); + + if (!lock_stack.is_full() && lock_stack.try_recursive_enter(obj())) { + // Recursively fast locked + return; + } + + if (lock_stack.contains(obj())) { + ObjectMonitor* monitor = inflate_fast_locked_object(obj(), ObjectSynchronizer::inflate_cause_monitor_enter, current, current); + bool entered = monitor->enter(current); + assert(entered, "recursive ObjectMonitor::enter must succeed"); + cache_setter.set_monitor(monitor); + return; + } + + while (true) { + // Fast-locking does not use the 'lock' argument. + // Fast-lock spinning to avoid inflating for short critical sections. + // The goal is to only inflate when the extra cost of using ObjectMonitors + // is worth it. + // If deflation has been observed we also spin while deflation is ongoing. + if (fast_lock_try_enter(obj(), lock_stack, current)) { + return; + } else if (UseObjectMonitorTable && fast_lock_spin_enter(obj(), lock_stack, current, observed_deflation)) { + return; + } + + if (observed_deflation) { + spin_yield.wait(); + } + + ObjectMonitor* monitor = inflate_and_enter(obj(), ObjectSynchronizer::inflate_cause_monitor_enter, current, current); + if (monitor != nullptr) { + cache_setter.set_monitor(monitor); + return; + } + + // If inflate_and_enter returns nullptr it is because a deflated monitor + // was encountered. Fallback to fast locking. The deflater is responsible + // for clearing out the monitor and transitioning the markWord back to + // fast locking. + observed_deflation = true; + } +} + +void LightweightSynchronizer::exit(oop object, JavaThread* current) { + assert(LockingMode == LM_LIGHTWEIGHT, "must be"); + assert(current == Thread::current(), "must be"); + + markWord mark = object->mark(); + assert(!mark.is_unlocked(), "must be"); + + LockStack& lock_stack = current->lock_stack(); + if (mark.is_fast_locked()) { + if (lock_stack.try_recursive_exit(object)) { + // This is a recursive exit which succeeded + return; + } + if (lock_stack.is_recursive(object)) { + // Must inflate recursive locks if try_recursive_exit fails + // This happens for un-structured unlocks, could potentially + // fix try_recursive_exit to handle these. + inflate_fast_locked_object(object, ObjectSynchronizer::inflate_cause_vm_internal, current, current); + } + } + + while (mark.is_fast_locked()) { + markWord unlocked_mark = mark.set_unlocked(); + markWord old_mark = mark; + mark = object->cas_set_mark(unlocked_mark, old_mark); + if (old_mark == mark) { + // CAS successful, remove from lock_stack + size_t recursion = lock_stack.remove(object) - 1; + assert(recursion == 0, "Should not have unlocked here"); + return; + } + } + + assert(mark.has_monitor(), "must be"); + // The monitor exists + ObjectMonitor* monitor = ObjectSynchronizer::read_monitor(current, object, mark); + if (monitor->is_owner_anonymous()) { + assert(current->lock_stack().contains(object), "current must have object on its lock stack"); + monitor->set_owner_from_anonymous(current); + monitor->set_recursions(current->lock_stack().remove(object) - 1); + } + + monitor->exit(current); +} + +// LightweightSynchronizer::inflate_locked_or_imse is used to to get an inflated +// ObjectMonitor* with LM_LIGHTWEIGHT. It is used from contexts which require +// an inflated ObjectMonitor* for a monitor, and expects to throw a +// java.lang.IllegalMonitorStateException if it is not held by the current +// thread. Such as notify/wait and jni_exit. LM_LIGHTWEIGHT keeps it invariant +// that it only inflates if it is already locked by the current thread or the +// current thread is in the process of entering. To maintain this invariant we +// need to throw a java.lang.IllegalMonitorStateException before inflating if +// the current thread is not the owner. +// LightweightSynchronizer::inflate_locked_or_imse facilitates this. +ObjectMonitor* LightweightSynchronizer::inflate_locked_or_imse(oop obj, ObjectSynchronizer::InflateCause cause, TRAPS) { + assert(LockingMode == LM_LIGHTWEIGHT, "must be"); + JavaThread* current = THREAD; + + for (;;) { + markWord mark = obj->mark_acquire(); + if (mark.is_unlocked()) { + // No lock, IMSE. + THROW_MSG_(vmSymbols::java_lang_IllegalMonitorStateException(), + "current thread is not owner", nullptr); + } + + if (mark.is_fast_locked()) { + if (!current->lock_stack().contains(obj)) { + // Fast locked by other thread, IMSE. + THROW_MSG_(vmSymbols::java_lang_IllegalMonitorStateException(), + "current thread is not owner", nullptr); + } else { + // Current thread owns the lock, must inflate + return inflate_fast_locked_object(obj, cause, current, current); + } + } + + assert(mark.has_monitor(), "must be"); + ObjectMonitor* monitor = ObjectSynchronizer::read_monitor(current, obj, mark); + if (monitor != nullptr) { + if (monitor->is_owner_anonymous()) { + LockStack& lock_stack = current->lock_stack(); + if (lock_stack.contains(obj)) { + // Current thread owns the lock but someone else inflated it. + // Fix owner and pop lock stack. + monitor->set_owner_from_anonymous(current); + monitor->set_recursions(lock_stack.remove(obj) - 1); + } else { + // Fast locked (and inflated) by other thread, or deflation in progress, IMSE. + THROW_MSG_(vmSymbols::java_lang_IllegalMonitorStateException(), + "current thread is not owner", nullptr); + } + } + return monitor; + } + } +} + +ObjectMonitor* LightweightSynchronizer::inflate_into_object_header(oop object, ObjectSynchronizer::InflateCause cause, JavaThread* inflating_thread, Thread* current) { + + // The JavaThread* inflating_thread parameter is only used by LM_LIGHTWEIGHT and requires + // that the inflating_thread == Thread::current() or is suspended throughout the call by + // some other mechanism. + // Even with LM_LIGHTWEIGHT the thread might be nullptr when called from a non + // JavaThread. (As may still be the case from FastHashCode). However it is only + // important for the correctness of the LM_LIGHTWEIGHT algorithm that the thread + // is set when called from ObjectSynchronizer::enter from the owning thread, + // ObjectSynchronizer::enter_for from any thread, or ObjectSynchronizer::exit. + EventJavaMonitorInflate event; + + for (;;) { + const markWord mark = object->mark_acquire(); + + // The mark can be in one of the following states: + // * inflated - Just return if using stack-locking. + // If using fast-locking and the ObjectMonitor owner + // is anonymous and the inflating_thread owns the + // object lock, then we make the inflating_thread + // the ObjectMonitor owner and remove the lock from + // the inflating_thread's lock stack. + // * fast-locked - Coerce it to inflated from fast-locked. + // * unlocked - Aggressively inflate the object. + + // CASE: inflated + if (mark.has_monitor()) { + ObjectMonitor* inf = mark.monitor(); + markWord dmw = inf->header(); + assert(dmw.is_neutral(), "invariant: header=" INTPTR_FORMAT, dmw.value()); + if (inf->is_owner_anonymous() && + inflating_thread != nullptr && inflating_thread->lock_stack().contains(object)) { + inf->set_owner_from_anonymous(inflating_thread); + size_t removed = inflating_thread->lock_stack().remove(object); + inf->set_recursions(removed - 1); + } + return inf; + } + + // CASE: fast-locked + // Could be fast-locked either by the inflating_thread or by some other thread. + // + // Note that we allocate the ObjectMonitor speculatively, _before_ + // attempting to set the object's mark to the new ObjectMonitor. If + // the inflating_thread owns the monitor, then we set the ObjectMonitor's + // owner to the inflating_thread. Otherwise, we set the ObjectMonitor's owner + // to anonymous. If we lose the race to set the object's mark to the + // new ObjectMonitor, then we just delete it and loop around again. + // + if (mark.is_fast_locked()) { + ObjectMonitor* monitor = new ObjectMonitor(object); + monitor->set_header(mark.set_unlocked()); + bool own = inflating_thread != nullptr && inflating_thread->lock_stack().contains(object); + if (own) { + // Owned by inflating_thread. + monitor->set_owner_from(nullptr, inflating_thread); + } else { + // Owned by somebody else. + monitor->set_owner_anonymous(); + } + markWord monitor_mark = markWord::encode(monitor); + markWord old_mark = object->cas_set_mark(monitor_mark, mark); + if (old_mark == mark) { + // Success! Return inflated monitor. + if (own) { + size_t removed = inflating_thread->lock_stack().remove(object); + monitor->set_recursions(removed - 1); + } + // Once the ObjectMonitor is configured and object is associated + // with the ObjectMonitor, it is safe to allow async deflation: + ObjectSynchronizer::_in_use_list.add(monitor); + + // Hopefully the performance counters are allocated on distinct + // cache lines to avoid false sharing on MP systems ... + OM_PERFDATA_OP(Inflations, inc()); + log_inflate(current, object, cause); + if (event.should_commit()) { + post_monitor_inflate_event(&event, object, cause); + } + return monitor; + } else { + delete monitor; + continue; // Interference -- just retry + } + } + + // CASE: unlocked + // TODO-FIXME: for entry we currently inflate and then try to CAS _owner. + // If we know we're inflating for entry it's better to inflate by swinging a + // pre-locked ObjectMonitor pointer into the object header. A successful + // CAS inflates the object *and* confers ownership to the inflating thread. + // In the current implementation we use a 2-step mechanism where we CAS() + // to inflate and then CAS() again to try to swing _owner from null to current. + // An inflateTry() method that we could call from enter() would be useful. + + assert(mark.is_unlocked(), "invariant: header=" INTPTR_FORMAT, mark.value()); + ObjectMonitor* m = new ObjectMonitor(object); + // prepare m for installation - set monitor to initial state + m->set_header(mark); + + if (object->cas_set_mark(markWord::encode(m), mark) != mark) { + delete m; + m = nullptr; + continue; + // interference - the markword changed - just retry. + // The state-transitions are one-way, so there's no chance of + // live-lock -- "Inflated" is an absorbing state. + } + + // Once the ObjectMonitor is configured and object is associated + // with the ObjectMonitor, it is safe to allow async deflation: + ObjectSynchronizer::_in_use_list.add(m); + + // Hopefully the performance counters are allocated on distinct + // cache lines to avoid false sharing on MP systems ... + OM_PERFDATA_OP(Inflations, inc()); + log_inflate(current, object, cause); + if (event.should_commit()) { + post_monitor_inflate_event(&event, object, cause); + } + return m; + } +} + +ObjectMonitor* LightweightSynchronizer::inflate_fast_locked_object(oop object, ObjectSynchronizer::InflateCause cause, JavaThread* locking_thread, JavaThread* current) { + assert(LockingMode == LM_LIGHTWEIGHT, "only used for lightweight"); + VerifyThreadState vts(locking_thread, current); + assert(locking_thread->lock_stack().contains(object), "locking_thread must have object on its lock stack"); + + ObjectMonitor* monitor; + + if (!UseObjectMonitorTable) { + return inflate_into_object_header(object, cause, locking_thread, current); + } + + // Inflating requires a hash code + ObjectSynchronizer::FastHashCode(current, object); + + markWord mark = object->mark_acquire(); + assert(!mark.is_unlocked(), "Cannot be unlocked"); + + for (;;) { + // Fetch the monitor from the table + monitor = get_or_insert_monitor(object, current, cause); + + // ObjectMonitors are always inserted as anonymously owned, this thread is + // the current holder of the monitor. So unless the entry is stale and + // contains a deflating monitor it must be anonymously owned. + if (monitor->is_owner_anonymous()) { + // The monitor must be anonymously owned if it was added + assert(monitor == get_monitor_from_table(current, object), "The monitor must be found"); + // New fresh monitor + break; + } + + // If the monitor was not anonymously owned then we got a deflating monitor + // from the table. We need to let the deflator make progress and remove this + // entry before we are allowed to add a new one. + os::naked_yield(); + assert(monitor->is_being_async_deflated(), "Should be the reason"); + } + + // Set the mark word; loop to handle concurrent updates to other parts of the mark word + while (mark.is_fast_locked()) { + mark = object->cas_set_mark(mark.set_has_monitor(), mark); + } + + // Indicate that the monitor now has a known owner + monitor->set_owner_from_anonymous(locking_thread); + + // Remove the entry from the thread's lock stack + monitor->set_recursions(locking_thread->lock_stack().remove(object) - 1); + + if (locking_thread == current) { + // Only change the thread local state of the current thread. + locking_thread->om_set_monitor_cache(monitor); + } + + return monitor; +} + +ObjectMonitor* LightweightSynchronizer::inflate_and_enter(oop object, ObjectSynchronizer::InflateCause cause, JavaThread* locking_thread, JavaThread* current) { + assert(LockingMode == LM_LIGHTWEIGHT, "only used for lightweight"); + VerifyThreadState vts(locking_thread, current); + + // Note: In some paths (deoptimization) the 'current' thread inflates and + // enters the lock on behalf of the 'locking_thread' thread. + + ObjectMonitor* monitor = nullptr; + + if (!UseObjectMonitorTable) { + // Do the old inflate and enter. + monitor = inflate_into_object_header(object, cause, locking_thread, current); + + bool entered; + if (locking_thread == current) { + entered = monitor->enter(locking_thread); + } else { + entered = monitor->enter_for(locking_thread); + } + + // enter returns false for deflation found. + return entered ? monitor : nullptr; + } + + NoSafepointVerifier nsv; + + // Lightweight monitors require that hash codes are installed first + ObjectSynchronizer::FastHashCode(locking_thread, object); + + // Try to get the monitor from the thread-local cache. + // There's no need to use the cache if we are locking + // on behalf of another thread. + if (current == locking_thread) { + monitor = current->om_get_from_monitor_cache(object); + } + + // Get or create the monitor + if (monitor == nullptr) { + monitor = get_or_insert_monitor(object, current, cause); + } + + if (monitor->try_enter(locking_thread)) { + return monitor; + } + + // Holds is_being_async_deflated() stable throughout this function. + ObjectMonitorContentionMark contention_mark(monitor); + + /// First handle the case where the monitor from the table is deflated + if (monitor->is_being_async_deflated()) { + // The MonitorDeflation thread is deflating the monitor. The locking thread + // must spin until further progress has been made. + + const markWord mark = object->mark_acquire(); + + if (mark.has_monitor()) { + // Waiting on the deflation thread to remove the deflated monitor from the table. + os::naked_yield(); + + } else if (mark.is_fast_locked()) { + // Some other thread managed to fast-lock the lock, or this is a + // recursive lock from the same thread; yield for the deflation + // thread to remove the deflated monitor from the table. + os::naked_yield(); + + } else { + assert(mark.is_unlocked(), "Implied"); + // Retry immediately + } + + // Retry + return nullptr; + } + + for (;;) { + const markWord mark = object->mark_acquire(); + // The mark can be in one of the following states: + // * inflated - If the ObjectMonitor owner is anonymous + // and the locking_thread owns the object + // lock, then we make the locking_thread + // the ObjectMonitor owner and remove the + // lock from the locking_thread's lock stack. + // * fast-locked - Coerce it to inflated from fast-locked. + // * neutral - Inflate the object. Successful CAS is locked + + // CASE: inflated + if (mark.has_monitor()) { + LockStack& lock_stack = locking_thread->lock_stack(); + if (monitor->is_owner_anonymous() && lock_stack.contains(object)) { + // The lock is fast-locked by the locking thread, + // convert it to a held monitor with a known owner. + monitor->set_owner_from_anonymous(locking_thread); + monitor->set_recursions(lock_stack.remove(object) - 1); + } + + break; // Success + } + + // CASE: fast-locked + // Could be fast-locked either by locking_thread or by some other thread. + // + if (mark.is_fast_locked()) { + markWord old_mark = object->cas_set_mark(mark.set_has_monitor(), mark); + if (old_mark != mark) { + // CAS failed + continue; + } + + // Success! Return inflated monitor. + LockStack& lock_stack = locking_thread->lock_stack(); + if (lock_stack.contains(object)) { + // The lock is fast-locked by the locking thread, + // convert it to a held monitor with a known owner. + monitor->set_owner_from_anonymous(locking_thread); + monitor->set_recursions(lock_stack.remove(object) - 1); + } + + break; // Success + } + + // CASE: neutral (unlocked) + + // Catch if the object's header is not neutral (not locked and + // not marked is what we care about here). + assert(mark.is_neutral(), "invariant: header=" INTPTR_FORMAT, mark.value()); + markWord old_mark = object->cas_set_mark(mark.set_has_monitor(), mark); + if (old_mark != mark) { + // CAS failed + continue; + } + + // Transitioned from unlocked to monitor means locking_thread owns the lock. + monitor->set_owner_from_anonymous(locking_thread); + + return monitor; + } + + if (current == locking_thread) { + // One round of spinning + if (monitor->spin_enter(locking_thread)) { + return monitor; + } + + // Monitor is contended, take the time before entering to fix the lock stack. + LockStackInflateContendedLocks().inflate(current); + } + + // enter can block for safepoints; clear the unhandled object oop + PauseNoSafepointVerifier pnsv(&nsv); + object = nullptr; + + if (current == locking_thread) { + monitor->enter_with_contention_mark(locking_thread, contention_mark); + } else { + monitor->enter_for_with_contention_mark(locking_thread, contention_mark); + } + + return monitor; +} + +void LightweightSynchronizer::deflate_monitor(Thread* current, oop obj, ObjectMonitor* monitor) { + if (obj != nullptr) { + deflate_mark_word(obj); + } + bool removed = remove_monitor(current, monitor, obj); + if (obj != nullptr) { + assert(removed, "Should have removed the entry if obj was alive"); + } +} + +ObjectMonitor* LightweightSynchronizer::get_monitor_from_table(Thread* current, oop obj) { + assert(UseObjectMonitorTable, "must be"); + return ObjectMonitorTable::monitor_get(current, obj); +} + +bool LightweightSynchronizer::contains_monitor(Thread* current, ObjectMonitor* monitor) { + assert(UseObjectMonitorTable, "must be"); + return ObjectMonitorTable::contains_monitor(current, monitor); +} + +bool LightweightSynchronizer::quick_enter(oop obj, BasicLock* lock, JavaThread* current) { + assert(current->thread_state() == _thread_in_Java, "must be"); + assert(obj != nullptr, "must be"); + NoSafepointVerifier nsv; + + // If quick_enter succeeds with entering, the cache should be in a valid initialized state. + CacheSetter cache_setter(current, lock); + + LockStack& lock_stack = current->lock_stack(); + if (lock_stack.is_full()) { + // Always go into runtime if the lock stack is full. + return false; + } + + const markWord mark = obj->mark(); + +#ifndef _LP64 + // Only for 32bit which has limited support for fast locking outside the runtime. + if (lock_stack.try_recursive_enter(obj)) { + // Recursive lock successful. + current->inc_held_monitor_count(); + return true; + } + + if (mark.is_unlocked()) { + markWord locked_mark = mark.set_fast_locked(); + if (obj->cas_set_mark(locked_mark, mark) == mark) { + // Successfully fast-locked, push object to lock-stack and return. + lock_stack.push(obj); + current->inc_held_monitor_count(); + return true; + } + } +#endif + + if (mark.has_monitor()) { + ObjectMonitor* const monitor = UseObjectMonitorTable ? current->om_get_from_monitor_cache(obj) : + ObjectSynchronizer::read_monitor(mark); + + if (monitor == nullptr) { + // Take the slow-path on a cache miss. + return false; + } + + if (monitor->try_enter(current)) { + // ObjectMonitor enter successful. + cache_setter.set_monitor(monitor); + current->inc_held_monitor_count(); + return true; + } + } + + // Slow-path. + return false; +} diff --git a/src/hotspot/share/runtime/lightweightSynchronizer.hpp b/src/hotspot/share/runtime/lightweightSynchronizer.hpp new file mode 100644 index 00000000000..c546988f778 --- /dev/null +++ b/src/hotspot/share/runtime/lightweightSynchronizer.hpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_RUNTIME_LIGHTWEIGHTSYNCHRONIZER_HPP +#define SHARE_RUNTIME_LIGHTWEIGHTSYNCHRONIZER_HPP + +#include "memory/allStatic.hpp" +#include "runtime/javaThread.hpp" +#include "runtime/objectMonitor.hpp" +#include "runtime/synchronizer.hpp" + +class ObjectMonitorTable; + +class LightweightSynchronizer : AllStatic { + private: + static ObjectMonitor* get_or_insert_monitor_from_table(oop object, JavaThread* current, bool* inserted); + static ObjectMonitor* get_or_insert_monitor(oop object, JavaThread* current, ObjectSynchronizer::InflateCause cause); + + static ObjectMonitor* add_monitor(JavaThread* current, ObjectMonitor* monitor, oop obj); + static bool remove_monitor(Thread* current, ObjectMonitor* monitor, oop obj); + + static void deflate_mark_word(oop object); + + static void ensure_lock_stack_space(JavaThread* current); + + class CacheSetter; + class LockStackInflateContendedLocks; + class VerifyThreadState; + + public: + static void initialize(); + + static bool needs_resize(); + static bool resize_table(JavaThread* current); + + private: + static inline bool fast_lock_try_enter(oop obj, LockStack& lock_stack, JavaThread* current); + static bool fast_lock_spin_enter(oop obj, LockStack& lock_stack, JavaThread* current, bool observed_deflation); + + public: + static void enter_for(Handle obj, BasicLock* lock, JavaThread* locking_thread); + static void enter(Handle obj, BasicLock* lock, JavaThread* current); + static void exit(oop object, JavaThread* current); + + static ObjectMonitor* inflate_into_object_header(oop object, ObjectSynchronizer::InflateCause cause, JavaThread* inflating_thread, Thread* current); + static ObjectMonitor* inflate_locked_or_imse(oop object, ObjectSynchronizer::InflateCause cause, TRAPS); + static ObjectMonitor* inflate_fast_locked_object(oop object, ObjectSynchronizer::InflateCause cause, JavaThread* locking_thread, JavaThread* current); + static ObjectMonitor* inflate_and_enter(oop object, ObjectSynchronizer::InflateCause cause, JavaThread* locking_thread, JavaThread* current); + + static void deflate_monitor(Thread* current, oop obj, ObjectMonitor* monitor); + + static ObjectMonitor* get_monitor_from_table(Thread* current, oop obj); + + static bool contains_monitor(Thread* current, ObjectMonitor* monitor); + + static bool quick_enter(oop obj, BasicLock* Lock, JavaThread* current); +}; + +#endif // SHARE_RUNTIME_LIGHTWEIGHTSYNCHRONIZER_HPP diff --git a/src/hotspot/share/runtime/lockStack.cpp b/src/hotspot/share/runtime/lockStack.cpp index 2f783c97c99..185fc931b67 100644 --- a/src/hotspot/share/runtime/lockStack.cpp +++ b/src/hotspot/share/runtime/lockStack.cpp @@ -29,17 +29,20 @@ #include "oops/markWord.hpp" #include "oops/oop.inline.hpp" #include "runtime/globals.hpp" +#include "runtime/javaThread.inline.hpp" #include "runtime/lockStack.inline.hpp" #include "runtime/objectMonitor.inline.hpp" #include "runtime/safepoint.hpp" #include "runtime/stackWatermark.hpp" #include "runtime/stackWatermarkSet.inline.hpp" +#include "runtime/synchronizer.inline.hpp" #include "runtime/thread.hpp" #include "utilities/copy.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/growableArray.hpp" #include "utilities/ostream.hpp" +#include "utilities/sizes.hpp" #include @@ -114,3 +117,11 @@ void LockStack::print_on(outputStream* st) { } } } + +OMCache::OMCache(JavaThread* jt) : _entries() { + STATIC_ASSERT(std::is_standard_layout::value); + STATIC_ASSERT(std::is_standard_layout::value); + STATIC_ASSERT(offsetof(OMCache, _null_sentinel) == offsetof(OMCache, _entries) + + offsetof(OMCache::OMCacheEntry, _oop) + + OMCache::CAPACITY * in_bytes(oop_to_oop_difference())); +} diff --git a/src/hotspot/share/runtime/lockStack.hpp b/src/hotspot/share/runtime/lockStack.hpp index 064f70a37fb..de32eb41259 100644 --- a/src/hotspot/share/runtime/lockStack.hpp +++ b/src/hotspot/share/runtime/lockStack.hpp @@ -32,18 +32,20 @@ #include "utilities/sizes.hpp" class JavaThread; +class ObjectMonitor; class OopClosure; class outputStream; template class GrowableArray; +class Thread; class LockStack { friend class LockStackTest; friend class VMStructs; JVMCI_ONLY(friend class JVMCIVMStructs;) -public: + public: static const int CAPACITY = 8; -private: + private: // TODO: It would be very useful if JavaThread::lock_stack_offset() and friends were constexpr, // but this is currently not the case because we're using offset_of() which is non-constexpr, @@ -73,7 +75,7 @@ class LockStack { // Given an offset (in bytes) calculate the index into the lock-stack. static inline int to_index(uint32_t offset); -public: + public: static ByteSize top_offset() { return byte_offset_of(LockStack, _top); } static ByteSize base_offset() { return byte_offset_of(LockStack, _base); } @@ -123,4 +125,29 @@ class LockStack { void print_on(outputStream* st); }; +class OMCache { + friend class VMStructs; + public: + static constexpr int CAPACITY = 8; + + private: + struct OMCacheEntry { + oop _oop = nullptr; + ObjectMonitor* _monitor = nullptr; + } _entries[CAPACITY]; + const oop _null_sentinel = nullptr; + + public: + static ByteSize entries_offset() { return byte_offset_of(OMCache, _entries); } + static constexpr ByteSize oop_to_oop_difference() { return in_ByteSize(sizeof(OMCacheEntry)); } + static constexpr ByteSize oop_to_monitor_difference() { return in_ByteSize(sizeof(oop)); } + + explicit OMCache(JavaThread* jt); + + inline ObjectMonitor* get_monitor(oop o); + inline void set_monitor(ObjectMonitor* monitor); + inline void clear(); + +}; + #endif // SHARE_RUNTIME_LOCKSTACK_HPP diff --git a/src/hotspot/share/runtime/lockStack.inline.hpp b/src/hotspot/share/runtime/lockStack.inline.hpp index 7a9874a9291..515ca94c741 100644 --- a/src/hotspot/share/runtime/lockStack.inline.hpp +++ b/src/hotspot/share/runtime/lockStack.inline.hpp @@ -31,6 +31,8 @@ #include "memory/iterator.hpp" #include "runtime/javaThread.hpp" +#include "runtime/lightweightSynchronizer.hpp" +#include "runtime/objectMonitor.inline.hpp" #include "runtime/safepoint.hpp" #include "runtime/stackWatermark.hpp" #include "runtime/stackWatermarkSet.inline.hpp" @@ -222,4 +224,54 @@ inline void LockStack::oops_do(OopClosure* cl) { verify("post-oops-do"); } +inline void OMCache::set_monitor(ObjectMonitor *monitor) { + const int end = OMCache::CAPACITY - 1; + + oop obj = monitor->object_peek(); + assert(obj != nullptr, "must be alive"); + assert(monitor == LightweightSynchronizer::get_monitor_from_table(JavaThread::current(), obj), "must exist in table"); + + OMCacheEntry to_insert = {obj, monitor}; + + for (int i = 0; i < end; ++i) { + if (_entries[i]._oop == obj || + _entries[i]._monitor == nullptr || + _entries[i]._monitor->is_being_async_deflated()) { + // Use stale slot. + _entries[i] = to_insert; + return; + } + // Swap with the most recent value. + ::swap(to_insert, _entries[i]); + } + _entries[end] = to_insert; +} + +inline ObjectMonitor* OMCache::get_monitor(oop o) { + for (int i = 0; i < CAPACITY; ++i) { + if (_entries[i]._oop == o) { + assert(_entries[i]._monitor != nullptr, "monitor must exist"); + if (_entries[i]._monitor->is_being_async_deflated()) { + // Bad monitor + // Shift down rest + for (; i < CAPACITY - 1; ++i) { + _entries[i] = _entries[i + 1]; + } + // Clear end + _entries[i] = {}; + return nullptr; + } + return _entries[i]._monitor; + } + } + return nullptr; +} + +inline void OMCache::clear() { + for (size_t i = 0; i < CAPACITY; ++i) { + // Clear + _entries[i] = {}; + } +} + #endif // SHARE_RUNTIME_LOCKSTACK_INLINE_HPP diff --git a/src/hotspot/share/runtime/objectMonitor.cpp b/src/hotspot/share/runtime/objectMonitor.cpp index c509ed691cd..367d79a5283 100644 --- a/src/hotspot/share/runtime/objectMonitor.cpp +++ b/src/hotspot/share/runtime/objectMonitor.cpp @@ -43,6 +43,7 @@ #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/javaThread.inline.hpp" +#include "runtime/lightweightSynchronizer.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/objectMonitor.hpp" #include "runtime/objectMonitor.inline.hpp" @@ -53,6 +54,7 @@ #include "runtime/safepointMechanism.inline.hpp" #include "runtime/sharedRuntime.hpp" #include "services/threadService.hpp" +#include "utilities/debug.hpp" #include "utilities/dtrace.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" @@ -246,7 +248,7 @@ static void check_object_context() { } ObjectMonitor::ObjectMonitor(oop object) : - _header(markWord::zero()), + _metadata(0), _object(_oop_storage, object), _owner(nullptr), _previous_owner_tid(0), @@ -272,10 +274,6 @@ oop ObjectMonitor::object() const { return _object.resolve(); } -oop ObjectMonitor::object_peek() const { - return _object.peek(); -} - void ObjectMonitor::ExitOnSuspend::operator()(JavaThread* current) { if (current->is_suspended()) { _om->_recursions = 0; @@ -297,109 +295,147 @@ void ObjectMonitor::ClearSuccOnSuspend::operator()(JavaThread* current) { } } +#define assert_mark_word_consistency() \ + assert(UseObjectMonitorTable || object()->mark() == markWord::encode(this), \ + "object mark must match encoded this: mark=" INTPTR_FORMAT \ + ", encoded this=" INTPTR_FORMAT, object()->mark().value(), \ + markWord::encode(this).value()); + // ----------------------------------------------------------------------------- // Enter support -bool ObjectMonitor::enter_for(JavaThread* locking_thread) { +bool ObjectMonitor::enter_is_async_deflating() { + if (is_being_async_deflated()) { + if (!UseObjectMonitorTable) { + const oop l_object = object(); + if (l_object != nullptr) { + // Attempt to restore the header/dmw to the object's header so that + // we only retry once if the deflater thread happens to be slow. + install_displaced_markword_in_object(l_object); + } + } + return true; + } + + return false; +} + +void ObjectMonitor::enter_for_with_contention_mark(JavaThread* locking_thread, ObjectMonitorContentionMark& contention_mark) { // Used by ObjectSynchronizer::enter_for to enter for another thread. // The monitor is private to or already owned by locking_thread which must be suspended. // So this code may only contend with deflation. assert(locking_thread == Thread::current() || locking_thread->is_obj_deopt_suspend(), "must be"); + assert(contention_mark._monitor == this, "must be"); + assert(!is_being_async_deflated(), "must be"); - // Block out deflation as soon as possible. - add_to_contentions(1); + + void* prev_owner = try_set_owner_from(nullptr, locking_thread); bool success = false; - if (!is_being_async_deflated()) { - void* prev_owner = try_set_owner_from(nullptr, locking_thread); - if (prev_owner == nullptr) { - assert(_recursions == 0, "invariant"); - success = true; - } else if (prev_owner == locking_thread) { - _recursions++; - success = true; - } else if (prev_owner == DEFLATER_MARKER) { - // Racing with deflation. - prev_owner = try_set_owner_from(DEFLATER_MARKER, locking_thread); - if (prev_owner == DEFLATER_MARKER) { - // Cancelled deflation. Increment contentions as part of the deflation protocol. - add_to_contentions(1); - success = true; - } else if (prev_owner == nullptr) { - // At this point we cannot race with deflation as we have both incremented - // contentions, seen contention > 0 and seen a DEFLATER_MARKER. - // success will only be false if this races with something other than - // deflation. - prev_owner = try_set_owner_from(nullptr, locking_thread); - success = prev_owner == nullptr; - } - } else if (LockingMode == LM_LEGACY && locking_thread->is_lock_owned((address)prev_owner)) { - assert(_recursions == 0, "must be"); - _recursions = 1; - set_owner_from_BasicLock(prev_owner, locking_thread); + if (prev_owner == nullptr) { + assert(_recursions == 0, "invariant"); + success = true; + } else if (prev_owner == locking_thread) { + _recursions++; + success = true; + } else if (prev_owner == DEFLATER_MARKER) { + // Racing with deflation. + prev_owner = try_set_owner_from(DEFLATER_MARKER, locking_thread); + if (prev_owner == DEFLATER_MARKER) { + // Cancelled deflation. Increment contentions as part of the deflation protocol. + add_to_contentions(1); success = true; + } else if (prev_owner == nullptr) { + // At this point we cannot race with deflation as we have both incremented + // contentions, seen contention > 0 and seen a DEFLATER_MARKER. + // success will only be false if this races with something other than + // deflation. + prev_owner = try_set_owner_from(nullptr, locking_thread); + success = prev_owner == nullptr; } - assert(success, "Failed to enter_for: locking_thread=" INTPTR_FORMAT - ", this=" INTPTR_FORMAT "{owner=" INTPTR_FORMAT "}, observed owner: " INTPTR_FORMAT, - p2i(locking_thread), p2i(this), p2i(owner_raw()), p2i(prev_owner)); - } else { - // Async deflation is in progress and our contentions increment - // above lost the race to async deflation. Undo the work and - // force the caller to retry. - const oop l_object = object(); - if (l_object != nullptr) { - // Attempt to restore the header/dmw to the object's header so that - // we only retry once if the deflater thread happens to be slow. - install_displaced_markword_in_object(l_object); - } + } else if (LockingMode == LM_LEGACY && locking_thread->is_lock_owned((address)prev_owner)) { + assert(_recursions == 0, "must be"); + _recursions = 1; + set_owner_from_BasicLock(prev_owner, locking_thread); + success = true; } + assert(success, "Failed to enter_for: locking_thread=" INTPTR_FORMAT + ", this=" INTPTR_FORMAT "{owner=" INTPTR_FORMAT "}, observed owner: " INTPTR_FORMAT, + p2i(locking_thread), p2i(this), p2i(owner_raw()), p2i(prev_owner)); +} + +bool ObjectMonitor::enter_for(JavaThread* locking_thread) { - add_to_contentions(-1); + // Block out deflation as soon as possible. + ObjectMonitorContentionMark contention_mark(this); - assert(!success || owner_raw() == locking_thread, "must be"); + // Check for deflation. + if (enter_is_async_deflating()) { + return false; + } - return success; + enter_for_with_contention_mark(locking_thread, contention_mark); + assert(owner_raw() == locking_thread, "must be"); + return true; } -bool ObjectMonitor::enter(JavaThread* current) { - assert(current == JavaThread::current(), "must be"); - // The following code is ordered to check the most common cases first - // and to reduce RTS->RTO cache line upgrades on SPARC and IA32 processors. - - void* cur = try_set_owner_from(nullptr, current); - if (cur == nullptr) { +bool ObjectMonitor::try_enter(JavaThread* current) { + // TryLock avoids the CAS + TryLockResult r = TryLock(current); + if (r == TryLockResult::Success) { assert(_recursions == 0, "invariant"); return true; } - if (cur == current) { - // TODO-FIXME: check for integer overflow! BUGID 6557169. + if (r == TryLockResult::HasOwner && owner() == current) { _recursions++; return true; } - if (LockingMode != LM_LIGHTWEIGHT && current->is_lock_owned((address)cur)) { + void* cur = owner_raw(); + if (LockingMode == LM_LEGACY && current->is_lock_owned((address)cur)) { assert(_recursions == 0, "internal state error"); _recursions = 1; set_owner_from_BasicLock(cur, current); // Convert from BasicLock* to Thread*. return true; } + return false; +} + +bool ObjectMonitor::spin_enter(JavaThread* current) { + assert(current == JavaThread::current(), "must be"); + + // Check for recursion. + if (try_enter(current)) { + return true; + } + + // Check for deflation. + if (enter_is_async_deflating()) { + return false; + } + // We've encountered genuine contention. - // Try one round of spinning *before* enqueueing current - // and before going through the awkward and expensive state - // transitions. The following spin is strictly optional ... + // Do one round of spinning. // Note that if we acquire the monitor from an initial spin // we forgo posting JVMTI events and firing DTRACE probes. if (TrySpin(current)) { assert(owner_raw() == current, "must be current: owner=" INTPTR_FORMAT, p2i(owner_raw())); assert(_recursions == 0, "must be 0: recursions=" INTX_FORMAT, _recursions); - assert(object()->mark() == markWord::encode(this), - "object mark must match encoded this: mark=" INTPTR_FORMAT - ", encoded this=" INTPTR_FORMAT, object()->mark().value(), - markWord::encode(this).value()); + assert_mark_word_consistency(); + return true; + } + + return false; +} + +bool ObjectMonitor::enter(JavaThread* current) { + assert(current == JavaThread::current(), "must be"); + + if (spin_enter(current)) { return true; } @@ -408,22 +444,25 @@ bool ObjectMonitor::enter(JavaThread* current) { assert(!SafepointSynchronize::is_at_safepoint(), "invariant"); assert(current->thread_state() != _thread_blocked, "invariant"); - // Keep track of contention for JVM/TI and M&M queries. - add_to_contentions(1); - if (is_being_async_deflated()) { - // Async deflation is in progress and our contentions increment - // above lost the race to async deflation. Undo the work and - // force the caller to retry. - const oop l_object = object(); - if (l_object != nullptr) { - // Attempt to restore the header/dmw to the object's header so that - // we only retry once if the deflater thread happens to be slow. - install_displaced_markword_in_object(l_object); - } - add_to_contentions(-1); + // Keep is_being_async_deflated stable across the rest of enter + ObjectMonitorContentionMark contention_mark(this); + + // Check for deflation. + if (enter_is_async_deflating()) { return false; } + // At this point this ObjectMonitor cannot be deflated, finish contended enter + enter_with_contention_mark(current, contention_mark); + return true; +} + +void ObjectMonitor::enter_with_contention_mark(JavaThread *current, ObjectMonitorContentionMark &cm) { + assert(current == JavaThread::current(), "must be"); + assert(owner_raw() != current, "must be"); + assert(cm._monitor == this, "must be"); + assert(!is_being_async_deflated(), "must be"); + JFR_ONLY(JfrConditionalFlush flush(current);) EventJavaMonitorEnter event; if (event.is_started()) { @@ -480,14 +519,13 @@ bool ObjectMonitor::enter(JavaThread* current) { // the monitor free and clear. } - add_to_contentions(-1); assert(contentions() >= 0, "must not be negative: contentions=%d", contentions()); // Must either set _recursions = 0 or ASSERT _recursions == 0. assert(_recursions == 0, "invariant"); assert(owner_raw() == current, "invariant"); assert(_succ != current, "invariant"); - assert(object()->mark() == markWord::encode(this), "invariant"); + assert_mark_word_consistency(); // The thread -- now the owner -- is back in vm mode. // Report the glorious news via TI,DTrace and jvmstat. @@ -516,7 +554,6 @@ bool ObjectMonitor::enter(JavaThread* current) { event.commit(); } OM_PERFDATA_OP(ContendedLockAttempts, inc()); - return true; } // Caveat: TryLock() is not necessarily serializing if it returns failure. @@ -549,7 +586,7 @@ ObjectMonitor::TryLockResult ObjectMonitor::TryLock(JavaThread* current) { // (contentions < 0) // Contending threads that see that condition know to retry their operation. // -bool ObjectMonitor::deflate_monitor() { +bool ObjectMonitor::deflate_monitor(Thread* current) { if (is_busy()) { // Easy checks are first - the ObjectMonitor is busy so no deflation. return false; @@ -620,7 +657,11 @@ bool ObjectMonitor::deflate_monitor() { p2i(obj), obj->mark().value(), obj->klass()->external_name()); } + } + if (UseObjectMonitorTable) { + LightweightSynchronizer::deflate_monitor(current, obj, this); + } else if (obj != nullptr) { // Install the old mark word if nobody else has already done it. install_displaced_markword_in_object(obj); } @@ -636,6 +677,7 @@ bool ObjectMonitor::deflate_monitor() { // monitor and by other threads that have detected a race with the // deflation process. void ObjectMonitor::install_displaced_markword_in_object(const oop obj) { + assert(!UseObjectMonitorTable, "ObjectMonitorTable has no dmw"); // This function must only be called when (owner == DEFLATER_MARKER // && contentions <= 0), but we can't guarantee that here because // those values could change when the ObjectMonitor gets moved from @@ -972,12 +1014,11 @@ void ObjectMonitor::EnterI(JavaThread* current) { void ObjectMonitor::ReenterI(JavaThread* current, ObjectWaiter* currentNode) { assert(current != nullptr, "invariant"); + assert(current->thread_state() != _thread_blocked, "invariant"); assert(currentNode != nullptr, "invariant"); assert(currentNode->_thread == current, "invariant"); assert(_waiters > 0, "invariant"); - assert(object()->mark() == markWord::encode(this), "invariant"); - - assert(current->thread_state() != _thread_blocked, "invariant"); + assert_mark_word_consistency(); for (;;) { ObjectWaiter::TStates v = currentNode->TState; @@ -1042,7 +1083,7 @@ void ObjectMonitor::ReenterI(JavaThread* current, ObjectWaiter* currentNode) { // In addition, current.TState is stable. assert(owner_raw() == current, "invariant"); - assert(object()->mark() == markWord::encode(this), "invariant"); + assert_mark_word_consistency(); UnlinkAfterAcquire(current, currentNode); if (_succ == current) _succ = nullptr; assert(_succ != current, "invariant"); @@ -1668,7 +1709,7 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) { // Verify a few postconditions assert(owner_raw() == current, "invariant"); assert(_succ != current, "invariant"); - assert(object()->mark() == markWord::encode(this), "invariant"); + assert_mark_word_consistency(); // check if the notification happened if (!WasNotified) { @@ -2185,7 +2226,7 @@ void ObjectMonitor::print() const { print_on(tty); } // Print the ObjectMonitor like a debugger would: // // (ObjectMonitor) 0x00007fdfb6012e40 = { -// _header = 0x0000000000000001 +// _metadata = 0x0000000000000001 // _object = 0x000000070ff45fd0 // _pad_buf0 = { // [0] = '\0' @@ -2214,7 +2255,7 @@ void ObjectMonitor::print() const { print_on(tty); } // void ObjectMonitor::print_debug_style_on(outputStream* st) const { st->print_cr("(ObjectMonitor*) " INTPTR_FORMAT " = {", p2i(this)); - st->print_cr(" _header = " INTPTR_FORMAT, header().value()); + st->print_cr(" _metadata = " INTPTR_FORMAT, _metadata); st->print_cr(" _object = " INTPTR_FORMAT, p2i(object_peek())); st->print_cr(" _pad_buf0 = {"); st->print_cr(" [0] = '\\0'"); diff --git a/src/hotspot/share/runtime/objectMonitor.hpp b/src/hotspot/share/runtime/objectMonitor.hpp index fdc482a3555..ef85559c2b6 100644 --- a/src/hotspot/share/runtime/objectMonitor.hpp +++ b/src/hotspot/share/runtime/objectMonitor.hpp @@ -33,6 +33,7 @@ #include "utilities/checkedCast.hpp" class ObjectMonitor; +class ObjectMonitorContentionMark; class ParkEvent; // ObjectWaiter serves as a "proxy" or surrogate thread. @@ -69,20 +70,21 @@ class ObjectWaiter : public StackObj { // // ObjectMonitor Layout Overview/Highlights/Restrictions: // -// - The _header field must be at offset 0 because the displaced header +// - The _metadata field must be at offset 0 because the displaced header // from markWord is stored there. We do not want markWord.hpp to include // ObjectMonitor.hpp to avoid exposing ObjectMonitor everywhere. This // means that ObjectMonitor cannot inherit from any other class nor can // it use any virtual member functions. This restriction is critical to // the proper functioning of the VM. -// - The _header and _owner fields should be separated by enough space +// - The _metadata and _owner fields should be separated by enough space // to avoid false sharing due to parallel access by different threads. // This is an advisory recommendation. // - The general layout of the fields in ObjectMonitor is: -// _header +// _metadata // // // _owner +// // // - The VM assumes write ordering and machine word alignment with // respect to the _owner field and the that can @@ -106,20 +108,19 @@ class ObjectWaiter : public StackObj { // in synchronizer.cpp. Also see TEST_VM(SynchronizerTest, sanity) gtest. // // Futures notes: -// - Separating _owner from the by enough space to -// avoid false sharing might be profitable. Given -// http://blogs.oracle.com/dave/entry/cas_and_cache_trivia_invalidate -// we know that the CAS in monitorenter will invalidate the line -// underlying _owner. We want to avoid an L1 data cache miss on that -// same line for monitorexit. Putting these : -// _recursions, _EntryList, _cxq, and _succ, all of which may be -// fetched in the inflated unlock path, on a different cache line -// would make them immune to CAS-based invalidation from the _owner -// field. +// - Separating _owner from the by enough space to +// avoid false sharing might be profitable. Given that the CAS in +// monitorenter will invalidate the line underlying _owner. We want +// to avoid an L1 data cache miss on that same line for monitorexit. +// Putting these : +// _recursions, _EntryList, _cxq, and _succ, all of which may be +// fetched in the inflated unlock path, on a different cache line +// would make them immune to CAS-based invalidation from the _owner +// field. // -// - The _recursions field should be of type int, or int32_t but not -// intptr_t. There's no reason to use a 64-bit type for this field -// in a 64-bit JVM. +// - The _recursions field should be of type int, or int32_t but not +// intptr_t. There's no reason to use a 64-bit type for this field +// in a 64-bit JVM. #define OM_CACHE_LINE_SIZE DEFAULT_CACHE_LINE_SIZE @@ -131,15 +132,19 @@ class ObjectMonitor : public CHeapObj { static OopStorage* _oop_storage; - // The sync code expects the header field to be at offset zero (0). - // Enforced by the assert() in header_addr(). - volatile markWord _header; // displaced object header word - mark + // The sync code expects the metadata field to be at offset zero (0). + // Enforced by the assert() in metadata_addr(). + // * LM_LIGHTWEIGHT with UseObjectMonitorTable: + // Contains the _object's hashCode. + // * LM_LEGACY, LM_MONITOR, LM_LIGHTWEIGHT without UseObjectMonitorTable: + // Contains the displaced object header word - mark + volatile uintptr_t _metadata; // metadata WeakHandle _object; // backward object pointer - // Separate _header and _owner on different cache lines since both can - // have busy multi-threaded access. _header and _object are set at initial + // Separate _metadata and _owner on different cache lines since both can + // have busy multi-threaded access. _metadata and _object are set at initial // inflation. The _object does not change, so it is a good choice to share - // its cache line with _header. - DEFINE_PAD_MINUS_SIZE(0, OM_CACHE_LINE_SIZE, sizeof(volatile markWord) + + // its cache line with _metadata. + DEFINE_PAD_MINUS_SIZE(0, OM_CACHE_LINE_SIZE, sizeof(_metadata) + sizeof(WeakHandle)); // Used by async deflation as a marker in the _owner field. // Note that the choice of the two markers is peculiar: @@ -149,12 +154,13 @@ class ObjectMonitor : public CHeapObj { // and small values encode much better. // - We test for anonymous owner by testing for the lowest bit, therefore // DEFLATER_MARKER must *not* have that bit set. - #define DEFLATER_MARKER reinterpret_cast(2) -public: + static const uintptr_t DEFLATER_MARKER_VALUE = 2; + #define DEFLATER_MARKER reinterpret_cast(DEFLATER_MARKER_VALUE) + public: // NOTE: Typed as uintptr_t so that we can pick it up in SA, via vmStructs. static const uintptr_t ANONYMOUS_OWNER = 1; -private: + private: static void* anon_owner_ptr() { return reinterpret_cast(ANONYMOUS_OWNER); } void* volatile _owner; // pointer to owning thread OR BasicLock @@ -181,10 +187,9 @@ class ObjectMonitor : public CHeapObj { // along with other fields to determine if an ObjectMonitor can be // deflated. It is also used by the async deflation protocol. See // ObjectMonitor::deflate_monitor(). - protected: + ObjectWaiter* volatile _WaitSet; // LL of threads wait()ing on the monitor volatile int _waiters; // number of waiting threads - private: volatile int _WaitSetLock; // protects Wait Queue - simple spinlock public: @@ -213,6 +218,7 @@ class ObjectMonitor : public CHeapObj { static int Knob_SpinLimit; + static ByteSize metadata_offset() { return byte_offset_of(ObjectMonitor, _metadata); } static ByteSize owner_offset() { return byte_offset_of(ObjectMonitor, _owner); } static ByteSize recursions_offset() { return byte_offset_of(ObjectMonitor, _recursions); } static ByteSize cxq_offset() { return byte_offset_of(ObjectMonitor, _cxq); } @@ -233,9 +239,15 @@ class ObjectMonitor : public CHeapObj { #define OM_OFFSET_NO_MONITOR_VALUE_TAG(f) \ ((in_bytes(ObjectMonitor::f ## _offset())) - checked_cast(markWord::monitor_value)) - markWord header() const; - volatile markWord* header_addr(); - void set_header(markWord hdr); + uintptr_t metadata() const; + void set_metadata(uintptr_t value); + volatile uintptr_t* metadata_addr(); + + markWord header() const; + void set_header(markWord hdr); + + intptr_t hash() const; + void set_hash(intptr_t hash); bool is_busy() const { // TODO-FIXME: assert _owner == null implies _recursions = 0 @@ -306,6 +318,8 @@ class ObjectMonitor : public CHeapObj { oop object() const; oop object_peek() const; + bool object_is_dead() const; + bool object_refers_to(oop obj) const; // Returns true if the specified thread owns the ObjectMonitor. Otherwise // returns false and throws IllegalMonitorStateException (IMSE). @@ -328,9 +342,15 @@ class ObjectMonitor : public CHeapObj { ClearSuccOnSuspend(ObjectMonitor* om) : _om(om) {} void operator()(JavaThread* current); }; + + bool enter_is_async_deflating(); public: + void enter_for_with_contention_mark(JavaThread* locking_thread, ObjectMonitorContentionMark& contention_mark); bool enter_for(JavaThread* locking_thread); bool enter(JavaThread* current); + bool try_enter(JavaThread* current); + bool spin_enter(JavaThread* current); + void enter_with_contention_mark(JavaThread* current, ObjectMonitorContentionMark& contention_mark); void exit(JavaThread* current, bool not_suspended = true); void wait(jlong millis, bool interruptible, TRAPS); void notify(TRAPS); @@ -364,8 +384,23 @@ class ObjectMonitor : public CHeapObj { void ExitEpilog(JavaThread* current, ObjectWaiter* Wakee); // Deflation support - bool deflate_monitor(); + bool deflate_monitor(Thread* current); + private: void install_displaced_markword_in_object(const oop obj); }; +// RAII object to ensure that ObjectMonitor::is_being_async_deflated() is +// stable within the context of this mark. +class ObjectMonitorContentionMark : StackObj { + DEBUG_ONLY(friend class ObjectMonitor;) + + ObjectMonitor* _monitor; + + NONCOPYABLE(ObjectMonitorContentionMark); + + public: + explicit ObjectMonitorContentionMark(ObjectMonitor* monitor); + ~ObjectMonitorContentionMark(); +}; + #endif // SHARE_RUNTIME_OBJECTMONITOR_HPP diff --git a/src/hotspot/share/runtime/objectMonitor.inline.hpp b/src/hotspot/share/runtime/objectMonitor.inline.hpp index b371663eeb3..d26c459b1b4 100644 --- a/src/hotspot/share/runtime/objectMonitor.inline.hpp +++ b/src/hotspot/share/runtime/objectMonitor.inline.hpp @@ -29,9 +29,13 @@ #include "logging/log.hpp" #include "oops/access.inline.hpp" +#include "oops/markWord.hpp" #include "runtime/atomic.hpp" +#include "runtime/globals.hpp" #include "runtime/lockStack.inline.hpp" #include "runtime/synchronizer.hpp" +#include "utilities/checkedCast.hpp" +#include "utilities/globalDefinitions.hpp" inline bool ObjectMonitor::is_entered(JavaThread* current) const { if (LockingMode == LM_LIGHTWEIGHT) { @@ -49,16 +53,38 @@ inline bool ObjectMonitor::is_entered(JavaThread* current) const { return false; } -inline markWord ObjectMonitor::header() const { - return Atomic::load(&_header); +inline uintptr_t ObjectMonitor::metadata() const { + return Atomic::load(&_metadata); +} + +inline void ObjectMonitor::set_metadata(uintptr_t value) { + Atomic::store(&_metadata, value); } -inline volatile markWord* ObjectMonitor::header_addr() { - return &_header; +inline volatile uintptr_t* ObjectMonitor::metadata_addr() { + STATIC_ASSERT(std::is_standard_layout::value); + STATIC_ASSERT(offsetof(ObjectMonitor, _metadata) == 0); + return &_metadata; +} + +inline markWord ObjectMonitor::header() const { + assert(!UseObjectMonitorTable, "Lightweight locking with OM table does not use header"); + return markWord(metadata()); } inline void ObjectMonitor::set_header(markWord hdr) { - Atomic::store(&_header, hdr); + assert(!UseObjectMonitorTable, "Lightweight locking with OM table does not use header"); + set_metadata(hdr.value()); +} + +inline intptr_t ObjectMonitor::hash() const { + assert(UseObjectMonitorTable, "Only used by lightweight locking with OM table"); + return metadata(); +} + +inline void ObjectMonitor::set_hash(intptr_t hash) { + assert(UseObjectMonitorTable, "Only used by lightweight locking with OM table"); + set_metadata(hash); } inline int ObjectMonitor::waiters() const { @@ -180,4 +206,31 @@ inline void ObjectMonitor::set_next_om(ObjectMonitor* new_value) { Atomic::store(&_next_om, new_value); } +inline ObjectMonitorContentionMark::ObjectMonitorContentionMark(ObjectMonitor* monitor) + : _monitor(monitor) { + _monitor->add_to_contentions(1); +} + +inline ObjectMonitorContentionMark::~ObjectMonitorContentionMark() { + _monitor->add_to_contentions(-1); +} + +inline oop ObjectMonitor::object_peek() const { + if (_object.is_null()) { + return nullptr; + } + return _object.peek(); +} + +inline bool ObjectMonitor::object_is_dead() const { + return object_peek() == nullptr; +} + +inline bool ObjectMonitor::object_refers_to(oop obj) const { + if (_object.is_null()) { + return false; + } + return _object.peek() == obj; +} + #endif // SHARE_RUNTIME_OBJECTMONITOR_INLINE_HPP diff --git a/src/hotspot/share/runtime/safepoint.cpp b/src/hotspot/share/runtime/safepoint.cpp index 05f59de4a17..bea0b68354e 100644 --- a/src/hotspot/share/runtime/safepoint.cpp +++ b/src/hotspot/share/runtime/safepoint.cpp @@ -731,6 +731,11 @@ void ThreadSafepointState::account_safe_thread() { DEBUG_ONLY(_thread->set_visited_for_critical_count(SafepointSynchronize::safepoint_counter());) assert(!_safepoint_safe, "Must be unsafe before safe"); _safepoint_safe = true; + + // The oops in the monitor cache are cleared to prevent stale cache entries + // from keeping dead objects alive. Because these oops are always cleared + // before safepoint operations they are not visited in JavaThread::oops_do. + _thread->om_clear_monitor_cache(); } void ThreadSafepointState::restart() { diff --git a/src/hotspot/share/runtime/serviceThread.cpp b/src/hotspot/share/runtime/serviceThread.cpp index a81285ac97c..f5653ccd5f4 100644 --- a/src/hotspot/share/runtime/serviceThread.cpp +++ b/src/hotspot/share/runtime/serviceThread.cpp @@ -32,20 +32,21 @@ #include "classfile/vmClasses.hpp" #include "gc/shared/oopStorage.hpp" #include "gc/shared/oopStorageSet.hpp" -#include "memory/universe.hpp" #include "interpreter/oopMapCache.hpp" +#include "memory/universe.hpp" #include "oops/oopHandle.inline.hpp" +#include "prims/jvmtiImpl.hpp" +#include "prims/jvmtiTagMap.hpp" +#include "prims/resolvedMethodTable.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/java.hpp" #include "runtime/javaCalls.hpp" #include "runtime/jniHandles.hpp" -#include "runtime/serviceThread.hpp" +#include "runtime/lightweightSynchronizer.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/os.hpp" -#include "prims/jvmtiImpl.hpp" -#include "prims/jvmtiTagMap.hpp" -#include "prims/resolvedMethodTable.hpp" +#include "runtime/serviceThread.hpp" #include "services/diagnosticArgument.hpp" #include "services/diagnosticFramework.hpp" #include "services/finalizerService.hpp" @@ -94,6 +95,7 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) { bool cldg_cleanup_work = false; bool jvmti_tagmap_work = false; bool oopmap_cache_work = false; + bool object_monitor_table_work = false; { // Need state transition ThreadBlockInVM so that this thread // will be handled by safepoint correctly when this thread is @@ -121,7 +123,8 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) { (oop_handles_to_release = JavaThread::has_oop_handles_to_release()) | (cldg_cleanup_work = ClassLoaderDataGraph::should_clean_metaspaces_and_reset()) | (jvmti_tagmap_work = JvmtiTagMap::has_object_free_events_and_reset()) | - (oopmap_cache_work = OopMapCache::has_cleanup_work()) + (oopmap_cache_work = OopMapCache::has_cleanup_work()) | + (object_monitor_table_work = LightweightSynchronizer::needs_resize()) ) == 0) { // Wait until notified that there is some work to do or timer expires. // Some cleanup requests don't notify the ServiceThread so work needs to be done at periodic intervals. @@ -183,6 +186,10 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) { if (oopmap_cache_work) { OopMapCache::cleanup(); } + + if (object_monitor_table_work) { + LightweightSynchronizer::resize_table(jt); + } } } diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 0eec7e4c34c..0587032ec5c 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -58,6 +58,7 @@ #include "prims/nativeLookup.hpp" #include "runtime/arguments.hpp" #include "runtime/atomic.hpp" +#include "runtime/basicLock.inline.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/init.hpp" @@ -69,13 +70,14 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/stackWatermarkSet.hpp" #include "runtime/stubRoutines.hpp" -#include "runtime/synchronizer.hpp" +#include "runtime/synchronizer.inline.hpp" #include "runtime/vframe.inline.hpp" #include "runtime/vframeArray.hpp" #include "runtime/vm_version.hpp" #include "utilities/copy.hpp" #include "utilities/dtrace.hpp" #include "utilities/events.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/resourceHash.hpp" #include "utilities/macros.hpp" #include "utilities/xmlstream.hpp" @@ -1883,7 +1885,7 @@ void SharedRuntime::monitor_enter_helper(oopDesc* obj, BasicLock* lock, JavaThre if (!SafepointSynchronize::is_synchronizing()) { // Only try quick_enter() if we're not trying to reach a safepoint // so that the calling thread reaches the safepoint more quickly. - if (ObjectSynchronizer::quick_enter(obj, current, lock)) { + if (ObjectSynchronizer::quick_enter(obj, lock, current)) { return; } } @@ -2945,6 +2947,8 @@ JRT_LEAF(intptr_t*, SharedRuntime::OSR_migration_begin( JavaThread *current) ) // Now the displaced header is free to move because the // object's header no longer refers to it. buf[i] = (intptr_t)lock->displaced_header().value(); + } else if (UseObjectMonitorTable) { + buf[i] = (intptr_t)lock->object_monitor_cache(); } #ifdef ASSERT else { diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp index b4ff263d455..d8fb7a4734a 100644 --- a/src/hotspot/share/runtime/synchronizer.cpp +++ b/src/hotspot/share/runtime/synchronizer.cpp @@ -35,12 +35,14 @@ #include "oops/markWord.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.hpp" +#include "runtime/basicLock.inline.hpp" #include "runtime/frame.inline.hpp" #include "runtime/globals.hpp" #include "runtime/handles.inline.hpp" #include "runtime/handshake.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/javaThread.hpp" +#include "runtime/lightweightSynchronizer.hpp" #include "runtime/lockStack.inline.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/objectMonitor.hpp" @@ -52,7 +54,7 @@ #include "runtime/safepointVerifiers.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" -#include "runtime/synchronizer.hpp" +#include "runtime/synchronizer.inline.hpp" #include "runtime/threads.hpp" #include "runtime/timer.hpp" #include "runtime/trimNativeHeap.hpp" @@ -276,6 +278,10 @@ void ObjectSynchronizer::initialize() { // Start the timer for deflations, so it does not trigger immediately. _last_async_deflation_time_ns = os::javaTimeNanos(); + + if (LockingMode == LM_LIGHTWEIGHT) { + LightweightSynchronizer::initialize(); + } } MonitorList ObjectSynchronizer::_in_use_list; @@ -349,7 +355,11 @@ bool ObjectSynchronizer::quick_notify(oopDesc* obj, JavaThread* current, bool al } if (mark.has_monitor()) { - ObjectMonitor* const mon = mark.monitor(); + ObjectMonitor* const mon = read_monitor(current, obj, mark); + if (LockingMode == LM_LIGHTWEIGHT && mon == nullptr) { + // Racing with inflation/deflation go slow path + return false; + } assert(mon->object() == oop(obj), "invariant"); if (mon->owner() != current) return false; // slow-path for IMS exception @@ -376,6 +386,13 @@ bool ObjectSynchronizer::quick_notify(oopDesc* obj, JavaThread* current, bool al return false; } +static bool useHeavyMonitors() { +#if defined(X86) || defined(AARCH64) || defined(PPC64) || defined(RISCV64) || defined(S390) + return LockingMode == LM_MONITOR; +#else + return false; +#endif +} // The LockNode emitted directly at the synchronization site would have // been too big if it were to have included support for the cases of inflated @@ -383,33 +400,24 @@ bool ObjectSynchronizer::quick_notify(oopDesc* obj, JavaThread* current, bool al // Note that we can't safely call AsyncPrintJavaStack() from within // quick_enter() as our thread state remains _in_Java. -bool ObjectSynchronizer::quick_enter(oop obj, JavaThread* current, - BasicLock * lock) { +bool ObjectSynchronizer::quick_enter_legacy(oop obj, BasicLock* lock, JavaThread* current) { assert(current->thread_state() == _thread_in_Java, "invariant"); - NoSafepointVerifier nsv; - if (obj == nullptr) return false; // Need to throw NPE - if (obj->klass()->is_value_based()) { - return false; + if (useHeavyMonitors()) { + return false; // Slow path } if (LockingMode == LM_LIGHTWEIGHT) { - LockStack& lock_stack = current->lock_stack(); - if (lock_stack.is_full()) { - // Always go into runtime if the lock stack is full. - return false; - } - if (lock_stack.try_recursive_enter(obj)) { - // Recursive lock successful. - current->inc_held_monitor_count(); - return true; - } + return LightweightSynchronizer::quick_enter(obj, lock, current); } + assert(LockingMode == LM_LEGACY, "legacy mode below"); + const markWord mark = obj->mark(); if (mark.has_monitor()) { - ObjectMonitor* const m = mark.monitor(); + + ObjectMonitor* const m = read_monitor(mark); // An async deflation or GC can race us before we manage to make // the ObjectMonitor busy by setting the owner below. If we detect // that race we just bail out to the slow-path here. @@ -429,18 +437,16 @@ bool ObjectSynchronizer::quick_enter(oop obj, JavaThread* current, return true; } - if (LockingMode != LM_LIGHTWEIGHT) { - // This Java Monitor is inflated so obj's header will never be - // displaced to this thread's BasicLock. Make the displaced header - // non-null so this BasicLock is not seen as recursive nor as - // being locked. We do this unconditionally so that this thread's - // BasicLock cannot be mis-interpreted by any stack walkers. For - // performance reasons, stack walkers generally first check for - // stack-locking in the object's header, the second check is for - // recursive stack-locking in the displaced header in the BasicLock, - // and last are the inflated Java Monitor (ObjectMonitor) checks. - lock->set_displaced_header(markWord::unused_mark()); - } + // This Java Monitor is inflated so obj's header will never be + // displaced to this thread's BasicLock. Make the displaced header + // non-null so this BasicLock is not seen as recursive nor as + // being locked. We do this unconditionally so that this thread's + // BasicLock cannot be mis-interpreted by any stack walkers. For + // performance reasons, stack walkers generally first check for + // stack-locking in the object's header, the second check is for + // recursive stack-locking in the displaced header in the BasicLock, + // and last are the inflated Java Monitor (ObjectMonitor) checks. + lock->set_displaced_header(markWord::unused_mark()); if (owner == nullptr && m->try_set_owner_from(nullptr, current) == nullptr) { assert(m->_recursions == 0, "invariant"); @@ -508,14 +514,6 @@ void ObjectSynchronizer::handle_sync_on_value_based_class(Handle obj, JavaThread } } -static bool useHeavyMonitors() { -#if defined(X86) || defined(AARCH64) || defined(PPC64) || defined(RISCV64) || defined(S390) - return LockingMode == LM_MONITOR; -#else - return false; -#endif -} - // ----------------------------------------------------------------------------- // Monitor Enter/Exit @@ -524,6 +522,11 @@ void ObjectSynchronizer::enter_for(Handle obj, BasicLock* lock, JavaThread* lock // the locking_thread with respect to the current thread. Currently only used when // deoptimizing and re-locking locks. See Deoptimization::relock_objects assert(locking_thread == Thread::current() || locking_thread->is_obj_deopt_suspend(), "must be"); + + if (LockingMode == LM_LIGHTWEIGHT) { + return LightweightSynchronizer::enter_for(obj, lock, locking_thread); + } + if (!enter_fast_impl(obj, lock, locking_thread)) { // Inflated ObjectMonitor::enter_for is required @@ -540,8 +543,7 @@ void ObjectSynchronizer::enter_for(Handle obj, BasicLock* lock, JavaThread* lock } } -void ObjectSynchronizer::enter(Handle obj, BasicLock* lock, JavaThread* current) { - assert(current == Thread::current(), "must be"); +void ObjectSynchronizer::enter_legacy(Handle obj, BasicLock* lock, JavaThread* current) { if (!enter_fast_impl(obj, lock, current)) { // Inflated ObjectMonitor::enter is required @@ -561,6 +563,7 @@ void ObjectSynchronizer::enter(Handle obj, BasicLock* lock, JavaThread* current) // of this algorithm. Make sure to update that code if the following function is // changed. The implementation is extremely sensitive to race condition. Be careful. bool ObjectSynchronizer::enter_fast_impl(Handle obj, BasicLock* lock, JavaThread* locking_thread) { + assert(LockingMode != LM_LIGHTWEIGHT, "Use LightweightSynchronizer"); if (obj->klass()->is_value_based()) { handle_sync_on_value_based_class(obj, locking_thread); @@ -569,61 +572,7 @@ bool ObjectSynchronizer::enter_fast_impl(Handle obj, BasicLock* lock, JavaThread locking_thread->inc_held_monitor_count(); if (!useHeavyMonitors()) { - if (LockingMode == LM_LIGHTWEIGHT) { - // Fast-locking does not use the 'lock' argument. - LockStack& lock_stack = locking_thread->lock_stack(); - if (lock_stack.is_full()) { - // We unconditionally make room on the lock stack by inflating - // the least recently locked object on the lock stack. - - // About the choice to inflate least recently locked object. - // First we must chose to inflate a lock, either some lock on - // the lock-stack or the lock that is currently being entered - // (which may or may not be on the lock-stack). - // Second the best lock to inflate is a lock which is entered - // in a control flow where there are only a very few locks being - // used, as the costly part of inflated locking is inflation, - // not locking. But this property is entirely program dependent. - // Third inflating the lock currently being entered on when it - // is not present on the lock-stack will result in a still full - // lock-stack. This creates a scenario where every deeper nested - // monitorenter must call into the runtime. - // The rational here is as follows: - // Because we cannot (currently) figure out the second, and want - // to avoid the third, we inflate a lock on the lock-stack. - // The least recently locked lock is chosen as it is the lock - // with the longest critical section. - - log_info(monitorinflation)("LockStack capacity exceeded, inflating."); - ObjectMonitor* monitor = inflate_for(locking_thread, lock_stack.bottom(), inflate_cause_vm_internal); - assert(monitor->owner() == locking_thread, "must be owner=" PTR_FORMAT " locking_thread=" PTR_FORMAT " mark=" PTR_FORMAT, - p2i(monitor->owner()), p2i(locking_thread), monitor->object()->mark_acquire().value()); - assert(!lock_stack.is_full(), "must have made room here"); - } - - markWord mark = obj()->mark_acquire(); - while (mark.is_unlocked()) { - // Retry until a lock state change has been observed. cas_set_mark() may collide with non lock bits modifications. - // Try to swing into 'fast-locked' state. - assert(!lock_stack.contains(obj()), "thread must not already hold the lock"); - const markWord locked_mark = mark.set_fast_locked(); - const markWord old_mark = obj()->cas_set_mark(locked_mark, mark); - if (old_mark == mark) { - // Successfully fast-locked, push object to lock-stack and return. - lock_stack.push(obj()); - return true; - } - mark = old_mark; - } - - if (mark.is_fast_locked() && lock_stack.try_recursive_enter(obj())) { - // Recursive lock successful. - return true; - } - - // Failed to fast lock. - return false; - } else if (LockingMode == LM_LEGACY) { + if (LockingMode == LM_LEGACY) { markWord mark = obj->mark(); if (mark.is_unlocked()) { // Anticipate successful CAS -- the ST of the displaced mark must @@ -656,37 +605,12 @@ bool ObjectSynchronizer::enter_fast_impl(Handle obj, BasicLock* lock, JavaThread return false; } -void ObjectSynchronizer::exit(oop object, BasicLock* lock, JavaThread* current) { - current->dec_held_monitor_count(); +void ObjectSynchronizer::exit_legacy(oop object, BasicLock* lock, JavaThread* current) { + assert(LockingMode != LM_LIGHTWEIGHT, "Use LightweightSynchronizer"); if (!useHeavyMonitors()) { markWord mark = object->mark(); - if (LockingMode == LM_LIGHTWEIGHT) { - // Fast-locking does not use the 'lock' argument. - LockStack& lock_stack = current->lock_stack(); - if (mark.is_fast_locked() && lock_stack.try_recursive_exit(object)) { - // Recursively unlocked. - return; - } - - if (mark.is_fast_locked() && lock_stack.is_recursive(object)) { - // This lock is recursive but is not at the top of the lock stack so we're - // doing an unbalanced exit. We have to fall thru to inflation below and - // let ObjectMonitor::exit() do the unlock. - } else { - while (mark.is_fast_locked()) { - // Retry until a lock state change has been observed. cas_set_mark() may collide with non lock bits modifications. - const markWord unlocked_mark = mark.set_unlocked(); - const markWord old_mark = object->cas_set_mark(unlocked_mark, mark); - if (old_mark == mark) { - size_t recursions = lock_stack.remove(object) - 1; - assert(recursions == 0, "must not be recursive here"); - return; - } - mark = old_mark; - } - } - } else if (LockingMode == LM_LEGACY) { + if (LockingMode == LM_LEGACY) { markWord dhw = lock->displaced_header(); if (dhw.value() == 0) { // If the displaced header is null, then this exit matches up with @@ -708,7 +632,7 @@ void ObjectSynchronizer::exit(oop object, BasicLock* lock, JavaThread* current) // Monitor owner's stack and update the BasicLocks because a // Java Monitor can be asynchronously inflated by a thread that // does not own the Java Monitor. - ObjectMonitor* m = mark.monitor(); + ObjectMonitor* m = read_monitor(mark); assert(m->object()->mark() == mark, "invariant"); assert(m->is_entered(current), "invariant"); } @@ -752,8 +676,16 @@ void ObjectSynchronizer::jni_enter(Handle obj, JavaThread* current) { // enter() can make the ObjectMonitor busy. enter() returns false if // we have lost the race to async deflation and we simply try again. while (true) { - ObjectMonitor* monitor = inflate(current, obj(), inflate_cause_jni_enter); - if (monitor->enter(current)) { + ObjectMonitor* monitor; + bool entered; + if (LockingMode == LM_LIGHTWEIGHT) { + entered = LightweightSynchronizer::inflate_and_enter(obj(), inflate_cause_jni_enter, current, current) != nullptr; + } else { + monitor = inflate(current, obj(), inflate_cause_jni_enter); + entered = monitor->enter(current); + } + + if (entered) { current->inc_held_monitor_count(1, true); break; } @@ -765,9 +697,14 @@ void ObjectSynchronizer::jni_enter(Handle obj, JavaThread* current) { void ObjectSynchronizer::jni_exit(oop obj, TRAPS) { JavaThread* current = THREAD; - // The ObjectMonitor* can't be async deflated until ownership is - // dropped inside exit() and the ObjectMonitor* must be !is_busy(). - ObjectMonitor* monitor = inflate(current, obj, inflate_cause_jni_exit); + ObjectMonitor* monitor; + if (LockingMode == LM_LIGHTWEIGHT) { + monitor = LightweightSynchronizer::inflate_locked_or_imse(obj, inflate_cause_jni_exit, CHECK); + } else { + // The ObjectMonitor* can't be async deflated until ownership is + // dropped inside exit() and the ObjectMonitor* must be !is_busy(). + monitor = inflate(current, obj, inflate_cause_jni_exit); + } // If this thread has locked the object, exit the monitor. We // intentionally do not use CHECK on check_owner because we must exit the // monitor even if an exception was already pending. @@ -800,15 +737,22 @@ ObjectLocker::~ObjectLocker() { // ----------------------------------------------------------------------------- // Wait/Notify/NotifyAll // NOTE: must use heavy weight monitor to handle wait() + int ObjectSynchronizer::wait(Handle obj, jlong millis, TRAPS) { JavaThread* current = THREAD; if (millis < 0) { THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative"); } - // The ObjectMonitor* can't be async deflated because the _waiters - // field is incremented before ownership is dropped and decremented - // after ownership is regained. - ObjectMonitor* monitor = inflate(current, obj(), inflate_cause_wait); + + ObjectMonitor* monitor; + if (LockingMode == LM_LIGHTWEIGHT) { + monitor = LightweightSynchronizer::inflate_locked_or_imse(obj(), inflate_cause_wait, CHECK_0); + } else { + // The ObjectMonitor* can't be async deflated because the _waiters + // field is incremented before ownership is dropped and decremented + // after ownership is regained. + monitor = inflate(current, obj(), inflate_cause_wait); + } DTRACE_MONITOR_WAIT_PROBE(monitor, obj(), current, millis); monitor->wait(millis, true, THREAD); // Not CHECK as we need following code @@ -825,9 +769,14 @@ void ObjectSynchronizer::waitUninterruptibly(Handle obj, jlong millis, TRAPS) { if (millis < 0) { THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative"); } - ObjectSynchronizer::inflate(THREAD, - obj(), - inflate_cause_wait)->wait(millis, false, THREAD); + + ObjectMonitor* monitor; + if (LockingMode == LM_LIGHTWEIGHT) { + monitor = LightweightSynchronizer::inflate_locked_or_imse(obj(), inflate_cause_wait, CHECK); + } else { + monitor = inflate(THREAD, obj(), inflate_cause_wait); + } + monitor->wait(millis, false, THREAD); } @@ -846,9 +795,15 @@ void ObjectSynchronizer::notify(Handle obj, TRAPS) { return; } } - // The ObjectMonitor* can't be async deflated until ownership is - // dropped by the calling thread. - ObjectMonitor* monitor = inflate(current, obj(), inflate_cause_notify); + + ObjectMonitor* monitor; + if (LockingMode == LM_LIGHTWEIGHT) { + monitor = LightweightSynchronizer::inflate_locked_or_imse(obj(), inflate_cause_notify, CHECK); + } else { + // The ObjectMonitor* can't be async deflated until ownership is + // dropped by the calling thread. + monitor = inflate(current, obj(), inflate_cause_notify); + } monitor->notify(CHECK); } @@ -868,9 +823,15 @@ void ObjectSynchronizer::notifyall(Handle obj, TRAPS) { return; } } - // The ObjectMonitor* can't be async deflated until ownership is - // dropped by the calling thread. - ObjectMonitor* monitor = inflate(current, obj(), inflate_cause_notify); + + ObjectMonitor* monitor; + if (LockingMode == LM_LIGHTWEIGHT) { + monitor = LightweightSynchronizer::inflate_locked_or_imse(obj(), inflate_cause_notify, CHECK); + } else { + // The ObjectMonitor* can't be async deflated until ownership is + // dropped by the calling thread. + monitor = inflate(current, obj(), inflate_cause_notify); + } monitor->notifyAll(CHECK); } @@ -968,7 +929,7 @@ static markWord read_stable_mark(oop obj) { // There are simple ways to "diffuse" the middle address bits over the // generated hashCode values: -static inline intptr_t get_next_hash(Thread* current, oop obj) { +static intptr_t get_next_hash(Thread* current, oop obj) { intptr_t value = 0; if (hashCode == 0) { // This form uses global Park-Miller RNG. @@ -1008,7 +969,33 @@ static inline intptr_t get_next_hash(Thread* current, oop obj) { return value; } +static intptr_t install_hash_code(Thread* current, oop obj) { + assert(UseObjectMonitorTable && LockingMode == LM_LIGHTWEIGHT, "must be"); + + markWord mark = obj->mark_acquire(); + for (;;) { + intptr_t hash = mark.hash(); + if (hash != 0) { + return hash; + } + + hash = get_next_hash(current, obj); + const markWord old_mark = mark; + const markWord new_mark = old_mark.copy_set_hash(hash); + + mark = obj->cas_set_mark(new_mark, old_mark); + if (old_mark == mark) { + return hash; + } + } +} + intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) { + if (UseObjectMonitorTable) { + // Since the monitor isn't in the object header, the hash can simply be + // installed in the object header. + return install_hash_code(current, obj); + } while (true) { ObjectMonitor* monitor = nullptr; @@ -1102,7 +1089,7 @@ intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) { hash = get_next_hash(current, obj); // get a new hash temp = mark.copy_set_hash(hash) ; // merge the hash into header assert(temp.is_neutral(), "invariant: header=" INTPTR_FORMAT, temp.value()); - uintptr_t v = Atomic::cmpxchg((volatile uintptr_t*)monitor->header_addr(), mark.value(), temp.value()); + uintptr_t v = Atomic::cmpxchg(monitor->metadata_addr(), mark.value(), temp.value()); test = markWord(v); if (test != mark) { // The attempt to update the ObjectMonitor's header/dmw field @@ -1114,7 +1101,7 @@ intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) { assert(test.is_neutral(), "invariant: header=" INTPTR_FORMAT, test.value()); assert(hash != 0, "should only have lost the race to a thread that set a non-zero hash"); } - if (monitor->is_being_async_deflated()) { + if (monitor->is_being_async_deflated() && !UseObjectMonitorTable) { // If we detect that async deflation has occurred, then we // attempt to restore the header/dmw to the object's header // so that we only retry once if the deflater thread happens @@ -1145,11 +1132,25 @@ bool ObjectSynchronizer::current_thread_holds_lock(JavaThread* current, return current->lock_stack().contains(h_obj()); } - if (mark.has_monitor()) { + while (LockingMode == LM_LIGHTWEIGHT && mark.has_monitor()) { + ObjectMonitor* monitor = read_monitor(current, obj, mark); + if (monitor != nullptr) { + return monitor->is_entered(current) != 0; + } + // Racing with inflation/deflation, retry + mark = obj->mark_acquire(); + + if (mark.is_fast_locked()) { + // Some other thread fast_locked, current could not have held the lock + return false; + } + } + + if (LockingMode != LM_LIGHTWEIGHT && mark.has_monitor()) { // Inflated monitor so header points to ObjectMonitor (tagged pointer). // The first stage of async deflation does not affect any field // used by this comparison so the ObjectMonitor* is usable here. - ObjectMonitor* monitor = mark.monitor(); + ObjectMonitor* monitor = read_monitor(mark); return monitor->is_entered(current) != 0; } // Unlocked case, header in place @@ -1173,11 +1174,25 @@ JavaThread* ObjectSynchronizer::get_lock_owner(ThreadsList * t_list, Handle h_ob return Threads::owning_thread_from_object(t_list, h_obj()); } - if (mark.has_monitor()) { + while (LockingMode == LM_LIGHTWEIGHT && mark.has_monitor()) { + ObjectMonitor* monitor = read_monitor(Thread::current(), obj, mark); + if (monitor != nullptr) { + return Threads::owning_thread_from_monitor(t_list, monitor); + } + // Racing with inflation/deflation, retry + mark = obj->mark_acquire(); + + if (mark.is_fast_locked()) { + // Some other thread fast_locked + return Threads::owning_thread_from_object(t_list, h_obj()); + } + } + + if (LockingMode != LM_LIGHTWEIGHT && mark.has_monitor()) { // Inflated monitor so header points to ObjectMonitor (tagged pointer). // The first stage of async deflation does not affect any field // used by this comparison so the ObjectMonitor* is usable here. - ObjectMonitor* monitor = mark.monitor(); + ObjectMonitor* monitor = read_monitor(mark); assert(monitor != nullptr, "monitor should be non-null"); // owning_thread_from_monitor() may also return null here: return Threads::owning_thread_from_monitor(t_list, monitor); @@ -1389,9 +1404,10 @@ static void post_monitor_inflate_event(EventJavaMonitorInflate* event, // Fast path code shared by multiple functions void ObjectSynchronizer::inflate_helper(oop obj) { + assert(LockingMode != LM_LIGHTWEIGHT, "only inflate through enter"); markWord mark = obj->mark_acquire(); if (mark.has_monitor()) { - ObjectMonitor* monitor = mark.monitor(); + ObjectMonitor* monitor = read_monitor(mark); markWord dmw = monitor->header(); assert(dmw.is_neutral(), "sanity check: header=" INTPTR_FORMAT, dmw.value()); return; @@ -1401,39 +1417,25 @@ void ObjectSynchronizer::inflate_helper(oop obj) { ObjectMonitor* ObjectSynchronizer::inflate(Thread* current, oop obj, const InflateCause cause) { assert(current == Thread::current(), "must be"); - if (LockingMode == LM_LIGHTWEIGHT && current->is_Java_thread()) { - return inflate_impl(JavaThread::cast(current), obj, cause); - } - return inflate_impl(nullptr, obj, cause); + assert(LockingMode != LM_LIGHTWEIGHT, "only inflate through enter"); + return inflate_impl(obj, cause); } ObjectMonitor* ObjectSynchronizer::inflate_for(JavaThread* thread, oop obj, const InflateCause cause) { assert(thread == Thread::current() || thread->is_obj_deopt_suspend(), "must be"); - return inflate_impl(thread, obj, cause); -} - -ObjectMonitor* ObjectSynchronizer::inflate_impl(JavaThread* inflating_thread, oop object, const InflateCause cause) { - // The JavaThread* inflating_thread parameter is only used by LM_LIGHTWEIGHT and requires - // that the inflating_thread == Thread::current() or is suspended throughout the call by - // some other mechanism. - // Even with LM_LIGHTWEIGHT the thread might be nullptr when called from a non - // JavaThread. (As may still be the case from FastHashCode). However it is only - // important for the correctness of the LM_LIGHTWEIGHT algorithm that the thread - // is set when called from ObjectSynchronizer::enter from the owning thread, - // ObjectSynchronizer::enter_for from any thread, or ObjectSynchronizer::exit. + assert(LockingMode != LM_LIGHTWEIGHT, "LM_LIGHTWEIGHT cannot use inflate_for"); + return inflate_impl(obj, cause); +} + +ObjectMonitor* ObjectSynchronizer::inflate_impl(oop object, const InflateCause cause) { + assert(LockingMode != LM_LIGHTWEIGHT, "LM_LIGHTWEIGHT cannot use inflate_impl"); EventJavaMonitorInflate event; for (;;) { const markWord mark = object->mark_acquire(); // The mark can be in one of the following states: - // * inflated - Just return if using stack-locking. - // If using fast-locking and the ObjectMonitor owner - // is anonymous and the inflating_thread owns the - // object lock, then we make the inflating_thread - // the ObjectMonitor owner and remove the lock from - // the inflating_thread's lock stack. - // * fast-locked - Coerce it to inflated from fast-locked. + // * inflated - Just return it. // * stack-locked - Coerce it to inflated from stack-locked. // * INFLATING - Busy wait for conversion from stack-locked to // inflated. @@ -1444,80 +1446,18 @@ ObjectMonitor* ObjectSynchronizer::inflate_impl(JavaThread* inflating_thread, oo ObjectMonitor* inf = mark.monitor(); markWord dmw = inf->header(); assert(dmw.is_neutral(), "invariant: header=" INTPTR_FORMAT, dmw.value()); - if (LockingMode == LM_LIGHTWEIGHT && inf->is_owner_anonymous() && - inflating_thread != nullptr && inflating_thread->lock_stack().contains(object)) { - inf->set_owner_from_anonymous(inflating_thread); - size_t removed = inflating_thread->lock_stack().remove(object); - inf->set_recursions(removed - 1); - } return inf; } - if (LockingMode != LM_LIGHTWEIGHT) { - // New lightweight locking does not use INFLATING. - // CASE: inflation in progress - inflating over a stack-lock. - // Some other thread is converting from stack-locked to inflated. - // Only that thread can complete inflation -- other threads must wait. - // The INFLATING value is transient. - // Currently, we spin/yield/park and poll the markword, waiting for inflation to finish. - // We could always eliminate polling by parking the thread on some auxiliary list. - if (mark == markWord::INFLATING()) { - read_stable_mark(object); - continue; - } - } - - // CASE: fast-locked - // Could be fast-locked either by the inflating_thread or by some other thread. - // - // Note that we allocate the ObjectMonitor speculatively, _before_ - // attempting to set the object's mark to the new ObjectMonitor. If - // the inflating_thread owns the monitor, then we set the ObjectMonitor's - // owner to the inflating_thread. Otherwise, we set the ObjectMonitor's owner - // to anonymous. If we lose the race to set the object's mark to the - // new ObjectMonitor, then we just delete it and loop around again. - // - LogStreamHandle(Trace, monitorinflation) lsh; - if (LockingMode == LM_LIGHTWEIGHT && mark.is_fast_locked()) { - ObjectMonitor* monitor = new ObjectMonitor(object); - monitor->set_header(mark.set_unlocked()); - bool own = inflating_thread != nullptr && inflating_thread->lock_stack().contains(object); - if (own) { - // Owned by inflating_thread. - monitor->set_owner_from(nullptr, inflating_thread); - } else { - // Owned by somebody else. - monitor->set_owner_anonymous(); - } - markWord monitor_mark = markWord::encode(monitor); - markWord old_mark = object->cas_set_mark(monitor_mark, mark); - if (old_mark == mark) { - // Success! Return inflated monitor. - if (own) { - size_t removed = inflating_thread->lock_stack().remove(object); - monitor->set_recursions(removed - 1); - } - // Once the ObjectMonitor is configured and object is associated - // with the ObjectMonitor, it is safe to allow async deflation: - _in_use_list.add(monitor); - - // Hopefully the performance counters are allocated on distinct - // cache lines to avoid false sharing on MP systems ... - OM_PERFDATA_OP(Inflations, inc()); - if (log_is_enabled(Trace, monitorinflation)) { - ResourceMark rm; - lsh.print_cr("inflate(has_locker): object=" INTPTR_FORMAT ", mark=" - INTPTR_FORMAT ", type='%s'", p2i(object), - object->mark().value(), object->klass()->external_name()); - } - if (event.should_commit()) { - post_monitor_inflate_event(&event, object, cause); - } - return monitor; - } else { - delete monitor; - continue; // Interference -- just retry - } + // CASE: inflation in progress - inflating over a stack-lock. + // Some other thread is converting from stack-locked to inflated. + // Only that thread can complete inflation -- other threads must wait. + // The INFLATING value is transient. + // Currently, we spin/yield/park and poll the markword, waiting for inflation to finish. + // We could always eliminate polling by parking the thread on some auxiliary list. + if (mark == markWord::INFLATING()) { + read_stable_mark(object); + continue; } // CASE: stack-locked @@ -1531,8 +1471,8 @@ ObjectMonitor* ObjectSynchronizer::inflate_impl(JavaThread* inflating_thread, oo // the odds of inflation contention. If we lose the race to set INFLATING, // then we just delete the ObjectMonitor and loop around again. // + LogStreamHandle(Trace, monitorinflation) lsh; if (LockingMode == LM_LEGACY && mark.has_locker()) { - assert(LockingMode != LM_LIGHTWEIGHT, "cannot happen with new lightweight locking"); ObjectMonitor* m = new ObjectMonitor(object); // Optimistically prepare the ObjectMonitor - anticipate successful CAS // We do this before the CAS in order to minimize the length of time @@ -1664,13 +1604,14 @@ ObjectMonitor* ObjectSynchronizer::inflate_impl(JavaThread* inflating_thread, oo size_t ObjectSynchronizer::deflate_monitor_list(ObjectMonitorDeflationSafepointer* safepointer) { MonitorList::Iterator iter = _in_use_list.iterator(); size_t deflated_count = 0; + Thread* current = Thread::current(); while (iter.has_next()) { if (deflated_count >= (size_t)MonitorDeflationMax) { break; } ObjectMonitor* mid = iter.next(); - if (mid->deflate_monitor()) { + if (mid->deflate_monitor(current)) { deflated_count++; } @@ -1688,6 +1629,11 @@ class HandshakeForDeflation : public HandshakeClosure { void do_thread(Thread* thread) { log_trace(monitorinflation)("HandshakeForDeflation::do_thread: thread=" INTPTR_FORMAT, p2i(thread)); + if (thread->is_Java_thread()) { + // Clear OM cache + JavaThread* jt = JavaThread::cast(thread); + jt->om_clear_monitor_cache(); + } } }; @@ -1834,6 +1780,14 @@ size_t ObjectSynchronizer::deflate_idle_monitors() { GrowableArray delete_list((int)deflated_count); unlinked_count = _in_use_list.unlink_deflated(deflated_count, &delete_list, &safepointer); +#ifdef ASSERT + if (UseObjectMonitorTable) { + for (ObjectMonitor* monitor : delete_list) { + assert(!LightweightSynchronizer::contains_monitor(current, monitor), "Should have been removed"); + } + } +#endif + log.before_handshake(unlinked_count); // A JavaThread needs to handshake in order to safely free the @@ -2042,29 +1996,35 @@ void ObjectSynchronizer::chk_in_use_entry(ObjectMonitor* n, outputStream* out, return; } - if (n->header().value() == 0) { + + if (n->metadata() == 0) { out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": in-use monitor must " - "have non-null _header field.", p2i(n)); + "have non-null _metadata (header/hash) field.", p2i(n)); *error_cnt_p = *error_cnt_p + 1; } + const oop obj = n->object_peek(); - if (obj != nullptr) { - const markWord mark = obj->mark(); - if (!mark.has_monitor()) { - out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": in-use monitor's " - "object does not think it has a monitor: obj=" - INTPTR_FORMAT ", mark=" INTPTR_FORMAT, p2i(n), - p2i(obj), mark.value()); - *error_cnt_p = *error_cnt_p + 1; - } - ObjectMonitor* const obj_mon = mark.monitor(); - if (n != obj_mon) { - out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": in-use monitor's " - "object does not refer to the same monitor: obj=" - INTPTR_FORMAT ", mark=" INTPTR_FORMAT ", obj_mon=" - INTPTR_FORMAT, p2i(n), p2i(obj), mark.value(), p2i(obj_mon)); - *error_cnt_p = *error_cnt_p + 1; - } + if (obj == nullptr) { + return; + } + + const markWord mark = obj->mark(); + if (!mark.has_monitor()) { + out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": in-use monitor's " + "object does not think it has a monitor: obj=" + INTPTR_FORMAT ", mark=" INTPTR_FORMAT, p2i(n), + p2i(obj), mark.value()); + *error_cnt_p = *error_cnt_p + 1; + return; + } + + ObjectMonitor* const obj_mon = read_monitor(Thread::current(), obj, mark); + if (n != obj_mon) { + out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": in-use monitor's " + "object does not refer to the same monitor: obj=" + INTPTR_FORMAT ", mark=" INTPTR_FORMAT ", obj_mon=" + INTPTR_FORMAT, p2i(n), p2i(obj), mark.value(), p2i(obj_mon)); + *error_cnt_p = *error_cnt_p + 1; } } @@ -2087,10 +2047,10 @@ void ObjectSynchronizer::log_in_use_monitor_details(outputStream* out, bool log_ monitors_iterate([&](ObjectMonitor* monitor) { if (is_interesting(monitor)) { const oop obj = monitor->object_peek(); - const markWord mark = monitor->header(); + const intptr_t hash = UseObjectMonitorTable ? monitor->hash() : monitor->header().hash(); ResourceMark rm; out->print(INTPTR_FORMAT " %d%d%d " INTPTR_FORMAT " %s", p2i(monitor), - monitor->is_busy(), mark.hash() != 0, monitor->owner() != nullptr, + monitor->is_busy(), hash != 0, monitor->owner() != nullptr, p2i(obj), obj == nullptr ? "" : obj->klass()->external_name()); if (monitor->is_busy()) { out->print(" (%s)", monitor->is_busy_to_string(&ss)); diff --git a/src/hotspot/share/runtime/synchronizer.hpp b/src/hotspot/share/runtime/synchronizer.hpp index 493303df661..5b171560ee1 100644 --- a/src/hotspot/share/runtime/synchronizer.hpp +++ b/src/hotspot/share/runtime/synchronizer.hpp @@ -29,6 +29,7 @@ #include "oops/markWord.hpp" #include "runtime/basicLock.hpp" #include "runtime/handles.hpp" +#include "runtime/javaThread.hpp" #include "utilities/resourceHash.hpp" template class GrowableArray; @@ -93,8 +94,9 @@ class ObjectSynchronizer : AllStatic { // deoptimization at monitor exit. Hence, it does not take a Handle argument. // This is the "slow path" version of monitor enter and exit. - static void enter(Handle obj, BasicLock* lock, JavaThread* current); - static void exit(oop obj, BasicLock* lock, JavaThread* current); + static inline void enter(Handle obj, BasicLock* lock, JavaThread* current); + static inline void exit(oop obj, BasicLock* lock, JavaThread* current); + // Used to enter a monitor for another thread. This requires that the // locking_thread is suspended, and that entering on a potential // inflated monitor may only contend with deflation. That is the obj being @@ -106,6 +108,9 @@ class ObjectSynchronizer : AllStatic { // inflated monitor enter. static bool enter_fast_impl(Handle obj, BasicLock* lock, JavaThread* locking_thread); + static bool quick_enter_legacy(oop obj, BasicLock* Lock, JavaThread* current); + static void enter_legacy(Handle obj, BasicLock* Lock, JavaThread* current); + static void exit_legacy(oop obj, BasicLock* lock, JavaThread* current); public: // Used only to handle jni locks or other unmatched monitor enter/exit // Internally they will use heavy weight monitor. @@ -118,7 +123,7 @@ class ObjectSynchronizer : AllStatic { static void notifyall(Handle obj, TRAPS); static bool quick_notify(oopDesc* obj, JavaThread* current, bool All); - static bool quick_enter(oop obj, JavaThread* current, BasicLock* Lock); + static inline bool quick_enter(oop obj, BasicLock* Lock, JavaThread* current); // Special internal-use-only method for use by JVM infrastructure // that needs to wait() on a java-level object but that can't risk @@ -132,13 +137,16 @@ class ObjectSynchronizer : AllStatic { private: // Shared implementation between the different LockingMode. - static ObjectMonitor* inflate_impl(JavaThread* thread, oop obj, const InflateCause cause); + static ObjectMonitor* inflate_impl(oop obj, const InflateCause cause); public: // This version is only for internal use static void inflate_helper(oop obj); static const char* inflate_cause_name(const InflateCause cause); + inline static ObjectMonitor* read_monitor(markWord mark); + inline static ObjectMonitor* read_monitor(Thread* current, oop obj, markWord mark); + // Returns the identity hash value for an oop // NOTE: It may cause monitor inflation static intptr_t FastHashCode(Thread* current, oop obj); @@ -200,6 +208,7 @@ class ObjectSynchronizer : AllStatic { private: friend class SynchronizerTest; + friend class LightweightSynchronizer; static MonitorList _in_use_list; static volatile bool _is_async_deflation_requested; diff --git a/src/hotspot/share/runtime/synchronizer.inline.hpp b/src/hotspot/share/runtime/synchronizer.inline.hpp new file mode 100644 index 00000000000..53a9f99a39e --- /dev/null +++ b/src/hotspot/share/runtime/synchronizer.inline.hpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_RUNTIME_SYNCHRONIZER_INLINE_HPP +#define SHARE_RUNTIME_SYNCHRONIZER_INLINE_HPP + +#include "runtime/synchronizer.hpp" + +#include "runtime/lightweightSynchronizer.hpp" +#include "runtime/safepointVerifiers.hpp" + +inline ObjectMonitor* ObjectSynchronizer::read_monitor(markWord mark) { + return mark.monitor(); +} + +inline ObjectMonitor* ObjectSynchronizer::read_monitor(Thread* current, oop obj, markWord mark) { + if (!UseObjectMonitorTable) { + return read_monitor(mark); + } else { + return LightweightSynchronizer::get_monitor_from_table(current, obj); + } +} + +inline void ObjectSynchronizer::enter(Handle obj, BasicLock* lock, JavaThread* current) { + assert(current == Thread::current(), "must be"); + + if (LockingMode == LM_LIGHTWEIGHT) { + LightweightSynchronizer::enter(obj, lock, current); + } else { + enter_legacy(obj, lock, current); + } +} + +inline bool ObjectSynchronizer::quick_enter(oop obj, BasicLock* lock, JavaThread* current) { + assert(current->thread_state() == _thread_in_Java, "invariant"); + NoSafepointVerifier nsv; + if (obj == nullptr) return false; // Need to throw NPE + + if (obj->klass()->is_value_based()) { + return false; + } + + if (LockingMode == LM_LIGHTWEIGHT) { + return LightweightSynchronizer::quick_enter(obj, lock, current); + } else { + return quick_enter_legacy(obj, lock, current); + } +} + +inline void ObjectSynchronizer::exit(oop object, BasicLock* lock, JavaThread* current) { + current->dec_held_monitor_count(); + + if (LockingMode == LM_LIGHTWEIGHT) { + LightweightSynchronizer::exit(object, current); + } else { + exit_legacy(object, lock, current); + } +} + +#endif // SHARE_RUNTIME_SYNCHRONIZER_INLINE_HPP diff --git a/src/hotspot/share/runtime/vframe.cpp b/src/hotspot/share/runtime/vframe.cpp index ebd5af5b74e..58eead692c6 100644 --- a/src/hotspot/share/runtime/vframe.cpp +++ b/src/hotspot/share/runtime/vframe.cpp @@ -50,7 +50,7 @@ #include "runtime/signature.hpp" #include "runtime/stackFrameStream.inline.hpp" #include "runtime/stubRoutines.hpp" -#include "runtime/synchronizer.hpp" +#include "runtime/synchronizer.inline.hpp" #include "runtime/vframe.inline.hpp" #include "runtime/vframeArray.hpp" #include "runtime/vframe_hp.hpp" @@ -247,13 +247,16 @@ void javaVFrame::print_lock_info_on(outputStream* st, int frame_count) { markWord mark = monitor->owner()->mark(); // The first stage of async deflation does not affect any field // used by this comparison so the ObjectMonitor* is usable here. - if (mark.has_monitor() && - ( // we have marked ourself as pending on this monitor - mark.monitor() == thread()->current_pending_monitor() || + if (mark.has_monitor()) { + ObjectMonitor* mon = ObjectSynchronizer::read_monitor(current, monitor->owner(), mark); + if (// if the monitor is null we must be in the process of locking + mon == nullptr || + // we have marked ourself as pending on this monitor + mon == thread()->current_pending_monitor() || // we are not the owner of this monitor - !mark.monitor()->is_entered(thread()) - )) { - lock_state = "waiting to lock"; + !mon->is_entered(thread())) { + lock_state = "waiting to lock"; + } } } print_locked_object_class_name(st, Handle(current, monitor->owner()), lock_state); diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 913f988e48b..fe9620586be 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -777,11 +777,11 @@ /* Monitors */ \ /************/ \ \ - volatile_nonstatic_field(ObjectMonitor, _header, markWord) \ + volatile_nonstatic_field(ObjectMonitor, _metadata, uintptr_t) \ unchecked_nonstatic_field(ObjectMonitor, _object, sizeof(void *)) /* NOTE: no type */ \ unchecked_nonstatic_field(ObjectMonitor, _owner, sizeof(void *)) /* NOTE: no type */ \ volatile_nonstatic_field(ObjectMonitor, _next_om, ObjectMonitor*) \ - volatile_nonstatic_field(BasicLock, _displaced_header, markWord) \ + volatile_nonstatic_field(BasicLock, _metadata, uintptr_t) \ nonstatic_field(ObjectMonitor, _contentions, int) \ volatile_nonstatic_field(ObjectMonitor, _waiters, int) \ volatile_nonstatic_field(ObjectMonitor, _recursions, intx) \ diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Mark.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Mark.java index 7512257a197..a3a06ec73f5 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Mark.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Mark.java @@ -156,6 +156,16 @@ public ObjectMonitor monitor() { if (Assert.ASSERTS_ENABLED) { Assert.that(hasMonitor(), "check"); } + if (VM.getVM().getCommandLineFlag("UseObjectMonitorTable").getBool()) { + Iterator it = ObjectSynchronizer.objectMonitorIterator(); + while (it != null && it.hasNext()) { + ObjectMonitor mon = (ObjectMonitor)it.next(); + if (getAddress().equals(mon.object())) { + return mon; + } + } + return null; + } // Use xor instead of &~ to provide one extra tag-bit check. Address monAddr = valueAsAddress().xorWithMask(monitorValue); return new ObjectMonitor(monAddr); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/BasicLock.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/BasicLock.java index 55e5d0e4598..4028bae3f5b 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/BasicLock.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/BasicLock.java @@ -43,7 +43,7 @@ public void update(Observable o, Object data) { private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { Type type = db.lookupType("BasicLock"); - displacedHeaderField = type.getCIntegerField("_displaced_header"); + displacedHeaderField = type.getCIntegerField("_metadata"); } private static CIntegerField displacedHeaderField; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectMonitor.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectMonitor.java index 3f3c67fbf26..e16982ce434 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectMonitor.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectMonitor.java @@ -45,8 +45,8 @@ private static synchronized void initialize(TypeDataBase db) throws WrongTypeExc heap = VM.getVM().getObjectHeap(); Type type = db.lookupType("ObjectMonitor"); - sun.jvm.hotspot.types.Field f = type.getField("_header"); - headerFieldOffset = f.getOffset(); + sun.jvm.hotspot.types.Field f = type.getField("_metadata"); + metadataFieldOffset = f.getOffset(); f = type.getField("_object"); objectFieldOffset = f.getOffset(); f = type.getField("_owner"); @@ -65,7 +65,7 @@ public ObjectMonitor(Address addr) { } public Mark header() { - return new Mark(addr.addOffsetTo(headerFieldOffset)); + return new Mark(addr.addOffsetTo(metadataFieldOffset)); } // FIXME @@ -114,7 +114,7 @@ public int contentions() { // vmStructs.cpp because they aren't strongly typed in the VM, or // would confuse the SA's type system. private static ObjectHeap heap; - private static long headerFieldOffset; + private static long metadataFieldOffset; private static long objectFieldOffset; private static long ownerFieldOffset; private static long nextOMFieldOffset; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectSynchronizer.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectSynchronizer.java index f8e71aa3761..a9c97e06a44 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectSynchronizer.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectSynchronizer.java @@ -55,6 +55,9 @@ public long identityHashValueFor(Oop obj) { // FIXME: can not generate marks in debugging system return mark.hash(); } else if (mark.hasMonitor()) { + if (VM.getVM().getCommandLineFlag("UseObjectMonitorTable").getBool()) { + return mark.hash(); + } ObjectMonitor monitor = mark.monitor(); Mark temp = monitor.header(); return temp.hash(); diff --git a/test/hotspot/gtest/runtime/test_objectMonitor.cpp b/test/hotspot/gtest/runtime/test_objectMonitor.cpp index 62eeba1587a..fcdb102fcf7 100644 --- a/test/hotspot/gtest/runtime/test_objectMonitor.cpp +++ b/test/hotspot/gtest/runtime/test_objectMonitor.cpp @@ -27,20 +27,20 @@ #include "unittest.hpp" TEST_VM(ObjectMonitor, sanity) { - uint cache_line_size = VM_Version::L1_data_cache_line_size(); + uint cache_line_size = VM_Version::L1_data_cache_line_size(); - if (cache_line_size != 0) { - // We were able to determine the L1 data cache line size so - // do some cache line specific sanity checks - EXPECT_EQ((size_t) 0, sizeof (PaddedEnd) % cache_line_size) - << "PaddedEnd size is not a " - << "multiple of a cache line which permits false sharing. " - << "sizeof(PaddedEnd) = " - << sizeof (PaddedEnd) - << "; cache_line_size = " << cache_line_size; + if (cache_line_size != 0) { - EXPECT_GE((size_t) in_bytes(ObjectMonitor::owner_offset()), cache_line_size) - << "the _header and _owner fields are closer " + EXPECT_EQ(in_bytes(ObjectMonitor::metadata_offset()), 0) + << "_metadata at a non 0 offset. metadata_offset = " + << in_bytes(ObjectMonitor::metadata_offset()); + + EXPECT_GE((size_t) in_bytes(ObjectMonitor::owner_offset()), cache_line_size) + << "the _metadata and _owner fields are closer " + << "than a cache line which permits false sharing."; + + EXPECT_GE((size_t) in_bytes(ObjectMonitor::recursions_offset() - ObjectMonitor::owner_offset()), cache_line_size) + << "the _owner and _recursions fields are closer " << "than a cache line which permits false sharing."; } } diff --git a/test/hotspot/jtreg/runtime/Monitor/UseObjectMonitorTableTest.java b/test/hotspot/jtreg/runtime/Monitor/UseObjectMonitorTableTest.java new file mode 100644 index 00000000000..6af1602e338 --- /dev/null +++ b/test/hotspot/jtreg/runtime/Monitor/UseObjectMonitorTableTest.java @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test id=NormalDeflation + * @summary A collection of small tests using synchronized, wait, notify to try + * and achieve good cheap coverage of UseObjectMonitorTable. + * @library /test/lib + * @run main/othervm -XX:+UnlockDiagnosticVMOptions + * -XX:+UseObjectMonitorTable + * UseObjectMonitorTableTest + */ + +/** + * @test id=ExtremeDeflation + * @summary Run the same tests but with deflation running constantly. + * @library /test/lib + * @run main/othervm -XX:+UnlockDiagnosticVMOptions + * -XX:GuaranteedAsyncDeflationInterval=1 + * -XX:+UseObjectMonitorTable + * UseObjectMonitorTableTest + */ + +import jdk.test.lib.Utils; + +import java.lang.Runnable; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; +import java.util.Random; +import java.util.stream.Stream; + +public class UseObjectMonitorTableTest { + static final ThreadFactory TF = Executors.defaultThreadFactory(); + + static class WaitNotifyTest implements Runnable { + static final int ITERATIONS = 10_000; + static final int THREADS = 10; + final WaitNotifySyncChannel startLatchChannel = new WaitNotifySyncChannel(); + final WaitNotifySyncChannel endLatchChannel = new WaitNotifySyncChannel(); + int count = 0; + + static class WaitNotifyCountDownLatch { + int latch; + WaitNotifyCountDownLatch(int count) { + latch = count; + } + synchronized void await() { + while (latch != 0) { + try { + wait(); + } catch (InterruptedException e) { + throw new RuntimeException("WaitNotifyTest: Unexpected interrupt", e); + } + } + } + synchronized void countDown() { + if (latch != 0) { + latch--; + if (latch == 0) { + notifyAll(); + } + } + } + } + static class WaitNotifySyncChannel extends WaitNotifyCountDownLatch { + WaitNotifyCountDownLatch object; + WaitNotifySyncChannel() { super(0); } + synchronized void send(WaitNotifyCountDownLatch object, int count) { + await(); + latch = count; + this.object = object; + notifyAll(); + } + synchronized WaitNotifyCountDownLatch receive() { + while (latch == 0) { + try { + wait(); + } catch (InterruptedException e) { + throw new RuntimeException("WaitNotifyTest: Unexpected interrupt", e); + } + } + countDown(); + return object; + } + } + synchronized int getCount() { + return count; + } + synchronized void increment() { + count++; + } + public void run() { + System.out.println("WaitNotifyTest started."); + for (int t = 0; t < THREADS; t++) { + TF.newThread(() -> { + for (int i = 0; i < ITERATIONS; i++) { + startLatchChannel.receive().await(); + increment(); + endLatchChannel.receive().countDown(); + } + }).start(); + } + for (int i = 0; i < ITERATIONS; i++) { + WaitNotifyCountDownLatch startLatch = new WaitNotifyCountDownLatch(1); + WaitNotifyCountDownLatch endLatch = new WaitNotifyCountDownLatch(THREADS); + int count = getCount(); + if (count != i * THREADS) { + throw new RuntimeException("WaitNotifyTest: Invalid Count " + count + + " pre-iteration " + i); + } + startLatchChannel.send(startLatch, 10); + startLatch.countDown(); + endLatchChannel.send(endLatch, 10); + endLatch.await(); + } + int count = getCount(); + if (count != ITERATIONS * THREADS) { + throw new RuntimeException("WaitNotifyTest: Invalid Count " + count); + } + System.out.println("WaitNotifyTest passed."); + } + } + + static class RandomDepthTest implements Runnable { + static final int THREADS = 10; + static final int ITERATIONS = 10_000; + static final int MAX_DEPTH = 20; + static final int MAX_RECURSION_COUNT = 10; + static final double RECURSION_CHANCE = .25; + final Random random = Utils.getRandomInstance(); + final Locker lockers[] = new Locker[MAX_DEPTH]; + final CyclicBarrier syncBarrier = new CyclicBarrier(THREADS + 1); + int count = 0; + + class Locker { + final int depth; + Locker(int depth) { + this.depth = depth; + } + synchronized int getCount() { + if (depth == MAX_DEPTH) { + return count; + } + return lockers[depth].getCount(); + } + synchronized void increment(int recursion_count) { + if (recursion_count != MAX_RECURSION_COUNT && + random.nextDouble() < RECURSION_CHANCE) { + this.increment(recursion_count + 1); + return; + } + if (depth == MAX_DEPTH) { + count++; + return; + } + lockers[depth + random.nextInt(MAX_DEPTH - depth)].increment(recursion_count); + } + synchronized Locker create() { + if (depth != MAX_DEPTH) { + lockers[depth] = (new Locker(depth + 1)).create(); + } + return this; + } + } + int getCount() { + return lockers[0].getCount(); + } + void increment() { + lockers[random.nextInt(MAX_DEPTH)].increment(0); + } + void create() { + lockers[0] = (new Locker(1)).create(); + } + void syncPoint() { + try { + syncBarrier.await(); + } catch (InterruptedException e) { + throw new RuntimeException("RandomDepthTest: Unexpected interrupt", e); + } catch (BrokenBarrierException e) { + throw new RuntimeException("RandomDepthTest: Unexpected broken barrier", e); + } + } + public void run() { + System.out.println("RandomDepthTest started."); + for (int t = 0; t < THREADS; t++) { + TF.newThread(() -> { + syncPoint(); + for (int i = 0; i < ITERATIONS; i++) { + increment(); + } + syncPoint(); + }).start(); + } + create(); + syncPoint(); + syncPoint(); + int count = getCount(); + if (count != THREADS * ITERATIONS) { + throw new RuntimeException("RandomDepthTest: Invalid Count " + count); + } + System.out.println("RandomDepthTest passed."); + } + } + + public static void main(String[] args) { + Stream.of( + TF.newThread(new WaitNotifyTest()), + TF.newThread(new RandomDepthTest()) + ).map(t -> { + t.start(); + return t; + }).forEach(t -> { + try { + t.join(); + } catch (InterruptedException e) { + throw new RuntimeException("UseObjectMonitorTableTest: Unexpected interrupt", e); + } + }); + + System.out.println("UseObjectMonitorTableTest passed."); + } +} diff --git a/test/hotspot/jtreg/runtime/logging/MonitorInflationTest.java b/test/hotspot/jtreg/runtime/logging/MonitorInflationTest.java index 737c64621e8..8666e2ee774 100644 --- a/test/hotspot/jtreg/runtime/logging/MonitorInflationTest.java +++ b/test/hotspot/jtreg/runtime/logging/MonitorInflationTest.java @@ -38,7 +38,7 @@ public class MonitorInflationTest { static void analyzeOutputOn(ProcessBuilder pb) throws Exception { OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldContain("inflate(has_locker):"); + output.shouldContain("inflate:"); output.shouldContain("type='MonitorInflationTest$Waiter'"); output.shouldContain("I've been waiting."); output.shouldHaveExitValue(0); diff --git a/test/micro/org/openjdk/bench/vm/lang/LockUnlock.java b/test/micro/org/openjdk/bench/vm/lang/LockUnlock.java index 49181971768..3ed862e8218 100644 --- a/test/micro/org/openjdk/bench/vm/lang/LockUnlock.java +++ b/test/micro/org/openjdk/bench/vm/lang/LockUnlock.java @@ -54,6 +54,8 @@ public class LockUnlock { public Object lockObject1; public Object lockObject2; + public volatile Object lockObject3Inflated; + public volatile Object lockObject4Inflated; public int factorial; public int dummyInt1; public int dummyInt2; @@ -62,13 +64,28 @@ public class LockUnlock { public void setup() { lockObject1 = new Object(); lockObject2 = new Object(); + lockObject3Inflated = new Object(); + lockObject4Inflated = new Object(); + + // Inflate the lock to use an ObjectMonitor + try { + synchronized (lockObject3Inflated) { + lockObject3Inflated.wait(1); + } + synchronized (lockObject4Inflated) { + lockObject4Inflated.wait(1); + } + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + dummyInt1 = 47; dummyInt2 = 11; // anything } /** Perform a synchronized on a local object within a loop. */ @Benchmark - public void testSimpleLockUnlock() { + public void testBasicSimpleLockUnlockLocal() { Object localObject = lockObject1; for (int i = 0; i < innerCount; i++) { synchronized (localObject) { @@ -78,9 +95,43 @@ public void testSimpleLockUnlock() { } } + /** Perform a synchronized on an object within a loop. */ + @Benchmark + public void testBasicSimpleLockUnlock() { + for (int i = 0; i < innerCount; i++) { + synchronized (lockObject1) { + dummyInt1++; + dummyInt2++; + } + } + } + + /** Perform a synchronized on a local object within a loop. */ + @Benchmark + public void testInflatedSimpleLockUnlockLocal() { + Object localObject = lockObject3Inflated; + for (int i = 0; i < innerCount; i++) { + synchronized (localObject) { + dummyInt1++; + dummyInt2++; + } + } + } + + /** Perform a synchronized on an object within a loop. */ + @Benchmark + public void testInflatedSimpleLockUnlock() { + for (int i = 0; i < innerCount; i++) { + synchronized (lockObject3Inflated) { + dummyInt1++; + dummyInt2++; + } + } + } + /** Perform a recursive synchronized on a local object within a loop. */ @Benchmark - public void testRecursiveLockUnlock() { + public void testBasicRecursiveLockUnlockLocal() { Object localObject = lockObject1; for (int i = 0; i < innerCount; i++) { synchronized (localObject) { @@ -92,9 +143,22 @@ public void testRecursiveLockUnlock() { } } + /** Perform a recursive synchronized on an object within a loop. */ + @Benchmark + public void testBasicRecursiveLockUnlock() { + for (int i = 0; i < innerCount; i++) { + synchronized (lockObject1) { + synchronized (lockObject1) { + dummyInt1++; + dummyInt2++; + } + } + } + } + /** Perform two synchronized after each other on the same local object. */ @Benchmark - public void testSerialLockUnlock() { + public void testBasicSerialLockUnlockLocal() { Object localObject = lockObject1; for (int i = 0; i < innerCount; i++) { synchronized (localObject) { @@ -106,6 +170,126 @@ public void testSerialLockUnlock() { } } + /** Perform two synchronized after each other on the same object. */ + @Benchmark + public void testBasicSerialLockUnlock() { + for (int i = 0; i < innerCount; i++) { + synchronized (lockObject1) { + dummyInt1++; + } + synchronized (lockObject1) { + dummyInt2++; + } + } + } + + /** Perform two synchronized after each other on the same local object. */ + @Benchmark + public void testInflatedSerialLockUnlockLocal() { + Object localObject = lockObject3Inflated; + for (int i = 0; i < innerCount; i++) { + synchronized (localObject) { + dummyInt1++; + } + synchronized (localObject) { + dummyInt2++; + } + } + } + + /** Perform two synchronized after each other on the same object. */ + @Benchmark + public void testInflatedSerialLockUnlock() { + for (int i = 0; i < innerCount; i++) { + synchronized (lockObject3Inflated) { + dummyInt1++; + } + synchronized (lockObject3Inflated) { + dummyInt2++; + } + } + } + + /** Perform two synchronized after each other on the same object. */ + @Benchmark + public void testInflatedMultipleSerialLockUnlock() { + for (int i = 0; i < innerCount; i++) { + synchronized (lockObject3Inflated) { + dummyInt1++; + } + synchronized (lockObject4Inflated) { + dummyInt2++; + } + } + } + + /** Perform two synchronized after each other on the same object. */ + @Benchmark + public void testInflatedMultipleRecursiveLockUnlock() { + for (int i = 0; i < innerCount; i++) { + synchronized (lockObject3Inflated) { + dummyInt1++; + synchronized (lockObject4Inflated) { + dummyInt2++; + } + } + } + } + + /** Perform a recursive-only synchronized on a local object within a loop. */ + @Benchmark + public void testInflatedRecursiveOnlyLockUnlockLocal() { + Object localObject = lockObject3Inflated; + synchronized (localObject) { + for (int i = 0; i < innerCount; i++) { + synchronized (localObject) { + dummyInt1++; + dummyInt2++; + } + } + } + } + + /** Perform a recursive-only synchronized on an object within a loop. */ + @Benchmark + public void testInflatedRecursiveOnlyLockUnlock() { + synchronized (lockObject3Inflated) { + for (int i = 0; i < innerCount; i++) { + synchronized (lockObject3Inflated) { + dummyInt1++; + dummyInt2++; + } + } + } + } + + /** Perform a recursive-only synchronized on a local object within a loop. */ + @Benchmark + public void testInflatedRecursiveLockUnlockLocal() { + Object localObject = lockObject3Inflated; + for (int i = 0; i < innerCount; i++) { + synchronized (localObject) { + synchronized (localObject) { + dummyInt1++; + dummyInt2++; + } + } + } + } + + /** Perform a recursive-only synchronized on an object within a loop. */ + @Benchmark + public void testInflatedRecursiveLockUnlock() { + for (int i = 0; i < innerCount; i++) { + synchronized (lockObject3Inflated) { + synchronized (lockObject3Inflated) { + dummyInt1++; + dummyInt2++; + } + } + } + } + /** * Performs recursive synchronizations on the same local object. *

From 60c9b5cd9f18830f0fb1aea6cb3dc43af3908cc5 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Fri, 16 Aug 2024 08:49:18 +0000 Subject: [PATCH 439/460] 8337839: Make a few fields in MergeCollation static Reviewed-by: jpai, naoto --- src/java.base/share/classes/java/text/MergeCollation.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/java/text/MergeCollation.java b/src/java.base/share/classes/java/text/MergeCollation.java index 1db779e003f..8cac7871b56 100644 --- a/src/java.base/share/classes/java/text/MergeCollation.java +++ b/src/java.base/share/classes/java/text/MergeCollation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -220,9 +220,9 @@ public PatternEntry getItemAt(int index) { // Using BitSet would make this easier, but it's significantly slower. // private transient byte[] statusArray = new byte[8192]; - private final byte BITARRAYMASK = (byte)0x1; - private final int BYTEPOWER = 3; - private final int BYTEMASK = (1 << BYTEPOWER) - 1; + private static final byte BITARRAYMASK = (byte)0x1; + private static final int BYTEPOWER = 3; + private static final int BYTEMASK = (1 << BYTEPOWER) - 1; /* If the strength is RESET, then just change the lastEntry to From ddbc0b6a39148cb30a8fda80fa7290e90e2a77d6 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Fri, 16 Aug 2024 11:24:40 +0000 Subject: [PATCH 440/460] 8338495: Revert "8336655: java/net/httpclient/DigestEchoClient.java IOException: HTTP/1.1 header parser received no bytes" Reviewed-by: jpai --- .../jdk/internal/net/http/ConnectionPool.java | 36 ++++--------------- .../jdk/internal/net/http/SocketTube.java | 23 ++---------- .../java/net/httpclient/DigestEchoClient.java | 4 +-- 3 files changed, 11 insertions(+), 52 deletions(-) diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java b/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java index edaf53a8a0d..0ad7b9d5992 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, 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,6 @@ import jdk.internal.net.http.common.Deadline; import jdk.internal.net.http.common.FlowTube; -import jdk.internal.net.http.common.Log; import jdk.internal.net.http.common.Logger; import jdk.internal.net.http.common.TimeLine; import jdk.internal.net.http.common.TimeSource; @@ -493,13 +492,13 @@ void clear() { // Remove a connection from the pool. // should only be called while holding the ConnectionPool stateLock. - private boolean removeFromPool(HttpConnection c) { + private void removeFromPool(HttpConnection c) { assert stateLock.isHeldByCurrentThread(); if (c instanceof PlainHttpConnection) { - return removeFromPool(c, plainPool); + removeFromPool(c, plainPool); } else { assert c.isSecure() : "connection " + c + " is not secure!"; - return removeFromPool(c, sslPool); + removeFromPool(c, sslPool); } } @@ -530,29 +529,13 @@ void cleanup(HttpConnection c, Throwable error) { debug.log("%s : ConnectionPool.cleanup(%s)", String.valueOf(c.getConnectionFlow()), error); stateLock.lock(); - boolean removed; try { - removed = removeFromPool(c); + removeFromPool(c); expiryList.remove(c); } finally { stateLock.unlock(); } - if (!removed) { - // this should not happen; the cleanup may have consumed - // some data that wasn't supposed to be consumed, so - // the only thing we can do is log it and close the - // connection. - if (Log.errors()) { - Log.logError("WARNING: CleanupTrigger triggered for" + - " a connection not found in the pool: closing {0}", c); - } else if (debug.on()) { - debug.log("WARNING: CleanupTrigger triggered for" + - " a connection not found in the pool: closing %s", c); - } - c.close(new IOException("Unexpected cleanup triggered for non pooled connection")); - } else { - c.close(); - } + c.close(); } /** @@ -566,7 +549,6 @@ private final class CleanupTrigger implements private final HttpConnection connection; private volatile boolean done; - private volatile boolean dropped; public CleanupTrigger(HttpConnection connection) { this.connection = connection; @@ -584,7 +566,6 @@ private void triggerCleanup(Throwable error) { @Override public void onSubscribe(Flow.Subscription subscription) { - if (dropped || done) return; subscription.request(1); } @Override @@ -605,10 +586,5 @@ public void subscribe(Flow.Subscriber> subscriber) { public String toString() { return "CleanupTrigger(" + connection.getConnectionFlow() + ")"; } - - @Override - public void dropSubscription() { - dropped = true; - } } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/SocketTube.java b/src/java.net.http/share/classes/jdk/internal/net/http/SocketTube.java index 9317bdf442a..cbdf6633576 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/SocketTube.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/SocketTube.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2023, 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 @@ -573,8 +573,6 @@ public void subscribe(Flow.Subscriber> s) { debug.log("read publisher: dropping pending subscriber: " + previous.subscriber); previous.errorRef.compareAndSet(null, errorRef.get()); - // make sure no data will be routed to the old subscriber. - previous.stopReading(); previous.signalOnSubscribe(); if (subscriptionImpl.completed) { previous.signalCompletion(); @@ -608,7 +606,6 @@ final class ReadSubscription implements Flow.Subscription { volatile boolean subscribed; volatile boolean cancelled; volatile boolean completed; - volatile boolean stopped; public ReadSubscription(InternalReadSubscription impl, TubeSubscriber subscriber) { @@ -626,11 +623,11 @@ public void cancel() { @Override public void request(long n) { - if (!cancelled && !stopped) { + if (!cancelled) { impl.request(n); } else { if (debug.on()) - debug.log("subscription stopped or cancelled, ignoring request %d", n); + debug.log("subscription cancelled, ignoring request %d", n); } } @@ -664,20 +661,6 @@ void signalOnSubscribe() { signalCompletion(); } } - - /** - * Called when switching subscriber on the {@link InternalReadSubscription}. - * This subscriber is the old subscriber. Demand on the internal - * subscription will be reset and reading will be paused until the - * new subscriber is subscribed. - * This should ensure that no data is routed to this subscriber - * until the new subscriber is subscribed. - */ - void stopReading() { - stopped = true; - impl.demand.reset(); - impl.pauseReadEvent(); - } } final class InternalReadSubscription implements Flow.Subscription { diff --git a/test/jdk/java/net/httpclient/DigestEchoClient.java b/test/jdk/java/net/httpclient/DigestEchoClient.java index 1450bf09b2d..3b6d1a1773f 100644 --- a/test/jdk/java/net/httpclient/DigestEchoClient.java +++ b/test/jdk/java/net/httpclient/DigestEchoClient.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2023, 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,7 +64,7 @@ * @test * @summary this test verifies that a client may provides authorization * headers directly when connecting with a server. - * @bug 8087112 8336655 + * @bug 8087112 * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.common.HttpServerAdapters jdk.test.lib.net.SimpleSSLContext * DigestEchoServer ReferenceTracker DigestEchoClient From 5022109b2a33a8cf2608eb829098b27641b731a4 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Fri, 16 Aug 2024 13:18:02 +0000 Subject: [PATCH 441/460] 8336856: Efficient hidden class-based string concatenation strategy Co-authored-by: Claes Redestad Reviewed-by: redestad, liach --- .../classes/java/lang/StringConcatHelper.java | 343 ++++++++ .../share/classes/java/lang/System.java | 4 + .../java/lang/invoke/StringConcatFactory.java | 762 +++++++++++++++--- .../jdk/internal/access/JavaLangAccess.java | 2 + .../jdk/internal/util/ClassFileDumper.java | 9 +- .../String/concat/HiddenClassUnloading.java | 69 ++ .../openjdk/bench/java/lang/StringConcat.java | 149 +++- .../bench/java/lang/StringConcatStartup.java | 111 ++- 8 files changed, 1316 insertions(+), 133 deletions(-) create mode 100644 test/jdk/java/lang/String/concat/HiddenClassUnloading.java diff --git a/src/java.base/share/classes/java/lang/StringConcatHelper.java b/src/java.base/share/classes/java/lang/StringConcatHelper.java index 486e115369e..ae2b9693409 100644 --- a/src/java.base/share/classes/java/lang/StringConcatHelper.java +++ b/src/java.base/share/classes/java/lang/StringConcatHelper.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding 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 @@ -28,6 +29,7 @@ import jdk.internal.misc.Unsafe; import jdk.internal.util.DecimalDigits; import jdk.internal.vm.annotation.ForceInline; +import jdk.internal.vm.annotation.Stable; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -39,6 +41,98 @@ * combinators there. */ final class StringConcatHelper { + static abstract class StringConcatBase { + @Stable + final String[] constants; + final int length; + final byte coder; + + StringConcatBase(String[] constants) { + int length = 0; + byte coder = String.LATIN1; + for (String c : constants) { + length += c.length(); + coder |= c.coder(); + } + this.constants = constants; + this.length = length; + this.coder = coder; + } + } + + static final class Concat1 extends StringConcatBase { + Concat1(String[] constants) { + super(constants); + } + + @ForceInline + String concat0(String value) { + int length = stringSize(this.length, value); + byte coder = (byte) (this.coder | value.coder()); + byte[] buf = newArray(length << coder); + String prefix = constants[0]; + prefix.getBytes(buf, 0, coder); + value.getBytes(buf, prefix.length(), coder); + constants[1].getBytes(buf, prefix.length() + value.length(), coder); + return new String(buf, coder); + } + + @ForceInline + String concat(boolean value) { + int length = stringSize(this.length, value); + String suffix = constants[1]; + length -= suffix.length(); + byte[] buf = newArrayWithSuffix(suffix, length, coder); + prepend(length, coder, buf, value, constants[0]); + return new String(buf, coder); + } + + @ForceInline + String concat(char value) { + int length = stringSize(this.length, value); + byte coder = (byte) (this.coder | stringCoder(value)); + String suffix = constants[1]; + length -= suffix.length(); + byte[] buf = newArrayWithSuffix(suffix, length, coder); + prepend(length, coder, buf, value, constants[0]); + return new String(buf, coder); + } + + @ForceInline + String concat(int value) { + int length = stringSize(this.length, value); + String suffix = constants[1]; + length -= suffix.length(); + byte[] buf = newArrayWithSuffix(suffix, length, coder); + prepend(length, coder, buf, value, constants[0]); + return new String(buf, coder); + } + + @ForceInline + String concat(long value) { + int length = stringSize(this.length, value); + String suffix = constants[1]; + length -= suffix.length(); + byte[] buf = newArrayWithSuffix(suffix, length, coder); + prepend(length, coder, buf, value, constants[0]); + return new String(buf, coder); + } + + @ForceInline + String concat(Object value) { + return concat0(stringOf(value)); + } + + @ForceInline + String concat(float value) { + return concat0(Float.toString(value)); + } + + @ForceInline + String concat(double value) { + return concat0(Double.toString(value)); + } + } private StringConcatHelper() { // no instantiation @@ -375,6 +469,64 @@ static String stringOf(Object value) { private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + static String stringOf(float value) { + return Float.toString(value); + } + + static String stringOf(double value) { + return Double.toString(value); + } + + /** + * return add stringSize of value + * @param length length + * @param value value to add stringSize + * @return new length + */ + static int stringSize(int length, char value) { + return checkOverflow(length + 1); + } + + /** + * return add stringSize of value + * @param length length + * @param value value to add stringSize + * @return new length + */ + static int stringSize(int length, boolean value) { + return checkOverflow(length + (value ? 4 : 5)); + } + + /** + * return add stringSize of value + * @param length length + * @param value value + * @return new length + */ + static int stringSize(int length, int value) { + return checkOverflow(length + DecimalDigits.stringSize(value)); + } + + /** + * return add stringSize of value + * @param length length + * @param value value to add stringSize + * @return new length + */ + static int stringSize(int length, long value) { + return checkOverflow(length + DecimalDigits.stringSize(value)); + } + + /** + * return add stringSize of value + * @param length length + * @param value value to add stringSize + * @return new length + */ + static int stringSize(int length, String value) { + return checkOverflow(length + value.length()); + } + /** * Allocates an uninitialized byte array based on the length and coder * information, then prepends the given suffix string at the end of the @@ -440,4 +592,195 @@ static MethodHandle lookupStatic(String name, MethodType methodType) { } } + /** + * Allocates an uninitialized byte array based on the length and coder + * information, then prepends the given suffix string at the end of the + * byte array before returning it. The calling code must adjust the + * indexCoder so that it's taken the coder of the suffix into account, but + * subtracted the length of the suffix. + * + * @param suffix + * @param indexCoder + * @return the newly allocated byte array + */ + @ForceInline + static byte[] newArrayWithSuffix(String suffix, int index, byte coder) { + byte[] buf = newArray((index + suffix.length()) << coder); + if (coder == String.LATIN1) { + suffix.getBytes(buf, index, String.LATIN1); + } else { + suffix.getBytes(buf, index, String.UTF16); + } + return buf; + } + + /** + * Return the coder for the character. + * @param value character + * @return coder + */ + static byte stringCoder(char value) { + return StringLatin1.canEncode(value) ? String.LATIN1 : String.UTF16; + } + + /** + * Prepends constant and the stringly representation of value into buffer, + * given the coder and final index. Index is measured in chars, not in bytes! + * + * @param index final char index in the buffer + * @param coder coder of the buffer + * @param buf buffer to append to + * @param value boolean value to encode + * @param prefix a constant to prepend before value + * @return updated index + */ + static int prepend(int index, byte coder, byte[] buf, boolean value, String prefix) { + if (coder == String.LATIN1) { + if (value) { + index -= 4; + buf[index] = 't'; + buf[index + 1] = 'r'; + buf[index + 2] = 'u'; + buf[index + 3] = 'e'; + } else { + index -= 5; + buf[index] = 'f'; + buf[index + 1] = 'a'; + buf[index + 2] = 'l'; + buf[index + 3] = 's'; + buf[index + 4] = 'e'; + } + index -= prefix.length(); + prefix.getBytes(buf, index, String.LATIN1); + } else { + if (value) { + index -= 4; + StringUTF16.putChar(buf, index, 't'); + StringUTF16.putChar(buf, index + 1, 'r'); + StringUTF16.putChar(buf, index + 2, 'u'); + StringUTF16.putChar(buf, index + 3, 'e'); + } else { + index -= 5; + StringUTF16.putChar(buf, index, 'f'); + StringUTF16.putChar(buf, index + 1, 'a'); + StringUTF16.putChar(buf, index + 2, 'l'); + StringUTF16.putChar(buf, index + 3, 's'); + StringUTF16.putChar(buf, index + 4, 'e'); + } + index -= prefix.length(); + prefix.getBytes(buf, index, String.UTF16); + } + return index; + } + + /** + * Prepends constant and the stringly representation of value into buffer, + * given the coder and final index. Index is measured in chars, not in bytes! + * + * @param index final char index in the buffer + * @param coder coder of the buffer + * @param buf buffer to append to + * @param value char value to encode + * @param prefix a constant to prepend before value + * @return updated index + */ + static int prepend(int index, byte coder, byte[] buf, char value, String prefix) { + if (coder == String.LATIN1) { + buf[--index] = (byte) (value & 0xFF); + index -= prefix.length(); + prefix.getBytes(buf, index, String.LATIN1); + } else { + StringUTF16.putChar(buf, --index, value); + index -= prefix.length(); + prefix.getBytes(buf, index, String.UTF16); + } + return index; + } + + /** + * Prepends constant and the stringly representation of value into buffer, + * given the coder and final index. Index is measured in chars, not in bytes! + * + * @param index final char index in the buffer + * @param coder coder of the buffer + * @param buf buffer to append to + * @param value int value to encode + * @param prefix a constant to prepend before value + * @return updated index + */ + static int prepend(int index, byte coder, byte[] buf, int value, String prefix) { + if (coder == String.LATIN1) { + index = StringLatin1.getChars(value, index, buf); + index -= prefix.length(); + prefix.getBytes(buf, index, String.LATIN1); + } else { + index = StringUTF16.getChars(value, index, buf); + index -= prefix.length(); + prefix.getBytes(buf, index, String.UTF16); + } + return index; + } + + /** + * Prepends constant and the stringly representation of value into buffer, + * given the coder and final index. Index is measured in chars, not in bytes! + * + * @param index final char index in the buffer + * @param coder coder of the buffer + * @param buf buffer to append to + * @param value long value to encode + * @param prefix a constant to prepend before value + * @return updated index + */ + static int prepend(int index, byte coder, byte[] buf, long value, String prefix) { + if (coder == String.LATIN1) { + index = StringLatin1.getChars(value, index, buf); + index -= prefix.length(); + prefix.getBytes(buf, index, String.LATIN1); + } else { + index = StringUTF16.getChars(value, index, buf); + index -= prefix.length(); + prefix.getBytes(buf, index, String.UTF16); + } + return index; + } + + /** + * Prepends constant and the stringly representation of value into buffer, + * given the coder and final index. Index is measured in chars, not in bytes! + * + * @param index final char index in the buffer + * @param coder coder of the buffer + * @param buf buffer to append to + * @param value boolean value to encode + * @param prefix a constant to prepend before value + * @return updated index + */ + static int prepend(int index, byte coder, byte[] buf, String value, String prefix) { + index -= value.length(); + if (coder == String.LATIN1) { + value.getBytes(buf, index, String.LATIN1); + index -= prefix.length(); + prefix.getBytes(buf, index, String.LATIN1); + } else { + value.getBytes(buf, index, String.UTF16); + index -= prefix.length(); + prefix.getBytes(buf, index, String.UTF16); + } + return index; + } + + /** + * Check for overflow, throw exception on overflow. + * + * @param value + * @return the given parameter value, if valid + */ + @ForceInline + static int checkOverflow(int value) { + if (value >= 0) { + return value; + } + throw new OutOfMemoryError("Overflow: String length out of range"); + } } diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index 0947da8ded7..5ff4796505b 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -2623,6 +2623,10 @@ public long stringConcatMix(long lengthCoder, char value) { return StringConcatHelper.mix(lengthCoder, value); } + public Object stringConcat1(String[] constants) { + return new StringConcatHelper.Concat1(constants); + } + public int getCharsLatin1(long i, int index, byte[] buf) { return StringLatin1.getChars(i, index, buf); } diff --git a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java index cf552c434be..dd262193574 100644 --- a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java +++ b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding 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 @@ -30,23 +31,33 @@ import jdk.internal.constant.ConstantUtils; import jdk.internal.misc.VM; import jdk.internal.util.ClassFileDumper; +import jdk.internal.util.ReferenceKey; +import jdk.internal.util.ReferencedKeyMap; import jdk.internal.vm.annotation.Stable; import sun.invoke.util.Wrapper; +import java.lang.classfile.Annotation; import java.lang.classfile.ClassBuilder; import java.lang.classfile.ClassFile; import java.lang.classfile.CodeBuilder; +import java.lang.classfile.MethodBuilder; import java.lang.classfile.TypeKind; +import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; import java.lang.constant.ClassDesc; -import java.lang.constant.ConstantDescs; import java.lang.constant.MethodTypeDesc; import java.lang.invoke.MethodHandles.Lookup; -import java.lang.reflect.AccessFlag; +import java.lang.ref.SoftReference; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; +import java.util.function.Supplier; -import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG; +import static java.lang.classfile.ClassFile.*; +import static java.lang.constant.ConstantDescs.*; import static java.lang.invoke.MethodType.methodType; /** @@ -107,12 +118,15 @@ * @since 9 */ public final class StringConcatFactory { - private static final int HIGH_ARITY_THRESHOLD; + private static final int FORCE_INLINE_THRESHOLD; static { String highArity = VM.getSavedProperty("java.lang.invoke.StringConcat.highArityThreshold"); - HIGH_ARITY_THRESHOLD = highArity != null ? Integer.parseInt(highArity) : 20; + HIGH_ARITY_THRESHOLD = highArity != null ? Integer.parseInt(highArity) : 0; + + String inlineThreshold = VM.getSavedProperty("java.lang.invoke.StringConcat.inlineThreshold"); + FORCE_INLINE_THRESHOLD = inlineThreshold != null ? Integer.parseInt(inlineThreshold) : 16; } /** @@ -371,14 +385,17 @@ public static CallSite makeConcatWithConstants(MethodHandles.Lookup lookup, } try { - if (concatType.parameterCount() <= HIGH_ARITY_THRESHOLD) { - return new ConstantCallSite( - generateMHInlineCopy(concatType, constantStrings) - .viewAsType(concatType, true)); - } else { - return new ConstantCallSite( - SimpleStringBuilderStrategy.generate(lookup, concatType, constantStrings)); + MethodHandle mh = makeSimpleConcat(concatType, constantStrings); + if (mh == null && concatType.parameterCount() <= HIGH_ARITY_THRESHOLD) { + mh = generateMHInlineCopy(concatType, constantStrings); } + + if (mh == null) { + mh = InlineHiddenClassStrategy.generate(lookup, concatType, constantStrings); + } + mh = mh.viewAsType(concatType, true); + + return new ConstantCallSite(mh); } catch (Error e) { // Pass through any error throw e; @@ -427,7 +444,7 @@ private static String[] parseRecipe(MethodType concatType, } // Flush any accumulated characters into a constant - consts[oCount++] = acc.length() > 0 ? acc.toString() : null; + consts[oCount++] = acc.length() > 0 ? acc.toString() : ""; acc.setLength(0); } else { // Not a special character, this is a constant embedded into @@ -443,7 +460,7 @@ private static String[] parseRecipe(MethodType concatType, } // Flush the remaining characters as constant: - consts[oCount] = acc.length() > 0 ? acc.toString() : null; + consts[oCount] = acc.length() > 0 ? acc.toString() : ""; return consts; } @@ -466,14 +483,7 @@ private static StringConcatException constantMismatch(Object[] constants, " are passed"); } - /** - *

This strategy replicates what StringBuilders are doing: it builds the - * byte[] array on its own and passes that byte[] array to String - * constructor. This strategy requires access to some private APIs in JDK, - * most notably, the private String constructor that accepts byte[] arrays - * without copying. - */ - private static MethodHandle generateMHInlineCopy(MethodType mt, String[] constants) { + private static MethodHandle makeSimpleConcat(MethodType mt, String[] constants) { int paramCount = mt.parameterCount(); String suffix = constants[paramCount]; @@ -484,22 +494,37 @@ private static MethodHandle generateMHInlineCopy(MethodType mt, String[] constan if (paramCount == 1) { String prefix = constants[0]; // Empty constants will be - if (prefix == null) { - if (suffix == null) { + if (prefix.isEmpty()) { + if (suffix.isEmpty()) { return unaryConcat(mt.parameterType(0)); } else if (!mt.hasPrimitives()) { return MethodHandles.insertArguments(simpleConcat(), 1, suffix); } // else fall-through - } else if (suffix == null && !mt.hasPrimitives()) { + } else if (suffix.isEmpty() && !mt.hasPrimitives()) { // Non-primitive argument return MethodHandles.insertArguments(simpleConcat(), 0, prefix); } // fall-through if there's both a prefix and suffix - } - if (paramCount == 2 && !mt.hasPrimitives() && suffix == null - && constants[0] == null && constants[1] == null) { + } else if (paramCount == 2 && !mt.hasPrimitives() && suffix.isEmpty() + && constants[0].isEmpty() && constants[1].isEmpty()) { // Two reference arguments, no surrounding constants return simpleConcat(); } + + return null; + } + + /** + *

This strategy replicates what StringBuilders are doing: it builds the + * byte[] array on its own and passes that byte[] array to String + * constructor. This strategy requires access to some private APIs in JDK, + * most notably, the private String constructor that accepts byte[] arrays + * without copying. + */ + private static MethodHandle generateMHInlineCopy(MethodType mt, String[] constants) { + int paramCount = mt.parameterCount(); + String suffix = constants[paramCount]; + + // else... fall-through to slow-path // Create filters and obtain filtered parameter types. Filters would be used in the beginning @@ -1043,139 +1068,638 @@ private StringConcatFactory() { } /** - * Bytecode StringBuilder strategy. + * Implement efficient hidden class strategy for String concatenation * - *

This strategy emits StringBuilder chains as similar as possible - * to what javac would. No exact sizing of parameters or estimates. + *

This strategy replicates based on the bytecode what StringBuilders are doing: it builds the + * byte[] array on its own and passes that byte[] array to String + * constructor. This strategy requires access to some private APIs in JDK, + * most notably, the private String constructor that accepts byte[] arrays + * without copying. */ - private static final class SimpleStringBuilderStrategy { - static final String METHOD_NAME = "concat"; - static final ClassDesc STRING_BUILDER = ClassDesc.ofDescriptor("Ljava/lang/StringBuilder;"); + private static final class InlineHiddenClassStrategy { + static final String CLASS_NAME = "java.lang.String$$StringConcat"; + static final String METHOD_NAME = "concat"; + static final ClassFileDumper DUMPER = ClassFileDumper.getInstance("java.lang.invoke.StringConcatFactory.dump", "stringConcatClasses"); - static final MethodTypeDesc APPEND_BOOLEAN_TYPE = MethodTypeDesc.of(STRING_BUILDER, ConstantDescs.CD_boolean); - static final MethodTypeDesc APPEND_CHAR_TYPE = MethodTypeDesc.of(STRING_BUILDER, ConstantDescs.CD_char); - static final MethodTypeDesc APPEND_DOUBLE_TYPE = MethodTypeDesc.of(STRING_BUILDER, ConstantDescs.CD_double); - static final MethodTypeDesc APPEND_FLOAT_TYPE = MethodTypeDesc.of(STRING_BUILDER, ConstantDescs.CD_float); - static final MethodTypeDesc APPEND_INT_TYPE = MethodTypeDesc.of(STRING_BUILDER, ConstantDescs.CD_int); - static final MethodTypeDesc APPEND_LONG_TYPE = MethodTypeDesc.of(STRING_BUILDER, ConstantDescs.CD_long); - static final MethodTypeDesc APPEND_OBJECT_TYPE = MethodTypeDesc.of(STRING_BUILDER, ConstantDescs.CD_Object); - static final MethodTypeDesc APPEND_STRING_TYPE = MethodTypeDesc.of(STRING_BUILDER, ConstantDescs.CD_String); - static final MethodTypeDesc INT_CONSTRUCTOR_TYPE = MethodTypeDesc.of(ConstantDescs.CD_void, ConstantDescs.CD_int); - static final MethodTypeDesc TO_STRING_TYPE = MethodTypeDesc.of(ConstantDescs.CD_String); + static final MethodHandles.Lookup STR_LOOKUP = new MethodHandles.Lookup(String.class); + + static final ClassDesc CD_CONCAT = ConstantUtils.binaryNameToDesc(CLASS_NAME); + static final ClassDesc CD_StringConcatHelper = ClassDesc.ofDescriptor("Ljava/lang/StringConcatHelper;"); + static final ClassDesc CD_StringConcatBase = ClassDesc.ofDescriptor("Ljava/lang/StringConcatHelper$StringConcatBase;"); + static final ClassDesc CD_Array_byte = ClassDesc.ofDescriptor("[B"); + static final ClassDesc CD_Array_String = ClassDesc.ofDescriptor("[Ljava/lang/String;"); + + static final MethodTypeDesc MTD_byte_char = MethodTypeDesc.of(CD_byte, CD_char); + static final MethodTypeDesc MTD_byte = MethodTypeDesc.of(CD_byte); + static final MethodTypeDesc MTD_int = MethodTypeDesc.of(CD_int); + static final MethodTypeDesc MTD_int_int_boolean = MethodTypeDesc.of(CD_int, CD_int, CD_boolean); + static final MethodTypeDesc MTD_int_int_char = MethodTypeDesc.of(CD_int, CD_int, CD_char); + static final MethodTypeDesc MTD_int_int_int = MethodTypeDesc.of(CD_int, CD_int, CD_int); + static final MethodTypeDesc MTD_int_int_long = MethodTypeDesc.of(CD_int, CD_int, CD_long); + static final MethodTypeDesc MTD_int_int_String = MethodTypeDesc.of(CD_int, CD_int, CD_String); + static final MethodTypeDesc MTD_String_float = MethodTypeDesc.of(CD_String, CD_float); + static final MethodTypeDesc MTD_String_double = MethodTypeDesc.of(CD_String, CD_double); + static final MethodTypeDesc MTD_String_Object = MethodTypeDesc.of(CD_String, CD_Object); + + static final MethodTypeDesc MTD_INIT = MethodTypeDesc.of(CD_void, CD_Array_String); + static final MethodTypeDesc MTD_NEW_ARRAY_SUFFIX = MethodTypeDesc.of(CD_Array_byte, CD_String, CD_int, CD_byte); + static final MethodTypeDesc MTD_STRING_INIT = MethodTypeDesc.of(CD_void, CD_Array_byte, CD_byte); + + static final MethodTypeDesc PREPEND_int = MethodTypeDesc.of(CD_int, CD_int, CD_byte, CD_Array_byte, CD_int, CD_String); + static final MethodTypeDesc PREPEND_long = MethodTypeDesc.of(CD_int, CD_int, CD_byte, CD_Array_byte, CD_long, CD_String); + static final MethodTypeDesc PREPEND_boolean = MethodTypeDesc.of(CD_int, CD_int, CD_byte, CD_Array_byte, CD_boolean, CD_String); + static final MethodTypeDesc PREPEND_char = MethodTypeDesc.of(CD_int, CD_int, CD_byte, CD_Array_byte, CD_char, CD_String); + static final MethodTypeDesc PREPEND_String = MethodTypeDesc.of(CD_int, CD_int, CD_byte, CD_Array_byte, CD_String, CD_String); + + static final RuntimeVisibleAnnotationsAttribute FORCE_INLINE = RuntimeVisibleAnnotationsAttribute.of(Annotation.of(ClassDesc.ofDescriptor("Ljdk/internal/vm/annotation/ForceInline;"))); + + static final MethodType CONSTRUCTOR_METHOD_TYPE = MethodType.methodType(void.class, String[].class); + static final Consumer CONSTRUCTOR_BUILDER = new Consumer() { + @Override + public void accept(CodeBuilder cb) { + /* + * super(constants); + */ + int thisSlot = cb.receiverSlot(), + constantsSlot = cb.parameterSlot(0); + cb.aload(thisSlot) + .aload(constantsSlot) + .invokespecial(CD_StringConcatBase, INIT_NAME, MTD_INIT, false) + .return_(); + } + }; + + static final ReferencedKeyMap> CACHE = + ReferencedKeyMap.create(true, true, + new Supplier<>() { + @Override + public Map, SoftReference> get() { + return new ConcurrentHashMap<>(64); + } + }); + + private InlineHiddenClassStrategy() { + // no instantiation + } + + private record MethodHandlePair(MethodHandle constructor, MethodHandle concatenator) { }; /** - * Ensure a capacity in the initial StringBuilder to accommodate all - * constants plus this factor times the number of arguments. + * The parameter types are normalized into 7 types: int,long,boolean,char,float,double,Object */ - static final int ARGUMENT_SIZE_FACTOR = 4; + private static MethodType erasedArgs(MethodType args) { + int parameterCount = args.parameterCount(); + var paramTypes = new Class[parameterCount]; + boolean changed = false; + for (int i = 0; i < parameterCount; i++) { + Class cl = args.parameterType(i); + // Use int as the logical type for subword integral types + // (byte and short). char and boolean require special + // handling so don't change the logical type of those + if (cl == byte.class || cl == short.class) { + cl = int.class; + changed = true; + } else if (cl != Object.class && !cl.isPrimitive()) { + cl = Object.class; + changed = true; + } + paramTypes[i] = cl; + } + return changed ? MethodType.methodType(args.returnType(), paramTypes) : args; + } - static final Set SET_OF_STRONG = Set.of(STRONG); + /** + * Construct the MethodType of the prepend method, The parameters only support 5 types: + * int/long/char/boolean/String. Not int/long/char/boolean type, use String type

+ * + * The following is an example of the generated target code: + *

+         *  int prepend(int length, byte coder, byte[] buff,  String[] constants
+         *      int arg0, long arg1, boolean arg2, char arg3, String arg5)
+         * 
+ */ + private static MethodTypeDesc prependArgs(MethodType concatArgs) { + int parameterCount = concatArgs.parameterCount(); + var paramTypes = new ClassDesc[parameterCount + 4]; + paramTypes[0] = CD_int; // length + paramTypes[1] = CD_byte; // coder + paramTypes[2] = CD_Array_byte; // buff + paramTypes[3] = CD_Array_String; // constants + + for (int i = 0; i < parameterCount; i++) { + var cl = concatArgs.parameterType(i); + paramTypes[i + 4] = needStringOf(cl) ? CD_String : ConstantUtils.classDesc(cl); + } + return MethodTypeDesc.of(CD_int, paramTypes); + } - private SimpleStringBuilderStrategy() { - // no instantiation + /** + * Construct the MethodType of the coder method, + * The first parameter is the initialized coder, Only parameter types that can be UTF16 are added. + */ + private static MethodTypeDesc coderArgs(MethodType concatArgs) { + int parameterCount = concatArgs.parameterCount(); + List paramTypes = new ArrayList<>(); + paramTypes.add(CD_int); // init coder + for (int i = 0; i < parameterCount; i++) { + var cl = concatArgs.parameterType(i); + if (maybeUTF16(cl)) { + paramTypes.add(cl == char.class ? CD_char : CD_String); + } + } + return MethodTypeDesc.of(CD_int, paramTypes); + } + + /** + * Construct the MethodType of the length method, + * The first parameter is the initialized length + */ + private static MethodTypeDesc lengthArgs(MethodType concatArgs) { + int parameterCount = concatArgs.parameterCount(); + var paramTypes = new ClassDesc[parameterCount + 1]; + paramTypes[0] = CD_int; // init long + for (int i = 0; i < parameterCount; i++) { + var cl = concatArgs.parameterType(i); + paramTypes[i + 1] = needStringOf(cl) ? CD_String : ConstantUtils.classDesc(cl); + } + return MethodTypeDesc.of(CD_int, paramTypes); } private static MethodHandle generate(Lookup lookup, MethodType args, String[] constants) throws Exception { - String className = getClassName(lookup.lookupClass()); + lookup = STR_LOOKUP; + final MethodType concatArgs = erasedArgs(args); + + // 1 argment use built-in method + if (args.parameterCount() == 1) { + Object concat1 = JLA.stringConcat1(constants); + var handle = lookup.findVirtual(concat1.getClass(), METHOD_NAME, concatArgs); + return handle.bindTo(concat1); + } - byte[] classBytes = ClassFile.of().build(ConstantUtils.binaryNameToDesc(className), + var weakConstructorHandle = CACHE.get(concatArgs); + if (weakConstructorHandle != null) { + MethodHandlePair handlePair = weakConstructorHandle.get(); + if (handlePair != null) { + try { + var instance = handlePair.constructor.invoke(constants); + return handlePair.concatenator.bindTo(instance); + } catch (Throwable e) { + throw new StringConcatException("Exception while utilizing the hidden class", e); + } + } + } + MethodTypeDesc lengthArgs = lengthArgs(concatArgs), + coderArgs = parameterMaybeUTF16(concatArgs) ? coderArgs(concatArgs) : null, + prependArgs = prependArgs(concatArgs); + + byte[] classBytes = ClassFile.of().build(CD_CONCAT, new Consumer() { + final boolean forceInline = concatArgs.parameterCount() < FORCE_INLINE_THRESHOLD; + @Override public void accept(ClassBuilder clb) { - clb.withFlags(AccessFlag.FINAL, AccessFlag.SUPER, AccessFlag.SYNTHETIC) - .withMethodBody(METHOD_NAME, - ConstantUtils.methodTypeDesc(args), - ClassFile.ACC_FINAL | ClassFile.ACC_PRIVATE | ClassFile.ACC_STATIC, - generateMethod(constants, args)); + clb.withSuperclass(CD_StringConcatBase) + .withFlags(ACC_FINAL | ACC_SUPER | ACC_SYNTHETIC) + .withMethodBody(INIT_NAME, MTD_INIT, 0, CONSTRUCTOR_BUILDER) + .withMethod("length", + lengthArgs, + ACC_STATIC | ACC_PRIVATE, + new Consumer() { + public void accept(MethodBuilder mb) { + if (forceInline) { + mb.with(FORCE_INLINE); + } + mb.withCode(generateLengthMethod(lengthArgs)); + } + }) + .withMethod("prepend", + prependArgs, + ACC_STATIC | ACC_PRIVATE, + new Consumer() { + public void accept(MethodBuilder mb) { + if (forceInline) { + mb.with(FORCE_INLINE); + } + mb.withCode(generatePrependMethod(prependArgs)); + } + }) + .withMethod(METHOD_NAME, + ConstantUtils.methodTypeDesc(concatArgs), + ACC_FINAL, + new Consumer() { + public void accept(MethodBuilder mb) { + if (forceInline) { + mb.with(FORCE_INLINE); + } + mb.withCode(generateConcatMethod( + CD_CONCAT, + concatArgs, + lengthArgs, + coderArgs, + prependArgs)); + } + }); + + if (coderArgs != null) { + clb.withMethod("coder", + coderArgs, + ACC_STATIC | ACC_PRIVATE, + new Consumer() { + public void accept(MethodBuilder mb) { + if (forceInline) { + mb.with(FORCE_INLINE); + } + mb.withCode(generateCoderMethod(coderArgs)); + } + }); + } }}); try { - Lookup hiddenLookup = lookup.makeHiddenClassDefiner(className, classBytes, SET_OF_STRONG, DUMPER) - .defineClassAsLookup(true); - Class innerClass = hiddenLookup.lookupClass(); - return hiddenLookup.findStatic(innerClass, METHOD_NAME, args); - } catch (Exception e) { + var hiddenClass = lookup.makeHiddenClassDefiner(CLASS_NAME, classBytes, Set.of(), DUMPER) + .defineClass(true, null); + var constructor = lookup.findConstructor(hiddenClass, CONSTRUCTOR_METHOD_TYPE); + var concat = lookup.findVirtual(hiddenClass, METHOD_NAME, concatArgs); + CACHE.put(concatArgs, new SoftReference<>(new MethodHandlePair(constructor, concat))); + var instance = hiddenClass.cast(constructor.invoke(constants)); + return concat.bindTo(instance); + } catch (Throwable e) { throw new StringConcatException("Exception while spinning the class", e); } } - private static Consumer generateMethod(String[] constants, MethodType args) { + /** + * Generate InlineCopy-based code.

+ * + * The following is an example of the generated target code: + * + *

+         *  import static java.lang.StringConcatHelper.newArrayWithSuffix;
+         *  import static java.lang.StringConcatHelper.prepend;
+         *  import static java.lang.StringConcatHelper.stringCoder;
+         *  import static java.lang.StringConcatHelper.stringSize;
+         *
+         *  class StringConcat extends java.lang.StringConcatHelper.StringConcatBase {
+         *      // super class defines
+         *      // String[] constants;
+         *      // int length;
+         *      // byte coder;
+         *
+         *      StringConcat(String[] constants) {
+         *          super(constants);
+         *      }
+         *
+         *      String concat(int arg0, long arg1, boolean arg2, char arg3, String arg4,
+         *          float arg5, double arg6, Object arg7
+         *      ) {
+         *          // Types other than byte/short/int/long/boolean/String require a local variable to store
+         *          String str4 = stringOf(arg4);
+         *          String str5 = stringOf(arg5);
+         *          String str6 = stringOf(arg6);
+         *          String str7 = stringOf(arg7);
+         *
+         *          int coder  = coder(this.coder, arg0, arg1, arg2, arg3, str4, str5, str6, str7);
+         *          int length = length(this.length, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+         *          String[] constants = this.constants;
+         *          byte[] buf = newArrayWithSuffix(constants[paramCount], length. coder);
+         *
+         *          prepend(length, coder, buf, constants, arg0, arg1, arg2, arg3, str4, str5, str6, str7);
+         *
+         *          return new String(buf, coder);
+         *      }
+         *
+         *      static int length(int length, int arg0, long arg1, boolean arg2, char arg3,
+         *                       String arg4, String arg5, String arg6, String arg7) {
+         *          return stringSize(stringSize(stringSize(stringSize(stringSize(stringSize(stringSize(stringSize(
+         *                      length, arg0), arg1), arg2), arg3), arg4), arg5), arg6), arg7);
+         *      }
+         *
+         *      static int cocder(int coder, char arg3, String str4, String str5, String str6, String str7) {
+         *          return coder | stringCoder(arg3) | str4.coder() | str5.coder() | str6.coder() | str7.coder();
+         *      }
+         *
+         *      static int prepend(int length, int coder, byte[] buf, String[] constants,
+         *                     int arg0, long arg1, boolean arg2, char arg3,
+         *                     String str4, String str5, String str6, String str7) {
+         *          // StringConcatHelper.prepend
+         *          return prepend(prepend(prepend(prepend(
+         *                  prepend(apppend(prepend(prepend(length,
+         *                       buf, str7, constant[7]), buf, str6, constant[6]),
+         *                       buf, str5, constant[5]), buf, str4, constant[4]),
+         *                       buf, arg3, constant[3]), buf, arg2, constant[2]),
+         *                       buf, arg1, constant[1]), buf, arg0, constant[0]);
+         *      }
+         *  }
+         * 
+ */ + private static Consumer generateConcatMethod( + ClassDesc concatClass, + MethodType concatArgs, + MethodTypeDesc lengthArgs, + MethodTypeDesc coderArgs, + MethodTypeDesc prependArgs + ) { return new Consumer() { @Override public void accept(CodeBuilder cb) { - cb.new_(STRING_BUILDER); - cb.dup(); - - int len = 0; - for (String constant : constants) { - if (constant != null) { - len += constant.length(); + // Compute parameter variable slots + int paramCount = concatArgs.parameterCount(), + thisSlot = cb.receiverSlot(), + lengthSlot = cb.allocateLocal(TypeKind.IntType), + coderSlot = cb.allocateLocal(TypeKind.ByteType), + bufSlot = cb.allocateLocal(TypeKind.ReferenceType), + constantsSlot = cb.allocateLocal(TypeKind.ReferenceType), + suffixSlot = cb.allocateLocal(TypeKind.ReferenceType); + + /* + * Types other than int/long/char/boolean require local variables to store the result of stringOf. + * + * stringSlots stores the slots of parameters relative to local variables + * + * str0 = stringOf(arg0); + * str1 = stringOf(arg1); + * ... + * strN = toString(argN); + */ + int[] stringSlots = new int[paramCount]; + for (int i = 0; i < paramCount; i++) { + var cl = concatArgs.parameterType(i); + if (needStringOf(cl)) { + MethodTypeDesc methodTypeDesc; + if (cl == float.class) { + methodTypeDesc = MTD_String_float; + } else if (cl == double.class) { + methodTypeDesc = MTD_String_double; + } else { + methodTypeDesc = MTD_String_Object; + } + stringSlots[i] = cb.allocateLocal(TypeKind.ReferenceType); + cb.loadLocal(TypeKind.from(cl), cb.parameterSlot(i)) + .invokestatic(CD_StringConcatHelper, "stringOf", methodTypeDesc) + .astore(stringSlots[i]); } } - len += args.parameterCount() * ARGUMENT_SIZE_FACTOR; - cb.loadConstant(len); - cb.invokespecial(STRING_BUILDER, "", INT_CONSTRUCTOR_TYPE); - - // At this point, we have a blank StringBuilder on stack, fill it in with .append calls. - { - int off = 0; - for (int c = 0; c < args.parameterCount(); c++) { - if (constants[c] != null) { - cb.ldc(constants[c]); - cb.invokevirtual(STRING_BUILDER, "append", APPEND_STRING_TYPE); + + /* + * coder = coder(this.coder, arg0, arg1, ... argN); + */ + cb.aload(thisSlot) + .getfield(concatClass, "coder", CD_byte); + if (coderArgs != null) { + for (int i = 0; i < paramCount; i++) { + var cl = concatArgs.parameterType(i); + if (maybeUTF16(cl)) { + if (cl == char.class) { + cb.loadLocal(TypeKind.CharType, cb.parameterSlot(i)); + } else { + cb.aload(stringSlots[i]); + } } - Class cl = args.parameterType(c); - TypeKind kind = TypeKind.from(cl); - cb.loadLocal(kind, off); - off += kind.slotSize(); - MethodTypeDesc desc = getSBAppendDesc(cl); - cb.invokevirtual(STRING_BUILDER, "append", desc); } - if (constants[constants.length - 1] != null) { - cb.ldc(constants[constants.length - 1]); - cb.invokevirtual(STRING_BUILDER, "append", APPEND_STRING_TYPE); + cb.invokestatic(concatClass, "coder", coderArgs); + } + cb.istore(coderSlot); + + /* + * length = length(this.length, arg0, arg1, ..., argN); + */ + cb.aload(thisSlot) + .getfield(concatClass, "length", CD_int); + for (int i = 0; i < paramCount; i++) { + var cl = concatArgs.parameterType(i); + int paramSlot = cb.parameterSlot(i); + if (needStringOf(cl)) { + paramSlot = stringSlots[i]; + cl = String.class; + } + cb.loadLocal(TypeKind.from(cl), paramSlot); + } + cb.invokestatic(concatClass, "length", lengthArgs); + + /* + * String[] constants = this.constants; + * suffix = constants[paranCount]; + * length -= suffix.length(); + */ + cb.aload(thisSlot) + .getfield(concatClass, "constants", CD_Array_String) + .dup() + .astore(constantsSlot) + .ldc(paramCount) + .aaload() + .dup() + .astore(suffixSlot) + .invokevirtual(CD_String, "length", MTD_int) + .isub() + .istore(lengthSlot); + + /* + * Allocate buffer : + * + * buf = newArrayWithSuffix(suffix, length, coder) + */ + cb.aload(suffixSlot) + .iload(lengthSlot) + .iload(coderSlot) + .invokestatic(CD_StringConcatHelper, "newArrayWithSuffix", MTD_NEW_ARRAY_SUFFIX) + .astore(bufSlot); + + /* + * prepend(length, coder, buf, constants, ar0, ar1, ..., argN); + */ + cb.iload(lengthSlot) + .iload(coderSlot) + .aload(bufSlot) + .aload(constantsSlot); + for (int i = 0; i < paramCount; i++) { + var cl = concatArgs.parameterType(i); + int paramSlot = cb.parameterSlot(i); + var kind = TypeKind.from(cl); + if (needStringOf(cl)) { + paramSlot = stringSlots[i]; + kind = TypeKind.ReferenceType; } + cb.loadLocal(kind, paramSlot); } + cb.invokestatic(concatClass, "prepend", prependArgs); + + // return new String(buf, coder); + cb.new_(CD_String) + .dup() + .aload(bufSlot) + .iload(coderSlot) + .invokespecial(CD_String, INIT_NAME, MTD_STRING_INIT) + .areturn(); + } + }; + } - cb.invokevirtual(STRING_BUILDER, "toString", TO_STRING_TYPE); - cb.areturn(); + /** + * Generate length method.

+ * + * The following is an example of the generated target code: + * + *

+         * import static java.lang.StringConcatHelper.stringSize;
+         *
+         * static int length(int length, int arg0, long arg1, boolean arg2, char arg3,
+         *                  String arg4, String arg5, String arg6, String arg7) {
+         *     return stringSize(stringSize(stringSize(length, arg0), arg1), ..., arg7);
+         * }
+         * 
+ */ + private static Consumer generateLengthMethod(MethodTypeDesc lengthArgs) { + return new Consumer() { + @Override + public void accept(CodeBuilder cb) { + int lengthSlot = cb.parameterSlot(0); + cb.iload(lengthSlot); + for (int i = 1; i < lengthArgs.parameterCount(); i++) { + var cl = lengthArgs.parameterType(i); + MethodTypeDesc methodTypeDesc; + if (cl == CD_char) { + methodTypeDesc = MTD_int_int_char; + } else if (cl == CD_int) { + methodTypeDesc = MTD_int_int_int; + } else if (cl == CD_long) { + methodTypeDesc = MTD_int_int_long; + } else if (cl == CD_boolean) { + methodTypeDesc = MTD_int_int_boolean; + } else { + methodTypeDesc = MTD_int_int_String; + } + cb.loadLocal(TypeKind.from(cl), cb.parameterSlot(i)) + .invokestatic(CD_StringConcatHelper, "stringSize", methodTypeDesc); + } + cb.ireturn(); } }; } /** - * The generated class is in the same package as the host class as - * it's the implementation of the string concatenation for the host - * class. + * Generate coder method.

+ * + * The following is an example of the generated target code: + * + *

+         * import static java.lang.StringConcatHelper.stringCoder;
+         *
+         * static int cocder(int coder, char arg3, String str4, String str5, String str6, String str7) {
+         *     return coder | stringCoder(arg3) | str4.coder() | str5.coder() | str6.coder() | str7.coder();
+         * }
+         * 
*/ - private static String getClassName(Class hostClass) { - String name = hostClass.isHidden() ? hostClass.getName().replace('/', '_') - : hostClass.getName(); - return name + "$$StringConcat"; + private static Consumer generateCoderMethod(MethodTypeDesc coderArgs) { + return new Consumer() { + @Override + public void accept(CodeBuilder cb) { + /* + * return coder | stringCoder(argN) | ... | arg1.coder() | arg0.coder(); + */ + int coderSlot = cb.parameterSlot(0); + cb.iload(coderSlot); + for (int i = 1; i < coderArgs.parameterCount(); i++) { + var cl = coderArgs.parameterType(i); + cb.loadLocal(TypeKind.from(cl), cb.parameterSlot(i)); + if (cl == CD_char) { + cb.invokestatic(CD_StringConcatHelper, "stringCoder", MTD_byte_char); + } else { + cb.invokevirtual(CD_String, "coder", MTD_byte); + } + cb.ior(); + } + cb.ireturn(); + } + }; } - private static MethodTypeDesc getSBAppendDesc(Class cl) { - if (cl.isPrimitive()) { - if (cl == Integer.TYPE || cl == Byte.TYPE || cl == Short.TYPE) { - return APPEND_INT_TYPE; - } else if (cl == Boolean.TYPE) { - return APPEND_BOOLEAN_TYPE; - } else if (cl == Character.TYPE) { - return APPEND_CHAR_TYPE; - } else if (cl == Double.TYPE) { - return APPEND_DOUBLE_TYPE; - } else if (cl == Float.TYPE) { - return APPEND_FLOAT_TYPE; - } else if (cl == Long.TYPE) { - return APPEND_LONG_TYPE; - } else { - throw new IllegalStateException("Unhandled primitive StringBuilder.append: " + cl); + /** + * Generate prepend method.

+ * + * The following is an example of the generated target code: + * + *

+         * import static java.lang.StringConcatHelper.prepend;
+         *
+         * static int prepend(int length, int coder, byte[] buf, String[] constants,
+         *                int arg0, long arg1, boolean arg2, char arg3,
+         *                String str4, String str5, String str6, String str7) {
+         *
+         *     return prepend(prepend(prepend(prepend(
+         *             prepend(prepend(prepend(prepend(length,
+         *                  buf, str7, constant[7]), buf, str6, constant[6]),
+         *                  buf, str5, constant[5]), buf, str4, constant[4]),
+         *                  buf, arg3, constant[3]), buf, arg2, constant[2]),
+         *                  buf, arg1, constant[1]), buf, arg0, constant[0]);
+         * }
+         * 
+ */ + private static Consumer generatePrependMethod(MethodTypeDesc prependArgs) { + return new Consumer() { + @Override + public void accept(CodeBuilder cb) { + // Compute parameter variable slots + int lengthSlot = cb.parameterSlot(0), + coderSlot = cb.parameterSlot(1), + bufSlot = cb.parameterSlot(2), + constantsSlot = cb.parameterSlot(3); + /* + * // StringConcatHelper.prepend + * return prepend(prepend(prepend(prepend( + * prepend(apppend(prepend(prepend(length, + * buf, str7, constant[7]), buf, str6, constant[6]), + * buf, str5, constant[5]), buf, arg4, constant[4]), + * buf, arg3, constant[3]), buf, arg2, constant[2]), + * buf, arg1, constant[1]), buf, arg0, constant[0]); + */ + cb.iload(lengthSlot); + for (int i = prependArgs.parameterCount() - 1; i >= 4; i--) { + var cl = prependArgs.parameterType(i); + var kind = TypeKind.from(cl); + + // There are only 5 types of parameters: int, long, boolean, char, String + MethodTypeDesc methodTypeDesc; + if (cl == CD_int) { + methodTypeDesc = PREPEND_int; + } else if (cl == CD_long) { + methodTypeDesc = PREPEND_long; + } else if (cl == CD_boolean) { + methodTypeDesc = PREPEND_boolean; + } else if (cl == CD_char) { + methodTypeDesc = PREPEND_char; + } else { + kind = TypeKind.ReferenceType; + methodTypeDesc = PREPEND_String; + } + + cb.iload(coderSlot) + .aload(bufSlot) + .loadLocal(kind, cb.parameterSlot(i)) + .aload(constantsSlot) + .ldc(i - 4) + .aaload() + .invokestatic(CD_StringConcatHelper, "prepend", methodTypeDesc); + } + cb.ireturn(); + } + }; + } + + static boolean needStringOf(Class cl) { + return cl != int.class && cl != long.class && cl != boolean.class && cl != char.class; + } + + static boolean maybeUTF16(Class cl) { + return cl == char.class || !cl.isPrimitive(); + } + + static boolean parameterMaybeUTF16(MethodType args) { + for (int i = 0; i < args.parameterCount(); i++) { + if (maybeUTF16(args.parameterType(i))) { + return true; } - } else if (cl == String.class) { - return APPEND_STRING_TYPE; - } else { - return APPEND_OBJECT_TYPE; } + return false; } } } diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java index 24aeabf6d36..e4d322a20d7 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java @@ -446,6 +446,8 @@ public interface JavaLangAccess { */ long stringConcatMix(long lengthCoder, char value); + Object stringConcat1(String[] constants); + /** * Join strings */ diff --git a/src/java.base/share/classes/jdk/internal/util/ClassFileDumper.java b/src/java.base/share/classes/jdk/internal/util/ClassFileDumper.java index afb3d1374ab..b104b56ac0e 100644 --- a/src/java.base/share/classes/jdk/internal/util/ClassFileDumper.java +++ b/src/java.base/share/classes/jdk/internal/util/ClassFileDumper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ package jdk.internal.util; import jdk.internal.misc.VM; -import sun.security.action.GetPropertyAction; import java.io.IOException; import java.nio.file.Files; @@ -80,7 +79,11 @@ public static ClassFileDumper getInstance(String key, String path) { private final AtomicInteger counter = new AtomicInteger(); private ClassFileDumper(String key, String path) { - String value = GetPropertyAction.privilegedGetProperty(key); + /* + * GetPropertyAction.privilegedGetProperty cannot be used here, Using VM.getSavedProperty to avoid a bootstrap + * circularity issue in the java/lang/String/concat/WithSecurityManager.java test + */ + String value = VM.getSavedProperty(key); this.key = key; boolean enabled = value != null && value.isEmpty() ? true : Boolean.parseBoolean(value); if (enabled) { diff --git a/test/jdk/java/lang/String/concat/HiddenClassUnloading.java b/test/jdk/java/lang/String/concat/HiddenClassUnloading.java new file mode 100644 index 00000000000..9e682f38ef5 --- /dev/null +++ b/test/jdk/java/lang/String/concat/HiddenClassUnloading.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2024, Alibaba Group Holding 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 + * 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.lang.StringBuilder; + +import java.lang.invoke.*; +import java.lang.management.ManagementFactory; + +/** + * @test + * @summary Test whether the hidden class unloading of StringConcatFactory works + * + * @requires vm.flagless + * @run main/othervm -Xmx8M -Xms8M -Xverify:all HiddenClassUnloading + * @run main/othervm -Xmx8M -Xms8M -Xverify:all -XX:-CompactStrings HiddenClassUnloading + */ +public class HiddenClassUnloading { + public static void main(String[] args) throws Throwable { + var lookup = MethodHandles.lookup(); + var types = new Class[] { + int.class, long.class, double.class, float.class, char.class, boolean.class, String.class, + }; + + long initUnloadedClassCount = ManagementFactory.getClassLoadingMXBean().getUnloadedClassCount(); + + for (int i = 0; i < 2000; i++) { + int radix = types.length; + String str = Integer.toString(i, radix); + int length = str.length(); + var ptypes = new Class[length]; + for (int j = 0; j < length; j++) { + int index = Integer.parseInt(str.substring(j, j + 1), radix); + ptypes[j] = types[index]; + } + StringConcatFactory.makeConcatWithConstants( + lookup, + "concat", + MethodType.methodType(String.class, ptypes), + "\1".repeat(length), // recipe + new Object[0] + ); + } + + long unloadedClassCount = ManagementFactory.getClassLoadingMXBean().getUnloadedClassCount(); + if (initUnloadedClassCount == unloadedClassCount) { + throw new RuntimeException("unloadedClassCount is zero"); + } + } +} diff --git a/test/micro/org/openjdk/bench/java/lang/StringConcat.java b/test/micro/org/openjdk/bench/java/lang/StringConcat.java index 015ad224631..e1b8d882dd9 100644 --- a/test/micro/org/openjdk/bench/java/lang/StringConcat.java +++ b/test/micro/org/openjdk/bench/java/lang/StringConcat.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding 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 @@ -48,22 +49,40 @@ public class StringConcat { @Param("4711") public int intValue; - + public Integer integerValue = intValue; + public float floatValue = 156456.36435637F + intValue; public String stringValue = String.valueOf(intValue); - public Object objectValue = Long.valueOf(intValue); - public boolean boolValue = true; - + public Boolean booleanValue = Boolean.TRUE; public byte byteValue = (byte)-128; - public String emptyString = ""; + @Benchmark + public String concatConstBool() { + return "string" + boolValue; + } + + @Benchmark + public String concatConstBoolean() { + return "string" + booleanValue; + } + @Benchmark public String concatConstInt() { return "string" + intValue; } + @Benchmark + public String concatConstInteger() { + return "string" + integerValue; + } + + @Benchmark + public String concatConstFloat() { + return "string" + floatValue; + } + @Benchmark public String concatConstString() { return "string" + stringValue; @@ -94,6 +113,31 @@ public String concatMethodConstString() { return "string".concat(stringValue); } + @Benchmark + public String concatConstBoolString() { + return "string" + boolValue + stringValue; + } + + @Benchmark + public String concatConstBooleanString() { + return "string" + booleanValue + stringValue; + } + + @Benchmark + public String concatConstIntString() { + return "string" + intValue + stringValue; + } + + @Benchmark + public String concatConstIntegerString() { + return "string" + integerValue + stringValue; + } + + @Benchmark + public String concatConstFloatString() { + return "string" + floatValue + stringValue; + } + @Benchmark public String concatConstIntConstInt() { return "string" + intValue + "string" + intValue; @@ -104,6 +148,36 @@ public String concatConstStringConstInt() { return "string" + stringValue + "string" + intValue; } + @Benchmark + public String concatConstStringConst() { + return "string" + stringValue + "string"; + } + + @Benchmark + public String concatConstIntConst() { + return "string" + intValue + "string"; + } + + @Benchmark + public String concatConstIntegerConst() { + return "string" + integerValue + "string"; + } + + @Benchmark + public String concatConstFloatConst() { + return "string" + floatValue + "string"; + } + + @Benchmark + public String concatConstObjectConst() { + return "string" + objectValue + "string"; + } + + @Benchmark + public String concatConstBooleanConst() { + return "string" + booleanValue + "string"; + } + @Benchmark public String concatMix4String() { // Investigate "profile pollution" between shared LFs that might eliminate some JIT optimizations @@ -114,6 +188,31 @@ public String concatMix4String() { return s1 + s2 + s3 + s4; } + @Benchmark + public String concat3String() { + return stringValue + stringValue + stringValue; + } + + @Benchmark + public String concatStringBoolString() { + return stringValue + boolValue + stringValue; + } + + @Benchmark + public String concatStringBooleanString() { + return stringValue + booleanValue + stringValue; + } + + @Benchmark + public String concatStringIntString() { + return stringValue + intValue + stringValue; + } + + @Benchmark + public String concatStringIntegerString() { + return stringValue + integerValue + stringValue; + } + @Benchmark public String concatConst4String() { return "string" + stringValue + stringValue + stringValue + stringValue; @@ -176,6 +275,15 @@ public String concat23String() { + f10 + ","+ f11 + ","+ f12 + ","+ f13 + ","+ f14 + ","+ f15 + ","+ f16 + ","+ f17 + ","+ f18 + ","+ f19 + "," + f20 + ","+ f21 + ","+ f22; } + + @Benchmark + public String concat30Mix() { + return f0 + "," + f1 + ","+ f2 + ","+ f3 + ","+ f4 + ","+ f5 + ","+ f6 + ","+ f7 + ","+ f8 + ","+ f9 + "," + +f10 + ","+f11 + ","+f12 + ","+ f13 + ","+ f14 + ","+ f15 + ","+ f16 + ","+ f17 + ","+ f18 + ","+ f19 + "," + +f20 + ","+f21 + ","+f22 + "," + boolValue + "," + booleanValue + "," + intValue + "," + integerValue + + "," + floatValue + "," + byteValue + "," + objectValue; + } + @Benchmark public String concat123String() { return f0 + ","+ f1 + ","+ f2 + ","+ f3 + ","+ f4 + ","+ f5 + ","+ f6 + ","+ f7 + ","+ f8 + ","+ f9 + "," @@ -193,9 +301,38 @@ public String concat123String() { +f120 + ","+f121 + ","+f122; } + @Benchmark + public String concat13StringConst() { + return f0 + f1 + f2 + f3 + f4 + + f5 + f6 + f7 + f8 + f9 + +f10 + f11 + f12 + """ + A really long constant string. Such as a copyright header: + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + """; + } + @Benchmark public String concat23StringConst() { - return f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + """ + return f0 + f1 + f2 + f3 + f4 + f5 + f6 + f7 + f8 + f9 + f10 + f11 + f12 + f13 + f14 + f15 + f16 + f17 + f18 + f19 + f20 + f21 + f22 + """ A really long constant string. Such as a copyright header: * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. diff --git a/test/micro/org/openjdk/bench/java/lang/StringConcatStartup.java b/test/micro/org/openjdk/bench/java/lang/StringConcatStartup.java index d146fbf9885..cb3d09f94ad 100644 --- a/test/micro/org/openjdk/bench/java/lang/StringConcatStartup.java +++ b/test/micro/org/openjdk/bench/java/lang/StringConcatStartup.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding 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 @@ -27,6 +28,7 @@ import org.openjdk.jmh.annotations.Fork; 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; @@ -44,13 +46,31 @@ public class StringConcatStartup { public static void main(String... args) { - String[] selection = new String[] { "StringLarge", "MixedSmall", "StringSingle", "MixedLarge" }; + String[] selection = { + "StringLarge", + "MixedSmall", + "StringSingle", + "StringThree", + "MixedLarge" + }; if (args.length > 0) { selection = args; } for (String select : selection) { switch (select) { - case "StringSingle" -> new StringSingle().run(); + case "StringSingle" -> { + new StringSingle().constInt(); + new StringSingle().constFloat(); + new StringSingle().constString(); + new StringSingle().const2String(); + new StringSingle().constIntString(); + new StringSingle().constFloatString(); + new StringSingle().constBooleanString(); + } + case "StringThree" -> { + new StringThree().stringIntString(); + new StringThree().stringIntegerString(); + } case "MixedSmall" -> new MixedSmall().run(); case "StringLarge" -> new StringLarge().run(); case "MixedLarge" -> new MixedLarge().run(); @@ -64,14 +84,95 @@ public static void main(String... args) { @Fork(value = 40, warmups = 2) public static class StringSingle { - public String s = "foo"; + @Param("4711") + public int intValue; + public Integer integerValue = intValue; + public float floatValue = 156456.36435637F + intValue; + public String stringValue = String.valueOf(intValue); + public boolean boolValue = true; + public Boolean booleanValue = Boolean.TRUE; @Benchmark - public String run() { - return "" + s; + public String constBool() { + return "string" + boolValue; + } + + @Benchmark + public String constBoolean() { + return "string" + booleanValue; + } + + @Benchmark + public String constInt() { + return "string" + intValue; + } + + @Benchmark + public String constInteger() { + return "string" + integerValue; + } + + @Benchmark + public String constFloat() { + return "string" + floatValue; + } + + @Benchmark + public String constString() { + return "string" + stringValue; + } + + public String const2String() { + return "string" + stringValue + stringValue; + } + + @Benchmark + public String constIntString() { + return "string" + intValue + stringValue; + } + + @Benchmark + public String constIntegerString() { + return "string" + integerValue + stringValue; + } + + @Benchmark + public String constFloatString() { + return "string" + floatValue + stringValue; + } + + @Benchmark + public String constBoolString() { + return "string" + boolValue + stringValue; + } + + @Benchmark + public String constBooleanString() { + return "string" + booleanValue + stringValue; } } + @BenchmarkMode(Mode.SingleShotTime) + @OutputTimeUnit(TimeUnit.MILLISECONDS) + @State(Scope.Thread) + @Fork(value = 40, warmups = 2) + public static class StringThree { + + @Param("4711") + public int intValue; + public Integer integerValue = intValue; + public String stringValue = String.valueOf(intValue); + + @Benchmark + public String stringIntString() { + return stringValue + intValue + stringValue; + } + + @Benchmark + public String stringIntegerString() { + return stringValue + integerValue + stringValue; + } + } @BenchmarkMode(Mode.SingleShotTime) @OutputTimeUnit(TimeUnit.MILLISECONDS) From 07352c67448f3f35827395c83ac95e3ca0e4c6bc Mon Sep 17 00:00:00 2001 From: Pavel Rappo Date: Fri, 16 Aug 2024 14:06:10 +0000 Subject: [PATCH 442/460] 8338398: Trivially fix grammar and typos Reviewed-by: aivanov --- .../share/classes/java/util/concurrent/CompletableFuture.java | 4 ++-- .../share/classes/java/util/concurrent/ForkJoinPool.java | 4 ++-- .../share/classes/java/util/concurrent/ForkJoinTask.java | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java b/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java index 1a43b29d798..8adfd106eeb 100644 --- a/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java +++ b/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java @@ -2805,7 +2805,7 @@ public CompletableFuture completeAsync(Supplier supplier) { /** * Exceptionally completes this CompletableFuture with * a {@link TimeoutException} if not otherwise completed - * before the given timeout. + * before the given timeout elapsed. * * @param timeout how long to wait before completing exceptionally * with a TimeoutException, in units of {@code unit} @@ -2825,7 +2825,7 @@ public CompletableFuture orTimeout(long timeout, TimeUnit unit) { /** * Completes this CompletableFuture with the given value if not - * otherwise completed before the given timeout. + * otherwise completed before the given timeout elapsed. * * @param value the value to use upon timeout * @param timeout how long to wait before completing normally diff --git a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java index 18b2bdeaa42..cb061813c8a 100644 --- a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java +++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java @@ -670,7 +670,7 @@ public class ForkJoinPool extends AbstractExecutorService { * period given by field keepAlive (default 60sec), which applies * to the first timeout of a quiescent pool. Subsequent cases use * minimal delays such that, if still quiescent, all will be - * released soon therafter. This is checked by setting the + * released soon thereafter. This is checked by setting the * "source" field of signallee to an invalid value, that will * remain invalid only if it did not process any tasks. * @@ -855,7 +855,7 @@ public class ForkJoinPool extends AbstractExecutorService { * non-workers (which comply with Future.get() specs). Internal * usages of ForkJoinTasks ignore interrupt status when executing * or awaiting completion. Otherwise, reporting task results or - * exceptions is preferred to throwing InterruptedExecptions, + * exceptions is preferred to throwing InterruptedExceptions, * which are in turn preferred to timeouts. Similarly, completion * status is preferred to reporting cancellation. Cancellation is * reported as an unchecked exception by join(), and by worker diff --git a/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java b/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java index 8ca52dc5cb2..7c1e974aafa 100644 --- a/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java +++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java @@ -1072,7 +1072,7 @@ public final void quietlyInvoke() { /** * Tries to join this task, returning true if it completed - * (possibly exceptionally) before the given timeout and + * (possibly exceptionally) before the given timeout elapsed and * the current thread has not been interrupted. * * @param timeout the maximum time to wait @@ -1097,7 +1097,7 @@ public final boolean quietlyJoin(long timeout, TimeUnit unit) /** * Tries to join this task, returning true if it completed - * (possibly exceptionally) before the given timeout. + * (possibly exceptionally) before the given timeout elapsed. * * @param timeout the maximum time to wait * @param unit the time unit of the timeout argument From 961e944fa731dc84be2764c01e4b326187474605 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Fri, 16 Aug 2024 15:48:54 +0000 Subject: [PATCH 443/460] 8336754: Remodel TypeAnnotation to "has" instead of "be" an Annotation Co-authored-by: Alex Buckley Reviewed-by: asotona --- .../java/lang/classfile/Annotation.java | 46 +++++-- .../lang/classfile/AnnotationElement.java | 58 +++++--- .../java/lang/classfile/AnnotationValue.java | 127 ++++++++++-------- .../java/lang/classfile/TypeAnnotation.java | 72 +++------- .../impl/AbstractAttributeMapper.java | 4 +- .../classfile/impl/AnnotationReader.java | 70 +++++++++- .../classfile/impl/ClassPrinterImpl.java | 4 +- .../classfile/impl/ClassRemapperImpl.java | 4 +- .../classfile/impl/UnboundAttribute.java | 73 +--------- .../impl/verifier/ParserVerifier.java | 4 +- .../com/sun/tools/javap/AnnotationWriter.java | 6 +- test/jdk/jdk/classfile/ClassPrinterTest.java | 6 +- test/jdk/jdk/classfile/TransformTests.java | 2 +- .../jdk/classfile/helpers/ClassRecord.java | 2 +- .../helpers/RebuildingTransformation.java | 3 +- .../classfile/ClassfileInspector.java | 8 +- .../classfile/AnonymousClassTest.java | 4 +- .../referenceinfos/ReferenceInfoUtil.java | 4 +- .../tools/javac/patterns/Annotations.java | 4 +- .../javac/records/RecordCompilationTests.java | 2 +- 20 files changed, 260 insertions(+), 243 deletions(-) diff --git a/src/java.base/share/classes/java/lang/classfile/Annotation.java b/src/java.base/share/classes/java/lang/classfile/Annotation.java index 28c3672bf91..357a7cb77ee 100644 --- a/src/java.base/share/classes/java/lang/classfile/Annotation.java +++ b/src/java.base/share/classes/java/lang/classfile/Annotation.java @@ -37,43 +37,60 @@ import jdk.internal.javac.PreviewFeature; /** - * Models an annotation on a declaration. + * Models an {@code annotation} structure (JVMS {@jvms 4.7.16}) or part of a {@code + * type_annotation} structure (JVMS {@jvms 4.7.20}). This model indicates the + * interface of the annotation and a set of element-value pairs. + *

+ * This model can reconstruct an annotation, given the location of the modeled structure + * in the class file and the definition of the annotation interface. + *

+ * Two {@code Annotation} objects should be compared using the {@link + * Object#equals(Object) equals} method. + * + * @apiNote + * For Java programs, the location of the modeled structure indicates the source code + * element or type (JLS {@jls 9.7.4}) on which the reconstructed annotation appears, + * and the annotation interface definition determines whether the reconstructed annotation has + * elements with default values (JLS {@jls 9.6.2}), and whether the reconstructed annotation + * is a container annotation for multiple annotations (JLS {@jls 9.7.5}). * * @see AnnotationElement * @see AnnotationValue + * @see TypeAnnotation * @see RuntimeVisibleAnnotationsAttribute * @see RuntimeInvisibleAnnotationsAttribute * @see RuntimeVisibleParameterAnnotationsAttribute * @see RuntimeInvisibleParameterAnnotationsAttribute * - * @sealedGraph * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) public sealed interface Annotation - permits TypeAnnotation, AnnotationImpl { + permits AnnotationImpl { /** - * {@return the class of the annotation} + * {@return the constant pool entry holding the {@linkplain Class#descriptorString + * descriptor string} of the annotation interface} */ Utf8Entry className(); /** - * {@return the class of the annotation, as a symbolic descriptor} + * {@return the annotation interface, as a symbolic descriptor} */ default ClassDesc classSymbol() { return ClassDesc.ofDescriptor(className().stringValue()); } /** - * {@return the elements of the annotation} + * {@return the element-value pairs of the annotation} */ List elements(); /** * {@return an annotation} - * @param annotationClass the class of the annotation - * @param elements the elements of the annotation + * @param annotationClass the constant pool entry holding the descriptor string + * of the annotation interface + * @param elements the element-value pairs of the annotation */ static Annotation of(Utf8Entry annotationClass, List elements) { @@ -82,8 +99,9 @@ static Annotation of(Utf8Entry annotationClass, /** * {@return an annotation} - * @param annotationClass the class of the annotation - * @param elements the elements of the annotation + * @param annotationClass the constant pool entry holding the descriptor string + * of the annotation interface + * @param elements the element-value pairs of the annotation */ static Annotation of(Utf8Entry annotationClass, AnnotationElement... elements) { @@ -92,8 +110,8 @@ static Annotation of(Utf8Entry annotationClass, /** * {@return an annotation} - * @param annotationClass the class of the annotation - * @param elements the elements of the annotation + * @param annotationClass the descriptor of the annotation interface + * @param elements the element-value pairs of the annotation */ static Annotation of(ClassDesc annotationClass, List elements) { @@ -102,8 +120,8 @@ static Annotation of(ClassDesc annotationClass, /** * {@return an annotation} - * @param annotationClass the class of the annotation - * @param elements the elements of the annotation + * @param annotationClass the descriptor of the annotation interface + * @param elements the element-value pairs of the annotation */ static Annotation of(ClassDesc annotationClass, AnnotationElement... elements) { diff --git a/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java b/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java index 80adb07ec4b..33bd410e78d 100644 --- a/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java +++ b/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java @@ -32,7 +32,13 @@ import jdk.internal.javac.PreviewFeature; /** - * Models a key-value pair of an annotation. + * Models an element-value pair in the {@code element_value_pairs} + * table in the {@code annotation} structure defined in JVMS + * {@jvms 4.7.16} or the {@code type_annotation} structure defined + * in JVMS {@jvms 4.7.20}. + *

+ * Two {@code AnnotationElement} objects should be compared using the + * {@link Object#equals(Object) equals} method. * * @see Annotation * @see AnnotationValue @@ -45,6 +51,12 @@ public sealed interface AnnotationElement /** * {@return the element name} + * + * @apiNote + * In Java source code, by convention, the name of the sole element in a + * single-element annotation interface is {@code value}. (JLS {@jls 9.6.1}) + * This is the case for single-element annotations (JLS {@jls 9.7.3}) and + * container annotations for multiple annotations (JLS {@jls 9.6.3}). */ Utf8Entry name(); @@ -54,7 +66,7 @@ public sealed interface AnnotationElement AnnotationValue value(); /** - * {@return an annotation key-value pair} + * {@return an element-value pair} * @param name the name of the key * @param value the associated value */ @@ -64,7 +76,7 @@ static AnnotationElement of(Utf8Entry name, } /** - * {@return an annotation key-value pair} + * {@return an element-value pair} * @param name the name of the key * @param value the associated value */ @@ -74,9 +86,10 @@ static AnnotationElement of(String name, } /** - * {@return an annotation key-value pair for a class-valued annotation} + * {@return an element-value pair for a class-valued element} * @param name the name of the key * @param value the associated value + * @see AnnotationValue#ofClass(ClassDesc) AnnotationValue::ofClass */ static AnnotationElement ofClass(String name, ClassDesc value) { @@ -84,9 +97,10 @@ static AnnotationElement ofClass(String name, } /** - * {@return an annotation key-value pair for a string-valued annotation} + * {@return an element-value pair for a string-valued element} * @param name the name of the key * @param value the associated value + * @see AnnotationValue#ofString(String) AnnotationValue::ofString */ static AnnotationElement ofString(String name, String value) { @@ -94,9 +108,10 @@ static AnnotationElement ofString(String name, } /** - * {@return an annotation key-value pair for a long-valued annotation} + * {@return an element-value pair for a long-valued element} * @param name the name of the key * @param value the associated value + * @see AnnotationValue#ofLong(long) AnnotationValue::ofLong */ static AnnotationElement ofLong(String name, long value) { @@ -104,9 +119,10 @@ static AnnotationElement ofLong(String name, } /** - * {@return an annotation key-value pair for an int-valued annotation} + * {@return an element-value pair for an int-valued element} * @param name the name of the key * @param value the associated value + * @see AnnotationValue#ofInt(int) AnnotationValue::ofInt */ static AnnotationElement ofInt(String name, int value) { @@ -114,9 +130,10 @@ static AnnotationElement ofInt(String name, } /** - * {@return an annotation key-value pair for a char-valued annotation} + * {@return an element-value pair for a char-valued element} * @param name the name of the key * @param value the associated value + * @see AnnotationValue#ofChar(char) AnnotationValue::ofChar */ static AnnotationElement ofChar(String name, char value) { @@ -124,9 +141,10 @@ static AnnotationElement ofChar(String name, } /** - * {@return an annotation key-value pair for a short-valued annotation} + * {@return an element-value pair for a short-valued element} * @param name the name of the key * @param value the associated value + * @see AnnotationValue#ofShort(short) AnnotationValue::ofShort */ static AnnotationElement ofShort(String name, short value) { @@ -134,29 +152,32 @@ static AnnotationElement ofShort(String name, } /** - * {@return an annotation key-value pair for a byte-valued annotation} + * {@return an element-value pair for a byte-valued element} * @param name the name of the key * @param value the associated value + * @see AnnotationValue#ofByte(byte) AnnotationValue::ofByte */ static AnnotationElement ofByte(String name, - byte value) { + byte value) { return of(name, AnnotationValue.ofByte(value)); } /** - * {@return an annotation key-value pair for a boolean-valued annotation} + * {@return an element-value pair for a boolean-valued element} * @param name the name of the key * @param value the associated value + * @see AnnotationValue#ofBoolean(boolean) AnnotationValue::ofBoolean */ static AnnotationElement ofBoolean(String name, - boolean value) { + boolean value) { return of(name, AnnotationValue.ofBoolean(value)); } /** - * {@return an annotation key-value pair for a double-valued annotation} + * {@return an element-value pair for a double-valued element} * @param name the name of the key * @param value the associated value + * @see AnnotationValue#ofDouble(double) AnnotationValue::ofDouble */ static AnnotationElement ofDouble(String name, double value) { @@ -164,9 +185,10 @@ static AnnotationElement ofDouble(String name, } /** - * {@return an annotation key-value pair for a float-valued annotation} + * {@return an element-value pair for a float-valued element} * @param name the name of the key * @param value the associated value + * @see AnnotationValue#ofFloat(float) AnnotationValue::ofFloat */ static AnnotationElement ofFloat(String name, float value) { @@ -174,9 +196,10 @@ static AnnotationElement ofFloat(String name, } /** - * {@return an annotation key-value pair for an annotation-valued annotation} + * {@return an element-value pair for an annotation-valued element} * @param name the name of the key * @param value the associated value + * @see AnnotationValue#ofAnnotation AnnotationValue::ofAnnotation */ static AnnotationElement ofAnnotation(String name, Annotation value) { @@ -184,9 +207,10 @@ static AnnotationElement ofAnnotation(String name, } /** - * {@return an annotation key-value pair for an array-valued annotation} + * {@return an element-value pair for an array-valued element} * @param name the name of the key * @param values the associated values + * @see AnnotationValue#ofArray(AnnotationValue...) AnnotationValue::ofArray */ static AnnotationElement ofArray(String name, AnnotationValue... values) { diff --git a/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java b/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java index 04bbcffb8bc..4decff86ad7 100644 --- a/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java +++ b/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java @@ -41,7 +41,11 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the value of a key-value pair of an annotation. + * Models an {@code element_value} structure, or a value of an element-value + * pair of an annotation, as defined in JVMS {@jvms 4.7.16.1}. + *

+ * Two {@code AnnotationValue} objects should be compared using the {@link + * Object#equals(Object) equals} method. * * @see Annotation * @see AnnotationElement @@ -53,8 +57,8 @@ public sealed interface AnnotationValue { /** - * Models an annotation-valued element. - * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_ANNOTATION}. + * Models an annotation value of an element-value pair. + * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_ANNOTATION}. * * @since 22 */ @@ -66,8 +70,8 @@ sealed interface OfAnnotation extends AnnotationValue } /** - * Models an array-valued element. - * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_ARRAY}. + * Models an array value of an element-value pair. + * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_ARRAY}. * * @since 22 */ @@ -79,13 +83,15 @@ sealed interface OfArray extends AnnotationValue * * @apiNote * All array elements derived from Java source code have the same type, - * which must not be an array type. ({@jls 9.6.1}) + * which must not be an array type. (JLS {@jls 9.6.1}) If such elements are + * annotations, they have the same annotation interface; if such elements + * are enum, they belong to the same enum class. */ List values(); } /** - * Models a constant-valued element. + * Models a constant value of an element-value pair. * * @sealedGraph * @since 22 @@ -123,8 +129,8 @@ sealed interface OfConstant } /** - * Models a string-valued element. - * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_STRING}. + * Models a string value of an element-value pair. + * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_STRING}. * * @since 22 */ @@ -151,8 +157,8 @@ default String resolvedValue() { } /** - * Models a double-valued element. - * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_DOUBLE}. + * Models a double value of an element-value pair. + * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_DOUBLE}. * * @since 22 */ @@ -179,8 +185,8 @@ default Double resolvedValue() { } /** - * Models a float-valued element. - * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_FLOAT}. + * Models a float value of an element-value pair. + * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_FLOAT}. * * @since 22 */ @@ -207,8 +213,8 @@ default Float resolvedValue() { } /** - * Models a long-valued element. - * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_LONG}. + * Models a long value of an element-value pair. + * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_LONG}. * * @since 22 */ @@ -235,8 +241,8 @@ default Long resolvedValue() { } /** - * Models an int-valued element. - * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_INT}. + * Models an int value of an element-value pair. + * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_INT}. * * @since 22 */ @@ -263,8 +269,8 @@ default Integer resolvedValue() { } /** - * Models a short-valued element. - * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_SHORT}. + * Models a short value of an element-value pair. + * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_SHORT}. * * @since 22 */ @@ -294,8 +300,8 @@ default Short resolvedValue() { } /** - * Models a char-valued element. - * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_CHAR}. + * Models a char value of an element-value pair. + * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_CHAR}. * * @since 22 */ @@ -325,8 +331,8 @@ default Character resolvedValue() { } /** - * Models a byte-valued element. - * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_BYTE}. + * Models a byte value of an element-value pair. + * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_BYTE}. * * @since 22 */ @@ -356,8 +362,8 @@ default Byte resolvedValue() { } /** - * Models a boolean-valued element. - * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_BOOLEAN}. + * Models a boolean value of an element-value pair. + * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_BOOLEAN}. * * @since 22 */ @@ -387,8 +393,8 @@ default Boolean resolvedValue() { } /** - * Models a class-valued element. - * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_CLASS}. + * Models a class value of an element-value pair. + * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_CLASS}. * * @since 22 */ @@ -405,8 +411,8 @@ default ClassDesc classSymbol() { } /** - * Models an enum-valued element. - * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_ENUM}. + * Models an enum value of an element-value pair. + * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_ENUM}. * * @since 22 */ @@ -426,12 +432,13 @@ default ClassDesc classSymbol() { } /** - * {@return the tag character for this type as per JVMS {@jvms 4.7.16.1}} + * {@return the tag character for this value as per JVMS {@jvms 4.7.16.1}} + * The tag characters have a one-to-one mapping to the types of annotation element values. */ char tag(); /** - * {@return an annotation element for a enum-valued element} + * {@return an enum value for an element-value pair} * @param className the descriptor string of the enum class * @param constantName the name of the enum constant */ @@ -441,7 +448,7 @@ static OfEnum ofEnum(Utf8Entry className, } /** - * {@return an annotation element for a enum-valued element} + * {@return an enum value for an element-value pair} * @param className the descriptor of the enum class * @param constantName the name of the enum constant */ @@ -451,7 +458,7 @@ static OfEnum ofEnum(ClassDesc className, String constantName) { } /** - * {@return an annotation element for a class-valued element} + * {@return a class value for an element-value pair} * @param className the descriptor string of the class */ static OfClass ofClass(Utf8Entry className) { @@ -459,7 +466,7 @@ static OfClass ofClass(Utf8Entry className) { } /** - * {@return an annotation element for a class-valued element} + * {@return a class value for an element-value pair} * @param className the descriptor of the class */ static OfClass ofClass(ClassDesc className) { @@ -467,7 +474,7 @@ static OfClass ofClass(ClassDesc className) { } /** - * {@return an annotation element for a string-valued element} + * {@return a string value for an element-value pair} * @param value the string */ static OfString ofString(Utf8Entry value) { @@ -475,7 +482,7 @@ static OfString ofString(Utf8Entry value) { } /** - * {@return an annotation element for a string-valued element} + * {@return a string value for an element-value pair} * @param value the string */ static OfString ofString(String value) { @@ -483,7 +490,7 @@ static OfString ofString(String value) { } /** - * {@return an annotation element for a double-valued element} + * {@return a double value for an element-value pair} * @param value the double value */ static OfDouble ofDouble(DoubleEntry value) { @@ -491,7 +498,7 @@ static OfDouble ofDouble(DoubleEntry value) { } /** - * {@return an annotation element for a double-valued element} + * {@return a double value for an element-value pair} * @param value the double value */ static OfDouble ofDouble(double value) { @@ -499,7 +506,7 @@ static OfDouble ofDouble(double value) { } /** - * {@return an annotation element for a float-valued element} + * {@return a float value for an element-value pair} * @param value the float value */ static OfFloat ofFloat(FloatEntry value) { @@ -507,7 +514,7 @@ static OfFloat ofFloat(FloatEntry value) { } /** - * {@return an annotation element for a float-valued element} + * {@return a float value for an element-value pair} * @param value the float value */ static OfFloat ofFloat(float value) { @@ -515,7 +522,7 @@ static OfFloat ofFloat(float value) { } /** - * {@return an annotation element for a long-valued element} + * {@return a long value for an element-value pair} * @param value the long value */ static OfLong ofLong(LongEntry value) { @@ -523,7 +530,7 @@ static OfLong ofLong(LongEntry value) { } /** - * {@return an annotation element for a long-valued element} + * {@return a long value for an element-value pair} * @param value the long value */ static OfLong ofLong(long value) { @@ -531,7 +538,7 @@ static OfLong ofLong(long value) { } /** - * {@return an annotation element for an int-valued element} + * {@return an int value for an element-value pair} * @param value the int value */ static OfInt ofInt(IntegerEntry value) { @@ -539,7 +546,7 @@ static OfInt ofInt(IntegerEntry value) { } /** - * {@return an annotation element for an int-valued element} + * {@return an int value for an element-value pair} * @param value the int value */ static OfInt ofInt(int value) { @@ -547,7 +554,7 @@ static OfInt ofInt(int value) { } /** - * {@return an annotation element for a short-valued element} + * {@return a short value for an element-value pair} * @param value the short value */ static OfShort ofShort(IntegerEntry value) { @@ -555,7 +562,7 @@ static OfShort ofShort(IntegerEntry value) { } /** - * {@return an annotation element for a short-valued element} + * {@return a short value for an element-value pair} * @param value the short value */ static OfShort ofShort(short value) { @@ -563,7 +570,7 @@ static OfShort ofShort(short value) { } /** - * {@return an annotation element for a char-valued element} + * {@return a char value for an element-value pair} * @param value the char value */ static OfChar ofChar(IntegerEntry value) { @@ -571,7 +578,7 @@ static OfChar ofChar(IntegerEntry value) { } /** - * {@return an annotation element for a char-valued element} + * {@return a char value for an element-value pair} * @param value the char value */ static OfChar ofChar(char value) { @@ -579,7 +586,7 @@ static OfChar ofChar(char value) { } /** - * {@return an annotation element for a byte-valued element} + * {@return a byte value for an element-value pair} * @param value the byte value */ static OfByte ofByte(IntegerEntry value) { @@ -587,7 +594,7 @@ static OfByte ofByte(IntegerEntry value) { } /** - * {@return an annotation element for a byte-valued element} + * {@return a byte value for an element-value pair} * @param value the byte value */ static OfByte ofByte(byte value) { @@ -595,7 +602,7 @@ static OfByte ofByte(byte value) { } /** - * {@return an annotation element for a boolean-valued element} + * {@return a boolean value for an element-value pair} * @param value the boolean value */ static OfBoolean ofBoolean(IntegerEntry value) { @@ -603,7 +610,7 @@ static OfBoolean ofBoolean(IntegerEntry value) { } /** - * {@return an annotation element for a boolean-valued element} + * {@return a boolean value for an element-value pair} * @param value the boolean value */ static OfBoolean ofBoolean(boolean value) { @@ -612,7 +619,7 @@ static OfBoolean ofBoolean(boolean value) { } /** - * {@return an annotation element for an annotation-valued element} + * {@return an annotation value for an element-value pair} * @param value the annotation */ static OfAnnotation ofAnnotation(Annotation value) { @@ -620,7 +627,12 @@ static OfAnnotation ofAnnotation(Annotation value) { } /** - * {@return an annotation element for an array-valued element} + * {@return an array value for an element-value pair} + * + * @apiNote + * See {@link AnnotationValue.OfArray#values() values()} for conventions + * on array values derived from Java source code. + * * @param values the array elements */ static OfArray ofArray(List values) { @@ -628,7 +640,12 @@ static OfArray ofArray(List values) { } /** - * {@return an annotation element for an array-valued element} + * {@return an array value for an element-value pair} + * + * @apiNote + * See {@link AnnotationValue.OfArray#values() values()} for conventions + * on array values derived from Java source code. + * * @param values the array elements */ static OfArray ofArray(AnnotationValue... values) { diff --git a/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java b/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java index 01a2f5fc696..b6c9aec76a1 100644 --- a/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java +++ b/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java @@ -25,12 +25,10 @@ package java.lang.classfile; -import java.lang.constant.ClassDesc; import java.util.List; import java.lang.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute; import java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute; -import java.lang.classfile.constantpool.Utf8Entry; import jdk.internal.classfile.impl.TargetInfoImpl; import jdk.internal.classfile.impl.UnboundAttribute; @@ -56,12 +54,22 @@ import static java.lang.classfile.ClassFile.TAT_NEW; import static java.lang.classfile.ClassFile.TAT_RESOURCE_VARIABLE; import static java.lang.classfile.ClassFile.TAT_THROWS; -import jdk.internal.classfile.impl.TemporaryConstantPool; import jdk.internal.javac.PreviewFeature; /** - * Models an annotation on a type use, as defined in JVMS {@jvms 4.7.19} and {@jvms 4.7.20}. + * Models a {@code type_annotation} structure (JVMS {@jvms 4.7.20}). This model + * indicates the annotated type within a declaration or expression and the part + * of the indicated type that is annotated, in addition to what is {@linkplain + * #annotation() available} in an {@code Annotation}. + *

+ * This model can reconstruct an annotation on a type or a part of a type, given + * the location of the {@code type_annotation} structure in the class file and + * the definition of the annotation interface. + *

+ * Two {@code TypeAnnotation} objects should be compared using the {@link + * Object#equals(Object) equals} method. * + * @see Annotation * @see RuntimeVisibleTypeAnnotationsAttribute * @see RuntimeInvisibleTypeAnnotationsAttribute * @@ -69,7 +77,6 @@ */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) public sealed interface TypeAnnotation - extends Annotation permits UnboundAttribute.UnboundTypeAnnotation { /** @@ -170,7 +177,7 @@ public int sizeIfFixed() { /** * {@return information describing precisely which type in a declaration or expression - * is annotated} + * is annotated} This models the {@code target_type} and {@code target_info} items. */ TargetInfo targetInfo(); @@ -180,57 +187,22 @@ public int sizeIfFixed() { List targetPath(); /** - * {@return a type annotation} - * @param targetInfo which type in a declaration or expression is annotated - * @param targetPath which part of the type is annotated - * @param annotationClassUtf8Entry the annotation class - * @param annotationElements the annotation elements - */ - static TypeAnnotation of(TargetInfo targetInfo, List targetPath, - Utf8Entry annotationClassUtf8Entry, - List annotationElements) { - return new UnboundAttribute.UnboundTypeAnnotation(targetInfo, targetPath, - annotationClassUtf8Entry, annotationElements); - } - - /** - * {@return a type annotation} - * @param targetInfo which type in a declaration or expression is annotated - * @param targetPath which part of the type is annotated - * @param annotationClass the annotation class - * @param annotationElements the annotation elements + * {@return the annotation applied to the part indicated by {@link #targetPath()}} + * This models the interface of the annotation and the set of element-value pairs, + * the subset of the {@code type_annotation} structure that is identical to the + * {@code annotation} structure. */ - static TypeAnnotation of(TargetInfo targetInfo, List targetPath, - ClassDesc annotationClass, - AnnotationElement... annotationElements) { - return of(targetInfo, targetPath, annotationClass, List.of(annotationElements)); - } - - /** - * {@return a type annotation} - * @param targetInfo which type in a declaration or expression is annotated - * @param targetPath which part of the type is annotated - * @param annotationClass the annotation class - * @param annotationElements the annotation elements - */ - static TypeAnnotation of(TargetInfo targetInfo, List targetPath, - ClassDesc annotationClass, - List annotationElements) { - return of(targetInfo, targetPath, - TemporaryConstantPool.INSTANCE.utf8Entry(annotationClass.descriptorString()), annotationElements); - } + Annotation annotation(); /** - * {@return a type annotation} + * {@return a {@code type_annotation} structure} * @param targetInfo which type in a declaration or expression is annotated * @param targetPath which part of the type is annotated - * @param annotationClassUtf8Entry the annotation class - * @param annotationElements the annotation elements + * @param annotation the annotation */ static TypeAnnotation of(TargetInfo targetInfo, List targetPath, - Utf8Entry annotationClassUtf8Entry, - AnnotationElement... annotationElements) { - return of(targetInfo, targetPath, annotationClassUtf8Entry, List.of(annotationElements)); + Annotation annotation) { + return new UnboundAttribute.UnboundTypeAnnotation(targetInfo, targetPath, annotation); } /** diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java index 0029b503d7a..8be167cd119 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java @@ -657,7 +657,7 @@ public RuntimeInvisibleTypeAnnotationsAttribute readAttribute(AttributedElement @Override protected void writeBody(BufWriter buf, RuntimeInvisibleTypeAnnotationsAttribute attr) { - AnnotationReader.writeAnnotations(buf, attr.annotations()); + AnnotationReader.writeTypeAnnotations(buf, attr.annotations()); } } @@ -714,7 +714,7 @@ public RuntimeVisibleTypeAnnotationsAttribute readAttribute(AttributedElement e, @Override protected void writeBody(BufWriter buf, RuntimeVisibleTypeAnnotationsAttribute attr) { - AnnotationReader.writeAnnotations(buf, attr.annotations()); + AnnotationReader.writeTypeAnnotations(buf, attr.annotations()); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java index e21938bbc0c..6802d6e75aa 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java @@ -241,10 +241,8 @@ private static TypeAnnotation readTypeAnnotation(ClassReader classReader, int p, }; } // the annotation info for this annotation - Utf8Entry type = classReader.readEntry(p, Utf8Entry.class); - p += 2; - return TypeAnnotation.of(targetInfo, List.of(typePath), type, - readAnnotationElementValuePairs(classReader, p)); + var anno = readAnnotation(classReader, p); + return TypeAnnotation.of(targetInfo, List.of(typePath), anno); } private static List readLocalVarEntries(ClassReader classReader, int p, LabelContext lc, int targetType) { @@ -283,13 +281,11 @@ private static int skipTypeAnnotation(ClassReader classReader, int p) { } public static void writeAnnotation(BufWriterImpl buf, Annotation annotation) { - // handles annotations and type annotations // TODO annotation cleanup later ((Util.Writable) annotation).writeTo(buf); } - public static void writeAnnotations(BufWriter buf, List list) { - // handles annotations and type annotations + public static void writeAnnotations(BufWriter buf, List list) { var internalBuf = (BufWriterImpl) buf; internalBuf.writeU2(list.size()); for (var e : list) { @@ -297,6 +293,66 @@ public static void writeAnnotations(BufWriter buf, List li } } + private static int labelToBci(LabelContext lr, Label label, TypeAnnotation ta) { + //helper method to avoid NPE + if (lr == null) throw new IllegalArgumentException("Illegal targetType '%s' in TypeAnnotation outside of Code attribute".formatted(ta.targetInfo().targetType())); + return lr.labelToBci(label); + } + + public static void writeTypeAnnotation(BufWriterImpl buf, TypeAnnotation ta) { + LabelContext lr = buf.labelContext(); + // target_type + buf.writeU1(ta.targetInfo().targetType().targetTypeValue()); + + // target_info + switch (ta.targetInfo()) { + case TypeAnnotation.TypeParameterTarget tpt -> buf.writeU1(tpt.typeParameterIndex()); + case TypeAnnotation.SupertypeTarget st -> buf.writeU2(st.supertypeIndex()); + case TypeAnnotation.TypeParameterBoundTarget tpbt -> { + buf.writeU1(tpbt.typeParameterIndex()); + buf.writeU1(tpbt.boundIndex()); + } + case TypeAnnotation.EmptyTarget _ -> { + // nothing to write + } + case TypeAnnotation.FormalParameterTarget fpt -> buf.writeU1(fpt.formalParameterIndex()); + case TypeAnnotation.ThrowsTarget tt -> buf.writeU2(tt.throwsTargetIndex()); + case TypeAnnotation.LocalVarTarget lvt -> { + buf.writeU2(lvt.table().size()); + for (var e : lvt.table()) { + int startPc = labelToBci(lr, e.startLabel(), ta); + buf.writeU2(startPc); + buf.writeU2(labelToBci(lr, e.endLabel(), ta) - startPc); + buf.writeU2(e.index()); + } + } + case TypeAnnotation.CatchTarget ct -> buf.writeU2(ct.exceptionTableIndex()); + case TypeAnnotation.OffsetTarget ot -> buf.writeU2(labelToBci(lr, ot.target(), ta)); + case TypeAnnotation.TypeArgumentTarget tat -> { + buf.writeU2(labelToBci(lr, tat.target(), ta)); + buf.writeU1(tat.typeArgumentIndex()); + } + } + + // target_path + buf.writeU1(ta.targetPath().size()); + for (TypeAnnotation.TypePathComponent component : ta.targetPath()) { + buf.writeU1(component.typePathKind().tag()); + buf.writeU1(component.typeArgumentIndex()); + } + + // annotation data + writeAnnotation(buf, ta.annotation()); + } + + public static void writeTypeAnnotations(BufWriter buf, List list) { + var internalBuf = (BufWriterImpl) buf; + internalBuf.writeU2(list.size()); + for (var e : list) { + writeTypeAnnotation(internalBuf, e); + } + } + public static void writeAnnotationValue(BufWriterImpl buf, AnnotationValue value) { // TODO annotation cleanup later ((Util.Writable) value).writeTo(buf); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java index 75346dd5998..2a648e27568 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java @@ -1038,9 +1038,9 @@ private static Node annotationsToTree(String name, List annos) { private static Node typeAnnotationsToTree(Style style, String name, List annos) { return new ListNodeImpl(style, name, annos.stream().map(a -> new MapNodeImpl(FLOW, "anno") - .with(leaf("annotation class", a.className().stringValue()), + .with(leaf("annotation class", a.annotation().className().stringValue()), leaf("target info", a.targetInfo().targetType().name())) - .with(elementValuePairsToTree(a.elements())))); + .with(elementValuePairsToTree(a.annotation().elements())))); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java index e3f701b2e2a..9b5e7639fa2 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java @@ -401,9 +401,7 @@ AnnotationValue mapAnnotationValue(AnnotationValue val) { List mapTypeAnnotations(List typeAnnotations) { return typeAnnotations.stream().map(a -> TypeAnnotation.of(a.targetInfo(), - a.targetPath(), map(a.classSymbol()), - a.elements().stream().map(el -> AnnotationElement.of(el.name(), - mapAnnotationValue(el.value()))).toList())).toList(); + a.targetPath(), mapAnnotation(a.annotation()))).toList(); } List mapTypeParams(List typeParams) { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java index 6b64511fd5a..5ee3759bba3 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java @@ -29,14 +29,12 @@ import java.util.Optional; import java.lang.classfile.Annotation; -import java.lang.classfile.AnnotationElement; import java.lang.classfile.AnnotationValue; import java.lang.classfile.Attribute; import java.lang.classfile.AttributeMapper; import java.lang.classfile.Attributes; import java.lang.classfile.BootstrapMethodEntry; import java.lang.classfile.constantpool.ClassEntry; -import java.lang.classfile.Label; import java.lang.classfile.TypeAnnotation; import java.lang.classfile.attribute.AnnotationDefaultAttribute; import java.lang.classfile.attribute.BootstrapMethodsAttribute; @@ -758,75 +756,10 @@ public UnboundRecordComponentInfo(Utf8Entry name, Utf8Entry descriptor, List targetPath, - Utf8Entry className, - List elements) implements TypeAnnotation, Util.Writable { - - public UnboundTypeAnnotation(TargetInfo targetInfo, List targetPath, - Utf8Entry className, List elements) { - this.targetInfo = targetInfo; - this.targetPath = List.copyOf(targetPath); - this.className = className; - this.elements = List.copyOf(elements); - } - - private int labelToBci(LabelContext lr, Label label) { - //helper method to avoid NPE - if (lr == null) throw new IllegalArgumentException("Illegal targetType '%s' in TypeAnnotation outside of Code attribute".formatted(targetInfo.targetType())); - return lr.labelToBci(label); - } - - @Override - public void writeTo(BufWriterImpl buf) { - LabelContext lr = buf.labelContext(); - // target_type - buf.writeU1(targetInfo.targetType().targetTypeValue()); - - // target_info - switch (targetInfo) { - case TypeParameterTarget tpt -> buf.writeU1(tpt.typeParameterIndex()); - case SupertypeTarget st -> buf.writeU2(st.supertypeIndex()); - case TypeParameterBoundTarget tpbt -> { - buf.writeU1(tpbt.typeParameterIndex()); - buf.writeU1(tpbt.boundIndex()); - } - case EmptyTarget et -> { - // nothing to write - } - case FormalParameterTarget fpt -> buf.writeU1(fpt.formalParameterIndex()); - case ThrowsTarget tt -> buf.writeU2(tt.throwsTargetIndex()); - case LocalVarTarget lvt -> { - buf.writeU2(lvt.table().size()); - for (var e : lvt.table()) { - int startPc = labelToBci(lr, e.startLabel()); - buf.writeU2(startPc); - buf.writeU2(labelToBci(lr, e.endLabel()) - startPc); - buf.writeU2(e.index()); - } - } - case CatchTarget ct -> buf.writeU2(ct.exceptionTableIndex()); - case OffsetTarget ot -> buf.writeU2(labelToBci(lr, ot.target())); - case TypeArgumentTarget tat -> { - buf.writeU2(labelToBci(lr, tat.target())); - buf.writeU1(tat.typeArgumentIndex()); - } - } + Annotation annotation) implements TypeAnnotation { - // target_path - buf.writeU1(targetPath().size()); - for (TypePathComponent component : targetPath()) { - buf.writeU1(component.typePathKind().tag()); - buf.writeU1(component.typeArgumentIndex()); - } - - // type_index - buf.writeIndex(className); - - // element_value_pairs - buf.writeU2(elements.size()); - for (AnnotationElement pair : elements()) { - buf.writeIndex(pair.name()); - AnnotationReader.writeAnnotationValue(buf, pair.value()); - } + public UnboundTypeAnnotation { + targetPath = List.copyOf(targetPath); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/ParserVerifier.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/ParserVerifier.java index 4a2ffd3f25d..77f56b322dd 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/ParserVerifier.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/ParserVerifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -393,7 +393,7 @@ private static int annotationsSize(List ans) { private static int typeAnnotationsSize(List ans) { int l = 2; for (var an : ans) { - l += 2 + an.targetInfo().size() + 2 * an.targetPath().size() + annotationSize(an); + l += 2 + an.targetInfo().size() + 2 * an.targetPath().size() + annotationSize(an.annotation()); } return l; } diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/AnnotationWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/AnnotationWriter.java index ae5cd2df024..66b978f252c 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/AnnotationWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/AnnotationWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -95,13 +95,13 @@ public void write(TypeAnnotation annot, CodeAttribute lr) { write(annot, true, false, lr); println(); indent(+1); - write(annot, true); + write(annot.annotation(), true); indent(-1); } public void write(TypeAnnotation annot, boolean showOffsets, boolean resolveIndices, CodeAttribute lr) { - write(annot, resolveIndices); + write(annot.annotation(), resolveIndices); print(": "); write(annot.targetInfo(), annot.targetPath(), showOffsets, lr); } diff --git a/test/jdk/jdk/classfile/ClassPrinterTest.java b/test/jdk/jdk/classfile/ClassPrinterTest.java index 7668648f829..bd95075a08e 100644 --- a/test/jdk/jdk/classfile/ClassPrinterTest.java +++ b/test/jdk/jdk/classfile/ClassPrinterTest.java @@ -66,7 +66,7 @@ ClassModel getClassModel() { RuntimeInvisibleTypeAnnotationsAttribute.of( TypeAnnotation.of(TypeAnnotation.TargetInfo.ofField(), List.of(TypeAnnotation.TypePathComponent.WILDCARD), - ClassDesc.of("Boo"), List.of())))))) + Annotation.of(ClassDesc.of("Boo"), List.of()))))))) .with(RuntimeInvisibleAnnotationsAttribute.of(Annotation.of(ClassDesc.of("Phoo"), AnnotationElement.ofFloat("flfl", 2), AnnotationElement.ofFloat("frfl", 3)))) .with(PermittedSubclassesAttribute.ofSymbols(ClassDesc.of("Boo"), ClassDesc.of("Phoo"))) .withField("f", ConstantDescs.CD_String, fb -> fb @@ -101,7 +101,7 @@ ClassModel getClassModel() { tryb.with(RuntimeInvisibleTypeAnnotationsAttribute.of( TypeAnnotation.of(TypeAnnotation.TargetInfo.ofField(), List.of(TypeAnnotation.TypePathComponent.WILDCARD), - ClassDesc.of("Boo"), List.of()))); + Annotation.of(ClassDesc.of("Boo"), List.of())))); tryb.invokedynamic(DynamicCallSiteDesc.of( MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.STATIC, ClassDesc.of("Phoo"), "phee", MethodTypeDesc.of(ClassDesc.of("Boo"))), "intfMethod", @@ -116,7 +116,7 @@ ClassModel getClassModel() { .with(RuntimeVisibleTypeAnnotationsAttribute.of( TypeAnnotation.of(TypeAnnotation.TargetInfo.ofField(), List.of(TypeAnnotation.TypePathComponent.ARRAY), - ClassDesc.of("Fee"), List.of(AnnotationElement.ofBoolean("yes", false))))) + Annotation.of(ClassDesc.of("Fee"), List.of(AnnotationElement.ofBoolean("yes", false)))))) )))); } diff --git a/test/jdk/jdk/classfile/TransformTests.java b/test/jdk/jdk/classfile/TransformTests.java index fb9f72ba3aa..b78da8b4311 100644 --- a/test/jdk/jdk/classfile/TransformTests.java +++ b/test/jdk/jdk/classfile/TransformTests.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8336010 8336588 + * @bug 8335935 8336588 * @summary Testing ClassFile transformations. * @run junit TransformTests */ diff --git a/test/jdk/jdk/classfile/helpers/ClassRecord.java b/test/jdk/jdk/classfile/helpers/ClassRecord.java index a62ef172367..ce22037ccda 100644 --- a/test/jdk/jdk/classfile/helpers/ClassRecord.java +++ b/test/jdk/jdk/classfile/helpers/ClassRecord.java @@ -828,7 +828,7 @@ public static TypeAnnotationRecord ofTypeAnnotation(TypeAnnotation ann, CodeAttr ann.targetInfo().targetType().targetTypeValue(), TargetInfoRecord.ofTargetInfo(ann.targetInfo(), lr, code), ann.targetPath().stream().map(tpc -> TypePathRecord.ofTypePathComponent(tpc)).collect(toSet()), - AnnotationRecord.ofAnnotation(ann)); + AnnotationRecord.ofAnnotation(ann.annotation())); } public interface TargetInfoRecord { diff --git a/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java b/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java index 7667403aaab..b769898d785 100644 --- a/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java +++ b/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java @@ -179,8 +179,7 @@ static TypeAnnotation[] transformTypeAnnotations(List annotation return annotations.stream().map(ta -> TypeAnnotation.of( transformTargetInfo(ta.targetInfo(), cob, labels), ta.targetPath().stream().map(tpc -> TypeAnnotation.TypePathComponent.of(tpc.typePathKind(), tpc.typeArgumentIndex())).toList(), - ta.classSymbol(), - ta.elements().stream().map(ae -> AnnotationElement.of(ae.name().stringValue(), transformAnnotationValue(ae.value()))).toList())).toArray(TypeAnnotation[]::new); + transformAnnotation(ta.annotation()))).toArray(TypeAnnotation[]::new); } static TypeAnnotation.TargetInfo transformTargetInfo(TypeAnnotation.TargetInfo ti, CodeBuilder cob, HashMap labels) { diff --git a/test/langtools/lib/annotations/annotations/classfile/ClassfileInspector.java b/test/langtools/lib/annotations/annotations/classfile/ClassfileInspector.java index d6219dbff11..30a5f54ac26 100644 --- a/test/langtools/lib/annotations/annotations/classfile/ClassfileInspector.java +++ b/test/langtools/lib/annotations/annotations/classfile/ClassfileInspector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -603,7 +603,7 @@ public void matchAnnotation(TypeAnnotation anno) { } public boolean checkMatch(TypeAnnotation anno) { - boolean matches = checkMatch((Annotation) anno); + boolean matches = checkMatch(anno.annotation()); int boundIdx = Integer.MIN_VALUE, paraIdx = Integer.MIN_VALUE, tIdx = Integer.MIN_VALUE, exIdx = Integer.MIN_VALUE; switch (anno.targetInfo()) { case TypeAnnotation.TypeParameterBoundTarget binfo -> { @@ -1197,8 +1197,8 @@ public void annoMatcher(Attribute attr, ExpectedAnnotation expected) { switch (attr) { case RuntimeVisibleTypeAnnotationsAttribute rvattr -> { if (expected.matchVisibility(true)) { - for(Annotation anno : rvattr.annotations()) { - expected.matchAnnotation(anno); + for(var anno : rvattr.annotations()) { + expected.matchAnnotation(anno.annotation()); } } } diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousClassTest.java b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousClassTest.java index 94610ddf055..eb4b5aa2cf7 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousClassTest.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousClassTest.java @@ -215,7 +215,7 @@ private static String annotationDebugString(ClassModel cm, CodeAttribute cAttr, int offset = info instanceof TypeAnnotation.OffsetTarget offsetInfo? cAttr.labelToBci(offsetInfo.target()): -1; String name; try { - name = annotation.classSymbol().descriptorString(); + name = annotation.annotation().classSymbol().descriptorString(); } catch (Exception e) { throw new AssertionError(e); } @@ -227,7 +227,7 @@ private static String annotationDebugString(ClassModel cm, CodeAttribute cAttr, return String.format( "@%s(%s) %s, offset=%d, location=%s", name, - annotationValueDebugString(cm, annotation), + annotationValueDebugString(cm, annotation.annotation()), info.targetType(), offset, location); diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/referenceinfos/ReferenceInfoUtil.java b/test/langtools/tools/javac/annotations/typeAnnotations/referenceinfos/ReferenceInfoUtil.java index e2e69a01a49..18e3a3dec56 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/referenceinfos/ReferenceInfoUtil.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/referenceinfos/ReferenceInfoUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -97,7 +97,7 @@ private static List generateTADList(List annos, CodeAttribu List result = new ArrayList<>(); for (TypeAnnotation anno: annos) { TAD tad = new TAD(); - tad.annotation = anno.className().stringValue(); + tad.annotation = anno.annotation().className().stringValue(); tad.type = anno.targetInfo().targetType(); switch (anno.targetInfo().targetType()) { case CAST, CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT, METHOD_INVOCATION_TYPE_ARGUMENT -> { diff --git a/test/langtools/tools/javac/patterns/Annotations.java b/test/langtools/tools/javac/patterns/Annotations.java index a471cc57b63..a8106a39827 100644 --- a/test/langtools/tools/javac/patterns/Annotations.java +++ b/test/langtools/tools/javac/patterns/Annotations.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,7 +74,7 @@ void run() throws Exception { StringBuilder actual = new StringBuilder(); for (TypeAnnotation ta: annotations.annotations()) { TypeAnnotation.LocalVarTargetInfo info = ((TypeAnnotation.LocalVarTarget) ta.targetInfo()).table().getFirst(); - actual.append(ta.className().stringValue() + " pos: [" + ta.targetInfo().targetType()); + actual.append(ta.annotation().className().stringValue() + " pos: [" + ta.targetInfo().targetType()); actual.append(", {start_pc=" + codeAttr.labelToBci(info.startLabel()) + ", end_pc=" + codeAttr.labelToBci(info.endLabel())); actual.append(", index=" + info.index()+ "}], "); } diff --git a/test/langtools/tools/javac/records/RecordCompilationTests.java b/test/langtools/tools/javac/records/RecordCompilationTests.java index d80ade50a3b..a01712fedb3 100644 --- a/test/langtools/tools/javac/records/RecordCompilationTests.java +++ b/test/langtools/tools/javac/records/RecordCompilationTests.java @@ -1615,7 +1615,7 @@ private void checkTypeAnno(Attribute rtAnnos, } assert tAnno != null; Assert.check(tAnno.targetInfo().targetType().name().equals(positionType)); - String annotationName = tAnno.classSymbol().displayName(); + String annotationName = tAnno.annotation().classSymbol().displayName(); Assert.check(annotationName.startsWith(annoName)); } private void checkAnno(Attribute rAnnos, From 8635642dbdfb74d2ae50a51611fd2c5980fe6e74 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Fri, 16 Aug 2024 16:39:36 +0000 Subject: [PATCH 444/460] 8338469: com/sun/jdi/DataDumpTest.java failed with Not a debuggee, or not listening for debugger to attach Reviewed-by: dcubed --- test/jdk/com/sun/jdi/DataDumpTest.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/jdk/com/sun/jdi/DataDumpTest.java b/test/jdk/com/sun/jdi/DataDumpTest.java index f46d0d5de4f..8d7404f58e9 100644 --- a/test/jdk/com/sun/jdi/DataDumpTest.java +++ b/test/jdk/com/sun/jdi/DataDumpTest.java @@ -84,6 +84,11 @@ private static void runTest(String jdwpArg) throws Exception { try { p = pb.start(); InputStream is = p.getInputStream(); + + // Read the first character of output to make sure we've waited until the + // debuggee is ready. This will be the debug agent's "Listening..." message. + char firstChar = (char)is.read(); + out = new OutputAnalyzer(p); // Attach a debugger and do the data dump. The data dump output will appear @@ -92,8 +97,8 @@ private static void runTest(String jdwpArg) throws Exception { out.waitFor(); // Wait for the debuggee to exit - System.out.println("Deuggee output:"); - System.out.println(out.getOutput()); + System.out.println("Debuggee output:"); + System.out.println(firstChar + out.getOutput()); // All these strings are part of the debug agent data dump output. out.shouldHaveExitValue(0); From 2f7ba781bf2e4e6d0fa658c19f86c6c05d60358a Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Mon, 19 Aug 2024 04:44:24 +0000 Subject: [PATCH 445/460] 8335150: Test LogGeneratedClassesTest.java fails on rpmbuild mock enviroment Reviewed-by: jpai --- .../lambda/LogGeneratedClassesTest.java | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/test/jdk/java/lang/invoke/lambda/LogGeneratedClassesTest.java b/test/jdk/java/lang/invoke/lambda/LogGeneratedClassesTest.java index 91ea4b932ca..06aa479717b 100644 --- a/test/jdk/java/lang/invoke/lambda/LogGeneratedClassesTest.java +++ b/test/jdk/java/lang/invoke/lambda/LogGeneratedClassesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.FileStore; import java.nio.file.attribute.PosixFileAttributeView; import jdk.test.lib.compiler.CompilerUtils; @@ -47,6 +48,7 @@ import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import org.testng.SkipException; import static java.nio.file.attribute.PosixFilePermissions.*; import static jdk.test.lib.process.ProcessTools.*; @@ -207,15 +209,15 @@ private static boolean isWriteableDirectory(Path p) { @Test public void testDumpDirNotWritable() throws Exception { - if (!Files.getFileStore(Paths.get(".")) - .supportsFileAttributeView(PosixFileAttributeView.class)) { + FileStore fs; + try { + fs = Files.getFileStore(Paths.get(".")); + } catch (IOException e) { + throw new SkipException("WARNING: IOException occurred: " + e + ", Skipping testDumpDirNotWritable test."); + } + if (!fs.supportsFileAttributeView(PosixFileAttributeView.class)) { // No easy way to setup readonly directory without POSIX - // We would like to skip the test with a cause with - // throw new SkipException("Posix not supported"); - // but jtreg will report failure so we just pass the test - // which we can look at if jtreg changed its behavior - System.out.println("WARNING: POSIX is not supported. Skipping testDumpDirNotWritable test."); - return; + throw new SkipException("WARNING: POSIX is not supported. Skipping testDumpDirNotWritable test."); } Path testDir = Path.of("readOnly"); @@ -227,8 +229,7 @@ public void testDumpDirNotWritable() throws Exception { if (isWriteableDirectory(dumpDir)) { // Skipping the test: it's allowed to write into read-only directory // (e.g. current user is super user). - System.out.println("WARNING: The dump directory is writeable. Skipping testDumpDirNotWritable test."); - return; + throw new SkipException("WARNING: The dump directory is writeable. Skipping testDumpDirNotWritable test."); } ProcessBuilder pb = createLimitedTestJavaProcessBuilder( From 56a007dd32061695d7bb0faf47e1793728e86c88 Mon Sep 17 00:00:00 2001 From: Tejesh R Date: Mon, 19 Aug 2024 06:42:51 +0000 Subject: [PATCH 446/460] 8338488: Add screen capture for failure case Reviewed-by: azvegint --- .../java/awt/Checkbox/CheckboxCheckerScalingTest.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/jdk/java/awt/Checkbox/CheckboxCheckerScalingTest.java b/test/jdk/java/awt/Checkbox/CheckboxCheckerScalingTest.java index 5e531e84801..a07620dbd38 100644 --- a/test/jdk/java/awt/Checkbox/CheckboxCheckerScalingTest.java +++ b/test/jdk/java/awt/Checkbox/CheckboxCheckerScalingTest.java @@ -29,6 +29,10 @@ import java.awt.Rectangle; import java.awt.Robot; import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; /* * @test @@ -78,6 +82,12 @@ public static void main(String[] args) throws Exception { }); if (!checkmarkFound) { + try { + ImageIO.write(imageAfterChecked, "png", + new File("imageAfterChecked.png")); + } catch (IOException e) { + throw new RuntimeException(e); + } throw new RuntimeException("Checkmark not scaled"); } System.out.println("Test Passed"); From 15b20cb1fd18b849e49c175737dd3826c8d0ceff Mon Sep 17 00:00:00 2001 From: Manukumar V S Date: Mon, 19 Aug 2024 07:17:37 +0000 Subject: [PATCH 447/460] 8337886: java/awt/Frame/MaximizeUndecoratedTest.java fails in OEL due to a slight color difference Reviewed-by: dnguyen, honkar, serb --- test/jdk/java/awt/Frame/MaximizeUndecoratedTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/java/awt/Frame/MaximizeUndecoratedTest.java b/test/jdk/java/awt/Frame/MaximizeUndecoratedTest.java index 77046ea3e1f..3e23af76bb6 100644 --- a/test/jdk/java/awt/Frame/MaximizeUndecoratedTest.java +++ b/test/jdk/java/awt/Frame/MaximizeUndecoratedTest.java @@ -50,7 +50,7 @@ public class MaximizeUndecoratedTest { private static final int SIZE = 300; - private static final int OFFSET = 2; + private static final int OFFSET = 5; private static Frame frame; private static Robot robot; From f0374a0bc181d0f2a8c0aa9aa032b07998ffaf60 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Mon, 19 Aug 2024 09:00:19 +0000 Subject: [PATCH 448/460] 8337987: Relocate jfr and throw_exception stubs from StubGenerator to SharedRuntime Reviewed-by: fyang, kvn, yzheng --- .../cpu/aarch64/macroAssembler_aarch64.cpp | 2 +- .../cpu/aarch64/methodHandles_aarch64.cpp | 4 +- .../cpu/aarch64/sharedRuntime_aarch64.cpp | 196 ++++++++++++++ .../cpu/aarch64/stubGenerator_aarch64.cpp | 238 +---------------- .../templateInterpreterGenerator_aarch64.cpp | 4 +- src/hotspot/cpu/arm/methodHandles_arm.cpp | 5 +- src/hotspot/cpu/arm/sharedRuntime_arm.cpp | 140 ++++++++++ src/hotspot/cpu/arm/stubGenerator_arm.cpp | 154 ----------- .../arm/templateInterpreterGenerator_arm.cpp | 2 +- src/hotspot/cpu/ppc/macroAssembler_ppc.cpp | 2 +- src/hotspot/cpu/ppc/methodHandles_ppc.cpp | 6 +- src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp | 173 +++++++++++++ src/hotspot/cpu/ppc/stubGenerator_ppc.cpp | 209 +-------------- .../ppc/templateInterpreterGenerator_ppc.cpp | 4 +- .../cpu/riscv/macroAssembler_riscv.cpp | 2 +- src/hotspot/cpu/riscv/methodHandles_riscv.cpp | 4 +- src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp | 195 ++++++++++++++ src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 239 +---------------- .../templateInterpreterGenerator_riscv.cpp | 4 +- src/hotspot/cpu/s390/macroAssembler_s390.cpp | 2 +- src/hotspot/cpu/s390/methodHandles_s390.cpp | 6 +- src/hotspot/cpu/s390/sharedRuntime_s390.cpp | 94 +++++++ src/hotspot/cpu/s390/stubGenerator_s390.cpp | 122 --------- .../templateInterpreterGenerator_s390.cpp | 6 +- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 2 +- src/hotspot/cpu/x86/methodHandles_x86.cpp | 4 +- src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp | 211 +++++++++++++++ src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp | 193 ++++++++++++++ src/hotspot/cpu/x86/stubGenerator_x86_32.cpp | 239 ----------------- src/hotspot/cpu/x86/stubGenerator_x86_64.cpp | 240 +----------------- src/hotspot/cpu/x86/stubGenerator_x86_64.hpp | 10 - .../x86/templateInterpreterGenerator_x86.cpp | 4 +- src/hotspot/cpu/zero/sharedRuntime_zero.cpp | 21 +- src/hotspot/cpu/zero/stubGenerator_zero.cpp | 16 -- src/hotspot/share/jvmci/jvmciCompilerToVM.hpp | 1 + .../share/jvmci/jvmciCompilerToVMInit.cpp | 2 + src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 4 +- src/hotspot/share/opto/library_call.cpp | 4 +- src/hotspot/share/runtime/init.cpp | 6 + src/hotspot/share/runtime/sharedRuntime.cpp | 68 ++++- src/hotspot/share/runtime/sharedRuntime.hpp | 36 ++- src/hotspot/share/runtime/stubRoutines.cpp | 10 - src/hotspot/share/runtime/stubRoutines.hpp | 53 ++-- 43 files changed, 1392 insertions(+), 1545 deletions(-) diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index ead4220add0..f8b703fb4da 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -744,7 +744,7 @@ void MacroAssembler::reserved_stack_check() { // We have already removed our own frame. // throw_delayed_StackOverflowError will think that it's been // called by our caller. - lea(rscratch1, RuntimeAddress(StubRoutines::throw_delayed_StackOverflowError_entry())); + lea(rscratch1, RuntimeAddress(SharedRuntime::throw_delayed_StackOverflowError_entry())); br(rscratch1); should_not_reach_here(); diff --git a/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp b/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp index ee19079db7d..68800d04d69 100644 --- a/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp @@ -120,7 +120,7 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register meth __ ldr(rscratch1,Address(method, entry_offset)); __ br(rscratch1); __ bind(L_no_such_method); - __ far_jump(RuntimeAddress(StubRoutines::throw_AbstractMethodError_entry())); + __ far_jump(RuntimeAddress(SharedRuntime::throw_AbstractMethodError_entry())); } void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm, @@ -451,7 +451,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, jump_from_method_handle(_masm, rmethod, temp1, for_compiler_entry); if (iid == vmIntrinsics::_linkToInterface) { __ bind(L_incompatible_class_change_error); - __ far_jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry())); + __ far_jump(RuntimeAddress(SharedRuntime::throw_IncompatibleClassChangeError_entry())); } } } diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index a4dac0ccf6d..901ae502999 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -66,6 +66,12 @@ #define __ masm-> +#ifdef PRODUCT +#define BLOCK_COMMENT(str) /* nothing */ +#else +#define BLOCK_COMMENT(str) __ block_comment(str) +#endif + const int StackAlignmentInSlots = StackAlignmentInBytes / VMRegImpl::stack_slot_size; // FIXME -- this is used by C1 @@ -2764,3 +2770,193 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha // frame_size_words or bytes?? return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_in_words, oop_maps, true); } + +// Continuation point for throwing of implicit exceptions that are +// not handled in the current activation. Fabricates an exception +// oop and initiates normal exception dispatching in this +// frame. Since we need to preserve callee-saved values (currently +// only for C2, but done for C1 as well) we need a callee-saved oop +// map and therefore have to make these stubs into RuntimeStubs +// rather than BufferBlobs. If the compiler needs all registers to +// be preserved between the fault point and the exception handler +// then it must assume responsibility for that in +// AbstractCompiler::continuation_for_implicit_null_exception or +// continuation_for_implicit_division_by_zero_exception. All other +// implicit exceptions (e.g., NullPointerException or +// AbstractMethodError on entry) are either at call sites or +// otherwise assume that stack unwinding will be initiated, so +// caller saved registers were assumed volatile in the compiler. + +RuntimeStub* SharedRuntime::generate_throw_exception(const char* name, address runtime_entry) { + // Information about frame layout at time of blocking runtime call. + // Note that we only have to preserve callee-saved registers since + // the compilers are responsible for supplying a continuation point + // if they expect all registers to be preserved. + // n.b. aarch64 asserts that frame::arg_reg_save_area_bytes == 0 + enum layout { + rfp_off = 0, + rfp_off2, + return_off, + return_off2, + framesize // inclusive of return address + }; + + int insts_size = 512; + int locs_size = 64; + + ResourceMark rm; + const char* timer_msg = "SharedRuntime generate_throw_exception"; + TraceTime timer(timer_msg, TRACETIME_LOG(Info, startuptime)); + + CodeBuffer code(name, insts_size, locs_size); + OopMapSet* oop_maps = new OopMapSet(); + MacroAssembler* masm = new MacroAssembler(&code); + + address start = __ pc(); + + // This is an inlined and slightly modified version of call_VM + // which has the ability to fetch the return PC out of + // thread-local storage and also sets up last_Java_sp slightly + // differently than the real call_VM + + __ enter(); // Save FP and LR before call + + assert(is_even(framesize/2), "sp not 16-byte aligned"); + + // lr and fp are already in place + __ sub(sp, rfp, ((uint64_t)framesize-4) << LogBytesPerInt); // prolog + + int frame_complete = __ pc() - start; + + // Set up last_Java_sp and last_Java_fp + address the_pc = __ pc(); + __ set_last_Java_frame(sp, rfp, the_pc, rscratch1); + + __ mov(c_rarg0, rthread); + BLOCK_COMMENT("call runtime_entry"); + __ mov(rscratch1, runtime_entry); + __ blr(rscratch1); + + // Generate oop map + OopMap* map = new OopMap(framesize, 0); + + oop_maps->add_gc_map(the_pc - start, map); + + __ reset_last_Java_frame(true); + + // Reinitialize the ptrue predicate register, in case the external runtime + // call clobbers ptrue reg, as we may return to SVE compiled code. + __ reinitialize_ptrue(); + + __ leave(); + + // check for pending exceptions +#ifdef ASSERT + Label L; + __ ldr(rscratch1, Address(rthread, Thread::pending_exception_offset())); + __ cbnz(rscratch1, L); + __ should_not_reach_here(); + __ bind(L); +#endif // ASSERT + __ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry())); + + // codeBlob framesize is in words (not VMRegImpl::slot_size) + RuntimeStub* stub = + RuntimeStub::new_runtime_stub(name, + &code, + frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, false); + return stub; +} + +#if INCLUDE_JFR + +static void jfr_prologue(address the_pc, MacroAssembler* masm, Register thread) { + __ set_last_Java_frame(sp, rfp, the_pc, rscratch1); + __ mov(c_rarg0, thread); +} + +// The handle is dereferenced through a load barrier. +static void jfr_epilogue(MacroAssembler* masm) { + __ reset_last_Java_frame(true); +} + +// For c2: c_rarg0 is junk, call to runtime to write a checkpoint. +// It returns a jobject handle to the event writer. +// The handle is dereferenced and the return value is the event writer oop. +RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { + enum layout { + rbp_off, + rbpH_off, + return_off, + return_off2, + framesize // inclusive of return address + }; + + int insts_size = 1024; + int locs_size = 64; + CodeBuffer code("jfr_write_checkpoint", insts_size, locs_size); + OopMapSet* oop_maps = new OopMapSet(); + MacroAssembler* masm = new MacroAssembler(&code); + + address start = __ pc(); + __ enter(); + int frame_complete = __ pc() - start; + address the_pc = __ pc(); + jfr_prologue(the_pc, masm, rthread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), 1); + jfr_epilogue(masm); + __ resolve_global_jobject(r0, rscratch1, rscratch2); + __ leave(); + __ ret(lr); + + OopMap* map = new OopMap(framesize, 1); // rfp + oop_maps->add_gc_map(the_pc - start, map); + + RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) + RuntimeStub::new_runtime_stub("jfr_write_checkpoint", &code, frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, false); + return stub; +} + +// For c2: call to return a leased buffer. +RuntimeStub* SharedRuntime::generate_jfr_return_lease() { + enum layout { + rbp_off, + rbpH_off, + return_off, + return_off2, + framesize // inclusive of return address + }; + + int insts_size = 1024; + int locs_size = 64; + + CodeBuffer code("jfr_return_lease", insts_size, locs_size); + OopMapSet* oop_maps = new OopMapSet(); + MacroAssembler* masm = new MacroAssembler(&code); + + address start = __ pc(); + __ enter(); + int frame_complete = __ pc() - start; + address the_pc = __ pc(); + jfr_prologue(the_pc, masm, rthread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), 1); + jfr_epilogue(masm); + + __ leave(); + __ ret(lr); + + OopMap* map = new OopMap(framesize, 1); // rfp + oop_maps->add_gc_map(the_pc - start, map); + + RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) + RuntimeStub::new_runtime_stub("jfr_return_lease", &code, frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, false); + return stub; +} + +#endif // INCLUDE_JFR diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index 5e2ef97e4a3..b3513a586de 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -7045,7 +7045,7 @@ class StubGenerator: public StubCodeGenerator { Label thaw_success; // rscratch2 contains the size of the frames to thaw, 0 if overflow or no more frames __ cbnz(rscratch2, thaw_success); - __ lea(rscratch1, RuntimeAddress(StubRoutines::throw_StackOverflowError_entry())); + __ lea(rscratch1, RuntimeAddress(SharedRuntime::throw_StackOverflowError_entry())); __ br(rscratch1); __ bind(thaw_success); @@ -7305,98 +7305,6 @@ class StubGenerator: public StubCodeGenerator { return start; } -#if INCLUDE_JFR - - static void jfr_prologue(address the_pc, MacroAssembler* _masm, Register thread) { - __ set_last_Java_frame(sp, rfp, the_pc, rscratch1); - __ mov(c_rarg0, thread); - } - - // The handle is dereferenced through a load barrier. - static void jfr_epilogue(MacroAssembler* _masm) { - __ reset_last_Java_frame(true); - } - - // For c2: c_rarg0 is junk, call to runtime to write a checkpoint. - // It returns a jobject handle to the event writer. - // The handle is dereferenced and the return value is the event writer oop. - static RuntimeStub* generate_jfr_write_checkpoint() { - enum layout { - rbp_off, - rbpH_off, - return_off, - return_off2, - framesize // inclusive of return address - }; - - int insts_size = 1024; - int locs_size = 64; - CodeBuffer code("jfr_write_checkpoint", insts_size, locs_size); - OopMapSet* oop_maps = new OopMapSet(); - MacroAssembler* masm = new MacroAssembler(&code); - MacroAssembler* _masm = masm; - - address start = __ pc(); - __ enter(); - int frame_complete = __ pc() - start; - address the_pc = __ pc(); - jfr_prologue(the_pc, _masm, rthread); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), 1); - jfr_epilogue(_masm); - __ resolve_global_jobject(r0, rscratch1, rscratch2); - __ leave(); - __ ret(lr); - - OopMap* map = new OopMap(framesize, 1); // rfp - oop_maps->add_gc_map(the_pc - start, map); - - RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) - RuntimeStub::new_runtime_stub("jfr_write_checkpoint", &code, frame_complete, - (framesize >> (LogBytesPerWord - LogBytesPerInt)), - oop_maps, false); - return stub; - } - - // For c2: call to return a leased buffer. - static RuntimeStub* generate_jfr_return_lease() { - enum layout { - rbp_off, - rbpH_off, - return_off, - return_off2, - framesize // inclusive of return address - }; - - int insts_size = 1024; - int locs_size = 64; - CodeBuffer code("jfr_return_lease", insts_size, locs_size); - OopMapSet* oop_maps = new OopMapSet(); - MacroAssembler* masm = new MacroAssembler(&code); - MacroAssembler* _masm = masm; - - address start = __ pc(); - __ enter(); - int frame_complete = __ pc() - start; - address the_pc = __ pc(); - jfr_prologue(the_pc, _masm, rthread); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), 1); - jfr_epilogue(_masm); - - __ leave(); - __ ret(lr); - - OopMap* map = new OopMap(framesize, 1); // rfp - oop_maps->add_gc_map(the_pc - start, map); - - RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) - RuntimeStub::new_runtime_stub("jfr_return_lease", &code, frame_complete, - (framesize >> (LogBytesPerWord - LogBytesPerInt)), - oop_maps, false); - return stub; - } - -#endif // INCLUDE_JFR - // exception handler for upcall stubs address generate_upcall_stub_exception_handler() { StubCodeMark mark(this, "StubRoutines", "upcall stub exception handler"); @@ -7412,115 +7320,9 @@ class StubGenerator: public StubCodeGenerator { return start; } - // Continuation point for throwing of implicit exceptions that are - // not handled in the current activation. Fabricates an exception - // oop and initiates normal exception dispatching in this - // frame. Since we need to preserve callee-saved values (currently - // only for C2, but done for C1 as well) we need a callee-saved oop - // map and therefore have to make these stubs into RuntimeStubs - // rather than BufferBlobs. If the compiler needs all registers to - // be preserved between the fault point and the exception handler - // then it must assume responsibility for that in - // AbstractCompiler::continuation_for_implicit_null_exception or - // continuation_for_implicit_division_by_zero_exception. All other - // implicit exceptions (e.g., NullPointerException or - // AbstractMethodError on entry) are either at call sites or - // otherwise assume that stack unwinding will be initiated, so - // caller saved registers were assumed volatile in the compiler. - #undef __ #define __ masm-> - address generate_throw_exception(const char* name, - address runtime_entry, - Register arg1 = noreg, - Register arg2 = noreg) { - // Information about frame layout at time of blocking runtime call. - // Note that we only have to preserve callee-saved registers since - // the compilers are responsible for supplying a continuation point - // if they expect all registers to be preserved. - // n.b. aarch64 asserts that frame::arg_reg_save_area_bytes == 0 - enum layout { - rfp_off = 0, - rfp_off2, - return_off, - return_off2, - framesize // inclusive of return address - }; - - int insts_size = 512; - int locs_size = 64; - - CodeBuffer code(name, insts_size, locs_size); - OopMapSet* oop_maps = new OopMapSet(); - MacroAssembler* masm = new MacroAssembler(&code); - - address start = __ pc(); - - // This is an inlined and slightly modified version of call_VM - // which has the ability to fetch the return PC out of - // thread-local storage and also sets up last_Java_sp slightly - // differently than the real call_VM - - __ enter(); // Save FP and LR before call - - assert(is_even(framesize/2), "sp not 16-byte aligned"); - - // lr and fp are already in place - __ sub(sp, rfp, ((uint64_t)framesize-4) << LogBytesPerInt); // prolog - - int frame_complete = __ pc() - start; - - // Set up last_Java_sp and last_Java_fp - address the_pc = __ pc(); - __ set_last_Java_frame(sp, rfp, the_pc, rscratch1); - - // Call runtime - if (arg1 != noreg) { - assert(arg2 != c_rarg1, "clobbered"); - __ mov(c_rarg1, arg1); - } - if (arg2 != noreg) { - __ mov(c_rarg2, arg2); - } - __ mov(c_rarg0, rthread); - BLOCK_COMMENT("call runtime_entry"); - __ mov(rscratch1, runtime_entry); - __ blr(rscratch1); - - // Generate oop map - OopMap* map = new OopMap(framesize, 0); - - oop_maps->add_gc_map(the_pc - start, map); - - __ reset_last_Java_frame(true); - - // Reinitialize the ptrue predicate register, in case the external runtime - // call clobbers ptrue reg, as we may return to SVE compiled code. - __ reinitialize_ptrue(); - - __ leave(); - - // check for pending exceptions -#ifdef ASSERT - Label L; - __ ldr(rscratch1, Address(rthread, Thread::pending_exception_offset())); - __ cbnz(rscratch1, L); - __ should_not_reach_here(); - __ bind(L); -#endif // ASSERT - __ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry())); - - // codeBlob framesize is in words (not VMRegImpl::slot_size) - RuntimeStub* stub = - RuntimeStub::new_runtime_stub(name, - &code, - frame_complete, - (framesize >> (LogBytesPerWord - LogBytesPerInt)), - oop_maps, false); - return stub->entry_point(); - } - class MontgomeryMultiplyGenerator : public MacroAssembler { Register Pa_base, Pb_base, Pn_base, Pm_base, inv, Rlen, Ra, Rb, Rm, Rn, @@ -8363,16 +8165,6 @@ class StubGenerator: public StubCodeGenerator { // is referenced by megamorphic call StubRoutines::_catch_exception_entry = generate_catch_exception(); - // Build this early so it's available for the interpreter. - StubRoutines::_throw_StackOverflowError_entry = - generate_throw_exception("StackOverflowError throw_exception", - CAST_FROM_FN_PTR(address, - SharedRuntime::throw_StackOverflowError)); - StubRoutines::_throw_delayed_StackOverflowError_entry = - generate_throw_exception("delayed StackOverflowError throw_exception", - CAST_FROM_FN_PTR(address, - SharedRuntime::throw_delayed_StackOverflowError)); - // Initialize table for copy memory (arraycopy) check. if (UnsafeMemoryAccess::_table == nullptr) { UnsafeMemoryAccess::create_table(8 + 4); // 8 for copyMemory; 4 for setMemory @@ -8408,41 +8200,13 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_cont_thaw = generate_cont_thaw(); StubRoutines::_cont_returnBarrier = generate_cont_returnBarrier(); StubRoutines::_cont_returnBarrierExc = generate_cont_returnBarrier_exception(); - - JFR_ONLY(generate_jfr_stubs();) - } - -#if INCLUDE_JFR - void generate_jfr_stubs() { - StubRoutines::_jfr_write_checkpoint_stub = generate_jfr_write_checkpoint(); - StubRoutines::_jfr_write_checkpoint = StubRoutines::_jfr_write_checkpoint_stub->entry_point(); - StubRoutines::_jfr_return_lease_stub = generate_jfr_return_lease(); - StubRoutines::_jfr_return_lease = StubRoutines::_jfr_return_lease_stub->entry_point(); } -#endif // INCLUDE_JFR void generate_final_stubs() { // support for verify_oop (must happen after universe_init) if (VerifyOops) { StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop(); } - StubRoutines::_throw_AbstractMethodError_entry = - generate_throw_exception("AbstractMethodError throw_exception", - CAST_FROM_FN_PTR(address, - SharedRuntime:: - throw_AbstractMethodError)); - - StubRoutines::_throw_IncompatibleClassChangeError_entry = - generate_throw_exception("IncompatibleClassChangeError throw_exception", - CAST_FROM_FN_PTR(address, - SharedRuntime:: - throw_IncompatibleClassChangeError)); - - StubRoutines::_throw_NullPointerException_at_call_entry = - generate_throw_exception("NullPointerException at call throw_exception", - CAST_FROM_FN_PTR(address, - SharedRuntime:: - throw_NullPointerException_at_call)); // arraycopy stubs used by compilers generate_arraycopy_stubs(); diff --git a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp index ed2450a9110..38d48b86f23 100644 --- a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp @@ -752,8 +752,8 @@ void TemplateInterpreterGenerator::generate_stack_overflow_check(void) { // Note: the restored frame is not necessarily interpreted. // Use the shared runtime version of the StackOverflowError. - assert(StubRoutines::throw_StackOverflowError_entry() != nullptr, "stub not yet generated"); - __ far_jump(RuntimeAddress(StubRoutines::throw_StackOverflowError_entry())); + assert(SharedRuntime::throw_StackOverflowError_entry() != nullptr, "stub not yet generated"); + __ far_jump(RuntimeAddress(SharedRuntime::throw_StackOverflowError_entry())); // all done with frame size check __ bind(after_frame_check); diff --git a/src/hotspot/cpu/arm/methodHandles_arm.cpp b/src/hotspot/cpu/arm/methodHandles_arm.cpp index 83939292055..7fc984afa99 100644 --- a/src/hotspot/cpu/arm/methodHandles_arm.cpp +++ b/src/hotspot/cpu/arm/methodHandles_arm.cpp @@ -39,6 +39,7 @@ #include "prims/jvmtiExport.hpp" #include "prims/methodHandles.hpp" #include "runtime/frame.inline.hpp" +#include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "utilities/preserveException.hpp" @@ -140,7 +141,7 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, bool for_comp __ bind(L_no_such_method); // throw exception - __ jump(StubRoutines::throw_AbstractMethodError_entry(), relocInfo::runtime_call_type, Rtemp); + __ jump(SharedRuntime::throw_AbstractMethodError_entry(), relocInfo::runtime_call_type, Rtemp); } void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm, @@ -461,7 +462,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, if (iid == vmIntrinsics::_linkToInterface) { __ bind(L_incompatible_class_change_error); - __ jump(StubRoutines::throw_IncompatibleClassChangeError_entry(), relocInfo::runtime_call_type, Rtemp); + __ jump(SharedRuntime::throw_IncompatibleClassChangeError_entry(), relocInfo::runtime_call_type, Rtemp); } } } diff --git a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp index 1305283aeae..f07c1f8e53c 100644 --- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp +++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp @@ -1728,3 +1728,143 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_words, oop_maps, true); } + +//------------------------------------------------------------------------------------------------------------------------ +// Continuation point for throwing of implicit exceptions that are not handled in +// the current activation. Fabricates an exception oop and initiates normal +// exception dispatching in this frame. +RuntimeStub* SharedRuntime::generate_throw_exception(const char* name, address runtime_entry) { + int insts_size = 128; + int locs_size = 32; + + ResourceMark rm; + const char* timer_msg = "SharedRuntime generate_throw_exception"; + TraceTime timer(timer_msg, TRACETIME_LOG(Info, startuptime)); + + CodeBuffer code(name, insts_size, locs_size); + OopMapSet* oop_maps; + int frame_size; + int frame_complete; + + oop_maps = new OopMapSet(); + MacroAssembler* masm = new MacroAssembler(&code); + + address start = __ pc(); + + frame_size = 2; + __ mov(Rexception_pc, LR); + __ raw_push(FP, LR); + + frame_complete = __ pc() - start; + + // Any extra arguments are already supposed to be R1 and R2 + __ mov(R0, Rthread); + + int pc_offset = __ set_last_Java_frame(SP, FP, false, Rtemp); + assert(((__ pc()) - start) == __ offset(), "warning: start differs from code_begin"); + __ call(runtime_entry); + if (pc_offset == -1) { + pc_offset = __ offset(); + } + + // Generate oop map + OopMap* map = new OopMap(frame_size*VMRegImpl::slots_per_word, 0); + oop_maps->add_gc_map(pc_offset, map); + __ reset_last_Java_frame(Rtemp); // Rtemp free since scratched by far call + + __ raw_pop(FP, LR); + __ jump(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type, Rtemp); + + RuntimeStub* stub = RuntimeStub::new_runtime_stub(name, &code, frame_complete, + frame_size, oop_maps, false); + return stub; +} + +#if INCLUDE_JFR + +// For c2: c_rarg0 is junk, call to runtime to write a checkpoint. +// It returns a jobject handle to the event writer. +// The handle is dereferenced and the return value is the event writer oop. +RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { + enum layout { + r1_off, + r2_off, + return_off, + framesize // inclusive of return address + }; + + CodeBuffer code("jfr_write_checkpoint", 512, 64); + MacroAssembler* masm = new MacroAssembler(&code); + + address start = __ pc(); + __ raw_push(R1, R2, LR); + address the_pc = __ pc(); + + int frame_complete = the_pc - start; + + __ set_last_Java_frame(SP, FP, true, Rtemp); + __ mov(c_rarg0, Rthread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), c_rarg0); + __ reset_last_Java_frame(Rtemp); + + // R0 is jobject handle result, unpack and process it through a barrier. + __ resolve_global_jobject(R0, Rtemp, R1); + + __ raw_pop(R1, R2, LR); + __ ret(); + + OopMapSet* oop_maps = new OopMapSet(); + OopMap* map = new OopMap(framesize, 1); + oop_maps->add_gc_map(frame_complete, map); + + RuntimeStub* stub = + RuntimeStub::new_runtime_stub(code.name(), + &code, + frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, + false); + return stub; +} + +// For c2: call to return a leased buffer. +RuntimeStub* SharedRuntime::generate_jfr_return_lease() { + enum layout { + r1_off, + r2_off, + return_off, + framesize // inclusive of return address + }; + + CodeBuffer code("jfr_return_lease", 512, 64); + MacroAssembler* masm = new MacroAssembler(&code); + + address start = __ pc(); + __ raw_push(R1, R2, LR); + address the_pc = __ pc(); + + int frame_complete = the_pc - start; + + __ set_last_Java_frame(SP, FP, true, Rtemp); + __ mov(c_rarg0, Rthread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), c_rarg0); + __ reset_last_Java_frame(Rtemp); + + __ raw_pop(R1, R2, LR); + __ ret(); + + OopMapSet* oop_maps = new OopMapSet(); + OopMap* map = new OopMap(framesize, 1); + oop_maps->add_gc_map(frame_complete, map); + + RuntimeStub* stub = + RuntimeStub::new_runtime_stub(code.name(), + &code, + frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, + false); + return stub; +} + +#endif // INCLUDE_JFR diff --git a/src/hotspot/cpu/arm/stubGenerator_arm.cpp b/src/hotspot/cpu/arm/stubGenerator_arm.cpp index 0d66a2fbb0a..9b91e02cf07 100644 --- a/src/hotspot/cpu/arm/stubGenerator_arm.cpp +++ b/src/hotspot/cpu/arm/stubGenerator_arm.cpp @@ -2961,52 +2961,6 @@ class StubGenerator: public StubCodeGenerator { #undef __ #define __ masm-> - //------------------------------------------------------------------------------------------------------------------------ - // Continuation point for throwing of implicit exceptions that are not handled in - // the current activation. Fabricates an exception oop and initiates normal - // exception dispatching in this frame. - address generate_throw_exception(const char* name, address runtime_entry) { - int insts_size = 128; - int locs_size = 32; - CodeBuffer code(name, insts_size, locs_size); - OopMapSet* oop_maps; - int frame_size; - int frame_complete; - - oop_maps = new OopMapSet(); - MacroAssembler* masm = new MacroAssembler(&code); - - address start = __ pc(); - - frame_size = 2; - __ mov(Rexception_pc, LR); - __ raw_push(FP, LR); - - frame_complete = __ pc() - start; - - // Any extra arguments are already supposed to be R1 and R2 - __ mov(R0, Rthread); - - int pc_offset = __ set_last_Java_frame(SP, FP, false, Rtemp); - assert(((__ pc()) - start) == __ offset(), "warning: start differs from code_begin"); - __ call(runtime_entry); - if (pc_offset == -1) { - pc_offset = __ offset(); - } - - // Generate oop map - OopMap* map = new OopMap(frame_size*VMRegImpl::slots_per_word, 0); - oop_maps->add_gc_map(pc_offset, map); - __ reset_last_Java_frame(Rtemp); // Rtemp free since scratched by far call - - __ raw_pop(FP, LR); - __ jump(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type, Rtemp); - - RuntimeStub* stub = RuntimeStub::new_runtime_stub(name, &code, frame_complete, - frame_size, oop_maps, false); - return stub->entry_point(); - } - address generate_cont_thaw(const char* label, Continuation::thaw_kind kind) { if (!Continuations::enabled()) return nullptr; Unimplemented(); @@ -3025,95 +2979,6 @@ class StubGenerator: public StubCodeGenerator { return generate_cont_thaw("Cont thaw return barrier exception", Continuation::thaw_return_barrier_exception); } -#if INCLUDE_JFR - - // For c2: c_rarg0 is junk, call to runtime to write a checkpoint. - // It returns a jobject handle to the event writer. - // The handle is dereferenced and the return value is the event writer oop. - static RuntimeStub* generate_jfr_write_checkpoint() { - enum layout { - r1_off, - r2_off, - return_off, - framesize // inclusive of return address - }; - - CodeBuffer code("jfr_write_checkpoint", 512, 64); - MacroAssembler* masm = new MacroAssembler(&code); - - address start = __ pc(); - __ raw_push(R1, R2, LR); - address the_pc = __ pc(); - - int frame_complete = the_pc - start; - - __ set_last_Java_frame(SP, FP, true, Rtemp); - __ mov(c_rarg0, Rthread); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), c_rarg0); - __ reset_last_Java_frame(Rtemp); - - // R0 is jobject handle result, unpack and process it through a barrier. - __ resolve_global_jobject(R0, Rtemp, R1); - - __ raw_pop(R1, R2, LR); - __ ret(); - - OopMapSet* oop_maps = new OopMapSet(); - OopMap* map = new OopMap(framesize, 1); - oop_maps->add_gc_map(frame_complete, map); - - RuntimeStub* stub = - RuntimeStub::new_runtime_stub(code.name(), - &code, - frame_complete, - (framesize >> (LogBytesPerWord - LogBytesPerInt)), - oop_maps, - false); - return stub; - } - - // For c2: call to return a leased buffer. - static RuntimeStub* generate_jfr_return_lease() { - enum layout { - r1_off, - r2_off, - return_off, - framesize // inclusive of return address - }; - - CodeBuffer code("jfr_return_lease", 512, 64); - MacroAssembler* masm = new MacroAssembler(&code); - - address start = __ pc(); - __ raw_push(R1, R2, LR); - address the_pc = __ pc(); - - int frame_complete = the_pc - start; - - __ set_last_Java_frame(SP, FP, true, Rtemp); - __ mov(c_rarg0, Rthread); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), c_rarg0); - __ reset_last_Java_frame(Rtemp); - - __ raw_pop(R1, R2, LR); - __ ret(); - - OopMapSet* oop_maps = new OopMapSet(); - OopMap* map = new OopMap(framesize, 1); - oop_maps->add_gc_map(frame_complete, map); - - RuntimeStub* stub = - RuntimeStub::new_runtime_stub(code.name(), - &code, - frame_complete, - (framesize >> (LogBytesPerWord - LogBytesPerInt)), - oop_maps, - false); - return stub; - } - -#endif // INCLUDE_JFR - //--------------------------------------------------------------------------- // Initialization @@ -3132,8 +2997,6 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_catch_exception_entry = generate_catch_exception(); // stub for throwing stack overflow error used both by interpreter and compiler - StubRoutines::_throw_StackOverflowError_entry = generate_throw_exception("StackOverflowError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError)); - if (UnsafeMemoryAccess::_table == nullptr) { UnsafeMemoryAccess::create_table(32 + 4); // 32 for copyMemory; 4 for setMemory } @@ -3155,28 +3018,11 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_cont_thaw = generate_cont_thaw(); StubRoutines::_cont_returnBarrier = generate_cont_returnBarrier(); StubRoutines::_cont_returnBarrierExc = generate_cont_returnBarrier_exception(); - - JFR_ONLY(generate_jfr_stubs();) } -#if INCLUDE_JFR - void generate_jfr_stubs() { - StubRoutines::_jfr_write_checkpoint_stub = generate_jfr_write_checkpoint(); - StubRoutines::_jfr_write_checkpoint = StubRoutines::_jfr_write_checkpoint_stub->entry_point(); - StubRoutines::_jfr_return_lease_stub = generate_jfr_return_lease(); - StubRoutines::_jfr_return_lease = StubRoutines::_jfr_return_lease_stub->entry_point(); - } -#endif // INCLUDE_JFR - void generate_final_stubs() { // Generates all stubs and initializes the entry points - // These entry points require SharedInfo::stack0 to be set up in non-core builds - // and need to be relocatable, so they each fabricate a RuntimeStub internally. - StubRoutines::_throw_AbstractMethodError_entry = generate_throw_exception("AbstractMethodError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_AbstractMethodError)); - StubRoutines::_throw_IncompatibleClassChangeError_entry= generate_throw_exception("IncompatibleClassChangeError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError)); - StubRoutines::_throw_NullPointerException_at_call_entry= generate_throw_exception("NullPointerException at call throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException_at_call)); - //------------------------------------------------------------------------------------------------------------------------ // entry points that are platform specific diff --git a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp index efaf78ee568..679f07a028e 100644 --- a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp +++ b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp @@ -560,7 +560,7 @@ void TemplateInterpreterGenerator::generate_stack_overflow_check(void) { __ cmp(Rtemp, R0); __ mov(SP, Rsender_sp, ls); // restore SP - __ b(StubRoutines::throw_StackOverflowError_entry(), ls); + __ b(SharedRuntime::throw_StackOverflowError_entry(), ls); } diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index 544c0d120d0..c7cf678b49e 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -1501,7 +1501,7 @@ void MacroAssembler::reserved_stack_check(Register return_pc) { call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), R16_thread); pop_frame(); mtlr(return_pc); - load_const_optimized(R0, StubRoutines::throw_delayed_StackOverflowError_entry()); + load_const_optimized(R0, SharedRuntime::throw_delayed_StackOverflowError_entry()); mtctr(R0); bctr(); diff --git a/src/hotspot/cpu/ppc/methodHandles_ppc.cpp b/src/hotspot/cpu/ppc/methodHandles_ppc.cpp index 6e5ac325e50..ccec05e7105 100644 --- a/src/hotspot/cpu/ppc/methodHandles_ppc.cpp +++ b/src/hotspot/cpu/ppc/methodHandles_ppc.cpp @@ -158,8 +158,8 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register meth __ bctr(); __ bind(L_no_such_method); - assert(StubRoutines::throw_AbstractMethodError_entry() != nullptr, "not yet generated!"); - __ load_const_optimized(target, StubRoutines::throw_AbstractMethodError_entry()); + assert(SharedRuntime::throw_AbstractMethodError_entry() != nullptr, "not yet generated!"); + __ load_const_optimized(target, SharedRuntime::throw_AbstractMethodError_entry()); __ mtctr(target); __ bctr(); } @@ -489,7 +489,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, if (iid == vmIntrinsics::_linkToInterface) { __ BIND(L_incompatible_class_change_error); - __ load_const_optimized(temp1, StubRoutines::throw_IncompatibleClassChangeError_entry()); + __ load_const_optimized(temp1, SharedRuntime::throw_IncompatibleClassChangeError_entry()); __ mtctr(temp1); __ bctr(); } diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index 505f67ab6f9..98610d21b67 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -44,6 +44,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/signature.hpp" #include "runtime/stubRoutines.hpp" +#include "runtime/timerTrace.hpp" #include "runtime/vframeArray.hpp" #include "utilities/align.hpp" #include "utilities/macros.hpp" @@ -3404,6 +3405,100 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha oop_maps, true); } +// Continuation point for throwing of implicit exceptions that are +// not handled in the current activation. Fabricates an exception +// oop and initiates normal exception dispatching in this +// frame. Only callee-saved registers are preserved (through the +// normal register window / RegisterMap handling). If the compiler +// needs all registers to be preserved between the fault point and +// the exception handler then it must assume responsibility for that +// in AbstractCompiler::continuation_for_implicit_null_exception or +// continuation_for_implicit_division_by_zero_exception. All other +// implicit exceptions (e.g., NullPointerException or +// AbstractMethodError on entry) are either at call sites or +// otherwise assume that stack unwinding will be initiated, so +// caller saved registers were assumed volatile in the compiler. +// +// Note that we generate only this stub into a RuntimeStub, because +// it needs to be properly traversed and ignored during GC, so we +// change the meaning of the "__" macro within this method. +// +// Note: the routine set_pc_not_at_call_for_caller in +// SharedRuntime.cpp requires that this code be generated into a +// RuntimeStub. +RuntimeStub* SharedRuntime::generate_throw_exception(const char* name, address runtime_entry) { + ResourceMark rm; + const char* timer_msg = "SharedRuntime generate_throw_exception"; + TraceTime timer(timer_msg, TRACETIME_LOG(Info, startuptime)); + + CodeBuffer code(name, 1024 DEBUG_ONLY(+ 512), 0); + MacroAssembler* masm = new MacroAssembler(&code); + + OopMapSet* oop_maps = new OopMapSet(); + int frame_size_in_bytes = frame::native_abi_reg_args_size; + OopMap* map = new OopMap(frame_size_in_bytes / sizeof(jint), 0); + + address start = __ pc(); + + __ save_LR(R11_scratch1); + + // Push a frame. + __ push_frame_reg_args(0, R11_scratch1); + + address frame_complete_pc = __ pc(); + + // Note that we always have a runtime stub frame on the top of + // stack by this point. Remember the offset of the instruction + // whose address will be moved to R11_scratch1. + address gc_map_pc = __ get_PC_trash_LR(R11_scratch1); + + __ set_last_Java_frame(/*sp*/R1_SP, /*pc*/R11_scratch1); + + __ mr(R3_ARG1, R16_thread); +#if defined(ABI_ELFv2) + __ call_c(runtime_entry, relocInfo::none); +#else + __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, runtime_entry), relocInfo::none); +#endif + + // Set an oopmap for the call site. + oop_maps->add_gc_map((int)(gc_map_pc - start), map); + + __ reset_last_Java_frame(); + +#ifdef ASSERT + // Make sure that this code is only executed if there is a pending + // exception. + { + Label L; + __ ld(R0, + in_bytes(Thread::pending_exception_offset()), + R16_thread); + __ cmpdi(CCR0, R0, 0); + __ bne(CCR0, L); + __ stop("SharedRuntime::throw_exception: no pending exception"); + __ bind(L); + } +#endif + + // Pop frame. + __ pop_frame(); + + __ restore_LR(R11_scratch1); + + __ load_const(R11_scratch1, StubRoutines::forward_exception_entry()); + __ mtctr(R11_scratch1); + __ bctr(); + + // Create runtime stub with OopMap. + RuntimeStub* stub = + RuntimeStub::new_runtime_stub(name, &code, + /*frame_complete=*/ (int)(frame_complete_pc - start), + frame_size_in_bytes/wordSize, + oop_maps, + false); + return stub; +} //------------------------------Montgomery multiplication------------------------ // @@ -3647,3 +3742,81 @@ void SharedRuntime::montgomery_square(jint *a_ints, jint *n_ints, reverse_words(m, (unsigned long *)m_ints, longwords); } + +#if INCLUDE_JFR + +// For c2: c_rarg0 is junk, call to runtime to write a checkpoint. +// It returns a jobject handle to the event writer. +// The handle is dereferenced and the return value is the event writer oop. +RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { + CodeBuffer code("jfr_write_checkpoint", 512, 64); + MacroAssembler* masm = new MacroAssembler(&code); + + Register tmp1 = R10_ARG8; + Register tmp2 = R9_ARG7; + + int framesize = frame::native_abi_reg_args_size / VMRegImpl::stack_slot_size; + address start = __ pc(); + __ mflr(tmp1); + __ std(tmp1, _abi0(lr), R1_SP); // save return pc + __ push_frame_reg_args(0, tmp1); + int frame_complete = __ pc() - start; + __ set_last_Java_frame(R1_SP, noreg); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), R16_thread); + address calls_return_pc = __ last_calls_return_pc(); + __ reset_last_Java_frame(); + // The handle is dereferenced through a load barrier. + __ resolve_global_jobject(R3_RET, tmp1, tmp2, MacroAssembler::PRESERVATION_NONE); + __ pop_frame(); + __ ld(tmp1, _abi0(lr), R1_SP); + __ mtlr(tmp1); + __ blr(); + + OopMapSet* oop_maps = new OopMapSet(); + OopMap* map = new OopMap(framesize, 0); + oop_maps->add_gc_map(calls_return_pc - start, map); + + RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) + RuntimeStub::new_runtime_stub(code.name(), + &code, frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, false); + return stub; +} + +// For c2: call to return a leased buffer. +RuntimeStub* SharedRuntime::generate_jfr_return_lease() { + CodeBuffer code("jfr_return_lease", 512, 64); + MacroAssembler* masm = new MacroAssembler(&code); + + Register tmp1 = R10_ARG8; + Register tmp2 = R9_ARG7; + + int framesize = frame::native_abi_reg_args_size / VMRegImpl::stack_slot_size; + address start = __ pc(); + __ mflr(tmp1); + __ std(tmp1, _abi0(lr), R1_SP); // save return pc + __ push_frame_reg_args(0, tmp1); + int frame_complete = __ pc() - start; + __ set_last_Java_frame(R1_SP, noreg); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), R16_thread); + address calls_return_pc = __ last_calls_return_pc(); + __ reset_last_Java_frame(); + __ pop_frame(); + __ ld(tmp1, _abi0(lr), R1_SP); + __ mtlr(tmp1); + __ blr(); + + OopMapSet* oop_maps = new OopMapSet(); + OopMap* map = new OopMap(framesize, 0); + oop_maps->add_gc_map(calls_return_pc - start, map); + + RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) + RuntimeStub::new_runtime_stub(code.name(), + &code, frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, false); + return stub; +} + +#endif // INCLUDE_JFR diff --git a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp index 8da7cf7e791..ee3f1911e20 100644 --- a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp @@ -517,109 +517,6 @@ class StubGenerator: public StubCodeGenerator { } #undef __ -#define __ masm-> - // Continuation point for throwing of implicit exceptions that are - // not handled in the current activation. Fabricates an exception - // oop and initiates normal exception dispatching in this - // frame. Only callee-saved registers are preserved (through the - // normal register window / RegisterMap handling). If the compiler - // needs all registers to be preserved between the fault point and - // the exception handler then it must assume responsibility for that - // in AbstractCompiler::continuation_for_implicit_null_exception or - // continuation_for_implicit_division_by_zero_exception. All other - // implicit exceptions (e.g., NullPointerException or - // AbstractMethodError on entry) are either at call sites or - // otherwise assume that stack unwinding will be initiated, so - // caller saved registers were assumed volatile in the compiler. - // - // Note that we generate only this stub into a RuntimeStub, because - // it needs to be properly traversed and ignored during GC, so we - // change the meaning of the "__" macro within this method. - // - // Note: the routine set_pc_not_at_call_for_caller in - // SharedRuntime.cpp requires that this code be generated into a - // RuntimeStub. - address generate_throw_exception(const char* name, address runtime_entry, bool restore_saved_exception_pc, - Register arg1 = noreg, Register arg2 = noreg) { - CodeBuffer code(name, 1024 DEBUG_ONLY(+ 512), 0); - MacroAssembler* masm = new MacroAssembler(&code); - - OopMapSet* oop_maps = new OopMapSet(); - int frame_size_in_bytes = frame::native_abi_reg_args_size; - OopMap* map = new OopMap(frame_size_in_bytes / sizeof(jint), 0); - - address start = __ pc(); - - __ save_LR(R11_scratch1); - - // Push a frame. - __ push_frame_reg_args(0, R11_scratch1); - - address frame_complete_pc = __ pc(); - - if (restore_saved_exception_pc) { - __ unimplemented("StubGenerator::throw_exception with restore_saved_exception_pc"); - } - - // Note that we always have a runtime stub frame on the top of - // stack by this point. Remember the offset of the instruction - // whose address will be moved to R11_scratch1. - address gc_map_pc = __ get_PC_trash_LR(R11_scratch1); - - __ set_last_Java_frame(/*sp*/R1_SP, /*pc*/R11_scratch1); - - __ mr(R3_ARG1, R16_thread); - if (arg1 != noreg) { - __ mr(R4_ARG2, arg1); - } - if (arg2 != noreg) { - __ mr(R5_ARG3, arg2); - } -#if defined(ABI_ELFv2) - __ call_c(runtime_entry, relocInfo::none); -#else - __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, runtime_entry), relocInfo::none); -#endif - - // Set an oopmap for the call site. - oop_maps->add_gc_map((int)(gc_map_pc - start), map); - - __ reset_last_Java_frame(); - -#ifdef ASSERT - // Make sure that this code is only executed if there is a pending - // exception. - { - Label L; - __ ld(R0, - in_bytes(Thread::pending_exception_offset()), - R16_thread); - __ cmpdi(CCR0, R0, 0); - __ bne(CCR0, L); - __ stop("StubRoutines::throw_exception: no pending exception"); - __ bind(L); - } -#endif - - // Pop frame. - __ pop_frame(); - - __ restore_LR(R11_scratch1); - - __ load_const(R11_scratch1, StubRoutines::forward_exception_entry()); - __ mtctr(R11_scratch1); - __ bctr(); - - // Create runtime stub with OopMap. - RuntimeStub* stub = - RuntimeStub::new_runtime_stub(name, &code, - /*frame_complete=*/ (int)(frame_complete_pc - start), - frame_size_in_bytes/wordSize, - oop_maps, - false); - return stub->entry_point(); - } -#undef __ #define __ _masm-> @@ -4616,7 +4513,7 @@ address generate_lookup_secondary_supers_table_stub(u1 super_klass_index) { Label thaw_success; __ cmpdi(CCR0, R3_RET, 0); __ bne(CCR0, thaw_success); - __ load_const_optimized(tmp1, (StubRoutines::throw_StackOverflowError_entry()), R0); + __ load_const_optimized(tmp1, (SharedRuntime::throw_StackOverflowError_entry()), R0); __ mtctr(tmp1); __ bctr(); __ bind(thaw_success); @@ -4675,84 +4572,6 @@ address generate_lookup_secondary_supers_table_stub(u1 super_klass_index) { return generate_cont_thaw("Cont thaw return barrier exception", Continuation::thaw_return_barrier_exception); } -#if INCLUDE_JFR - - // For c2: c_rarg0 is junk, call to runtime to write a checkpoint. - // It returns a jobject handle to the event writer. - // The handle is dereferenced and the return value is the event writer oop. - RuntimeStub* generate_jfr_write_checkpoint() { - CodeBuffer code("jfr_write_checkpoint", 512, 64); - MacroAssembler* _masm = new MacroAssembler(&code); - - Register tmp1 = R10_ARG8; - Register tmp2 = R9_ARG7; - - int framesize = frame::native_abi_reg_args_size / VMRegImpl::stack_slot_size; - address start = __ pc(); - __ mflr(tmp1); - __ std(tmp1, _abi0(lr), R1_SP); // save return pc - __ push_frame_reg_args(0, tmp1); - int frame_complete = __ pc() - start; - __ set_last_Java_frame(R1_SP, noreg); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), R16_thread); - address calls_return_pc = __ last_calls_return_pc(); - __ reset_last_Java_frame(); - // The handle is dereferenced through a load barrier. - __ resolve_global_jobject(R3_RET, tmp1, tmp2, MacroAssembler::PRESERVATION_NONE); - __ pop_frame(); - __ ld(tmp1, _abi0(lr), R1_SP); - __ mtlr(tmp1); - __ blr(); - - OopMapSet* oop_maps = new OopMapSet(); - OopMap* map = new OopMap(framesize, 0); - oop_maps->add_gc_map(calls_return_pc - start, map); - - RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) - RuntimeStub::new_runtime_stub(code.name(), - &code, frame_complete, - (framesize >> (LogBytesPerWord - LogBytesPerInt)), - oop_maps, false); - return stub; - } - - // For c2: call to return a leased buffer. - RuntimeStub* generate_jfr_return_lease() { - CodeBuffer code("jfr_return_lease", 512, 64); - MacroAssembler* _masm = new MacroAssembler(&code); - - Register tmp1 = R10_ARG8; - Register tmp2 = R9_ARG7; - - int framesize = frame::native_abi_reg_args_size / VMRegImpl::stack_slot_size; - address start = __ pc(); - __ mflr(tmp1); - __ std(tmp1, _abi0(lr), R1_SP); // save return pc - __ push_frame_reg_args(0, tmp1); - int frame_complete = __ pc() - start; - __ set_last_Java_frame(R1_SP, noreg); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), R16_thread); - address calls_return_pc = __ last_calls_return_pc(); - __ reset_last_Java_frame(); - __ pop_frame(); - __ ld(tmp1, _abi0(lr), R1_SP); - __ mtlr(tmp1); - __ blr(); - - OopMapSet* oop_maps = new OopMapSet(); - OopMap* map = new OopMap(framesize, 0); - oop_maps->add_gc_map(calls_return_pc - start, map); - - RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) - RuntimeStub::new_runtime_stub(code.name(), - &code, frame_complete, - (framesize >> (LogBytesPerWord - LogBytesPerInt)), - oop_maps, false); - return stub; - } - -#endif // INCLUDE_JFR - // exception handler for upcall stubs address generate_upcall_stub_exception_handler() { StubCodeMark mark(this, "StubRoutines", "upcall stub exception handler"); @@ -4786,14 +4605,6 @@ address generate_lookup_secondary_supers_table_stub(u1 super_klass_index) { UnsafeMemoryAccess::create_table(8 + 4); // 8 for copyMemory; 4 for setMemory } - // Build this early so it's available for the interpreter. - StubRoutines::_throw_StackOverflowError_entry = - generate_throw_exception("StackOverflowError throw_exception", - CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError), false); - StubRoutines::_throw_delayed_StackOverflowError_entry = - generate_throw_exception("delayed StackOverflowError throw_exception", - CAST_FROM_FN_PTR(address, SharedRuntime::throw_delayed_StackOverflowError), false); - // CRC32 Intrinsics. if (UseCRC32Intrinsics) { StubRoutines::_crc_table_adr = StubRoutines::ppc::generate_crc_constants(REVERSE_CRC32_POLY); @@ -4812,29 +4623,11 @@ address generate_lookup_secondary_supers_table_stub(u1 super_klass_index) { StubRoutines::_cont_thaw = generate_cont_thaw(); StubRoutines::_cont_returnBarrier = generate_cont_returnBarrier(); StubRoutines::_cont_returnBarrierExc = generate_cont_returnBarrier_exception(); - - JFR_ONLY(generate_jfr_stubs();) - } - -#if INCLUDE_JFR - void generate_jfr_stubs() { - StubRoutines::_jfr_write_checkpoint_stub = generate_jfr_write_checkpoint(); - StubRoutines::_jfr_write_checkpoint = StubRoutines::_jfr_write_checkpoint_stub->entry_point(); - StubRoutines::_jfr_return_lease_stub = generate_jfr_return_lease(); - StubRoutines::_jfr_return_lease = StubRoutines::_jfr_return_lease_stub->entry_point(); } -#endif // INCLUDE_JFR void generate_final_stubs() { // Generates all stubs and initializes the entry points - // These entry points require SharedInfo::stack0 to be set up in - // non-core builds - StubRoutines::_throw_AbstractMethodError_entry = generate_throw_exception("AbstractMethodError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_AbstractMethodError), false); - // Handle IncompatibleClassChangeError in itable stubs. - StubRoutines::_throw_IncompatibleClassChangeError_entry= generate_throw_exception("IncompatibleClassChangeError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError), false); - StubRoutines::_throw_NullPointerException_at_call_entry= generate_throw_exception("NullPointerException at call throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException_at_call), false); - // support for verify_oop (must happen after universe_init) StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop(); diff --git a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp index 4caae200253..bb746619616 100644 --- a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp @@ -783,8 +783,8 @@ void TemplateInterpreterGenerator::generate_stack_overflow_check(Register Rmem_f __ bgt(CCR0/*is_stack_overflow*/, done); // The stack overflows. Load target address of the runtime stub and call it. - assert(StubRoutines::throw_StackOverflowError_entry() != nullptr, "generated in wrong order"); - __ load_const_optimized(Rscratch1, (StubRoutines::throw_StackOverflowError_entry()), R0); + assert(SharedRuntime::throw_StackOverflowError_entry() != nullptr, "generated in wrong order"); + __ load_const_optimized(Rscratch1, (SharedRuntime::throw_StackOverflowError_entry()), R0); __ mtctr(Rscratch1); // Restore caller_sp (c2i adapter may exist, but no shrinking of interpreted caller frame). #ifdef ASSERT diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index c6624cb45bb..32ccba6b0ce 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -4144,7 +4144,7 @@ void MacroAssembler::reserved_stack_check() { // We have already removed our own frame. // throw_delayed_StackOverflowError will think that it's been // called by our caller. - la(t0, RuntimeAddress(StubRoutines::throw_delayed_StackOverflowError_entry())); + la(t0, RuntimeAddress(SharedRuntime::throw_delayed_StackOverflowError_entry())); jr(t0); should_not_reach_here(); diff --git a/src/hotspot/cpu/riscv/methodHandles_riscv.cpp b/src/hotspot/cpu/riscv/methodHandles_riscv.cpp index fbb5b914038..deeb771d83b 100644 --- a/src/hotspot/cpu/riscv/methodHandles_riscv.cpp +++ b/src/hotspot/cpu/riscv/methodHandles_riscv.cpp @@ -120,7 +120,7 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register meth __ ld(t0,Address(method, entry_offset)); __ jr(t0); __ bind(L_no_such_method); - __ far_jump(RuntimeAddress(StubRoutines::throw_AbstractMethodError_entry())); + __ far_jump(RuntimeAddress(SharedRuntime::throw_AbstractMethodError_entry())); } void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm, @@ -441,7 +441,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, jump_from_method_handle(_masm, xmethod, temp1, for_compiler_entry); if (iid == vmIntrinsics::_linkToInterface) { __ bind(L_incompatible_class_change_error); - __ far_jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry())); + __ far_jump(RuntimeAddress(SharedRuntime::throw_IncompatibleClassChangeError_entry())); } } diff --git a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp index ad06f688d6a..bed24e442e8 100644 --- a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp +++ b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp @@ -48,6 +48,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/signature.hpp" #include "runtime/stubRoutines.hpp" +#include "runtime/timerTrace.hpp" #include "runtime/vframeArray.hpp" #include "utilities/align.hpp" #include "utilities/formatBuffer.hpp" @@ -65,6 +66,12 @@ #define __ masm-> +#ifdef PRODUCT +#define BLOCK_COMMENT(str) /* nothing */ +#else +#define BLOCK_COMMENT(str) __ block_comment(str) +#endif + const int StackAlignmentInSlots = StackAlignmentInBytes / VMRegImpl::stack_slot_size; class RegisterSaver { @@ -2628,3 +2635,191 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha // return the blob return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_in_words, oop_maps, true); } + +// Continuation point for throwing of implicit exceptions that are +// not handled in the current activation. Fabricates an exception +// oop and initiates normal exception dispatching in this +// frame. Since we need to preserve callee-saved values (currently +// only for C2, but done for C1 as well) we need a callee-saved oop +// map and therefore have to make these stubs into RuntimeStubs +// rather than BufferBlobs. If the compiler needs all registers to +// be preserved between the fault point and the exception handler +// then it must assume responsibility for that in +// AbstractCompiler::continuation_for_implicit_null_exception or +// continuation_for_implicit_division_by_zero_exception. All other +// implicit exceptions (e.g., NullPointerException or +// AbstractMethodError on entry) are either at call sites or +// otherwise assume that stack unwinding will be initiated, so +// caller saved registers were assumed volatile in the compiler. + +RuntimeStub* SharedRuntime::generate_throw_exception(const char* name, address runtime_entry) { + // Information about frame layout at time of blocking runtime call. + // Note that we only have to preserve callee-saved registers since + // the compilers are responsible for supplying a continuation point + // if they expect all registers to be preserved. + // n.b. riscv asserts that frame::arg_reg_save_area_bytes == 0 + assert_cond(runtime_entry != nullptr); + enum layout { + fp_off = 0, + fp_off2, + return_off, + return_off2, + framesize // inclusive of return address + }; + + const int insts_size = 1024; + const int locs_size = 64; + + ResourceMark rm; + const char* timer_msg = "SharedRuntime generate_throw_exception"; + TraceTime timer(timer_msg, TRACETIME_LOG(Info, startuptime)); + + CodeBuffer code(name, insts_size, locs_size); + OopMapSet* oop_maps = new OopMapSet(); + MacroAssembler* masm = new MacroAssembler(&code); + assert_cond(oop_maps != nullptr && masm != nullptr); + + address start = __ pc(); + + // This is an inlined and slightly modified version of call_VM + // which has the ability to fetch the return PC out of + // thread-local storage and also sets up last_Java_sp slightly + // differently than the real call_VM + + __ enter(); // Save FP and RA before call + + assert(is_even(framesize / 2), "sp not 16-byte aligned"); + + // ra and fp are already in place + __ addi(sp, fp, 0 - ((unsigned)framesize << LogBytesPerInt)); // prolog + + int frame_complete = __ pc() - start; + + // Set up last_Java_sp and last_Java_fp + address the_pc = __ pc(); + __ set_last_Java_frame(sp, fp, the_pc, t0); + + // Call runtime + __ mv(c_rarg0, xthread); + BLOCK_COMMENT("call runtime_entry"); + __ rt_call(runtime_entry); + + // Generate oop map + OopMap* map = new OopMap(framesize, 0); + assert_cond(map != nullptr); + + oop_maps->add_gc_map(the_pc - start, map); + + __ reset_last_Java_frame(true); + + __ leave(); + + // check for pending exceptions +#ifdef ASSERT + Label L; + __ ld(t0, Address(xthread, Thread::pending_exception_offset())); + __ bnez(t0, L); + __ should_not_reach_here(); + __ bind(L); +#endif // ASSERT + __ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry())); + + // codeBlob framesize is in words (not VMRegImpl::slot_size) + RuntimeStub* stub = + RuntimeStub::new_runtime_stub(name, + &code, + frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, false); + assert(stub != nullptr, "create runtime stub fail!"); + return stub; +} + +#if INCLUDE_JFR + +static void jfr_prologue(address the_pc, MacroAssembler* masm, Register thread) { + __ set_last_Java_frame(sp, fp, the_pc, t0); + __ mv(c_rarg0, thread); +} + +static void jfr_epilogue(MacroAssembler* masm) { + __ reset_last_Java_frame(true); +} +// For c2: c_rarg0 is junk, call to runtime to write a checkpoint. +// It returns a jobject handle to the event writer. +// The handle is dereferenced and the return value is the event writer oop. +RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { + enum layout { + fp_off, + fp_off2, + return_off, + return_off2, + framesize // inclusive of return address + }; + + int insts_size = 1024; + int locs_size = 64; + CodeBuffer code("jfr_write_checkpoint", insts_size, locs_size); + OopMapSet* oop_maps = new OopMapSet(); + MacroAssembler* masm = new MacroAssembler(&code); + + address start = __ pc(); + __ enter(); + int frame_complete = __ pc() - start; + address the_pc = __ pc(); + jfr_prologue(the_pc, masm, xthread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), 1); + + jfr_epilogue(masm); + __ resolve_global_jobject(x10, t0, t1); + __ leave(); + __ ret(); + + OopMap* map = new OopMap(framesize, 1); + oop_maps->add_gc_map(the_pc - start, map); + + RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) + RuntimeStub::new_runtime_stub("jfr_write_checkpoint", &code, frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, false); + return stub; +} + +// For c2: call to return a leased buffer. +RuntimeStub* SharedRuntime::generate_jfr_return_lease() { + enum layout { + fp_off, + fp_off2, + return_off, + return_off2, + framesize // inclusive of return address + }; + + int insts_size = 1024; + int locs_size = 64; + CodeBuffer code("jfr_return_lease", insts_size, locs_size); + OopMapSet* oop_maps = new OopMapSet(); + MacroAssembler* masm = new MacroAssembler(&code); + + address start = __ pc(); + __ enter(); + int frame_complete = __ pc() - start; + address the_pc = __ pc(); + jfr_prologue(the_pc, masm, xthread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), 1); + + jfr_epilogue(masm); + __ leave(); + __ ret(); + + OopMap* map = new OopMap(framesize, 1); + oop_maps->add_gc_map(the_pc - start, map); + + RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) + RuntimeStub::new_runtime_stub("jfr_return_lease", &code, frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, false); + return stub; +} + +#endif // INCLUDE_JFR diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index 6a2c6c7d6c9..f214c489557 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -3774,7 +3774,7 @@ class StubGenerator: public StubCodeGenerator { Label thaw_success; // t1 contains the size of the frames to thaw, 0 if overflow or no more frames __ bnez(t1, thaw_success); - __ la(t0, RuntimeAddress(StubRoutines::throw_StackOverflowError_entry())); + __ la(t0, RuntimeAddress(SharedRuntime::throw_StackOverflowError_entry())); __ jr(t0); __ bind(thaw_success); @@ -5834,97 +5834,6 @@ static const int64_t right_3_bits = right_n_bits(3); return start; } -#if INCLUDE_JFR - - static void jfr_prologue(address the_pc, MacroAssembler* _masm, Register thread) { - __ set_last_Java_frame(sp, fp, the_pc, t0); - __ mv(c_rarg0, thread); - } - - static void jfr_epilogue(MacroAssembler* _masm) { - __ reset_last_Java_frame(true); - } - // For c2: c_rarg0 is junk, call to runtime to write a checkpoint. - // It returns a jobject handle to the event writer. - // The handle is dereferenced and the return value is the event writer oop. - static RuntimeStub* generate_jfr_write_checkpoint() { - enum layout { - fp_off, - fp_off2, - return_off, - return_off2, - framesize // inclusive of return address - }; - - int insts_size = 1024; - int locs_size = 64; - CodeBuffer code("jfr_write_checkpoint", insts_size, locs_size); - OopMapSet* oop_maps = new OopMapSet(); - MacroAssembler* masm = new MacroAssembler(&code); - MacroAssembler* _masm = masm; - - address start = __ pc(); - __ enter(); - int frame_complete = __ pc() - start; - address the_pc = __ pc(); - jfr_prologue(the_pc, _masm, xthread); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), 1); - - jfr_epilogue(_masm); - __ resolve_global_jobject(x10, t0, t1); - __ leave(); - __ ret(); - - OopMap* map = new OopMap(framesize, 1); - oop_maps->add_gc_map(the_pc - start, map); - - RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) - RuntimeStub::new_runtime_stub("jfr_write_checkpoint", &code, frame_complete, - (framesize >> (LogBytesPerWord - LogBytesPerInt)), - oop_maps, false); - return stub; - } - - // For c2: call to return a leased buffer. - static RuntimeStub* generate_jfr_return_lease() { - enum layout { - fp_off, - fp_off2, - return_off, - return_off2, - framesize // inclusive of return address - }; - - int insts_size = 1024; - int locs_size = 64; - CodeBuffer code("jfr_return_lease", insts_size, locs_size); - OopMapSet* oop_maps = new OopMapSet(); - MacroAssembler* masm = new MacroAssembler(&code); - MacroAssembler* _masm = masm; - - address start = __ pc(); - __ enter(); - int frame_complete = __ pc() - start; - address the_pc = __ pc(); - jfr_prologue(the_pc, _masm, xthread); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), 1); - - jfr_epilogue(_masm); - __ leave(); - __ ret(); - - OopMap* map = new OopMap(framesize, 1); - oop_maps->add_gc_map(the_pc - start, map); - - RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) - RuntimeStub::new_runtime_stub("jfr_return_lease", &code, frame_complete, - (framesize >> (LogBytesPerWord - LogBytesPerInt)), - oop_maps, false); - return stub; - } - -#endif // INCLUDE_JFR - // exception handler for upcall stubs address generate_upcall_stub_exception_handler() { StubCodeMark mark(this, "StubRoutines", "upcall stub exception handler"); @@ -5939,114 +5848,6 @@ static const int64_t right_3_bits = right_n_bits(3); return start; } - // Continuation point for throwing of implicit exceptions that are - // not handled in the current activation. Fabricates an exception - // oop and initiates normal exception dispatching in this - // frame. Since we need to preserve callee-saved values (currently - // only for C2, but done for C1 as well) we need a callee-saved oop - // map and therefore have to make these stubs into RuntimeStubs - // rather than BufferBlobs. If the compiler needs all registers to - // be preserved between the fault point and the exception handler - // then it must assume responsibility for that in - // AbstractCompiler::continuation_for_implicit_null_exception or - // continuation_for_implicit_division_by_zero_exception. All other - // implicit exceptions (e.g., NullPointerException or - // AbstractMethodError on entry) are either at call sites or - // otherwise assume that stack unwinding will be initiated, so - // caller saved registers were assumed volatile in the compiler. - -#undef __ -#define __ masm-> - - address generate_throw_exception(const char* name, - address runtime_entry, - Register arg1 = noreg, - Register arg2 = noreg) { - // Information about frame layout at time of blocking runtime call. - // Note that we only have to preserve callee-saved registers since - // the compilers are responsible for supplying a continuation point - // if they expect all registers to be preserved. - // n.b. riscv asserts that frame::arg_reg_save_area_bytes == 0 - assert_cond(runtime_entry != nullptr); - enum layout { - fp_off = 0, - fp_off2, - return_off, - return_off2, - framesize // inclusive of return address - }; - - const int insts_size = 1024; - const int locs_size = 64; - - CodeBuffer code(name, insts_size, locs_size); - OopMapSet* oop_maps = new OopMapSet(); - MacroAssembler* masm = new MacroAssembler(&code); - assert_cond(oop_maps != nullptr && masm != nullptr); - - address start = __ pc(); - - // This is an inlined and slightly modified version of call_VM - // which has the ability to fetch the return PC out of - // thread-local storage and also sets up last_Java_sp slightly - // differently than the real call_VM - - __ enter(); // Save FP and RA before call - - assert(is_even(framesize / 2), "sp not 16-byte aligned"); - - // ra and fp are already in place - __ addi(sp, fp, 0 - ((unsigned)framesize << LogBytesPerInt)); // prolog - - int frame_complete = __ pc() - start; - - // Set up last_Java_sp and last_Java_fp - address the_pc = __ pc(); - __ set_last_Java_frame(sp, fp, the_pc, t0); - - // Call runtime - if (arg1 != noreg) { - assert(arg2 != c_rarg1, "clobbered"); - __ mv(c_rarg1, arg1); - } - if (arg2 != noreg) { - __ mv(c_rarg2, arg2); - } - __ mv(c_rarg0, xthread); - BLOCK_COMMENT("call runtime_entry"); - __ rt_call(runtime_entry); - - // Generate oop map - OopMap* map = new OopMap(framesize, 0); - assert_cond(map != nullptr); - - oop_maps->add_gc_map(the_pc - start, map); - - __ reset_last_Java_frame(true); - - __ leave(); - - // check for pending exceptions -#ifdef ASSERT - Label L; - __ ld(t0, Address(xthread, Thread::pending_exception_offset())); - __ bnez(t0, L); - __ should_not_reach_here(); - __ bind(L); -#endif // ASSERT - __ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry())); - - // codeBlob framesize is in words (not VMRegImpl::slot_size) - RuntimeStub* stub = - RuntimeStub::new_runtime_stub(name, - &code, - frame_complete, - (framesize >> (LogBytesPerWord - LogBytesPerInt)), - oop_maps, false); - assert(stub != nullptr, "create runtime stub fail!"); - return stub->entry_point(); - } - #undef __ // Initialization @@ -6071,16 +5872,6 @@ static const int64_t right_3_bits = right_n_bits(3); // is referenced by megamorphic call StubRoutines::_catch_exception_entry = generate_catch_exception(); - // Build this early so it's available for the interpreter. - StubRoutines::_throw_StackOverflowError_entry = - generate_throw_exception("StackOverflowError throw_exception", - CAST_FROM_FN_PTR(address, - SharedRuntime::throw_StackOverflowError)); - StubRoutines::_throw_delayed_StackOverflowError_entry = - generate_throw_exception("delayed StackOverflowError throw_exception", - CAST_FROM_FN_PTR(address, - SharedRuntime::throw_delayed_StackOverflowError)); - if (UseCRC32Intrinsics) { // set table address before stub generation which use it StubRoutines::_crc_table_adr = (address)StubRoutines::riscv::_crc_table; @@ -6093,42 +5884,14 @@ static const int64_t right_3_bits = right_n_bits(3); StubRoutines::_cont_thaw = generate_cont_thaw(); StubRoutines::_cont_returnBarrier = generate_cont_returnBarrier(); StubRoutines::_cont_returnBarrierExc = generate_cont_returnBarrier_exception(); - - JFR_ONLY(generate_jfr_stubs();) } -#if INCLUDE_JFR - void generate_jfr_stubs() { - StubRoutines::_jfr_write_checkpoint_stub = generate_jfr_write_checkpoint(); - StubRoutines::_jfr_write_checkpoint = StubRoutines::_jfr_write_checkpoint_stub->entry_point(); - StubRoutines::_jfr_return_lease_stub = generate_jfr_return_lease(); - StubRoutines::_jfr_return_lease = StubRoutines::_jfr_return_lease_stub->entry_point(); - } -#endif // INCLUDE_JFR - void generate_final_stubs() { // support for verify_oop (must happen after universe_init) if (VerifyOops) { StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop(); } - StubRoutines::_throw_AbstractMethodError_entry = - generate_throw_exception("AbstractMethodError throw_exception", - CAST_FROM_FN_PTR(address, - SharedRuntime:: - throw_AbstractMethodError)); - - StubRoutines::_throw_IncompatibleClassChangeError_entry = - generate_throw_exception("IncompatibleClassChangeError throw_exception", - CAST_FROM_FN_PTR(address, - SharedRuntime:: - throw_IncompatibleClassChangeError)); - - StubRoutines::_throw_NullPointerException_at_call_entry = - generate_throw_exception("NullPointerException at call throw_exception", - CAST_FROM_FN_PTR(address, - SharedRuntime:: - throw_NullPointerException_at_call)); // arraycopy stubs used by compilers generate_arraycopy_stubs(); diff --git a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp index f01945bc6a3..1f32488777d 100644 --- a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp @@ -658,8 +658,8 @@ void TemplateInterpreterGenerator::generate_stack_overflow_check(void) { // Note: the restored frame is not necessarily interpreted. // Use the shared runtime version of the StackOverflowError. - assert(StubRoutines::throw_StackOverflowError_entry() != nullptr, "stub not yet generated"); - __ far_jump(RuntimeAddress(StubRoutines::throw_StackOverflowError_entry())); + assert(SharedRuntime::throw_StackOverflowError_entry() != nullptr, "stub not yet generated"); + __ far_jump(RuntimeAddress(SharedRuntime::throw_StackOverflowError_entry())); // all done with frame size check __ bind(after_frame_check); diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp index b72b36eef53..a233934405f 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp @@ -2751,7 +2751,7 @@ void MacroAssembler::reserved_stack_check(Register return_pc) { pop_frame(); restore_return_pc(); - load_const_optimized(Z_R1, StubRoutines::throw_delayed_StackOverflowError_entry()); + load_const_optimized(Z_R1, SharedRuntime::throw_delayed_StackOverflowError_entry()); // Don't use call() or z_basr(), they will invalidate Z_R14 which contains the return pc. z_br(Z_R1); diff --git a/src/hotspot/cpu/s390/methodHandles_s390.cpp b/src/hotspot/cpu/s390/methodHandles_s390.cpp index ef8722f2499..b42822a6eee 100644 --- a/src/hotspot/cpu/s390/methodHandles_s390.cpp +++ b/src/hotspot/cpu/s390/methodHandles_s390.cpp @@ -180,8 +180,8 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register meth __ z_br(target); __ bind(L_no_such_method); - assert(StubRoutines::throw_AbstractMethodError_entry() != nullptr, "not yet generated!"); - __ load_const_optimized(target, StubRoutines::throw_AbstractMethodError_entry()); + assert(SharedRuntime::throw_AbstractMethodError_entry() != nullptr, "not yet generated!"); + __ load_const_optimized(target, SharedRuntime::throw_AbstractMethodError_entry()); __ z_br(target); } @@ -543,7 +543,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, __ bind(L_no_such_interface); // Throw exception. - __ load_const_optimized(Z_R1, StubRoutines::throw_IncompatibleClassChangeError_entry()); + __ load_const_optimized(Z_R1, SharedRuntime::throw_IncompatibleClassChangeError_entry()); __ z_br(Z_R1); break; } diff --git a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp index 641b3712a17..364ef948d91 100644 --- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp +++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp @@ -3010,6 +3010,85 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha } +// Continuation point for throwing of implicit exceptions that are +// not handled in the current activation. Fabricates an exception +// oop and initiates normal exception dispatching in this +// frame. Only callee-saved registers are preserved (through the +// normal RegisterMap handling). If the compiler +// needs all registers to be preserved between the fault point and +// the exception handler then it must assume responsibility for that +// in AbstractCompiler::continuation_for_implicit_null_exception or +// continuation_for_implicit_division_by_zero_exception. All other +// implicit exceptions (e.g., NullPointerException or +// AbstractMethodError on entry) are either at call sites or +// otherwise assume that stack unwinding will be initiated, so +// caller saved registers were assumed volatile in the compiler. + +// Note that we generate only this stub into a RuntimeStub, because +// it needs to be properly traversed and ignored during GC, so we +// change the meaning of the "__" macro within this method. + +// Note: the routine set_pc_not_at_call_for_caller in +// SharedRuntime.cpp requires that this code be generated into a +// RuntimeStub. + +RuntimeStub* SharedRuntime::generate_throw_exception(const char* name, address runtime_entry) { + + int insts_size = 256; + int locs_size = 0; + + ResourceMark rm; + const char* timer_msg = "SharedRuntime generate_throw_exception"; + TraceTime timer(timer_msg, TRACETIME_LOG(Info, startuptime)); + + CodeBuffer code(name, insts_size, locs_size); + MacroAssembler* masm = new MacroAssembler(&code); + int framesize_in_bytes; + address start = __ pc(); + + __ save_return_pc(); + framesize_in_bytes = __ push_frame_abi160(0); + + address frame_complete_pc = __ pc(); + + // Note that we always have a runtime stub frame on the top of stack at this point. + __ get_PC(Z_R1); + __ set_last_Java_frame(/*sp*/Z_SP, /*pc*/Z_R1); + + // Do the call. + BLOCK_COMMENT("call runtime_entry"); + __ call_VM_leaf(runtime_entry, Z_thread); + + __ reset_last_Java_frame(); + +#ifdef ASSERT + // Make sure that this code is only executed if there is a pending exception. + { Label L; + __ z_lg(Z_R0, + in_bytes(Thread::pending_exception_offset()), + Z_thread); + __ z_ltgr(Z_R0, Z_R0); + __ z_brne(L); + __ stop("SharedRuntime::throw_exception: no pending exception"); + __ bind(L); + } +#endif + + __ pop_frame(); + __ restore_return_pc(); + + __ load_const_optimized(Z_R1, StubRoutines::forward_exception_entry()); + __ z_br(Z_R1); + + RuntimeStub* stub = + RuntimeStub::new_runtime_stub(name, &code, + frame_complete_pc - start, + framesize_in_bytes/wordSize, + nullptr /*oop_maps*/, false); + + return stub; +} + //------------------------------Montgomery multiplication------------------------ // @@ -3263,3 +3342,18 @@ extern "C" int SpinPause() { return 0; } + +#if INCLUDE_JFR +RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { + if (!Continuations::enabled()) return nullptr; + Unimplemented(); + return nullptr; +} + +RuntimeStub* SharedRuntime::generate_jfr_return_lease() { + if (!Continuations::enabled()) return nullptr; + Unimplemented(); + return nullptr; +} + +#endif // INCLUDE_JFR diff --git a/src/hotspot/cpu/s390/stubGenerator_s390.cpp b/src/hotspot/cpu/s390/stubGenerator_s390.cpp index 556c0d4703d..d878731cca5 100644 --- a/src/hotspot/cpu/s390/stubGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/stubGenerator_s390.cpp @@ -572,89 +572,6 @@ class StubGenerator: public StubCodeGenerator { #undef pending_exception_offset } - // Continuation point for throwing of implicit exceptions that are - // not handled in the current activation. Fabricates an exception - // oop and initiates normal exception dispatching in this - // frame. Only callee-saved registers are preserved (through the - // normal RegisterMap handling). If the compiler - // needs all registers to be preserved between the fault point and - // the exception handler then it must assume responsibility for that - // in AbstractCompiler::continuation_for_implicit_null_exception or - // continuation_for_implicit_division_by_zero_exception. All other - // implicit exceptions (e.g., NullPointerException or - // AbstractMethodError on entry) are either at call sites or - // otherwise assume that stack unwinding will be initiated, so - // caller saved registers were assumed volatile in the compiler. - - // Note that we generate only this stub into a RuntimeStub, because - // it needs to be properly traversed and ignored during GC, so we - // change the meaning of the "__" macro within this method. - - // Note: the routine set_pc_not_at_call_for_caller in - // SharedRuntime.cpp requires that this code be generated into a - // RuntimeStub. -#undef __ -#define __ masm-> - - address generate_throw_exception(const char* name, address runtime_entry, - bool restore_saved_exception_pc, - Register arg1 = noreg, Register arg2 = noreg) { - assert_different_registers(arg1, Z_R0_scratch); // would be destroyed by push_frame() - assert_different_registers(arg2, Z_R0_scratch); // would be destroyed by push_frame() - - int insts_size = 256; - int locs_size = 0; - CodeBuffer code(name, insts_size, locs_size); - MacroAssembler* masm = new MacroAssembler(&code); - int framesize_in_bytes; - address start = __ pc(); - - __ save_return_pc(); - framesize_in_bytes = __ push_frame_abi160(0); - - address frame_complete_pc = __ pc(); - if (restore_saved_exception_pc) { - __ unimplemented("StubGenerator::throw_exception", 74); - } - - // Note that we always have a runtime stub frame on the top of stack at this point. - __ get_PC(Z_R1); - __ set_last_Java_frame(/*sp*/Z_SP, /*pc*/Z_R1); - - // Do the call. - BLOCK_COMMENT("call runtime_entry"); - __ call_VM_leaf(runtime_entry, Z_thread, arg1, arg2); - - __ reset_last_Java_frame(); - -#ifdef ASSERT - // Make sure that this code is only executed if there is a pending exception. - { Label L; - __ z_lg(Z_R0, - in_bytes(Thread::pending_exception_offset()), - Z_thread); - __ z_ltgr(Z_R0, Z_R0); - __ z_brne(L); - __ stop("StubRoutines::throw_exception: no pending exception"); - __ bind(L); - } -#endif - - __ pop_frame(); - __ restore_return_pc(); - - __ load_const_optimized(Z_R1, StubRoutines::forward_exception_entry()); - __ z_br(Z_R1); - - RuntimeStub* stub = - RuntimeStub::new_runtime_stub(name, &code, - frame_complete_pc - start, - framesize_in_bytes/wordSize, - nullptr /*oop_maps*/, false); - - return stub->entry_point(); - } - #undef __ #ifdef PRODUCT #define __ _masm-> @@ -3121,21 +3038,6 @@ class StubGenerator: public StubCodeGenerator { return nullptr; } - #if INCLUDE_JFR - RuntimeStub* generate_jfr_write_checkpoint() { - if (!Continuations::enabled()) return nullptr; - Unimplemented(); - return nullptr; - } - - RuntimeStub* generate_jfr_return_lease() { - if (!Continuations::enabled()) return nullptr; - Unimplemented(); - return nullptr; - } - - #endif // INCLUDE_JFR - // exception handler for upcall stubs address generate_upcall_stub_exception_handler() { StubCodeMark mark(this, "StubRoutines", "upcall stub exception handler"); @@ -3164,14 +3066,6 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_call_stub_entry = generate_call_stub(StubRoutines::_call_stub_return_address); StubRoutines::_catch_exception_entry = generate_catch_exception(); - // Build this early so it's available for the interpreter. - StubRoutines::_throw_StackOverflowError_entry = - generate_throw_exception("StackOverflowError throw_exception", - CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError), false); - StubRoutines::_throw_delayed_StackOverflowError_entry = - generate_throw_exception("delayed StackOverflowError throw_exception", - CAST_FROM_FN_PTR(address, SharedRuntime::throw_delayed_StackOverflowError), false); - //---------------------------------------------------------------------- // Entry points that are platform specific. @@ -3196,29 +3090,13 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_cont_thaw = generate_cont_thaw(); StubRoutines::_cont_returnBarrier = generate_cont_returnBarrier(); StubRoutines::_cont_returnBarrierExc = generate_cont_returnBarrier_exception(); - - JFR_ONLY(generate_jfr_stubs();) } -#if INCLUDE_JFR - void generate_jfr_stubs() { - StubRoutines::_jfr_write_checkpoint_stub = generate_jfr_write_checkpoint(); - StubRoutines::_jfr_write_checkpoint = StubRoutines::_jfr_write_checkpoint_stub->entry_point(); - StubRoutines::_jfr_return_lease_stub = generate_jfr_return_lease(); - StubRoutines::_jfr_return_lease = StubRoutines::_jfr_return_lease_stub->entry_point(); - } -#endif // INCLUDE_JFR - void generate_final_stubs() { // Generates all stubs and initializes the entry points. StubRoutines::zarch::_partial_subtype_check = generate_partial_subtype_check(); - // These entry points require SharedInfo::stack0 to be set up in non-core builds. - StubRoutines::_throw_AbstractMethodError_entry = generate_throw_exception("AbstractMethodError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_AbstractMethodError), false); - StubRoutines::_throw_IncompatibleClassChangeError_entry= generate_throw_exception("IncompatibleClassChangeError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError), false); - StubRoutines::_throw_NullPointerException_at_call_entry= generate_throw_exception("NullPointerException at call throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException_at_call), false); - // Support for verify_oop (must happen after universe_init). StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop_subroutine(); diff --git a/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp b/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp index 87025826400..c16e4449045 100644 --- a/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp @@ -850,9 +850,9 @@ void TemplateInterpreterGenerator::generate_stack_overflow_check(Register frame_ // Note also that the restored frame is not necessarily interpreted. // Use the shared runtime version of the StackOverflowError. - assert(StubRoutines::throw_StackOverflowError_entry() != nullptr, "stub not yet generated"); - AddressLiteral stub(StubRoutines::throw_StackOverflowError_entry()); - __ load_absolute_address(tmp1, StubRoutines::throw_StackOverflowError_entry()); + assert(SharedRuntime::throw_StackOverflowError_entry() != nullptr, "stub not yet generated"); + AddressLiteral stub(SharedRuntime::throw_StackOverflowError_entry()); + __ load_absolute_address(tmp1, SharedRuntime::throw_StackOverflowError_entry()); __ z_br(tmp1); // If you get to here, then there is enough stack space. diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index a5ad19806ea..ba337751d19 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -1303,7 +1303,7 @@ void MacroAssembler::reserved_stack_check() { jcc(Assembler::below, no_reserved_zone_enabling); call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), thread); - jump(RuntimeAddress(StubRoutines::throw_delayed_StackOverflowError_entry())); + jump(RuntimeAddress(SharedRuntime::throw_delayed_StackOverflowError_entry())); should_not_reach_here(); bind(no_reserved_zone_enabling); diff --git a/src/hotspot/cpu/x86/methodHandles_x86.cpp b/src/hotspot/cpu/x86/methodHandles_x86.cpp index 3a8c1048766..fd738b7333e 100644 --- a/src/hotspot/cpu/x86/methodHandles_x86.cpp +++ b/src/hotspot/cpu/x86/methodHandles_x86.cpp @@ -159,7 +159,7 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register meth __ jmp(Address(method, entry_offset)); __ bind(L_no_such_method); - __ jump(RuntimeAddress(StubRoutines::throw_AbstractMethodError_entry())); + __ jump(RuntimeAddress(SharedRuntime::throw_AbstractMethodError_entry())); } void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm, @@ -510,7 +510,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, if (iid == vmIntrinsics::_linkToInterface) { __ bind(L_incompatible_class_change_error); - __ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry())); + __ jump(RuntimeAddress(SharedRuntime::throw_IncompatibleClassChangeError_entry())); } } } diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp index 85c9125a97d..273bbcc6525 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp @@ -43,6 +43,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/signature.hpp" #include "runtime/stubRoutines.hpp" +#include "runtime/timerTrace.hpp" #include "runtime/vframeArray.hpp" #include "runtime/vm_version.hpp" #include "utilities/align.hpp" @@ -56,6 +57,12 @@ #define __ masm-> +#ifdef PRODUCT +#define BLOCK_COMMENT(str) /* nothing */ +#else +#define BLOCK_COMMENT(str) __ block_comment(str) +#endif // PRODUCT + const int StackAlignmentInSlots = StackAlignmentInBytes / VMRegImpl::stack_slot_size; class RegisterSaver { @@ -2631,3 +2638,207 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha // frame_size_words or bytes?? return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_words, oop_maps, true); } + + //------------------------------------------------------------------------------------------------------------------------ + // Continuation point for throwing of implicit exceptions that are not handled in + // the current activation. Fabricates an exception oop and initiates normal + // exception dispatching in this frame. + // + // Previously the compiler (c2) allowed for callee save registers on Java calls. + // This is no longer true after adapter frames were removed but could possibly + // be brought back in the future if the interpreter code was reworked and it + // was deemed worthwhile. The comment below was left to describe what must + // happen here if callee saves were resurrected. As it stands now this stub + // could actually be a vanilla BufferBlob and have now oopMap at all. + // Since it doesn't make much difference we've chosen to leave it the + // way it was in the callee save days and keep the comment. + + // If we need to preserve callee-saved values we need a callee-saved oop map and + // therefore have to make these stubs into RuntimeStubs rather than BufferBlobs. + // If the compiler needs all registers to be preserved between the fault + // point and the exception handler then it must assume responsibility for that in + // AbstractCompiler::continuation_for_implicit_null_exception or + // continuation_for_implicit_division_by_zero_exception. All other implicit + // exceptions (e.g., NullPointerException or AbstractMethodError on entry) are + // either at call sites or otherwise assume that stack unwinding will be initiated, + // so caller saved registers were assumed volatile in the compiler. +RuntimeStub* SharedRuntime::generate_throw_exception(const char* name, address runtime_entry) { + + // Information about frame layout at time of blocking runtime call. + // Note that we only have to preserve callee-saved registers since + // the compilers are responsible for supplying a continuation point + // if they expect all registers to be preserved. + enum layout { + thread_off, // last_java_sp + arg1_off, + arg2_off, + rbp_off, // callee saved register + ret_pc, + framesize + }; + + int insts_size = 256; + int locs_size = 32; + + ResourceMark rm; + const char* timer_msg = "SharedRuntime generate_throw_exception"; + TraceTime timer(timer_msg, TRACETIME_LOG(Info, startuptime)); + + CodeBuffer code(name, insts_size, locs_size); + OopMapSet* oop_maps = new OopMapSet(); + MacroAssembler* masm = new MacroAssembler(&code); + + address start = __ pc(); + + // This is an inlined and slightly modified version of call_VM + // which has the ability to fetch the return PC out of + // thread-local storage and also sets up last_Java_sp slightly + // differently than the real call_VM + Register java_thread = rbx; + __ get_thread(java_thread); + + __ enter(); // required for proper stackwalking of RuntimeStub frame + + // pc and rbp, already pushed + __ subptr(rsp, (framesize-2) * wordSize); // prolog + + // Frame is now completed as far as size and linkage. + + int frame_complete = __ pc() - start; + + // push java thread (becomes first argument of C function) + __ movptr(Address(rsp, thread_off * wordSize), java_thread); + // Set up last_Java_sp and last_Java_fp + __ set_last_Java_frame(java_thread, rsp, rbp, nullptr, noreg); + + // Call runtime + BLOCK_COMMENT("call runtime_entry"); + __ call(RuntimeAddress(runtime_entry)); + // Generate oop map + OopMap* map = new OopMap(framesize, 0); + oop_maps->add_gc_map(__ pc() - start, map); + + // restore the thread (cannot use the pushed argument since arguments + // may be overwritten by C code generated by an optimizing compiler); + // however can use the register value directly if it is callee saved. + __ get_thread(java_thread); + + __ reset_last_Java_frame(java_thread, true); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + + // check for pending exceptions +#ifdef ASSERT + Label L; + __ cmpptr(Address(java_thread, Thread::pending_exception_offset()), NULL_WORD); + __ jcc(Assembler::notEqual, L); + __ should_not_reach_here(); + __ bind(L); +#endif /* ASSERT */ + __ jump(RuntimeAddress(StubRoutines::forward_exception_entry())); + + + RuntimeStub* stub = RuntimeStub::new_runtime_stub(name, &code, frame_complete, framesize, oop_maps, false); + return stub; +} + +#if INCLUDE_JFR + +static void jfr_prologue(address the_pc, MacroAssembler* masm) { + Register java_thread = rdi; + __ get_thread(java_thread); + __ set_last_Java_frame(java_thread, rsp, rbp, the_pc, noreg); + __ movptr(Address(rsp, 0), java_thread); +} + +// The handle is dereferenced through a load barrier. +static void jfr_epilogue(MacroAssembler* masm) { + Register java_thread = rdi; + __ get_thread(java_thread); + __ reset_last_Java_frame(java_thread, true); +} + +// For c2: c_rarg0 is junk, call to runtime to write a checkpoint. +// It returns a jobject handle to the event writer. +// The handle is dereferenced and the return value is the event writer oop. +RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { + enum layout { + FPUState_off = 0, + rbp_off = FPUStateSizeInWords, + rdi_off, + rsi_off, + rcx_off, + rbx_off, + saved_argument_off, + saved_argument_off2, // 2nd half of double + framesize + }; + + int insts_size = 1024; + int locs_size = 64; + CodeBuffer code("jfr_write_checkpoint", insts_size, locs_size); + OopMapSet* oop_maps = new OopMapSet(); + MacroAssembler* masm = new MacroAssembler(&code); + + address start = __ pc(); + __ enter(); + int frame_complete = __ pc() - start; + address the_pc = __ pc(); + jfr_prologue(the_pc, masm); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), 1); + jfr_epilogue(masm); + __ resolve_global_jobject(rax, rdi, rdx); + __ leave(); + __ ret(0); + + OopMap* map = new OopMap(framesize, 1); // rbp + oop_maps->add_gc_map(the_pc - start, map); + + RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) + RuntimeStub::new_runtime_stub("jfr_write_checkpoint", &code, frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, false); + return stub; +} + +// For c2: call to return a leased buffer. +RuntimeStub* SharedRuntime::generate_jfr_return_lease() { + enum layout { + FPUState_off = 0, + rbp_off = FPUStateSizeInWords, + rdi_off, + rsi_off, + rcx_off, + rbx_off, + saved_argument_off, + saved_argument_off2, // 2nd half of double + framesize + }; + + int insts_size = 1024; + int locs_size = 64; + CodeBuffer code("jfr_return_lease", insts_size, locs_size); + OopMapSet* oop_maps = new OopMapSet(); + MacroAssembler* masm = new MacroAssembler(&code); + + address start = __ pc(); + __ enter(); + int frame_complete = __ pc() - start; + address the_pc = __ pc(); + jfr_prologue(the_pc, masm); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), 1); + jfr_epilogue(masm); + __ leave(); + __ ret(0); + + OopMap* map = new OopMap(framesize, 1); // rbp + oop_maps->add_gc_map(the_pc - start, map); + + RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) + RuntimeStub::new_runtime_stub("jfr_return_lease", &code, frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, false); + return stub; +} + +#endif // INCLUDE_JFR diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index b5362a9942c..05ec85ef09a 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -52,6 +52,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/signature.hpp" #include "runtime/stubRoutines.hpp" +#include "runtime/timerTrace.hpp" #include "runtime/vframeArray.hpp" #include "runtime/vm_version.hpp" #include "utilities/align.hpp" @@ -70,6 +71,12 @@ #define __ masm-> +#ifdef PRODUCT +#define BLOCK_COMMENT(str) /* nothing */ +#else +#define BLOCK_COMMENT(str) __ block_comment(str) +#endif // PRODUCT + const int StackAlignmentInSlots = StackAlignmentInBytes / VMRegImpl::stack_slot_size; class RegisterSaver { @@ -3210,6 +3217,101 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_in_words, oop_maps, true); } +// Continuation point for throwing of implicit exceptions that are +// not handled in the current activation. Fabricates an exception +// oop and initiates normal exception dispatching in this +// frame. Since we need to preserve callee-saved values (currently +// only for C2, but done for C1 as well) we need a callee-saved oop +// map and therefore have to make these stubs into RuntimeStubs +// rather than BufferBlobs. If the compiler needs all registers to +// be preserved between the fault point and the exception handler +// then it must assume responsibility for that in +// AbstractCompiler::continuation_for_implicit_null_exception or +// continuation_for_implicit_division_by_zero_exception. All other +// implicit exceptions (e.g., NullPointerException or +// AbstractMethodError on entry) are either at call sites or +// otherwise assume that stack unwinding will be initiated, so +// caller saved registers were assumed volatile in the compiler. +RuntimeStub* SharedRuntime::generate_throw_exception(const char* name, address runtime_entry) { + // Information about frame layout at time of blocking runtime call. + // Note that we only have to preserve callee-saved registers since + // the compilers are responsible for supplying a continuation point + // if they expect all registers to be preserved. + enum layout { + rbp_off = frame::arg_reg_save_area_bytes/BytesPerInt, + rbp_off2, + return_off, + return_off2, + framesize // inclusive of return address + }; + + int insts_size = 512; + int locs_size = 64; + + ResourceMark rm; + const char* timer_msg = "SharedRuntime generate_throw_exception"; + TraceTime timer(timer_msg, TRACETIME_LOG(Info, startuptime)); + + CodeBuffer code(name, insts_size, locs_size); + OopMapSet* oop_maps = new OopMapSet(); + MacroAssembler* masm = new MacroAssembler(&code); + + address start = __ pc(); + + // This is an inlined and slightly modified version of call_VM + // which has the ability to fetch the return PC out of + // thread-local storage and also sets up last_Java_sp slightly + // differently than the real call_VM + + __ enter(); // required for proper stackwalking of RuntimeStub frame + + assert(is_even(framesize/2), "sp not 16-byte aligned"); + + // return address and rbp are already in place + __ subptr(rsp, (framesize-4) << LogBytesPerInt); // prolog + + int frame_complete = __ pc() - start; + + // Set up last_Java_sp and last_Java_fp + address the_pc = __ pc(); + __ set_last_Java_frame(rsp, rbp, the_pc, rscratch1); + __ andptr(rsp, -(StackAlignmentInBytes)); // Align stack + + // Call runtime + __ movptr(c_rarg0, r15_thread); + BLOCK_COMMENT("call runtime_entry"); + __ call(RuntimeAddress(runtime_entry)); + + // Generate oop map + OopMap* map = new OopMap(framesize, 0); + + oop_maps->add_gc_map(the_pc - start, map); + + __ reset_last_Java_frame(true); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + + // check for pending exceptions +#ifdef ASSERT + Label L; + __ cmpptr(Address(r15_thread, Thread::pending_exception_offset()), NULL_WORD); + __ jcc(Assembler::notEqual, L); + __ should_not_reach_here(); + __ bind(L); +#endif // ASSERT + __ jump(RuntimeAddress(StubRoutines::forward_exception_entry())); + + + // codeBlob framesize is in words (not VMRegImpl::slot_size) + RuntimeStub* stub = + RuntimeStub::new_runtime_stub(name, + &code, + frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, false); + return stub; +} + //------------------------------Montgomery multiplication------------------------ // @@ -3475,3 +3577,94 @@ void SharedRuntime::montgomery_square(jint *a_ints, jint *n_ints, reverse_words(m, (julong *)m_ints, longwords); } +#if INCLUDE_JFR + +// For c2: c_rarg0 is junk, call to runtime to write a checkpoint. +// It returns a jobject handle to the event writer. +// The handle is dereferenced and the return value is the event writer oop. +RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { + enum layout { + rbp_off, + rbpH_off, + return_off, + return_off2, + framesize // inclusive of return address + }; + + CodeBuffer code("jfr_write_checkpoint", 1024, 64); + MacroAssembler* masm = new MacroAssembler(&code); + address start = __ pc(); + + __ enter(); + address the_pc = __ pc(); + + int frame_complete = the_pc - start; + + __ set_last_Java_frame(rsp, rbp, the_pc, rscratch1); + __ movptr(c_rarg0, r15_thread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), 1); + __ reset_last_Java_frame(true); + + // rax is jobject handle result, unpack and process it through a barrier. + __ resolve_global_jobject(rax, r15_thread, c_rarg0); + + __ leave(); + __ ret(0); + + OopMapSet* oop_maps = new OopMapSet(); + OopMap* map = new OopMap(framesize, 1); + oop_maps->add_gc_map(frame_complete, map); + + RuntimeStub* stub = + RuntimeStub::new_runtime_stub(code.name(), + &code, + frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, + false); + return stub; +} + +// For c2: call to return a leased buffer. +RuntimeStub* SharedRuntime::generate_jfr_return_lease() { + enum layout { + rbp_off, + rbpH_off, + return_off, + return_off2, + framesize // inclusive of return address + }; + + CodeBuffer code("jfr_return_lease", 1024, 64); + MacroAssembler* masm = new MacroAssembler(&code); + address start = __ pc(); + + __ enter(); + address the_pc = __ pc(); + + int frame_complete = the_pc - start; + + __ set_last_Java_frame(rsp, rbp, the_pc, rscratch2); + __ movptr(c_rarg0, r15_thread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), 1); + __ reset_last_Java_frame(true); + + __ leave(); + __ ret(0); + + OopMapSet* oop_maps = new OopMapSet(); + OopMap* map = new OopMap(framesize, 1); + oop_maps->add_gc_map(frame_complete, map); + + RuntimeStub* stub = + RuntimeStub::new_runtime_stub(code.name(), + &code, + frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, + false); + return stub; +} + +#endif // INCLUDE_JFR + diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp index d8067a39177..de13772dcfb 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp @@ -3843,121 +3843,8 @@ class StubGenerator: public StubCodeGenerator { return start; } - public: - // Information about frame layout at time of blocking runtime call. - // Note that we only have to preserve callee-saved registers since - // the compilers are responsible for supplying a continuation point - // if they expect all registers to be preserved. - enum layout { - thread_off, // last_java_sp - arg1_off, - arg2_off, - rbp_off, // callee saved register - ret_pc, - framesize - }; - private: -#undef __ -#define __ masm-> - - //------------------------------------------------------------------------------------------------------------------------ - // Continuation point for throwing of implicit exceptions that are not handled in - // the current activation. Fabricates an exception oop and initiates normal - // exception dispatching in this frame. - // - // Previously the compiler (c2) allowed for callee save registers on Java calls. - // This is no longer true after adapter frames were removed but could possibly - // be brought back in the future if the interpreter code was reworked and it - // was deemed worthwhile. The comment below was left to describe what must - // happen here if callee saves were resurrected. As it stands now this stub - // could actually be a vanilla BufferBlob and have now oopMap at all. - // Since it doesn't make much difference we've chosen to leave it the - // way it was in the callee save days and keep the comment. - - // If we need to preserve callee-saved values we need a callee-saved oop map and - // therefore have to make these stubs into RuntimeStubs rather than BufferBlobs. - // If the compiler needs all registers to be preserved between the fault - // point and the exception handler then it must assume responsibility for that in - // AbstractCompiler::continuation_for_implicit_null_exception or - // continuation_for_implicit_division_by_zero_exception. All other implicit - // exceptions (e.g., NullPointerException or AbstractMethodError on entry) are - // either at call sites or otherwise assume that stack unwinding will be initiated, - // so caller saved registers were assumed volatile in the compiler. - address generate_throw_exception(const char* name, address runtime_entry, - Register arg1 = noreg, Register arg2 = noreg) { - - int insts_size = 256; - int locs_size = 32; - - CodeBuffer code(name, insts_size, locs_size); - OopMapSet* oop_maps = new OopMapSet(); - MacroAssembler* masm = new MacroAssembler(&code); - - address start = __ pc(); - - // This is an inlined and slightly modified version of call_VM - // which has the ability to fetch the return PC out of - // thread-local storage and also sets up last_Java_sp slightly - // differently than the real call_VM - Register java_thread = rbx; - __ get_thread(java_thread); - - __ enter(); // required for proper stackwalking of RuntimeStub frame - - // pc and rbp, already pushed - __ subptr(rsp, (framesize-2) * wordSize); // prolog - - // Frame is now completed as far as size and linkage. - - int frame_complete = __ pc() - start; - - // push java thread (becomes first argument of C function) - __ movptr(Address(rsp, thread_off * wordSize), java_thread); - if (arg1 != noreg) { - __ movptr(Address(rsp, arg1_off * wordSize), arg1); - } - if (arg2 != noreg) { - assert(arg1 != noreg, "missing reg arg"); - __ movptr(Address(rsp, arg2_off * wordSize), arg2); - } - - // Set up last_Java_sp and last_Java_fp - __ set_last_Java_frame(java_thread, rsp, rbp, nullptr, noreg); - - // Call runtime - BLOCK_COMMENT("call runtime_entry"); - __ call(RuntimeAddress(runtime_entry)); - // Generate oop map - OopMap* map = new OopMap(framesize, 0); - oop_maps->add_gc_map(__ pc() - start, map); - - // restore the thread (cannot use the pushed argument since arguments - // may be overwritten by C code generated by an optimizing compiler); - // however can use the register value directly if it is callee saved. - __ get_thread(java_thread); - - __ reset_last_Java_frame(java_thread, true); - - __ leave(); // required for proper stackwalking of RuntimeStub frame - - // check for pending exceptions -#ifdef ASSERT - Label L; - __ cmpptr(Address(java_thread, Thread::pending_exception_offset()), NULL_WORD); - __ jcc(Assembler::notEqual, L); - __ should_not_reach_here(); - __ bind(L); -#endif /* ASSERT */ - __ jump(RuntimeAddress(StubRoutines::forward_exception_entry())); - - - RuntimeStub* stub = RuntimeStub::new_runtime_stub(name, &code, frame_complete, framesize, oop_maps, false); - return stub->entry_point(); - } - - void create_control_words() { // Round to nearest, 53-bit mode, exceptions masked StubRoutines::x86::_fpu_cntrl_wrd_std = 0x027F; @@ -3997,109 +3884,6 @@ class StubGenerator: public StubCodeGenerator { return nullptr; } -#if INCLUDE_JFR - - static void jfr_prologue(address the_pc, MacroAssembler* masm) { - Register java_thread = rdi; - __ get_thread(java_thread); - __ set_last_Java_frame(java_thread, rsp, rbp, the_pc, noreg); - __ movptr(Address(rsp, 0), java_thread); - } - - // The handle is dereferenced through a load barrier. - static void jfr_epilogue(MacroAssembler* masm) { - Register java_thread = rdi; - __ get_thread(java_thread); - __ reset_last_Java_frame(java_thread, true); - } - - // For c2: c_rarg0 is junk, call to runtime to write a checkpoint. - // It returns a jobject handle to the event writer. - // The handle is dereferenced and the return value is the event writer oop. - static RuntimeStub* generate_jfr_write_checkpoint() { - enum layout { - FPUState_off = 0, - rbp_off = FPUStateSizeInWords, - rdi_off, - rsi_off, - rcx_off, - rbx_off, - saved_argument_off, - saved_argument_off2, // 2nd half of double - framesize - }; - - int insts_size = 1024; - int locs_size = 64; - CodeBuffer code("jfr_write_checkpoint", insts_size, locs_size); - OopMapSet* oop_maps = new OopMapSet(); - MacroAssembler* masm = new MacroAssembler(&code); - MacroAssembler* _masm = masm; - - address start = __ pc(); - __ enter(); - int frame_complete = __ pc() - start; - address the_pc = __ pc(); - jfr_prologue(the_pc, _masm); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), 1); - jfr_epilogue(_masm); - __ resolve_global_jobject(rax, rdi, rdx); - __ leave(); - __ ret(0); - - OopMap* map = new OopMap(framesize, 1); // rbp - oop_maps->add_gc_map(the_pc - start, map); - - RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) - RuntimeStub::new_runtime_stub("jfr_write_checkpoint", &code, frame_complete, - (framesize >> (LogBytesPerWord - LogBytesPerInt)), - oop_maps, false); - return stub; - } - - // For c2: call to return a leased buffer. - static RuntimeStub* generate_jfr_return_lease() { - enum layout { - FPUState_off = 0, - rbp_off = FPUStateSizeInWords, - rdi_off, - rsi_off, - rcx_off, - rbx_off, - saved_argument_off, - saved_argument_off2, // 2nd half of double - framesize - }; - - int insts_size = 1024; - int locs_size = 64; - CodeBuffer code("jfr_return_lease", insts_size, locs_size); - OopMapSet* oop_maps = new OopMapSet(); - MacroAssembler* masm = new MacroAssembler(&code); - MacroAssembler* _masm = masm; - - address start = __ pc(); - __ enter(); - int frame_complete = __ pc() - start; - address the_pc = __ pc(); - jfr_prologue(the_pc, _masm); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), 1); - jfr_epilogue(_masm); - __ leave(); - __ ret(0); - - OopMap* map = new OopMap(framesize, 1); // rbp - oop_maps->add_gc_map(the_pc - start, map); - - RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) - RuntimeStub::new_runtime_stub("jfr_return_lease", &code, frame_complete, - (framesize >> (LogBytesPerWord - LogBytesPerInt)), - oop_maps, false); - return stub; - } - -#endif // INCLUDE_JFR - //--------------------------------------------------------------------------- // Initialization @@ -4130,12 +3914,6 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::x86::_d2i_wrapper = generate_d2i_wrapper(T_INT, CAST_FROM_FN_PTR(address, SharedRuntime::d2i)); StubRoutines::x86::_d2l_wrapper = generate_d2i_wrapper(T_LONG, CAST_FROM_FN_PTR(address, SharedRuntime::d2l)); - // Build this early so it's available for the interpreter - StubRoutines::_throw_StackOverflowError_entry = generate_throw_exception("StackOverflowError throw_exception", - CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError)); - StubRoutines::_throw_delayed_StackOverflowError_entry = generate_throw_exception("delayed StackOverflowError throw_exception", - CAST_FROM_FN_PTR(address, SharedRuntime::throw_delayed_StackOverflowError)); - if (UseCRC32Intrinsics) { // set table address before stub generation which use it StubRoutines::_crc_table_adr = (address)StubRoutines::x86::_crc_table; @@ -4188,28 +3966,11 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_cont_thaw = generate_cont_thaw(); StubRoutines::_cont_returnBarrier = generate_cont_returnBarrier(); StubRoutines::_cont_returnBarrierExc = generate_cont_returnBarrier_exception(); - - JFR_ONLY(generate_jfr_stubs();) } -#if INCLUDE_JFR - void generate_jfr_stubs() { - StubRoutines::_jfr_write_checkpoint_stub = generate_jfr_write_checkpoint(); - StubRoutines::_jfr_write_checkpoint = StubRoutines::_jfr_write_checkpoint_stub->entry_point(); - StubRoutines::_jfr_return_lease_stub = generate_jfr_return_lease(); - StubRoutines::_jfr_return_lease = StubRoutines::_jfr_return_lease_stub->entry_point(); - } -#endif // INCLUDE_JFR - void generate_final_stubs() { // Generates all stubs and initializes the entry points - // These entry points require SharedInfo::stack0 to be set up in non-core builds - // and need to be relocatable, so they each fabricate a RuntimeStub internally. - StubRoutines::_throw_AbstractMethodError_entry = generate_throw_exception("AbstractMethodError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_AbstractMethodError)); - StubRoutines::_throw_IncompatibleClassChangeError_entry= generate_throw_exception("IncompatibleClassChangeError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError)); - StubRoutines::_throw_NullPointerException_at_call_entry= generate_throw_exception("NullPointerException at call throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException_at_call)); - // support for verify_oop (must happen after universe_init) StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop(); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index a7404b298f6..2bc4a0a9cba 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -45,9 +45,6 @@ #if INCLUDE_JVMCI #include "jvmci/jvmci_globals.hpp" #endif -#if INCLUDE_JFR -#include "jfr/support/jfrIntrinsics.hpp" -#endif // For a more detailed description of the stub routine structure // see the comment in stubRoutines.hpp @@ -3702,7 +3699,7 @@ address StubGenerator::generate_cont_thaw(const char* label, Continuation::thaw_ Label L_thaw_success; __ testptr(rbx, rbx); __ jccb(Assembler::notZero, L_thaw_success); - __ jump(RuntimeAddress(StubRoutines::throw_StackOverflowError_entry())); + __ jump(RuntimeAddress(SharedRuntime::throw_StackOverflowError_entry())); __ bind(L_thaw_success); // Make room for the thawed frames and align the stack. @@ -3778,198 +3775,6 @@ address StubGenerator::generate_cont_returnBarrier_exception() { return generate_cont_thaw("Cont thaw return barrier exception", Continuation::thaw_return_barrier_exception); } -#if INCLUDE_JFR - -// For c2: c_rarg0 is junk, call to runtime to write a checkpoint. -// It returns a jobject handle to the event writer. -// The handle is dereferenced and the return value is the event writer oop. -RuntimeStub* StubGenerator::generate_jfr_write_checkpoint() { - enum layout { - rbp_off, - rbpH_off, - return_off, - return_off2, - framesize // inclusive of return address - }; - - CodeBuffer code("jfr_write_checkpoint", 1024, 64); - MacroAssembler* _masm = new MacroAssembler(&code); - address start = __ pc(); - - __ enter(); - address the_pc = __ pc(); - - int frame_complete = the_pc - start; - - __ set_last_Java_frame(rsp, rbp, the_pc, rscratch1); - __ movptr(c_rarg0, r15_thread); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), 1); - __ reset_last_Java_frame(true); - - // rax is jobject handle result, unpack and process it through a barrier. - __ resolve_global_jobject(rax, r15_thread, c_rarg0); - - __ leave(); - __ ret(0); - - OopMapSet* oop_maps = new OopMapSet(); - OopMap* map = new OopMap(framesize, 1); - oop_maps->add_gc_map(frame_complete, map); - - RuntimeStub* stub = - RuntimeStub::new_runtime_stub(code.name(), - &code, - frame_complete, - (framesize >> (LogBytesPerWord - LogBytesPerInt)), - oop_maps, - false); - return stub; -} - -// For c2: call to return a leased buffer. -RuntimeStub* StubGenerator::generate_jfr_return_lease() { - enum layout { - rbp_off, - rbpH_off, - return_off, - return_off2, - framesize // inclusive of return address - }; - - CodeBuffer code("jfr_return_lease", 1024, 64); - MacroAssembler* _masm = new MacroAssembler(&code); - address start = __ pc(); - - __ enter(); - address the_pc = __ pc(); - - int frame_complete = the_pc - start; - - __ set_last_Java_frame(rsp, rbp, the_pc, rscratch2); - __ movptr(c_rarg0, r15_thread); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), 1); - __ reset_last_Java_frame(true); - - __ leave(); - __ ret(0); - - OopMapSet* oop_maps = new OopMapSet(); - OopMap* map = new OopMap(framesize, 1); - oop_maps->add_gc_map(frame_complete, map); - - RuntimeStub* stub = - RuntimeStub::new_runtime_stub(code.name(), - &code, - frame_complete, - (framesize >> (LogBytesPerWord - LogBytesPerInt)), - oop_maps, - false); - return stub; -} - -#endif // INCLUDE_JFR - -// Continuation point for throwing of implicit exceptions that are -// not handled in the current activation. Fabricates an exception -// oop and initiates normal exception dispatching in this -// frame. Since we need to preserve callee-saved values (currently -// only for C2, but done for C1 as well) we need a callee-saved oop -// map and therefore have to make these stubs into RuntimeStubs -// rather than BufferBlobs. If the compiler needs all registers to -// be preserved between the fault point and the exception handler -// then it must assume responsibility for that in -// AbstractCompiler::continuation_for_implicit_null_exception or -// continuation_for_implicit_division_by_zero_exception. All other -// implicit exceptions (e.g., NullPointerException or -// AbstractMethodError on entry) are either at call sites or -// otherwise assume that stack unwinding will be initiated, so -// caller saved registers were assumed volatile in the compiler. -address StubGenerator::generate_throw_exception(const char* name, - address runtime_entry, - Register arg1, - Register arg2) { - // Information about frame layout at time of blocking runtime call. - // Note that we only have to preserve callee-saved registers since - // the compilers are responsible for supplying a continuation point - // if they expect all registers to be preserved. - enum layout { - rbp_off = frame::arg_reg_save_area_bytes/BytesPerInt, - rbp_off2, - return_off, - return_off2, - framesize // inclusive of return address - }; - - int insts_size = 512; - int locs_size = 64; - - CodeBuffer code(name, insts_size, locs_size); - OopMapSet* oop_maps = new OopMapSet(); - MacroAssembler* _masm = new MacroAssembler(&code); - - address start = __ pc(); - - // This is an inlined and slightly modified version of call_VM - // which has the ability to fetch the return PC out of - // thread-local storage and also sets up last_Java_sp slightly - // differently than the real call_VM - - __ enter(); // required for proper stackwalking of RuntimeStub frame - - assert(is_even(framesize/2), "sp not 16-byte aligned"); - - // return address and rbp are already in place - __ subptr(rsp, (framesize-4) << LogBytesPerInt); // prolog - - int frame_complete = __ pc() - start; - - // Set up last_Java_sp and last_Java_fp - address the_pc = __ pc(); - __ set_last_Java_frame(rsp, rbp, the_pc, rscratch1); - __ andptr(rsp, -(StackAlignmentInBytes)); // Align stack - - // Call runtime - if (arg1 != noreg) { - assert(arg2 != c_rarg1, "clobbered"); - __ movptr(c_rarg1, arg1); - } - if (arg2 != noreg) { - __ movptr(c_rarg2, arg2); - } - __ movptr(c_rarg0, r15_thread); - BLOCK_COMMENT("call runtime_entry"); - __ call(RuntimeAddress(runtime_entry)); - - // Generate oop map - OopMap* map = new OopMap(framesize, 0); - - oop_maps->add_gc_map(the_pc - start, map); - - __ reset_last_Java_frame(true); - - __ leave(); // required for proper stackwalking of RuntimeStub frame - - // check for pending exceptions -#ifdef ASSERT - Label L; - __ cmpptr(Address(r15_thread, Thread::pending_exception_offset()), NULL_WORD); - __ jcc(Assembler::notEqual, L); - __ should_not_reach_here(); - __ bind(L); -#endif // ASSERT - __ jump(RuntimeAddress(StubRoutines::forward_exception_entry())); - - - // codeBlob framesize is in words (not VMRegImpl::slot_size) - RuntimeStub* stub = - RuntimeStub::new_runtime_stub(name, - &code, - frame_complete, - (framesize >> (LogBytesPerWord - LogBytesPerInt)), - oop_maps, false); - return stub->entry_point(); -} - // exception handler for upcall stubs address StubGenerator::generate_upcall_stub_exception_handler() { StubCodeMark mark(this, "StubRoutines", "upcall stub exception handler"); @@ -4087,17 +3892,6 @@ void StubGenerator::generate_initial_stubs() { StubRoutines::x86::_double_sign_mask = generate_fp_mask("double_sign_mask", 0x7FFFFFFFFFFFFFFF); StubRoutines::x86::_double_sign_flip = generate_fp_mask("double_sign_flip", 0x8000000000000000); - // Build this early so it's available for the interpreter. - StubRoutines::_throw_StackOverflowError_entry = - generate_throw_exception("StackOverflowError throw_exception", - CAST_FROM_FN_PTR(address, - SharedRuntime:: - throw_StackOverflowError)); - StubRoutines::_throw_delayed_StackOverflowError_entry = - generate_throw_exception("delayed StackOverflowError throw_exception", - CAST_FROM_FN_PTR(address, - SharedRuntime:: - throw_delayed_StackOverflowError)); if (UseCRC32Intrinsics) { // set table address before stub generation which use it StubRoutines::_crc_table_adr = (address)StubRoutines::x86::_crc_table; @@ -4131,43 +3925,11 @@ void StubGenerator::generate_continuation_stubs() { StubRoutines::_cont_thaw = generate_cont_thaw(); StubRoutines::_cont_returnBarrier = generate_cont_returnBarrier(); StubRoutines::_cont_returnBarrierExc = generate_cont_returnBarrier_exception(); - - JFR_ONLY(generate_jfr_stubs();) } -#if INCLUDE_JFR -void StubGenerator::generate_jfr_stubs() { - StubRoutines::_jfr_write_checkpoint_stub = generate_jfr_write_checkpoint(); - StubRoutines::_jfr_write_checkpoint = StubRoutines::_jfr_write_checkpoint_stub->entry_point(); - StubRoutines::_jfr_return_lease_stub = generate_jfr_return_lease(); - StubRoutines::_jfr_return_lease = StubRoutines::_jfr_return_lease_stub->entry_point(); -} -#endif - void StubGenerator::generate_final_stubs() { // Generates the rest of stubs and initializes the entry points - // These entry points require SharedInfo::stack0 to be set up in - // non-core builds and need to be relocatable, so they each - // fabricate a RuntimeStub internally. - StubRoutines::_throw_AbstractMethodError_entry = - generate_throw_exception("AbstractMethodError throw_exception", - CAST_FROM_FN_PTR(address, - SharedRuntime:: - throw_AbstractMethodError)); - - StubRoutines::_throw_IncompatibleClassChangeError_entry = - generate_throw_exception("IncompatibleClassChangeError throw_exception", - CAST_FROM_FN_PTR(address, - SharedRuntime:: - throw_IncompatibleClassChangeError)); - - StubRoutines::_throw_NullPointerException_at_call_entry = - generate_throw_exception("NullPointerException at call throw_exception", - CAST_FROM_FN_PTR(address, - SharedRuntime:: - throw_NullPointerException_at_call)); - // support for verify_oop (must happen after universe_init) if (VerifyOops) { StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop(); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp index 374679750a4..d65c681585d 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp @@ -586,16 +586,6 @@ class StubGenerator: public StubCodeGenerator { address generate_cont_returnBarrier(); address generate_cont_returnBarrier_exception(); -#if INCLUDE_JFR - void generate_jfr_stubs(); - // For c2: c_rarg0 is junk, call to runtime to write a checkpoint. - // It returns a jobject handle to the event writer. - // The handle is dereferenced and the return value is the event writer oop. - RuntimeStub* generate_jfr_write_checkpoint(); - // For c2: call to runtime to return a buffer lease. - RuntimeStub* generate_jfr_return_lease(); -#endif // INCLUDE_JFR - // Continuation point for throwing of implicit exceptions that are // not handled in the current activation. Fabricates an exception // oop and initiates normal exception dispatching in this diff --git a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp index 3b32d577d44..76ad498be0e 100644 --- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp @@ -545,8 +545,8 @@ void TemplateInterpreterGenerator::generate_stack_overflow_check(void) { // Note: the restored frame is not necessarily interpreted. // Use the shared runtime version of the StackOverflowError. - assert(StubRoutines::throw_StackOverflowError_entry() != nullptr, "stub not yet generated"); - __ jump(RuntimeAddress(StubRoutines::throw_StackOverflowError_entry())); + assert(SharedRuntime::throw_StackOverflowError_entry() != nullptr, "stub not yet generated"); + __ jump(RuntimeAddress(SharedRuntime::throw_StackOverflowError_entry())); // all done with frame size check __ bind(after_frame_check_pop); NOT_LP64(__ pop(rsi)); diff --git a/src/hotspot/cpu/zero/sharedRuntime_zero.cpp b/src/hotspot/cpu/zero/sharedRuntime_zero.cpp index 986cee68512..454f8e5f632 100644 --- a/src/hotspot/cpu/zero/sharedRuntime_zero.cpp +++ b/src/hotspot/cpu/zero/sharedRuntime_zero.cpp @@ -89,7 +89,7 @@ JRT_LEAF(void, zero_stub()) ShouldNotCallThis(); JRT_END -static RuntimeStub* generate_empty_runtime_stub(const char* name) { +static RuntimeStub* generate_empty_runtime_stub() { return CAST_FROM_FN_PTR(RuntimeStub*,zero_stub); } @@ -101,7 +101,6 @@ static DeoptimizationBlob* generate_empty_deopt_blob() { return CAST_FROM_FN_PTR(DeoptimizationBlob*,zero_stub); } - void SharedRuntime::generate_deopt_blob() { _deopt_blob = generate_empty_deopt_blob(); } @@ -111,7 +110,11 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t } RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const char* name) { - return generate_empty_runtime_stub("resolve_blob"); + return generate_empty_runtime_stub(); +} + +RuntimeStub* SharedRuntime::generate_throw_exception(const char* name, address runtime_entry) { + return generate_empty_runtime_stub(); } int SharedRuntime::c_calling_convention(const BasicType *sig_bt, @@ -127,3 +130,15 @@ int SharedRuntime::vector_calling_convention(VMRegPair *regs, ShouldNotCallThis(); return 0; } + +#if INCLUDE_JFR +RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { + return nullptr; +} + +RuntimeStub* SharedRuntime::generate_jfr_return_lease() { + return nullptr; +} + +#endif // INCLUDE_JFR + diff --git a/src/hotspot/cpu/zero/stubGenerator_zero.cpp b/src/hotspot/cpu/zero/stubGenerator_zero.cpp index 5c7772021ea..b6905791e98 100644 --- a/src/hotspot/cpu/zero/stubGenerator_zero.cpp +++ b/src/hotspot/cpu/zero/stubGenerator_zero.cpp @@ -203,22 +203,6 @@ class StubGenerator: public StubCodeGenerator { void generate_final_stubs() { // Generates all stubs and initializes the entry points - // These entry points require SharedInfo::stack0 to be set up in - // non-core builds and need to be relocatable, so they each - // fabricate a RuntimeStub internally. - StubRoutines::_throw_AbstractMethodError_entry = - ShouldNotCallThisStub(); - - StubRoutines::_throw_NullPointerException_at_call_entry = - ShouldNotCallThisStub(); - - StubRoutines::_throw_StackOverflowError_entry = - ShouldNotCallThisStub(); - - // support for verify_oop (must happen after universe_init) - StubRoutines::_verify_oop_subroutine_entry = - ShouldNotCallThisStub(); - // arraycopy stubs used by compilers generate_arraycopy_stubs(); diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp index 8fdb96a3038..fa4b1c75c05 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp @@ -50,6 +50,7 @@ class CompilerToVM { static address SharedRuntime_deopt_blob_unpack_with_exception_in_tls; static address SharedRuntime_deopt_blob_uncommon_trap; static address SharedRuntime_polling_page_return_handler; + static address SharedRuntime_throw_delayed_StackOverflowError_entry; static address nmethod_entry_barrier; static int thread_disarmed_guard_value_offset; diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp index 2116133e56e..26c88abec0f 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp @@ -68,6 +68,7 @@ address CompilerToVM::Data::SharedRuntime_deopt_blob_unpack; address CompilerToVM::Data::SharedRuntime_deopt_blob_unpack_with_exception_in_tls; address CompilerToVM::Data::SharedRuntime_deopt_blob_uncommon_trap; address CompilerToVM::Data::SharedRuntime_polling_page_return_handler; +address CompilerToVM::Data::SharedRuntime_throw_delayed_StackOverflowError_entry; address CompilerToVM::Data::nmethod_entry_barrier; int CompilerToVM::Data::thread_disarmed_guard_value_offset; @@ -158,6 +159,7 @@ void CompilerToVM::Data::initialize(JVMCI_TRAPS) { SharedRuntime_deopt_blob_unpack_with_exception_in_tls = SharedRuntime::deopt_blob()->unpack_with_exception_in_tls(); SharedRuntime_deopt_blob_uncommon_trap = SharedRuntime::deopt_blob()->uncommon_trap(); SharedRuntime_polling_page_return_handler = SharedRuntime::polling_page_return_handler_blob()->entry_point(); + SharedRuntime_throw_delayed_StackOverflowError_entry = SharedRuntime::throw_delayed_StackOverflowError_entry(); BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); if (bs_nm != nullptr) { diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 5870e49ac94..688691fb976 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -68,6 +68,8 @@ static_field(CompilerToVM::Data, SharedRuntime_deopt_blob_uncommon_trap, address) \ static_field(CompilerToVM::Data, SharedRuntime_polling_page_return_handler, \ address) \ + static_field(CompilerToVM::Data, SharedRuntime_throw_delayed_StackOverflowError_entry, \ + address) \ \ static_field(CompilerToVM::Data, nmethod_entry_barrier, address) \ static_field(CompilerToVM::Data, thread_disarmed_guard_value_offset, int) \ @@ -328,8 +330,6 @@ \ static_field(StubRoutines, _verify_oop_count, jint) \ \ - static_field(StubRoutines, _throw_delayed_StackOverflowError_entry, address) \ - \ static_field(StubRoutines, _jbyte_arraycopy, address) \ static_field(StubRoutines, _jshort_arraycopy, address) \ static_field(StubRoutines, _jint_arraycopy, address) \ diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 542514b1f7e..eced285f8cb 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -3167,7 +3167,7 @@ bool LibraryCallKit::inline_native_jvm_commit() { // Make a runtime call, which can safepoint, to return the leased buffer. This updates both the JfrThreadLocal and the Java event writer oop. Node* call_return_lease = make_runtime_call(RC_NO_LEAF, OptoRuntime::void_void_Type(), - StubRoutines::jfr_return_lease(), + SharedRuntime::jfr_return_lease(), "return_lease", TypePtr::BOTTOM); Node* call_return_lease_control = _gvn.transform(new ProjNode(call_return_lease, TypeFunc::Control)); @@ -3366,7 +3366,7 @@ bool LibraryCallKit::inline_native_getEventWriter() { // The call also updates the native thread local thread id and the vthread with the current epoch. Node* call_write_checkpoint = make_runtime_call(RC_NO_LEAF, OptoRuntime::jfr_write_checkpoint_Type(), - StubRoutines::jfr_write_checkpoint(), + SharedRuntime::jfr_write_checkpoint(), "write_checkpoint", TypePtr::BOTTOM); Node* call_write_checkpoint_control = _gvn.transform(new ProjNode(call_write_checkpoint, TypeFunc::Control)); diff --git a/src/hotspot/share/runtime/init.cpp b/src/hotspot/share/runtime/init.cpp index 368f4e62c76..7f23aca0961 100644 --- a/src/hotspot/share/runtime/init.cpp +++ b/src/hotspot/share/runtime/init.cpp @@ -126,7 +126,10 @@ jint init_globals() { compilationPolicy_init(); codeCache_init(); VM_Version_init(); // depends on codeCache_init for emitting code + // stub routines in initial blob are referenced by later generated code initial_stubs_init(); + // stack overflow exception blob is referenced by the interpreter + SharedRuntime::generate_initial_stubs(); jint status = universe_init(); // dependent on codeCache_init and // initial_stubs_init and metaspace_init. if (status != JNI_OK) @@ -144,6 +147,9 @@ jint init_globals() { gc_barrier_stubs_init(); // depends on universe_init, must be before interpreter_init continuations_init(); // must precede continuation stub generation continuation_stubs_init(); // depends on continuations_init +#if INCLUDE_JFR + SharedRuntime::generate_jfr_stubs(); +#endif interpreter_init_stub(); // before methods get loaded accessFlags_init(); InterfaceSupport_init(); diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 0587032ec5c..f98d031a2cd 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -71,6 +71,7 @@ #include "runtime/stackWatermarkSet.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/synchronizer.inline.hpp" +#include "runtime/timerTrace.hpp" #include "runtime/vframe.inline.hpp" #include "runtime/vframeArray.hpp" #include "runtime/vm_version.hpp" @@ -88,23 +89,42 @@ #include "jfr/jfr.hpp" #endif -// Shared stub locations +// Shared runtime stub routines reside in their own unique blob with a +// single entry point + RuntimeStub* SharedRuntime::_wrong_method_blob; RuntimeStub* SharedRuntime::_wrong_method_abstract_blob; RuntimeStub* SharedRuntime::_ic_miss_blob; RuntimeStub* SharedRuntime::_resolve_opt_virtual_call_blob; RuntimeStub* SharedRuntime::_resolve_virtual_call_blob; RuntimeStub* SharedRuntime::_resolve_static_call_blob; -address SharedRuntime::_resolve_static_call_entry; DeoptimizationBlob* SharedRuntime::_deopt_blob; SafepointBlob* SharedRuntime::_polling_page_vectors_safepoint_handler_blob; SafepointBlob* SharedRuntime::_polling_page_safepoint_handler_blob; SafepointBlob* SharedRuntime::_polling_page_return_handler_blob; +RuntimeStub* SharedRuntime::_throw_AbstractMethodError_blob; +RuntimeStub* SharedRuntime::_throw_IncompatibleClassChangeError_blob; +RuntimeStub* SharedRuntime::_throw_NullPointerException_at_call_blob; +RuntimeStub* SharedRuntime::_throw_StackOverflowError_blob; +RuntimeStub* SharedRuntime::_throw_delayed_StackOverflowError_blob; + +#if INCLUDE_JFR +RuntimeStub* SharedRuntime::_jfr_write_checkpoint_blob = nullptr; +RuntimeStub* SharedRuntime::_jfr_return_lease_blob = nullptr; +#endif + nmethod* SharedRuntime::_cont_doYield_stub; //----------------------------generate_stubs----------------------------------- +void SharedRuntime::generate_initial_stubs() { + // Build this early so it's available for the interpreter. + _throw_StackOverflowError_blob = + generate_throw_exception("StackOverflowError throw_exception", + CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError)); +} + void SharedRuntime::generate_stubs() { _wrong_method_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::handle_wrong_method), "wrong_method_stub"); _wrong_method_abstract_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::handle_wrong_method_abstract), "wrong_method_abstract_stub"); @@ -112,7 +132,22 @@ void SharedRuntime::generate_stubs() { _resolve_opt_virtual_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_opt_virtual_call_C), "resolve_opt_virtual_call"); _resolve_virtual_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_virtual_call_C), "resolve_virtual_call"); _resolve_static_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_static_call_C), "resolve_static_call"); - _resolve_static_call_entry = _resolve_static_call_blob->entry_point(); + + _throw_delayed_StackOverflowError_blob = + generate_throw_exception("delayed StackOverflowError throw_exception", + CAST_FROM_FN_PTR(address, SharedRuntime::throw_delayed_StackOverflowError)); + + _throw_AbstractMethodError_blob = + generate_throw_exception("AbstractMethodError throw_exception", + CAST_FROM_FN_PTR(address, SharedRuntime::throw_AbstractMethodError)); + + _throw_IncompatibleClassChangeError_blob = + generate_throw_exception("IncompatibleClassChangeError throw_exception", + CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError)); + + _throw_NullPointerException_at_call_blob = + generate_throw_exception("NullPointerException at call throw_exception", + CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException_at_call)); AdapterHandlerLibrary::initialize(); @@ -129,6 +164,19 @@ void SharedRuntime::generate_stubs() { generate_deopt_blob(); } +#if INCLUDE_JFR +//------------------------------generate jfr runtime stubs ------ +void SharedRuntime::generate_jfr_stubs() { + ResourceMark rm; + const char* timer_msg = "SharedRuntime generate_jfr_stubs"; + TraceTime timer(timer_msg, TRACETIME_LOG(Info, startuptime)); + + _jfr_write_checkpoint_blob = generate_jfr_write_checkpoint(); + _jfr_return_lease_blob = generate_jfr_return_lease(); +} + +#endif // INCLUDE_JFR + #include // Implementation of SharedRuntime @@ -867,7 +915,7 @@ address SharedRuntime::continuation_for_implicit_exception(JavaThread* current, // method stack banging. assert(current->deopt_mark() == nullptr, "no stack overflow from deopt blob/uncommon trap"); Events::log_exception(current, "StackOverflowError at " INTPTR_FORMAT, p2i(pc)); - return StubRoutines::throw_StackOverflowError_entry(); + return SharedRuntime::throw_StackOverflowError_entry(); } case IMPLICIT_NULL: { @@ -893,7 +941,7 @@ address SharedRuntime::continuation_for_implicit_exception(JavaThread* current, // Assert that the signal comes from the expected location in stub code. assert(vt_stub->is_null_pointer_exception(pc), "obtained signal from unexpected location in stub code"); - return StubRoutines::throw_NullPointerException_at_call_entry(); + return SharedRuntime::throw_NullPointerException_at_call_entry(); } } else { CodeBlob* cb = CodeCache::find_blob(pc); @@ -914,7 +962,7 @@ address SharedRuntime::continuation_for_implicit_exception(JavaThread* current, } Events::log_exception(current, "NullPointerException in code blob at " INTPTR_FORMAT, p2i(pc)); // There is no handler here, so we will simply unwind. - return StubRoutines::throw_NullPointerException_at_call_entry(); + return SharedRuntime::throw_NullPointerException_at_call_entry(); } // Otherwise, it's a compiled method. Consult its exception handlers. @@ -925,13 +973,13 @@ address SharedRuntime::continuation_for_implicit_exception(JavaThread* current, // is not set up yet) => use return address pushed by // caller => don't push another return address Events::log_exception(current, "NullPointerException in IC check " INTPTR_FORMAT, p2i(pc)); - return StubRoutines::throw_NullPointerException_at_call_entry(); + return SharedRuntime::throw_NullPointerException_at_call_entry(); } if (nm->method()->is_method_handle_intrinsic()) { // exception happened inside MH dispatch code, similar to a vtable stub Events::log_exception(current, "NullPointerException in MH adapter " INTPTR_FORMAT, p2i(pc)); - return StubRoutines::throw_NullPointerException_at_call_entry(); + return SharedRuntime::throw_NullPointerException_at_call_entry(); } #ifndef PRODUCT @@ -1467,7 +1515,7 @@ JRT_BLOCK_ENTRY(address, SharedRuntime::handle_wrong_method_abstract(JavaThread* assert(callerFrame.is_compiled_frame(), "must be"); // Install exception and return forward entry. - address res = StubRoutines::throw_AbstractMethodError_entry(); + address res = SharedRuntime::throw_AbstractMethodError_entry(); JRT_BLOCK methodHandle callee(current, invoke.static_target(current)); if (!callee.is_null()) { @@ -2387,7 +2435,7 @@ void AdapterHandlerLibrary::initialize() { // AbstractMethodError for invalid invocations. address wrong_method_abstract = SharedRuntime::get_handle_wrong_method_abstract_stub(); _abstract_method_handler = AdapterHandlerLibrary::new_entry(new AdapterFingerPrint(0, nullptr), - StubRoutines::throw_AbstractMethodError_entry(), + SharedRuntime::throw_AbstractMethodError_entry(), wrong_method_abstract, wrong_method_abstract); _buffer = BufferBlob::create("adapters", AdapterHandlerLibrary_size); diff --git a/src/hotspot/share/runtime/sharedRuntime.hpp b/src/hotspot/share/runtime/sharedRuntime.hpp index 9eec8e079ec..00a72f5db1e 100644 --- a/src/hotspot/share/runtime/sharedRuntime.hpp +++ b/src/hotspot/share/runtime/sharedRuntime.hpp @@ -54,7 +54,6 @@ class SharedRuntime: AllStatic { static RuntimeStub* _resolve_opt_virtual_call_blob; static RuntimeStub* _resolve_virtual_call_blob; static RuntimeStub* _resolve_static_call_blob; - static address _resolve_static_call_entry; static DeoptimizationBlob* _deopt_blob; @@ -64,6 +63,17 @@ class SharedRuntime: AllStatic { static nmethod* _cont_doYield_stub; + static RuntimeStub* _throw_AbstractMethodError_blob; + static RuntimeStub* _throw_IncompatibleClassChangeError_blob; + static RuntimeStub* _throw_NullPointerException_at_call_blob; + static RuntimeStub* _throw_StackOverflowError_blob; + static RuntimeStub* _throw_delayed_StackOverflowError_blob; + +#if INCLUDE_JFR + static RuntimeStub* _jfr_write_checkpoint_blob; + static RuntimeStub* _jfr_return_lease_blob; +#endif + #ifndef PRODUCT // Counters static int64_t _nof_megamorphic_calls; // total # of megamorphic calls (through vtable) @@ -73,9 +83,19 @@ class SharedRuntime: AllStatic { enum { POLL_AT_RETURN, POLL_AT_LOOP, POLL_AT_VECTOR_LOOP }; static SafepointBlob* generate_handler_blob(address call_ptr, int poll_type); static RuntimeStub* generate_resolve_blob(address destination, const char* name); - + static RuntimeStub* generate_throw_exception(const char* name, address runtime_entry); public: + static void generate_initial_stubs(void); static void generate_stubs(void); +#if INCLUDE_JFR + static void generate_jfr_stubs(void); + // For c2: c_rarg0 is junk, call to runtime to write a checkpoint. + // It returns a jobject handle to the event writer. + // The handle is dereferenced and the return value is the event writer oop. + static RuntimeStub* generate_jfr_write_checkpoint(); + // For c2: call to runtime to return a buffer lease. + static RuntimeStub* generate_jfr_return_lease(); +#endif // max bytes for each dtrace string parameter enum { max_dtrace_string_size = 256 }; @@ -241,6 +261,18 @@ class SharedRuntime: AllStatic { return _cont_doYield_stub; } + // Implicit exceptions + static address throw_AbstractMethodError_entry() { return _throw_AbstractMethodError_blob->entry_point(); } + static address throw_IncompatibleClassChangeError_entry() { return _throw_IncompatibleClassChangeError_blob->entry_point(); } + static address throw_NullPointerException_at_call_entry() { return _throw_NullPointerException_at_call_blob->entry_point(); } + static address throw_StackOverflowError_entry() { return _throw_StackOverflowError_blob->entry_point(); } + static address throw_delayed_StackOverflowError_entry() { return _throw_delayed_StackOverflowError_blob->entry_point(); } + +#if INCLUDE_JFR + static address jfr_write_checkpoint() { return _jfr_write_checkpoint_blob->entry_point(); } + static address jfr_return_lease() { return _jfr_return_lease_blob->entry_point(); } +#endif + // Counters #ifndef PRODUCT static address nof_megamorphic_calls_addr() { return (address)&_nof_megamorphic_calls; } diff --git a/src/hotspot/share/runtime/stubRoutines.cpp b/src/hotspot/share/runtime/stubRoutines.cpp index 773f8031e15..c13f64fca4b 100644 --- a/src/hotspot/share/runtime/stubRoutines.cpp +++ b/src/hotspot/share/runtime/stubRoutines.cpp @@ -61,11 +61,6 @@ address StubRoutines::_call_stub_entry = nullptr; address StubRoutines::_catch_exception_entry = nullptr; address StubRoutines::_forward_exception_entry = nullptr; -address StubRoutines::_throw_AbstractMethodError_entry = nullptr; -address StubRoutines::_throw_IncompatibleClassChangeError_entry = nullptr; -address StubRoutines::_throw_NullPointerException_at_call_entry = nullptr; -address StubRoutines::_throw_StackOverflowError_entry = nullptr; -address StubRoutines::_throw_delayed_StackOverflowError_entry = nullptr; jint StubRoutines::_verify_oop_count = 0; address StubRoutines::_verify_oop_subroutine_entry = nullptr; address StubRoutines::_atomic_xchg_entry = nullptr; @@ -191,11 +186,6 @@ address StubRoutines::_cont_thaw = nullptr; address StubRoutines::_cont_returnBarrier = nullptr; address StubRoutines::_cont_returnBarrierExc = nullptr; -JFR_ONLY(RuntimeStub* StubRoutines::_jfr_write_checkpoint_stub = nullptr;) -JFR_ONLY(address StubRoutines::_jfr_write_checkpoint = nullptr;) -JFR_ONLY(RuntimeStub* StubRoutines::_jfr_return_lease_stub = nullptr;) -JFR_ONLY(address StubRoutines::_jfr_return_lease = nullptr;) - address StubRoutines::_upcall_stub_exception_handler = nullptr; address StubRoutines::_lookup_secondary_supers_table_slow_path_stub = nullptr; diff --git a/src/hotspot/share/runtime/stubRoutines.hpp b/src/hotspot/share/runtime/stubRoutines.hpp index 762a6edf590..206a5ec2e99 100644 --- a/src/hotspot/share/runtime/stubRoutines.hpp +++ b/src/hotspot/share/runtime/stubRoutines.hpp @@ -36,7 +36,34 @@ // StubRoutines provides entry points to assembly routines used by // compiled code and the run-time system. Platform-specific entry -// points are defined in the platform-specific inner class. +// points are defined in the platform-specific inner class. Most +// routines have a single (main) entry point. However, a few routines +// do provide alternative entry points. +// +// Stub routines whose entries are advertised via class StubRoutines +// are generated in batches at well-defined stages during JVM init: +// initial stubs, continuation stubs, compiler stubs, final stubs. +// Each batch is embedded in a single, associated blob (an instance of +// BufferBlob) i.e. the blob to entry relationship is 1-m. +// +// Note that this constrasts with the much smaller number of stub +// routines generated via classes SharedRuntime, c1_Runtime1 and +// OptoRuntime. The latter routines are also generated at well-defined +// points during JVM init. However, each stub routine has its own +// unique blob (various subclasses of RuntimeBlob) i.e. the blob to +// entry relationship is 1-1. The difference arises because +// SharedRuntime routines may need to be relocatable or advertise +// properties such as a frame size via their blob. +// +// Staging of stub routine generation is needed in order to manage +// init dependencies between 1) stubs and other stubs or 2) stubs and +// other runtime components. For example, some exception throw stubs +// need to be generated before compiler stubs (such as the +// deoptimization stub) so that the latter can invoke the thrwo rotine +// in bail-out code. Likewise, stubs that access objects (such as the +// object array copy stub) need to be created after initialization of +// some GC constants and generation of the GC barrier stubs they might +// need to invoke. // // Class scheme: // @@ -49,8 +76,7 @@ // | | // | | // stubRoutines.cpp stubRoutines_.cpp -// stubRoutines_.cpp stubGenerator_.cpp -// stubRoutines_.cpp +// stubGenerator_.cpp // // Note 1: The important thing is a clean decoupling between stub // entry points (interfacing to the whole vm; i.e., 1-to-n @@ -75,6 +101,8 @@ // 3. add a public accessor function to the instance variable // 4. implement the corresponding generator function in the platform-dependent // stubGenerator_.cpp file and call the function in generate_all() of that file +// 5. ensure the entry is generated in the right blob to satisfy initialization +// dependencies between it and other stubs or runtime components. class UnsafeMemoryAccess : public CHeapObj { private: @@ -137,11 +165,6 @@ class StubRoutines: AllStatic { static address _call_stub_entry; static address _forward_exception_entry; static address _catch_exception_entry; - static address _throw_AbstractMethodError_entry; - static address _throw_IncompatibleClassChangeError_entry; - static address _throw_NullPointerException_at_call_entry; - static address _throw_StackOverflowError_entry; - static address _throw_delayed_StackOverflowError_entry; static address _atomic_xchg_entry; static address _atomic_cmpxchg_entry; @@ -269,11 +292,6 @@ class StubRoutines: AllStatic { static address _cont_returnBarrier; static address _cont_returnBarrierExc; - JFR_ONLY(static RuntimeStub* _jfr_write_checkpoint_stub;) - JFR_ONLY(static address _jfr_write_checkpoint;) - JFR_ONLY(static RuntimeStub* _jfr_return_lease_stub;) - JFR_ONLY(static address _jfr_return_lease;) - // Vector Math Routines static address _vector_f_math[VectorSupport::NUM_VEC_SIZES][VectorSupport::NUM_SVML_OP]; static address _vector_d_math[VectorSupport::NUM_VEC_SIZES][VectorSupport::NUM_SVML_OP]; @@ -329,12 +347,6 @@ class StubRoutines: AllStatic { // Exceptions static address forward_exception_entry() { return _forward_exception_entry; } - // Implicit exceptions - static address throw_AbstractMethodError_entry() { return _throw_AbstractMethodError_entry; } - static address throw_IncompatibleClassChangeError_entry(){ return _throw_IncompatibleClassChangeError_entry; } - static address throw_NullPointerException_at_call_entry(){ return _throw_NullPointerException_at_call_entry; } - static address throw_StackOverflowError_entry() { return _throw_StackOverflowError_entry; } - static address throw_delayed_StackOverflowError_entry() { return _throw_delayed_StackOverflowError_entry; } static address atomic_xchg_entry() { return _atomic_xchg_entry; } static address atomic_cmpxchg_entry() { return _atomic_cmpxchg_entry; } @@ -487,9 +499,6 @@ class StubRoutines: AllStatic { static address cont_returnBarrier() { return _cont_returnBarrier; } static address cont_returnBarrierExc(){return _cont_returnBarrierExc; } - JFR_ONLY(static address jfr_write_checkpoint() { return _jfr_write_checkpoint; }) - JFR_ONLY(static address jfr_return_lease() { return _jfr_return_lease; }) - static address upcall_stub_exception_handler() { assert(_upcall_stub_exception_handler != nullptr, "not implemented"); return _upcall_stub_exception_handler; From 6d430f24df9d599fe1e12c6b65117c02773ae5d8 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Mon, 19 Aug 2024 09:08:54 +0000 Subject: [PATCH 449/460] 8338314: JFR: Split JFRCheckpoint VM operation Reviewed-by: mgronlun, egahlin --- .../recorder/service/jfrRecorderService.cpp | 28 ++++++++++++------- .../recorder/service/jfrRecorderService.hpp | 2 ++ src/hotspot/share/runtime/vmOperation.hpp | 3 +- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp index 0395b711c65..9f24bddcd3c 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp @@ -393,14 +393,22 @@ static u4 write_metadata(JfrChunkWriter& chunkwriter) { return invoke(wm); } -template -class JfrVMOperation : public VM_Operation { +class JfrSafepointClearVMOperation : public VM_Operation { private: - Instance& _instance; + JfrRecorderService& _instance; + public: + JfrSafepointClearVMOperation(JfrRecorderService& instance) : _instance(instance) {} + void doit() { _instance.safepoint_clear(); } + VMOp_Type type() const { return VMOp_JFRSafepointClear; } +}; + +class JfrSafepointWriteVMOperation : public VM_Operation { + private: + JfrRecorderService& _instance; public: - JfrVMOperation(Instance& instance) : _instance(instance) {} - void doit() { (_instance.*func)(); } - VMOp_Type type() const { return VMOp_JFRCheckpoint; } + JfrSafepointWriteVMOperation(JfrRecorderService& instance) : _instance(instance) {} + void doit() { _instance.safepoint_write(); } + VMOp_Type type() const { return VMOp_JFRSafepointWrite; } }; JfrRecorderService::JfrRecorderService() : @@ -470,9 +478,9 @@ void JfrRecorderService::pre_safepoint_clear() { } void JfrRecorderService::invoke_safepoint_clear() { - JfrVMOperation safepoint_task(*this); + JfrSafepointClearVMOperation op(*this); ThreadInVMfromNative transition(JavaThread::current()); - VMThread::execute(&safepoint_task); + VMThread::execute(&op); } void JfrRecorderService::safepoint_clear() { @@ -577,10 +585,10 @@ void JfrRecorderService::pre_safepoint_write() { } void JfrRecorderService::invoke_safepoint_write() { - JfrVMOperation safepoint_task(*this); + JfrSafepointWriteVMOperation op(*this); // can safepoint here ThreadInVMfromNative transition(JavaThread::current()); - VMThread::execute(&safepoint_task); + VMThread::execute(&op); } void JfrRecorderService::safepoint_write() { diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.hpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.hpp index 89c0437dd13..e5b4500afc0 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.hpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.hpp @@ -35,6 +35,8 @@ class JfrStorage; class JfrStringPool; class JfrRecorderService : public StackObj { + friend class JfrSafepointClearVMOperation; + friend class JfrSafepointWriteVMOperation; private: JfrCheckpointManager& _checkpoint_manager; JfrChunkWriter& _chunkwriter; diff --git a/src/hotspot/share/runtime/vmOperation.hpp b/src/hotspot/share/runtime/vmOperation.hpp index 36aa6d3f28a..532a9231b70 100644 --- a/src/hotspot/share/runtime/vmOperation.hpp +++ b/src/hotspot/share/runtime/vmOperation.hpp @@ -87,7 +87,8 @@ template(HeapWalkOperation) \ template(HeapIterateOperation) \ template(ReportJavaOutOfMemory) \ - template(JFRCheckpoint) \ + template(JFRSafepointClear) \ + template(JFRSafepointWrite) \ template(ShenandoahFullGC) \ template(ShenandoahInitMark) \ template(ShenandoahFinalMarkStartEvac) \ From e07a5b66267156f55ee1c28579382990e58f15eb Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Mon, 19 Aug 2024 10:42:58 +0000 Subject: [PATCH 450/460] 8338512: JFR: Revert changes to TestCodeSweeper Reviewed-by: mgronlun --- test/jdk/ProblemList.txt | 1 + .../jfr/event/compiler/TestCodeSweeper.java | 54 ++++++------------- 2 files changed, 17 insertions(+), 38 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 6cde7111383..bbf594f3bc7 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -743,6 +743,7 @@ jdk/incubator/vector/LoadJsvmlTest.java 8305390 windows- # jdk_jfr +jdk/jfr/event/compiler/TestCodeSweeper.java 8338127 generic-all jdk/jfr/event/runtime/TestResidentSetSizeEvent.java 8309846 aix-ppc64 jdk/jfr/jvm/TestWaste.java 8282427 generic-all diff --git a/test/jdk/jdk/jfr/event/compiler/TestCodeSweeper.java b/test/jdk/jdk/jfr/event/compiler/TestCodeSweeper.java index df95af5b9be..62fb137b1cf 100644 --- a/test/jdk/jdk/jfr/event/compiler/TestCodeSweeper.java +++ b/test/jdk/jdk/jfr/event/compiler/TestCodeSweeper.java @@ -27,11 +27,9 @@ import java.lang.reflect.Method; import java.time.Instant; import java.util.ArrayList; -import java.util.Collections; import java.util.List; -import jdk.jfr.Event; -import jdk.jfr.consumer.RecordingStream; +import jdk.jfr.Recording; import jdk.jfr.consumer.RecordedEvent; import jdk.test.lib.Asserts; import jdk.test.lib.jfr.EventNames; @@ -41,7 +39,7 @@ import jdk.test.whitebox.code.CodeBlob; /** - * Test for events: jdk.CodeCacheFull jdk.CompilationFailure + * Test for events: vm/code_cache/full vm/compiler/failure * * We verify that we should get at least one of each of the events listed above. * @@ -60,15 +58,13 @@ */ public class TestCodeSweeper { - static class ProvocationEvent extends Event { - } private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); private static final int COMP_LEVEL_SIMPLE = 1; private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4; private static final int SIZE = 1; private static final String METHOD_NAME = "verifyFullEvent"; - private static final String EVENT_CODE_CACHE_FULL = EventNames.CodeCacheFull; - private static final String EVENT_COMPILATION_FAILURE = EventNames.CompilationFailure; + private static final String pathFull = EventNames.CodeCacheFull; + private static final String pathFailure = EventNames.CompilationFailure; public static final long SEGMENT_SIZE = WhiteBox.getWhiteBox().getUintxVMFlag("CodeCacheSegmentSize"); public static final long MIN_BLOCK_LENGTH = WhiteBox.getWhiteBox().getUintxVMFlag("CodeCacheMinBlockLength"); public static final long MIN_ALLOCATION = SEGMENT_SIZE * MIN_BLOCK_LENGTH; @@ -81,41 +77,26 @@ public static void main(String[] args) throws Throwable { System.out.println("This test will warn that the code cache is full."); System.out.println("That is expected and is the purpose of the test."); System.out.println("************************************************"); - List events = Collections.synchronizedList(new ArrayList<>()); - try (RecordingStream rs = new RecordingStream()) { - rs.setReuse(false); - rs.enable(EVENT_CODE_CACHE_FULL); - rs.enable(EVENT_COMPILATION_FAILURE); - rs.onEvent(EVENT_CODE_CACHE_FULL, events::add); - rs.onEvent(EVENT_COMPILATION_FAILURE, events::add); - rs.onEvent(ProvocationEvent.class.getName(), e -> { - if (!events.isEmpty()) { - rs.close(); - return; - } - // Retry if CodeCacheFull or CompilationFailure events weren't provoked - try { - provokeEvents(); - } catch (Exception ex) { - ex.printStackTrace(); - rs.close(); - } - }); - rs.startAsync(); - provokeEvents(); - rs.awaitTermination(); - } + + Recording r = new Recording(); + r.enable(pathFull); + r.enable(pathFailure); + r.start(); + provokeEvents(); + r.stop(); int countEventFull = 0; int countEventFailure = 0; + + List events = Events.fromRecording(r); Events.hasEvents(events); - for (RecordedEvent event : new ArrayList<>(events)) { + for (RecordedEvent event : events) { switch (event.getEventType().getName()) { - case EVENT_CODE_CACHE_FULL: + case pathFull: countEventFull++; verifyFullEvent(event); break; - case EVENT_COMPILATION_FAILURE: + case pathFailure: countEventFailure++; verifyFailureEvent(event); break; @@ -134,8 +115,6 @@ private static boolean canAllocate(double size, long maxSize, MemoryPoolMXBean b } private static void provokeEvents() throws NoSuchMethodException, InterruptedException { - System.out.println("provokeEvents()"); - ProvocationEvent provocationEvent = new ProvocationEvent(); // Prepare for later, since we don't want to trigger any compilation // setting this up. Method method = TestCodeSweeper.class.getDeclaredMethod(METHOD_NAME, new Class[] { RecordedEvent.class }); @@ -180,7 +159,6 @@ private static void provokeEvents() throws NoSuchMethodException, InterruptedExc for (Long blob : blobs) { WHITE_BOX.freeCodeBlob(blob); } - provocationEvent.commit(); } private static void verifyFullEvent(RecordedEvent event) throws Throwable { From 6ff6b0994380276e0096f7b55a0d659803344679 Mon Sep 17 00:00:00 2001 From: Renjith Kannath Pariyangad Date: Mon, 19 Aug 2024 12:40:35 +0000 Subject: [PATCH 451/460] 8290501: Typo in javax.swing.BoundedRangeModel documentation Reviewed-by: aivanov, prr, honkar --- .../share/classes/javax/swing/BoundedRangeModel.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/java.desktop/share/classes/javax/swing/BoundedRangeModel.java b/src/java.desktop/share/classes/javax/swing/BoundedRangeModel.java index bc6a84ac891..e6a9d08611d 100644 --- a/src/java.desktop/share/classes/javax/swing/BoundedRangeModel.java +++ b/src/java.desktop/share/classes/javax/swing/BoundedRangeModel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ package javax.swing; -import javax.swing.event.*; +import javax.swing.event.ChangeListener; /** @@ -40,7 +40,7 @@ * range is value,value+extent. The inner range * must lie within the outer one, i.e. value must be * less than or equal to maximum and value+extent - * must greater than or equal to minimum, and maximum + * must be greater than or equal to minimum, and maximum * must be greater than or equal to minimum. * There are a few features of this model that one might find a little * surprising. These quirks exist for the convenience of the @@ -228,7 +228,7 @@ public interface BoundedRangeModel /** - * This method sets all of the model's data with a single method call. + * This method sets all the model's data with a single method call. * The method results in a single change event being generated. This is * convenient when you need to adjust all the model data simultaneously and * do not want individual change events to occur. From f0fe31383aec652ad4e3cc4873cd3ff9b918fef7 Mon Sep 17 00:00:00 2001 From: Adam Sotona Date: Mon, 19 Aug 2024 12:57:17 +0000 Subject: [PATCH 452/460] 8338564: Remove obsolete AbstractNamedEntry::equals method Reviewed-by: liach --- .../jdk/internal/classfile/impl/AbstractPoolEntry.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java index c6e6c4dce57..c27968eecab 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java @@ -534,15 +534,6 @@ public Utf8Entry name() { public String asInternalName() { return ref1.stringValue(); } - - @Override - public boolean equals(Object o) { - if (o == this) { return true; } - if (o instanceof AbstractNamedEntry ne) { - return tag == ne.tag() && name().equals(ref1()); - } - return false; - } } public static final class ClassEntryImpl extends AbstractNamedEntry implements ClassEntry { From 2766b09e29d7c1c31fdef20f016a181eedb2d429 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Mon, 19 Aug 2024 12:57:29 +0000 Subject: [PATCH 453/460] 8338452: (dc) DatagramChannelImpl.blockingReceive with timeout may block indefinitely if all datagrams blocked by SecurityManager Reviewed-by: dfuchs --- .../classes/sun/nio/ch/DatagramChannelImpl.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java index 06e79f416ac..5fac688b311 100644 --- a/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java @@ -683,14 +683,12 @@ void blockingReceive(DatagramPacket p, long nanos) throws IOException { } long startNanos = System.nanoTime(); + long remainingNanos = nanos; SocketAddress sender = null; try { SocketAddress remote = beginRead(true, false); boolean connected = (remote != null); do { - long remainingNanos = (nanos > 0) - ? nanos - (System.nanoTime() - startNanos) - : 0; ByteBuffer dst = tryBlockingReceive(connected, bufLength, remainingNanos); // if datagram received then get sender and copy to DatagramPacket @@ -711,8 +709,8 @@ void blockingReceive(DatagramPacket p, long nanos) throws IOException { } } - // copy bytes to the DatagramPacket, and set length and sender if (sender != null) { + // copy bytes to the DatagramPacket, and set length and sender synchronized (p) { // re-read p.bufLength in case DatagramPacket changed int len = Math.min(dst.limit(), DatagramPackets.getBufLength(p)); @@ -720,6 +718,14 @@ void blockingReceive(DatagramPacket p, long nanos) throws IOException { DatagramPackets.setLength(p, len); p.setSocketAddress(sender); } + } else { + // need to retry, adjusting timeout if needed + if (nanos > 0) { + remainingNanos = nanos - (System.nanoTime() - startNanos); + if (remainingNanos <= 0) { + throw new SocketTimeoutException("Receive timed out"); + } + } } } finally { Util.offerFirstTemporaryDirectBuffer(dst); @@ -746,6 +752,7 @@ void blockingReceive(DatagramPacket p, long nanos) throws IOException { private ByteBuffer tryBlockingReceive(boolean connected, int len, long nanos) throws IOException { + assert nanos >= 0; long startNanos = System.nanoTime(); ByteBuffer dst = Util.getTemporaryDirectBuffer(len); int n = -1; From 3ca359ad224b07f283c99eb43bed02eb93ef2dc7 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Mon, 19 Aug 2024 13:47:40 +0000 Subject: [PATCH 454/460] 8335771: Improve stability of java/nio/channels/DatagramChannel tests Reviewed-by: alanb --- .../DatagramChannel/AdaptorMulticasting.java | 32 ++++-- .../DatagramChannel/AfterDisconnect.java | 99 +++++++++++++++---- .../nio/channels/DatagramChannel/Connect.java | 18 +++- .../ManySourcesAndTargets.java | 27 ++++- .../MulticastSendReceiveTests.java | 21 +++- .../channels/DatagramChannel/NotBound.java | 74 ++++++++++---- .../channels/DatagramChannel/Promiscuous.java | 43 ++++---- .../channels/DatagramChannel/ReceiveISA.java | 18 +++- .../DatagramChannel/SelectWhenRefused.java | 60 ++++++++--- .../DatagramChannel/SendReceiveMaxSize.java | 33 ++++++- .../nio/channels/DatagramChannel/Sender.java | 52 ++++++---- 11 files changed, 365 insertions(+), 112 deletions(-) diff --git a/test/jdk/java/nio/channels/DatagramChannel/AdaptorMulticasting.java b/test/jdk/java/nio/channels/DatagramChannel/AdaptorMulticasting.java index 0c8da1ff9d9..cab2bc76285 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/AdaptorMulticasting.java +++ b/test/jdk/java/nio/channels/DatagramChannel/AdaptorMulticasting.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,6 +48,7 @@ import java.util.stream.Collectors; import static java.net.StandardSocketOptions.*; import static java.net.StandardProtocolFamily.*; +import static jdk.test.lib.NetworkConfiguration.isSameInterface; import jdk.test.lib.NetworkConfiguration; import jdk.test.lib.net.IPSupport; @@ -295,8 +296,8 @@ static void testNetworkInterface(MulticastSocket s, // setNetworkInterface s.setNetworkInterface(ni); - assertTrue(s.getNetworkInterface().equals(ni)); - assertTrue(s.getOption(IP_MULTICAST_IF).equals(ni)); + assertTrue(isSameInterface(s.getNetworkInterface(), ni)); + assertTrue(isSameInterface(s.getOption(IP_MULTICAST_IF), ni)); InetAddress address = s.getInterface(); assertTrue(ni.inetAddresses().filter(address::equals).findAny().isPresent()); @@ -315,8 +316,8 @@ static void testNetworkInterface(MulticastSocket s, // setOption(IP_MULTICAST_IF) s.setOption(IP_MULTICAST_IF, ni); - assertTrue(s.getOption(IP_MULTICAST_IF).equals(ni)); - assertTrue(s.getNetworkInterface().equals(ni)); + assertTrue(isSameInterface(s.getOption(IP_MULTICAST_IF), ni)); + assertTrue(isSameInterface(s.getNetworkInterface(), ni)); // bad values for IP_MULTICAST_IF assertThrows(IllegalArgumentException.class, @@ -412,7 +413,8 @@ static void testSendReceive(MulticastSocket s, InetAddress group) throws IOExcep assertTrue(s.getOption(IP_MULTICAST_IF) != null); SocketAddress target = new InetSocketAddress(group, s.getLocalPort()); - byte[] message = "hello".getBytes("UTF-8"); + String msg = "AdaptorMulticasting: " + System.nanoTime(); + byte[] message = msg.getBytes("UTF-8"); // send message to multicast group DatagramPacket p = new DatagramPacket(message, message.length); @@ -421,8 +423,22 @@ static void testSendReceive(MulticastSocket s, InetAddress group) throws IOExcep // receive message s.setSoTimeout(0); - p = new DatagramPacket(new byte[1024], 100); - s.receive(p); + while (true) { + p = new DatagramPacket(new byte[1024], 100); + s.receive(p); + if (p.getPort() == s.getLocalPort()) { + String str = new String(p.getData(), p.getOffset(), p.getLength(), "UTF-8"); + if (Arrays.equals(p.getData(), p.getOffset(), p.getLength(), message, 0, message.length)) { + System.out.format("Got expected message \"%s\" from %s%n", str, p.getSocketAddress()); + break; + } + System.out.println("Unexpected message received. Expected: " + msg); + System.out.println("Received message doesn't match - skipping: " + str); + } else { + System.out.println("Unexpected message received. Expected message from: " + s.getLocalAddress()); + System.out.println("Received message sender doesn't match - skipping: " + p.getSocketAddress()); + } + } assertTrue(p.getLength() == message.length); assertTrue(p.getPort() == s.getLocalPort()); diff --git a/test/jdk/java/nio/channels/DatagramChannel/AfterDisconnect.java b/test/jdk/java/nio/channels/DatagramChannel/AfterDisconnect.java index 6a80d686b30..de59984dae1 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/AfterDisconnect.java +++ b/test/jdk/java/nio/channels/DatagramChannel/AfterDisconnect.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ */ import java.io.IOException; +import java.net.BindException; import java.net.InetAddress; import java.net.Inet6Address; import java.net.InetSocketAddress; @@ -46,6 +47,7 @@ import java.nio.channels.Selector; import java.util.HashMap; import java.util.Map; +import java.util.function.Predicate; import org.testng.annotations.Test; import static org.testng.Assert.*; @@ -54,6 +56,38 @@ public class AfterDisconnect { + interface RetryableTest { + public void runTest() throws T; + } + + // retry the given lambda (RetryableTest) if an exception + // that satisfies the predicate (retryOn) is caught. + void testWithRetry(RetryableTest test, + Predicate retryOn, + int max) throws T { + for (int i=0; i < max; i++) { + try { + test.runTest(); + break; + } catch (Throwable t) { + if (i < max -1 && retryOn.test(t)) { + System.out.println("Got " + t + "; will retry"); + } else throw t; + } + } + } + + /** + * When calling {@link DatagramChannel#disconnect()} a {@link BindException} + * may occur. In which case we want to retry the test. + */ + class BindExceptionOnDisconnect extends BindException { + BindExceptionOnDisconnect(BindException x) { + super(x.getMessage()); + initCause(x); + } + } + @Test public void execute() throws IOException { IPSupport.throwSkippedExceptionIfNonOperational(); @@ -61,34 +95,41 @@ public void execute() throws IOException { InetAddress lb = InetAddress.getLoopbackAddress(); // test with default protocol family - try (DatagramChannel dc = DatagramChannel.open()) { - System.out.println("Test with default"); - dc.bind(new InetSocketAddress(lb, 0)); - test(dc); - test(dc); - } - - // test with IPv6 socket - if (IPSupport.hasIPv6()) { - System.out.println("Test with IPv6 socket"); - try (DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET6)) { + System.out.println("Test with default"); + testWithRetry(() -> { + try (DatagramChannel dc = DatagramChannel.open()) { dc.bind(new InetSocketAddress(lb, 0)); test(dc); test(dc); } + }, BindExceptionOnDisconnect.class::isInstance, 5); + + // test with IPv6 socket + if (IPSupport.hasIPv6()) { + System.out.println("Test with IPv6 socket"); + testWithRetry(() -> { + try (DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET6)) { + dc.bind(new InetSocketAddress(lb, 0)); + test(dc); + test(dc); + } + }, BindExceptionOnDisconnect.class::isInstance, 5); } // test with IPv4 socket if (IPSupport.hasIPv4() && !preferIPv6) { System.out.println("Test with IPv4 socket"); - try (DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET)) { - dc.bind(new InetSocketAddress(lb, 0)); - test(dc); - test(dc); - } + testWithRetry(() -> { + try (DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET)) { + dc.bind(new InetSocketAddress(lb, 0)); + test(dc); + test(dc); + } + }, BindExceptionOnDisconnect.class::isInstance, 5); } } + void test(DatagramChannel dc) throws IOException { testLocalAddress(dc); testSocketOptions(dc); @@ -111,7 +152,11 @@ void testLocalAddress(DatagramChannel dc) throws IOException { assertEquals(dc.getLocalAddress(), local); assertEquals(dc.getRemoteAddress(), remote); - dc.disconnect(); + try { + dc.disconnect(); + } catch (BindException x) { + throw new BindExceptionOnDisconnect(x); + } assertFalse(dc.isConnected()); assertEquals(dc.getLocalAddress(), local); assertTrue(dc.getRemoteAddress() == null); @@ -134,7 +179,11 @@ void testSocketOptions(DatagramChannel dc) throws IOException { Map, Object> map = options(dc); dc.connect(dc.getLocalAddress()); - dc.disconnect(); + try { + dc.disconnect(); + } catch (BindException x) { + throw new BindExceptionOnDisconnect(x); + } // check socket options have not changed assertEquals(map, options(dc)); @@ -168,7 +217,11 @@ void testSelectorRegistration(DatagramChannel dc) throws IOException { sel.selectNow(); dc.connect(dc.getLocalAddress()); - dc.disconnect(); + try { + dc.disconnect(); + } catch (BindException x) { + throw new BindExceptionOnDisconnect(x); + } // selection key should still be valid assertTrue(key.isValid()); @@ -210,7 +263,11 @@ void testMulticastGroups(DatagramChannel dc) throws IOException { MembershipKey key = dc.join(group, ni); dc.connect(dc.getLocalAddress()); - dc.disconnect(); + try { + dc.disconnect(); + } catch (BindException x) { + throw new BindExceptionOnDisconnect(x); + } // membership key should still be valid assertTrue(key.isValid()); diff --git a/test/jdk/java/nio/channels/DatagramChannel/Connect.java b/test/jdk/java/nio/channels/DatagramChannel/Connect.java index 082a3234cc5..41c172b3328 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/Connect.java +++ b/test/jdk/java/nio/channels/DatagramChannel/Connect.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,8 @@ /* @test * @bug 4313882 7183800 + * @library /test/lib + * @build jdk.test.lib.Platform Connect * @run main/othervm Connect * @summary Test DatagramChannel's send and receive methods */ @@ -38,6 +40,8 @@ import java.util.concurrent.CompletionException; import java.util.stream.Stream; +import jdk.test.lib.Platform; + import static java.nio.charset.StandardCharsets.US_ASCII; public class Connect { @@ -114,9 +118,21 @@ public void run() { ByteBuffer bb = ByteBuffer.allocateDirect(MAX); bb.put(bytes); bb.flip(); + // When connecting an unbound datagram channel, the underlying + // socket will first be bound to the wildcard address. On macOS, + // the system may allocate the same port on which another socket + // is already bound with a more specific address. This may prevent + // datagrams directed at the connected socket to reach it. + // To avoid this, when on macOS, we preemptively bind `dc` to the + // specific address instead of letting it bind to the wildcard. + if (Platform.isOSX()) { + dc.bind(new InetSocketAddress(((InetSocketAddress)connectSocketAddress).getAddress(), 0)); + err.println("Initiator bound to: " + connectSocketAddress); + } err.println("Initiator connecting to: " + connectSocketAddress); dc.connect(connectSocketAddress); err.println("Initiator bound to: " + dc.getLocalAddress()); + assert !connectSocketAddress.equals(dc.getLocalAddress()); // Send a message err.println("Initiator attempting to write to Responder at " + connectSocketAddress); diff --git a/test/jdk/java/nio/channels/DatagramChannel/ManySourcesAndTargets.java b/test/jdk/java/nio/channels/DatagramChannel/ManySourcesAndTargets.java index ed4e9c0c02e..18a18fcba0a 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/ManySourcesAndTargets.java +++ b/test/jdk/java/nio/channels/DatagramChannel/ManySourcesAndTargets.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* @test * @bug 8234805 8235193 * @summary Test DatagramChannel send/receive and that receive returns the expected - * sender address + * sender address. * @run main/othervm ManySourcesAndTargets * @run main/othervm -Djava.net.preferIPv4Stack=true ManySourcesAndTargets */ @@ -63,6 +63,7 @@ public static void main(String[] args) throws Exception { try (DatagramChannel reader = DatagramChannel.open()) { // bind reader to wildcard address so it can receive from any address reader.bind(new InetSocketAddress(0)); + System.out.println("\nReader bound to: " + reader.getLocalAddress()); for (InetAddress address : addresses) { System.out.format("%n-- %s --%n", address.getHostAddress()); @@ -75,6 +76,7 @@ public static void main(String[] args) throws Exception { try (DatagramChannel sender = DatagramChannel.open()) { // bind sender to wildcard address so it can send to any address sender.bind(new InetSocketAddress(0)); + System.out.println("\nSender bound to: " + sender.getLocalAddress()); for (InetAddress address : addresses) { System.out.format("%n-- %s --%n", address.getHostAddress()); @@ -97,6 +99,11 @@ static void testSend(int count, InetAddress address, DatagramChannel reader) thr sender.bind(new InetSocketAddress(address, 0)); SocketAddress local = sender.getLocalAddress(); + System.out.println("Sender bound to: " + local); + if (((InetSocketAddress)local).getPort() == remotePort) { + System.out.println("testSend: Sender and reader have same port: skipping"); + return; + } byte[] bytes = serialize(local); SocketAddress previousSource = null; @@ -105,6 +112,8 @@ static void testSend(int count, InetAddress address, DatagramChannel reader) thr sender.send(ByteBuffer.wrap(bytes), remote); ByteBuffer bb = ByteBuffer.allocate(1000); + System.out.format("testSend: reader waiting to receive at: %s%n", + reader.getLocalAddress()); SocketAddress source = reader.receive(bb); System.out.format("received datagram from %s%n", source); @@ -138,11 +147,18 @@ static void testReceive(int count, DatagramChannel sender, InetAddress address) SocketAddress remote = reader.getLocalAddress(); + System.out.println("Reader bound to: " + remote); + if (((InetSocketAddress)local).getPort() == ((InetSocketAddress)remote).getPort()) { + System.out.println("testReceive: Sender and reader have same port: skipping"); + return; + } for (int i = 0; i < count; i++) { System.out.format("send %s -> %s%n", local, remote); sender.send(ByteBuffer.allocate(32), remote); ByteBuffer bb = ByteBuffer.allocate(1000); + System.out.format("testReceive: reader waiting to receive at: %s%n", + reader.getLocalAddress()); SocketAddress source = reader.receive(bb); System.out.format("received datagram from %s%n", source); } @@ -165,7 +181,12 @@ private static SocketAddress deserialize(byte[] bytes) throws Exception { private static Optional networkInterface(InetAddress ia) { try { - return Optional.ofNullable(NetworkInterface.getByInetAddress(ia)); + NetworkInterface nif = NetworkInterface.getByInetAddress(ia); + if (nif != null) { + System.out.format("Selecting interface %s[%d]%n\twith addresses:%n\t%s%n", + nif.getDisplayName(), nif.getIndex(), nif.inetAddresses().toList()); + } + return Optional.ofNullable(nif); } catch (SocketException e) { return Optional.empty(); } diff --git a/test/jdk/java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java b/test/jdk/java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java index c1ea04ba216..87aedc8efd9 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java +++ b/test/jdk/java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -99,15 +99,25 @@ static void receiveDatagram(DatagramChannel dc, ByteBuffer buf = ByteBuffer.allocateDirect(100); try { + long elapsed = 0; for (;;) { System.out.println("Waiting to receive message"); + long start = System.nanoTime(); sel.select(5*1000); + long waited = (System.nanoTime() - start) / 1000_000; + elapsed += waited; + buf.clear(); SocketAddress sa = dc.receive(buf); // no datagram received if (sa == null) { if (expectedSender != null) { - throw new RuntimeException("Expected message not received"); + if (elapsed > 4800) { + throw new RuntimeException("Expected message not received"); + } else { + sel.selectedKeys().clear(); + continue; + } } System.out.println("No message received (correct)"); return; @@ -123,8 +133,8 @@ static void receiveDatagram(DatagramChannel dc, int receivedId = -1; try { receivedId = Integer.parseInt(s); - System.out.format("Received message from %s (id=0x%x)\n", - sender, receivedId); + System.out.format("Received message from %s (id=0x%x, length=%s)\n", + sender, receivedId, bytes.length); } catch (NumberFormatException x) { System.out.format("Received message from %s (msg=%s)\n", sender, s); } @@ -142,7 +152,6 @@ static void receiveDatagram(DatagramChannel dc, } sel.selectedKeys().clear(); - buf.rewind(); } } finally { sel.close(); @@ -160,6 +169,8 @@ static void test(ProtocolFamily family, throws IOException { System.out.format("\nTest DatagramChannel to %s socket\n", family.name()); + System.out.format("With interface=%s[%s]%n\twith bound addresses:%n\t%s%n", + nif.getDisplayName(), nif.getIndex(), nif.inetAddresses().toList()); try (DatagramChannel dc = (family == UNSPEC) ? DatagramChannel.open() : DatagramChannel.open(family)) { dc.setOption(StandardSocketOptions.SO_REUSEADDR, true) diff --git a/test/jdk/java/nio/channels/DatagramChannel/NotBound.java b/test/jdk/java/nio/channels/DatagramChannel/NotBound.java index 4cd9a030336..bcd73591bf9 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/NotBound.java +++ b/test/jdk/java/nio/channels/DatagramChannel/NotBound.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,19 +24,26 @@ /* @test * @bug 4512723 6621689 * @summary Test that connect/send/receive with unbound DatagramChannel causes - * the channel's socket to be bound to a local address + * the channel's socket to be bound to a local address. + * @run main/othervm NotBound */ import java.net.*; import java.nio.ByteBuffer; import java.nio.channels.DatagramChannel; import java.io.IOException; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; public class NotBound { + static final CountDownLatch received = new CountDownLatch(1); + static void checkBound(DatagramChannel dc) throws IOException { if (dc.getLocalAddress() == null) throw new RuntimeException("Not bound??"); + System.out.println("Bound to: " + dc.getLocalAddress()); } // starts a thread to send a datagram to the given channel once the channel @@ -51,19 +58,44 @@ public void run() { Thread.sleep(50); local = (InetSocketAddress)dc.getLocalAddress(); } while (local == null); + System.out.format("receiver bound to: %s%n", local); - // send message to channel to wakeup receiver - DatagramChannel sender = DatagramChannel.open(); - try { - ByteBuffer bb = ByteBuffer.wrap("hello".getBytes()); - InetAddress lh = InetAddress.getLocalHost(); - SocketAddress target = - new InetSocketAddress(lh, local.getPort()); - sender.send(bb, target); - } finally { - sender.close(); + boolean isAnyLocal = local.getAddress().isAnyLocalAddress(); + int maxAttempts = 5; + int localPort = 0; + List llh = isAnyLocal + ? List.of(InetAddress.getLocalHost(), InetAddress.getLoopbackAddress()) + : List.of(local.getAddress()); + SocketAddress target = null; + for (int i = 0 ; i < maxAttempts ; i++) { + InetAddress lh = llh.get(i % llh.size()); + target = new InetSocketAddress(lh, local.getPort()); + // send message to channel to wakeup receiver + try (DatagramChannel sender = DatagramChannel.open()) { + ByteBuffer bb = ByteBuffer.wrap("NotBound: hello".getBytes()); + sender.send(bb, target); + System.out.format("Woke up receiver: sent datagram to %s from %s%n", + target, sender.getLocalAddress()); + localPort = ((InetSocketAddress)sender.getLocalAddress()).getPort(); + } + if (received.await(250, TimeUnit.MILLISECONDS)) { + // The datagram has been received: no need to continue + // sending + break; + } + // if sender port and destination port were identical, which + // could happen on some systems, the receiver might not receive + // the datagram. So in that case we try again, bailing out if + // we had to retry too many times + if (localPort == local.getPort()) { + System.out.println("Local port and peer port are identical. Retrying..."); + } else { + System.out.println("Datagram not received after 250ms. Retrying..."); + } + } + if (localPort == local.getPort()) { + System.out.println("Couldn't find a port to send to " + target); } - } catch (Exception x) { x.printStackTrace(); } @@ -77,14 +109,12 @@ public static void main(String[] args) throws IOException { // connect dc = DatagramChannel.open(); try { - DatagramChannel peer = DatagramChannel.open() - .bind(new InetSocketAddress(0)); - int peerPort = ((InetSocketAddress)(peer.getLocalAddress())).getPort(); - try { + System.out.println("Check that connect() binds the socket"); + try (DatagramChannel peer = DatagramChannel.open()) { + peer.bind(new InetSocketAddress(0)); + int peerPort = ((InetSocketAddress)(peer.getLocalAddress())).getPort(); dc.connect(new InetSocketAddress(InetAddress.getLocalHost(), peerPort)); checkBound(dc); - } finally { - peer.close(); } } finally { dc.close(); @@ -93,7 +123,8 @@ public static void main(String[] args) throws IOException { // send dc = DatagramChannel.open(); try { - ByteBuffer bb = ByteBuffer.wrap("ignore this".getBytes()); + System.out.println("Check that send() binds the socket"); + ByteBuffer bb = ByteBuffer.wrap("NotBound: ignore this".getBytes()); SocketAddress target = new InetSocketAddress(InetAddress.getLocalHost(), 5000); dc.send(bb, target); @@ -105,9 +136,11 @@ public static void main(String[] args) throws IOException { // receive (blocking) dc = DatagramChannel.open(); try { + System.out.println("Check that blocking receive() binds the socket"); ByteBuffer bb = ByteBuffer.allocateDirect(128); wakeupWhenBound(dc); SocketAddress sender = dc.receive(bb); + received.countDown(); if (sender == null) throw new RuntimeException("Sender should not be null"); checkBound(dc); @@ -118,6 +151,7 @@ public static void main(String[] args) throws IOException { // receive (non-blocking) dc = DatagramChannel.open(); try { + System.out.println("Check that non-blocking receive() binds the socket"); dc.configureBlocking(false); ByteBuffer bb = ByteBuffer.allocateDirect(128); SocketAddress sender = dc.receive(bb); diff --git a/test/jdk/java/nio/channels/DatagramChannel/Promiscuous.java b/test/jdk/java/nio/channels/DatagramChannel/Promiscuous.java index 8db9c60c0b5..a8a5772b87b 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/Promiscuous.java +++ b/test/jdk/java/nio/channels/DatagramChannel/Promiscuous.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -71,9 +71,11 @@ static int sendDatagram(NetworkInterface nif, dc.setOption(StandardSocketOptions.IP_MULTICAST_IF, nif); byte[] msg = Integer.toString(id).getBytes("UTF-8"); ByteBuffer buf = ByteBuffer.wrap(msg); - System.out.format("Send message -> group %s (id=0x%x)\n", - group.getHostAddress(), id); + System.out.format("Send message -> group [%s]:%d (id=0x%x) nif:%s[%s]%n", + group.getHostAddress(), port, id, nif.getDisplayName(), nif.getIndex()); + System.out.format("bound address before send: %s%n", dc.getLocalAddress()); dc.send(buf, new InetSocketAddress(group, port)); + System.out.format("bound address after send: %s%n", dc.getLocalAddress()); } return id; } @@ -97,15 +99,26 @@ static void receiveDatagram(DatagramChannel dc, ByteBuffer buf = ByteBuffer.allocateDirect(100); try { + long elapsed = 0; for (;;) { System.out.println("Waiting to receive message"); + long start = System.nanoTime(); sel.select(5*1000); + long waited = (System.nanoTime() - start) / 1000_000; + elapsed += waited; + buf.clear(); SocketAddress sa = dc.receive(buf); // no datagram received if (sa == null) { if (datagramExpected) { - throw new RuntimeException("Expected message not received"); + if (elapsed > 4800) { + throw new RuntimeException("Expected message not received"); + } else { + sel.selectedKeys().clear(); + // We haven't waited long enough, + continue; + } } System.out.println("No message received (correct)"); return; @@ -121,8 +134,8 @@ static void receiveDatagram(DatagramChannel dc, int receivedId = -1; try { receivedId = Integer.parseInt(s); - System.out.format("Received message from %s (id=0x%x)\n", - sender, receivedId); + System.out.format("Received message from %s (id=0x%x, length=%s)\n", + sender, receivedId, bytes.length); } catch (NumberFormatException x) { System.out.format("Received message from %s (msg=%s)\n", sender, s); } @@ -140,7 +153,6 @@ static void receiveDatagram(DatagramChannel dc, } sel.selectedKeys().clear(); - buf.rewind(); } } finally { sel.close(); @@ -155,13 +167,14 @@ static void test(ProtocolFamily family, { System.out.format("%nTest family=%s%n", family.name()); + System.out.format("With interface=%s[%s]%n\twith bound addresses:%n\t%s%n", + nif.getDisplayName(), nif.getIndex(), nif.inetAddresses().toList()); - DatagramChannel dc1 = (family == UNSPEC) ? - DatagramChannel.open() : DatagramChannel.open(family); - DatagramChannel dc2 = (family == UNSPEC) ? - DatagramChannel.open() : DatagramChannel.open(family); + try (DatagramChannel dc1 = (family == UNSPEC) ? + DatagramChannel.open() : DatagramChannel.open(family); + DatagramChannel dc2 = (family == UNSPEC) ? + DatagramChannel.open() : DatagramChannel.open(family)) { - try { dc1.setOption(StandardSocketOptions.SO_REUSEADDR, true); dc2.setOption(StandardSocketOptions.SO_REUSEADDR, true); @@ -184,12 +197,8 @@ static void test(ProtocolFamily family, id = sendDatagram(nif, group2, port); - receiveDatagram(dc1, "dc1", false, id); receiveDatagram(dc2, "dc2", true, id); - - } finally { - dc1.close(); - dc2.close(); + receiveDatagram(dc1, "dc1", false, id); } } diff --git a/test/jdk/java/nio/channels/DatagramChannel/ReceiveISA.java b/test/jdk/java/nio/channels/DatagramChannel/ReceiveISA.java index 69df204e915..ef764c85d71 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/ReceiveISA.java +++ b/test/jdk/java/nio/channels/DatagramChannel/ReceiveISA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,10 +27,19 @@ * @summary Check that DatagramChannel.receive returns a new SocketAddress * when it receives a packet from the same source address but * different endpoint. + * @library /test/lib + * @build jdk.test.lib.NetworkConfiguration + * jdk.test.lib.Platform + * ReceiveISA + * @run main/othervm ReceiveISA + * */ import java.nio.*; import java.nio.channels.*; import java.net.*; + +import jdk.test.lib.Platform; + import static java.lang.System.out; public class ReceiveISA { @@ -44,10 +53,13 @@ public static void main(String args[]) throws Exception { DatagramChannel dc3 = DatagramChannel.open(); DatagramChannel dc4 = DatagramChannel.open()) { // client - dc3.socket().bind((SocketAddress) null); // bind server to any port + InetAddress lh = InetAddress.getLocalHost(); + InetSocketAddress dest = Platform.isOSX() + ? new InetSocketAddress(lh, 0) + : null; + dc3.socket().bind(dest); // bind server to any port // get server address - InetAddress lh = InetAddress.getLocalHost(); InetSocketAddress isa = new InetSocketAddress(lh, dc3.socket().getLocalPort()); ByteBuffer bb = ByteBuffer.allocateDirect(100); diff --git a/test/jdk/java/nio/channels/DatagramChannel/SelectWhenRefused.java b/test/jdk/java/nio/channels/DatagramChannel/SelectWhenRefused.java index d851e4f2b81..58ccf9d0b80 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/SelectWhenRefused.java +++ b/test/jdk/java/nio/channels/DatagramChannel/SelectWhenRefused.java @@ -39,8 +39,8 @@ import static org.junit.jupiter.api.Assertions.assertNotEquals; public class SelectWhenRefused { - static final int MAX_TRIES = 3; - static final String GREETINGS_MESSAGE = "Greetings from SelectWhenRefused!"; + static final int MAX_TRIES = 10; + static final String GREETINGS_MESSAGE = System.nanoTime() + ": Greetings from SelectWhenRefused!"; @Test public void test() throws IOException { @@ -49,9 +49,39 @@ public void test() throws IOException { // datagram sent to this address should be refused SocketAddress refuser = new InetSocketAddress(InetAddress.getLocalHost(), port); + System.err.println("Refuser is: " + refuser); - DatagramChannel dc = DatagramChannel.open().bind(new InetSocketAddress(0)); + DatagramChannel dc = null; + for (int i=0; i < MAX_TRIES; i++) { + dc = DatagramChannel.open(); + try { + dc.bind(new InetSocketAddress(0)); + } catch (Throwable t) { + dc.close(); + throw t; + } + + // check the port assigned to dc + if (((InetSocketAddress)dc.getLocalAddress()).getPort() != port) { + // We got a good port. Do not retry + break; + } + + // We bound to the same port that the refuser is using, This will not + // work. Retry binding if possible. + if (i < MAX_TRIES - 1) { + // we will retry... + System.err.format("Refuser port has been reused by dc: %s, retrying...%n", + dc.getLocalAddress()); + } else { + // that was the last attempt... Skip the test + System.err.format("Skipping test: refuser port has been reused by dc: %s%n", + dc.getLocalAddress()); + return; + } + } dc1.close(); + assert dc != null; Selector sel = Selector.open(); try { @@ -88,7 +118,7 @@ public void test() throws IOException { } } catch (BindException e) { // Do nothing, some other test has used this port - System.out.println("Skipping test: refuser port has been reused: " + e); + System.err.println("Skipping test: refuser port has been reused: " + e); } finally { sel.close(); dc.close(); @@ -119,7 +149,9 @@ static boolean testNoPUEBeforeConnection(DatagramChannel dc, // BindException will be thrown if another service is using // our expected refuser port, cannot run just exit. - DatagramChannel.open().bind(refuser).close(); + try (DatagramChannel dc2 = DatagramChannel.open()) { + dc2.bind(refuser); + } throw new RuntimeException("Unexpected wakeup"); } return true; // test passed @@ -151,7 +183,7 @@ static boolean testPUEOnConnect(DatagramChannel dc, byte[] bytes = new byte[buf.remaining()]; buf.get(bytes); String message = new String(bytes); - System.out.format("received %s at %s from %s%n", message, dc.getLocalAddress(), sa); + System.err.format("received %s at %s from %s%n", message, dc.getLocalAddress(), sa); // If any received data contains the message from sendDatagram then throw exception if (message.contains(GREETINGS_MESSAGE)) { @@ -166,10 +198,12 @@ static boolean testPUEOnConnect(DatagramChannel dc, // BindException will be thrown if another service is using // our expected refuser port, cannot run just exit. - DatagramChannel.open().bind(refuser).close(); + try (DatagramChannel dc2 = DatagramChannel.open()) { + dc2.bind(refuser); + } throw new RuntimeException("PortUnreachableException not raised"); } catch (PortUnreachableException pue) { - System.out.println("Got expected PortUnreachableException " + pue); + System.err.println("Got expected PortUnreachableException " + pue); } } return true; // test passed @@ -215,16 +249,16 @@ static void sendDatagram(DatagramChannel dc, SocketAddress remote) * */ static boolean checkUnexpectedWakeup(Set selectedKeys) { - System.out.format("Received %d keys%n", selectedKeys.size()); + System.err.format("Received %d keys%n", selectedKeys.size()); for (SelectionKey key : selectedKeys) { if (!key.isValid() || !key.isReadable()) { - System.out.println("Invalid or unreadable key: " + key); + System.err.println("Invalid or unreadable key: " + key); continue; } try { - System.out.println("Attempting to read datagram from key: " + key); + System.err.println("Attempting to read datagram from key: " + key); DatagramChannel datagramChannel = (DatagramChannel) key.channel(); ByteBuffer buf = ByteBuffer.allocate(100); SocketAddress sa = datagramChannel.receive(buf); @@ -234,7 +268,7 @@ static boolean checkUnexpectedWakeup(Set selectedKeys) { byte[] bytes = new byte[buf.remaining()]; buf.get(bytes); String message = new String(bytes); - System.out.format("received %s at %s from %s%n", message, datagramChannel.getLocalAddress(), sa); + System.err.format("received %s at %s from %s%n", message, datagramChannel.getLocalAddress(), sa); // If any received data contains the message from sendDatagram then return false if (message.contains(GREETINGS_MESSAGE)) { @@ -243,7 +277,7 @@ static boolean checkUnexpectedWakeup(Set selectedKeys) { } } catch (IOException io) { - System.out.println("Unable to read from datagram " + io); + System.err.println("Unable to read from datagram " + io); } } return true; diff --git a/test/jdk/java/nio/channels/DatagramChannel/SendReceiveMaxSize.java b/test/jdk/java/nio/channels/DatagramChannel/SendReceiveMaxSize.java index 31407ecb493..8d74fd8a387 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/SendReceiveMaxSize.java +++ b/test/jdk/java/nio/channels/DatagramChannel/SendReceiveMaxSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,7 @@ import jdk.test.lib.NetworkConfiguration; import jdk.test.lib.Platform; import jdk.test.lib.net.IPSupport; +import org.testng.Assert; import org.testng.annotations.BeforeTest; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -46,6 +47,7 @@ import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.nio.ByteBuffer; import java.nio.channels.DatagramChannel; import java.util.ArrayList; @@ -139,7 +141,9 @@ public void testSendReceiveMaxSize(DatagramChannelSupplier supplier, int capacit var addr = new InetSocketAddress(host, port); try (var sender = supplier.open()) { - sender.bind(null); + sender.bind(new InetSocketAddress(host, 0)); + System.out.format("testSendReceiveMaxSize: sender: %s -> receiver: %s%n", + sender.getLocalAddress(), receiver.getLocalAddress()); if (!Platform.isOSX()) { if (sender.getOption(SO_SNDBUF) < capacity) sender.setOption(SO_SNDBUF, capacity); @@ -150,7 +154,18 @@ public void testSendReceiveMaxSize(DatagramChannelSupplier supplier, int capacit var sendBuf = ByteBuffer.wrap(testData); sender.send(sendBuf, addr); var receiveBuf = ByteBuffer.allocate(capacity); - receiver.receive(receiveBuf); + SocketAddress src; + int count = 0; + do { + receiveBuf.clear(); + src = receiver.receive(receiveBuf); + if (sender.getLocalAddress().equals(src)) break; + System.out.println("step1: received unexpected datagram from: " + src); + System.out.println("\texpected: " + sender.getLocalAddress()); + if (++count > 10) { + throw new AssertionError("too many unexpected messages"); + } + } while (true); sendBuf.flip(); receiveBuf.flip(); @@ -167,7 +182,17 @@ public void testSendReceiveMaxSize(DatagramChannelSupplier supplier, int capacit sendBuf = ByteBuffer.wrap(testData); sender.send(sendBuf, addr); receiveBuf = ByteBuffer.allocate(capacity - 1); - receiver.receive(receiveBuf); + count = 0; + do { + receiveBuf.clear(); + src = receiver.receive(receiveBuf); + if (sender.getLocalAddress().equals(src)) break; + System.out.println("step1: received unexpected datagram from: " + src); + System.out.println("\texpected: " + sender.getLocalAddress()); + if (++count > 10) { + throw new AssertionError("too many unexpected messages"); + } + } while (true); sendBuf.flip(); receiveBuf.flip(); diff --git a/test/jdk/java/nio/channels/DatagramChannel/Sender.java b/test/jdk/java/nio/channels/DatagramChannel/Sender.java index 8ab4268e3a4..fcecdf9d79a 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/Sender.java +++ b/test/jdk/java/nio/channels/DatagramChannel/Sender.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,9 @@ /* @test * @bug 4669040 8130394 * @summary Test DatagramChannel subsequent receives with no datagram ready + * @library /test/lib + * @build jdk.test.lib.Platform Sender + * @run main Sender * @author Mike McCloskey */ @@ -36,6 +39,8 @@ import java.nio.ByteOrder; import java.nio.channels.DatagramChannel; +import jdk.test.lib.Platform; + public class Sender { static PrintStream log = System.err; @@ -46,25 +51,26 @@ public static void main(String[] args) throws Exception { } static void test() throws Exception { - Server server = new Server(); - Client client = new Client(server.port()); + try (Server server = new Server()) { + Client client = new Client(server.port()); - Thread serverThread = new Thread(server); - serverThread.start(); + Thread serverThread = new Thread(server); + serverThread.start(); - Thread clientThread = new Thread(client); - clientThread.start(); + Thread clientThread = new Thread(client); + clientThread.start(); - serverThread.join(); - clientThread.join(); + serverThread.join(); + clientThread.join(); - server.throwException(); - client.throwException(); + server.throwException(); + client.throwException(); + } } public static class Client implements Runnable { final int port; - Exception e = null; + volatile Exception e = null; Client(int port) { this.port = port; @@ -76,14 +82,17 @@ void throwException() throws Exception { } public void run() { - try { - DatagramChannel dc = DatagramChannel.open(); + try (DatagramChannel dc = DatagramChannel.open()) { ByteBuffer bb = ByteBuffer.allocateDirect(12); bb.order(ByteOrder.BIG_ENDIAN); bb.putInt(1).putLong(1); bb.flip(); InetAddress address = InetAddress.getLocalHost(); InetSocketAddress isa = new InetSocketAddress(address, port); + if (Platform.isOSX()) { + // avoid binding on wildcard on macOS + dc.bind(new InetSocketAddress(address, 0)); + } dc.connect(isa); clientISA = dc.getLocalAddress(); dc.write(bb); @@ -93,12 +102,16 @@ public void run() { } } - public static class Server implements Runnable { + public static class Server implements Runnable, AutoCloseable { final DatagramChannel dc; - Exception e = null; + volatile Exception e = null; Server() throws IOException { - dc = DatagramChannel.open().bind(new InetSocketAddress(0)); + // avoid binding to wildcard address on macOS + InetSocketAddress lo = Platform.isOSX() + ? new InetSocketAddress(InetAddress.getLocalHost(), 0) + : new InetSocketAddress(0); + dc = DatagramChannel.open().bind(lo); } int port() { @@ -149,6 +162,11 @@ public void run() { e = ex; } } + + @Override + public void close() throws IOException { + dc.close(); + } } } From 6460b300487071bcf98f5ac70d9c0a6fd6b94083 Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Mon, 19 Aug 2024 16:43:43 +0000 Subject: [PATCH 455/460] 8321140: Add comment to note difference in Metal's JButton margins Reviewed-by: honkar, aivanov --- .../swing/plaf/basic/BasicLookAndFeel.java | 4 +- .../swing/plaf/metal/MetalLookAndFeel.java | 51 ++++++++++++++----- 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java index 999e7f923c7..4041bfca714 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -727,6 +727,8 @@ public Object createValue(UIDefaults table) { "Button.highlight", controlLtHighlight, "Button.border", buttonBorder, "Button.margin", new InsetsUIResource(2, 14, 2, 14), + // The above margin has vastly larger horizontal values when + // compared to other look and feels that don't rely on these values "Button.textIconGap", 4, "Button.textShiftOffset", zero, "Button.focusInputMap", new UIDefaults.LazyInputMap(new Object[] { diff --git a/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalLookAndFeel.java b/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalLookAndFeel.java index 98747bbd2dc..e46091c523c 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalLookAndFeel.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalLookAndFeel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,28 +25,53 @@ package javax.swing.plaf.metal; -import java.awt.*; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Frame; +import java.awt.Insets; +import java.awt.Toolkit; +import java.awt.Window; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import javax.swing.plaf.*; -import javax.swing.*; -import javax.swing.plaf.basic.*; -import javax.swing.text.DefaultEditorKit; - -import java.awt.Color; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; - import java.security.AccessController; -import sun.awt.*; +import javax.swing.ButtonModel; +import javax.swing.DefaultButtonModel; +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JRootPane; +import javax.swing.JTextField; +import javax.swing.JToggleButton; +import javax.swing.LayoutStyle; +import javax.swing.LookAndFeel; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.plaf.BorderUIResource; +import javax.swing.plaf.ColorUIResource; +import javax.swing.plaf.FontUIResource; +import javax.swing.plaf.InsetsUIResource; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicLookAndFeel; +import javax.swing.text.DefaultEditorKit; + +import sun.awt.AppContext; +import sun.awt.OSInfo; +import sun.awt.SunToolkit; import sun.security.action.GetPropertyAction; import sun.swing.DefaultLayoutStyle; -import static javax.swing.UIDefaults.LazyValue; - import sun.swing.SwingAccessor; import sun.swing.SwingUtilities2; +import static javax.swing.UIDefaults.LazyValue; + /** * The Java Look and Feel, otherwise known as Metal. *

@@ -782,6 +807,8 @@ protected void initComponentDefaults(UIDefaults table) { "SPACE", "pressed", "released SPACE", "released" }), + // Button default margin is (2, 14, 2, 14), defined in + // BasicLookAndFeel via "Button.margin" UI property. "CheckBox.disabledText", inactiveControlTextColor, "Checkbox.select", controlShadow, From c7690c34c2d7bff11501188266b7be7a486c1bd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Mon, 19 Aug 2024 17:47:25 +0000 Subject: [PATCH 456/460] 8338190: TOC vertical offsets not updated when document size changes Reviewed-by: jjg --- .../doclets/formats/html/resources/script.js.template | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template index 71ef8476708..633f453bc43 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template @@ -461,7 +461,7 @@ document.addEventListener("DOMContentLoaded", function(e) { }) } // Resize handler - function handleResize(e) { + new ResizeObserver((entries) => { if (expanded) { if (windowWidth !== window.innerWidth) { collapse(); @@ -475,7 +475,5 @@ document.addEventListener("DOMContentLoaded", function(e) { handleScroll(); } setTopMargin(); - } - window.addEventListener("orientationchange", handleResize); - window.addEventListener("resize", handleResize); + }).observe(document.body); }); From 55851a312baaea5af14c04fb1b436313fe0deac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Mon, 19 Aug 2024 18:05:37 +0000 Subject: [PATCH 457/460] 8281533: Odd "preview" label in link/linkplain Reviewed-by: jjg --- .../doclets/formats/html/HtmlLinkFactory.java | 88 +++++++++++-------- .../formats/html/taglets/LinkTaglet.java | 1 + .../doclet/testPreview/TestPreview.java | 17 +++- .../doclet/testPreview/api/preview/Core.java | 9 +- 4 files changed, 73 insertions(+), 42 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java index 8e0c010dd1a..494d5e22d6e 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java @@ -52,6 +52,7 @@ import jdk.javadoc.internal.html.Content; import jdk.javadoc.internal.html.ContentBuilder; import jdk.javadoc.internal.html.Entity; +import jdk.javadoc.internal.html.HtmlId; import jdk.javadoc.internal.html.HtmlTag; import jdk.javadoc.internal.html.HtmlTree; import jdk.javadoc.internal.html.Text; @@ -296,26 +297,12 @@ protected Content getClassLink(HtmlLinkInfo linkInfo) { Content link = new ContentBuilder(); if (utils.isIncluded(typeElement)) { if (configuration.isGeneratedDoc(typeElement) && !utils.hasHiddenTag(typeElement)) { - DocPath filename = getPath(linkInfo); + DocPath fileName = getPath(linkInfo); if (linkInfo.linkToSelf() || typeElement != m_writer.getCurrentPageElement()) { link.add(m_writer.links.createLink( - filename.fragment(linkInfo.getFragment()), - label, - linkInfo.getStyle(), - title)); - Content spacer = Text.EMPTY; - if (flags.contains(ElementFlag.PREVIEW)) { - link.add(HtmlTree.SUP(m_writer.links.createLink( - filename.fragment(m_writer.htmlIds.forPreviewSection(previewTarget).name()), - m_writer.contents.previewMark))); - spacer = Entity.NO_BREAK_SPACE; - } - if (flags.contains(ElementFlag.RESTRICTED)) { - link.add(spacer); - link.add(HtmlTree.SUP(m_writer.links.createLink( - filename.fragment(m_writer.htmlIds.forRestrictedSection(restrictedTarget).name()), - m_writer.contents.restrictedMark))); - } + fileName.fragment(linkInfo.getFragment()), + label, linkInfo.getStyle(), title)); + addSuperscript(link, flags, fileName, null, previewTarget, restrictedTarget); return link; } } @@ -325,38 +312,61 @@ protected Content getClassLink(HtmlLinkInfo linkInfo) { label, linkInfo.getStyle(), true); if (crossLink != null) { link.add(crossLink); - Content spacer = Text.EMPTY; - if (flags.contains(ElementFlag.PREVIEW)) { - link.add(HtmlTree.SUP(m_writer.getCrossClassLink( - typeElement, - m_writer.htmlIds.forPreviewSection(previewTarget).name(), - m_writer.contents.previewMark, - null, false))); - spacer = Entity.NO_BREAK_SPACE; - } - if (flags.contains(ElementFlag.RESTRICTED)) { - link.add(spacer); - link.add(HtmlTree.SUP(m_writer.getCrossClassLink( - typeElement, - m_writer.htmlIds.forRestrictedSection(restrictedTarget).name(), - m_writer.contents.restrictedMark, - null, false))); - } + addSuperscript(link, flags, null, typeElement, previewTarget, restrictedTarget); return link; } } // Can't link so just write label. link.add(label); + addSuperscript(link, flags, null, null, previewTarget, restrictedTarget); + return link; + } + + /** + * Adds PREVIEW and RESTRICTED superscript labels. Depending on the parameter values, + * labels will be formatted as local or external links or plain text. + * + * @param content the content to add to + * @param flags the flags + * @param fileName file name to link to, or null if no local link target + * @param typeElement external type to link to, or null if no external link + * @param previewTarget preview link target element + * @param restrictedTarget restricted link target element + */ + private void addSuperscript(Content content, Set flags, DocPath fileName, TypeElement typeElement, + Element previewTarget, ExecutableElement restrictedTarget) { Content spacer = Text.EMPTY; if (flags.contains(ElementFlag.PREVIEW)) { - link.add(HtmlTree.SUP(m_writer.contents.previewMark)); + content.add(HtmlTree.SUP(getSuperscript(fileName, typeElement, + m_writer.htmlIds.forPreviewSection(previewTarget), + m_writer.contents.previewMark))); spacer = Entity.NO_BREAK_SPACE; } if (flags.contains(ElementFlag.RESTRICTED)) { - link.add(spacer); - link.add(HtmlTree.SUP(m_writer.contents.restrictedMark)); + content.add(spacer); + content.add(HtmlTree.SUP(getSuperscript(fileName, typeElement, + m_writer.htmlIds.forRestrictedSection(restrictedTarget), + m_writer.contents.restrictedMark))); + } + } + + /** + * Returns PREVIEW or RESTRICTED superscript as either local or external link or as plain text. + * + * @param fileName local file name to link to, or null if no local link target + * @param typeElement external type to link to, or null if no external link + * @param id the id fragment to link to + * @param label the label content + * @return superscript content + */ + private Content getSuperscript(DocPath fileName, TypeElement typeElement, HtmlId id, Content label) { + if (fileName != null) { + return m_writer.links.createLink(fileName.fragment(id.name()), label); + } else if (typeElement != null) { + return (m_writer.getCrossClassLink(typeElement, id.name(), label, null, false)); + } else { + return label; } - return link; } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java index b16a1490b63..15e88da5bae 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java @@ -224,6 +224,7 @@ Content linkSeeReferenceOutput(Element holder, labelContent = plainOrCode(isPlain, Text.of(utils.getSimpleName(refClass))); } return htmlWriter.getLink(new HtmlLinkInfo(config, HtmlLinkInfo.Kind.PLAIN, refClass) + .skipPreview(isPlain) .label(labelContent)); } else if (refMem == null) { // This is a fragment reference since refClass and refFragment are not null but refMem is null. diff --git a/test/langtools/jdk/javadoc/doclet/testPreview/TestPreview.java b/test/langtools/jdk/javadoc/doclet/testPreview/TestPreview.java index a59e68d25a0..369312d690a 100644 --- a/test/langtools/jdk/javadoc/doclet/testPreview/TestPreview.java +++ b/test/langtools/jdk/javadoc/doclet/testPreview/TestPreview.java @@ -24,7 +24,7 @@ /* * @test * @bug 8250768 8261976 8277300 8282452 8287597 8325325 8325874 8297879 - * 8331947 + * 8331947 8281533 * @summary test generated docs for items declared using preview * @library ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool @@ -156,7 +156,20 @@ public void testPreviewAPIJavadoc() {

  • java.base
  • preview
  • Core
  • - """); + """, + """ + """, + """ +
  • CoreRecord<\ + /a>PREVIEW<\ + /li> +
  • core record
  • """); // 8331947: Support preview features without JEP should not be included in Preview API page checkOutput("preview-list.html", false, "supportMethod"); diff --git a/test/langtools/jdk/javadoc/doclet/testPreview/api/preview/Core.java b/test/langtools/jdk/javadoc/doclet/testPreview/api/preview/Core.java index d2cf31c2e89..1b23d202285 100644 --- a/test/langtools/jdk/javadoc/doclet/testPreview/api/preview/Core.java +++ b/test/langtools/jdk/javadoc/doclet/testPreview/api/preview/Core.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,13 @@ import jdk.internal.javac.PreviewFeature; import jdk.internal.javac.PreviewFeature.Feature; +/** + * Preview feature. Links: {@link CoreRecord}, {@link CoreRecord core record}, + * {@linkplain CoreRecord}, {@linkplain CoreRecord core record}. + * + * @see CoreRecord + * @see CoreRecord core record + */ @PreviewFeature(feature=Feature.TEST) public class Core { } From 68d1f5c33bf3f64f44f8a10c2f9e4007cfd07d2b Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Tue, 20 Aug 2024 05:43:04 +0000 Subject: [PATCH 458/460] 8338543: ClassBuilder withMethod builders should cache the method type symbol Reviewed-by: asotona --- .../classes/java/lang/classfile/ClassBuilder.java | 5 +---- .../internal/classfile/impl/ChainedClassBuilder.java | 10 ++++++++++ .../internal/classfile/impl/DirectClassBuilder.java | 8 ++++++++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java b/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java index 7ad6e94df3f..98371c9e15a 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java @@ -276,10 +276,7 @@ default ClassBuilder withMethodBody(String name, MethodTypeDesc descriptor, int methodFlags, Consumer handler) { - return withMethodBody(constantPool().utf8Entry(name), - constantPool().utf8Entry(descriptor), - methodFlags, - handler); + return withMethod(name, descriptor, methodFlags, mb -> mb.withCode(handler)); } /** diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java index d31debf6f35..50c1590e8a2 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java @@ -24,6 +24,7 @@ */ package jdk.internal.classfile.impl; +import java.lang.constant.MethodTypeDesc; import java.util.function.Consumer; import java.lang.classfile.*; @@ -78,6 +79,15 @@ public ClassBuilder withMethod(Utf8Entry name, Utf8Entry descriptor, int flags, return this; } + @Override + public ClassBuilder withMethod(String name, MethodTypeDesc descriptor, int flags, Consumer handler) { + var mb = new BufferedMethodBuilder(terminal.constantPool, terminal.context, + constantPool().utf8Entry(name), constantPool().utf8Entry(descriptor), flags, null); + mb.mDesc = descriptor; + consumer.accept(mb.run(handler).toModel()); + return this; + } + @Override public ClassBuilder transformMethod(MethodModel method, MethodTransform transform) { BufferedMethodBuilder builder = new BufferedMethodBuilder(terminal.constantPool, terminal.context, diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java index 21fde0f6002..0d61895fe9f 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java @@ -26,6 +26,7 @@ package jdk.internal.classfile.impl; import java.lang.constant.ConstantDescs; +import java.lang.constant.MethodTypeDesc; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -106,6 +107,13 @@ public ClassBuilder withMethod(Utf8Entry name, .run(handler)); } + @Override + public ClassBuilder withMethod(String name, MethodTypeDesc descriptor, int flags, Consumer handler) { + var method = new DirectMethodBuilder(constantPool, context, constantPool.utf8Entry(name), constantPool.utf8Entry(descriptor), flags, null); + method.mDesc = descriptor; + return withMethod(method.run(handler)); + } + @Override public ClassBuilder transformMethod(MethodModel method, MethodTransform transform) { DirectMethodBuilder builder = new DirectMethodBuilder(constantPool, context, method.methodName(), From 9775d57168695dc0d758e017fe5069d93d593f3e Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Tue, 20 Aug 2024 06:15:56 +0000 Subject: [PATCH 459/460] 8338139: {ClassLoading,Memory}MXBean::isVerbose methods are inconsistent with their setVerbose methods Co-authored-by: David Holmes Reviewed-by: lmesnik, dcubed, dholmes --- .../share/services/classLoadingService.cpp | 18 +++- .../share/services/classLoadingService.hpp | 4 +- src/hotspot/share/services/memoryService.cpp | 17 +++- src/hotspot/share/services/memoryService.hpp | 4 +- .../TestVerboseClassLoading.java | 84 +++++++++++++++++++ .../MemoryMXBean/TestVerboseMemory.java | 79 +++++++++++++++++ 6 files changed, 200 insertions(+), 6 deletions(-) create mode 100644 test/jdk/java/lang/management/ClassLoadingMXBean/TestVerboseClassLoading.java create mode 100644 test/jdk/java/lang/management/MemoryMXBean/TestVerboseMemory.java diff --git a/src/hotspot/share/services/classLoadingService.cpp b/src/hotspot/share/services/classLoadingService.cpp index 2df8d12278d..09da45dc079 100644 --- a/src/hotspot/share/services/classLoadingService.cpp +++ b/src/hotspot/share/services/classLoadingService.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -128,6 +128,22 @@ bool ClassLoadingService::set_verbose(bool verbose) { return verbose; } +bool ClassLoadingService::get_verbose() { + for (LogTagSet* ts = LogTagSet::first(); ts != nullptr; ts = ts->next()) { + // set_verbose looks for a non-exact match for class+load, + // so look for all tag sets that match class+load* + if (ts->contains(LogTag::_class) && + ts->contains(LogTag::_load)) { + LogLevelType l = ts->level_for(LogConfiguration::StdoutLog); + if (l != LogLevel::Info && l != LogLevel::Debug && l != LogLevel::Trace) { + return false; + } + } + } + + return true; +} + // Caller to this function must own Management_lock void ClassLoadingService::reset_trace_class_unloading() { assert(Management_lock->owned_by_self(), "Must own the Management_lock"); diff --git a/src/hotspot/share/services/classLoadingService.hpp b/src/hotspot/share/services/classLoadingService.hpp index f9db3da5091..3aeb3f556a5 100644 --- a/src/hotspot/share/services/classLoadingService.hpp +++ b/src/hotspot/share/services/classLoadingService.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,6 +53,7 @@ class ClassLoadingService : public AllStatic { public: static void init() NOT_MANAGEMENT_RETURN; static bool set_verbose(bool verbose) NOT_MANAGEMENT_RETURN_(false); + static bool get_verbose() NOT_MANAGEMENT_RETURN_(false); static void reset_trace_class_unloading() NOT_MANAGEMENT_RETURN; static jlong loaded_class_count() NOT_MANAGEMENT_RETURN_(0L); static jlong unloaded_class_count() NOT_MANAGEMENT_RETURN_(0L); @@ -63,7 +64,6 @@ class ClassLoadingService : public AllStatic { static jlong loaded_shared_class_bytes() NOT_MANAGEMENT_RETURN_(0L); static jlong unloaded_shared_class_bytes() NOT_MANAGEMENT_RETURN_(0L); static jlong class_method_data_size() NOT_MANAGEMENT_RETURN_(0L); - static bool get_verbose() { return log_is_enabled(Info, class, load); } static void notify_class_loaded(InstanceKlass* k, bool shared_class) NOT_MANAGEMENT_RETURN; diff --git a/src/hotspot/share/services/memoryService.cpp b/src/hotspot/share/services/memoryService.cpp index 21b773e204e..de30bee12bd 100644 --- a/src/hotspot/share/services/memoryService.cpp +++ b/src/hotspot/share/services/memoryService.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -202,6 +202,21 @@ bool MemoryService::set_verbose(bool verbose) { return verbose; } +bool MemoryService::get_verbose() { + for (LogTagSet* ts = LogTagSet::first(); ts != nullptr; ts = ts->next()) { + // set_verbose only sets gc and not gc*, so check for an exact match + const bool is_gc_exact_match = ts->contains(LogTag::_gc) && ts->ntags() == 1; + if (is_gc_exact_match) { + LogLevelType l = ts->level_for(LogConfiguration::StdoutLog); + if (l == LogLevel::Info || l == LogLevel::Debug || l == LogLevel::Trace) { + return true; + } + } + } + + return false; +} + Handle MemoryService::create_MemoryUsage_obj(MemoryUsage usage, TRAPS) { InstanceKlass* ik = Management::java_lang_management_MemoryUsage_klass(CHECK_NH); diff --git a/src/hotspot/share/services/memoryService.hpp b/src/hotspot/share/services/memoryService.hpp index 2d28f25c695..d10c3d2e9d9 100644 --- a/src/hotspot/share/services/memoryService.hpp +++ b/src/hotspot/share/services/memoryService.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -106,8 +106,8 @@ class MemoryService : public AllStatic { GCCause::Cause cause, bool allMemoryPoolsAffected, const char* notificationMessage = nullptr); - static bool get_verbose() { return log_is_enabled(Info, gc); } static bool set_verbose(bool verbose); + static bool get_verbose(); // Create an instance of java/lang/management/MemoryUsage static Handle create_MemoryUsage_obj(MemoryUsage usage, TRAPS); diff --git a/test/jdk/java/lang/management/ClassLoadingMXBean/TestVerboseClassLoading.java b/test/jdk/java/lang/management/ClassLoadingMXBean/TestVerboseClassLoading.java new file mode 100644 index 00000000000..4e865f24b29 --- /dev/null +++ b/test/jdk/java/lang/management/ClassLoadingMXBean/TestVerboseClassLoading.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8338139 + * @summary Basic unit test of ClassLoadingMXBean.set/isVerbose() when + * related unified logging is enabled. + * + * @run main/othervm -Xlog:class+load=trace:file=vm.log TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load=debug:file=vm.log TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load=info:file=vm.log TestVerboseClassLoading false + * + * @run main/othervm -Xlog:class+load=trace TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load=debug TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load=info TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load=warning TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load=error TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load=off TestVerboseClassLoading false + * + * @run main/othervm -Xlog:class+load*=trace TestVerboseClassLoading true + * @run main/othervm -Xlog:class+load*=debug TestVerboseClassLoading true + * @run main/othervm -Xlog:class+load*=info TestVerboseClassLoading true + * @run main/othervm -Xlog:class+load*=warning TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load*=error TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load*=off TestVerboseClassLoading false + * + * @run main/othervm -Xlog:class+load*=info,class+load+cause=trace TestVerboseClassLoading true + * @run main/othervm -Xlog:class+load*=info,class+load+cause=debug TestVerboseClassLoading true + * @run main/othervm -Xlog:class+load*=info,class+load+cause=info TestVerboseClassLoading true + * @run main/othervm -Xlog:class+load*=info,class+load+cause=warning TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load*=info,class+load+cause=error TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load*=info,class+load+cause=off TestVerboseClassLoading false + * + * @run main/othervm -Xlog:all=trace:file=vm.log TestVerboseClassLoading false + */ + +import java.lang.management.ManagementFactory; +import java.lang.management.ClassLoadingMXBean; + +public class TestVerboseClassLoading { + + public static void main(String[] args) throws Exception { + ClassLoadingMXBean mxBean = ManagementFactory.getClassLoadingMXBean(); + boolean expected = Boolean.parseBoolean(args[0]); + boolean initial = mxBean.isVerbose(); + if (expected != initial) { + throw new Error("Initial verbosity setting was unexpectedly " + initial); + } + mxBean.setVerbose(false); + if (mxBean.isVerbose()) { + throw new Error("Verbosity was still enabled"); + } + mxBean.setVerbose(true); + if (!mxBean.isVerbose()) { + throw new Error("Verbosity was still disabled"); + } + // Turn off again as a double-check and also to avoid excessive logging + mxBean.setVerbose(false); + if (mxBean.isVerbose()) { + throw new Error("Verbosity was still enabled"); + } + } +} diff --git a/test/jdk/java/lang/management/MemoryMXBean/TestVerboseMemory.java b/test/jdk/java/lang/management/MemoryMXBean/TestVerboseMemory.java new file mode 100644 index 00000000000..7d34c45036b --- /dev/null +++ b/test/jdk/java/lang/management/MemoryMXBean/TestVerboseMemory.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8338139 + * @summary Basic unit test of TestVerboseMemory.set/isVerbose() when + * related unified logging is enabled. + * + * @run main/othervm -Xlog:gc=trace:file=vm.log TestVerboseMemory false + * @run main/othervm -Xlog:gc=debug:file=vm.log TestVerboseMemory false + * @run main/othervm -Xlog:gc=info:file=vm.log TestVerboseMemory false + * + * @run main/othervm -Xlog:gc=off TestVerboseMemory false + * @run main/othervm -Xlog:gc=error TestVerboseMemory false + * @run main/othervm -Xlog:gc=warning TestVerboseMemory false + * + * @run main/othervm -Xlog:gc=info TestVerboseMemory true + * @run main/othervm -Xlog:gc=trace TestVerboseMemory true + * @run main/othervm -Xlog:gc=debug TestVerboseMemory true + * + * @run main/othervm -Xlog:gc*=info TestVerboseMemory true + * @run main/othervm -Xlog:gc*=debug TestVerboseMemory true + * @run main/othervm -Xlog:gc*=trace TestVerboseMemory true + * + * @run main/othervm -Xlog:gc=info,gc+init=off TestVerboseMemory true + * @run main/othervm -Xlog:gc=off,gc+init=info TestVerboseMemory false + * @run main/othervm -Xlog:gc,gc+init TestVerboseMemory true + * + * @run main/othervm -Xlog:all=trace:file=vm.log TestVerboseMemory false + */ + +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryMXBean; + +public class TestVerboseMemory { + + public static void main(String[] args) throws Exception { + MemoryMXBean mxBean = ManagementFactory.getMemoryMXBean(); + boolean expected = Boolean.parseBoolean(args[0]); + boolean initial = mxBean.isVerbose(); + if (expected != initial) { + throw new Error("Initial verbosity setting was unexpectedly " + initial); + } + mxBean.setVerbose(false); + if (mxBean.isVerbose()) { + throw new Error("Verbosity was still enabled"); + } + mxBean.setVerbose(true); + if (!mxBean.isVerbose()) { + throw new Error("Verbosity was still disabled"); + } + // Turn off again as a double-check and also to avoid excessive logging + mxBean.setVerbose(false); + if (mxBean.isVerbose()) { + throw new Error("Verbosity was still enabled"); + } + } +} From b9d49dcef22ab81a087d890bbac0329a5244a2ef Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 20 Aug 2024 08:40:45 +0000 Subject: [PATCH 460/460] 8337981: ShenandoahHeap::is_in should check for alive regions Reviewed-by: rkennke, wkemper --- .../share/gc/shenandoah/shenandoahAsserts.cpp | 46 ++++++++++++------- .../share/gc/shenandoah/shenandoahAsserts.hpp | 16 +++---- .../shenandoahCollectionSet.inline.hpp | 4 +- .../gc/shenandoah/shenandoahConcurrentGC.cpp | 2 +- .../shenandoahForwarding.inline.hpp | 2 +- .../share/gc/shenandoah/shenandoahHeap.cpp | 15 ++++-- .../share/gc/shenandoah/shenandoahHeap.hpp | 2 + .../gc/shenandoah/shenandoahMarkBitMap.cpp | 2 +- .../shenandoah/shenandoahMarkingContext.hpp | 4 +- .../shenandoahMarkingContext.inline.hpp | 12 ++++- .../shenandoahReferenceProcessor.cpp | 31 +++++++++---- .../gc/shenandoah/shenandoahVerifier.cpp | 35 ++++++++------ 12 files changed, 111 insertions(+), 60 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp index 8235b59b80e..1539c7c2c5d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp @@ -37,7 +37,7 @@ void print_raw_memory(ShenandoahMessageBuffer &msg, void* loc) { // should be in heap, in known committed region, within that region. ShenandoahHeap* heap = ShenandoahHeap::heap(); - if (!heap->is_in(loc)) return; + if (!heap->is_in_reserved(loc)) return; ShenandoahHeapRegion* r = heap->heap_region_containing(loc); if (r != nullptr && r->is_committed()) { @@ -77,7 +77,7 @@ void ShenandoahAsserts::print_obj(ShenandoahMessageBuffer& msg, oop obj) { void ShenandoahAsserts::print_non_obj(ShenandoahMessageBuffer& msg, void* loc) { ShenandoahHeap* heap = ShenandoahHeap::heap(); - if (heap->is_in(loc)) { + if (heap->is_in_reserved(loc)) { msg.append(" inside Java heap\n"); ShenandoahHeapRegion *r = heap->heap_region_containing(loc); stringStream ss; @@ -96,7 +96,7 @@ void ShenandoahAsserts::print_non_obj(ShenandoahMessageBuffer& msg, void* loc) { void ShenandoahAsserts::print_obj_safe(ShenandoahMessageBuffer& msg, void* loc) { ShenandoahHeap* heap = ShenandoahHeap::heap(); msg.append(" " PTR_FORMAT " - safe print, no details\n", p2i(loc)); - if (heap->is_in(loc)) { + if (heap->is_in_reserved(loc)) { ShenandoahHeapRegion* r = heap->heap_region_containing(loc); if (r != nullptr) { stringStream ss; @@ -113,7 +113,7 @@ void ShenandoahAsserts::print_failure(SafeLevel level, oop obj, void* interior_l ShenandoahHeap* heap = ShenandoahHeap::heap(); ResourceMark rm; - bool loc_in_heap = (loc != nullptr && heap->is_in(loc)); + bool loc_in_heap = (loc != nullptr && heap->is_in_reserved(loc)); ShenandoahMessageBuffer msg("%s; %s\n\n", phase, label); @@ -166,22 +166,22 @@ void ShenandoahAsserts::print_failure(SafeLevel level, oop obj, void* interior_l report_vm_error(file, line, msg.buffer()); } -void ShenandoahAsserts::assert_in_heap(void* interior_loc, oop obj, const char *file, int line) { +void ShenandoahAsserts::assert_in_heap_bounds(void* interior_loc, oop obj, const char *file, int line) { ShenandoahHeap* heap = ShenandoahHeap::heap(); - if (!heap->is_in(obj)) { - print_failure(_safe_unknown, obj, interior_loc, nullptr, "Shenandoah assert_in_heap failed", - "oop must point to a heap address", + if (!heap->is_in_reserved(obj)) { + print_failure(_safe_unknown, obj, interior_loc, nullptr, "Shenandoah assert_in_heap_bounds failed", + "oop must be in heap bounds", file, line); } } -void ShenandoahAsserts::assert_in_heap_or_null(void* interior_loc, oop obj, const char *file, int line) { +void ShenandoahAsserts::assert_in_heap_bounds_or_null(void* interior_loc, oop obj, const char *file, int line) { ShenandoahHeap* heap = ShenandoahHeap::heap(); - if (obj != nullptr && !heap->is_in(obj)) { - print_failure(_safe_unknown, obj, interior_loc, nullptr, "Shenandoah assert_in_heap_or_null failed", - "oop must point to a heap address", + if (obj != nullptr && !heap->is_in_reserved(obj)) { + print_failure(_safe_unknown, obj, interior_loc, nullptr, "Shenandoah assert_in_heap_bounds_or_null failed", + "oop must be in heap bounds", file, line); } } @@ -191,9 +191,9 @@ void ShenandoahAsserts::assert_correct(void* interior_loc, oop obj, const char* // Step 1. Check that obj is correct. // After this step, it is safe to call heap_region_containing(). - if (!heap->is_in(obj)) { + if (!heap->is_in_reserved(obj)) { print_failure(_safe_unknown, obj, interior_loc, nullptr, "Shenandoah assert_correct failed", - "oop must point to a heap address", + "oop must be in heap bounds", file, line); } @@ -210,6 +210,12 @@ void ShenandoahAsserts::assert_correct(void* interior_loc, oop obj, const char* file,line); } + if (!heap->is_in(obj)) { + print_failure(_safe_unknown, obj, interior_loc, nullptr, "Shenandoah assert_correct failed", + "Object should be in active region area", + file, line); + } + oop fwd = ShenandoahForwarding::get_forwardee_raw_unchecked(obj); if (obj != fwd) { @@ -223,9 +229,9 @@ void ShenandoahAsserts::assert_correct(void* interior_loc, oop obj, const char* } // Step 2. Check that forwardee is correct - if (!heap->is_in(fwd)) { + if (!heap->is_in_reserved(fwd)) { print_failure(_safe_oop, obj, interior_loc, nullptr, "Shenandoah assert_correct failed", - "Forwardee must point to a heap address", + "Forwardee must be in heap bounds", file, line); } @@ -236,9 +242,15 @@ void ShenandoahAsserts::assert_correct(void* interior_loc, oop obj, const char* } // Step 3. Check that forwardee points to correct region + if (!heap->is_in(fwd)) { + print_failure(_safe_oop, obj, interior_loc, nullptr, "Shenandoah assert_correct failed", + "Forwardee should be in active region area", + file, line); + } + if (heap->heap_region_index_containing(fwd) == heap->heap_region_index_containing(obj)) { print_failure(_safe_all, obj, interior_loc, nullptr, "Shenandoah assert_correct failed", - "Non-trivial forwardee should in another region", + "Non-trivial forwardee should be in another region", file, line); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.hpp b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.hpp index c730eafb89d..154edebcf3e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.hpp @@ -53,8 +53,8 @@ class ShenandoahAsserts { static void print_rp_failure(const char *label, BoolObjectClosure* actual, const char *file, int line); - static void assert_in_heap(void* interior_loc, oop obj, const char* file, int line); - static void assert_in_heap_or_null(void* interior_loc, oop obj, const char* file, int line); + static void assert_in_heap_bounds(void* interior_loc, oop obj, const char* file, int line); + static void assert_in_heap_bounds_or_null(void* interior_loc, oop obj, const char* file, int line); static void assert_in_correct_region(void* interior_loc, oop obj, const char* file, int line); static void assert_correct(void* interior_loc, oop obj, const char* file, int line); @@ -74,10 +74,10 @@ class ShenandoahAsserts { static void assert_heaplocked_or_safepoint(const char* file, int line); #ifdef ASSERT -#define shenandoah_assert_in_heap(interior_loc, obj) \ - ShenandoahAsserts::assert_in_heap(interior_loc, obj, __FILE__, __LINE__) -#define shenandoah_assert_in_heap_or_null(interior_loc, obj) \ - ShenandoahAsserts::assert_in_heap_or_null(interior_loc, obj, __FILE__, __LINE__) +#define shenandoah_assert_in_heap_bounds(interior_loc, obj) \ + ShenandoahAsserts::assert_in_heap_bounds(interior_loc, obj, __FILE__, __LINE__) +#define shenandoah_assert_in_heap_bounds_or_null(interior_loc, obj) \ + ShenandoahAsserts::assert_in_heap_bounds_or_null(interior_loc, obj, __FILE__, __LINE__) #define shenandoah_assert_in_correct_region(interior_loc, obj) \ ShenandoahAsserts::assert_in_correct_region(interior_loc, obj, __FILE__, __LINE__) @@ -164,8 +164,8 @@ class ShenandoahAsserts { #define shenandoah_assert_heaplocked_or_safepoint() \ ShenandoahAsserts::assert_heaplocked_or_safepoint(__FILE__, __LINE__) #else -#define shenandoah_assert_in_heap(interior_loc, obj) -#define shenandoah_assert_in_heap_or_null(interior_loc, obj) +#define shenandoah_assert_in_heap_bounds(interior_loc, obj) +#define shenandoah_assert_in_heap_bounds_or_null(interior_loc, obj) #define shenandoah_assert_in_correct_region(interior_loc, obj) #define shenandoah_assert_correct_if(interior_loc, obj, condition) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.inline.hpp index 6eb026561e4..cceebae0b1c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.inline.hpp @@ -41,12 +41,12 @@ bool ShenandoahCollectionSet::is_in(ShenandoahHeapRegion* r) const { } bool ShenandoahCollectionSet::is_in(oop p) const { - shenandoah_assert_in_heap_or_null(nullptr, p); + shenandoah_assert_in_heap_bounds_or_null(nullptr, p); return is_in_loc(cast_from_oop(p)); } bool ShenandoahCollectionSet::is_in_loc(void* p) const { - assert(p == nullptr || _heap->is_in(p), "Must be in the heap"); + assert(p == nullptr || _heap->is_in_reserved(p), "Must be in the heap"); uintx index = ((uintx) p) >> _region_size_bytes_shift; // no need to subtract the bottom of the heap from p, // _biased_cset_map is biased diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index 0301ef422a6..0e18b591037 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -718,7 +718,7 @@ void ShenandoahEvacUpdateCleanupOopStorageRootsClosure::do_oop(oop* p) { const oop obj = RawAccess<>::oop_load(p); if (!CompressedOops::is_null(obj)) { if (!_mark_context->is_marked(obj)) { - shenandoah_assert_correct(p, obj); + // Note: The obj is dead here. Do not touch it, just clear. ShenandoahHeap::atomic_clear_oop(p, obj); } else if (_evac_in_progress && _heap->in_collection_set(obj)) { oop resolved = ShenandoahBarrierSet::resolve_forwarded_not_null(obj); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahForwarding.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahForwarding.inline.hpp index cf69eb67e47..01294f9c890 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahForwarding.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahForwarding.inline.hpp @@ -32,7 +32,7 @@ #include "runtime/javaThread.hpp" inline oop ShenandoahForwarding::get_forwardee_raw(oop obj) { - shenandoah_assert_in_heap(nullptr, obj); + shenandoah_assert_in_heap_bounds(nullptr, obj); return get_forwardee_raw_unchecked(obj); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 6f5fce53f85..a587cc417e3 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -730,9 +730,18 @@ size_t ShenandoahHeap::initial_capacity() const { } bool ShenandoahHeap::is_in(const void* p) const { - HeapWord* heap_base = (HeapWord*) base(); - HeapWord* last_region_end = heap_base + ShenandoahHeapRegion::region_size_words() * num_regions(); - return p >= heap_base && p < last_region_end; + if (is_in_reserved(p)) { + if (is_full_gc_move_in_progress()) { + // Full GC move is running, we do not have a consistent region + // information yet. But we know the pointer is in heap. + return true; + } + // Now check if we point to a live section in active region. + ShenandoahHeapRegion* r = heap_region_containing(p); + return (r->is_active() && p < r->top()); + } else { + return false; + } } void ShenandoahHeap::maybe_uncommit(double shrink_before, size_t shrink_until) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index 81b1c3df6f4..1ee1f9dfc88 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -493,6 +493,8 @@ class ShenandoahHeap : public CollectedHeap, public ShenandoahSpaceInfo { public: bool is_maximal_no_gc() const override shenandoah_not_implemented_return(false); + // Check the pointer is in active part of Java heap. + // Use is_in_reserved to check if object is within heap bounds. bool is_in(const void* p) const override; bool requires_barriers(stackChunkOop obj) const override; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.cpp index 30389b4e95c..fa2e15a98c7 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.cpp @@ -122,7 +122,7 @@ void ShenandoahMarkBitMap::clear_range_large(MemRegion mr) { #ifdef ASSERT void ShenandoahMarkBitMap::check_mark(HeapWord* addr) const { - assert(ShenandoahHeap::heap()->is_in(addr), + assert(ShenandoahHeap::heap()->is_in_reserved(addr), "Trying to access bitmap " PTR_FORMAT " for address " PTR_FORMAT " not in the heap.", p2i(this), p2i(addr)); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.hpp index d58117c02e2..62baf3e61ea 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.hpp @@ -63,8 +63,10 @@ class ShenandoahMarkingContext : public CHeapObj { inline bool mark_weak(oop obj); // Simple versions of marking accessors, to be used outside of marking (e.g. no possible concurrent updates) - inline bool is_marked(oop) const; + inline bool is_marked(oop obj) const; + inline bool is_marked(HeapWord* raw_obj) const; inline bool is_marked_strong(oop obj) const; + inline bool is_marked_strong(HeapWord* raw_obj) const; inline bool is_marked_weak(oop obj) const; inline HeapWord* get_next_marked_addr(HeapWord* addr, HeapWord* limit) const; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.inline.hpp index 34b8288f476..1ba3caf26b7 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.inline.hpp @@ -38,11 +38,19 @@ inline bool ShenandoahMarkingContext::mark_weak(oop obj) { } inline bool ShenandoahMarkingContext::is_marked(oop obj) const { - return allocated_after_mark_start(obj) || _mark_bit_map.is_marked(cast_from_oop(obj)); + return is_marked(cast_from_oop(obj)); +} + +inline bool ShenandoahMarkingContext::is_marked(HeapWord* raw_obj) const { + return allocated_after_mark_start(raw_obj) || _mark_bit_map.is_marked(raw_obj); } inline bool ShenandoahMarkingContext::is_marked_strong(oop obj) const { - return allocated_after_mark_start(obj) || _mark_bit_map.is_marked_strong(cast_from_oop(obj)); + return is_marked_strong(cast_from_oop(obj)); +} + +inline bool ShenandoahMarkingContext::is_marked_strong(HeapWord* raw_obj) const { + return allocated_after_mark_start(raw_obj) || _mark_bit_map.is_marked_strong(raw_obj); } inline bool ShenandoahMarkingContext::is_marked_weak(oop obj) const { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp index f395119d46a..42c8d0ad271 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp @@ -83,10 +83,21 @@ static volatile T* reference_referent_addr(oop reference) { return (volatile T*)java_lang_ref_Reference::referent_addr_raw(reference); } +inline oop reference_coop_decode_raw(narrowOop v) { + return CompressedOops::is_null(v) ? nullptr : CompressedOops::decode_raw(v); +} + +inline oop reference_coop_decode_raw(oop v) { + return v; +} + +// Raw referent, it can be dead. You cannot treat it as oop without additional safety +// checks, this is why it is HeapWord*. The decoding uses a special-case inlined +// CompressedOops::decode method that bypasses normal oop-ness checks. template -static oop reference_referent(oop reference) { - T heap_oop = Atomic::load(reference_referent_addr(reference)); - return CompressedOops::decode(heap_oop); +static HeapWord* reference_referent_raw(oop reference) { + T raw_oop = Atomic::load(reference_referent_addr(reference)); + return cast_from_oop(reference_coop_decode_raw(raw_oop)); } static void reference_clear_referent(oop reference) { @@ -278,8 +289,8 @@ bool ShenandoahReferenceProcessor::should_discover(oop reference, ReferenceType template bool ShenandoahReferenceProcessor::should_drop(oop reference, ReferenceType type) const { - const oop referent = reference_referent(reference); - if (referent == nullptr) { + HeapWord* raw_referent = reference_referent_raw(reference); + if (raw_referent == nullptr) { // Reference has been cleared, by a call to Reference.enqueue() // or Reference.clear() from the application, which means we // should drop the reference. @@ -289,9 +300,9 @@ bool ShenandoahReferenceProcessor::should_drop(oop reference, ReferenceType type // Check if the referent is still alive, in which case we should // drop the reference. if (type == REF_PHANTOM) { - return ShenandoahHeap::heap()->complete_marking_context()->is_marked(referent); + return ShenandoahHeap::heap()->complete_marking_context()->is_marked(raw_referent); } else { - return ShenandoahHeap::heap()->complete_marking_context()->is_marked_strong(referent); + return ShenandoahHeap::heap()->complete_marking_context()->is_marked_strong(raw_referent); } } @@ -303,7 +314,7 @@ void ShenandoahReferenceProcessor::make_inactive(oop reference, ReferenceType ty // next field. An application can't call FinalReference.enqueue(), so there is // no race to worry about when setting the next field. assert(reference_next(reference) == nullptr, "Already inactive"); - assert(ShenandoahHeap::heap()->marking_context()->is_marked(reference_referent(reference)), "only make inactive final refs with alive referents"); + assert(ShenandoahHeap::heap()->marking_context()->is_marked(reference_referent_raw(reference)), "only make inactive final refs with alive referents"); reference_set_next(reference, reference); } else { // Clear referent @@ -376,8 +387,8 @@ oop ShenandoahReferenceProcessor::drop(oop reference, ReferenceType type) { log_trace(gc, ref)("Dropped Reference: " PTR_FORMAT " (%s)", p2i(reference), reference_type_name(type)); #ifdef ASSERT - oop referent = reference_referent(reference); - assert(referent == nullptr || ShenandoahHeap::heap()->marking_context()->is_marked(referent), + HeapWord* raw_referent = reference_referent_raw(reference); + assert(raw_referent == nullptr || ShenandoahHeap::heap()->marking_context()->is_marked(raw_referent), "only drop references with alive referents"); #endif diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp index 23da3d7f637..4834ecba543 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp @@ -51,13 +51,6 @@ static bool is_instance_ref_klass(Klass* k) { return k->is_instance_klass() && InstanceKlass::cast(k)->reference_type() != REF_NONE; } -class ShenandoahIgnoreReferenceDiscoverer : public ReferenceDiscoverer { -public: - virtual bool discover_reference(oop obj, ReferenceType type) { - return true; - } -}; - class ShenandoahVerifyOopClosure : public BasicOopIterateClosure { private: const char* _phase; @@ -68,6 +61,7 @@ class ShenandoahVerifyOopClosure : public BasicOopIterateClosure { ShenandoahLivenessData* _ld; void* _interior_loc; oop _loc; + ReferenceIterationMode _ref_mode; public: ShenandoahVerifyOopClosure(ShenandoahVerifierStack* stack, MarkBitMap* map, ShenandoahLivenessData* ld, @@ -82,10 +76,20 @@ class ShenandoahVerifyOopClosure : public BasicOopIterateClosure { _loc(nullptr) { if (options._verify_marked == ShenandoahVerifier::_verify_marked_complete_except_references || options._verify_marked == ShenandoahVerifier::_verify_marked_disable) { - set_ref_discoverer_internal(new ShenandoahIgnoreReferenceDiscoverer()); + // Unknown status for Reference.referent field. Do not touch it, it might be dead. + // Normally, barriers would prevent us from seeing the dead referents, but verifier + // runs with barriers disabled. + _ref_mode = DO_FIELDS_EXCEPT_REFERENT; + } else { + // Otherwise do all fields. + _ref_mode = DO_FIELDS; } } + ReferenceIterationMode reference_iteration_mode() override { + return _ref_mode; + } + private: void check(ShenandoahAsserts::SafeLevel level, oop obj, bool test, const char* label) { if (!test) { @@ -119,8 +123,8 @@ class ShenandoahVerifyOopClosure : public BasicOopIterateClosure { // that failure report would not try to touch something that was not yet verified to be // safe to process. - check(ShenandoahAsserts::_safe_unknown, obj, _heap->is_in(obj), - "oop must be in heap"); + check(ShenandoahAsserts::_safe_unknown, obj, _heap->is_in_reserved(obj), + "oop must be in heap bounds"); check(ShenandoahAsserts::_safe_unknown, obj, is_object_aligned(obj), "oop must be aligned"); @@ -177,8 +181,8 @@ class ShenandoahVerifyOopClosure : public BasicOopIterateClosure { ShenandoahHeapRegion* fwd_reg = nullptr; if (obj != fwd) { - check(ShenandoahAsserts::_safe_oop, obj, _heap->is_in(fwd), - "Forwardee must be in heap"); + check(ShenandoahAsserts::_safe_oop, obj, _heap->is_in_reserved(fwd), + "Forwardee must be in heap bounds"); check(ShenandoahAsserts::_safe_oop, obj, !CompressedOops::is_null(fwd), "Forwardee is set"); check(ShenandoahAsserts::_safe_oop, obj, is_object_aligned(fwd), @@ -195,6 +199,9 @@ class ShenandoahVerifyOopClosure : public BasicOopIterateClosure { fwd_reg = _heap->heap_region_containing(fwd); + check(ShenandoahAsserts::_safe_oop, obj, fwd_reg->is_active(), + "Forwardee should be in active region"); + // Verify that forwardee is not in the dead space: check(ShenandoahAsserts::_safe_oop, obj, !fwd_reg->is_humongous(), "Should have no humongous forwardees"); @@ -324,8 +331,8 @@ class ShenandoahVerifyOopClosure : public BasicOopIterateClosure { _loc = nullptr; } - virtual void do_oop(oop* p) { do_oop_work(p); } - virtual void do_oop(narrowOop* p) { do_oop_work(p); } + virtual void do_oop(oop* p) override { do_oop_work(p); } + virtual void do_oop(narrowOop* p) override { do_oop_work(p); } }; class ShenandoahCalculateRegionStatsClosure : public ShenandoahHeapRegionClosure {