From b74c8abd1132824f95d81309f96645f272c064dc Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Thu, 8 Feb 2024 07:22:07 -0800 Subject: [PATCH] YJIT: Skip pushing a frame for Hash#empty? (#9875) --- hash.c | 2 +- yjit/src/codegen.rs | 23 +++++++++++++++++++++++ yjit/src/cruby.rs | 3 ++- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/hash.c b/hash.c index 91f1e73a39..201ada4f6e 100644 --- a/hash.c +++ b/hash.c @@ -3015,7 +3015,7 @@ rb_hash_size_num(VALUE hash) * {foo: 0, bar: 1, baz: 2}.empty? # => false */ -static VALUE +VALUE rb_hash_empty_p(VALUE hash) { return RBOOL(RHASH_EMPTY_P(hash)); diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index 4eaeebd503..b7df2b44f8 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -5499,6 +5499,27 @@ fn jit_rb_ary_push( true } +// Just a leaf method, but not using `Primitive.attr! :leaf` since BOP methods can't use it. +fn jit_rb_hash_empty_p( + _jit: &mut JITState, + asm: &mut Assembler, + _ocb: &mut OutlinedCb, + _ci: *const rb_callinfo, + _cme: *const rb_callable_method_entry_t, + _block: Option, + _argc: i32, + _known_recv_class: *const VALUE, +) -> bool { + asm_comment!(asm, "Hash#empty?"); + + let hash_opnd = asm.stack_pop(1); + let ret = asm.ccall(rb_hash_empty_p as *const u8, vec![hash_opnd]); + + let ret_opnd = asm.stack_push(Type::UnknownImm); + asm.mov(ret_opnd, ret); + true +} + fn jit_obj_respond_to( jit: &mut JITState, asm: &mut Assembler, @@ -9360,6 +9381,8 @@ pub fn yjit_reg_method_codegen_fns() { yjit_reg_method(rb_cArray, "size", jit_rb_ary_length); yjit_reg_method(rb_cArray, "<<", jit_rb_ary_push); + yjit_reg_method(rb_cHash, "empty?", jit_rb_hash_empty_p); + yjit_reg_method(rb_mKernel, "respond_to?", jit_obj_respond_to); yjit_reg_method(rb_mKernel, "block_given?", jit_rb_f_block_given_p); diff --git a/yjit/src/cruby.rs b/yjit/src/cruby.rs index 0f3519b820..78cb2d65ea 100644 --- a/yjit/src/cruby.rs +++ b/yjit/src/cruby.rs @@ -107,11 +107,12 @@ pub use autogened::*; // TODO: For #defines that affect memory layout, we need to check for them // on build and fail if they're wrong. e.g. USE_FLONUM *must* be true. -// These are functions we expose from vm_insnhelper.c, not in any header. +// These are functions we expose from C files, not in any header. // Parsing it would result in a lot of duplicate definitions. // Use bindgen for functions that are defined in headers or in yjit.c. #[cfg_attr(test, allow(unused))] // We don't link against C code when testing extern "C" { + pub fn rb_hash_empty_p(hash: VALUE) -> VALUE; pub fn rb_vm_splat_array(flag: VALUE, ary: VALUE) -> VALUE; pub fn rb_vm_concat_array(ary1: VALUE, ary2st: VALUE) -> VALUE; pub fn rb_vm_concat_to_array(ary1: VALUE, ary2st: VALUE) -> VALUE;