--- a/hotspot/src/share/vm/opto/escape.cpp Thu Feb 09 18:01:20 2012 -0800
+++ b/hotspot/src/share/vm/opto/escape.cpp Fri Feb 10 12:53:43 2012 -0800
@@ -1,5 +1,5 @@
/*
- * 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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1687,12 +1687,23 @@
// Observed 8 passes in jvm2008 compiler.compiler.
// Set limit to 20 to catch situation when something
// 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
+#ifdef ASSERT
+#define CG_BUILD_TIME_LIMIT 60.0
+#else
+#define CG_BUILD_TIME_LIMIT 30.0
+#endif
+
uint length = worklist.length();
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;
for( uint next = 0; next < length; ++next ) {
int ni = worklist.at(next);
@@ -1701,18 +1712,19 @@
assert(n != NULL, "should be known node");
build_connection_graph(n, igvn);
}
+ time.stop();
}
- if (iterations >= CG_BUILD_ITER_LIMIT) {
- assert(iterations < CG_BUILD_ITER_LIMIT,
- err_msg("infinite EA connection graph build with %d nodes and worklist size %d",
- nodes_size(), length));
+ if ((iterations >= CG_BUILD_ITER_LIMIT) ||
+ (time.seconds() >= CG_BUILD_TIME_LIMIT)) {
+ assert(false, err_msg("infinite EA connection graph build (%f sec, %d iterations) with %d nodes and worklist size %d",
+ time.seconds(), iterations, nodes_size(), length));
// Possible infinite build_connection_graph loop,
- // retry compilation without escape analysis.
- C->record_failure(C2Compiler::retry_no_escape_analysis());
+ // bailout (no changes to ideal graph were made).
_collecting = false;
return false;
}
#undef CG_BUILD_ITER_LIMIT
+#undef CG_BUILD_TIME_LIMIT
// 5. Propagate escaped states.
worklist.clear();
@@ -2292,9 +2304,35 @@
PointsToNode::EscapeState arg_esc = ptnode_adr(arg->_idx)->escape_state();
if (!arg->is_top() && at->isa_ptr() && aat->isa_ptr() &&
(is_arraycopy || arg_esc < PointsToNode::ArgEscape)) {
-
+#ifdef ASSERT
assert(aat == Type::TOP || aat == TypePtr::NULL_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() &&
(aat->isa_oopptr()->klass() == NULL || aat->isa_instptr() ||
(aat->isa_aryptr() && aat->isa_aryptr()->klass()->is_obj_array_klass()));
@@ -2307,85 +2345,33 @@
// arraycopy(char[],0,Object*,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 &&
- arg_has_oops && (i > TypeFunc::Parms);
-#ifdef ASSERT
- 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
- // Always process arraycopy's destination object since
- // we need to add all possible edges to references in
- // source object.
- if (arg_esc >= PointsToNode::ArgEscape &&
- !arg_is_arraycopy_dest) {
- continue;
- }
- 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);
- }
- 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);
- }
- }
+ if (is_arraycopy && (i > TypeFunc::Parms) &&
+ src_has_oops && arg_has_oops) {
+ // Destination object's fields reference an unknown object.
+ Node* arg_base = arg;
+ if (arg->is_AddP()) {
+ arg_base = get_addp_base(arg);
+ }
+ for (VectorSetI s(PointsTo(arg_base)); s.test(); ++s) {
+ uint ps = s.elem;
+ set_escape_state(ps, PointsToNode::ArgEscape);
+ add_edge_from_fields(ps, _phantom_object, Type::OffsetBot);
+ }
+ // Conservatively all values in source object fields globally escape
+ // since we don't know if values in destination object fields
+ // escape (it could be traced but it is too expensive).
+ Node* src = call->in(TypeFunc::Parms)->uncast();
+ Node* src_base = src;
+ if (src->is_AddP()) {
+ src_base = get_addp_base(src);
+ }
+ for (VectorSetI s(PointsTo(src_base)); s.test(); ++s) {
+ uint ps = s.elem;
+ set_escape_state(ps, PointsToNode::ArgEscape);
+ // Use OffsetTop to indicate fields global escape.
+ add_edge_from_fields(ps, _phantom_object, Type::OffsetTop);
}
}
}