diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index a4bd56185ba..cb414131e9e 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -5105,7 +5105,7 @@ operand iRegP() match(iRegP_R0); //match(iRegP_R2); //match(iRegP_R4); - //match(iRegP_R5); + match(iRegP_R5); match(thread_RegP); op_cost(0); format %{ %} diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 4ca9328fbf3..91b5c8c8b67 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -3208,6 +3208,7 @@ operand iRegP() match(RegP); match(iRegPNoSp); match(iRegP_R10); + match(iRegP_R15); match(javaThread_RegP); op_cost(0); format %{ %} diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index 3dedf0d80e9..412a63b39e6 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -869,7 +869,11 @@ class StubGenerator: public StubCodeGenerator { // /* * if (is_aligned) { - * goto copy_8_bytes; + * if (count >= 32) + * goto copy32_loop; + * if (count >= 8) + * goto copy8_loop; + * goto copy_small; * } * bool is_backwards = step < 0; * int granularity = uabs(step); @@ -887,9 +891,12 @@ class StubGenerator: public StubCodeGenerator { * * if ((dst % 8) == (src % 8)) { * aligned; - * goto copy8; + * goto copy_big; * } * + * copy_big: + * if the amount to copy is more than (or equal to) 32 bytes goto copy32_loop + * else goto copy8_loop * copy_small: * load element one by one; * done; @@ -950,10 +957,10 @@ class StubGenerator: public StubCodeGenerator { bool is_backwards = step < 0; int granularity = uabs(step); - const Register src = x30, dst = x31, cnt = x15, tmp3 = x16, tmp4 = x17; + const Register src = x30, dst = x31, cnt = x15, tmp3 = x16, tmp4 = x17, tmp5 = x14, tmp6 = x13; Label same_aligned; - Label copy8, copy_small, done; + Label copy_big, copy32_loop, copy8_loop, copy_small, done; copy_insn ld_arr = NULL, st_arr = NULL; switch (granularity) { @@ -988,36 +995,69 @@ class StubGenerator: public StubCodeGenerator { } if (is_aligned) { + __ addi(tmp, cnt, -32); + __ bgez(tmp, copy32_loop); __ addi(tmp, cnt, -8); - __ bgez(tmp, copy8); + __ bgez(tmp, copy8_loop); __ j(copy_small); + } else { + __ mv(tmp, 16); + __ blt(cnt, tmp, copy_small); + + __ xorr(tmp, src, dst); + __ andi(tmp, tmp, 0b111); + __ bnez(tmp, copy_small); + + __ bind(same_aligned); + __ andi(tmp, src, 0b111); + __ beqz(tmp, copy_big); + if (is_backwards) { + __ addi(src, src, step); + __ addi(dst, dst, step); + } + (_masm->*ld_arr)(tmp3, Address(src), t0); + (_masm->*st_arr)(tmp3, Address(dst), t0); + if (!is_backwards) { + __ addi(src, src, step); + __ addi(dst, dst, step); + } + __ addi(cnt, cnt, -granularity); + __ beqz(cnt, done); + __ j(same_aligned); + + __ bind(copy_big); + __ mv(tmp, 32); + __ blt(cnt, tmp, copy8_loop); } - - __ mv(tmp, 16); - __ blt(cnt, tmp, copy_small); - - __ xorr(tmp, src, dst); - __ andi(tmp, tmp, 0b111); - __ bnez(tmp, copy_small); - - __ bind(same_aligned); - __ andi(tmp, src, 0b111); - __ beqz(tmp, copy8); + __ bind(copy32_loop); if (is_backwards) { - __ addi(src, src, step); - __ addi(dst, dst, step); + __ addi(src, src, -wordSize * 4); + __ addi(dst, dst, -wordSize * 4); } - (_masm->*ld_arr)(tmp3, Address(src), t0); - (_masm->*st_arr)(tmp3, Address(dst), t0); - if (!is_backwards) { - __ addi(src, src, step); - __ addi(dst, dst, step); - } - __ addi(cnt, cnt, -granularity); - __ beqz(cnt, done); - __ j(same_aligned); + // we first load 32 bytes, then write it, so the direction here doesn't matter + __ ld(tmp3, Address(src)); + __ ld(tmp4, Address(src, 8)); + __ ld(tmp5, Address(src, 16)); + __ ld(tmp6, Address(src, 24)); + __ sd(tmp3, Address(dst)); + __ sd(tmp4, Address(dst, 8)); + __ sd(tmp5, Address(dst, 16)); + __ sd(tmp6, Address(dst, 24)); - __ bind(copy8); + if (!is_backwards) { + __ addi(src, src, wordSize * 4); + __ addi(dst, dst, wordSize * 4); + } + __ addi(tmp, cnt, -(32 + wordSize * 4)); + __ addi(cnt, cnt, -wordSize * 4); + __ bgez(tmp, copy32_loop); // cnt >= 32, do next loop + + __ beqz(cnt, done); // if that's all - done + + __ addi(tmp, cnt, -8); // if not - copy the reminder + __ bltz(tmp, copy_small); // cnt < 8, go to copy_small, else fall throught to copy8_loop + + __ bind(copy8_loop); if (is_backwards) { __ addi(src, src, -wordSize); __ addi(dst, dst, -wordSize); @@ -1028,11 +1068,11 @@ class StubGenerator: public StubCodeGenerator { __ addi(src, src, wordSize); __ addi(dst, dst, wordSize); } + __ addi(tmp, cnt, -(8 + wordSize)); __ addi(cnt, cnt, -wordSize); - __ addi(tmp4, cnt, -8); - __ bgez(tmp4, copy8); // cnt >= 8, do next loop + __ bgez(tmp, copy8_loop); // cnt >= 8, do next loop - __ beqz(cnt, done); + __ beqz(cnt, done); // if that's all - done __ bind(copy_small); if (is_backwards) { diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index eb257c7a101..e96cbe20974 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -4328,13 +4328,13 @@ static void check_pax(void) { #ifndef ZERO size_t size = os::Linux::page_size(); - void* p = ::mmap(NULL, size, PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + void* p = ::mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); if (p == MAP_FAILED) { log_debug(os)("os_linux.cpp: check_pax: mmap failed (%s)" , os::strerror(errno)); vm_exit_out_of_memory(size, OOM_MMAP_ERROR, "failed to allocate memory for PaX check."); } - int res = ::mprotect(p, size, PROT_WRITE|PROT_EXEC); + int res = ::mprotect(p, size, PROT_READ|PROT_WRITE|PROT_EXEC); if (res == -1) { log_debug(os)("os_linux.cpp: check_pax: mprotect failed (%s)" , os::strerror(errno)); vm_exit_during_initialization( diff --git a/src/hotspot/share/compiler/compilerDefinitions.cpp b/src/hotspot/share/compiler/compilerDefinitions.cpp index bc1eb0e4392..7031e5af497 100644 --- a/src/hotspot/share/compiler/compilerDefinitions.cpp +++ b/src/hotspot/share/compiler/compilerDefinitions.cpp @@ -404,13 +404,7 @@ void CompilerConfig::set_compilation_policy_flags() { if (CompilerConfig::is_tiered() && CompilerConfig::is_c2_enabled()) { #ifdef COMPILER2 // Some inlining tuning -#ifdef X86 - if (FLAG_IS_DEFAULT(InlineSmallCode)) { - FLAG_SET_DEFAULT(InlineSmallCode, 2500); - } -#endif - -#if defined AARCH64 +#if defined(X86) || defined(AARCH64) || defined(RISCV64) if (FLAG_IS_DEFAULT(InlineSmallCode)) { FLAG_SET_DEFAULT(InlineSmallCode, 2500); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp index da12de337d9..08b76bad047 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp @@ -66,6 +66,10 @@ ShenandoahFullGC::ShenandoahFullGC() : _gc_timer(ShenandoahHeap::heap()->gc_timer()), _preserved_marks(new PreservedMarksSet(true)) {} +ShenandoahFullGC::~ShenandoahFullGC() { + delete _preserved_marks; +} + bool ShenandoahFullGC::collect(GCCause::Cause cause) { vmop_entry_full(cause); // Always success diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.hpp b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.hpp index d829306a599..1c1653e59ec 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.hpp @@ -66,6 +66,7 @@ private: public: ShenandoahFullGC(); + ~ShenandoahFullGC(); bool collect(GCCause::Cause cause); private: diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index 5bf7b14e297..c41936ca554 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -1270,15 +1270,6 @@ void Method::restore_unshareable_info(TRAPS) { assert(is_method() && is_valid_method(this), "ensure C++ vtable is restored"); } -address Method::from_compiled_entry_no_trampoline() const { - CompiledMethod *code = Atomic::load_acquire(&_code); - if (code) { - return code->verified_entry_point(); - } else { - return adapter()->get_c2i_entry(); - } -} - // The verified_code_entry() must be called when a invoke is resolved // on this method. diff --git a/src/hotspot/share/oops/method.hpp b/src/hotspot/share/oops/method.hpp index 758888bf2fe..6b08c75eb24 100644 --- a/src/hotspot/share/oops/method.hpp +++ b/src/hotspot/share/oops/method.hpp @@ -145,7 +145,6 @@ class Method : public Metadata { static address make_adapters(const methodHandle& mh, TRAPS); address from_compiled_entry() const; - address from_compiled_entry_no_trampoline() const; address from_interpreted_entry() const; // access flag diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 6fc069be143..aa1e399a290 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -402,7 +402,7 @@ void Compile::remove_useless_node(Node* dead) { } // Disconnect all useless nodes by disconnecting those at the boundary. -void Compile::remove_useless_nodes(Unique_Node_List &useful) { +void Compile::disconnect_useless_nodes(Unique_Node_List &useful, Unique_Node_List* worklist) { uint next = 0; while (next < useful.size()) { Node *n = useful.at(next++); @@ -425,7 +425,7 @@ void Compile::remove_useless_nodes(Unique_Node_List &useful) { } } if (n->outcnt() == 1 && n->has_special_unique_user()) { - record_for_igvn(n->unique_out()); + worklist->push(n->unique_out()); } } @@ -435,6 +435,11 @@ void Compile::remove_useless_nodes(Unique_Node_List &useful) { remove_useless_nodes(_expensive_nodes, useful); // remove useless expensive nodes remove_useless_nodes(_for_post_loop_igvn, useful); // remove useless node recorded for post loop opts IGVN pass remove_useless_coarsened_locks(useful); // remove useless coarsened locks nodes +#ifdef ASSERT + if (_modified_nodes != NULL) { + _modified_nodes->remove_useless_nodes(useful.member_set()); + } +#endif BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); bs->eliminate_useless_gc_barriers(useful, this); diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index d2f7a36852a..2e5acee28bd 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -945,7 +945,7 @@ class Compile : public Phase { void identify_useful_nodes(Unique_Node_List &useful); void update_dead_node_list(Unique_Node_List &useful); - void remove_useless_nodes (Unique_Node_List &useful); + void disconnect_useless_nodes(Unique_Node_List &useful, Unique_Node_List* worklist); void remove_useless_node(Node* dead); diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index 0590d5a44d7..2ed86cbc9e7 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -281,7 +281,9 @@ bool ConnectionGraph::compute_escape() { // 3. Adjust scalar_replaceable state of nonescaping objects and push // scalar replaceable allocations on alloc_worklist for processing // in split_unique_types(). + GrowableArray jobj_worklist; int non_escaped_length = non_escaped_allocs_worklist.length(); + bool found_nsr_alloc = false; for (int next = 0; next < non_escaped_length; next++) { JavaObjectNode* ptn = non_escaped_allocs_worklist.at(next); bool noescape = (ptn->escape_state() == PointsToNode::NoEscape); @@ -292,11 +294,25 @@ bool ConnectionGraph::compute_escape() { if (noescape && ptn->scalar_replaceable()) { adjust_scalar_replaceable_state(ptn); if (ptn->scalar_replaceable()) { - alloc_worklist.append(ptn->ideal_node()); + jobj_worklist.push(ptn); + } else { + found_nsr_alloc = true; } } } + // Propagate NSR (Not Scalar Replaceable) state. + if (found_nsr_alloc) { + find_scalar_replaceable_allocs(jobj_worklist); + } + + for (int next = 0; next < jobj_worklist.length(); ++next) { + JavaObjectNode* jobj = jobj_worklist.at(next); + if (jobj->scalar_replaceable()) { + alloc_worklist.append(jobj->ideal_node()); + } + } + #ifdef ASSERT if (VerifyConnectionGraph) { // Verify that graph is complete - no new edges could be added or needed. @@ -1865,15 +1881,19 @@ void ConnectionGraph::adjust_scalar_replaceable_state(JavaObjectNode* jobj) { set_not_scalar_replaceable(jobj NOT_PRODUCT(COMMA "is stored at unknown offset")); return; } - // 2. An object is not scalar replaceable if the field into which it is - // stored has multiple bases one of which is null. - if (field->base_count() > 1) { - for (BaseIterator i(field); i.has_next(); i.next()) { - PointsToNode* base = i.get(); - if (base == null_obj) { - set_not_scalar_replaceable(jobj NOT_PRODUCT(COMMA "is stored into field with potentially null base")); - return; - } + for (BaseIterator i(field); i.has_next(); i.next()) { + PointsToNode* base = i.get(); + // 2. An object is not scalar replaceable if the field into which it is + // stored has multiple bases one of which is null. + if ((base == null_obj) && (field->base_count() > 1)) { + set_not_scalar_replaceable(jobj NOT_PRODUCT(COMMA "is stored into field with potentially null base")); + return; + } + // 2.5. An object is not scalar replaceable if the field into which it is + // stored has NSR base. + if (!base->scalar_replaceable()) { + set_not_scalar_replaceable(jobj NOT_PRODUCT(COMMA "is stored into field with NSR base")); + return; } } } @@ -1963,6 +1983,36 @@ void ConnectionGraph::adjust_scalar_replaceable_state(JavaObjectNode* jobj) { } } +// Propagate NSR (Not scalar replaceable) state. +void ConnectionGraph::find_scalar_replaceable_allocs(GrowableArray& jobj_worklist) { + int jobj_length = jobj_worklist.length(); + bool found_nsr_alloc = true; + while (found_nsr_alloc) { + found_nsr_alloc = false; + for (int next = 0; next < jobj_length; ++next) { + JavaObjectNode* jobj = jobj_worklist.at(next); + for (UseIterator i(jobj); (jobj->scalar_replaceable() && i.has_next()); i.next()) { + PointsToNode* use = i.get(); + if (use->is_Field()) { + FieldNode* field = use->as_Field(); + assert(field->is_oop() && field->scalar_replaceable(), "sanity"); + assert(field->offset() != Type::OffsetBot, "sanity"); + for (BaseIterator i(field); i.has_next(); i.next()) { + PointsToNode* base = i.get(); + // An object is not scalar replaceable if the field into which + // it is stored has NSR base. + if ((base != null_obj) && !base->scalar_replaceable()) { + set_not_scalar_replaceable(jobj NOT_PRODUCT(COMMA "is stored into field with NSR base")); + found_nsr_alloc = true; + break; + } + } + } + } + } + } +} + #ifdef ASSERT void ConnectionGraph::verify_connection_graph( GrowableArray& ptnodes_worklist, diff --git a/src/hotspot/share/opto/escape.hpp b/src/hotspot/share/opto/escape.hpp index f6a45d08171..60bb301f9c5 100644 --- a/src/hotspot/share/opto/escape.hpp +++ b/src/hotspot/share/opto/escape.hpp @@ -463,6 +463,9 @@ private: // Adjust scalar_replaceable state after Connection Graph is built. void adjust_scalar_replaceable_state(JavaObjectNode* jobj); + // Propagate NSR (Not scalar replaceable) state. + void find_scalar_replaceable_allocs(GrowableArray& jobj_worklist); + // Optimize ideal graph. void optimize_ideal_graph(GrowableArray& ptr_cmp_worklist, GrowableArray& storestore_worklist); diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index d6027b0a161..3535fbee759 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -3653,29 +3653,21 @@ bool IdealLoopTree::do_remove_empty_loop(PhaseIdealLoop *phase) { } // Replace the phi at loop head with the final value of the last - // iteration. Then the CountedLoopEnd will collapse (backedge never - // taken) and all loop-invariant uses of the exit values will be correct. - Node *phi = cl->phi(); - Node *exact_limit = phase->exact_limit(this); - if (exact_limit != cl->limit()) { - // We also need to replace the original limit to collapse loop exit. - Node* cmp = cl->loopexit()->cmp_node(); - assert(cl->limit() == cmp->in(2), "sanity"); - // Duplicate cmp node if it has other users - if (cmp->outcnt() > 1) { - cmp = cmp->clone(); - cmp = phase->_igvn.register_new_node_with_optimizer(cmp); - BoolNode *bol = cl->loopexit()->in(CountedLoopEndNode::TestValue)->as_Bool(); - phase->_igvn.replace_input_of(bol, 1, cmp); // put bol on worklist - } - phase->_igvn._worklist.push(cmp->in(2)); // put limit on worklist - phase->_igvn.replace_input_of(cmp, 2, exact_limit); // put cmp on worklist - } + // iteration (exact_limit - stride), to make sure the loop exit value + // is correct, for any users after the loop. // Note: the final value after increment should not overflow since // counted loop has limit check predicate. - Node *final = new SubINode(exact_limit, cl->stride()); - phase->register_new_node(final,cl->in(LoopNode::EntryControl)); - phase->_igvn.replace_node(phi,final); + Node* phi = cl->phi(); + Node* exact_limit = phase->exact_limit(this); + Node* final_iv = new SubINode(exact_limit, cl->stride()); + phase->register_new_node(final_iv, cl->in(LoopNode::EntryControl)); + phase->_igvn.replace_node(phi, final_iv); + + // Set loop-exit condition to false. Then the CountedLoopEnd will collapse, + // because the back edge is never taken. + Node* zero = phase->_igvn.intcon(0); + phase->_igvn.replace_input_of(cl->loopexit(), CountedLoopEndNode::TestValue, zero); + phase->C->set_major_progress(); return true; } diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index 742e745a978..da035b2ff66 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -3896,17 +3896,6 @@ uint IdealLoopTree::est_loop_flow_merge_sz() const { return 0; } -#ifdef ASSERT -bool IdealLoopTree::has_reduction_nodes() const { - for (uint i = 0; i < _body.size(); i++) { - if (_body[i]->is_reduction()) { - return true; - } - } - return false; -} -#endif // ASSERT - #ifndef PRODUCT //------------------------------dump_head-------------------------------------- // Dump 1 liner for loop header info diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 731f84c41af..e54c892d954 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -778,11 +778,6 @@ public: void remove_main_post_loops(CountedLoopNode *cl, PhaseIdealLoop *phase); -#ifdef ASSERT - // Tell whether the body contains nodes marked as reductions. - bool has_reduction_nodes() const; -#endif // ASSERT - #ifndef PRODUCT void dump_head() const; // Dump loop head only void dump() const; // Dump this loop recursively diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index adcf61771ca..231d92e1aa2 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -1488,7 +1488,12 @@ static bool stable_phi(PhiNode* phi, PhaseGVN *phase) { } //------------------------------split_through_phi------------------------------ // Split instance or boxed field load through Phi. -Node *LoadNode::split_through_phi(PhaseGVN *phase) { +Node* LoadNode::split_through_phi(PhaseGVN* phase) { + if (req() > 3) { + assert(is_LoadVector() && Opcode() != Op_LoadVector, "load has too many inputs"); + // LoadVector subclasses such as LoadVectorMasked have extra inputs that the logic below doesn't take into account + return NULL; + } Node* mem = in(Memory); Node* address = in(Address); const TypeOopPtr *t_oop = phase->type(address)->isa_oopptr(); diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index 38a803b8645..660f791b201 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -423,7 +423,7 @@ PhaseRemoveUseless::PhaseRemoveUseless(PhaseGVN* gvn, Unique_Node_List* worklist worklist->remove_useless_nodes(_useful.member_set()); // Disconnect 'useless' nodes that are adjacent to useful nodes - C->remove_useless_nodes(_useful); + C->disconnect_useless_nodes(_useful, worklist); } //============================================================================= @@ -1764,6 +1764,9 @@ void PhaseCCP::analyze() { Unique_Node_List worklist; worklist.push(C->root()); + assert(_root_and_safepoints.size() == 0, "must be empty (unused)"); + _root_and_safepoints.push(C->root()); + // Pull from worklist; compute new value; push changes out. // This loop is the meat of CCP. while( worklist.size() ) { @@ -1774,8 +1777,9 @@ void PhaseCCP::analyze() { n = worklist.pop(); } if (n->is_SafePoint()) { - // Keep track of SafePoint nodes for PhaseCCP::transform() - _safepoints.push(n); + // Make sure safepoints are processed by PhaseCCP::transform even if they are + // not reachable from the bottom. Otherwise, infinite loops would be removed. + _root_and_safepoints.push(n); } const Type *t = n->Value(this); if (t != type(n)) { @@ -1904,14 +1908,15 @@ Node *PhaseCCP::transform( Node *n ) { Node *new_node = _nodes[n->_idx]; // Check for transformed node if( new_node != NULL ) return new_node; // Been there, done that, return old answer - new_node = transform_once(n); // Check for constant - _nodes.map( n->_idx, new_node ); // Flag as having been cloned + + assert(n->is_Root(), "traversal must start at root"); + assert(_root_and_safepoints.member(n), "root (n) must be in list"); // Allocate stack of size _nodes.Size()/2 to avoid frequent realloc - GrowableArray trstack(C->live_nodes() >> 1); - - trstack.push(new_node); // Process children of cloned node + GrowableArray transform_stack(C->live_nodes() >> 1); + Unique_Node_List useful; // track all visited nodes, so that we can remove the complement + // Initialize the traversal. // This CCP pass may prove that no exit test for a loop ever succeeds (i.e. the loop is infinite). In that case, // the logic below doesn't follow any path from Root to the loop body: there's at least one such path but it's proven // never taken (its type is TOP). As a consequence the node on the exit path that's input to Root (let's call it n) is @@ -1919,17 +1924,18 @@ Node *PhaseCCP::transform( Node *n ) { // through the graph from Root, this causes the loop body to never be processed here even when it's not dead (that // is reachable from Root following its uses). To prevent that issue, transform() starts walking the graph from Root // and all safepoints. - for (uint i = 0; i < _safepoints.size(); ++i) { - Node* nn = _safepoints.at(i); + for (uint i = 0; i < _root_and_safepoints.size(); ++i) { + Node* nn = _root_and_safepoints.at(i); Node* new_node = _nodes[nn->_idx]; assert(new_node == NULL, ""); - new_node = transform_once(nn); - _nodes.map(nn->_idx, new_node); - trstack.push(new_node); + new_node = transform_once(nn); // Check for constant + _nodes.map(nn->_idx, new_node); // Flag as having been cloned + transform_stack.push(new_node); // Process children of cloned node + useful.push(new_node); } - while ( trstack.is_nonempty() ) { - Node *clone = trstack.pop(); + while (transform_stack.is_nonempty()) { + Node* clone = transform_stack.pop(); uint cnt = clone->req(); for( uint i = 0; i < cnt; i++ ) { // For all inputs do Node *input = clone->in(i); @@ -1938,13 +1944,33 @@ Node *PhaseCCP::transform( Node *n ) { if( new_input == NULL ) { new_input = transform_once(input); // Check for constant _nodes.map( input->_idx, new_input );// Flag as having been cloned - trstack.push(new_input); + transform_stack.push(new_input); // Process children of cloned node + useful.push(new_input); } assert( new_input == clone->in(i), "insanity check"); } } } - return new_node; + + // The above transformation might lead to subgraphs becoming unreachable from the + // bottom while still being reachable from the top. As a result, nodes in that + // subgraph are not transformed and their bottom types are not updated, leading to + // an inconsistency between bottom_type() and type(). In rare cases, LoadNodes in + // such a subgraph, might be re-enqueued for IGVN indefinitely by MemNode::Ideal_common + // because their address type is inconsistent. Therefore, we aggressively remove + // all useless nodes here even before PhaseIdealLoop::build_loop_late gets a chance + // to remove them anyway. + if (C->cached_top_node()) { + useful.push(C->cached_top_node()); + } + C->update_dead_node_list(useful); + remove_useless_nodes(useful.member_set()); + _worklist.remove_useless_nodes(useful.member_set()); + C->disconnect_useless_nodes(useful, &_worklist); + + Node* new_root = _nodes[n->_idx]; + assert(new_root->is_Root(), "transformed root node must be a root node"); + return new_root; } diff --git a/src/hotspot/share/opto/phaseX.hpp b/src/hotspot/share/opto/phaseX.hpp index 4d0b651881e..f65d62ff03e 100644 --- a/src/hotspot/share/opto/phaseX.hpp +++ b/src/hotspot/share/opto/phaseX.hpp @@ -565,7 +565,7 @@ protected: // Phase for performing global Conditional Constant Propagation. // Should be replaced with combined CCP & GVN someday. class PhaseCCP : public PhaseIterGVN { - Unique_Node_List _safepoints; + Unique_Node_List _root_and_safepoints; // Non-recursive. Use analysis to transform single Node. virtual Node *transform_once( Node *n ); diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index f2ef02ed284..ab192ddf27e 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -2416,11 +2416,6 @@ bool SuperWord::output() { return false; } - // Check that the loop to be vectorized does not have inconsistent reduction - // information, which would likely lead to a miscompilation. - assert(!lpt()->has_reduction_nodes() || cl->is_reduction_loop(), - "non-reduction loop contains reduction nodes"); - #ifndef PRODUCT if (TraceLoopOpts) { tty->print("SuperWord::output "); diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 1b5c5883401..a4d07a46f8c 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -1992,8 +1992,6 @@ JRT_LEAF(void, SharedRuntime::fixup_callers_callsite(Method* method, address cal AARCH64_PORT_ONLY(assert(pauth_ptr_is_raw(caller_pc), "should be raw")); - address entry_point = moop->from_compiled_entry_no_trampoline(); - // It's possible that deoptimization can occur at a call site which hasn't // been resolved yet, in which case this function will be called from // an nmethod that has been patched for deopt and we can ignore the @@ -2004,8 +2002,16 @@ JRT_LEAF(void, SharedRuntime::fixup_callers_callsite(Method* method, address cal // "to interpreter" stub in order to load up the Method*. Don't // ask me how I know this... + // Result from nmethod::is_unloading is not stable across safepoints. + NoSafepointVerifier nsv; + + CompiledMethod* callee = moop->code(); + if (callee == NULL) { + return; + } + CodeBlob* cb = CodeCache::find_blob(caller_pc); - if (cb == NULL || !cb->is_compiled() || entry_point == moop->get_c2i_entry()) { + if (cb == NULL || !cb->is_compiled() || callee->is_unloading()) { return; } @@ -2063,6 +2069,7 @@ JRT_LEAF(void, SharedRuntime::fixup_callers_callsite(Method* method, address cal } } address destination = call->destination(); + address entry_point = callee->verified_entry_point(); if (should_fixup_call_destination(destination, entry_point, caller_pc, moop, cb)) { call->set_destination_mt_safe(entry_point); } diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index 9181d84d195..e4c42aa9a7c 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -1229,10 +1229,11 @@ JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) : JavaThread JavaThread::~JavaThread() { - // Ask ServiceThread to release the threadObj OopHandle + // Ask ServiceThread to release the OopHandles ServiceThread::add_oop_handle_release(_threadObj); ServiceThread::add_oop_handle_release(_vthread); ServiceThread::add_oop_handle_release(_jvmti_vthread); + ServiceThread::add_oop_handle_release(_extentLocalCache); // Return the sleep event to the free list ParkEvent::Release(_SleepEvent); diff --git a/src/java.base/share/classes/java/lang/ProcessHandleImpl.java b/src/java.base/share/classes/java/lang/ProcessHandleImpl.java index ff9cf8b0fbd..1596f23c921 100644 --- a/src/java.base/share/classes/java/lang/ProcessHandleImpl.java +++ b/src/java.base/share/classes/java/lang/ProcessHandleImpl.java @@ -100,7 +100,7 @@ final class ProcessHandleImpl implements ProcessHandle { ThreadFactory threadFactory = grimReaper -> { Thread t = InnocuousThread.newSystemThread("process reaper", grimReaper, stackSize, Thread.MAX_PRIORITY); - t.setDaemon(true); + privilegedThreadSetDaemon(t, true); return t; }; @@ -115,6 +115,22 @@ final class ProcessHandleImpl implements ProcessHandle { } } + @SuppressWarnings("removal") + private static void privilegedThreadSetName(Thread thread, String name) { + AccessController.doPrivileged((PrivilegedAction) () -> { + thread.setName(name); + return null; + }); + } + + @SuppressWarnings("removal") + private static void privilegedThreadSetDaemon(Thread thread, boolean on) { + AccessController.doPrivileged((PrivilegedAction) () -> { + thread.setDaemon(on); + return null; + }); + } + /** * Returns a CompletableFuture that completes with process exit status when * the process completes. @@ -140,8 +156,9 @@ final class ProcessHandleImpl implements ProcessHandle { processReaperExecutor.execute(new Runnable() { // Use inner class to avoid lambda stack overhead public void run() { - String threadName = Thread.currentThread().getName(); - Thread.currentThread().setName("process reaper (pid " + pid + ")"); + Thread t = Thread.currentThread(); + String threadName = t.getName(); + privilegedThreadSetName(t, "process reaper (pid " + pid + ")"); try { int exitValue = waitForProcessExit0(pid, shouldReap); if (exitValue == NOT_A_CHILD) { @@ -172,7 +189,7 @@ final class ProcessHandleImpl implements ProcessHandle { completions.remove(pid, newCompletion); } finally { // Restore thread name - Thread.currentThread().setName(threadName); + privilegedThreadSetName(t, threadName); } } }); diff --git a/src/java.desktop/share/native/common/awt/utility/sizecalc.h b/src/java.desktop/share/native/common/awt/utility/sizecalc.h index b4ca9f06591..62611fff2a2 100644 --- a/src/java.desktop/share/native/common/awt/utility/sizecalc.h +++ b/src/java.desktop/share/native/common/awt/utility/sizecalc.h @@ -91,7 +91,7 @@ (IS_SAFE_SIZE_MUL(sizeof(type), (n)) ? (new type[(size_t)(n)]) : throw std::bad_alloc()) #define SAFE_SIZE_NEW_ARRAY2(type, n, m) \ - (IS_SAFE_SIZE_MUL((m), (n)) && IS_SAFE_SIZE_MUL(sizeof(type), (n) * (m)) ? \ + (IS_SAFE_SIZE_MUL((m), (n)) && IS_SAFE_SIZE_MUL(sizeof(type), (size_t)(n) * (size_t)(m)) ? \ (new type[(size_t)(n) * (size_t)(m)]) : throw std::bad_alloc()) /* diff --git a/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyPartialInliningLoadSplit.java b/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyPartialInliningLoadSplit.java new file mode 100644 index 00000000000..abdcfbd726c --- /dev/null +++ b/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyPartialInliningLoadSplit.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug JDK-8292780 + * @summary misc tests failed "assert(false) failed: graph should be schedulable" + * + * @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestArrayCopyPartialInliningLoadSplit + */ + +public class TestArrayCopyPartialInliningLoadSplit { + public static void main(String[] args) { + byte[] array = new byte[16]; + for (int i = 0; i < 20_0000; i++) { + test(array, 16, 0, 0); + } + } + + private static void test(byte[] array, int length, int srcPos, int dstPos) { + byte[] nonEscaping = new byte[16]; + nonEscaping[0] = 0x42; + System.arraycopy(array, srcPos, nonEscaping, 1, 8); + System.arraycopy(nonEscaping, 0, array, 0, length); + } +} diff --git a/test/hotspot/jtreg/compiler/ccp/TestRemoveUnreachableCCP.java b/test/hotspot/jtreg/compiler/ccp/TestRemoveUnreachableCCP.java new file mode 100644 index 00000000000..d1ed8f14370 --- /dev/null +++ b/test/hotspot/jtreg/compiler/ccp/TestRemoveUnreachableCCP.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8287217 + * @summary CCP must remove nodes that are not traversed, else their type can be inconsistent + * @run main/othervm -Xcomp -XX:CompileCommand=compileonly,TestRemoveUnreachableCCP::test + * TestRemoveUnreachableCCP + */ + +public class TestRemoveUnreachableCCP { + + static void test() { + Byte x = 1; + for (int i = 0; i < 10000; i++) { + if ((i & 1) == 0) { + x = (byte)x; + } + } + } + + public static void main(String[] strArr) { + for (int i = 0; i < 11; i++) { + test(); + } + } +} diff --git a/test/hotspot/jtreg/compiler/escapeAnalysis/TestBrokenEA.java b/test/hotspot/jtreg/compiler/escapeAnalysis/TestBrokenEA.java new file mode 100644 index 00000000000..8216281afe5 --- /dev/null +++ b/test/hotspot/jtreg/compiler/escapeAnalysis/TestBrokenEA.java @@ -0,0 +1,82 @@ +/* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8285835 + * @summary EA does not propagate NSR (not scalar replaceable) state. + * @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestBrokenEA + */ + +public class TestBrokenEA { + + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + test1(true); + test1(false); + test2(true); + test2(false); + } + } + + private static void test1(boolean flag) { + A[] array = new A[1]; + if (flag) { + C c = new C(); + B b = new B(); + b.c = c; + A a = new A(); + a.b = b; + array[0] = a; + } + A a = array[0]; + if (a != null) { + a.b.c.f = 0x42; + } + } + + private static void test2(boolean flag) { + A a = null; + if (flag) { + C c = new C(); + B b = new B(); + b.c = c; + a = new A(); + a.b = b; + } + if (a != null) { + a.b.c.f = 0x42; + } + } + + private static class A { + public B b; + } + + private static class B { + public C c; + } + + private static class C { + public int f; + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/TestRemoveEmptyLoop.java b/test/hotspot/jtreg/compiler/loopopts/TestRemoveEmptyLoop.java index 780c092115b..7f8810d9f33 100644 --- a/test/hotspot/jtreg/compiler/loopopts/TestRemoveEmptyLoop.java +++ b/test/hotspot/jtreg/compiler/loopopts/TestRemoveEmptyLoop.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2019, Huawei Technologies Co., Ltd. All rights reserved. + * 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 @@ -23,7 +24,7 @@ /** * @test - * @bug 8231988 + * @bug 8231988 8293996 * @summary Unexpected test result caused by C2 IdealLoopTree::do_remove_empty_loop * * @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation @@ -34,9 +35,11 @@ package compiler.loopopts; public class TestRemoveEmptyLoop { - public void test() { + public void test_cmp_helper() { int i = 34; + // The empty loop that collapses for (; i > 0; i -= 11); + // If uses same Cmp node as the loop condition if (i < 0) { // do nothing } else { @@ -44,12 +47,38 @@ public class TestRemoveEmptyLoop { } } - public static void main(String[] args) { - TestRemoveEmptyLoop _instance = new TestRemoveEmptyLoop(); + public void test_cmp() { + // Loop is OSR compiled, and test_cmp_helper inlined for (int i = 0; i < 50000; i++) { - _instance.test(); + test_cmp_helper(); } - System.out.println("Test passed."); } + void test_collapse_helper() { + int o = 11; + int e = 43542; + for (int i = 524; i < 19325; i += 1) { + // The empty loop that is supposed to collapse + for (int j = 0; j < 32767; j++) { + o++; + } + for (int k = 0; k < o; k++) { + e++; + } + } + } + + public void test_collapse() { + // Loop is OSR compiled, and test_collapse_helper inlined + for (int i = 0; i < 50000; i++) { + test_collapse_helper(); + } + } + + public static void main(String[] args) { + TestRemoveEmptyLoop _instance = new TestRemoveEmptyLoop(); + _instance.test_cmp(); + _instance.test_collapse(); + System.out.println("Test passed."); + } } diff --git a/test/hotspot/jtreg/compiler/runtime/TestConstantsInError.java b/test/hotspot/jtreg/compiler/runtime/TestConstantsInError.java index 1c551b4efbd..df221959bb5 100644 --- a/test/hotspot/jtreg/compiler/runtime/TestConstantsInError.java +++ b/test/hotspot/jtreg/compiler/runtime/TestConstantsInError.java @@ -130,7 +130,7 @@ public abstract class TestConstantsInError implements OutputProcessor { results.shouldMatch("Test_C1/.*::test \\(3 bytes\\)$") .shouldMatch("Test_C2/.*::test \\(3 bytes\\)$"); - if (isC1 && Platform.isAArch64()) { // no code patching + if (isC1 && (Platform.isAArch64() || Platform.isRISCV64())) { // no code patching results.shouldMatch("Test_C1/.*::test \\(3 bytes\\) made not entrant") .shouldMatch("Test_C2/.*::test \\(3 bytes\\) made not entrant"); } else { @@ -168,7 +168,7 @@ public abstract class TestConstantsInError implements OutputProcessor { .shouldMatch("Test_MH3/.*::test \\(3 bytes\\)$") .shouldMatch("Test_MH4/.*::test \\(3 bytes\\)$"); - if (isC1 && Platform.isAArch64()) { // no code patching + if (isC1 && (Platform.isAArch64() || Platform.isRISCV64())) { // no code patching results.shouldMatch("Test_MH1/.*::test \\(3 bytes\\) made not entrant") .shouldMatch("Test_MH2/.*::test \\(3 bytes\\) made not entrant") .shouldMatch("Test_MH3/.*::test \\(3 bytes\\) made not entrant") @@ -191,7 +191,7 @@ public abstract class TestConstantsInError implements OutputProcessor { results.shouldMatch("Test_MT1/.*::test \\(3 bytes\\)$") .shouldMatch("Test_MT2/.*::test \\(3 bytes\\)$"); - if (isC1 && Platform.isAArch64()) { // no code patching + if (isC1 && (Platform.isAArch64() || Platform.isRISCV64())) { // no code patching results.shouldMatch("Test_MT1/.*::test \\(3 bytes\\) made not entrant") .shouldMatch("Test_MT2/.*::test \\(3 bytes\\) made not entrant"); } else { @@ -235,7 +235,7 @@ public abstract class TestConstantsInError implements OutputProcessor { .shouldMatch("Test_CD3.*::test \\(3 bytes\\)$") .shouldMatch("Test_CD4.*::test \\(3 bytes\\)$"); - if (isC1 && Platform.isAArch64()) { // no code patching + if (isC1 && (Platform.isAArch64() || Platform.isRISCV64())) { // no code patching results.shouldMatch("Test_CD1.*::test \\(3 bytes\\) made not entrant") .shouldMatch("Test_CD2.*::test \\(3 bytes\\) made not entrant") .shouldMatch("Test_CD3.*::test \\(3 bytes\\) made not entrant") diff --git a/test/hotspot/jtreg/compiler/types/TestSubTypeCheckMacroTrichotomy.java b/test/hotspot/jtreg/compiler/types/TestSubTypeCheckMacroTrichotomy.java index 54a5a0fc945..ef31bd30bb6 100644 --- a/test/hotspot/jtreg/compiler/types/TestSubTypeCheckMacroTrichotomy.java +++ b/test/hotspot/jtreg/compiler/types/TestSubTypeCheckMacroTrichotomy.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, Red Hat, Inc. All rights reserved. + * 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 @@ -24,10 +25,15 @@ /** * @test * @bug 8253566 + * @bug 8295414 * @summary clazz.isAssignableFrom will return false for interface implementors * @requires vm.compiler2.enabled * * @run main/othervm -XX:-BackgroundCompilation TestSubTypeCheckMacroTrichotomy + * @run main/othervm -XX:-BackgroundCompilation + * -XX:+IgnoreUnrecognizedVMOptions -XX:+StressReflectiveCode + * -XX:+UnlockDiagnosticVMOptions -XX:+ExpandSubTypeCheckAtParseTime + * -XX:-TieredCompilation -XX:CompileThreshold=100 TestSubTypeCheckMacroTrichotomy * */ diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index bf84a90602a..dc167492272 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -227,7 +227,6 @@ java/awt/print/Headless/HeadlessPrinterJob.java 8196088 windows-all sun/awt/datatransfer/SuplementaryCharactersTransferTest.java 8011371 generic-all sun/awt/shell/ShellFolderMemoryLeak.java 8197794 windows-all sun/java2d/DirectX/MultiPaintEventTest/MultiPaintEventTest.java 8284825 windows-all -sun/java2d/DirectX/OnScreenRenderingResizeTest/OnScreenRenderingResizeTest.java 8022403 generic-all sun/java2d/DirectX/OverriddenInsetsTest/OverriddenInsetsTest.java 8196102 generic-all sun/java2d/DirectX/RenderingToCachedGraphicsTest/RenderingToCachedGraphicsTest.java 8196180 windows-all,macosx-all sun/java2d/SunGraphics2D/EmptyClipRenderingTest.java 8144029 macosx-all,linux-all diff --git a/test/jdk/java/lang/ProcessBuilder/SecurityManagerClinit.java b/test/jdk/java/lang/ProcessBuilder/SecurityManagerClinit.java index 1aa56c9b728..068acad0ed0 100644 --- a/test/jdk/java/lang/ProcessBuilder/SecurityManagerClinit.java +++ b/test/jdk/java/lang/ProcessBuilder/SecurityManagerClinit.java @@ -24,7 +24,7 @@ /* * @test - * @bug 6980747 + * @bug 6980747 8297451 * @summary Check that Process-related classes have the proper * doPrivileged blocks, and can be initialized with an adversarial * security manager. @@ -52,6 +52,17 @@ public class SecurityManagerClinit { } } + // Security manager that unconditionally performs Thread Modify Access checks. + @SuppressWarnings("removal") + private static class TMACSecurityManager extends SecurityManager { + static final RuntimePermission MODIFY_THREAD_PERMISSION = + new RuntimePermission("modifyThread"); + @Override + public void checkAccess(Thread thread) { + checkPermission(MODIFY_THREAD_PERMISSION); + } + } + public static void main(String[] args) throws Throwable { String javaExe = System.getProperty("java.home") + @@ -60,10 +71,11 @@ public class SecurityManagerClinit { final SimplePolicy policy = new SimplePolicy (new FilePermission("<>", "execute"), - new RuntimePermission("setSecurityManager")); + new RuntimePermission("setSecurityManager"), + new RuntimePermission("modifyThread")); Policy.setPolicy(policy); - System.setSecurityManager(new SecurityManager()); + System.setSecurityManager(new TMACSecurityManager()); try { String[] cmd = { javaExe, "-version" }; diff --git a/test/jdk/java/lang/reflect/PublicMethods/PublicMethodsTest.java b/test/jdk/java/lang/reflect/PublicMethods/PublicMethodsTest.java index 507a94c6a3f..3d156a3399a 100644 --- a/test/jdk/java/lang/reflect/PublicMethods/PublicMethodsTest.java +++ b/test/jdk/java/lang/reflect/PublicMethods/PublicMethodsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,7 +60,7 @@ import static java.util.stream.Collectors.toMap; * @modules jdk.compiler * jdk.zipfs * @summary Nearly exhaustive test of Class.getMethod() and Class.getMethods() - * @run main PublicMethodsTest + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies PublicMethodsTest */ public class PublicMethodsTest { diff --git a/test/jdk/sun/java2d/DirectX/OnScreenRenderingResizeTest/OnScreenRenderingResizeTest.java b/test/jdk/sun/java2d/DirectX/OnScreenRenderingResizeTest/OnScreenRenderingResizeTest.java index b57d8b4a684..1015567357c 100644 --- a/test/jdk/sun/java2d/DirectX/OnScreenRenderingResizeTest/OnScreenRenderingResizeTest.java +++ b/test/jdk/sun/java2d/DirectX/OnScreenRenderingResizeTest/OnScreenRenderingResizeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,25 +25,21 @@ * @key headful * @bug 6664068 6666931 * @summary Tests that resizing a window to which a tight loop is rendering - * doesn't produce artifacts or crashes - * @author Dmitri.Trembovetski@sun.com: area=Graphics + * doesn't produce artifacts or crashes * @run main/othervm OnScreenRenderingResizeTest * @run main/othervm -Dsun.java2d.d3d=false OnScreenRenderingResizeTest */ import java.awt.AWTException; import java.awt.Color; -import java.awt.EventQueue; import java.awt.Frame; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; -import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; import java.awt.Robot; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; +import java.awt.EventQueue; import java.awt.image.BufferedImage; import java.awt.image.VolatileImage; import java.io.File; @@ -52,19 +48,33 @@ import javax.imageio.ImageIO; public class OnScreenRenderingResizeTest { - private static volatile boolean done = false; private static volatile boolean nocheck = false; - private static final int FRAME_W = 256; - private static final int FRAME_H = 256; - private static final int IMAGE_W = 128; - private static final int IMAGE_H = 128; + private static int FRAME_W; + private static int FRAME_H; + private static int IMAGE_W; + private static int IMAGE_H; + private static final int tolerance = 12; private static long RUN_TIME = 1000*20; private static final Color renderColor = Color.green; private static final Color bgColor = Color.white; - public static void main(String[] args) { + private static Frame frame; + + private static void createAndShowGUI() { + frame = new Frame() { + public void paint(Graphics g) {} + public void update(Graphics g) {} + }; + frame.setBackground(bgColor); + frame.setUndecorated(true); + frame.setAlwaysOnTop(true); + frame.pack(); + frame.setVisible(true); + } + + public static void main(String[] args) throws Exception { for (String arg : args) { if ("-inf".equals(arg)) { @@ -74,126 +84,138 @@ public class OnScreenRenderingResizeTest { System.err.println("Test will not check rendering results"); nocheck = true; } else { - System.err.println("Usage: OnScreenRenderingResizeTest [-inf][-nocheck]"); + System.err.println("Usage: OnScreenRenderingResizeTest" + + " [-inf][-nocheck]"); } } - BufferedImage output = - new BufferedImage(IMAGE_W, IMAGE_H, BufferedImage.TYPE_INT_RGB); - output.setAccelerationPriority(0.0f); - Graphics g = output.getGraphics(); - g.setColor(renderColor); - g.fillRect(0, 0, output.getWidth(), output.getHeight()); - - final Frame frame = new Frame("OnScreenRenderingResizeTest") { - public void paint(Graphics g) {} - public void update(Graphics g) {} - }; - frame.setBackground(bgColor); - frame.setUndecorated(true); - frame.pack(); - - GraphicsConfiguration gc = frame.getGraphicsConfiguration(); - Rectangle gcBounds = gc.getBounds(); - frame.setBounds(gcBounds.width / 4, gcBounds.height / 4, FRAME_W, FRAME_H); - - frame.addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent e) { - done = true; - } - }); try { EventQueue.invokeAndWait(new Runnable() { public void run() { - frame.setVisible(true); + createAndShowGUI(); } }); - // wait for Vista's effects to complete Thread.sleep(2000); } catch (Exception ex) { ex.printStackTrace(); } - int maxW = gcBounds.width /2; - int maxH = gcBounds.height/2; - int minW = frame.getWidth(); - int minH = frame.getHeight(); - int incW = 10, incH = 10, cnt = 0; - Robot robot = null; - if (!nocheck && gc.getColorModel().getPixelSize() > 8) { - try { - robot = new Robot(); - } catch (AWTException ex) { - System.err.println("Robot creation failed, continuing."); - } - } else { - System.err.println("No screen rendering checks."); - } + try { + GraphicsConfiguration gc = frame.getGraphicsConfiguration(); + Rectangle gcBounds = gc.getBounds(); + FRAME_W = (gcBounds.width / 4); + FRAME_H = (gcBounds.height / 4); + IMAGE_W = (gcBounds.width / 8); + IMAGE_H = (gcBounds.height / 8); + frame.setBounds(gcBounds.width / 4, gcBounds.height / 4, + FRAME_W, FRAME_H); - VolatileImage vi = gc.createCompatibleVolatileImage(512, 512); - vi.validate(gc); + BufferedImage output = + new BufferedImage(IMAGE_W, IMAGE_H, + BufferedImage.TYPE_INT_RGB); + output.setAccelerationPriority(0.0f); + Graphics g = output.getGraphics(); + g.setColor(renderColor); + g.fillRect(0, 0, IMAGE_W, IMAGE_H); - long timeStarted = System.currentTimeMillis(); - while (!done && (System.currentTimeMillis() - timeStarted) < RUN_TIME) { - - if (++cnt > 100) { - int w = frame.getWidth() + incW; - int h = frame.getHeight() + incH; - if (w < minW || w > maxW ) { - incW = -incW; + int maxW = gcBounds.width / 2; + int maxH = gcBounds.height / 2; + int minW = FRAME_W; + int minH = FRAME_H; + int incW = 10, incH = 10, cnt = 0; + Robot robot = null; + if (!nocheck && gc.getColorModel().getPixelSize() > 8) { + try { + robot = new Robot(); + robot.setAutoDelay(100); + robot.mouseMove(0,0); + } catch (AWTException ex) { + System.err.println("Robot creation failed, continuing."); } - if (h < minH || h > maxH ) { - incH = -incH; - } - frame.setSize(w, h); - cnt = 0; + } else { + System.err.println("No screen rendering checks."); } - - // try to put the device into non-default state, for example, - // this operation below will set the transform + VolatileImage vi = gc. + createCompatibleVolatileImage(IMAGE_W, IMAGE_H); vi.validate(gc); - Graphics2D vig = (Graphics2D)vi.getGraphics(); - vig.rotate(30.0f, vi.getWidth()/2, vi.getHeight()/2); - vig.drawImage(output, 0, 0, - vi.getWidth(), vi.getHeight(), null); + long timeStarted = System.currentTimeMillis(); + while ((System.currentTimeMillis() - timeStarted) < RUN_TIME) { - Insets in = frame.getInsets(); - frame.getGraphics().drawImage(output, in.left, in.top, null); - if (cnt == 90 && robot != null) { - robot.waitForIdle(); - // area where we blitted to should be either white or green - Point p = frame.getLocationOnScreen(); - p.translate(in.left+10, in.top+10); - BufferedImage bi = - robot.createScreenCapture( - new Rectangle(p.x, p.y, IMAGE_W/2, IMAGE_H/2)); - int accepted1[] = { Color.white.getRGB(), Color.green.getRGB()}; - checkBI(bi, accepted1); + if (++cnt > 100) { + int w = frame.getWidth() + incW; + int h = frame.getHeight() + incH; + if (w < minW || w > maxW ) { + incW = -incW; + } + if (h < minH || h > maxH ) { + incH = -incH; + } + frame.setSize(w, h); + if (robot != null) { + robot.waitForIdle(); + } + cnt = 0; + } + // try to put the device into non-default state, for example, + // this operation below will set the transform + vi.validate(gc); + Graphics2D vig = (Graphics2D)vi.getGraphics(); + vig.rotate(30.0f, IMAGE_W/2, IMAGE_H/2); + vig.drawImage(output, 0, 0, + IMAGE_W, IMAGE_H, null); - // the are where we didn't render should stay white - p = frame.getLocationOnScreen(); - p.translate(in.left, in.top+IMAGE_H+5); - bi = robot.createScreenCapture( - new Rectangle(p.x, p.y, - frame.getWidth()-in.left-in.right, - frame.getHeight()-in.top-in.bottom-5-IMAGE_H)); - int accepted2[] = { Color.white.getRGB() }; - checkBI(bi, accepted2); + frame.getGraphics(). + drawImage(output, 0, 0, null); + if (cnt == 90 && robot != null) { + robot.waitForIdle(); + // area where we blit and should be either white or green + Point p = frame.getLocationOnScreen(); + p.translate(10, 10); + BufferedImage bi = + robot.createScreenCapture( + new Rectangle(p.x, p.y, + (IMAGE_W / 2), (IMAGE_H / 2))); + int accepted1[] = {Color.white.getRGB(), + Color.green.getRGB()}; + checkBI(bi, accepted1); + + // the area where we didn't render should stay white + robot.waitForIdle(); + p = frame.getLocationOnScreen(); + p.translate(10, IMAGE_H + 10); + bi = robot.createScreenCapture( + new Rectangle(p.x, p.y, + frame.getWidth() - 20, + frame.getHeight() - 20 - (IMAGE_H))); + int accepted2[] = { Color.white.getRGB() }; + checkBI(bi, accepted2); + } + Thread.yield(); } - - Thread.yield(); + } finally { + frame.dispose(); } - frame.dispose(); System.out.println("Test Passed"); } private static void checkBI(BufferedImage bi, int accepted[]) { for (int x = 0; x < bi.getWidth(); x++) { for (int y = 0; y < bi.getHeight(); y++) { - int pix = bi.getRGB(x, y); + int actual = bi.getRGB(x, y); + int alpha = (actual >> 24) & 0xFF; + int red = (actual >> 16) & 0xFF; + int green = (actual >> 8) & 0xFF; + int blue = (actual) & 0xFF; boolean found = false; for (int acc : accepted) { - if (pix == acc) { + int accAlpha = (acc >> 24) & 0xFF; + int accRed = (acc >> 16) & 0xFF; + int accGreen = (acc >> 8) & 0xFF; + int accBlue = (acc) & 0xFF; + if (!(Math.abs(alpha - accAlpha) > tolerance || + Math.abs(red - accRed) > tolerance || + Math.abs(green - accGreen) > tolerance || + Math.abs(blue - accBlue) > tolerance)) { found = true; break; } @@ -204,10 +226,10 @@ public class OnScreenRenderingResizeTest { ImageIO.write(bi, "png", new File(name)); System.out.println("Screen shot file: " + name); } catch (IOException ex) {} - throw new RuntimeException("Test failed at " + x + "-" + y + - " rgb=0x" + Integer.toHexString(pix)); + " rgb=0x" + Integer. + toHexString(actual)); } } } diff --git a/test/jdk/sun/java2d/cmm/ColorConvertOp/UnexpectedSourceImageSize.java b/test/jdk/sun/java2d/cmm/ColorConvertOp/UnexpectedSourceImageSize.java index 4d7590f8171..a1912f71dbd 100644 --- a/test/jdk/sun/java2d/cmm/ColorConvertOp/UnexpectedSourceImageSize.java +++ b/test/jdk/sun/java2d/cmm/ColorConvertOp/UnexpectedSourceImageSize.java @@ -44,6 +44,7 @@ import static java.awt.image.BufferedImage.TYPE_USHORT_GRAY; * @test * @bug 8264666 * @summary No exception or errors should occur in ColorConvertOp.filter(). + * @run main/othervm/timeout=600 UnexpectedSourceImageSize */ public final class UnexpectedSourceImageSize {