Пример #1
0
  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);
  }
Пример #2
0
  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;
  }
Пример #3
0
  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);
  }
Пример #4
0
  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;
  }
Пример #5
0
  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);
  }
Пример #6
0
  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++;
    }
  }
Пример #7
0
    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);
    }
Пример #8
0
  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
  }
Пример #9
0
 Symbol* original_name() {
   return compiled_code->name();
 }
Пример #10
0
 Symbol* original_name() {
   return cm->name();
 }