--- a/hotspot/src/share/vm/opto/compile.cpp Fri Dec 21 10:27:49 2012 -0800
+++ b/hotspot/src/share/vm/opto/compile.cpp Sun Dec 23 17:08:22 2012 +0100
@@ -136,7 +136,7 @@
void Compile::register_intrinsic(CallGenerator* cg) {
if (_intrinsics == NULL) {
- _intrinsics = new GrowableArray<CallGenerator*>(60);
+ _intrinsics = new (comp_arena())GrowableArray<CallGenerator*>(comp_arena(), 60, 0, NULL);
}
// This code is stolen from ciObjectFactory::insert.
// Really, GrowableArray should have methods for
@@ -365,6 +365,21 @@
}
}
+void Compile::remove_useless_late_inlines(GrowableArray<CallGenerator*>* inlines, Unique_Node_List &useful) {
+ int shift = 0;
+ 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;
@@ -394,6 +409,9 @@
remove_macro_node(n);
}
}
+ // clean up the late inline lists
+ remove_useless_late_inlines(&_string_late_inlines, useful);
+ remove_useless_late_inlines(&_late_inlines, useful);
debug_only(verify_graph_edges(true/*check for no_dead_code*/);)
}
@@ -611,6 +629,12 @@
_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;
@@ -737,29 +761,13 @@
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(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()) {
+ inline_string_calls(true);
}
- assert(_late_inlines.length() == 0, "should have been processed");
- dump_inlining();
+
+ if (failing()) return;
print_method("Before RemoveUseless", 3);
@@ -906,6 +914,9 @@
_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;
@@ -1760,6 +1771,124 @@
assert(predicate_count()==0, "should be clean!");
}
+// StringOpts and late inlining of string methods
+void Compile::inline_string_calls(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::inline_incrementally_one(PhaseIterGVN& igvn) {
+ assert(IncrementalInline, "incremental inlining should be on");
+ PhaseGVN* gvn = initial_gvn();
+
+ set_inlining_progress(false);
+ for_igvn()->clear();
+ gvn->replace_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::inline_incrementally(PhaseIterGVN& igvn) {
+ PhaseGVN* gvn = initial_gvn();
+
+ set_inlining_incrementally(true);
+ set_inlining_progress(true);
+ 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;
+ }
+ }
+
+ inline_incrementally_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()->replace_with(&igvn);
+
+ inline_string_calls(false);
+
+ if (failing()) return;
+
+ {
+ ResourceMark rm;
+ PhaseRemoveUseless pru(initial_gvn(), for_igvn());
+ }
+
+ igvn = PhaseIterGVN(gvn);
+
+ igvn.optimize();
+ }
+
+ set_inlining_incrementally(false);
+}
+
+
//------------------------------Optimize---------------------------------------
// Given a graph, optimize it.
void Compile::Optimize() {
@@ -1792,6 +1921,12 @@
if (failing()) return;
+ inline_incrementally(igvn);
+
+ print_method("Incremental Inline", 2);
+
+ if (failing()) return;
+
// Perform escape analysis
if (_do_escape_analysis && ConnectionGraph::has_candidates(this)) {
if (has_loops()) {
@@ -1914,6 +2049,7 @@
} // (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); )
@@ -3362,6 +3498,28 @@
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->is_Call() && n->as_Call()->generator() != NULL && n->as_Call()->generator()->call_node() == n) {
+ CallNode* call = n->as_Call();
+ CallGenerator* cg = call->generator();
+ 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());
}