void LLVMState::compile_callframe(STATE, GCToken gct, CompiledCode* start, CallFrame* call_frame, int primitive) { // TODO: Fix compile policy checks if(!start->keywords()->nil_p()) { metrics().m.jit_metrics.methods_failed++; return; } if(debug_search) { std::cout << std::endl << "JIT: triggered: " << enclosure_name(start) << "#" << symbol_debug_str(start->name()) << std::endl; } CallFrame* candidate = find_candidate(state, start, call_frame); if(!candidate || candidate->jitted_p() || candidate->inline_method_p()) { if(config().jit_show_compiling) { llvm::outs() << "[[[ JIT error finding call frame " << enclosure_name(start) << "#" << symbol_debug_str(start->name()); if(!candidate) { llvm::outs() << " no candidate"; } else { if(candidate->jitted_p()) { llvm::outs() << " candidate is jitted"; } if(candidate->inline_method_p()) { llvm::outs() << " candidate is inlined"; } } llvm::outs() << " ]]]\n"; } return; } if(debug_search) { std::cout << "! "; candidate->print_backtrace(state, 1); } if(candidate->compiled_code->machine_code()->call_count <= 1) { if(!start || start->machine_code()->jitted_p()) return; // Ignore it. compile this one. candidate = call_frame; } if(candidate->block_p()) { compile_soon(state, gct, candidate->compiled_code, call_frame, candidate->self()->direct_class(state), candidate->block_env(), true); } else { if(candidate->compiled_code->can_specialize_p()) { compile_soon(state, gct, candidate->compiled_code, call_frame, candidate->self()->direct_class(state)); } else { compile_soon(state, gct, candidate->compiled_code, call_frame, NULL); } } }
void LLVMState::compile_callframe(STATE, CompiledMethod* start, CallFrame* call_frame, int primitive) { if(config().jit_inline_debug) { if(start) { log() << "JIT: target search from " << symbol_cstr(start->name()) << "\n"; } else { log() << "JIT: target search from primitive\n"; } } CallFrame* candidate = find_candidate(start, call_frame); if(!candidate || candidate->jitted_p() || candidate->inline_method_p()) { if(config().jit_inline_debug) { log() << "JIT: unable to find candidate\n"; } return; } if(candidate->cm->backend_method()->call_count <= 1) { if(!start || start->backend_method()->jitted()) return; // Ignore it. compile this one. candidate = call_frame; } if(candidate->block_p()) { compile_soon(state, candidate->cm, candidate->block_env()); } else { compile_soon(state, candidate->cm); } }
void LLVMState::compile_callframe(STATE, CompiledMethod* start, CallFrame* call_frame, int primitive) { if(debug_search) { std::cout << std::endl << "JIT: triggered: " << enclosure_name(start) << "#" << symbol_debug_str(start->name()) << std::endl; } // if(config().jit_inline_debug) { // if(start) { // std::cout << "JIT: target search from " // << symbol_debug_str(start->name()) << "\n"; // } else { // std::cout << "JIT: target search from primitive\n"; // } // } CallFrame* candidate = find_candidate(state, start, call_frame); if(!candidate || candidate->jitted_p() || candidate->inline_method_p()) { if(debug_search) { std::cout << "JIT: invalid candidate returned" << std::endl; } return; } if(debug_search) { std::cout << "! "; candidate->print_backtrace(state, 1); } if(start && candidate->cm != start) { start->backend_method()->call_count = 0; } if(candidate->cm->backend_method()->call_count <= 1) { if(!start || start->backend_method()->jitted()) return; // Ignore it. compile this one. candidate = call_frame; } if(candidate->block_p()) { compile_soon(state, candidate->cm, candidate->block_env(), true); } else { if(candidate->cm->can_specialize_p()) { compile_soon(state, candidate->cm, candidate->self()->class_object(state)); } else { compile_soon(state, candidate->cm, cNil); } } }
void SignalThread::print_backtraces() { STATE = shared_.env()->state; ThreadList* threads = shared_.thread_nexus()->threads(); for(ThreadList::iterator i = threads->begin(); i != threads->end(); ++i) { VM* vm = (*i)->as_vm(); if(!vm) continue; bool first = true; CallFrame* frame = vm->call_frame(); while(frame) { if(first) { logger::fatal("--- %s %d backtrace ---", vm->kind_name(), vm->thread_id()); first = false; } std::ostringstream stream; if(NativeMethodFrame* nmf = frame->native_method_frame()) { stream << static_cast<void*>(frame) << ": "; NativeMethod* nm = try_as<NativeMethod>(nmf->get_object(nmf->method())); if(nm && nm->name()->symbol_p()) { stream << "capi:" << nm->name()->debug_str(state) << " at "; stream << nm->file()->c_str(state); } else { stream << "unknown capi"; } } else if(frame->compiled_code) { if(frame->is_block_p(state)) { stream << "__block__"; } else { if(SingletonClass* sc = try_as<SingletonClass>(frame->module())) { Object* obj = sc->singleton(); if(Module* mod = try_as<Module>(obj)) { stream << mod->debug_str(state) << "."; } else { if(obj == G(main)) { stream << "MAIN."; } else { stream << "#<" << obj->class_object(state)->debug_str(state) << ":" << (void*)obj->id(state)->to_native() << ">."; } } } else if(IncludedModule* im = try_as<IncludedModule>(frame->module())) { stream << im->module()->debug_str(state) << "#"; } else { Symbol* name; std::string mod_name; if(frame->module()->nil_p()) { mod_name = frame->lexical_scope()->module()->debug_str(state); } else { if((name = try_as<Symbol>(frame->module()->module_name()))) { mod_name = name->debug_str(state); } else if((name = try_as<Symbol>( frame->lexical_scope()->module()->module_name()))) { mod_name = name->debug_str(state); } else { mod_name = "<anonymous module>"; } } stream << mod_name << "#"; } Symbol* name = try_as<Symbol>(frame->name()); if(name) { stream << name->debug_str(state); } else { stream << frame->compiled_code->name()->debug_str(state); } } stream << " in "; if(Symbol* file_sym = try_as<Symbol>(frame->compiled_code->file())) { stream << file_sym->debug_str(state) << ":" << frame->line(state); } else { stream << "<unknown>"; } stream << " (+" << frame->ip(); if(frame->is_inline_frame()) { stream << " inline"; } else if(frame->jitted_p()) { stream << " jit"; } stream << ")"; } logger::fatal(stream.str().c_str()); frame = frame->previous; } } }
void CallFrame::print_backtrace(STATE, std::ostream& stream, int total, bool filter) { CallFrame* cf = this; int i = -1; while(cf) { i++; if(total > 0 && i == total) return; if(NativeMethodFrame* nmf = cf->native_method_frame()) { stream << static_cast<void*>(cf) << ": "; NativeMethod* nm = try_as<NativeMethod>(nmf->get_object(nmf->method())); if(nm && nm->name()->symbol_p()) { stream << "capi:" << nm->name()->debug_str(state) << " at "; stream << nm->file()->c_str(state); } else { stream << "unknown capi"; } stream << std::endl; cf = cf->previous; continue; } if(!cf->compiled_code) { cf = cf->previous; continue; } if(filter && cf->compiled_code->kernel_method(state)) { cf = cf->previous; continue; } stream << static_cast<void*>(cf) << ": "; if(cf->is_block_p(state)) { stream << "__block__"; } else { if(SingletonClass* sc = try_as<SingletonClass>(cf->module())) { Object* obj = sc->attached_instance(); if(Module* mod = try_as<Module>(obj)) { stream << mod->debug_str(state) << "."; } else { if(obj == G(main)) { stream << "MAIN."; } else { stream << "#<" << obj->class_object(state)->debug_str(state) << ":" << (void*)obj->id(state)->to_native() << ">."; } } } else if(IncludedModule* im = try_as<IncludedModule>(cf->module())) { stream << im->module()->debug_str(state) << "#"; } else { Symbol* name; std::string mod_name; if(cf->module()->nil_p()) { mod_name = cf->constant_scope()->module()->debug_str(state); } else { if((name = try_as<Symbol>(cf->module()->module_name()))) { mod_name = name->debug_str(state); } else if((name = try_as<Symbol>( cf->constant_scope()->module()->module_name()))) { mod_name = name->debug_str(state); } else { mod_name = "<anonymous module>"; } } stream << mod_name << "#"; } Symbol* name = try_as<Symbol>(cf->name()); if(name) { stream << name->debug_str(state); } else { stream << cf->compiled_code->name()->debug_str(state); } } stream << " in "; if(Symbol* file_sym = try_as<Symbol>(cf->compiled_code->file())) { stream << file_sym->debug_str(state) << ":" << cf->line(state); } else { stream << "<unknown>"; } stream << " (+" << cf->ip(); if(cf->is_inline_frame()) { stream << " inline"; } else if(cf->jitted_p()) { stream << " jit"; } stream << ")"; stream << std::endl; cf = cf->previous; } }
CallFrame* LLVMState::find_candidate(STATE, CallFrame* call_frame, CompiledCode* start) { if(!config_.jit_inline_generic) { return call_frame; } int depth = config().jit_limit_search; if(!start) { throw CompileError("find_candidate: null start"); } if(!call_frame) { throw CompileError("find_candidate: null call frame"); } if(debug_search) { std::cout << "> call_count: " << call_frame->compiled_code->machine_code()->call_count << " size: " << call_frame->compiled_code->machine_code()->total << " sends: " << call_frame->compiled_code->machine_code()->call_site_count() << std::endl; call_frame->print_backtrace(state, 1); } if(start->machine_code()->total > (size_t)config_.jit_limit_inline_method) { if(debug_search) { std::cout << "JIT: STOP. reason: trigger method isn't small: " << start->machine_code()->total << " > " << config_.jit_limit_inline_method << std::endl; } return call_frame; } MachineCode* mcode = start->machine_code(); if(mcode->required_args != mcode->total_args) { if(debug_search) { std::cout << "JIT: STOP. reason: trigger method req_args != total_args" << std::endl; } return call_frame; } if(mcode->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; // Now start looking at callers. while(callee) { if(depth-- == 0) break; CompiledCode* cur = callee->compiled_code; if(!cur) { if(debug_search) { std::cout << "JIT: STOP. reason: synthetic CallFrame hit" << std::endl; } return callee; } MachineCode* mcode = cur->machine_code(); if(debug_search) { std::cout << "> call_count: " << mcode->call_count << " size: " << mcode->total << " sends: " << mcode->call_site_count() << std::endl; call_frame->print_backtrace(state, 1); } /* if(call_frame->block_p() || mcode->required_args != mcode->total_args // has a splat || mcode->call_count < 200 // not called much || mcode->jitted() // already jitted || mcode->parent() // is a block ) return callee; */ if(mcode->required_args != mcode->total_args) { if(debug_search) { std::cout << "JIT: STOP. reason: req_args != total_args" << std::endl; } return callee; } if(mcode->call_count < config_.jit_threshold_inline) { if(debug_search) { std::cout << "JIT: STOP. reason: call_count too small: " << mcode->call_count << " < " << config_.jit_threshold_inline << std::endl; } return callee; } if(mcode->jitted_p()) { if(debug_search) { std::cout << "JIT: STOP. reason: already jitted" << std::endl; } return callee; } if(mcode->no_inline_p()) { if(debug_search) { std::cout << "JIT: STOP. reason: no_inline_p() = true" << std::endl; } return callee; } if(callee->jitted_p() || callee->inline_method_p()) { return callee; } if(mcode->call_site_count() > eMaxInlineSendCount) { if(debug_search) { std::cout << "JIT: STOP. reason: high send count" << std::endl; } return callee; } // if(mcode->required_args != mcode->total_args // has a splat // || mcode->call_count < 200 // not called much // || mcode->jitted() // already jitted // || !mcode->no_inline_p() // method marked as not inlineable // ) return callee; // if(cur->machine_code()->total > SMALL_METHOD_SIZE) { // if(debug_search) { // std::cout << "JIT: STOP. reason: big method: " // << cur->machine_code()->total << " > " // << SMALL_METHOD_SIZE // << "\n"; // } // return call_frame; // } // if(!next || cur->machine_code()->total > SMALL_METHOD_SIZE) return call_frame; callee = callee->previous; } return callee; }