<commit_before>#ifdef ENABLE_LLVM

#include "llvm/state.hpp"

#include "llvm/jit_compiler.hpp"
#include "llvm/jit_method.hpp"
#include "llvm/jit_block.hpp"
#include "llvm/method_info.hpp"
#include "llvm/disassembler.hpp"
#include "llvm/jit_context.hpp"
#include "llvm/jit_memory_manager.hpp"
#include "llvm/detection.hpp"

#include "builtin/fixnum.hpp"
#include "builtin/constant_scope.hpp"
#include "builtin/module.hpp"
#include "builtin/compiled_code.hpp"
#include "builtin/class.hpp"
#include "builtin/block_environment.hpp"
#include "builtin/jit.hpp"
#include "builtin/list.hpp"
#include "builtin/thread.hpp"

#include "auxiliary_threads.hpp"
#include "machine_code.hpp"
#include "field_offset.hpp"
#include "object_memory.hpp"
#include "on_stack.hpp"

#include "call_frame.hpp"
#include "configuration.hpp"
#include "instruments/timing.hpp"
#include "dtrace/dtrace.h"

#if RBX_LLVM_API_VER >= 303
#include <llvm/IR/DataLayout.h>
#elif RBX_LLVM_API_VER >= 302
#include <llvm/DataLayout.h>
#else
#include <llvm/Target/TargetData.h>
#endif
#if RBX_LLVM_API_VER >= 305
#include <llvm/IR/Verifier.h>
#include <llvm/IR/CFG.h>
#else
#include <llvm/Analysis/Verifier.h>
#include <llvm/Support/CFG.h>
#endif
#if RBX_LLVM_API_VER >= 303
#include <llvm/IR/CallingConv.h>
#else
#include <llvm/CallingConv.h>
#endif
#include <llvm/Analysis/Passes.h>
// #include <llvm/LinkAllPasses.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/Format.h>
#include <llvm/Target/TargetOptions.h>
#include <llvm/Transforms/Scalar.h>

#include "windows_compat.h"

#include "gc/gc.hpp"

namespace autogen_types {
  void makeLLVMModuleContents(llvm::Module* module);
}

#include <iostream>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <stdlib.h>
#ifndef RBX_WINDOWS
#include <dlfcn.h>
#endif

#include "llvm/passes.hpp"
#include "instructions_util.hpp"

#include <udis86.h>
// for abi::__cxa_demangle
#include <cxxabi.h>

using namespace llvm;

namespace rubinius {

  static const bool debug_search = false;

  LLVMState::LLVMState(STATE)
    : AuxiliaryThread()
    , config_(state->shared().config)
    , vm_(NULL)
    , thread_(state)
    , compile_list_(state)
    , symbols_(state->shared().symbols)
    , accessors_inlined_(0)
    , uncommons_taken_(0)
    , shared_(state->shared())
    , include_profiling_(state->shared().config.jit_profile)
    , code_bytes_(0)
    , log_(NULL)
    , enabled_(false)
    , thread_exit_(false)
    , current_compiler_(0)
  {
    state->shared().auxiliary_threads()->register_thread(this);

    if(state->shared().config.jit_log.value.size() == 0) {
      log_ = &std::cerr;
    } else {
      std::ofstream* s = new std::ofstream(
          state->shared().config.jit_log.value.c_str(), std::ios::out);

      if(s->fail()) {
        delete s;
        log_ = &std::cerr;
      } else {
        log_ = s;
      }
    }

#if RBX_LLVM_API_VER <= 300
    llvm::NoFramePointerElim = true;
#endif
    llvm::InitializeNativeTarget();
    llvm::InitializeNativeTargetAsmPrinter();

    memory_ = new jit::RubiniusJITMemoryManager();
#if RBX_LLVM_API_VER > 300
    jit_event_listener_ = llvm::JITEventListener::createOProfileJITEventListener();
#else
    jit_event_listener_ = llvm::createOProfileJITEventListener();
#endif

    fixnum_class_id_   = G(fixnum_class)->class_id();
    integer_class_id_  = G(integer)->class_id();
    numeric_class_id_  = G(numeric)->class_id();
    bignum_class_id_   = G(bignum)->class_id();
    float_class_id_    = G(floatpoint)->class_id();
    symbol_class_id_   = G(symbol)->class_id();
    string_class_id_   = G(string)->class_id();
    regexp_class_id_   = G(regexp)->class_id();
    encoding_class_id_ = G(encoding)->class_id();
    module_class_id_   = G(module)->class_id();
    class_class_id_    = G(klass)->class_id();
    nil_class_id_      = G(nil_class)->class_id();
    true_class_id_     = G(true_class)->class_id();
    false_class_id_    = G(false_class)->class_id();
    array_class_id_    = G(array)->class_id();
    tuple_class_id_    = G(tuple)->class_id();

    type_optz_ = state->shared().config.jit_type_optz;

    cpu_ = rubinius::getHostCPUName();

    compile_list_.set(G(jit)->compile_list());
  }

