From b41c65b57735ce0d556b6fdad0ce490e939b1c7a Mon Sep 17 00:00:00 2001 From: Alan Wu Date: Mon, 21 Oct 2024 18:08:51 -0400 Subject: [PATCH] YJIT: Implement specialization for no-op `{Kernel,Numeric}#dup` Type information in the context for no additional work! This is the `if (special_object_p(obj)) return obj;` path in rb_obj_dup() and for Numeric#dup, it's always the identity function. --- yjit/bindgen/src/main.rs | 1 + yjit/src/codegen.rs | 39 ++++++++++++++++++++++++++++++++++ yjit/src/cruby_bindings.inc.rs | 1 + 3 files changed, 41 insertions(+) diff --git a/yjit/bindgen/src/main.rs b/yjit/bindgen/src/main.rs index 649d540c94..5f0f599b9a 100644 --- a/yjit/bindgen/src/main.rs +++ b/yjit/bindgen/src/main.rs @@ -167,6 +167,7 @@ fn main() { .allowlist_var("rb_cIO") .allowlist_var("rb_cSymbol") .allowlist_var("rb_cFloat") + .allowlist_var("rb_cNumeric") .allowlist_var("rb_cString") .allowlist_var("rb_cThread") .allowlist_var("rb_cArray") diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index ed8fc65491..6e2f96724a 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -6347,6 +6347,42 @@ fn jit_thread_s_current( true } +fn jit_numeric_dup( + _jit: &mut JITState, + _asm: &mut Assembler, + _ci: *const rb_callinfo, + _cme: *const rb_callable_method_entry_t, + _block: Option, + _argc: i32, + _known_recv_class: Option, +) -> bool { + // Numeric#dup has arity=0 and is the identity function. + // Our caller already did argument count check, so this is + // no-op to return the receiver that is already on the stack. + true +} + +/// Specialization for rb_obj_dup() (Kernel#dup) +fn jit_rb_obj_dup( + _jit: &mut JITState, + asm: &mut Assembler, + _ci: *const rb_callinfo, + _cme: *const rb_callable_method_entry_t, + _block: Option, + _argc: i32, + _known_recv_class: Option, +) -> bool { + // Kernel#dup has arity=0, and caller already did argument count check. + let self_type = asm.ctx.get_opnd_type(StackOpnd(0)); + + if self_type.is_imm() { + // Method is no-op when receiver is an immediate value. + true + } else { + false + } +} + /// Check if we know how to codegen for a particular cfunc method /// See also: [reg_method_codegen]. fn lookup_cfunc_codegen(def: *const rb_method_definition_t) -> Option { @@ -10424,6 +10460,8 @@ pub fn yjit_reg_method_codegen_fns() { reg_method_codegen(rb_cFloat, "*", jit_rb_float_mul); reg_method_codegen(rb_cFloat, "/", jit_rb_float_div); + reg_method_codegen(rb_cNumeric, "dup", jit_numeric_dup); + reg_method_codegen(rb_cString, "empty?", jit_rb_str_empty_p); reg_method_codegen(rb_cString, "to_s", jit_rb_str_to_s); reg_method_codegen(rb_cString, "to_str", jit_rb_str_to_s); @@ -10449,6 +10487,7 @@ pub fn yjit_reg_method_codegen_fns() { reg_method_codegen(rb_mKernel, "respond_to?", jit_obj_respond_to); reg_method_codegen(rb_mKernel, "block_given?", jit_rb_f_block_given_p); + reg_method_codegen(rb_mKernel, "dup", jit_rb_obj_dup); reg_method_codegen(rb_cClass, "superclass", jit_rb_class_superclass); diff --git a/yjit/src/cruby_bindings.inc.rs b/yjit/src/cruby_bindings.inc.rs index 8b53098cc9..4eb44634a1 100644 --- a/yjit/src/cruby_bindings.inc.rs +++ b/yjit/src/cruby_bindings.inc.rs @@ -997,6 +997,7 @@ extern "C" { pub static mut rb_cInteger: VALUE; pub static mut rb_cModule: VALUE; pub static mut rb_cNilClass: VALUE; + pub static mut rb_cNumeric: VALUE; pub static mut rb_cString: VALUE; pub static mut rb_cSymbol: VALUE; pub static mut rb_cThread: VALUE;