< prev index next >

src/hotspot/share/opto/escape.cpp

Print this page
rev 60137 : 8227745: Enable Escape Analysis for Better Performance in the Presence of JVMTI Agents
Reviewed-by: mdoerr, goetz
   1 /*
   2  * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *


 106   if (oop_null->outcnt() == 0)
 107     igvn->hash_delete(oop_null);
 108   if (noop_null->outcnt() == 0)
 109     igvn->hash_delete(noop_null);
 110 }
 111 
 112 bool ConnectionGraph::compute_escape() {
 113   Compile* C = _compile;
 114   PhaseGVN* igvn = _igvn;
 115 
 116   // Worklists used by EA.
 117   Unique_Node_List delayed_worklist;
 118   GrowableArray<Node*> alloc_worklist;
 119   GrowableArray<Node*> ptr_cmp_worklist;
 120   GrowableArray<Node*> storestore_worklist;
 121   GrowableArray<ArrayCopyNode*> arraycopy_worklist;
 122   GrowableArray<PointsToNode*>   ptnodes_worklist;
 123   GrowableArray<JavaObjectNode*> java_objects_worklist;
 124   GrowableArray<JavaObjectNode*> non_escaped_worklist;
 125   GrowableArray<FieldNode*>      oop_fields_worklist;

 126   DEBUG_ONLY( GrowableArray<Node*> addp_worklist; )
 127 
 128   { Compile::TracePhase tp("connectionGraph", &Phase::timers[Phase::_t_connectionGraph]);
 129 
 130   // 1. Populate Connection Graph (CG) with PointsTo nodes.
 131   ideal_nodes.map(C->live_nodes(), NULL);  // preallocate space
 132   // Initialize worklist
 133   if (C->root() != NULL) {
 134     ideal_nodes.push(C->root());
 135   }
 136   // Processed ideal nodes are unique on ideal_nodes list
 137   // but several ideal nodes are mapped to the phantom_obj.
 138   // To avoid duplicated entries on the following worklists
 139   // add the phantom_obj only once to them.
 140   ptnodes_worklist.append(phantom_obj);
 141   java_objects_worklist.append(phantom_obj);
 142   for( uint next = 0; next < ideal_nodes.size(); ++next ) {
 143     Node* n = ideal_nodes.at(next);
 144     // Create PointsTo nodes and add them to Connection Graph. Called
 145     // only once per ideal node since ideal_nodes is Unique_Node list.


 171       // escape status of the associated Allocate node some of them
 172       // may be eliminated.
 173       storestore_worklist.append(n);
 174     } else if (n->is_MemBar() && (n->Opcode() == Op_MemBarRelease) &&
 175                (n->req() > MemBarNode::Precedent)) {
 176       record_for_optimizer(n);
 177 #ifdef ASSERT
 178     } else if (n->is_AddP()) {
 179       // Collect address nodes for graph verification.
 180       addp_worklist.append(n);
 181 #endif
 182     } else if (n->is_ArrayCopy()) {
 183       // Keep a list of ArrayCopy nodes so if one of its input is non
 184       // escaping, we can record a unique type
 185       arraycopy_worklist.append(n->as_ArrayCopy());
 186     }
 187     for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
 188       Node* m = n->fast_out(i);   // Get user
 189       ideal_nodes.push(m);
 190     }



 191   }
 192   if (non_escaped_worklist.length() == 0) {
 193     _collecting = false;
 194     return false; // Nothing to do.
 195   }
 196   // Add final simple edges to graph.
 197   while(delayed_worklist.size() > 0) {
 198     Node* n = delayed_worklist.pop();
 199     add_final_edges(n);
 200   }
 201   int ptnodes_length = ptnodes_worklist.length();
 202 
 203 #ifdef ASSERT
 204   if (VerifyConnectionGraph) {
 205     // Verify that no new simple edges could be created and all
 206     // local vars has edges.
 207     _verify = true;
 208     for (int next = 0; next < ptnodes_length; ++next) {
 209       PointsToNode* ptn = ptnodes_worklist.at(next);
 210       add_final_edges(ptn->ideal_node());


 300     // Now use the escape information to create unique types for
 301     // scalar replaceable objects.
 302     split_unique_types(alloc_worklist, arraycopy_worklist);
 303     if (C->failing())  return false;
 304     C->print_method(PHASE_AFTER_EA, 2);
 305 
 306 #ifdef ASSERT
 307   } else if (Verbose && (PrintEscapeAnalysis || PrintEliminateAllocations)) {
 308     tty->print("=== No allocations eliminated for ");
 309     C->method()->print_short_name();
 310     if(!EliminateAllocations) {
 311       tty->print(" since EliminateAllocations is off ===");
 312     } else if(!has_scalar_replaceable_candidates) {
 313       tty->print(" since there are no scalar replaceable candidates ===");
 314     } else if(C->AliasLevel() < 3) {
 315       tty->print(" since AliasLevel < 3 ===");
 316     }
 317     tty->cr();
 318 #endif
 319   }



















 320   return has_non_escaping_obj;
 321 }





























































 322 
 323 // Utility function for nodes that load an object
 324 void ConnectionGraph::add_objload_to_connection_graph(Node *n, Unique_Node_List *delayed_worklist) {
 325   // Using isa_ptr() instead of isa_oopptr() for LoadP and Phi because
 326   // ThreadLocal has RawPtr type.
 327   const Type* t = _igvn->type(n);
 328   if (t->make_ptr() != NULL) {
 329     Node* adr = n->in(MemNode::Address);
 330 #ifdef ASSERT
 331     if (!adr->is_AddP()) {
 332       assert(_igvn->type(adr)->isa_rawptr(), "sanity");
 333     } else {
 334       assert((ptnode_adr(adr->_idx) == NULL ||
 335               ptnode_adr(adr->_idx)->as_Field()->is_oop()), "sanity");
 336     }
 337 #endif
 338     add_local_var_and_edge(n, PointsToNode::NoEscape,
 339                            adr, delayed_worklist);
 340   }
 341 }


   1 /*
   2  * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *


 106   if (oop_null->outcnt() == 0)
 107     igvn->hash_delete(oop_null);
 108   if (noop_null->outcnt() == 0)
 109     igvn->hash_delete(noop_null);
 110 }
 111 
 112 bool ConnectionGraph::compute_escape() {
 113   Compile* C = _compile;
 114   PhaseGVN* igvn = _igvn;
 115 
 116   // Worklists used by EA.
 117   Unique_Node_List delayed_worklist;
 118   GrowableArray<Node*> alloc_worklist;
 119   GrowableArray<Node*> ptr_cmp_worklist;
 120   GrowableArray<Node*> storestore_worklist;
 121   GrowableArray<ArrayCopyNode*> arraycopy_worklist;
 122   GrowableArray<PointsToNode*>   ptnodes_worklist;
 123   GrowableArray<JavaObjectNode*> java_objects_worklist;
 124   GrowableArray<JavaObjectNode*> non_escaped_worklist;
 125   GrowableArray<FieldNode*>      oop_fields_worklist;
 126   GrowableArray<SafePointNode*>  sfn_worklist;
 127   DEBUG_ONLY( GrowableArray<Node*> addp_worklist; )
 128 
 129   { Compile::TracePhase tp("connectionGraph", &Phase::timers[Phase::_t_connectionGraph]);
 130 
 131   // 1. Populate Connection Graph (CG) with PointsTo nodes.
 132   ideal_nodes.map(C->live_nodes(), NULL);  // preallocate space
 133   // Initialize worklist
 134   if (C->root() != NULL) {
 135     ideal_nodes.push(C->root());
 136   }
 137   // Processed ideal nodes are unique on ideal_nodes list
 138   // but several ideal nodes are mapped to the phantom_obj.
 139   // To avoid duplicated entries on the following worklists
 140   // add the phantom_obj only once to them.
 141   ptnodes_worklist.append(phantom_obj);
 142   java_objects_worklist.append(phantom_obj);
 143   for( uint next = 0; next < ideal_nodes.size(); ++next ) {
 144     Node* n = ideal_nodes.at(next);
 145     // Create PointsTo nodes and add them to Connection Graph. Called
 146     // only once per ideal node since ideal_nodes is Unique_Node list.


 172       // escape status of the associated Allocate node some of them
 173       // may be eliminated.
 174       storestore_worklist.append(n);
 175     } else if (n->is_MemBar() && (n->Opcode() == Op_MemBarRelease) &&
 176                (n->req() > MemBarNode::Precedent)) {
 177       record_for_optimizer(n);
 178 #ifdef ASSERT
 179     } else if (n->is_AddP()) {
 180       // Collect address nodes for graph verification.
 181       addp_worklist.append(n);
 182 #endif
 183     } else if (n->is_ArrayCopy()) {
 184       // Keep a list of ArrayCopy nodes so if one of its input is non
 185       // escaping, we can record a unique type
 186       arraycopy_worklist.append(n->as_ArrayCopy());
 187     }
 188     for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
 189       Node* m = n->fast_out(i);   // Get user
 190       ideal_nodes.push(m);
 191     }
 192     if (n-> is_SafePoint()) {
 193       sfn_worklist.append(n->as_SafePoint());
 194     }
 195   }
 196   if (non_escaped_worklist.length() == 0) {
 197     _collecting = false;
 198     return false; // Nothing to do.
 199   }
 200   // Add final simple edges to graph.
 201   while(delayed_worklist.size() > 0) {
 202     Node* n = delayed_worklist.pop();
 203     add_final_edges(n);
 204   }
 205   int ptnodes_length = ptnodes_worklist.length();
 206 
 207 #ifdef ASSERT
 208   if (VerifyConnectionGraph) {
 209     // Verify that no new simple edges could be created and all
 210     // local vars has edges.
 211     _verify = true;
 212     for (int next = 0; next < ptnodes_length; ++next) {
 213       PointsToNode* ptn = ptnodes_worklist.at(next);
 214       add_final_edges(ptn->ideal_node());


 304     // Now use the escape information to create unique types for
 305     // scalar replaceable objects.
 306     split_unique_types(alloc_worklist, arraycopy_worklist);
 307     if (C->failing())  return false;
 308     C->print_method(PHASE_AFTER_EA, 2);
 309 
 310 #ifdef ASSERT
 311   } else if (Verbose && (PrintEscapeAnalysis || PrintEliminateAllocations)) {
 312     tty->print("=== No allocations eliminated for ");
 313     C->method()->print_short_name();
 314     if(!EliminateAllocations) {
 315       tty->print(" since EliminateAllocations is off ===");
 316     } else if(!has_scalar_replaceable_candidates) {
 317       tty->print(" since there are no scalar replaceable candidates ===");
 318     } else if(C->AliasLevel() < 3) {
 319       tty->print(" since AliasLevel < 3 ===");
 320     }
 321     tty->cr();
 322 #endif
 323   }
 324 
 325   // Annotate at safepoints if they have <= ArgEscape objects in their scope and at
 326   // java calls if they pass ArgEscape objects as parameters.
 327   if (has_non_escaping_obj &&
 328       (C->env()->should_retain_local_variables() ||
 329        C->env()->jvmti_can_get_owned_monitor_info() ||
 330        C->env()->jvmti_can_walk_any_space() ||
 331        DeoptimizeObjectsALot)) {
 332     int sfn_length = sfn_worklist.length();
 333     for (int next = 0; next < sfn_length; next++) {
 334       SafePointNode* sfn = sfn_worklist.at(next);
 335       sfn->set_not_global_escape_in_scope(has_not_global_escape_in_scope(sfn));
 336       if (sfn->is_CallJava()) {
 337         CallJavaNode* call = sfn->as_CallJava();
 338         call->set_arg_escape(has_arg_escape(call));
 339       }
 340     }
 341   }
 342 
 343   return has_non_escaping_obj;
 344 }
 345 
 346 // Returns true if an object in the scope of sfn does not escape globally.
 347 bool ConnectionGraph::has_not_global_escape_in_scope(SafePointNode* sfn) {
 348   Compile* C = _compile;
 349   for (JVMState* jvms = sfn->jvms(); jvms != NULL; jvms = jvms->caller()) {
 350     if (C->env()->should_retain_local_variables() || C->env()->jvmti_can_walk_any_space() ||
 351         DeoptimizeObjectsALot) {
 352       // Jvmti agents can access locals. Must provide info about local objects at runtime.
 353       int num_locs = jvms->loc_size();
 354       for (int idx = 0; idx < num_locs; idx++) {
 355         Node* l = sfn->local(jvms, idx);
 356         if (not_global_escape(l)) {
 357           return true;
 358         }
 359       }
 360     }
 361     if (C->env()->jvmti_can_get_owned_monitor_info() ||
 362         C->env()->jvmti_can_walk_any_space() || DeoptimizeObjectsALot) {
 363       // Jvmti agents can read monitors. Must provide info about locked objects at runtime.
 364       int num_mon = jvms->nof_monitors();
 365       for (int idx = 0; idx < num_mon; idx++) {
 366         Node* m = sfn->monitor_obj(jvms, idx);
 367         if (m != NULL && not_global_escape(m)) {
 368           return true;
 369         }
 370       }
 371     }
 372   }
 373   return false;
 374 }
 375 
 376 // Returns true if at least one of the arguments to the call is an object
 377 // that does not escape globally.
 378 bool ConnectionGraph::has_arg_escape(CallJavaNode* call) {
 379   if (call->method() != NULL) {
 380     uint max_idx = TypeFunc::Parms + call->method()->arg_size();
 381     for (uint idx = TypeFunc::Parms; idx < max_idx; idx++) {
 382       Node* p = call->in(idx);
 383       if (not_global_escape(p)) {
 384         return true;
 385       }
 386     }
 387   } else {
 388     const char* name = call->as_CallStaticJava()->_name;
 389     assert(name != NULL, "no name");
 390     // no arg escapes through uncommon traps
 391     if (strcmp(name, "uncommon_trap") != 0) {
 392       // process_call_arguments() assumes that all arguments escape globally
 393       const TypeTuple* d = call->tf()->domain();
 394       for (uint i = TypeFunc::Parms; i < d->cnt(); i++) {
 395         const Type* at = d->field_at(i);
 396         if (at->isa_oopptr() != NULL) {
 397           return true;
 398         }
 399       }
 400     }
 401   }
 402   return false;
 403 }
 404 
 405 
 406 
 407 // Utility function for nodes that load an object
 408 void ConnectionGraph::add_objload_to_connection_graph(Node *n, Unique_Node_List *delayed_worklist) {
 409   // Using isa_ptr() instead of isa_oopptr() for LoadP and Phi because
 410   // ThreadLocal has RawPtr type.
 411   const Type* t = _igvn->type(n);
 412   if (t->make_ptr() != NULL) {
 413     Node* adr = n->in(MemNode::Address);
 414 #ifdef ASSERT
 415     if (!adr->is_AddP()) {
 416       assert(_igvn->type(adr)->isa_rawptr(), "sanity");
 417     } else {
 418       assert((ptnode_adr(adr->_idx) == NULL ||
 419               ptnode_adr(adr->_idx)->as_Field()->is_oop()), "sanity");
 420     }
 421 #endif
 422     add_local_var_and_edge(n, PointsToNode::NoEscape,
 423                            adr, delayed_worklist);
 424   }
 425 }


< prev index next >