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()); } } }