  LLVMState::~LLVMState() {
    shared_.auxiliary_threads()->unregister_thread(this);

    delete memory_;
    delete jit_event_listener_;
  }

  void LLVMState::enable(STATE) {
    utilities::thread::SpinLock::LockGuard lg(shared_.llvm_state_lock());

    start_thread(state);
    enabled_ = true;
  }

  bool LLVMState::debug_p() {
    return config_.jit_debug;
  }

  Object* jit_llvm_trampoline(STATE) {
    state->shared().llvm_state->perform(state);
    GCTokenImpl gct;
    state->gc_dependent(gct, 0);
    return cNil;
  }

  void LLVMState::start_thread(STATE) {
    SYNC(state);

    if(!vm_) {
      vm_ = state->shared().new_vm();
      thread_exit_ = false;

      Thread* thread = Thread::create(state, vm_, G(thread), jit_llvm_trampoline, true);
      OnStack<1> os(state, thread);

      if(thread->fork_attached(state)) {
        rubinius::bug("Unable to start JIT LLVM thread");
      }

      thread_.set(thread);
    }
  }

  void LLVMState::stop_thread(STATE) {
    SYNC(state);

    if(vm_) {
      {
        utilities::thread::Mutex::LockGuard lg(compile_lock_);
        thread_exit_ = true;
        compile_cond_.signal();
      }

      pthread_t os = vm_->os_thread();

      void* return_value;
      pthread_join(os, &return_value);

      vm_ = NULL;
    }
  }

  void LLVMState::stop(STATE) {
    enabled_ = false;
    stop_thread(state);
  }

  void LLVMState::after_fork_child(STATE) {
    compile_list_.get()->clear(state);
    current_compiler_ = 0;

    if(vm_) {
      VM::discard(state, vm_);
      vm_ = NULL;
    }

    start_thread(state);
    vm_->metrics()->init(metrics::eJITMetrics);
  }

