void Compiler::compile_method(BackgroundCompileRequest* req) { CompiledCode* code = req->method(); if(ctx_->llvm_state()->config().jit_inline_debug) { struct timeval tv; gettimeofday(&tv, NULL); ctx_->llvm_state()->log() << "JIT: compiling " << ctx_->llvm_state()->enclosure_name(code) << "#" << ctx_->llvm_state()->symbol_debug_str(code->name()) << " (" << tv.tv_sec << "." << tv.tv_usec << ")\n"; } JITMethodInfo info(ctx_, code, code->machine_code()); info.is_block = false; if(Class* cls = req->receiver_class()) { info.set_self_class(cls); } ctx_->set_root(&info); jit::MethodBuilder work(ctx_, info); work.setup(); compile_builder(info, work); ctx_->set_root(NULL); }
CompiledCode* UnMarshaller::get_cmethod() { size_t ver; stream >> ver; CompiledCode* cm = CompiledCode::create(state); cm->metadata(state, unmarshal()); cm->primitive(state, (Symbol*)unmarshal()); cm->name(state, (Symbol*)unmarshal()); cm->iseq(state, (InstructionSequence*)unmarshal()); cm->stack_size(state, (Fixnum*)unmarshal()); cm->local_count(state, (Fixnum*)unmarshal()); cm->required_args(state, (Fixnum*)unmarshal()); cm->post_args(state, (Fixnum*)unmarshal()); cm->total_args(state, (Fixnum*)unmarshal()); cm->splat(state, unmarshal()); cm->literals(state, (Tuple*)unmarshal()); cm->lines(state, (Tuple*)unmarshal()); cm->file(state, (Symbol*)unmarshal()); cm->local_names(state, (Tuple*)unmarshal()); cm->post_marshal(state); return cm; }
void Compiler::compile_method(LLVMState* ls, BackgroundCompileRequest* req) { CompiledCode* cm = req->method(); if(ls->config().jit_inline_debug) { struct timeval tv; gettimeofday(&tv, NULL); ls->log() << "JIT: compiling " << ls->enclosure_name(cm) << "#" << ls->symbol_debug_str(cm->name()) << " (" << tv.tv_sec << "." << tv.tv_usec << ")\n"; } JITMethodInfo info(ctx_, cm, cm->backend_method()); info.is_block = false; if(Class* cls = req->receiver_class()) { info.set_self_class(cls); } ctx_.set_root(&info); jit::MethodBuilder work(ls, info); work.setup(); compile_builder(ctx_, ls, info, work); ctx_.set_root(NULL); }
CompiledCode* UnMarshaller::get_compiled_code() { size_t ver; stream >> ver; CompiledCode* code = CompiledCode::create(state); code->metadata(state, unmarshal()); code->primitive(state, force_as<Symbol>(unmarshal())); code->name(state, force_as<Symbol>(unmarshal())); code->iseq(state, force_as<InstructionSequence>(unmarshal())); code->stack_size(state, force_as<Fixnum>(unmarshal())); code->local_count(state, force_as<Fixnum>(unmarshal())); code->required_args(state, force_as<Fixnum>(unmarshal())); code->post_args(state, force_as<Fixnum>(unmarshal())); code->total_args(state, force_as<Fixnum>(unmarshal())); code->splat(state, force_as<Fixnum>(unmarshal())); code->literals(state, force_as<Tuple>(unmarshal())); code->lines(state, force_as<Tuple>(unmarshal())); code->file(state, force_as<Symbol>(unmarshal())); code->local_names(state, force_as<Tuple>(unmarshal())); code->post_marshal(state); return code; }
void CompiledCode::Info::show(STATE, Object* self, int level) { CompiledCode* code = as<CompiledCode>(self); class_header(state, self); indent_attribute(++level, "file"); code->file()->show(state, level); indent_attribute(level, "iseq"); code->iseq()->show(state, level); indent_attribute(level, "lines"); code->lines()->show_simple(state, level); indent_attribute(level, "literals"); code->literals()->show_simple(state, level); indent_attribute(level, "local_count"); code->local_count()->show(state, level); indent_attribute(level, "local_names"); code->local_names()->show_simple(state, level); indent_attribute(level, "name"); code->name()->show(state, level); indent_attribute(level, "required_args"); code->required_args()->show(state, level); indent_attribute(level, "scope"); code->scope()->show(state, level); indent_attribute(level, "splat"); code->splat()->show(state, level); indent_attribute(level, "stack_size"); code->stack_size()->show(state, level); indent_attribute(level, "total_args"); code->total_args()->show(state, level); indent_attribute(level, "internalized"); if(!code->machine_code_) { std::cout << "no\n"; } else { std::cout << "yes\n"; #ifdef ENABLE_LLVM MachineCode* v = code->machine_code(); for(int i = 0; i < MachineCode::cMaxSpecializations; i++) { if(!v->specializations[i].jit_data) continue; llvm::Function* func = v->specializations[i].jit_data->llvm_function(); llvm::outs() << "<LLVM>\n" << *func << "</LLVM>\n<MachineCode>\n"; LLVMState::show_machine_code( v->specializations[i].jit_data->native_func(), v->specializations[i].jit_data->native_size()); llvm::outs() << "</MachineCode>\n"; } #endif } close_body(level); }
void LLVMState::run(STATE) { GCTokenImpl gct; JITCompileRequest* compile_request = nil<JITCompileRequest>(); OnStack<1> os(state, compile_request); metrics().init(metrics::eJITMetrics); state->gc_dependent(gct, 0); bool show_machine_code_ = jit_dump_code() & cMachineCode; while(!thread_exit_) { current_compiler_ = 0; { GCIndependent guard(state, 0); { utilities::thread::Mutex::LockGuard lg(compile_lock_); while(compile_list_.get()->empty_p()) { compile_cond_.wait(compile_lock_); if(thread_exit_) break; } } } if(thread_exit_) break; { utilities::thread::Mutex::LockGuard guard(request_lock_); compile_request = try_as<JITCompileRequest>(compile_list_.get()->shift(state)); if(!compile_request || compile_request->nil_p()) continue; } utilities::thread::Condition* cond = compile_request->waiter(); // Don't proceed until requester has reached the wait_cond if(cond) wait_mutex.lock(); Context ctx(this); jit::Compiler jit(&ctx); current_compiler_ = &jit; uint32_t class_id = 0; uint32_t serial_id = 0; void* func = 0; try { if(compile_request->receiver_class() && !compile_request->receiver_class()->nil_p()) { // Apparently already compiled, probably some race if(compile_request->method()->find_specialized( compile_request->receiver_class())) { if(config().jit_show_compiling) { CompiledCode* code = compile_request->method(); llvm::outs() << "[[[ JIT already compiled " << enclosure_name(code) << "#" << symbol_debug_str(code->name()) << (compile_request->is_block() ? " (block)" : " (method)") << " ]]]\n"; } // If someone was waiting on this, wake them up. if(cond) { wait_mutex.unlock(); cond->signal(); } current_compiler_ = 0; continue; } class_id = compile_request->receiver_class()->class_id(); serial_id = compile_request->receiver_class()->serial_id(); } { timer::StopWatch<timer::microseconds> timer( metrics().m.jit_metrics.time_last_us, metrics().m.jit_metrics.time_total_us); jit.compile(compile_request); bool indy = !config().jit_sync; func = jit.generate_function(indy); } // We were unable to compile this function, likely // because it's got something we don't support. if(!func) { if(config().jit_show_compiling) { CompiledCode* code = compile_request->method(); llvm::outs() << "[[[ JIT error background compiling " << enclosure_name(code) << "#" << symbol_debug_str(code->name()) << (compile_request->is_block() ? " (block)" : " (method)") << " ]]]\n"; } // If someone was waiting on this, wake them up. if(cond) { wait_mutex.unlock(); cond->signal(); } current_compiler_ = 0; continue; } } catch(LLVMState::CompileError& e) { utilities::logger::warn("JIT: compile error: %s", e.error()); metrics().m.jit_metrics.methods_failed++; // If someone was waiting on this, wake them up. if(cond) { wait_mutex.unlock(); cond->signal(); } current_compiler_ = 0; continue; } if(show_machine_code_) { jit.show_machine_code(); } // If the method has had jit'ing request disabled since we started // JIT'ing it, discard our work. if(!compile_request->machine_code()->jit_disabled()) { jit::RuntimeDataHolder* rd = ctx.runtime_data_holder(); atomic::memory_barrier(); start_method_update(); if(!compile_request->is_block()) { if(class_id) { compile_request->method()->add_specialized(state, class_id, serial_id, reinterpret_cast<executor>(func), rd); } else { compile_request->method()->set_unspecialized(reinterpret_cast<executor>(func), rd); } } else { compile_request->method()->set_unspecialized(reinterpret_cast<executor>(func), rd); } compile_request->machine_code()->clear_compiling(); end_method_update(); rd->run_write_barrier(shared().om, compile_request->method()); if(config().jit_show_compiling) { CompiledCode* code = compile_request->method(); llvm::outs() << "[[[ JIT finished background compiling " << enclosure_name(code) << "#" << symbol_debug_str(code->name()) << (compile_request->is_block() ? " (block)" : " (method)") << " ]]]\n"; } } // If someone was waiting on this, wake them up. if(cond) { wait_mutex.unlock(); cond->signal(); } current_compiler_ = 0; metrics().m.jit_metrics.methods_compiled++; } }
virtual void perform() { const char* thread_name = "rbx.jit"; ManagedThread::set_current(ls_, thread_name); ls_->set_run_state(ManagedThread::eIndependent); RUBINIUS_THREAD_START(thread_name, ls_->thread_id(), 1); #ifndef RBX_WINDOWS sigset_t set; sigfillset(&set); pthread_sigmask(SIG_SETMASK, &set, NULL); #endif for(;;) { // forever BackgroundCompileRequest* req = 0; // Lock, wait, get a request, unlock { utilities::thread::Mutex::LockGuard guard(mutex_); if(pause_) { state = cPaused; paused_ = true; pause_condition_.broadcast(); if(stop_) goto halt; while(pause_) { condition_.wait(mutex_); if(stop_) goto halt; } state = cUnknown; paused_ = false; } // If we've been asked to stop, do so now. if(stop_) goto halt; while(pending_requests_.empty()) { state = cIdle; // unlock and wait... condition_.wait(mutex_); if(stop_) goto halt; } // now locked again, shift a request req = pending_requests_.front(); state = cRunning; } // This isn't ideal, but it's the safest. Keep the GC from // running while we're building the IR. ls_->gc_dependent(); Context ctx(ls_); jit::Compiler jit(&ctx); // mutex now unlock, allowing others to push more requests // current_req_ = req; current_compiler_ = &jit; int spec_id = 0; Class* cls = req->receiver_class(); if(cls && !cls->nil_p()) { spec_id = cls->class_id(); } void* func = 0; { timer::Running<1000000> timer(ls_->shared().stats.jit_time_spent); jit.compile(req); func = jit.generate_function(); } // We were unable to compile this function, likely // because it's got something we don't support. if(!func) { if(ls_->config().jit_show_compiling) { CompiledCode* code = req->method(); llvm::outs() << "[[[ JIT error background compiling " << ls_->enclosure_name(code) << "#" << ls_->symbol_debug_str(code->name()) << (req->is_block() ? " (block)" : " (method)") << " ]]]\n"; } // If someone was waiting on this, wake them up. if(utilities::thread::Condition* cond = req->waiter()) { cond->signal(); } current_req_ = 0; current_compiler_ = 0; pending_requests_.pop_front(); delete req; // We don't depend on the GC here, so let it run independent // of us. ls_->gc_independent(); continue; } if(show_machine_code_) { jit.show_machine_code(); } // If the method has had jit'ing request disabled since we started // JIT'ing it, discard our work. if(!req->machine_code()->jit_disabled()) { jit::RuntimeDataHolder* rd = ctx.runtime_data_holder(); atomic::memory_barrier(); ls_->start_method_update(); if(!req->is_block()) { if(spec_id) { req->method()->add_specialized(spec_id, reinterpret_cast<executor>(func), rd); } else { req->method()->set_unspecialized(reinterpret_cast<executor>(func), rd); } } else { req->method()->set_unspecialized(reinterpret_cast<executor>(func), rd); } req->machine_code()->clear_compiling(); // assert(req->method()->jit_data()); ls_->end_method_update(); rd->run_write_barrier(ls_->write_barrier(), req->method()); ls_->shared().stats.jitted_methods++; if(ls_->config().jit_show_compiling) { CompiledCode* code = req->method(); llvm::outs() << "[[[ JIT finished background compiling " << ls_->enclosure_name(code) << "#" << ls_->symbol_debug_str(code->name()) << (req->is_block() ? " (block)" : " (method)") << " ]]]\n"; } } // If someone was waiting on this, wake them up. if(utilities::thread::Condition* cond = req->waiter()) { cond->signal(); } current_req_ = 0; current_compiler_ = 0; pending_requests_.pop_front(); delete req; // We don't depend on the GC here, so let it run independent // of us. ls_->gc_independent(); } halt: RUBINIUS_THREAD_STOP(thread_name, ls_->thread_id(), 1); }
void Compiler::compile_method(BackgroundCompileRequest* req) { CompiledCode* code = req->method(); if(ctx_->llvm_state()->config().jit_inline_debug) { struct timeval tv; gettimeofday(&tv, NULL); ctx_->llvm_state()->log() << "JIT: compiling " << ctx_->llvm_state()->enclosure_name(code) << "#" << ctx_->llvm_state()->symbol_debug_str(code->name()) << " (" << tv.tv_sec << "." << tv.tv_usec << ")\n"; } #ifdef HAVE_DTRACE if(RUBINIUS_JIT_FUNCTION_BEGIN_ENABLED()) { RBX_DTRACE_CONST char* class_name = const_cast<RBX_DTRACE_CONST char*>( ctx_->llvm_state()->enclosure_name(code).c_str()); RBX_DTRACE_CONST char* method_name = const_cast<RBX_DTRACE_CONST char*>( ctx_->llvm_state()->symbol_debug_str(code->name()).c_str()); RBX_DTRACE_CONST char* file_name = const_cast<RBX_DTRACE_CONST char*>( ctx_->llvm_state()->symbol_debug_str(code->file()).c_str()); int line = code->start_line(); RUBINIUS_JIT_FUNCTION_BEGIN(class_name, method_name, file_name, line); } #endif JITMethodInfo info(ctx_, code, code->machine_code()); info.is_block = false; info.hits = req->hits(); if(Class* cls = req->receiver_class()) { info.set_self_class(cls); } ctx_->set_root(&info); jit::MethodBuilder work(ctx_, info); work.setup(); compile_builder(info, work); ctx_->set_root(NULL); #ifdef HAVE_DTRACE if(RUBINIUS_JIT_FUNCTION_END_ENABLED()) { RBX_DTRACE_CONST char* class_name = const_cast<RBX_DTRACE_CONST char*>( ctx_->llvm_state()->enclosure_name(code).c_str()); RBX_DTRACE_CONST char* method_name = const_cast<RBX_DTRACE_CONST char*>( ctx_->llvm_state()->symbol_debug_str(code->name()).c_str()); RBX_DTRACE_CONST char* file_name = const_cast<RBX_DTRACE_CONST char*>( ctx_->llvm_state()->symbol_debug_str(code->file()).c_str()); int line = code->start_line(); RUBINIUS_JIT_FUNCTION_END(class_name, method_name, file_name, line); } #endif }
Symbol* original_name() { return compiled_code->name(); }
Symbol* original_name() { return cm->name(); }