CallFrame* LLVMState::find_candidate(CompiledMethod* start, CallFrame* call_frame) { if(!config_.jit_inline_generic) { return call_frame; } int depth = cInlineMaxDepth; if(!start) { start = call_frame->cm; call_frame = call_frame->previous; depth--; } if(!call_frame || start->backend_method()->total > SMALL_METHOD_SIZE) { return call_frame; } CallFrame* caller = call_frame; while(depth-- > 0) { CompiledMethod* cur = call_frame->cm; VMMethod* vmm = cur->backend_method(); /* if(call_frame->block_p() || vmm->required_args != vmm->total_args // has a splat || vmm->call_count < 200 // not called much || vmm->jitted() // already jitted || vmm->parent() // is a block ) return caller; */ if(vmm->required_args != vmm->total_args // has a splat || vmm->call_count < 200 // not called much || vmm->jitted() // already jitted || !vmm->no_inline_p() // method marked as not inlinable ) return caller; CallFrame* next = call_frame->previous; if(!next|| cur->backend_method()->total > SMALL_METHOD_SIZE) return call_frame; caller = call_frame; call_frame = next; } return caller; }
Location* Location::create(STATE, CallFrame* call_frame, bool include_variables) { if(NativeMethodFrame* nmf = call_frame->native_method_frame()) { return create(state, nmf); } Location* loc = state->new_object<Location>(G(location)); loc->method_module(state, call_frame->module()); loc->receiver(state, call_frame->self()); loc->method(state, call_frame->cm); loc->ip(state, Fixnum::from(call_frame->ip())); loc->flags(state, Fixnum::from(0)); if(call_frame->is_block_p(state)) { loc->name(state, call_frame->top_scope(state)->method()->name()); loc->set_is_block(state); } else { loc->name(state, call_frame->name()); } VMMethod* vmm = call_frame->cm->backend_method(); if(vmm && vmm->jitted()) { loc->set_is_jit(state); } if(include_variables) { // Use promote_scope because it can figure out of the generated // VariableScope should be isolated by default (true atm for JITd // frames) loc->variables(state, call_frame->promote_scope(state)); } loc->static_scope(state, call_frame->static_scope()); return loc; }
Location* Location::create(STATE, CallFrame* call_frame) { Location* loc = state->new_object<Location>(G(location)); loc->method_module(state, call_frame->module()); loc->receiver(state, call_frame->self()); loc->method(state, call_frame->cm); loc->ip(state, Fixnum::from(call_frame->ip() - 1)); if(call_frame->is_block_p(state)) { loc->name(state, call_frame->top_scope(state)->method()->name()); loc->is_block(state, Qtrue); } else { loc->name(state, call_frame->name()); loc->is_block(state, Qfalse); } VMMethod* vmm = call_frame->cm->backend_method(); if(vmm && vmm->jitted()) { loc->is_jit(state, Qtrue); } else { loc->is_jit(state, Qfalse); } return loc; }
VMMethod* LLVMState::find_candidate(VMMethod* start, CallFrame* call_frame) { VMMethod* found = start; int depth = 0; bool consider_block_parents = config_.jit_inline_blocks; // No upper call_frames or generic inlining is off, use the start. // With generic inlining off, there is no way to inline back to start, // so we don't both trying. if(!config_.jit_inline_generic) { if(!start) start = call_frame->cm->backend_method(); return find_first_non_block(call_frame); } /* std::cerr << "JIT target search:\n"; if(start) { show_method(this, start); } else { std::cerr << " <primitive>\n"; } */ VMMethod* next = call_frame->cm->backend_method(); VMMethod* parent = 0; while(depth < cInlineMaxDepth) { // show_method(this, next); // Basic requirements if(next->required_args != next->total_args || next->call_count < 200 || next->jitted()) break; // Jump to defining methods of blocks? parent = next->parent(); if(parent) { if(consider_block_parents) { // See if parent is in this call_frame chain properly.. if(CallFrame* pf = validate_block_parent(call_frame, parent)) { depth++; // Method parents are valuable, so always use them if we find them. if(!parent->parent()) { found = parent; } // show_method(this, parent, " parent!"); call_frame = pf; } } else { // We hit a block, just bail. break; } } else { found = next; } call_frame = call_frame->previous; if(!call_frame) break; next = call_frame->cm->backend_method(); depth++; } if(!found && !next->parent()) return next; return found; }
CallFrame* LLVMState::find_candidate(STATE, CompiledMethod* start, CallFrame* call_frame) { if(!config_.jit_inline_generic) { return call_frame; } int depth = cInlineMaxDepth; if(!start) rubinius::bug("null start"); if(!call_frame) rubinius::bug("null call_frame"); // if(!start) { // start = call_frame->cm; // call_frame = call_frame->previous; // depth--; // } if(debug_search) { std::cout << "> call_count: " << call_frame->cm->backend_method()->call_count << " size: " << call_frame->cm->backend_method()->total << " sends: " << call_frame->cm->backend_method()->inline_cache_count() << std::endl; call_frame->print_backtrace(state, 1); } if(start->backend_method()->total > (size_t)config_.jit_max_method_inline_size) { if(debug_search) { std::cout << "JIT: STOP. reason: trigger method isn't small: " << start->backend_method()->total << " > " << config_.jit_max_method_inline_size << std::endl; } return call_frame; } VMMethod* vmm = start->backend_method(); if(vmm->required_args != vmm->total_args) { if(debug_search) { std::cout << "JIT: STOP. reason: trigger method req_args != total_args" << std::endl; } return call_frame; } if(vmm->no_inline_p()) { if(debug_search) { std::cout << "JIT: STOP. reason: trigger method no_inline_p() = true" << std::endl; } return call_frame; } CallFrame* callee = call_frame; call_frame = call_frame->previous; if(!call_frame) return callee; // Now start looking at callers. while(depth-- > 0) { CompiledMethod* cur = call_frame->cm; if(!cur) { if(debug_search) { std::cout << "JIT: STOP. reason: synthetic CallFrame hit" << std::endl; } return callee; } VMMethod* vmm = cur->backend_method(); if(debug_search) { std::cout << "> call_count: " << vmm->call_count << " size: " << vmm->total << " sends: " << vmm->inline_cache_count() << std::endl; call_frame->print_backtrace(state, 1); } /* if(call_frame->block_p() || vmm->required_args != vmm->total_args // has a splat || vmm->call_count < 200 // not called much || vmm->jitted() // already jitted || vmm->parent() // is a block ) return callee; */ if(vmm->required_args != vmm->total_args) { if(debug_search) { std::cout << "JIT: STOP. reason: req_args != total_args" << std::endl; } return callee; } if(vmm->call_count < config_.jit_call_inline_threshold) { if(debug_search) { std::cout << "JIT: STOP. reason: call_count too small: " << vmm->call_count << " < " << config_.jit_call_inline_threshold << std::endl; } return callee; } if(vmm->jitted()) { if(debug_search) { std::cout << "JIT: STOP. reason: already jitted" << std::endl; } return callee; } if(vmm->no_inline_p()) { if(debug_search) { std::cout << "JIT: STOP. reason: no_inline_p() = true" << std::endl; } return callee; } if(vmm->inline_cache_count() > eMaxInlineSendCount) { if(debug_search) { std::cout << "JIT: STOP. reason: high send count" << std::endl; } return call_frame; } // if(vmm->required_args != vmm->total_args // has a splat // || vmm->call_count < 200 // not called much // || vmm->jitted() // already jitted // || !vmm->no_inline_p() // method marked as not inlineable // ) return callee; CallFrame* prev = call_frame->previous; if(!prev) { if(debug_search) { std::cout << "JIT: STOP. reason: toplevel method" << std::endl; } return call_frame; } // if(cur->backend_method()->total > SMALL_METHOD_SIZE) { // if(debug_search) { // std::cout << "JIT: STOP. reason: big method: " // << cur->backend_method()->total << " > " // << SMALL_METHOD_SIZE // << "\n"; // } // return call_frame; // } // if(!next || cur->backend_method()->total > SMALL_METHOD_SIZE) return call_frame; callee->cm->backend_method()->call_count = 0; callee = call_frame; call_frame = prev; } return callee; }