  void LLVMState::perform(STATE) {
    GCTokenImpl gct;
    RBX_DTRACE_CONST char* thread_name = const_cast<RBX_DTRACE_CONST char*>("rbx.jit");
    vm_->set_name(thread_name);

    RUBINIUS_THREAD_START(const_cast<RBX_DTRACE_CONST char*>(thread_name),
                          state->vm()->thread_id(), 1);

    state->vm()->thread->hard_unlock(state, gct, 0);
    state->gc_dependent(gct, 0);

    bool show_machine_code_ = jit_dump_code() & cMachineCode;

    while(!thread_exit_) {
      JITCompileRequest* compile_request = nil<JITCompileRequest>();
      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;
      }

      OnStack<1> os(state, compile_request);

      Context ctx(this);
      jit::Compiler jit(&ctx);

      current_compiler_ = &jit;

      uint32_t class_id = 0;
      uint32_t serial_id = 0;
      Class* receiver_class = compile_request->receiver_class();

      OnStack<1> os2(state, receiver_class);

      if(receiver_class && !receiver_class->nil_p()) {

        // Apparently already compiled, probably some race
        if(compile_request->method()->find_specialized(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(utilities::thread::Condition* cond = compile_request->waiter()) {
            cond->signal();
          }

          current_compiler_ = 0;

          continue;
        }

        class_id = receiver_class->class_id();
        serial_id = receiver_class->serial_id();
      }

      void* func = 0;
      {
        timer::StopWatch<timer::microseconds> timer(
            vm()->metrics()->m.jit_metrics.time_last_us,
            vm()->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(utilities::thread::Condition* cond = compile_request->waiter()) {
          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(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(utilities::thread::Condition* cond = compile_request->waiter()) {
        cond->signal();
      }

      current_compiler_ = 0;
      vm()->metrics()->m.jit_metrics.methods_compiled++;
    }
  }

  void LLVMState::gc_scan(GarbageCollector* gc) {
    if(current_compiler_) {
      jit::RuntimeDataHolder* rd = current_compiler_->context()->runtime_data_holder();
      rd->set_mark();
    }
  }

  Symbol* LLVMState::symbol(const std::string& sym) {
    return symbols_.lookup(&shared_, sym);
  }

  std::string LLVMState::symbol_debug_str(const Symbol* sym) {
    if(sym == nil<Symbol>()) return "<nil>";
    return symbols_.lookup_debug_string(sym);
  }

  std::string LLVMState::enclosure_name(CompiledCode* code) {
    ConstantScope* cs = code->scope();
    if(!kind_of<ConstantScope>(cs) || !kind_of<Module>(cs->module())) {
      return "ANONYMOUS";
    }

    return symbol_debug_str(cs->module()->module_name());
  }

  void LLVMState::add(STATE, JITCompileRequest* req) {
    utilities::thread::Mutex::LockGuard guard(request_lock_);

    if(!enabled_) return;

    G(jit)->compile_list()->append(state, req);
    vm()->metrics()->m.jit_metrics.methods_queued++;

    compile_cond_.signal();
  }

  void LLVMState::compile_soon(STATE, GCToken gct, CompiledCode* code, CallFrame* call_frame,
                               Class* receiver_class, BlockEnvironment* block_env, bool is_block)
  {
    bool wait = config().jit_sync;

    if(code->machine_code()->call_count <= 1) {
      return;
    }

    if(code->machine_code()->compiling_p()) {
      return;
    }

    int hits = code->machine_code()->method_call_count();
    code->machine_code()->set_compiling();

    JITCompileRequest* req = JITCompileRequest::create(state, code, receiver_class,
        hits, block_env, is_block);

    if(wait) {
      wait_mutex.lock();

      req->set_waiter(&wait_cond);

      add(state, req);
      bool req_block = req->is_block();

      state->set_call_frame(call_frame);

      wait_cond.wait(wait_mutex);

      wait_mutex.unlock();
      state->set_call_frame(0);

      if(state->shared().config.jit_show_compiling) {
        llvm::outs() << "[[[ JIT compiled "
          << enclosure_name(code) << "#" << symbol_debug_str(code->name())
          << (req_block ? " (block) " : " (method) ")
          << " (" << hits << ") " << " ]]]\n";
      }
    } else {
      add(state, req);

      if(state->shared().config.jit_show_compiling) {
        llvm::outs() << "[[[ JIT queued "
          << enclosure_name(code) << "#" << symbol_debug_str(code->name())
          << (req->is_block() ? " (block) " : " (method) ")
          << " (" << hits << ") " << " ]]]\n";
      }
    }
  }

  void LLVMState::remove(void* func) {
    vm_->metrics()->m.jit_metrics.methods_compiled--;
    memory_->deallocateFunctionBody(func);
  }

  const static int cInlineMaxDepth = 2;
  const static size_t eMaxInlineSendCount = 10;

  void LLVMState::compile_callframe(STATE, GCToken gct, CompiledCode* start, CallFrame* call_frame,
                                    int primitive) {<commit_msg>Don't use LLVM thread after it's been removed.<commit_after>#ifdef ENABLE_LLVM

#include "llvm/state.hpp"

#include "llvm/jit_compiler.hpp"
#include "llvm/jit_method.hpp"
#include "llvm/jit_block.hpp"
#include "llvm/method_info.hpp"
#include "llvm/disassembler.hpp"
#include "llvm/jit_context.hpp"
#include "llvm/jit_memory_manager.hpp"
#include "llvm/detection.hpp"

#include "builtin/fixnum.hpp"
#include "builtin/constant_scope.hpp"
#include "builtin/module.hpp"
#include "builtin/compiled_code.hpp"
#include "builtin/class.hpp"
#include "builtin/block_environment.hpp"
#include "builtin/jit.hpp"
#include "builtin/list.hpp"
#include "builtin/thread.hpp"

#include "auxiliary_threads.hpp"
#include "machine_code.hpp"
#include "field_offset.hpp"
#include "object_memory.hpp"
#include "on_stack.hpp"

#include "call_frame.hpp"
#include "configuration.hpp"
#include "instruments/timing.hpp"
#include "dtrace/dtrace.h"

#if RBX_LLVM_API_VER >= 303
#include <llvm/IR/DataLayout.h>
#elif RBX_LLVM_API_VER >= 302
#include <llvm/DataLayout.h>
#else
#include <llvm/Target/TargetData.h>
#endif
#if RBX_LLVM_API_VER >= 305
#include <llvm/IR/Verifier.h>
#include <llvm/IR/CFG.h>
#else
#include <llvm/Analysis/Verifier.h>
#include <llvm/Support/CFG.h>
#endif
#if RBX_LLVM_API_VER >= 303
#include <llvm/IR/CallingConv.h>
#else
#include <llvm/CallingConv.h>
#endif
#include <llvm/Analysis/Passes.h>
// #include <llvm/LinkAllPasses.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/Format.h>
#include <llvm/Target/TargetOptions.h>
#include <llvm/Transforms/Scalar.h>

#include "windows_compat.h"

#include "gc/gc.hpp"

namespace autogen_types {
  void makeLLVMModuleContents(llvm::Module* module);
}

#include <iostream>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <stdlib.h>
#ifndef RBX_WINDOWS
#include <dlfcn.h>
#endif

#include "llvm/passes.hpp"
#include "instructions_util.hpp"

#include <udis86.h>
// for abi::__cxa_demangle
#include <cxxabi.h>

using namespace llvm;

namespace rubinius {

  static const bool debug_search = false;

  LLVMState::LLVMState(STATE)
    : AuxiliaryThread()
    , config_(state->shared().config)
    , vm_(NULL)
    , thread_(state)
    , compile_list_(state)
    , symbols_(state->shared().symbols)
    , accessors_inlined_(0)
    , uncommons_taken_(0)
    , shared_(state->shared())
    , include_profiling_(state->shared().config.jit_profile)
    , code_bytes_(0)
    , log_(NULL)
    , enabled_(false)
    , thread_exit_(false)
    , current_compiler_(0)
  {
    state->shared().auxiliary_threads()->register_thread(this);

    if(state->shared().config.jit_log.value.size() == 0) {
      log_ = &std::cerr;
    } else {
      std::ofstream* s = new std::ofstream(
          state->shared().config.jit_log.value.c_str(), std::ios::out);

      if(s->fail()) {
        delete s;
        log_ = &std::cerr;
      } else {
        log_ = s;
      }
    }

#if RBX_LLVM_API_VER <= 300
    llvm::NoFramePointerElim = true;
#endif
    llvm::InitializeNativeTarget();
    llvm::InitializeNativeTargetAsmPrinter();

    memory_ = new jit::RubiniusJITMemoryManager();
#if RBX_LLVM_API_VER > 300
    jit_event_listener_ = llvm::JITEventListener::createOProfileJITEventListener();
#else
    jit_event_listener_ = llvm::createOProfileJITEventListener();
#endif

    fixnum_class_id_   = G(fixnum_class)->class_id();
    integer_class_id_  = G(integer)->class_id();
    numeric_class_id_  = G(numeric)->class_id();
    bignum_class_id_   = G(bignum)->class_id();
    float_class_id_    = G(floatpoint)->class_id();
    symbol_class_id_   = G(symbol)->class_id();
    string_class_id_   = G(string)->class_id();
    regexp_class_id_   = G(regexp)->class_id();
    encoding_class_id_ = G(encoding)->class_id();
    module_class_id_   = G(module)->class_id();
    class_class_id_    = G(klass)->class_id();
    nil_class_id_      = G(nil_class)->class_id();
    true_class_id_     = G(true_class)->class_id();
    false_class_id_    = G(false_class)->class_id();
    array_class_id_    = G(array)->class_id();
    tuple_class_id_    = G(tuple)->class_id();

    type_optz_ = state->shared().config.jit_type_optz;

    cpu_ = rubinius::getHostCPUName();

    compile_list_.set(G(jit)->compile_list());
  }

  LLVMState::~LLVMState() {
    shared_.auxiliary_threads()->unregister_thread(this);

    delete memory_;
    memory_ = NULL;

    delete jit_event_listener_;
    jit_event_listener_ = NULL;
  }

  void LLVMState::enable(STATE) {
    utilities::thread::SpinLock::LockGuard lg(shared_.llvm_state_lock());

    start_thread(state);
    enabled_ = true;
  }

  bool LLVMState::debug_p() {
    return config_.jit_debug;
  }

  Object* jit_llvm_trampoline(STATE) {
    state->shared().llvm_state->perform(state);
    GCTokenImpl gct;
    state->gc_dependent(gct, 0);
    return cNil;
  }

  void LLVMState::start_thread(STATE) {
    SYNC(state);

    if(!vm_) {
      vm_ = state->shared().new_vm();
      thread_exit_ = false;

      Thread* thread = Thread::create(state, vm_, G(thread), jit_llvm_trampoline, true);
      OnStack<1> os(state, thread);

      if(thread->fork_attached(state)) {
        rubinius::bug("Unable to start JIT LLVM thread");
      }

      thread_.set(thread);
    }
  }

  void LLVMState::stop_thread(STATE) {
    SYNC(state);

    if(vm_) {
      {
        utilities::thread::Mutex::LockGuard lg(compile_lock_);
        thread_exit_ = true;
        compile_cond_.signal();
      }

      pthread_t os = vm_->os_thread();

      void* return_value;
      pthread_join(os, &return_value);

      vm_ = NULL;
    }
  }

  void LLVMState::stop(STATE) {
    enabled_ = false;
    stop_thread(state);
  }

  void LLVMState::after_fork_child(STATE) {
    compile_list_.get()->clear(state);
    current_compiler_ = 0;

    if(vm_) {
      VM::discard(state, vm_);
      vm_ = NULL;
    }

    start_thread(state);
    vm_->metrics()->init(metrics::eJITMetrics);
  }

  void LLVMState::perform(STATE) {
    GCTokenImpl gct;
    RBX_DTRACE_CONST char* thread_name = const_cast<RBX_DTRACE_CONST char*>("rbx.jit");
    vm_->set_name(thread_name);

    RUBINIUS_THREAD_START(const_cast<RBX_DTRACE_CONST char*>(thread_name),
                          state->vm()->thread_id(), 1);

    state->vm()->thread->hard_unlock(state, gct, 0);
    state->gc_dependent(gct, 0);

    bool show_machine_code_ = jit_dump_code() & cMachineCode;

    while(!thread_exit_) {
      JITCompileRequest* compile_request = nil<JITCompileRequest>();
      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;
      }

      OnStack<1> os(state, compile_request);

      Context ctx(this);
      jit::Compiler jit(&ctx);

      current_compiler_ = &jit;

      uint32_t class_id = 0;
      uint32_t serial_id = 0;
      Class* receiver_class = compile_request->receiver_class();

      OnStack<1> os2(state, receiver_class);

      if(receiver_class && !receiver_class->nil_p()) {

        // Apparently already compiled, probably some race
        if(compile_request->method()->find_specialized(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(utilities::thread::Condition* cond = compile_request->waiter()) {
            cond->signal();
          }

          current_compiler_ = 0;

          continue;
        }

        class_id = receiver_class->class_id();
        serial_id = receiver_class->serial_id();
      }

      void* func = 0;
      {
        timer::StopWatch<timer::microseconds> timer(
            vm()->metrics()->m.jit_metrics.time_last_us,
            vm()->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(utilities::thread::Condition* cond = compile_request->waiter()) {
          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(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(utilities::thread::Condition* cond = compile_request->waiter()) {
        cond->signal();
      }

      current_compiler_ = 0;
      vm()->metrics()->m.jit_metrics.methods_compiled++;
    }
  }

  void LLVMState::gc_scan(GarbageCollector* gc) {
    if(current_compiler_) {
      jit::RuntimeDataHolder* rd = current_compiler_->context()->runtime_data_holder();
      rd->set_mark();
    }
  }

  Symbol* LLVMState::symbol(const std::string& sym) {
    return symbols_.lookup(&shared_, sym);
  }

  std::string LLVMState::symbol_debug_str(const Symbol* sym) {
    if(sym == nil<Symbol>()) return "<nil>";
    return symbols_.lookup_debug_string(sym);
  }

  std::string LLVMState::enclosure_name(CompiledCode* code) {
    ConstantScope* cs = code->scope();
    if(!kind_of<ConstantScope>(cs) || !kind_of<Module>(cs->module())) {
      return "ANONYMOUS";
    }

    return symbol_debug_str(cs->module()->module_name());
  }

  void LLVMState::add(STATE, JITCompileRequest* req) {
    utilities::thread::Mutex::LockGuard guard(request_lock_);

    if(!enabled_) return;

    G(jit)->compile_list()->append(state, req);
    vm()->metrics()->m.jit_metrics.methods_queued++;

    compile_cond_.signal();
  }

  void LLVMState::compile_soon(STATE, GCToken gct, CompiledCode* code, CallFrame* call_frame,
                               Class* receiver_class, BlockEnvironment* block_env, bool is_block)
  {
    bool wait = config().jit_sync;

    if(code->machine_code()->call_count <= 1) {
      return;
    }

    if(code->machine_code()->compiling_p()) {
      return;
    }

    int hits = code->machine_code()->method_call_count();
    code->machine_code()->set_compiling();

    JITCompileRequest* req = JITCompileRequest::create(state, code, receiver_class,
        hits, block_env, is_block);

    if(wait) {
      wait_mutex.lock();

      req->set_waiter(&wait_cond);

      add(state, req);
      bool req_block = req->is_block();

      state->set_call_frame(call_frame);

      wait_cond.wait(wait_mutex);

      wait_mutex.unlock();
      state->set_call_frame(0);

      if(state->shared().config.jit_show_compiling) {
        llvm::outs() << "[[[ JIT compiled "
          << enclosure_name(code) << "#" << symbol_debug_str(code->name())
          << (req_block ? " (block) " : " (method) ")
          << " (" << hits << ") " << " ]]]\n";
      }
    } else {
      add(state, req);

      if(state->shared().config.jit_show_compiling) {
        llvm::outs() << "[[[ JIT queued "
          << enclosure_name(code) << "#" << symbol_debug_str(code->name())
          << (req->is_block() ? " (block) " : " (method) ")
          << " (" << hits << ") " << " ]]]\n";
      }
    }
  }

  void LLVMState::remove(void* func) {
    if(vm_) vm_->metrics()->m.jit_metrics.methods_compiled--;
    if(memory_) memory_->deallocateFunctionBody(func);
  }

  const static int cInlineMaxDepth = 2;
  const static size_t eMaxInlineSendCount = 10;

  void LLVMState::compile_callframe(STATE, GCToken gct, CompiledCode* start, CallFrame* call_frame,
                                    int primitive) {
{'fraction_non_alphanumeric': 0.15058934123942438, 'fraction_numerical': 0.0036879022344348832, 'mean_word_length': 3.023712540005819, 'pattern_counts': {'":': 0, '<': 227, '<?xml version=': 0, '>': 325, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '720394', 'n_tokens_mistral': 9443, 'n_tokens_neox': 9097, 'n_words': 1443}