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* Node::_idx*/ int, VTransformNode* /* or null*/> _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 extends Path> 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 extends Runtime.Version> 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 super FieldBuilder> 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 super MethodBuilder> 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 super CodeBuilder> 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