提交 b55e5313 编写于 作者: K kvn

7129284: +DoEscapeAnalysis regression w/ early build of 7u4 (HotSpot 23) on Linux

Summary: Removed code which tried to create edges from fields of destination objects of arraycopy to fields of source objects. Added 30 sec time limit for EA graph construction.
Reviewed-by: never
上级 0f222ff2
/* /*
* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -1687,12 +1687,23 @@ bool ConnectionGraph::compute_escape() { ...@@ -1687,12 +1687,23 @@ bool ConnectionGraph::compute_escape() {
// Observed 8 passes in jvm2008 compiler.compiler. // Observed 8 passes in jvm2008 compiler.compiler.
// Set limit to 20 to catch situation when something // Set limit to 20 to catch situation when something
// did go wrong and recompile the method without EA. // did go wrong and recompile the method without EA.
// Also limit build time to 30 sec (60 in debug VM).
#define CG_BUILD_ITER_LIMIT 20 #define CG_BUILD_ITER_LIMIT 20
#ifdef ASSERT
#define CG_BUILD_TIME_LIMIT 60.0
#else
#define CG_BUILD_TIME_LIMIT 30.0
#endif
uint length = worklist.length(); uint length = worklist.length();
int iterations = 0; int iterations = 0;
while(_progress && (iterations++ < CG_BUILD_ITER_LIMIT)) { elapsedTimer time;
while(_progress &&
(iterations++ < CG_BUILD_ITER_LIMIT) &&
(time.seconds() < CG_BUILD_TIME_LIMIT)) {
time.start();
_progress = false; _progress = false;
for( uint next = 0; next < length; ++next ) { for( uint next = 0; next < length; ++next ) {
int ni = worklist.at(next); int ni = worklist.at(next);
...@@ -1701,18 +1712,19 @@ bool ConnectionGraph::compute_escape() { ...@@ -1701,18 +1712,19 @@ bool ConnectionGraph::compute_escape() {
assert(n != NULL, "should be known node"); assert(n != NULL, "should be known node");
build_connection_graph(n, igvn); build_connection_graph(n, igvn);
} }
time.stop();
} }
if (iterations >= CG_BUILD_ITER_LIMIT) { if ((iterations >= CG_BUILD_ITER_LIMIT) ||
assert(iterations < CG_BUILD_ITER_LIMIT, (time.seconds() >= CG_BUILD_TIME_LIMIT)) {
err_msg("infinite EA connection graph build with %d nodes and worklist size %d", assert(false, err_msg("infinite EA connection graph build (%f sec, %d iterations) with %d nodes and worklist size %d",
nodes_size(), length)); time.seconds(), iterations, nodes_size(), length));
// Possible infinite build_connection_graph loop, // Possible infinite build_connection_graph loop,
// retry compilation without escape analysis. // bailout (no changes to ideal graph were made).
C->record_failure(C2Compiler::retry_no_escape_analysis());
_collecting = false; _collecting = false;
return false; return false;
} }
#undef CG_BUILD_ITER_LIMIT #undef CG_BUILD_ITER_LIMIT
#undef CG_BUILD_TIME_LIMIT
// 5. Propagate escaped states. // 5. Propagate escaped states.
worklist.clear(); worklist.clear();
...@@ -2292,9 +2304,35 @@ void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *pha ...@@ -2292,9 +2304,35 @@ void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *pha
PointsToNode::EscapeState arg_esc = ptnode_adr(arg->_idx)->escape_state(); PointsToNode::EscapeState arg_esc = ptnode_adr(arg->_idx)->escape_state();
if (!arg->is_top() && at->isa_ptr() && aat->isa_ptr() && if (!arg->is_top() && at->isa_ptr() && aat->isa_ptr() &&
(is_arraycopy || arg_esc < PointsToNode::ArgEscape)) { (is_arraycopy || arg_esc < PointsToNode::ArgEscape)) {
#ifdef ASSERT
assert(aat == Type::TOP || aat == TypePtr::NULL_PTR || assert(aat == Type::TOP || aat == TypePtr::NULL_PTR ||
aat->isa_ptr() != NULL, "expecting an Ptr"); aat->isa_ptr() != NULL, "expecting an Ptr");
if (!(is_arraycopy ||
call->as_CallLeaf()->_name != NULL &&
(strcmp(call->as_CallLeaf()->_name, "g1_wb_pre") == 0 ||
strcmp(call->as_CallLeaf()->_name, "g1_wb_post") == 0 ))
) {
call->dump();
assert(false, "EA: unexpected CallLeaf");
}
#endif
if (arg_esc < PointsToNode::ArgEscape) {
set_escape_state(arg->_idx, PointsToNode::ArgEscape);
Node* arg_base = arg;
if (arg->is_AddP()) {
//
// The inline_native_clone() case when the arraycopy stub is called
// after the allocation before Initialize and CheckCastPP nodes.
// Or normal arraycopy for object arrays case.
//
// Set AddP's base (Allocate) as not scalar replaceable since
// pointer to the base (with offset) is passed as argument.
//
arg_base = get_addp_base(arg);
set_escape_state(arg_base->_idx, PointsToNode::ArgEscape);
}
}
bool arg_has_oops = aat->isa_oopptr() && bool arg_has_oops = aat->isa_oopptr() &&
(aat->isa_oopptr()->klass() == NULL || aat->isa_instptr() || (aat->isa_oopptr()->klass() == NULL || aat->isa_instptr() ||
(aat->isa_aryptr() && aat->isa_aryptr()->klass()->is_obj_array_klass())); (aat->isa_aryptr() && aat->isa_aryptr()->klass()->is_obj_array_klass()));
...@@ -2307,85 +2345,33 @@ void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *pha ...@@ -2307,85 +2345,33 @@ void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *pha
// arraycopy(char[],0,Object*,0,size); // arraycopy(char[],0,Object*,0,size);
// arraycopy(Object*,0,char[],0,size); // arraycopy(Object*,0,char[],0,size);
// //
// Don't add edges from dst's fields in such cases. // Do nothing special in such cases.
// //
bool arg_is_arraycopy_dest = src_has_oops && is_arraycopy && if (is_arraycopy && (i > TypeFunc::Parms) &&
arg_has_oops && (i > TypeFunc::Parms); src_has_oops && arg_has_oops) {
#ifdef ASSERT // Destination object's fields reference an unknown object.
if (!(is_arraycopy || Node* arg_base = arg;
call->as_CallLeaf()->_name != NULL && if (arg->is_AddP()) {
(strcmp(call->as_CallLeaf()->_name, "g1_wb_pre") == 0 || arg_base = get_addp_base(arg);
strcmp(call->as_CallLeaf()->_name, "g1_wb_post") == 0 )) }
) { for (VectorSetI s(PointsTo(arg_base)); s.test(); ++s) {
call->dump(); uint ps = s.elem;
assert(false, "EA: unexpected CallLeaf"); set_escape_state(ps, PointsToNode::ArgEscape);
} add_edge_from_fields(ps, _phantom_object, Type::OffsetBot);
#endif }
// Always process arraycopy's destination object since // Conservatively all values in source object fields globally escape
// we need to add all possible edges to references in // since we don't know if values in destination object fields
// source object. // escape (it could be traced but it is too expensive).
if (arg_esc >= PointsToNode::ArgEscape && Node* src = call->in(TypeFunc::Parms)->uncast();
!arg_is_arraycopy_dest) { Node* src_base = src;
continue; if (src->is_AddP()) {
} src_base = get_addp_base(src);
set_escape_state(arg->_idx, PointsToNode::ArgEscape); }
Node* arg_base = arg; for (VectorSetI s(PointsTo(src_base)); s.test(); ++s) {
if (arg->is_AddP()) { uint ps = s.elem;
// set_escape_state(ps, PointsToNode::ArgEscape);
// The inline_native_clone() case when the arraycopy stub is called // Use OffsetTop to indicate fields global escape.
// after the allocation before Initialize and CheckCastPP nodes. add_edge_from_fields(ps, _phantom_object, Type::OffsetTop);
// Or normal arraycopy for object arrays case.
//
// Set AddP's base (Allocate) as not scalar replaceable since
// pointer to the base (with offset) is passed as argument.
//
arg_base = get_addp_base(arg);
}
VectorSet argset = *PointsTo(arg_base); // Clone set
for( VectorSetI j(&argset); j.test(); ++j ) {
uint pd = j.elem; // Destination object
set_escape_state(pd, PointsToNode::ArgEscape);
if (arg_is_arraycopy_dest) {
PointsToNode* ptd = ptnode_adr(pd);
// Conservatively reference an unknown object since
// not all source's fields/elements may be known.
add_edge_from_fields(pd, _phantom_object, Type::OffsetBot);
Node *src = call->in(TypeFunc::Parms)->uncast();
Node* src_base = src;
if (src->is_AddP()) {
src_base = get_addp_base(src);
}
// Create edges from destination's fields to
// everything known source's fields could point to.
for( VectorSetI s(PointsTo(src_base)); s.test(); ++s ) {
uint ps = s.elem;
bool has_bottom_offset = false;
for (uint fd = 0; fd < ptd->edge_count(); fd++) {
assert(ptd->edge_type(fd) == PointsToNode::FieldEdge, "expecting a field edge");
int fdi = ptd->edge_target(fd);
PointsToNode* pfd = ptnode_adr(fdi);
int offset = pfd->offset();
if (offset == Type::OffsetBot)
has_bottom_offset = true;
assert(offset != -1, "offset should be set");
add_deferred_edge_to_fields(fdi, ps, offset);
}
// Destination object may not have access (no field edge)
// to fields which are accessed in source object.
// As result no edges will be created to those source's
// fields and escape state of destination object will
// not be propagated to those fields.
//
// Mark source object as global escape except in
// the case with Type::OffsetBot field (which is
// common case for array elements access) when
// edges are created to all source's fields.
if (!has_bottom_offset) {
set_escape_state(ps, PointsToNode::GlobalEscape);
}
}
} }
} }
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册