YJIT: Support ifunc on invokeblock (#7233)

This commit is contained in:
Takashi Kokubun 2023-02-03 07:14:42 -08:00 коммит произвёл GitHub
Родитель 8e7d2cc2ab
Коммит 08c529be90
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
3 изменённых файлов: 74 добавлений и 5 удалений

Просмотреть файл

@ -4396,6 +4396,12 @@ vm_yield_with_cfunc(rb_execution_context_t *ec,
return val;
}
VALUE
rb_vm_yield_with_cfunc(rb_execution_context_t *ec, const struct rb_captured_block *captured, int argc, const VALUE *argv)
{
return vm_yield_with_cfunc(ec, captured, captured->self, argc, argv, 0, VM_BLOCK_HANDLER_NONE, NULL);
}
static VALUE
vm_yield_with_symbol(rb_execution_context_t *ec, VALUE symbol, int argc, const VALUE *argv, int kw_splat, VALUE block_handler)
{

Просмотреть файл

@ -6339,7 +6339,16 @@ fn gen_invokeblock(
let side_exit = get_side_exit(jit, ocb, ctx);
let tag_opnd = asm.and(block_handler_opnd, 0x3.into()); // block_handler is a tagged pointer
asm.cmp(tag_opnd, 0x1.into()); // VM_BH_ISEQ_BLOCK_P
asm.jne(counted_exit!(ocb, side_exit, invokeblock_iseq_tag_changed));
let tag_changed_exit = counted_exit!(ocb, side_exit, invokeblock_tag_changed);
jit_chain_guard(
JCC_JNE,
jit,
ctx,
asm,
ocb,
SEND_MAX_CHAIN_DEPTH,
tag_changed_exit,
);
// Not supporting vm_callee_setup_block_arg_arg0_splat for now
let comptime_captured = unsafe { ((comptime_handler.0 & !0x3) as *const rb_captured_block).as_ref().unwrap() };
@ -6380,8 +6389,61 @@ fn gen_invokeblock(
Some(captured_opnd),
)
} else if comptime_handler.0 & 0x3 == 0x3 { // VM_BH_IFUNC_P
gen_counter_incr!(asm, invokeblock_ifunc);
CantCompile
// We aren't handling CALLER_SETUP_ARG and CALLER_REMOVE_EMPTY_KW_SPLAT yet.
if flags & VM_CALL_ARGS_SPLAT != 0 {
gen_counter_incr!(asm, invokeblock_ifunc_args_splat);
return CantCompile;
}
if flags & VM_CALL_KW_SPLAT != 0 {
gen_counter_incr!(asm, invokeblock_ifunc_kw_splat);
return CantCompile;
}
asm.comment("get local EP");
let ep_opnd = gen_get_lep(jit, asm);
let block_handler_opnd = asm.load(
Opnd::mem(64, ep_opnd, SIZEOF_VALUE_I32 * VM_ENV_DATA_INDEX_SPECVAL)
);
asm.comment("guard block_handler type");
let side_exit = get_side_exit(jit, ocb, ctx);
let tag_opnd = asm.and(block_handler_opnd, 0x3.into()); // block_handler is a tagged pointer
asm.cmp(tag_opnd, 0x3.into()); // VM_BH_IFUNC_P
let tag_changed_exit = counted_exit!(ocb, side_exit, invokeblock_tag_changed);
jit_chain_guard(
JCC_JNE,
jit,
ctx,
asm,
ocb,
SEND_MAX_CHAIN_DEPTH,
tag_changed_exit,
);
// The cfunc may not be leaf
jit_prepare_routine_call(jit, ctx, asm);
extern "C" {
fn rb_vm_yield_with_cfunc(ec: EcPtr, captured: *const rb_captured_block, argc: c_int, argv: *const VALUE) -> VALUE;
}
asm.comment("call ifunc");
let captured_opnd = asm.and(block_handler_opnd, Opnd::Imm(!0x3));
let argv = asm.lea(ctx.sp_opnd((-argc * SIZEOF_VALUE_I32) as isize));
let ret = asm.ccall(
rb_vm_yield_with_cfunc as *const u8,
vec![EC, captured_opnd, argc.into(), argv],
);
ctx.stack_pop(argc.try_into().unwrap());
let stack_ret = ctx.stack_push(Type::Unknown);
asm.mov(stack_ret, ret);
// cfunc calls may corrupt types
ctx.clear_local_types();
// Share the successor with other chains
jump_to_next_insn(jit, ctx, asm, ocb);
EndBlock
} else if comptime_handler.symbol_p() {
gen_counter_incr!(asm, invokeblock_symbol);
CantCompile

Просмотреть файл

@ -248,8 +248,9 @@ make_counters! {
invokeblock_none,
invokeblock_iseq_arg0_splat,
invokeblock_iseq_block_changed,
invokeblock_iseq_tag_changed,
invokeblock_ifunc,
invokeblock_tag_changed,
invokeblock_ifunc_args_splat,
invokeblock_ifunc_kw_splat,
invokeblock_proc,
invokeblock_symbol,