//-----------------------------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; }
void IdealGraphPrinter::visit_node(Node *n, bool edges, VectorSet* temp_set) { if (edges) { // Output edge node_idx_t dest_id = n->_idx; for ( uint i = 0; i < n->len(); i++ ) { if ( n->in(i) ) { Node *source = n->in(i); begin_elem(EDGE_ELEMENT); print_attr(FROM_PROPERTY, source->_idx); print_attr(TO_PROPERTY, dest_id); print_attr(INDEX_PROPERTY, i); end_elem(); } } } else { // Output node begin_head(NODE_ELEMENT); print_attr(NODE_ID_PROPERTY, n->_idx); end_head(); head(PROPERTIES_ELEMENT); Node *node = n; #ifndef PRODUCT Compile::current()->_in_dump_cnt++; print_prop(NODE_NAME_PROPERTY, (const char *)node->Name()); const Type *t = node->bottom_type(); print_prop("type", t->msg()); print_prop("idx", node->_idx); #ifdef ASSERT print_prop("debug_idx", node->_debug_idx); #endif if (C->cfg() != NULL) { Block* block = C->cfg()->get_block_for_node(node); if (block == NULL) { print_prop("block", C->cfg()->get_block(0)->_pre_order); } else { print_prop("block", block->_pre_order); } } const jushort flags = node->flags(); if (flags & Node::Flag_is_Copy) { print_prop("is_copy", "true"); } if (flags & Node::Flag_rematerialize) { print_prop("rematerialize", "true"); } if (flags & Node::Flag_needs_anti_dependence_check) { print_prop("needs_anti_dependence_check", "true"); } if (flags & Node::Flag_is_macro) { print_prop("is_macro", "true"); } if (flags & Node::Flag_is_Con) { print_prop("is_con", "true"); } if (flags & Node::Flag_is_cisc_alternate) { print_prop("is_cisc_alternate", "true"); } if (flags & Node::Flag_is_dead_loop_safe) { print_prop("is_dead_loop_safe", "true"); } if (flags & Node::Flag_may_be_short_branch) { print_prop("may_be_short_branch", "true"); } if (flags & Node::Flag_has_call) { print_prop("has_call", "true"); } if (C->matcher() != NULL) { if (C->matcher()->is_shared(node)) { print_prop("is_shared", "true"); } else { print_prop("is_shared", "false"); } if (C->matcher()->is_dontcare(node)) { print_prop("is_dontcare", "true"); } else { print_prop("is_dontcare", "false"); } #ifdef ASSERT Node* old = C->matcher()->find_old_node(node); if (old != NULL) { print_prop("old_node_idx", old->_idx); } #endif } if (node->is_Proj()) { print_prop("con", (int)node->as_Proj()->_con); } if (node->is_Mach()) { print_prop("idealOpcode", (const char *)NodeClassNames[node->as_Mach()->ideal_Opcode()]); } buffer[0] = 0; stringStream s2(buffer, sizeof(buffer) - 1); node->dump_spec(&s2); if (t != NULL && (t->isa_instptr() || t->isa_klassptr())) { const TypeInstPtr *toop = t->isa_instptr(); const TypeKlassPtr *tkls = t->isa_klassptr(); ciKlass* klass = toop ? toop->klass() : (tkls ? tkls->klass() : NULL ); if( klass && klass->is_loaded() && klass->is_interface() ) { s2.print(" Interface:"); } else if( toop ) { s2.print(" Oop:"); } else if( tkls ) { s2.print(" Klass:"); } t->dump_on(&s2); } else if( t == Type::MEMORY ) { s2.print(" Memory:"); MemNode::dump_adr_type(node, node->adr_type(), &s2); } assert(s2.size() < sizeof(buffer), "size in range"); print_prop("dump_spec", buffer); if (node->is_block_proj()) { print_prop("is_block_proj", "true"); } if (node->is_block_start()) { print_prop("is_block_start", "true"); } const char *short_name = "short_name"; if (strcmp(node->Name(), "Parm") == 0 && node->as_Proj()->_con >= TypeFunc::Parms) { int index = node->as_Proj()->_con - TypeFunc::Parms; if (index >= 10) { print_prop(short_name, "PA"); } else { sprintf(buffer, "P%d", index); print_prop(short_name, buffer); } } else if (strcmp(node->Name(), "IfTrue") == 0) { print_prop(short_name, "T"); } else if (strcmp(node->Name(), "IfFalse") == 0) { print_prop(short_name, "F"); } else if ((node->is_Con() && node->is_Type()) || node->is_Proj()) { if (t->base() == Type::Int && t->is_int()->is_con()) { const TypeInt *typeInt = t->is_int(); assert(typeInt->is_con(), "must be constant"); jint value = typeInt->get_con(); // max. 2 chars allowed if (value >= -9 && value <= 99) { sprintf(buffer, "%d", value); print_prop(short_name, buffer); } else { print_prop(short_name, "I"); } } else if (t == Type::TOP) { print_prop(short_name, "^"); } else if (t->base() == Type::Long && t->is_long()->is_con()) { const TypeLong *typeLong = t->is_long(); assert(typeLong->is_con(), "must be constant"); jlong value = typeLong->get_con(); // max. 2 chars allowed if (value >= -9 && value <= 99) { sprintf(buffer, JLONG_FORMAT, value); print_prop(short_name, buffer); } else { print_prop(short_name, "L"); } } else if (t->base() == Type::KlassPtr) { const TypeKlassPtr *typeKlass = t->is_klassptr(); print_prop(short_name, "CP"); } else if (t->base() == Type::Control) { print_prop(short_name, "C"); } else if (t->base() == Type::Memory) { print_prop(short_name, "M"); } else if (t->base() == Type::Abio) { print_prop(short_name, "IO"); } else if (t->base() == Type::Return_Address) { print_prop(short_name, "RA"); } else if (t->base() == Type::AnyPtr) { print_prop(short_name, "P"); } else if (t->base() == Type::RawPtr) { print_prop(short_name, "RP"); } else if (t->base() == Type::AryPtr) { print_prop(short_name, "AP"); } } JVMState* caller = NULL; if (node->is_SafePoint()) { caller = node->as_SafePoint()->jvms(); } else { Node_Notes* notes = C->node_notes_at(node->_idx); if (notes != NULL) { caller = notes->jvms(); } } if (caller != NULL) { stringStream bciStream; ciMethod* last = NULL; int last_bci; while(caller) { if (caller->has_method()) { last = caller->method(); last_bci = caller->bci(); } bciStream.print("%d ", caller->bci()); caller = caller->caller(); } print_prop("bci", bciStream.as_string()); if (last != NULL && last->has_linenumber_table() && last_bci >= 0) { print_prop("line", last->line_number_from_bci(last_bci)); } } #ifdef ASSERT if (node->debug_orig() != NULL) { temp_set->Clear(); stringStream dorigStream; Node* dorig = node->debug_orig(); while (dorig && temp_set->test_set(dorig->_idx)) { dorigStream.print("%d ", dorig->_idx); } print_prop("debug_orig", dorigStream.as_string()); } #endif if (_chaitin && _chaitin != (PhaseChaitin *)0xdeadbeef) { buffer[0] = 0; _chaitin->dump_register(node, buffer); print_prop("reg", buffer); uint lrg_id = 0; if (node->_idx < _chaitin->_lrg_map.size()) { lrg_id = _chaitin->_lrg_map.live_range_id(node); } print_prop("lrg", lrg_id); } Compile::current()->_in_dump_cnt--; #endif tail(PROPERTIES_ELEMENT); tail(NODE_ELEMENT); } }