Skip to content

Commit

Permalink
YJIT: Rename method substitution functions and improve docs
Browse files Browse the repository at this point in the history
  • Loading branch information
XrXr committed Oct 18, 2024
1 parent 7be9a33 commit c4359f9
Showing 1 changed file with 81 additions and 77 deletions.
158 changes: 81 additions & 77 deletions yjit/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6347,8 +6347,9 @@ fn jit_thread_s_current(
true
}

// Check if we know how to codegen for a particular cfunc method
fn lookup_cfunc_codegen(def: *const rb_method_definition_t) -> Option<MethodGenFn> {
/// Check if we know how to codegen for a particular cfunc method
/// See also: [reg_method_codegen].
fn lookup_method_codegen(def: *const rb_method_definition_t) -> Option<MethodGenFn> {
let method_serial = unsafe { get_def_method_serial(def) };
let table = unsafe { METHOD_CODEGEN_TABLE.as_ref().unwrap() };

Expand Down Expand Up @@ -6585,7 +6586,7 @@ fn gen_send_cfunc(
flags & VM_CALL_ARGS_SPLAT == 0 &&
(cfunc_argc == -1 || argc == cfunc_argc) {
let expected_stack_after = asm.ctx.get_stack_size() as i32 - argc;
if let Some(known_cfunc_codegen) = lookup_cfunc_codegen(unsafe { (*cme).def }) {
if let Some(known_cfunc_codegen) = lookup_method_codegen(unsafe { (*cme).def }) {
// We don't push a frame for specialized cfunc codegen, so the generated code must be leaf.
// However, the interpreter doesn't push a frame on opt_* instruction either, so we allow
// non-sendish instructions to break this rule as an exception.
Expand Down Expand Up @@ -10368,9 +10369,9 @@ fn get_gen_fn(opcode: VALUE) -> Option<InsnGenFn> {
}
}

// Return true when the codegen function generates code.
// known_recv_class has Some value when the caller has used jit_guard_known_klass().
// See yjit_reg_method().
/// Return true when the codegen function generates code.
/// known_recv_class has Some value when the caller has used jit_guard_known_klass().
/// See [reg_method_codegen]
type MethodGenFn = fn(
jit: &mut JITState,
asm: &mut Assembler,
Expand All @@ -10390,77 +10391,80 @@ pub fn yjit_reg_method_codegen_fns() {
assert!(METHOD_CODEGEN_TABLE.is_none());
METHOD_CODEGEN_TABLE = Some(HashMap::default());

// Specialization for C methods. See yjit_reg_method() for details.
yjit_reg_method(rb_cBasicObject, "!", jit_rb_obj_not);

yjit_reg_method(rb_cNilClass, "nil?", jit_rb_true);
yjit_reg_method(rb_mKernel, "nil?", jit_rb_false);
yjit_reg_method(rb_mKernel, "is_a?", jit_rb_kernel_is_a);
yjit_reg_method(rb_mKernel, "kind_of?", jit_rb_kernel_is_a);
yjit_reg_method(rb_mKernel, "instance_of?", jit_rb_kernel_instance_of);

yjit_reg_method(rb_cBasicObject, "==", jit_rb_obj_equal);
yjit_reg_method(rb_cBasicObject, "equal?", jit_rb_obj_equal);
yjit_reg_method(rb_cBasicObject, "!=", jit_rb_obj_not_equal);
yjit_reg_method(rb_mKernel, "eql?", jit_rb_obj_equal);
yjit_reg_method(rb_cModule, "==", jit_rb_obj_equal);
yjit_reg_method(rb_cModule, "===", jit_rb_mod_eqq);
yjit_reg_method(rb_cModule, "name", jit_rb_mod_name);
yjit_reg_method(rb_cSymbol, "==", jit_rb_obj_equal);
yjit_reg_method(rb_cSymbol, "===", jit_rb_obj_equal);
yjit_reg_method(rb_cInteger, "==", jit_rb_int_equal);
yjit_reg_method(rb_cInteger, "===", jit_rb_int_equal);

yjit_reg_method(rb_cInteger, "succ", jit_rb_int_succ);
yjit_reg_method(rb_cInteger, "/", jit_rb_int_div);
yjit_reg_method(rb_cInteger, "<<", jit_rb_int_lshift);
yjit_reg_method(rb_cInteger, ">>", jit_rb_int_rshift);
yjit_reg_method(rb_cInteger, "^", jit_rb_int_xor);
yjit_reg_method(rb_cInteger, "[]", jit_rb_int_aref);

yjit_reg_method(rb_cFloat, "+", jit_rb_float_plus);
yjit_reg_method(rb_cFloat, "-", jit_rb_float_minus);
yjit_reg_method(rb_cFloat, "*", jit_rb_float_mul);
yjit_reg_method(rb_cFloat, "/", jit_rb_float_div);

yjit_reg_method(rb_cString, "empty?", jit_rb_str_empty_p);
yjit_reg_method(rb_cString, "to_s", jit_rb_str_to_s);
yjit_reg_method(rb_cString, "to_str", jit_rb_str_to_s);
yjit_reg_method(rb_cString, "length", jit_rb_str_length);
yjit_reg_method(rb_cString, "size", jit_rb_str_length);
yjit_reg_method(rb_cString, "bytesize", jit_rb_str_bytesize);
yjit_reg_method(rb_cString, "getbyte", jit_rb_str_getbyte);
yjit_reg_method(rb_cString, "setbyte", jit_rb_str_setbyte);
yjit_reg_method(rb_cString, "byteslice", jit_rb_str_byteslice);
yjit_reg_method(rb_cString, "<<", jit_rb_str_concat);
yjit_reg_method(rb_cString, "+@", jit_rb_str_uplus);

yjit_reg_method(rb_cNilClass, "===", jit_rb_case_equal);
yjit_reg_method(rb_cTrueClass, "===", jit_rb_case_equal);
yjit_reg_method(rb_cFalseClass, "===", jit_rb_case_equal);

yjit_reg_method(rb_cArray, "empty?", jit_rb_ary_empty_p);
yjit_reg_method(rb_cArray, "length", jit_rb_ary_length);
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);

yjit_reg_method(rb_cClass, "superclass", jit_rb_class_superclass);

yjit_reg_method(rb_singleton_class(rb_cThread), "current", jit_thread_s_current);
}
}

// Register a specialized codegen function for a particular method. Note that
// if the function returns true, the code it generates runs without a
// control frame and without interrupt checks. To avoid creating observable
// behavior changes, the codegen function should only target simple code paths
// that do not allocate and do not make method calls.
fn yjit_reg_method(klass: VALUE, mid_str: &str, gen_fn: MethodGenFn) {
// Specialization for C methods. See the function's docs for details.
reg_method_codegen(rb_cBasicObject, "!", jit_rb_obj_not);

reg_method_codegen(rb_cNilClass, "nil?", jit_rb_true);
reg_method_codegen(rb_mKernel, "nil?", jit_rb_false);
reg_method_codegen(rb_mKernel, "is_a?", jit_rb_kernel_is_a);
reg_method_codegen(rb_mKernel, "kind_of?", jit_rb_kernel_is_a);
reg_method_codegen(rb_mKernel, "instance_of?", jit_rb_kernel_instance_of);

reg_method_codegen(rb_cBasicObject, "==", jit_rb_obj_equal);
reg_method_codegen(rb_cBasicObject, "equal?", jit_rb_obj_equal);
reg_method_codegen(rb_cBasicObject, "!=", jit_rb_obj_not_equal);
reg_method_codegen(rb_mKernel, "eql?", jit_rb_obj_equal);
reg_method_codegen(rb_cModule, "==", jit_rb_obj_equal);
reg_method_codegen(rb_cModule, "===", jit_rb_mod_eqq);
reg_method_codegen(rb_cModule, "name", jit_rb_mod_name);
reg_method_codegen(rb_cSymbol, "==", jit_rb_obj_equal);
reg_method_codegen(rb_cSymbol, "===", jit_rb_obj_equal);
reg_method_codegen(rb_cInteger, "==", jit_rb_int_equal);
reg_method_codegen(rb_cInteger, "===", jit_rb_int_equal);

reg_method_codegen(rb_cInteger, "succ", jit_rb_int_succ);
reg_method_codegen(rb_cInteger, "/", jit_rb_int_div);
reg_method_codegen(rb_cInteger, "<<", jit_rb_int_lshift);
reg_method_codegen(rb_cInteger, ">>", jit_rb_int_rshift);
reg_method_codegen(rb_cInteger, "^", jit_rb_int_xor);
reg_method_codegen(rb_cInteger, "[]", jit_rb_int_aref);

reg_method_codegen(rb_cFloat, "+", jit_rb_float_plus);
reg_method_codegen(rb_cFloat, "-", jit_rb_float_minus);
reg_method_codegen(rb_cFloat, "*", jit_rb_float_mul);
reg_method_codegen(rb_cFloat, "/", jit_rb_float_div);

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);
reg_method_codegen(rb_cString, "length", jit_rb_str_length);
reg_method_codegen(rb_cString, "size", jit_rb_str_length);
reg_method_codegen(rb_cString, "bytesize", jit_rb_str_bytesize);
reg_method_codegen(rb_cString, "getbyte", jit_rb_str_getbyte);
reg_method_codegen(rb_cString, "setbyte", jit_rb_str_setbyte);
reg_method_codegen(rb_cString, "byteslice", jit_rb_str_byteslice);
reg_method_codegen(rb_cString, "<<", jit_rb_str_concat);
reg_method_codegen(rb_cString, "+@", jit_rb_str_uplus);

reg_method_codegen(rb_cNilClass, "===", jit_rb_case_equal);
reg_method_codegen(rb_cTrueClass, "===", jit_rb_case_equal);
reg_method_codegen(rb_cFalseClass, "===", jit_rb_case_equal);

reg_method_codegen(rb_cArray, "empty?", jit_rb_ary_empty_p);
reg_method_codegen(rb_cArray, "length", jit_rb_ary_length);
reg_method_codegen(rb_cArray, "size", jit_rb_ary_length);
reg_method_codegen(rb_cArray, "<<", jit_rb_ary_push);

reg_method_codegen(rb_cHash, "empty?", jit_rb_hash_empty_p);

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_cClass, "superclass", jit_rb_class_superclass);

reg_method_codegen(rb_singleton_class(rb_cThread), "current", jit_thread_s_current);
}
}

/// Register a specialized codegen function for a particular method. Note that
/// if the function returns true, the code it generates runs without a
/// control frame and without interrupt checks, completely substituting the
/// original implementation of the method. To avoid creating observable
/// behavior changes, prefer targeting simple code paths that do not allocate
/// and do not make method calls.
///
/// See also: [lookup_method_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 mid = unsafe { rb_intern(id_string.as_ptr()) };
let me = unsafe { rb_method_entry_at(klass, mid) };
Expand Down

0 comments on commit c4359f9

Please sign in to comment.