YJIT: Rename method substitution functions and improve docs (+1) (#11919)

* YJIT: Fill in commented-out assertion

* YJIT: Rename yjit_reg_method() and add links in docs
This commit is contained in:
Alan Wu 2024-10-21 12:12:24 -04:00 committed by GitHub
parent 6588bbfa44
commit 20c5a3e133
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
Notes: git 2024-10-21 16:12:43 +00:00
Merged-By: maximecb <maximecb@ruby-lang.org>

View File

@ -6347,7 +6347,8 @@ fn jit_thread_s_current(
true true
} }
// Check if we know how to codegen for a particular cfunc method /// 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<MethodGenFn> { fn lookup_cfunc_codegen(def: *const rb_method_definition_t) -> Option<MethodGenFn> {
let method_serial = unsafe { get_def_method_serial(def) }; let method_serial = unsafe { get_def_method_serial(def) };
let table = unsafe { METHOD_CODEGEN_TABLE.as_ref().unwrap() }; let table = unsafe { METHOD_CODEGEN_TABLE.as_ref().unwrap() };
@ -10368,9 +10369,9 @@ fn get_gen_fn(opcode: VALUE) -> Option<InsnGenFn> {
} }
} }
// Return true when the codegen function generates code. /// Return true when the codegen function generates code.
// known_recv_class has Some value when the caller has used jit_guard_known_klass(). /// known_recv_class has Some value when the caller has used jit_guard_known_klass().
// See yjit_reg_method(). /// See [reg_method_codegen]
type MethodGenFn = fn( type MethodGenFn = fn(
jit: &mut JITState, jit: &mut JITState,
asm: &mut Assembler, asm: &mut Assembler,
@ -10390,77 +10391,80 @@ pub fn yjit_reg_method_codegen_fns() {
assert!(METHOD_CODEGEN_TABLE.is_none()); assert!(METHOD_CODEGEN_TABLE.is_none());
METHOD_CODEGEN_TABLE = Some(HashMap::default()); METHOD_CODEGEN_TABLE = Some(HashMap::default());
// Specialization for C methods. See yjit_reg_method() for details. // Specialization for C methods. See the function's docs for details.
yjit_reg_method(rb_cBasicObject, "!", jit_rb_obj_not); reg_method_codegen(rb_cBasicObject, "!", jit_rb_obj_not);
yjit_reg_method(rb_cNilClass, "nil?", jit_rb_true); reg_method_codegen(rb_cNilClass, "nil?", jit_rb_true);
yjit_reg_method(rb_mKernel, "nil?", jit_rb_false); reg_method_codegen(rb_mKernel, "nil?", jit_rb_false);
yjit_reg_method(rb_mKernel, "is_a?", jit_rb_kernel_is_a); reg_method_codegen(rb_mKernel, "is_a?", jit_rb_kernel_is_a);
yjit_reg_method(rb_mKernel, "kind_of?", jit_rb_kernel_is_a); reg_method_codegen(rb_mKernel, "kind_of?", jit_rb_kernel_is_a);
yjit_reg_method(rb_mKernel, "instance_of?", jit_rb_kernel_instance_of); reg_method_codegen(rb_mKernel, "instance_of?", jit_rb_kernel_instance_of);
yjit_reg_method(rb_cBasicObject, "==", jit_rb_obj_equal); reg_method_codegen(rb_cBasicObject, "==", jit_rb_obj_equal);
yjit_reg_method(rb_cBasicObject, "equal?", jit_rb_obj_equal); reg_method_codegen(rb_cBasicObject, "equal?", jit_rb_obj_equal);
yjit_reg_method(rb_cBasicObject, "!=", jit_rb_obj_not_equal); reg_method_codegen(rb_cBasicObject, "!=", jit_rb_obj_not_equal);
yjit_reg_method(rb_mKernel, "eql?", jit_rb_obj_equal); reg_method_codegen(rb_mKernel, "eql?", jit_rb_obj_equal);
yjit_reg_method(rb_cModule, "==", jit_rb_obj_equal); reg_method_codegen(rb_cModule, "==", jit_rb_obj_equal);
yjit_reg_method(rb_cModule, "===", jit_rb_mod_eqq); reg_method_codegen(rb_cModule, "===", jit_rb_mod_eqq);
yjit_reg_method(rb_cModule, "name", jit_rb_mod_name); reg_method_codegen(rb_cModule, "name", jit_rb_mod_name);
yjit_reg_method(rb_cSymbol, "==", jit_rb_obj_equal); reg_method_codegen(rb_cSymbol, "==", jit_rb_obj_equal);
yjit_reg_method(rb_cSymbol, "===", jit_rb_obj_equal); reg_method_codegen(rb_cSymbol, "===", jit_rb_obj_equal);
yjit_reg_method(rb_cInteger, "==", jit_rb_int_equal); reg_method_codegen(rb_cInteger, "==", jit_rb_int_equal);
yjit_reg_method(rb_cInteger, "===", jit_rb_int_equal); reg_method_codegen(rb_cInteger, "===", jit_rb_int_equal);
yjit_reg_method(rb_cInteger, "succ", jit_rb_int_succ); reg_method_codegen(rb_cInteger, "succ", jit_rb_int_succ);
yjit_reg_method(rb_cInteger, "/", jit_rb_int_div); reg_method_codegen(rb_cInteger, "/", jit_rb_int_div);
yjit_reg_method(rb_cInteger, "<<", jit_rb_int_lshift); reg_method_codegen(rb_cInteger, "<<", jit_rb_int_lshift);
yjit_reg_method(rb_cInteger, ">>", jit_rb_int_rshift); reg_method_codegen(rb_cInteger, ">>", jit_rb_int_rshift);
yjit_reg_method(rb_cInteger, "^", jit_rb_int_xor); reg_method_codegen(rb_cInteger, "^", jit_rb_int_xor);
yjit_reg_method(rb_cInteger, "[]", jit_rb_int_aref); reg_method_codegen(rb_cInteger, "[]", jit_rb_int_aref);
yjit_reg_method(rb_cFloat, "+", jit_rb_float_plus); reg_method_codegen(rb_cFloat, "+", jit_rb_float_plus);
yjit_reg_method(rb_cFloat, "-", jit_rb_float_minus); reg_method_codegen(rb_cFloat, "-", jit_rb_float_minus);
yjit_reg_method(rb_cFloat, "*", jit_rb_float_mul); reg_method_codegen(rb_cFloat, "*", jit_rb_float_mul);
yjit_reg_method(rb_cFloat, "/", jit_rb_float_div); reg_method_codegen(rb_cFloat, "/", jit_rb_float_div);
yjit_reg_method(rb_cString, "empty?", jit_rb_str_empty_p); reg_method_codegen(rb_cString, "empty?", jit_rb_str_empty_p);
yjit_reg_method(rb_cString, "to_s", jit_rb_str_to_s); reg_method_codegen(rb_cString, "to_s", jit_rb_str_to_s);
yjit_reg_method(rb_cString, "to_str", jit_rb_str_to_s); reg_method_codegen(rb_cString, "to_str", jit_rb_str_to_s);
yjit_reg_method(rb_cString, "length", jit_rb_str_length); reg_method_codegen(rb_cString, "length", jit_rb_str_length);
yjit_reg_method(rb_cString, "size", jit_rb_str_length); reg_method_codegen(rb_cString, "size", jit_rb_str_length);
yjit_reg_method(rb_cString, "bytesize", jit_rb_str_bytesize); reg_method_codegen(rb_cString, "bytesize", jit_rb_str_bytesize);
yjit_reg_method(rb_cString, "getbyte", jit_rb_str_getbyte); reg_method_codegen(rb_cString, "getbyte", jit_rb_str_getbyte);
yjit_reg_method(rb_cString, "setbyte", jit_rb_str_setbyte); reg_method_codegen(rb_cString, "setbyte", jit_rb_str_setbyte);
yjit_reg_method(rb_cString, "byteslice", jit_rb_str_byteslice); reg_method_codegen(rb_cString, "byteslice", jit_rb_str_byteslice);
yjit_reg_method(rb_cString, "<<", jit_rb_str_concat); reg_method_codegen(rb_cString, "<<", jit_rb_str_concat);
yjit_reg_method(rb_cString, "+@", jit_rb_str_uplus); reg_method_codegen(rb_cString, "+@", jit_rb_str_uplus);
yjit_reg_method(rb_cNilClass, "===", jit_rb_case_equal); reg_method_codegen(rb_cNilClass, "===", jit_rb_case_equal);
yjit_reg_method(rb_cTrueClass, "===", jit_rb_case_equal); reg_method_codegen(rb_cTrueClass, "===", jit_rb_case_equal);
yjit_reg_method(rb_cFalseClass, "===", jit_rb_case_equal); reg_method_codegen(rb_cFalseClass, "===", jit_rb_case_equal);
yjit_reg_method(rb_cArray, "empty?", jit_rb_ary_empty_p); reg_method_codegen(rb_cArray, "empty?", jit_rb_ary_empty_p);
yjit_reg_method(rb_cArray, "length", jit_rb_ary_length); reg_method_codegen(rb_cArray, "length", jit_rb_ary_length);
yjit_reg_method(rb_cArray, "size", jit_rb_ary_length); reg_method_codegen(rb_cArray, "size", jit_rb_ary_length);
yjit_reg_method(rb_cArray, "<<", jit_rb_ary_push); reg_method_codegen(rb_cArray, "<<", jit_rb_ary_push);
yjit_reg_method(rb_cHash, "empty?", jit_rb_hash_empty_p); reg_method_codegen(rb_cHash, "empty?", jit_rb_hash_empty_p);
yjit_reg_method(rb_mKernel, "respond_to?", jit_obj_respond_to); reg_method_codegen(rb_mKernel, "respond_to?", jit_obj_respond_to);
yjit_reg_method(rb_mKernel, "block_given?", jit_rb_f_block_given_p); reg_method_codegen(rb_mKernel, "block_given?", jit_rb_f_block_given_p);
yjit_reg_method(rb_cClass, "superclass", jit_rb_class_superclass); reg_method_codegen(rb_cClass, "superclass", jit_rb_class_superclass);
yjit_reg_method(rb_singleton_class(rb_cThread), "current", jit_thread_s_current); reg_method_codegen(rb_singleton_class(rb_cThread), "current", jit_thread_s_current);
} }
} }
// Register a specialized codegen function for a particular method. Note that /// Register a specialized codegen function for a particular method. Note that
// if the function returns true, the code it generates runs without a /// if the function returns true, the code it generates runs without a
// control frame and without interrupt checks. To avoid creating observable /// control frame and without interrupt checks, completely substituting the
// behavior changes, the codegen function should only target simple code paths /// original implementation of the method. To avoid creating observable
// that do not allocate and do not make method calls. /// behavior changes, prefer targeting simple code paths that do not allocate
fn yjit_reg_method(klass: VALUE, mid_str: &str, gen_fn: MethodGenFn) { /// and do not make method calls.
///
/// See also: [lookup_cfunc_codegen].
fn reg_method_codegen(klass: VALUE, mid_str: &str, gen_fn: MethodGenFn) {
let id_string = std::ffi::CString::new(mid_str).expect("couldn't convert to CString!"); let id_string = std::ffi::CString::new(mid_str).expect("couldn't convert to CString!");
let mid = unsafe { rb_intern(id_string.as_ptr()) }; let mid = unsafe { rb_intern(id_string.as_ptr()) };
let me = unsafe { rb_method_entry_at(klass, mid) }; let me = unsafe { rb_method_entry_at(klass, mid) };
@ -10469,9 +10473,8 @@ fn yjit_reg_method(klass: VALUE, mid_str: &str, gen_fn: MethodGenFn) {
panic!("undefined optimized method!: {mid_str}"); panic!("undefined optimized method!: {mid_str}");
} }
// For now, only cfuncs are supported // For now, only cfuncs are supported (me->cme cast fine since it's just me->def->type).
//RUBY_ASSERT(me && me->def); debug_assert_eq!(VM_METHOD_TYPE_CFUNC, unsafe { get_cme_def_type(me.cast()) });
//RUBY_ASSERT(me->def->type == VM_METHOD_TYPE_CFUNC);
let method_serial = unsafe { let method_serial = unsafe {
let def = (*me).def; let def = (*me).def;