src/share/vm/opto/compile.cpp
Print this page
rev 3904 : 8005071: Incremental inlining for JSR 292
Summary: post parse inlining driven by number of live nodes.
Reviewed-by:
*** 134,144 ****
return lo; // inexact match
}
void Compile::register_intrinsic(CallGenerator* cg) {
if (_intrinsics == NULL) {
! _intrinsics = new GrowableArray<CallGenerator*>(60);
}
// This code is stolen from ciObjectFactory::insert.
// Really, GrowableArray should have methods for
// insert_at, remove_at, and binary_search.
int len = _intrinsics->length();
--- 134,144 ----
return lo; // inexact match
}
void Compile::register_intrinsic(CallGenerator* cg) {
if (_intrinsics == NULL) {
! _intrinsics = new (comp_arena())GrowableArray<CallGenerator*>(comp_arena(), 60, 0, NULL);
}
// This code is stolen from ciObjectFactory::insert.
// Really, GrowableArray should have methods for
// insert_at, remove_at, and binary_search.
int len = _intrinsics->length();
*** 363,372 ****
--- 363,388 ----
record_dead_node(node_idx);
}
}
}
+ void Compile::remove_useless_late_inlines(Unique_Node_List &useful, bool string) {
+ int shift = 0;
+ GrowableArray<CallGenerator*>* inlines = string ? &_string_late_inlines : &_late_inlines;
+ for (int i = 0; i < inlines->length(); i++) {
+ CallGenerator* cg = inlines->at(i);
+ CallNode* call = cg->call_node();
+ if (shift > 0) {
+ inlines->at_put(i-shift, cg);
+ }
+ if (!useful.member(call)) {
+ shift++;
+ }
+ }
+ inlines->trunc_to(inlines->length()-shift);
+ }
+
// Disconnect all useless nodes by disconnecting those at the boundary.
void Compile::remove_useless_nodes(Unique_Node_List &useful) {
uint next = 0;
while (next < useful.size()) {
Node *n = useful.at(next++);
*** 392,401 ****
--- 408,420 ----
Node* n = C->macro_node(i);
if (!useful.member(n)) {
remove_macro_node(n);
}
}
+ // clean up the late inline lists
+ remove_useless_late_inlines(useful, true);
+ remove_useless_late_inlines(useful, false);
debug_only(verify_graph_edges(true/*check for no_dead_code*/);)
}
//------------------------------frame_size_in_words-----------------------------
// frame_slots in units of words
*** 609,618 ****
--- 628,643 ----
#ifndef PRODUCT
_trace_opto_output(TraceOptoOutput || method()->has_option("TraceOptoOutput")),
_printer(IdealGraphPrinter::printer()),
#endif
_congraph(NULL),
+ _late_inlines(comp_arena(), 2, 0, NULL),
+ _string_late_inlines(comp_arena(), 2, 0, NULL),
+ _late_inlines_pos(0),
+ _number_of_mh_late_inlines(0),
+ _inlining_progress(false),
+ _inlining_incrementally(false),
_print_inlining_list(NULL),
_print_inlining(0) {
C = this;
CompileWrapper cw(this);
*** 735,767 ****
// to whatever caller is dynamically above us on the stack.
// This is done by a special, unique RethrowNode bound to root.
rethrow_exceptions(kit.transfer_exceptions_into_jvms());
}
! if (!failing() && has_stringbuilder()) {
! {
! // remove useless nodes to make the usage analysis simpler
! ResourceMark rm;
! PhaseRemoveUseless pru(initial_gvn(), &for_igvn);
! }
! {
! ResourceMark rm;
! print_method("Before StringOpts", 3);
! PhaseStringOpts pso(initial_gvn(), &for_igvn);
! print_method("After StringOpts", 3);
}
- // now inline anything that we skipped the first time around
- while (_late_inlines.length() > 0) {
- CallGenerator* cg = _late_inlines.pop();
- cg->do_late_inline();
if (failing()) return;
- }
- }
- assert(_late_inlines.length() == 0, "should have been processed");
- dump_inlining();
print_method("Before RemoveUseless", 3);
// Remove clutter produced by parsing.
if (!failing()) {
--- 760,776 ----
// to whatever caller is dynamically above us on the stack.
// This is done by a special, unique RethrowNode bound to root.
rethrow_exceptions(kit.transfer_exceptions_into_jvms());
}
! assert(IncrementalInline || (_late_inlines.length() == 0 && !has_mh_late_inlines()), "incremental inlining is off");
! if (_late_inlines.length() == 0 && !has_mh_late_inlines() && !failing() && has_stringbuilder()) {
! string_inline(true);
}
if (failing()) return;
print_method("Before RemoveUseless", 3);
// Remove clutter produced by parsing.
if (!failing()) {
*** 904,913 ****
--- 913,925 ----
_printer(NULL),
#endif
_dead_node_list(comp_arena()),
_dead_node_count(0),
_congraph(NULL),
+ _number_of_mh_late_inlines(0),
+ _inlining_progress(false),
+ _inlining_incrementally(false),
_print_inlining_list(NULL),
_print_inlining(0) {
C = this;
#ifndef PRODUCT
*** 1758,1767 ****
--- 1770,1905 ----
igvn.replace_node(n, n->in(1));
}
assert(predicate_count()==0, "should be clean!");
}
+ // StringOpts and late inlining of string methods
+ void Compile::string_inline(bool parse_time) {
+ {
+ // remove useless nodes to make the usage analysis simpler
+ ResourceMark rm;
+ PhaseRemoveUseless pru(initial_gvn(), for_igvn());
+ }
+
+ {
+ ResourceMark rm;
+ print_method("Before StringOpts", 3);
+ PhaseStringOpts pso(initial_gvn(), for_igvn());
+ print_method("After StringOpts", 3);
+ }
+
+ // now inline anything that we skipped the first time around
+ if (!parse_time) {
+ _late_inlines_pos = _late_inlines.length();
+ }
+
+ while (_string_late_inlines.length() > 0) {
+ CallGenerator* cg = _string_late_inlines.pop();
+
+ cg->do_late_inline();
+
+ if (failing()) return;
+ }
+ _string_late_inlines.trunc_to(0);
+ }
+
+ void Compile::incremental_inline_one(PhaseIterGVN& igvn) {
+ assert(IncrementalInline, "incremental inlining should be on");
+ PhaseGVN* gvn = initial_gvn();
+
+ clear_inlining_progress();
+ for_igvn()->clear();
+ gvn->update_with(&igvn);
+
+ int i = 0;
+
+ {
+ for (; i <_late_inlines.length() && !inlining_progress(); i++) {
+
+ CallGenerator* cg = _late_inlines.at(i);
+
+ _late_inlines_pos = i+1;
+
+ cg->do_late_inline();
+
+ if (failing()) return;
+ }
+ int j = 0;
+ for (; i < _late_inlines.length(); i++, j++) {
+ _late_inlines.at_put(j, _late_inlines.at(i));
+ }
+ _late_inlines.trunc_to(j);
+
+ {
+ ResourceMark rm;
+ PhaseRemoveUseless pru(C->initial_gvn(), C->for_igvn());
+ }
+ }
+
+ igvn = PhaseIterGVN(gvn);
+ }
+
+ // Perform incremental inlining until bound on number of live nodes is reached
+ void Compile::incremental_inline(PhaseIterGVN& igvn) {
+ PhaseGVN* gvn = initial_gvn();
+
+ set_inlining_incrementally();
+ set_inlining_progress();
+ uint low_live_nodes = 0;
+
+ while(inlining_progress() && _late_inlines.length() > 0) {
+
+ if (live_nodes() > (uint)LiveNodeCountInliningCutoff) {
+ if (low_live_nodes < (uint)LiveNodeCountInliningCutoff * 8 / 10) {
+ // PhaseIdealLoop is expensive so we only try it once we are
+ // out of loop and we only try it again if the previous helped
+ // got the number of nodes down significantly
+ PhaseIdealLoop ideal_loop( igvn, false, true );
+ if (failing()) return;
+ low_live_nodes = live_nodes();
+ _major_progress = true;
+ }
+
+ if (live_nodes() > (uint)LiveNodeCountInliningCutoff) {
+ break;
+ }
+ }
+
+ incremental_inline_one(igvn);
+
+ if (failing()) return;
+
+ igvn.optimize();
+
+ if (failing()) return;
+ }
+
+ assert( igvn._worklist.size() == 0, "should be done with igvn" );
+
+ if (_string_late_inlines.length() > 0) {
+ assert(has_stringbuilder(), "inconsistent");
+ for_igvn()->clear();
+ initial_gvn()->update_with(&igvn);
+
+ string_inline(false);
+
+ if (failing()) return;
+
+ {
+ ResourceMark rm;
+ PhaseRemoveUseless pru(initial_gvn(), for_igvn());
+ }
+
+ igvn = PhaseIterGVN(gvn);
+
+ igvn.optimize();
+ }
+
+ clear_inlining_incrementally();
+ }
+
+
//------------------------------Optimize---------------------------------------
// Given a graph, optimize it.
void Compile::Optimize() {
TracePhase t1("optimizer", &_t_optimizer, true);
*** 1780,1799 ****
--- 1918,1945 ----
print_method("After Parsing");
{
// Iterative Global Value Numbering, including ideal transforms
// Initialize IterGVN with types and values from parse-time GVN
+
PhaseIterGVN igvn(initial_gvn());
+
{
NOT_PRODUCT( TracePhase t2("iterGVN", &_t_iterGVN, TimeCompiler); )
igvn.optimize();
}
print_method("Iter GVN 1", 2);
if (failing()) return;
+ incremental_inline(igvn);
+
+ print_method("Incremental Inline", 2);
+
+ if (failing()) return;
+
// Perform escape analysis
if (_do_escape_analysis && ConnectionGraph::has_candidates(this)) {
if (has_loops()) {
// Cleanup graph (remove dead nodes).
TracePhase t2("idealLoop", &_t_idealLoop, true);
*** 1912,1921 ****
--- 2058,2068 ----
}
}
} // (End scope of igvn; run destructor if necessary for asserts.)
+ dump_inlining();
// A method with only infinite loops has no edges entering loops from root
{
NOT_PRODUCT( TracePhase t2("graphReshape", &_t_graphReshaping, TimeCompiler); )
if (final_graph_reshaping()) {
assert(failing(), "must bail out w/ explicit message");
*** 3360,3369 ****
--- 3507,3538 ----
}
}
void Compile::dump_inlining() {
if (PrintInlining) {
+ // Print inlining message for candidates that we couldn't inline
+ // for lack of space or non constant receiver
+ for (int i = 0; i < _late_inlines.length(); i++) {
+ CallGenerator* cg = _late_inlines.at(i);
+ cg->print_inlining_late("live nodes > LiveNodeCountInliningCutoff");
+ }
+ Unique_Node_List useful;
+ useful.push(root());
+ for( uint next = 0; next < useful.size(); ++next ) {
+ Node *n = useful.at(next);
+ if (n->isa_Call() != NULL && n->as_Call()->_cg != NULL && n->as_Call()->_cg->call_node() == n) {
+ CallNode* call = n->as_Call();
+ CallGenerator* cg = call->_cg;
+ cg->print_inlining_late("receiver not constant");
+ }
+ uint max = n->len();
+ for( uint i = 0; i < max; ++i ) {
+ Node *m = n->in(i);
+ if( m == NULL ) continue;
+ useful.push(m);
+ }
+ }
for (int i = 0; i < _print_inlining_list->length(); i++) {
tty->print(_print_inlining_list->at(i).ss()->as_string());
}
}
}