aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Vladimir Kozlov <kvn@openjdk.org> 2021-03-24 15:31:13 +0000
committerGravatar Vladimir Kozlov <kvn@openjdk.org> 2021-03-24 15:31:13 +0000
commit57c3f271d3f04873c3d1f6470c5fda6de1a759fc (patch)
tree0ed77f1e30b885a60a5be842d0710b2ed946b938
parent4d8e9860e25727f28037da0f7f5caf349187af88 (diff)
downloadjdk-57c3f271d3f04873c3d1f6470c5fda6de1a759fc.tar.gz
jdk-57c3f271d3f04873c3d1f6470c5fda6de1a759fc.zip
8263989: Cleanup in EA
Reviewed-by: vlivanov, neliasso
-rw-r--r--src/hotspot/share/ci/bcEscapeAnalyzer.cpp4
-rw-r--r--src/hotspot/share/ci/bcEscapeAnalyzer.hpp4
-rw-r--r--src/hotspot/share/opto/callnode.cpp4
-rw-r--r--src/hotspot/share/opto/escape.cpp367
-rw-r--r--src/hotspot/share/opto/escape.hpp60
5 files changed, 248 insertions, 191 deletions
diff --git a/src/hotspot/share/ci/bcEscapeAnalyzer.cpp b/src/hotspot/share/ci/bcEscapeAnalyzer.cpp
index dfd998e9c3d..aba920f6c78 100644
--- a/src/hotspot/share/ci/bcEscapeAnalyzer.cpp
+++ b/src/hotspot/share/ci/bcEscapeAnalyzer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2021, 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
@@ -276,7 +276,7 @@ void BCEscapeAnalyzer::invoke(StateInfo &state, Bytecodes::Code code, ciMethod*
// direct recursive calls are skipped if they can be bound statically without introducing
// dependencies and if parameters are passed at the same position as in the current method
- // other calls are skipped if there are no unescaped arguments passed to them
+ // other calls are skipped if there are no non-escaped arguments passed to them
bool directly_recursive = (method() == target) &&
(code != Bytecodes::_invokevirtual || target->is_final_method() || state._stack[arg_base] .is_empty());
diff --git a/src/hotspot/share/ci/bcEscapeAnalyzer.hpp b/src/hotspot/share/ci/bcEscapeAnalyzer.hpp
index 4b377b99938..1dd1e13d29b 100644
--- a/src/hotspot/share/ci/bcEscapeAnalyzer.hpp
+++ b/src/hotspot/share/ci/bcEscapeAnalyzer.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2021, 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
@@ -139,7 +139,7 @@ class BCEscapeAnalyzer : public ResourceObj {
return !_conservative && _return_local;
}
- // True iff only newly allocated unescaped objects are returned.
+ // True iff only newly allocated non-escaped objects are returned.
bool is_return_allocated() const {
return !_conservative && _return_allocated && !_allocated_escapes;
}
diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp
index 4aa60c355d6..86eaa4d8f96 100644
--- a/src/hotspot/share/opto/callnode.cpp
+++ b/src/hotspot/share/opto/callnode.cpp
@@ -2058,7 +2058,7 @@ Node *LockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
// one computed above.
if (can_reshape && EliminateLocks && !is_non_esc_obj()) {
//
- // If we are locking an unescaped object, the lock/unlock is unnecessary
+ // If we are locking an non-escaped object, the lock/unlock is unnecessary
//
ConnectionGraph *cgr = phase->C->congraph();
if (cgr != NULL && cgr->not_global_escape(obj_node())) {
@@ -2226,7 +2226,7 @@ Node *UnlockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
// Escape state is defined after Parse phase.
if (can_reshape && EliminateLocks && !is_non_esc_obj()) {
//
- // If we are unlocking an unescaped object, the lock/unlock is unnecessary.
+ // If we are unlocking an non-escaped object, the lock/unlock is unnecessary.
//
ConnectionGraph *cgr = phase->C->congraph();
if (cgr != NULL && cgr->not_global_escape(obj_node())) {
diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp
index 3000dd615cb..9b5c7113471 100644
--- a/src/hotspot/share/opto/escape.cpp
+++ b/src/hotspot/share/opto/escape.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2021, 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
@@ -63,8 +63,6 @@ ConnectionGraph::ConnectionGraph(Compile * C, PhaseIterGVN *igvn) :
assert(noop_null->_idx < nodes_size(), "should be created already");
map_ideal_node(noop_null, null_obj);
}
- _pcmp_neq = NULL; // Should be initialized
- _pcmp_eq = NULL;
}
bool ConnectionGraph::has_candidates(Compile *C) {
@@ -73,12 +71,14 @@ bool ConnectionGraph::has_candidates(Compile *C) {
int cnt = C->macro_count();
for (int i = 0; i < cnt; i++) {
Node *n = C->macro_node(i);
- if (n->is_Allocate())
+ if (n->is_Allocate()) {
return true;
+ }
if (n->is_Lock()) {
Node* obj = n->as_Lock()->obj_node()->uncast();
- if (!(obj->is_Parm() || obj->is_Con()))
+ if (!(obj->is_Parm() || obj->is_Con())) {
return true;
+ }
}
if (n->is_CallStaticJava() &&
n->as_CallStaticJava()->is_boxing_method()) {
@@ -103,10 +103,12 @@ void ConnectionGraph::do_analysis(Compile *C, PhaseIterGVN *igvn) {
C->set_congraph(congraph);
}
// Cleanup.
- if (oop_null->outcnt() == 0)
+ if (oop_null->outcnt() == 0) {
igvn->hash_delete(oop_null);
- if (noop_null->outcnt() == 0)
+ }
+ if (noop_null->outcnt() == 0) {
igvn->hash_delete(noop_null);
+ }
}
bool ConnectionGraph::compute_escape() {
@@ -121,7 +123,7 @@ bool ConnectionGraph::compute_escape() {
GrowableArray<ArrayCopyNode*> arraycopy_worklist;
GrowableArray<PointsToNode*> ptnodes_worklist;
GrowableArray<JavaObjectNode*> java_objects_worklist;
- GrowableArray<JavaObjectNode*> non_escaped_worklist;
+ GrowableArray<JavaObjectNode*> non_escaped_allocs_worklist;
GrowableArray<FieldNode*> oop_fields_worklist;
GrowableArray<SafePointNode*> sfn_worklist;
DEBUG_ONLY( GrowableArray<Node*> addp_worklist; )
@@ -153,7 +155,7 @@ bool ConnectionGraph::compute_escape() {
if ((n->is_Allocate() || n->is_CallStaticJava()) &&
(ptn->escape_state() < PointsToNode::GlobalEscape)) {
// Only allocations and java static calls results are interesting.
- non_escaped_worklist.append(ptn->as_JavaObject());
+ non_escaped_allocs_worklist.append(ptn->as_JavaObject());
}
} else if (ptn->is_Field() && ptn->as_Field()->is_oop()) {
oop_fields_worklist.append(ptn->as_Field());
@@ -193,7 +195,7 @@ bool ConnectionGraph::compute_escape() {
sfn_worklist.append(n->as_SafePoint());
}
}
- if (non_escaped_worklist.length() == 0) {
+ if (non_escaped_allocs_worklist.length() == 0) {
_collecting = false;
return false; // Nothing to do.
}
@@ -202,13 +204,13 @@ bool ConnectionGraph::compute_escape() {
Node* n = delayed_worklist.pop();
add_final_edges(n);
}
- int ptnodes_length = ptnodes_worklist.length();
#ifdef ASSERT
if (VerifyConnectionGraph) {
// Verify that no new simple edges could be created and all
// local vars has edges.
_verify = true;
+ int ptnodes_length = ptnodes_worklist.length();
for (int next = 0; next < ptnodes_length; ++next) {
PointsToNode* ptn = ptnodes_worklist.at(next);
add_final_edges(ptn->ideal_node());
@@ -228,7 +230,7 @@ bool ConnectionGraph::compute_escape() {
// 2. Finish Graph construction by propagating references to all
// java objects through graph.
- if (!complete_connection_graph(ptnodes_worklist, non_escaped_worklist,
+ if (!complete_connection_graph(ptnodes_worklist, non_escaped_allocs_worklist,
java_objects_worklist, oop_fields_worklist)) {
// All objects escaped or hit time or iterations limits.
_collecting = false;
@@ -238,9 +240,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().
- int non_escaped_length = non_escaped_worklist.length();
+ int non_escaped_length = non_escaped_allocs_worklist.length();
for (int next = 0; next < non_escaped_length; next++) {
- JavaObjectNode* ptn = non_escaped_worklist.at(next);
+ JavaObjectNode* ptn = non_escaped_allocs_worklist.at(next);
bool noescape = (ptn->escape_state() == PointsToNode::NoEscape);
Node* n = ptn->ideal_node();
if (n->is_Allocate()) {
@@ -257,7 +259,7 @@ bool ConnectionGraph::compute_escape() {
#ifdef ASSERT
if (VerifyConnectionGraph) {
// Verify that graph is complete - no new edges could be added or needed.
- verify_connection_graph(ptnodes_worklist, non_escaped_worklist,
+ verify_connection_graph(ptnodes_worklist, non_escaped_allocs_worklist,
java_objects_worklist, addp_worklist);
}
assert(C->unique() == nodes_size(), "no new ideal nodes should be added during ConnectionGraph build");
@@ -272,7 +274,7 @@ bool ConnectionGraph::compute_escape() {
} // TracePhase t3("connectionGraph")
// 4. Optimize ideal graph based on EA information.
- bool has_non_escaping_obj = (non_escaped_worklist.length() > 0);
+ bool has_non_escaping_obj = (non_escaped_allocs_worklist.length() > 0);
if (has_non_escaping_obj) {
optimize_ideal_graph(ptr_cmp_worklist, storestore_worklist);
}
@@ -283,7 +285,6 @@ bool ConnectionGraph::compute_escape() {
}
#endif
- bool has_scalar_replaceable_candidates = (alloc_worklist.length() > 0);
#ifdef ASSERT
if (VerifyConnectionGraph) {
int alloc_length = alloc_worklist.length();
@@ -296,6 +297,7 @@ bool ConnectionGraph::compute_escape() {
#endif
// 5. Separate memory graph for scalar replaceable allcations.
+ bool has_scalar_replaceable_candidates = (alloc_worklist.length() > 0);
if (has_scalar_replaceable_candidates &&
C->AliasLevel() >= 3 && EliminateAllocations) {
// Now use the escape information to create unique types for
@@ -308,7 +310,7 @@ bool ConnectionGraph::compute_escape() {
} else if (Verbose && (PrintEscapeAnalysis || PrintEliminateAllocations)) {
tty->print("=== No allocations eliminated for ");
C->method()->print_short_name();
- if(!EliminateAllocations) {
+ if (!EliminateAllocations) {
tty->print(" since EliminateAllocations is off ===");
} else if(!has_scalar_replaceable_candidates) {
tty->print(" since there are no scalar replaceable candidates ===");
@@ -428,9 +430,9 @@ void ConnectionGraph::add_node_to_connection_graph(Node *n, Unique_Node_List *de
PhaseGVN* igvn = _igvn;
uint n_idx = n->_idx;
PointsToNode* n_ptn = ptnode_adr(n_idx);
- if (n_ptn != NULL)
+ if (n_ptn != NULL) {
return; // No need to redefine PointsTo node during first iteration.
-
+ }
int opcode = n->Opcode();
bool gc_handled = BarrierSet::barrier_set()->barrier_set_c2()->escape_add_to_con_graph(this, igvn, delayed_worklist, n, opcode);
if (gc_handled) {
@@ -449,8 +451,9 @@ void ConnectionGraph::add_node_to_connection_graph(Node *n, Unique_Node_List *de
} else {
if (n->is_CallStaticJava()) {
const char* name = n->as_CallStaticJava()->_name;
- if (name != NULL && strcmp(name, "uncommon_trap") == 0)
+ if (name != NULL && strcmp(name, "uncommon_trap") == 0) {
return; // Skip uncommon traps
+ }
}
// Don't mark as processed since call's arguments have to be processed.
delayed_worklist->push(n);
@@ -466,9 +469,9 @@ void ConnectionGraph::add_node_to_connection_graph(Node *n, Unique_Node_List *de
}
// Put this check here to process call arguments since some call nodes
// point to phantom_obj.
- if (n_ptn == phantom_obj || n_ptn == null_obj)
+ if (n_ptn == phantom_obj || n_ptn == null_obj) {
return; // Skip predefined nodes.
-
+ }
switch (opcode) {
case Op_AddP: {
Node* base = get_addp_base(n);
@@ -585,7 +588,7 @@ void ConnectionGraph::add_node_to_connection_graph(Node *n, Unique_Node_List *de
case Op_GetAndSetP:
case Op_GetAndSetN: {
add_objload_to_connection_graph(n, delayed_worklist);
- // fallthrough
+ // fall-through
}
case Op_StoreP:
case Op_StoreN:
@@ -673,11 +676,13 @@ void ConnectionGraph::add_final_edges(Node *n) {
case Op_CMoveP: {
for (uint i = CMoveNode::IfFalse; i < n->req(); i++) {
Node* in = n->in(i);
- if (in == NULL)
+ if (in == NULL) {
continue; // ignore NULL
+ }
Node* uncast_in = in->uncast();
- if (uncast_in->is_top() || uncast_in == n)
+ if (uncast_in->is_top() || uncast_in == n) {
continue; // ignore top or inputs which go back this node
+ }
PointsToNode* ptn = ptnode_adr(in->_idx);
assert(ptn != NULL, "node should be registered");
add_edge(n_ptn, ptn);
@@ -704,11 +709,13 @@ void ConnectionGraph::add_final_edges(Node *n) {
if (t->make_ptr() != NULL) {
for (uint i = 1; i < n->req(); i++) {
Node* in = n->in(i);
- if (in == NULL)
+ if (in == NULL) {
continue; // ignore NULL
+ }
Node* uncast_in = in->uncast();
- if (uncast_in->is_top() || uncast_in == n)
+ if (uncast_in->is_top() || uncast_in == n) {
continue; // ignore top or inputs which go back this node
+ }
PointsToNode* ptn = ptnode_adr(in->_idx);
assert(ptn != NULL, "node should be registered");
add_edge(n_ptn, ptn);
@@ -946,7 +953,7 @@ void ConnectionGraph::add_call_node(CallNode* call) {
if (meth == NULL) {
const char* name = call->as_CallStaticJava()->_name;
assert(strncmp(name, "_multianewarray", 15) == 0, "TODO: add failed case check");
- // Returns a newly allocated unescaped object.
+ // Returns a newly allocated non-escaped object.
add_java_object(call, PointsToNode::NoEscape);
ptnode_adr(call_idx)->set_scalar_replaceable(false);
} else if (meth->is_boxing_method()) {
@@ -965,7 +972,7 @@ void ConnectionGraph::add_call_node(CallNode* call) {
BCEscapeAnalyzer* call_analyzer = meth->get_bcea();
call_analyzer->copy_dependencies(_compile->dependencies());
if (call_analyzer->is_return_allocated()) {
- // Returns a newly allocated unescaped object, simply
+ // Returns a newly allocated non-escaped object, simply
// update dependency information.
// Mark it as NoEscape so that objects referenced by
// it's fields will be marked as NoEscape at least.
@@ -1029,8 +1036,9 @@ void ConnectionGraph::process_call_arguments(CallNode *call) {
continue;
}
const Type *aat = _igvn->type(arg);
- if (arg->is_top() || !at->isa_ptr() || !aat->isa_ptr())
+ if (arg->is_top() || !at->isa_ptr() || !aat->isa_ptr()) {
continue;
+ }
if (arg->is_AddP()) {
//
// The inline_native_clone() case when the arraycopy stub is called
@@ -1221,7 +1229,7 @@ void ConnectionGraph::process_call_arguments(CallNode *call) {
// Finish Graph construction.
bool ConnectionGraph::complete_connection_graph(
GrowableArray<PointsToNode*>& ptnodes_worklist,
- GrowableArray<JavaObjectNode*>& non_escaped_worklist,
+ GrowableArray<JavaObjectNode*>& non_escaped_allocs_worklist,
GrowableArray<JavaObjectNode*>& java_objects_worklist,
GrowableArray<FieldNode*>& oop_fields_worklist) {
// Normally only 1-3 passes needed to build Connection Graph depending
@@ -1229,23 +1237,25 @@ bool ConnectionGraph::complete_connection_graph(
// Set limit to 20 to catch situation when something did go wrong and
// bailout Escape Analysis.
// Also limit build time to 20 sec (60 in debug VM), EscapeAnalysisTimeout flag.
-#define CG_BUILD_ITER_LIMIT 20
+#define GRAPH_BUILD_ITER_LIMIT 20
// Propagate GlobalEscape and ArgEscape escape states and check that
// we still have non-escaping objects. The method pushs on _worklist
// Field nodes which reference phantom_object.
- if (!find_non_escaped_objects(ptnodes_worklist, non_escaped_worklist)) {
+ if (!find_non_escaped_objects(ptnodes_worklist, non_escaped_allocs_worklist)) {
return false; // Nothing to do.
}
// Now propagate references to all JavaObject nodes.
int java_objects_length = java_objects_worklist.length();
+ elapsedTimer build_time;
+ build_time.start();
elapsedTimer time;
bool timeout = false;
int new_edges = 1;
int iterations = 0;
do {
while ((new_edges > 0) &&
- (iterations++ < CG_BUILD_ITER_LIMIT)) {
+ (iterations++ < GRAPH_BUILD_ITER_LIMIT)) {
double start_time = time.seconds();
time.start();
new_edges = 0;
@@ -1280,7 +1290,7 @@ bool ConnectionGraph::complete_connection_graph(
if (timeout) break;
if (new_edges > 0) {
// Update escape states on each iteration if graph was updated.
- if (!find_non_escaped_objects(ptnodes_worklist, non_escaped_worklist)) {
+ if (!find_non_escaped_objects(ptnodes_worklist, non_escaped_allocs_worklist)) {
return false; // Nothing to do.
}
}
@@ -1290,7 +1300,7 @@ bool ConnectionGraph::complete_connection_graph(
break;
}
}
- if ((iterations < CG_BUILD_ITER_LIMIT) && !timeout) {
+ if ((iterations < GRAPH_BUILD_ITER_LIMIT) && !timeout) {
time.start();
// Find fields which have unknown value.
int fields_length = oop_fields_worklist.length();
@@ -1312,8 +1322,12 @@ bool ConnectionGraph::complete_connection_graph(
}
} while (new_edges > 0);
+ build_time.stop();
+ _build_time = build_time.seconds();
+ _build_iterations = iterations;
+
// Bailout if passed limits.
- if ((iterations >= CG_BUILD_ITER_LIMIT) || timeout) {
+ if ((iterations >= GRAPH_BUILD_ITER_LIMIT) || timeout) {
Compile* C = _compile;
if (C->log() != NULL) {
C->log()->begin_elem("connectionGraph_bailout reason='reached ");
@@ -1321,28 +1335,28 @@ bool ConnectionGraph::complete_connection_graph(
C->log()->end_elem(" limit'");
}
assert(ExitEscapeAnalysisOnTimeout, "infinite EA connection graph build (%f sec, %d iterations) with %d nodes and worklist size %d",
- time.seconds(), iterations, nodes_size(), ptnodes_worklist.length());
+ _build_time, _build_iterations, nodes_size(), ptnodes_worklist.length());
// Possible infinite build_connection_graph loop,
// bailout (no changes to ideal graph were made).
return false;
}
#ifdef ASSERT
if (Verbose && PrintEscapeAnalysis) {
- tty->print_cr("EA: %d iterations to build connection graph with %d nodes and worklist size %d",
- iterations, nodes_size(), ptnodes_worklist.length());
+ tty->print_cr("EA: %d iterations and %f sec to build connection graph with %d nodes and worklist size %d",
+ _build_iterations, _build_time, nodes_size(), ptnodes_worklist.length());
}
#endif
-#undef CG_BUILD_ITER_LIMIT
+#undef GRAPH_BUILD_ITER_LIMIT
// Find fields initialized by NULL for non-escaping Allocations.
- int non_escaped_length = non_escaped_worklist.length();
+ int non_escaped_length = non_escaped_allocs_worklist.length();
for (int next = 0; next < non_escaped_length; next++) {
- JavaObjectNode* ptn = non_escaped_worklist.at(next);
+ JavaObjectNode* ptn = non_escaped_allocs_worklist.at(next);
PointsToNode::EscapeState es = ptn->escape_state();
assert(es <= PointsToNode::ArgEscape, "sanity");
if (es == PointsToNode::NoEscape) {
- if (find_init_values(ptn, null_obj, _igvn) > 0) {
+ if (find_init_values_null(ptn, _igvn) > 0) {
// Adding references to NULL object does not change escape states
// since it does not escape. Also no fields are added to NULL object.
add_java_object_edges(null_obj, false);
@@ -1364,7 +1378,7 @@ bool ConnectionGraph::complete_connection_graph(
// Propagate GlobalEscape and ArgEscape escape states to all nodes
// and check that we still have non-escaping java objects.
bool ConnectionGraph::find_non_escaped_objects(GrowableArray<PointsToNode*>& ptnodes_worklist,
- GrowableArray<JavaObjectNode*>& non_escaped_worklist) {
+ GrowableArray<JavaObjectNode*>& non_escaped_allocs_worklist) {
GrowableArray<PointsToNode*> escape_worklist;
// First, put all nodes with GlobalEscape and ArgEscape states on worklist.
int ptnodes_length = ptnodes_worklist.length();
@@ -1427,17 +1441,17 @@ bool ConnectionGraph::find_non_escaped_objects(GrowableArray<PointsToNode*>& ptn
}
}
// Remove escaped objects from non_escaped list.
- for (int next = non_escaped_worklist.length()-1; next >= 0 ; --next) {
- JavaObjectNode* ptn = non_escaped_worklist.at(next);
+ for (int next = non_escaped_allocs_worklist.length()-1; next >= 0 ; --next) {
+ JavaObjectNode* ptn = non_escaped_allocs_worklist.at(next);
if (ptn->escape_state() >= PointsToNode::GlobalEscape) {
- non_escaped_worklist.delete_at(next);
+ non_escaped_allocs_worklist.delete_at(next);
}
if (ptn->escape_state() == PointsToNode::NoEscape) {
// Find fields in non-escaped allocations which have unknown value.
- find_init_values(ptn, phantom_obj, NULL);
+ find_init_values_phantom(ptn);
}
}
- return (non_escaped_worklist.length() > 0);
+ return (non_escaped_allocs_worklist.length() > 0);
}
// Add all references to JavaObject node by walking over all uses.
@@ -1447,8 +1461,9 @@ int ConnectionGraph::add_java_object_edges(JavaObjectNode* jobj, bool populate_w
// Populate _worklist by uses of jobj's uses.
for (UseIterator i(jobj); i.has_next(); i.next()) {
PointsToNode* use = i.get();
- if (use->is_Arraycopy())
+ if (use->is_Arraycopy()) {
continue;
+ }
add_uses_to_worklist(use);
if (use->is_Field() && use->as_Field()->is_oop()) {
// Put on worklist all field's uses (loads) and
@@ -1469,8 +1484,9 @@ int ConnectionGraph::add_java_object_edges(JavaObjectNode* jobj, bool populate_w
}
assert(!use->is_JavaObject(), "sanity");
if (use->is_Arraycopy()) {
- if (jobj == null_obj) // NULL object does not have field edges
+ if (jobj == null_obj) { // NULL object does not have field edges
continue;
+ }
// Added edge from Arraycopy node to arraycopy's source java object
if (add_edge(use, jobj)) {
jobj->set_arraycopy_src();
@@ -1479,8 +1495,9 @@ int ConnectionGraph::add_java_object_edges(JavaObjectNode* jobj, bool populate_w
// and stop here.
continue;
}
- if (!add_edge(use, jobj))
+ if (!add_edge(use, jobj)) {
continue; // No new edge added, there was such edge already.
+ }
new_edges++;
if (use->is_LocalVar()) {
add_uses_to_worklist(use);
@@ -1488,8 +1505,9 @@ int ConnectionGraph::add_java_object_edges(JavaObjectNode* jobj, bool populate_w
for (EdgeIterator i(use); i.has_next(); i.next()) {
PointsToNode* e = i.get();
if (e->is_Arraycopy()) {
- if (jobj == null_obj) // NULL object does not have field edges
+ if (jobj == null_obj) { // NULL object does not have field edges
continue;
+ }
// Add edge from arraycopy's destination java object to Arraycopy node.
if (add_edge(jobj, e)) {
new_edges++;
@@ -1548,8 +1566,9 @@ void ConnectionGraph::add_fields_to_worklist(FieldNode* field, PointsToNode* bas
PointsToNode* f = j.get();
if (PointsToNode::is_base_use(f)) { // Field
f = PointsToNode::get_use_node(f);
- if (f == field || !f->as_Field()->is_oop())
+ if (f == field || !f->as_Field()->is_oop()) {
continue;
+ }
int offs = f->as_Field()->offset();
if (offs == offset || offset == Type::OffsetBot || offs == Type::OffsetBot) {
add_to_worklist(f);
@@ -1571,8 +1590,9 @@ void ConnectionGraph::add_fields_to_worklist(FieldNode* field, PointsToNode* bas
assert(base->arraycopy_dst(), "sanity");
continue;
}
- if (f == field || !f->as_Field()->is_oop())
+ if (f == field || !f->as_Field()->is_oop()) {
continue;
+ }
int offs = f->as_Field()->offset();
if (offs == offset || offset == Type::OffsetBot || offs == Type::OffsetBot) {
add_to_worklist(f);
@@ -1591,8 +1611,9 @@ int ConnectionGraph::find_field_value(FieldNode* field) {
PointsToNode* base = i.get();
if (base->is_JavaObject()) {
// Skip Allocate's fields which will be processed later.
- if (base->ideal_node()->is_Allocate())
+ if (base->ideal_node()->is_Allocate()) {
return 0;
+ }
assert(base == null_obj, "only NULL ptr base expected here");
}
}
@@ -1605,44 +1626,49 @@ int ConnectionGraph::find_field_value(FieldNode* field) {
}
// Find fields initializing values for allocations.
-int ConnectionGraph::find_init_values(JavaObjectNode* pta, PointsToNode* init_val, PhaseTransform* phase) {
+int ConnectionGraph::find_init_values_phantom(JavaObjectNode* pta) {
assert(pta->escape_state() == PointsToNode::NoEscape, "Not escaped Allocate nodes only");
- int new_edges = 0;
Node* alloc = pta->ideal_node();
- if (init_val == phantom_obj) {
- // Do nothing for Allocate nodes since its fields values are
- // "known" unless they are initialized by arraycopy/clone.
- if (alloc->is_Allocate() && !pta->arraycopy_dst())
- return 0;
- assert(pta->arraycopy_dst() || alloc->as_CallStaticJava(), "sanity");
+
+ // Do nothing for Allocate nodes since its fields values are
+ // "known" unless they are initialized by arraycopy/clone.
+ if (alloc->is_Allocate() && !pta->arraycopy_dst()) {
+ return 0;
+ }
+ assert(pta->arraycopy_dst() || alloc->as_CallStaticJava(), "sanity");
#ifdef ASSERT
- if (!pta->arraycopy_dst() && alloc->as_CallStaticJava()->method() == NULL) {
- const char* name = alloc->as_CallStaticJava()->_name;
- assert(strncmp(name, "_multianewarray", 15) == 0, "sanity");
- }
+ if (!pta->arraycopy_dst() && alloc->as_CallStaticJava()->method() == NULL) {
+ const char* name = alloc->as_CallStaticJava()->_name;
+ assert(strncmp(name, "_multianewarray", 15) == 0, "sanity");
+ }
#endif
- // Non-escaped allocation returned from Java or runtime call have
- // unknown values in fields.
- for (EdgeIterator i(pta); i.has_next(); i.next()) {
- PointsToNode* field = i.get();
- if (field->is_Field() && field->as_Field()->is_oop()) {
- if (add_edge(field, phantom_obj)) {
- // New edge was added
- new_edges++;
- add_field_uses_to_worklist(field->as_Field());
- }
+ // Non-escaped allocation returned from Java or runtime call have unknown values in fields.
+ int new_edges = 0;
+ for (EdgeIterator i(pta); i.has_next(); i.next()) {
+ PointsToNode* field = i.get();
+ if (field->is_Field() && field->as_Field()->is_oop()) {
+ if (add_edge(field, phantom_obj)) {
+ // New edge was added
+ new_edges++;
+ add_field_uses_to_worklist(field->as_Field());
}
}
- return new_edges;
}
- assert(init_val == null_obj, "sanity");
+ return new_edges;
+}
+
+// Find fields initializing values for allocations.
+int ConnectionGraph::find_init_values_null(JavaObjectNode* pta, PhaseTransform* phase) {
+ assert(pta->escape_state() == PointsToNode::NoEscape, "Not escaped Allocate nodes only");
+ Node* alloc = pta->ideal_node();
// Do nothing for Call nodes since its fields values are unknown.
- if (!alloc->is_Allocate())
+ if (!alloc->is_Allocate()) {
return 0;
-
+ }
InitializeNode* ini = alloc->as_Allocate()->initialization();
bool visited_bottom_offset = false;
GrowableArray<int> offsets_worklist;
+ int new_edges = 0;
// Check if an oop field's initializing value is recorded and add
// a corresponding NULL if field's value if it is not recorded.
@@ -1651,8 +1677,9 @@ int ConnectionGraph::find_init_values(JavaObjectNode* pta, PointsToNode* init_va
//
for (EdgeIterator i(pta); i.has_next(); i.next()) {
PointsToNode* field = i.get(); // Field (AddP)
- if (!field->is_Field() || !field->as_Field()->is_oop())
+ if (!field->is_Field() || !field->as_Field()->is_oop()) {
continue; // Not oop field
+ }
int offset = field->as_Field()->offset();
if (offset == Type::OffsetBot) {
if (!visited_bottom_offset) {
@@ -1759,9 +1786,6 @@ void ConnectionGraph::adjust_scalar_replaceable_state(JavaObjectNode* jobj) {
// Search for non-escaping objects which are not scalar replaceable
// and mark them to propagate the state to referenced objects.
- // 1. An object is not scalar replaceable if the field into which it is
- // stored has unknown offset (stored into unknown element of an array).
- //
for (UseIterator i(jobj); i.has_next(); i.next()) {
PointsToNode* use = i.get();
if (use->is_Arraycopy()) {
@@ -1770,6 +1794,8 @@ void ConnectionGraph::adjust_scalar_replaceable_state(JavaObjectNode* jobj) {
if (use->is_Field()) {
FieldNode* field = use->as_Field();
assert(field->is_oop() && field->scalar_replaceable(), "sanity");
+ // 1. An object is not scalar replaceable if the field into which it is
+ // stored has unknown offset (stored into unknown element of an array).
if (field->offset() == Type::OffsetBot) {
jobj->set_scalar_replaceable(false);
return;
@@ -1875,12 +1901,12 @@ void ConnectionGraph::adjust_scalar_replaceable_state(JavaObjectNode* jobj) {
#ifdef ASSERT
void ConnectionGraph::verify_connection_graph(
GrowableArray<PointsToNode*>& ptnodes_worklist,
- GrowableArray<JavaObjectNode*>& non_escaped_worklist,
+ GrowableArray<JavaObjectNode*>& non_escaped_allocs_worklist,
GrowableArray<JavaObjectNode*>& java_objects_worklist,
GrowableArray<Node*>& addp_worklist) {
// Verify that graph is complete - no new edges could be added.
int java_objects_length = java_objects_worklist.length();
- int non_escaped_length = non_escaped_worklist.length();
+ int non_escaped_length = non_escaped_allocs_worklist.length();
int new_edges = 0;
for (int next = 0; next < java_objects_length; ++next) {
JavaObjectNode* ptn = java_objects_worklist.at(next);
@@ -1888,9 +1914,9 @@ void ConnectionGraph::verify_connection_graph(
}
assert(new_edges == 0, "graph was not complete");
// Verify that escape state is final.
- int length = non_escaped_worklist.length();
- find_non_escaped_objects(ptnodes_worklist, non_escaped_worklist);
- assert((non_escaped_length == non_escaped_worklist.length()) &&
+ int length = non_escaped_allocs_worklist.length();
+ find_non_escaped_objects(ptnodes_worklist, non_escaped_allocs_worklist);
+ assert((non_escaped_length == non_escaped_allocs_worklist.length()) &&
(non_escaped_length == length) &&
(_worklist.length() == 0), "escape state was not final");
@@ -1951,7 +1977,7 @@ void ConnectionGraph::optimize_ideal_graph(GrowableArray<Node*>& ptr_cmp_worklis
if (EliminateLocks) {
// Mark locks before changing ideal graph.
int cnt = C->macro_count();
- for( int i=0; i < cnt; i++ ) {
+ for (int i = 0; i < cnt; i++) {
Node *n = C->macro_node(i);
if (n->is_AbstractLock()) { // Lock and Unlock nodes
AbstractLockNode* alock = n->as_AbstractLock();
@@ -1972,42 +1998,34 @@ void ConnectionGraph::optimize_ideal_graph(GrowableArray<Node*>& ptr_cmp_worklis
}
if (OptimizePtrCompare) {
- // Add ConI(#CC_GT) and ConI(#CC_EQ).
- _pcmp_neq = igvn->makecon(TypeInt::CC_GT);
- _pcmp_eq = igvn->makecon(TypeInt::CC_EQ);
- // Optimize objects compare.
- while (ptr_cmp_worklist.length() != 0) {
- Node *n = ptr_cmp_worklist.pop();
- Node *res = optimize_ptr_compare(n);
- if (res != NULL) {
+ for (int i = 0; i < ptr_cmp_worklist.length(); i++) {
+ Node *n = ptr_cmp_worklist.at(i);
+ const TypeInt* tcmp = optimize_ptr_compare(n);
+ if (tcmp->singleton()) {
+ Node* cmp = igvn->makecon(tcmp);
#ifndef PRODUCT
if (PrintOptimizePtrCompare) {
- tty->print_cr("++++ Replaced: %d %s(%d,%d) --> %s", n->_idx, (n->Opcode() == Op_CmpP ? "CmpP" : "CmpN"), n->in(1)->_idx, n->in(2)->_idx, (res == _pcmp_eq ? "EQ" : "NotEQ"));
+ tty->print_cr("++++ Replaced: %d %s(%d,%d) --> %s", n->_idx, (n->Opcode() == Op_CmpP ? "CmpP" : "CmpN"), n->in(1)->_idx, n->in(2)->_idx, (tcmp == TypeInt::CC_EQ ? "EQ" : "NotEQ"));
if (Verbose) {
n->dump(1);
}
}
#endif
- igvn->replace_node(n, res);
+ igvn->replace_node(n, cmp);
}
}
- // cleanup
- if (_pcmp_neq->outcnt() == 0)
- igvn->hash_delete(_pcmp_neq);
- if (_pcmp_eq->outcnt() == 0)
- igvn->hash_delete(_pcmp_eq);
}
// For MemBarStoreStore nodes added in library_call.cpp, check
// escape status of associated AllocateNode and optimize out
// MemBarStoreStore node if the allocated object never escapes.
- while (storestore_worklist.length() != 0) {
- Node *n = storestore_worklist.pop();
- MemBarStoreStoreNode *storestore = n ->as_MemBarStoreStore();
- Node *alloc = storestore->in(MemBarNode::Precedent)->in(0);
+ for (int i = 0; i < storestore_worklist.length(); i++) {
+ Node* storestore = storestore_worklist.at(i);
+ assert(storestore->is_MemBarStoreStore(), "");
+ Node* alloc = storestore->in(MemBarNode::Precedent)->in(0);
if (alloc->is_Allocate() && not_global_escape(alloc)) {
MemBarNode* mb = MemBarNode::make(C, Op_MemBarCPUOrder, Compile::AliasIdxBot);
- mb->init_req(TypeFunc::Memory, storestore->in(TypeFunc::Memory));
+ mb->init_req(TypeFunc::Memory, storestore->in(TypeFunc::Memory));
mb->init_req(TypeFunc::Control, storestore->in(TypeFunc::Control));
igvn->register_new_node_with_optimizer(mb);
igvn->replace_node(storestore, mb);
@@ -2016,8 +2034,12 @@ void ConnectionGraph::optimize_ideal_graph(GrowableArray<Node*>& ptr_cmp_worklis
}
// Optimize objects compare.
-Node* ConnectionGraph::optimize_ptr_compare(Node* n) {
+const TypeInt* ConnectionGraph::optimize_ptr_compare(Node* n) {
assert(OptimizePtrCompare, "sanity");
+ const TypeInt* EQ = TypeInt::CC_EQ; // [0] == ZERO
+ const TypeInt* NE = TypeInt::CC_GT; // [1] == ONE
+ const TypeInt* UNKNOWN = TypeInt::CC; // [-1, 0,1]
+
PointsToNode* ptn1 = ptnode_adr(n->in(1)->_idx);
PointsToNode* ptn2 = ptnode_adr(n->in(2)->_idx);
JavaObjectNode* jobj1 = unique_java_object(n->in(1));
@@ -2030,13 +2052,13 @@ Node* ConnectionGraph::optimize_ptr_compare(Node* n) {
if (jobj1->escape_state() == PointsToNode::NoEscape) {
if (jobj1 == jobj2) {
// Comparing the same not escaping object.
- return _pcmp_eq;
+ return EQ;
}
Node* obj = jobj1->ideal_node();
// Comparing not escaping allocation.
if ((obj->is_Allocate() || obj->is_CallStaticJava()) &&
!ptn2->points_to(jobj1)) {
- return _pcmp_neq; // This includes nullness check.
+ return NE; // This includes nullness check.
}
}
}
@@ -2046,7 +2068,7 @@ Node* ConnectionGraph::optimize_ptr_compare(Node* n) {
// Comparing not escaping allocation.
if ((obj->is_Allocate() || obj->is_CallStaticJava()) &&
!ptn1->points_to(jobj2)) {
- return _pcmp_neq; // This includes nullness check.
+ return NE; // This includes nullness check.
}
}
}
@@ -2059,13 +2081,13 @@ Node* ConnectionGraph::optimize_ptr_compare(Node* n) {
const Type* t1 = jobj1->ideal_node()->get_ptr_type();
const Type* t2 = jobj2->ideal_node()->get_ptr_type();
if (t1->make_ptr() == t2->make_ptr()) {
- return _pcmp_eq;
+ return EQ;
} else {
- return _pcmp_neq;
+ return NE;
}
}
if (ptn1->meet(ptn2)) {
- return NULL; // Sets are not disjoint
+ return UNKNOWN; // Sets are not disjoint
}
// Sets are disjoint.
@@ -2076,7 +2098,7 @@ Node* ConnectionGraph::optimize_ptr_compare(Node* n) {
if ((set1_has_unknown_ptr && set2_has_null_ptr) ||
(set2_has_unknown_ptr && set1_has_null_ptr)) {
// Check nullness of unknown object.
- return NULL;
+ return UNKNOWN;
}
// Disjointness by itself is not sufficient since
@@ -2085,18 +2107,18 @@ Node* ConnectionGraph::optimize_ptr_compare(Node* n) {
// at least one set has only not escaping allocations.
if (!set1_has_unknown_ptr && !set1_has_null_ptr) {
if (ptn1->non_escaping_allocation()) {
- return _pcmp_neq;
+ return NE;
}
}
if (!set2_has_unknown_ptr && !set2_has_null_ptr) {
if (ptn2->non_escaping_allocation()) {
- return _pcmp_neq;
+ return NE;
}
}
- return NULL;
+ return UNKNOWN;
}
-// Connection Graph constuction functions.
+// Connection Graph construction functions.
void ConnectionGraph::add_local_var(Node *n, PointsToNode::EscapeState es) {
PointsToNode* ptadr = _nodes.at(n->_idx);
@@ -2106,7 +2128,7 @@ void ConnectionGraph::add_local_var(Node *n, PointsToNode::EscapeState es) {
}
Compile* C = _compile;
ptadr = new (C->comp_arena()) LocalVarNode(this, n, es);
- _nodes.at_put(n->_idx, ptadr);
+ map_ideal_node(n, ptadr);
}
void ConnectionGraph::add_java_object(Node *n, PointsToNode::EscapeState es) {
@@ -2117,7 +2139,7 @@ void ConnectionGraph::add_java_object(Node *n, PointsToNode::EscapeState es) {
}
Compile* C = _compile;
ptadr = new (C->comp_arena()) JavaObjectNode(this, n, es);
- _nodes.at_put(n->_idx, ptadr);
+ map_ideal_node(n, ptadr);
}
void ConnectionGraph::add_field(Node *n, PointsToNode::EscapeState es, int offset) {
@@ -2133,7 +2155,7 @@ void ConnectionGraph::add_field(Node *n, PointsToNode::EscapeState es, int offse
}
Compile* C = _compile;
FieldNode* field = new (C->comp_arena()) FieldNode(this, n, es, offset, is_oop);
- _nodes.at_put(n->_idx, field);
+ map_ideal_node(n, field);
}
void ConnectionGraph::add_arraycopy(Node *n, PointsToNode::EscapeState es,
@@ -2147,7 +2169,7 @@ void ConnectionGraph::add_arraycopy(Node *n, PointsToNode::EscapeState es,
}
Compile* C = _compile;
ptadr = new (C->comp_arena()) ArraycopyNode(this, n, es);
- _nodes.at_put(n->_idx, ptadr);
+ map_ideal_node(n, ptadr);
// Add edge from arraycopy node to source object.
(void)add_edge(ptadr, src);
src->set_arraycopy_src();
@@ -2209,7 +2231,7 @@ bool ConnectionGraph::is_oop_field(Node* n, int offset, bool* unsafe) {
// Returns unique pointed java object or NULL.
JavaObjectNode* ConnectionGraph::unique_java_object(Node *n) {
- assert(!_collecting, "should not call when contructed graph");
+ assert(!_collecting, "should not call when constructed graph");
// If the node was created after the escape computation we can't answer.
uint idx = n->_idx;
if (idx >= nodes_size()) {
@@ -2277,16 +2299,18 @@ bool ConnectionGraph::not_global_escape(Node *n) {
}
PointsToNode::EscapeState es = ptn->escape_state();
// If we have already computed a value, return it.
- if (es >= PointsToNode::GlobalEscape)
+ if (es >= PointsToNode::GlobalEscape) {
return false;
+ }
if (ptn->is_JavaObject()) {
return true; // (es < PointsToNode::GlobalEscape);
}
assert(ptn->is_LocalVar(), "sanity");
// Check all java objects it points to.
for (EdgeIterator i(ptn); i.has_next(); i.next()) {
- if (i.get()->escape_state() >= PointsToNode::GlobalEscape)
+ if (i.get()->escape_state() >= PointsToNode::GlobalEscape) {
return false;
+ }
}
return true;
}
@@ -2301,8 +2325,9 @@ bool PointsToNode::points_to(JavaObjectNode* ptn) const {
}
assert(is_LocalVar() || is_Field(), "sanity");
for (EdgeIterator i(this); i.has_next(); i.next()) {
- if (i.get() == ptn)
+ if (i.get() == ptn) {
return true;
+ }
}
return false;
}
@@ -2321,8 +2346,9 @@ bool PointsToNode::meet(PointsToNode* ptn) {
for (EdgeIterator i(this); i.has_next(); i.next()) {
PointsToNode* this_e = i.get();
for (int j = 0; j < ptn_count; j++) {
- if (this_e == ptn->edge(j))
+ if (this_e == ptn->edge(j)) {
return true;
+ }
}
}
return false;
@@ -2332,8 +2358,9 @@ bool PointsToNode::meet(PointsToNode* ptn) {
// Return true if bases point to this java object.
bool FieldNode::has_base(JavaObjectNode* jobj) const {
for (BaseIterator i(this); i.has_next(); i.next()) {
- if (i.get() == jobj)
+ if (i.get() == jobj) {
return true;
+ }
}
return false;
}
@@ -2804,8 +2831,9 @@ void ConnectionGraph::move_inst_mem(Node* n, GrowableArray<PhiNode *> &orig_phi
// is the specified alias index.
//
Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArray<PhiNode *> &orig_phis) {
- if (orig_mem == NULL)
+ if (orig_mem == NULL) {
return orig_mem;
+ }
Compile* C = _compile;
PhaseGVN* igvn = _igvn;
const TypeOopPtr *toop = C->get_adr_type(alias_idx)->isa_oopptr();
@@ -2815,24 +2843,28 @@ Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArra
Node *result = orig_mem;
while (prev != result) {
prev = result;
- if (result == start_mem)
+ if (result == start_mem) {
break; // hit one of our sentinels
+ }
if (result->is_Mem()) {
const Type *at = igvn->type(result->in(MemNode::Address));
- if (at == Type::TOP)
+ if (at == Type::TOP) {
break; // Dead
+ }
assert (at->isa_ptr() != NULL, "pointer type required.");
int idx = C->get_alias_index(at->is_ptr());
- if (idx == alias_idx)
+ if (idx == alias_idx) {
break; // Found
+ }
if (!is_instance && (at->isa_oopptr() == NULL ||
!at->is_oopptr()->is_known_instance())) {
break; // Do not skip store to general memory slice.
}
result = result->in(MemNode::Memory);
}
- if (!is_instance)
+ if (!is_instance) {
continue; // don't search further for non-instance types
+ }
// skip over a call which does not affect this memory slice
if (result->is_Proj() && result->as_Proj()->_con == TypeFunc::Memory) {
Node *proj_in = result->in(0);
@@ -2948,7 +2980,7 @@ Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArra
}
//
-// Convert the types of unescaped object to instance types where possible,
+// Convert the types of non-escaped object to instance types where possible,
// propagate the new type information through the graph, and update memory
// edges and MergeMem inputs to reflect the new type.
//
@@ -2976,7 +3008,7 @@ Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArra
// Phase 4: Update the inputs of non-instance memory Phis and the Memory input of memnodes.
//
// In the following example, the CheckCastPP nodes are the cast of allocation
-// results and the allocation of node 29 is unescaped and eligible to be an
+// results and the allocation of node 29 is non-escaped and eligible to be an
// instance type.
//
// We start with:
@@ -3061,9 +3093,10 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist,
PointsToNode* ptn = ptnode_adr(alloc->_idx);
PointsToNode::EscapeState es = ptn->escape_state();
// We have an allocation or call which returns a Java object,
- // see if it is unescaped.
- if (es != PointsToNode::NoEscape || !ptn->scalar_replaceable())
+ // see if it is non-escaped.
+ if (es != PointsToNode::NoEscape || !ptn->scalar_replaceable()) {
continue;
+ }
// Find CheckCastPP for the allocate or for the return value of a call
n = alloc->result_cast();
if (n == NULL) { // No uses except Initialize node
@@ -3110,11 +3143,12 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist,
}
const TypeOopPtr *t = igvn->type(n)->isa_oopptr();
- if (t == NULL)
+ if (t == NULL) {
continue; // not a TypeOopPtr
- if (!t->klass_is_exact())
+ }
+ if (!t->klass_is_exact()) {
continue; // not an unique type
-
+ }
if (alloc->is_Allocate()) {
// Set the scalar_replaceable flag for allocation
// so it could be eliminated.
@@ -3351,15 +3385,17 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist,
return; // nothing to do
while (memnode_worklist.length() != 0) {
Node *n = memnode_worklist.pop();
- if (visited.test_set(n->_idx))
+ if (visited.test_set(n->_idx)) {
continue;
+ }
if (n->is_Phi() || n->is_ClearArray()) {
// we don't need to do anything, but the users must be pushed
} else if (n->is_MemBar()) { // Initialize, MemBar nodes
// we don't need to do anything, but the users must be pushed
n = n->as_MemBar()->proj_out_or_null(TypeFunc::Memory);
- if (n == NULL)
+ if (n == NULL) {
continue;
+ }
} else if (n->Opcode() == Op_StrCompressedCopy ||
n->Opcode() == Op_EncodeISOArray) {
// get the memory projection
@@ -3369,8 +3405,9 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist,
assert(n->is_Mem(), "memory node required.");
Node *addr = n->in(MemNode::Address);
const Type *addr_t = igvn->type(addr);
- if (addr_t == Type::TOP)
+ if (addr_t == Type::TOP) {
continue;
+ }
assert (addr_t->isa_ptr() != NULL, "pointer type required.");
int alias_idx = _compile->get_alias_index(addr_t->is_ptr());
assert ((uint)alias_idx < new_index_end, "wrong alias index");
@@ -3397,8 +3434,9 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist,
if (use->is_Phi() || use->is_ClearArray()) {
memnode_worklist.append_if_missing(use);
} else if (use->is_Mem() && use->in(MemNode::Memory) == n) {
- if (use->Opcode() == Op_StoreCM) // Ignore cardmark stores
+ if (use->Opcode() == Op_StoreCM) { // Ignore cardmark stores
continue;
+ }
memnode_worklist.append_if_missing(use);
} else if (use->is_MemBar()) {
if (use->in(TypeFunc::Memory) == n) { // Ignore precedent edge
@@ -3449,8 +3487,9 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist,
for (uint i = Compile::AliasIdxRaw+1; i < nslices; i++) {
Node* mem = nmm->in(i);
Node* cur = NULL;
- if (mem == NULL || mem->is_top())
+ if (mem == NULL || mem->is_top()) {
continue;
+ }
// First, update mergemem by moving memory nodes to corresponding slices
// if their type became more precise since this mergemem was created.
while (mem->is_Mem()) {
@@ -3459,8 +3498,9 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist,
assert (at->isa_ptr() != NULL, "pointer type required.");
uint idx = (uint)_compile->get_alias_index(at->is_ptr());
if (idx == i) {
- if (cur == NULL)
+ if (cur == NULL) {
cur = mem;
+ }
} else {
if (idx >= nmm->req() || nmm->is_empty_memory(nmm->in(idx))) {
nmm->set_memory_at(idx, mem);
@@ -3507,7 +3547,7 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist,
// the Memory input of memnodes
// First update the inputs of any non-instance Phi's from
// which we split out an instance Phi. Note we don't have
- // to recursively process Phi's encounted on the input memory
+ // to recursively process Phi's encountered on the input memory
// chains as is done in split_memory_phi() since they will
// also be processed here.
for (int j = 0; j < orig_phis.length(); j++) {
@@ -3596,15 +3636,18 @@ void PointsToNode::dump(bool print_state) const {
EscapeState es = escape_state();
EscapeState fields_es = fields_escape_state();
tty->print("%s(%s) ", esc_names[(int)es], esc_names[(int)fields_es]);
- if (nt == PointsToNode::JavaObject && !this->scalar_replaceable())
+ if (nt == PointsToNode::JavaObject && !this->scalar_replaceable()) {
tty->print("NSR ");
+ }
}
if (is_Field()) {
FieldNode* f = (FieldNode*)this;
- if (f->is_oop())
+ if (f->is_oop()) {
tty->print("oop ");
- if (f->offset() > 0)
+ }
+ if (f->offset() > 0) {
tty->print("+%d ", f->offset());
+ }
tty->print("(");
for (BaseIterator i(f); i.has_next(); i.next()) {
PointsToNode* b = i.get();
@@ -3628,10 +3671,11 @@ void PointsToNode::dump(bool print_state) const {
tty->print(" %d%s%s", u->idx(), is_base ? "b" : "", u->is_Arraycopy() ? "cp" : "");
}
tty->print(" ]] ");
- if (_node == NULL)
+ if (_node == NULL) {
tty->print_cr("<null>");
- else
+ } else {
_node->dump();
+ }
}
void ConnectionGraph::dump(GrowableArray<PointsToNode*>& ptnodes_worklist) {
@@ -3639,8 +3683,9 @@ void ConnectionGraph::dump(GrowableArray<PointsToNode*>& ptnodes_worklist) {
int ptnodes_length = ptnodes_worklist.length();
for (int i = 0; i < ptnodes_length; i++) {
PointsToNode *ptn = ptnodes_worklist.at(i);
- if (ptn == NULL || !ptn->is_JavaObject())
+ if (ptn == NULL || !ptn->is_JavaObject()) {
continue;
+ }
PointsToNode::EscapeState es = ptn->escape_state();
if ((es != PointsToNode::NoEscape) && !Verbose) {
continue;
diff --git a/src/hotspot/share/opto/escape.hpp b/src/hotspot/share/opto/escape.hpp
index 3ae6ce5f2d4..e1df35bee1d 100644
--- a/src/hotspot/share/opto/escape.hpp
+++ b/src/hotspot/share/opto/escape.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -75,7 +75,7 @@
// the connection graph, the following IR nodes are treated as local variables:
// Phi (pointer values)
// LoadP, LoadN
-// Proj#5 (value returned from callnodes including allocations)
+// Proj#5 (value returned from call nodes including allocations)
// CheckCastPP, CastPP
//
// The LoadP, Proj and CheckCastPP behave like variables assigned to only once.
@@ -200,20 +200,21 @@ public:
void set_arraycopy_dst() { _flags |= ArraycopyDst; }
bool scalar_replaceable() const { return (_flags & ScalarReplaceable) != 0;}
- void set_scalar_replaceable(bool v) {
- if (v)
+ void set_scalar_replaceable(bool set) {
+ if (set) {
_flags |= ScalarReplaceable;
- else
+ } else {
_flags &= ~ScalarReplaceable;
+ }
}
int edge_count() const { return _edges.length(); }
PointsToNode* edge(int e) const { return _edges.at(e); }
- bool add_edge(PointsToNode* edge) { return _edges.append_if_missing(edge); }
+ bool add_edge(PointsToNode* edge) { return _edges.append_if_missing(edge); }
int use_count() const { return _uses.length(); }
PointsToNode* use(int e) const { return _uses.at(e); }
- bool add_use(PointsToNode* use) { return _uses.append_if_missing(use); }
+ bool add_use(PointsToNode* use) { return _uses.append_if_missing(use); }
// Mark base edge use to distinguish from stored value edge.
bool add_base_use(FieldNode* use) { return _uses.append_if_missing((PointsToNode*)((intptr_t)use + 1)); }
@@ -246,8 +247,9 @@ class JavaObjectNode: public PointsToNode {
public:
JavaObjectNode(ConnectionGraph *CG, Node* n, EscapeState es):
PointsToNode(CG, n, es, JavaObject) {
- if (es > NoEscape)
+ if (es > NoEscape) {
set_scalar_replaceable(false);
+ }
}
};
@@ -257,10 +259,7 @@ class FieldNode: public PointsToNode {
const bool _is_oop; // Field points to object
bool _has_unknown_base; // Has phantom_object base
public:
- FieldNode(ConnectionGraph *CG, Node* n, EscapeState es, int offs, bool is_oop):
- PointsToNode(CG, n, es, Field),
- _offset(offs), _is_oop(is_oop),
- _has_unknown_base(false) {}
+ inline FieldNode(ConnectionGraph *CG, Node* n, EscapeState es, int offs, bool is_oop);
int offset() const { return _offset;}
bool is_oop() const { return _is_oop;}
@@ -318,7 +317,8 @@ public:
class ConnectionGraph: public ResourceObj {
- friend class PointsToNode;
+ friend class PointsToNode; // to access _compile
+ friend class FieldNode;
private:
GrowableArray<PointsToNode*> _nodes; // Map from ideal nodes to
// ConnectionGraph nodes.
@@ -334,14 +334,15 @@ private:
bool _verify; // verify graph
JavaObjectNode* null_obj;
- Node* _pcmp_neq; // ConI(#CC_GT)
- Node* _pcmp_eq; // ConI(#CC_EQ)
Compile* _compile; // Compile object for current compilation
PhaseIterGVN* _igvn; // Value numbering
Unique_Node_List ideal_nodes; // Used by CG construction and types splitting.
+ int _build_iterations; // Number of iterations took to build graph
+ double _build_time; // Time (sec) took to build graph
+
public:
JavaObjectNode* phantom_obj; // Unknown object
@@ -423,23 +424,27 @@ private:
int find_field_value(FieldNode* field);
// Find fields initializing values for allocations.
- int find_init_values(JavaObjectNode* ptn, PointsToNode* init_val, PhaseTransform* phase);
+ int find_init_values_null (JavaObjectNode* ptn, PhaseTransform* phase);
+ int find_init_values_phantom(JavaObjectNode* ptn);
// Set the escape state of an object and its fields.
void set_escape_state(PointsToNode* ptn, PointsToNode::EscapeState esc) {
// Don't change non-escaping state of NULL pointer.
if (ptn != null_obj) {
- if (ptn->escape_state() < esc)
+ if (ptn->escape_state() < esc) {
ptn->set_escape_state(esc);
- if (ptn->fields_escape_state() < esc)
+ }
+ if (ptn->fields_escape_state() < esc) {
ptn->set_fields_escape_state(esc);
+ }
}
}
void set_fields_escape_state(PointsToNode* ptn, PointsToNode::EscapeState esc) {
// Don't change non-escaping state of NULL pointer.
if (ptn != null_obj) {
- if (ptn->fields_escape_state() < esc)
+ if (ptn->fields_escape_state() < esc) {
ptn->set_fields_escape_state(esc);
+ }
}
}
@@ -455,7 +460,7 @@ private:
void optimize_ideal_graph(GrowableArray<Node*>& ptr_cmp_worklist,
GrowableArray<Node*>& storestore_worklist);
// Optimize objects compare.
- Node* optimize_ptr_compare(Node* n);
+ const TypeInt* optimize_ptr_compare(Node* n);
// Returns unique corresponding java object or NULL.
JavaObjectNode* unique_java_object(Node *n);
@@ -494,8 +499,9 @@ private:
assert(to != phantom_obj || is_new, "sanity");
if (is_new) { // New edge?
assert(!_verify, "graph is incomplete");
- if (to == null_obj)
+ if (to == null_obj) {
return is_new; // Don't add fields to NULL pointer.
+ }
if (to->is_JavaObject()) {
is_new = to->add_edge(from);
} else {
@@ -514,8 +520,7 @@ private:
bool is_captured_store_address(Node* addp);
- // Propagate unique types created for unescaped allocated objects
- // through the graph
+ // Propagate unique types created for non-escaped allocated objects through the graph
void split_unique_types(GrowableArray<Node *> &alloc_worklist, GrowableArray<ArrayCopyNode*> &arraycopy_worklist);
// Helper methods for unique types split.
@@ -531,7 +536,7 @@ private:
GrowableArray<MergeMemNode*> _mergemem_worklist; // List of all MergeMem nodes
- Node_Array _node_map; // used for bookeeping during type splitting
+ Node_Array _node_map; // used for bookkeeping during type splitting
// Used for the following purposes:
// Memory Phi - most recent unique Phi split out
// from this Phi
@@ -624,4 +629,11 @@ inline PointsToNode::PointsToNode(ConnectionGraph *CG, Node* n, EscapeState es,
assert(n != NULL && es != UnknownEscape, "sanity");
}
+inline FieldNode::FieldNode(ConnectionGraph *CG, Node* n, EscapeState es, int offs, bool is_oop):
+ PointsToNode(CG, n, es, Field),
+ _bases(CG->_compile->comp_arena(), 2, 0, NULL),
+ _offset(offs), _is_oop(is_oop),
+ _has_unknown_base(false) {
+}
+
#endif // SHARE_OPTO_ESCAPE_HPP