зеркало из https://github.com/github/ruby.git
YJIT: getblockparamproxy for when block is a Proc
This commit is contained in:
Родитель
34825ed20d
Коммит
7633299c50
|
@ -441,6 +441,7 @@ fn main() {
|
||||||
.allowlist_function("rb_method_basic_definition_p")
|
.allowlist_function("rb_method_basic_definition_p")
|
||||||
.allowlist_function("rb_yjit_array_len")
|
.allowlist_function("rb_yjit_array_len")
|
||||||
.allowlist_function("rb_obj_class")
|
.allowlist_function("rb_obj_class")
|
||||||
|
.allowlist_function("rb_obj_is_proc")
|
||||||
|
|
||||||
// We define VALUE manually, don't import it
|
// We define VALUE manually, don't import it
|
||||||
.blocklist_type("VALUE")
|
.blocklist_type("VALUE")
|
||||||
|
|
|
@ -7784,19 +7784,19 @@ fn gen_getblockparamproxy(
|
||||||
return Some(EndBlock);
|
return Some(EndBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
// A mirror of the interpreter code. Checking for the case
|
|
||||||
// where it's pushing rb_block_param_proxy.
|
|
||||||
|
|
||||||
// EP level
|
// EP level
|
||||||
let level = jit.get_arg(1).as_u32();
|
let level = jit.get_arg(1).as_u32();
|
||||||
|
|
||||||
// Peek at the block handler so we can check whether it's nil
|
// Peek at the block handler so we can check whether it's nil
|
||||||
let comptime_handler = jit.peek_at_block_handler(level);
|
let comptime_handler = jit.peek_at_block_handler(level);
|
||||||
|
|
||||||
// When a block handler is present, it should always be a GC-guarded
|
// Filter for the 3 cases we currently handle
|
||||||
// pointer (VM_BH_ISEQ_BLOCK_P)
|
if !(comptime_handler.as_u64() == 0 || // no block given
|
||||||
if comptime_handler.as_u64() != 0 && comptime_handler.as_u64() & 0x3 != 0x1 {
|
comptime_handler.as_u64() & 0x3 == 0x1 || // iseq block (no associated GC managed object)
|
||||||
incr_counter!(gbpp_not_gc_guarded);
|
unsafe { rb_obj_is_proc(comptime_handler) }.test() // block is a Proc
|
||||||
|
) {
|
||||||
|
// Missing the symbol case, where we basically need to call Symbol#to_proc at runtime
|
||||||
|
gen_counter_incr(asm, Counter::gbpp_unsupported_type);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7818,7 +7818,12 @@ fn gen_getblockparamproxy(
|
||||||
Opnd::mem(64, ep_opnd, SIZEOF_VALUE_I32 * VM_ENV_DATA_INDEX_SPECVAL)
|
Opnd::mem(64, ep_opnd, SIZEOF_VALUE_I32 * VM_ENV_DATA_INDEX_SPECVAL)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Specialize compilation for the case where no block handler is present
|
// Use block handler sample to guide specialization...
|
||||||
|
// NOTE: we use jit_chain_guard() in this decision tree, and since
|
||||||
|
// there are only 3 cases, it should never reach the depth limit use
|
||||||
|
// the exit counter we pass to it.
|
||||||
|
//
|
||||||
|
// No block given
|
||||||
if comptime_handler.as_u64() == 0 {
|
if comptime_handler.as_u64() == 0 {
|
||||||
// Bail if there is a block handler
|
// Bail if there is a block handler
|
||||||
asm.cmp(block_handler, Opnd::UImm(0));
|
asm.cmp(block_handler, Opnd::UImm(0));
|
||||||
|
@ -7833,7 +7838,7 @@ fn gen_getblockparamproxy(
|
||||||
);
|
);
|
||||||
|
|
||||||
jit_putobject(asm, Qnil);
|
jit_putobject(asm, Qnil);
|
||||||
} else {
|
} else if comptime_handler.as_u64() & 0x3 == 0x1 {
|
||||||
// Block handler is a tagged pointer. Look at the tag. 0x03 is from VM_BH_ISEQ_BLOCK_P().
|
// Block handler is a tagged pointer. Look at the tag. 0x03 is from VM_BH_ISEQ_BLOCK_P().
|
||||||
let block_handler = asm.and(block_handler, 0x3.into());
|
let block_handler = asm.and(block_handler, 0x3.into());
|
||||||
|
|
||||||
|
@ -7854,6 +7859,39 @@ fn gen_getblockparamproxy(
|
||||||
|
|
||||||
let top = asm.stack_push(Type::BlockParamProxy);
|
let top = asm.stack_push(Type::BlockParamProxy);
|
||||||
asm.mov(top, Opnd::const_ptr(unsafe { rb_block_param_proxy }.as_ptr()));
|
asm.mov(top, Opnd::const_ptr(unsafe { rb_block_param_proxy }.as_ptr()));
|
||||||
|
} else if unsafe { rb_obj_is_proc(comptime_handler) }.test() {
|
||||||
|
// The block parameter is a Proc
|
||||||
|
c_callable! {
|
||||||
|
// We can't hold values across C calls due to a backend limitation,
|
||||||
|
// so we'll use this thin wrapper around rb_obj_is_proc().
|
||||||
|
fn is_proc(object: VALUE) -> VALUE {
|
||||||
|
if unsafe { rb_obj_is_proc(object) }.test() {
|
||||||
|
// VM_BH_TO_PROC() is the identify function.
|
||||||
|
object
|
||||||
|
} else {
|
||||||
|
Qfalse
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple predicate, no need to jit_prepare_routine_call()
|
||||||
|
let proc_or_false = asm.ccall(is_proc as _, vec![block_handler]);
|
||||||
|
|
||||||
|
// Guard for proc
|
||||||
|
asm.cmp(proc_or_false, Qfalse.into());
|
||||||
|
jit_chain_guard(
|
||||||
|
JCC_JE,
|
||||||
|
jit,
|
||||||
|
asm,
|
||||||
|
ocb,
|
||||||
|
SEND_MAX_DEPTH,
|
||||||
|
Counter::gbpp_block_handler_not_proc,
|
||||||
|
);
|
||||||
|
|
||||||
|
let top = asm.stack_push(Type::Unknown);
|
||||||
|
asm.mov(top, proc_or_false);
|
||||||
|
} else {
|
||||||
|
unreachable!("absurd given initial filtering");
|
||||||
}
|
}
|
||||||
|
|
||||||
jump_to_next_insn(jit, asm, ocb);
|
jump_to_next_insn(jit, asm, ocb);
|
||||||
|
|
|
@ -1099,6 +1099,7 @@ extern "C" {
|
||||||
pub fn rb_hash_aref(hash: VALUE, key: VALUE) -> VALUE;
|
pub fn rb_hash_aref(hash: VALUE, key: VALUE) -> VALUE;
|
||||||
pub fn rb_hash_aset(hash: VALUE, key: VALUE, val: VALUE) -> VALUE;
|
pub fn rb_hash_aset(hash: VALUE, key: VALUE, val: VALUE) -> VALUE;
|
||||||
pub fn rb_hash_bulk_insert(argc: ::std::os::raw::c_long, argv: *const VALUE, hash: VALUE);
|
pub fn rb_hash_bulk_insert(argc: ::std::os::raw::c_long, argv: *const VALUE, hash: VALUE);
|
||||||
|
pub fn rb_obj_is_proc(recv: VALUE) -> VALUE;
|
||||||
pub fn rb_sym2id(obj: VALUE) -> ID;
|
pub fn rb_sym2id(obj: VALUE) -> ID;
|
||||||
pub fn rb_id2sym(id: ID) -> VALUE;
|
pub fn rb_id2sym(id: ID) -> VALUE;
|
||||||
pub fn rb_intern(name: *const ::std::os::raw::c_char) -> ID;
|
pub fn rb_intern(name: *const ::std::os::raw::c_char) -> ID;
|
||||||
|
|
|
@ -355,11 +355,15 @@ make_counters! {
|
||||||
expandarray_not_array,
|
expandarray_not_array,
|
||||||
expandarray_rhs_too_small,
|
expandarray_rhs_too_small,
|
||||||
|
|
||||||
|
// getblockparam
|
||||||
gbp_wb_required,
|
gbp_wb_required,
|
||||||
gbpp_not_gc_guarded,
|
|
||||||
|
// getblockparamproxy
|
||||||
|
gbpp_unsupported_type,
|
||||||
gbpp_block_param_modified,
|
gbpp_block_param_modified,
|
||||||
gbpp_block_handler_not_none,
|
gbpp_block_handler_not_none,
|
||||||
gbpp_block_handler_not_iseq,
|
gbpp_block_handler_not_iseq,
|
||||||
|
gbpp_block_handler_not_proc,
|
||||||
|
|
||||||
branchif_interrupted,
|
branchif_interrupted,
|
||||||
branchunless_interrupted,
|
branchunless_interrupted,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче