diff options
author | Takashi Kokubun <[email protected]> | 2024-01-19 08:00:46 -0800 |
---|---|---|
committer | GitHub <[email protected]> | 2024-01-19 11:00:46 -0500 |
commit | 3c9290173a1421b0624a6d62c0844c778dbc61ad (patch) | |
tree | 97ac12c570c6494e920f3c031b698a5cf0e15cf4 | |
parent | a58e091686d9117673487b5b2ab6a793ecc81702 (diff) |
YJIT: Optimize defined?(yield) (#9599)
* YJIT: Optimize defined?(yield)
* Remove an irrelevant comment
* s/get/gen/
-rw-r--r-- | bootstraptest/test_yjit.rb | 5 | ||||
-rw-r--r-- | yjit/bindgen/src/main.rs | 1 | ||||
-rw-r--r-- | yjit/src/codegen.rs | 74 | ||||
-rw-r--r-- | yjit/src/cruby_bindings.inc.rs | 19 |
4 files changed, 72 insertions, 27 deletions
diff --git a/bootstraptest/test_yjit.rb b/bootstraptest/test_yjit.rb index a6b0f8f19c..3bf715f888 100644 --- a/bootstraptest/test_yjit.rb +++ b/bootstraptest/test_yjit.rb @@ -4364,3 +4364,8 @@ assert_equal '[2, 4611686018427387904]', %q{ assert_equal '[0, 1, -4]', %q{ [0 >> 1, 2 >> 1, -7 >> 1] } + +assert_equal '[nil, "yield"]', %q{ + def defined_yield = defined?(yield) + [defined_yield, defined_yield {}] +} diff --git a/yjit/bindgen/src/main.rs b/yjit/bindgen/src/main.rs index 848e9fadc4..e249181d51 100644 --- a/yjit/bindgen/src/main.rs +++ b/yjit/bindgen/src/main.rs @@ -348,6 +348,7 @@ fn main() { .allowlist_function("rb_iseqw_to_iseq") .allowlist_function("rb_iseq_label") .allowlist_function("rb_iseq_line_no") + .allowlist_type("defined_type") // From builtin.h .allowlist_type("rb_builtin_function.*") diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index 956bcb1aeb..b50cd10163 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -2655,31 +2655,41 @@ fn gen_defined( let obj = jit.get_arg(1); let pushval = jit.get_arg(2); - // Save the PC and SP because the callee may allocate - // Note that this modifies REG_SP, which is why we do it first - jit_prepare_routine_call(jit, asm); + match op_type as u32 { + DEFINED_YIELD => { + asm.stack_pop(1); // v operand is not used + let out_opnd = asm.stack_push(Type::Unknown); // nil or "yield" - // Get the operands from the stack - let v_opnd = asm.stack_opnd(0); + gen_block_given(jit, asm, out_opnd, pushval.into(), Qnil.into()); + } + _ => { + // Save the PC and SP because the callee may allocate + // Note that this modifies REG_SP, which is why we do it first + jit_prepare_routine_call(jit, asm); - // Call vm_defined(ec, reg_cfp, op_type, obj, v) - let def_result = asm.ccall(rb_vm_defined as *const u8, vec![EC, CFP, op_type.into(), obj.into(), v_opnd]); - asm.stack_pop(1); // Keep it on stack during ccall for GC + // Get the operands from the stack + let v_opnd = asm.stack_opnd(0); - // if (vm_defined(ec, GET_CFP(), op_type, obj, v)) { - // val = pushval; - // } - asm.test(def_result, Opnd::UImm(255)); - let out_value = asm.csel_nz(pushval.into(), Qnil.into()); + // Call vm_defined(ec, reg_cfp, op_type, obj, v) + let def_result = asm.ccall(rb_vm_defined as *const u8, vec![EC, CFP, op_type.into(), obj.into(), v_opnd]); + asm.stack_pop(1); // Keep it on stack during ccall for GC - // Push the return value onto the stack - let out_type = if pushval.special_const_p() { - Type::UnknownImm - } else { - Type::Unknown - }; - let stack_ret = asm.stack_push(out_type); - asm.mov(stack_ret, out_value); + // if (vm_defined(ec, GET_CFP(), op_type, obj, v)) { + // val = pushval; + // } + asm.test(def_result, Opnd::UImm(255)); + let out_value = asm.csel_nz(pushval.into(), Qnil.into()); + + // Push the return value onto the stack + let out_type = if pushval.special_const_p() { + Type::UnknownImm + } else { + Type::Unknown + }; + let stack_ret = asm.stack_push(out_type); + asm.mov(stack_ret, out_value); + } + } Some(KeepCompiling) } @@ -5265,6 +5275,21 @@ fn jit_rb_f_block_given_p( _argc: i32, _known_recv_class: *const VALUE, ) -> bool { + asm.stack_pop(1); + let out_opnd = asm.stack_push(Type::UnknownImm); + + gen_block_given(jit, asm, out_opnd, Qtrue.into(), Qfalse.into()); + + true +} + +fn gen_block_given( + jit: &mut JITState, + asm: &mut Assembler, + out_opnd: Opnd, + true_opnd: Opnd, + false_opnd: Opnd, +) { asm_comment!(asm, "block_given?"); // Same as rb_vm_frame_block_handler @@ -5273,15 +5298,10 @@ fn jit_rb_f_block_given_p( Opnd::mem(64, ep_opnd, SIZEOF_VALUE_I32 * VM_ENV_DATA_INDEX_SPECVAL) ); - asm.stack_pop(1); - let out_opnd = asm.stack_push(Type::UnknownImm); - // Return `block_handler != VM_BLOCK_HANDLER_NONE` asm.cmp(block_handler, VM_BLOCK_HANDLER_NONE.into()); - let block_given = asm.csel_ne(Qtrue.into(), Qfalse.into()); + let block_given = asm.csel_ne(true_opnd, false_opnd); asm.mov(out_opnd, block_given); - - true } fn jit_thread_s_current( diff --git a/yjit/src/cruby_bindings.inc.rs b/yjit/src/cruby_bindings.inc.rs index d71441c0be..d67653890c 100644 --- a/yjit/src/cruby_bindings.inc.rs +++ b/yjit/src/cruby_bindings.inc.rs @@ -874,6 +874,25 @@ pub type ruby_vminsn_type = u32; pub type rb_iseq_callback = ::std::option::Option< unsafe extern "C" fn(arg1: *const rb_iseq_t, arg2: *mut ::std::os::raw::c_void), >; +pub const DEFINED_NOT_DEFINED: defined_type = 0; +pub const DEFINED_NIL: defined_type = 1; +pub const DEFINED_IVAR: defined_type = 2; +pub const DEFINED_LVAR: defined_type = 3; +pub const DEFINED_GVAR: defined_type = 4; +pub const DEFINED_CVAR: defined_type = 5; +pub const DEFINED_CONST: defined_type = 6; +pub const DEFINED_METHOD: defined_type = 7; +pub const DEFINED_YIELD: defined_type = 8; +pub const DEFINED_ZSUPER: defined_type = 9; +pub const DEFINED_SELF: defined_type = 10; +pub const DEFINED_TRUE: defined_type = 11; +pub const DEFINED_FALSE: defined_type = 12; +pub const DEFINED_ASGN: defined_type = 13; +pub const DEFINED_EXPR: defined_type = 14; +pub const DEFINED_REF: defined_type = 15; +pub const DEFINED_FUNC: defined_type = 16; +pub const DEFINED_CONST_FROM: defined_type = 17; +pub type defined_type = u32; pub const ROBJECT_OFFSET_AS_HEAP_IVPTR: robject_offsets = 16; pub const ROBJECT_OFFSET_AS_HEAP_IV_INDEX_TBL: robject_offsets = 24; pub const ROBJECT_OFFSET_AS_ARY: robject_offsets = 16; |