Reduce the number of branches in jit_exec (#6722)

* Reduce the number of branches in jit_exec

* Address build failure in some configurations

* Refactor yjit.h
This commit is contained in:
Takashi Kokubun 2022-11-13 20:35:35 -08:00 коммит произвёл GitHub
Родитель ea278ddd92
Коммит 3dd4e381fe
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
2 изменённых файлов: 24 добавлений и 31 удалений

53
vm.c
Просмотреть файл

@ -378,7 +378,7 @@ extern VALUE rb_vm_invoke_bmethod(rb_execution_context_t *ec, rb_proc_t *proc, V
const rb_callable_method_entry_t *me);
static VALUE vm_invoke_proc(rb_execution_context_t *ec, rb_proc_t *proc, VALUE self, int argc, const VALUE *argv, int kw_splat, VALUE block_handler);
#if USE_MJIT
#if USE_MJIT || USE_YJIT
# ifdef MJIT_HEADER
NOINLINE(static COLDFUNC VALUE mjit_check_iseq(rb_execution_context_t *ec, const rb_iseq_t *iseq, struct rb_iseq_constant_body *body));
# else
@ -412,46 +412,39 @@ mjit_check_iseq(rb_execution_context_t *ec, const rb_iseq_t *iseq, struct rb_ise
static inline VALUE
jit_exec(rb_execution_context_t *ec)
{
// Increment the ISEQ's call counter
const rb_iseq_t *iseq = ec->cfp->iseq;
struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
bool yjit_enabled = false;
# ifndef MJIT_HEADER
// Don't want to compile with YJIT or use code generated by YJIT
// when running inside code generated by MJIT.
yjit_enabled = rb_yjit_enabled_p();
# endif
if (mjit_call_p || yjit_enabled) {
bool yjit_enabled = rb_yjit_enabled_p();
if (yjit_enabled || mjit_call_p) {
body->total_calls++;
}
else {
return Qundef;
}
# ifndef MJIT_HEADER
if (yjit_enabled && !mjit_call_p && body->total_calls == rb_yjit_call_threshold()) {
// If we couldn't generate any code for this iseq, then return
// Qundef so the interpreter will handle the call.
if (!rb_yjit_compile_iseq(iseq, ec)) {
// Trigger JIT compilation as needed
jit_func_t func;
if (yjit_enabled) {
if (body->total_calls == rb_yjit_call_threshold()) {
// If we couldn't generate any code for this iseq, then return
// Qundef so the interpreter will handle the call.
if (!rb_yjit_compile_iseq(iseq, ec)) {
return Qundef;
}
}
// YJIT tried compiling this function once before and couldn't do
// it, so return Qundef so the interpreter handles it.
if ((func = body->jit_func) == 0) {
return Qundef;
}
}
# endif
if (!(mjit_call_p || yjit_enabled))
return Qundef;
jit_func_t func = body->jit_func;
// YJIT tried compiling this function once before and couldn't do
// it, so return Qundef so the interpreter handles it.
if (yjit_enabled && func == 0) {
return Qundef;
}
if (UNLIKELY((uintptr_t)func <= LAST_JIT_ISEQ_FUNC)) {
else if (UNLIKELY((uintptr_t)(func = body->jit_func) <= LAST_JIT_ISEQ_FUNC)) {
return mjit_check_iseq(ec, iseq, body);
}
// Under SystemV x64 calling convention: ec -> RDI, cfp -> RSI
return func(ec, ec->cfp);
// Call the JIT code
return func(ec, ec->cfp); // SystemV x64 calling convention: ec -> RDI, cfp -> RSI
}
#endif

2
yjit.h
Просмотреть файл

@ -15,7 +15,7 @@
# define YJIT_STATS RUBY_DEBUG
#endif
#if USE_YJIT
#if USE_YJIT && !defined(MJIT_HEADER) // MJIT and YJIT can't be enabled simultaneously
// We generate x86 or arm64 assembly
#if defined(_WIN32) ? defined(_M_AMD64) : (defined(__x86_64__) || defined(__aarch64__))