This commit is contained in:
robm 2022-11-30 17:57:00 +00:00
commit 1d3871afcd
35 changed files with 615 additions and 255 deletions

View File

@ -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 %{ %}

View File

@ -3208,6 +3208,7 @@ operand iRegP()
match(RegP);
match(iRegPNoSp);
match(iRegP_R10);
match(iRegP_R15);
match(javaThread_RegP);
op_cost(0);
format %{ %}

View File

@ -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) {

View File

@ -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(

View File

@ -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);
}

View File

@ -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

View File

@ -66,6 +66,7 @@ private:
public:
ShenandoahFullGC();
~ShenandoahFullGC();
bool collect(GCCause::Cause cause);
private:

View File

@ -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.

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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<JavaObjectNode*> 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<JavaObjectNode*>& 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<PointsToNode*>& ptnodes_worklist,

View File

@ -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<JavaObjectNode*>& jobj_worklist);
// Optimize ideal graph.
void optimize_ideal_graph(GrowableArray<Node*>& ptr_cmp_worklist,
GrowableArray<MemBarStoreStoreNode*>& storestore_worklist);

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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();

View File

@ -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 <Node *> trstack(C->live_nodes() >> 1);
trstack.push(new_node); // Process children of cloned node
GrowableArray <Node *> 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;
}

View File

@ -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 );

View File

@ -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 ");

View File

@ -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);
}

View File

@ -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);

View File

@ -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<Void>) () -> {
thread.setName(name);
return null;
});
}
@SuppressWarnings("removal")
private static void privilegedThreadSetDaemon(Thread thread, boolean on) {
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
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);
}
}
});

View File

@ -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())
/*

View File

@ -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);
}
}

View File

@ -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();
}
}
}

View File

@ -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;
}
}

View File

@ -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.");
}
}

View File

@ -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")

View File

@ -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
*
*/

View File

@ -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

View File

@ -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("<<ALL FILES>>", "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" };

View File

@ -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 {

View File

@ -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));
}
}
}

View File

@ -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 {