//-----------------------------try_to_inline----------------------------------- // return true if ok // Relocated from "InliningClosure::try_to_inline" bool InlineTree::try_to_inline(ciMethod* callee_method, ciMethod* caller_method, int caller_bci, JVMState* jvms, ciCallProfile& profile, WarmCallInfo* wci_result, bool& should_delay) { if (ClipInlining && (int)count_inline_bcs() >= DesiredMethodLimit) { if (!callee_method->force_inline() || !IncrementalInline) { set_msg("size > DesiredMethodLimit"); return false; } else if (!C->inlining_incrementally()) { should_delay = true; } } _forced_inline = false; // Reset if (!should_inline(callee_method, caller_method, caller_bci, profile, wci_result)) { return false; } if (should_not_inline(callee_method, caller_method, jvms, wci_result)) { return false; } if (InlineAccessors && callee_method->is_accessor()) { // accessor methods are not subject to any of the following limits. set_msg("accessor"); return true; } // suppress a few checks for accessors and trivial methods if (callee_method->code_size() > MaxTrivialSize) { // don't inline into giant methods if (C->over_inlining_cutoff()) { if ((!callee_method->force_inline() && !caller_method->is_compiled_lambda_form()) || !IncrementalInline) { set_msg("NodeCountInliningCutoff"); return false; } else { should_delay = true; } } if ((!UseInterpreter || CompileTheWorld) && is_init_with_ea(callee_method, caller_method, C)) { // Escape Analysis stress testing when running Xcomp or CTW: // inline constructors even if they are not reached. } else if (forced_inline()) { // Inlining was forced by CompilerOracle, ciReplay or annotation } else if (profile.count() == 0) { // don't inline unreached call sites set_msg("call site not reached"); return false; } } if (!C->do_inlining() && InlineAccessors) { set_msg("not an accessor"); return false; } // Limit inlining depth in case inlining is forced or // _max_inline_level was increased to compensate for lambda forms. if (inline_level() > MaxForceInlineLevel) { set_msg("MaxForceInlineLevel"); return false; } if (inline_level() > _max_inline_level) { if (!callee_method->force_inline() || !IncrementalInline) { set_msg("inlining too deep"); return false; } else if (!C->inlining_incrementally()) { should_delay = true; } } // detect direct and indirect recursive inlining { // count the current method and the callee const bool is_compiled_lambda_form = callee_method->is_compiled_lambda_form(); int inline_level = 0; if (!is_compiled_lambda_form) { if (method() == callee_method) { inline_level++; } } // count callers of current method and callee Node* callee_argument0 = is_compiled_lambda_form ? jvms->map()->argument(jvms, 0)->uncast() : NULL; for (JVMState* j = jvms->caller(); j != NULL && j->has_method(); j = j->caller()) { if (j->method() == callee_method) { if (is_compiled_lambda_form) { // Since compiled lambda forms are heavily reused we allow recursive inlining. If it is truly // a recursion (using the same "receiver") we limit inlining otherwise we can easily blow the // compiler stack. Node* caller_argument0 = j->map()->argument(j, 0)->uncast(); if (caller_argument0 == callee_argument0) { inline_level++; } } else { inline_level++; } } } if (inline_level > MaxRecursiveInlineLevel) { set_msg("recursive inlining is too deep"); return false; } } int size = callee_method->code_size_for_inlining(); if (ClipInlining && (int)count_inline_bcs() + size >= DesiredMethodLimit) { if (!callee_method->force_inline() || !IncrementalInline) { set_msg("size > DesiredMethodLimit"); return false; } else if (!C->inlining_incrementally()) { should_delay = true; } } // ok, inline this method return true; }
JVMState* PredicatedIntrinsicGenerator::generate(JVMState* jvms) { // The code we want to generate here is: // if (receiver == NULL) // uncommon_Trap // if (predicate(0)) // do_intrinsic(0) // else // if (predicate(1)) // do_intrinsic(1) // ... // else // do_java_comp GraphKit kit(jvms); PhaseGVN& gvn = kit.gvn(); CompileLog* log = kit.C->log(); if (log != NULL) { log->elem("predicated_intrinsic bci='%d' method='%d'", jvms->bci(), log->identify(method())); } if (!method()->is_static()) { // We need an explicit receiver null_check before checking its type in predicate. // We share a map with the caller, so his JVMS gets adjusted. Node* receiver = kit.null_check_receiver_before_call(method()); if (kit.stopped()) { return kit.transfer_exceptions_into_jvms(); } } int n_predicates = _intrinsic->predicates_count(); assert(n_predicates > 0, "sanity"); JVMState** result_jvms = NEW_RESOURCE_ARRAY(JVMState*, (n_predicates+1)); // Region for normal compilation code if intrinsic failed. Node* slow_region = new (kit.C) RegionNode(1); int results = 0; for (int predicate = 0; (predicate < n_predicates) && !kit.stopped(); predicate++) { #ifdef ASSERT JVMState* old_jvms = kit.jvms(); SafePointNode* old_map = kit.map(); Node* old_io = old_map->i_o(); Node* old_mem = old_map->memory(); Node* old_exc = old_map->next_exception(); #endif Node* else_ctrl = _intrinsic->generate_predicate(kit.sync_jvms(), predicate); #ifdef ASSERT // Assert(no_new_memory && no_new_io && no_new_exceptions) after generate_predicate. assert(old_jvms == kit.jvms(), "generate_predicate should not change jvm state"); SafePointNode* new_map = kit.map(); assert(old_io == new_map->i_o(), "generate_predicate should not change i_o"); assert(old_mem == new_map->memory(), "generate_predicate should not change memory"); assert(old_exc == new_map->next_exception(), "generate_predicate should not add exceptions"); #endif if (!kit.stopped()) { PreserveJVMState pjvms(&kit); // Generate intrinsic code: JVMState* new_jvms = _intrinsic->generate(kit.sync_jvms()); if (new_jvms == NULL) { // Intrinsic failed, use normal compilation path for this predicate. slow_region->add_req(kit.control()); } else { kit.add_exception_states_from(new_jvms); kit.set_jvms(new_jvms); if (!kit.stopped()) { result_jvms[results++] = kit.jvms(); } } } if (else_ctrl == NULL) { else_ctrl = kit.C->top(); } kit.set_control(else_ctrl); } if (!kit.stopped()) { // Final 'else' after predicates. slow_region->add_req(kit.control()); } if (slow_region->req() > 1) { PreserveJVMState pjvms(&kit); // Generate normal compilation code: kit.set_control(gvn.transform(slow_region)); JVMState* new_jvms = _cg->generate(kit.sync_jvms()); if (kit.failing()) return NULL; // might happen because of NodeCountInliningCutoff assert(new_jvms != NULL, "must be"); kit.add_exception_states_from(new_jvms); kit.set_jvms(new_jvms); if (!kit.stopped()) { result_jvms[results++] = kit.jvms(); } } if (results == 0) { // All paths ended in uncommon traps. (void) kit.stop(); return kit.transfer_exceptions_into_jvms(); } if (results == 1) { // Only one path kit.set_jvms(result_jvms[0]); return kit.transfer_exceptions_into_jvms(); } // Merge all paths. kit.C->set_has_split_ifs(true); // Has chance for split-if optimization RegionNode* region = new (kit.C) RegionNode(results + 1); Node* iophi = PhiNode::make(region, kit.i_o(), Type::ABIO); for (int i = 0; i < results; i++) { JVMState* jvms = result_jvms[i]; int path = i + 1; SafePointNode* map = jvms->map(); region->init_req(path, map->control()); iophi->set_req(path, map->i_o()); if (i == 0) { kit.set_jvms(jvms); } else { kit.merge_memory(map->merged_memory(), region, path); } } kit.set_control(gvn.transform(region)); kit.set_i_o(gvn.transform(iophi)); // Transform new memory Phis. for (MergeMemStream mms(kit.merged_memory()); mms.next_non_empty();) { Node* phi = mms.memory(); if (phi->is_Phi() && phi->in(0) == region) { mms.set_memory(gvn.transform(phi)); } } // Merge debug info. Node** ins = NEW_RESOURCE_ARRAY(Node*, results); uint tos = kit.jvms()->stkoff() + kit.sp(); Node* map = kit.map(); uint limit = map->req(); for (uint i = TypeFunc::Parms; i < limit; i++) { // Skip unused stack slots; fast forward to monoff(); if (i == tos) { i = kit.jvms()->monoff(); if( i >= limit ) break; } Node* n = map->in(i); ins[0] = n; const Type* t = gvn.type(n); bool needs_phi = false; for (int j = 1; j < results; j++) { JVMState* jvms = result_jvms[j]; Node* jmap = jvms->map(); Node* m = NULL; if (jmap->req() > i) { m = jmap->in(i); if (m != n) { needs_phi = true; t = t->meet_speculative(gvn.type(m)); } } ins[j] = m; } if (needs_phi) { Node* phi = PhiNode::make(region, n, t); for (int j = 1; j < results; j++) { phi->set_req(j + 1, ins[j]); } map->set_req(i, gvn.transform(phi)); } } return kit.transfer_exceptions_into_jvms(); }