YJIT: rb_ivar_get_at skip ractor checks

Using `assume_single_ractor_mode` we can skip all ractor safety
checks if we're in single ractor mode.

```
compare-ruby: ruby 3.5.0dev (2025-08-27T14:58:58Z merge-vm-setivar-d.. 5b749d8e53) +YJIT +PRISM [arm64-darwin24]
built-ruby: ruby 3.5.0dev (2025-08-28T21:23:38Z yjit-get-exivar 3cc21b76d4) +YJIT +PRISM [arm64-darwin24]

|                           |compare-ruby|built-ruby|
|:--------------------------|-----------:|---------:|
|vm_ivar_get_on_obj         |     975.981|   975.772|
|                           |       1.00x|         -|
|vm_ivar_get_on_class       |     136.214|   470.912|
|                           |           -|     3.46x|
|vm_ivar_get_on_generic     |     148.315|   299.122|
|                           |           -|     2.02x|
```
This commit is contained in:
Jean Boussier 2025-08-28 23:23:38 +02:00
parent 3646596e5b
commit 4992d2c298
5 changed files with 27 additions and 2 deletions

View File

@ -54,6 +54,7 @@ void rb_ivar_set_internal(VALUE obj, ID id, VALUE val);
attr_index_t rb_ivar_set_index(VALUE obj, ID id, VALUE val);
attr_index_t rb_obj_field_set(VALUE obj, shape_id_t target_shape_id, ID field_name, VALUE val);
VALUE rb_ivar_get_at(VALUE obj, attr_index_t index, ID id);
VALUE rb_ivar_get_at_no_ractor_check(VALUE obj, attr_index_t index);
RUBY_SYMBOL_EXPORT_BEGIN
/* variable.c (export) */

View File

@ -1493,6 +1493,26 @@ rb_ivar_get_at(VALUE obj, attr_index_t index, ID id)
}
}
VALUE
rb_ivar_get_at_no_ractor_check(VALUE obj, attr_index_t index)
{
// Used by JITs, but never for T_OBJECT.
VALUE fields_obj;
switch (BUILTIN_TYPE(obj)) {
case T_OBJECT:
UNREACHABLE_RETURN(Qundef);
case T_CLASS:
case T_MODULE:
fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
break;
default:
fields_obj = rb_obj_fields_no_ractor_check(obj);
break;
}
return rb_imemo_fields_ptr(fields_obj)[index];
}
VALUE
rb_attr_get(VALUE obj, ID id)
{

View File

@ -314,6 +314,7 @@ fn main() {
// From yjit.c
.allowlist_function("rb_object_shape_count")
.allowlist_function("rb_ivar_get_at")
.allowlist_function("rb_ivar_get_at_no_ractor_check")
.allowlist_function("rb_iseq_(get|set)_yjit_payload")
.allowlist_function("rb_iseq_pc_at_idx")
.allowlist_function("rb_iseq_opcode_at_pc")

View File

@ -2947,11 +2947,13 @@ fn gen_get_ivar(
} else {
asm_comment!(asm, "call rb_ivar_get_at()");
if !assume_single_ractor_mode(jit, asm) {
if assume_single_ractor_mode(jit, asm) {
asm.ccall(rb_ivar_get_at_no_ractor_check as *const u8, vec![recv, Opnd::UImm((ivar_index as u32).into())])
} else {
// The function could raise RactorIsolationError.
jit_prepare_non_leaf_call(jit, asm);
asm.ccall(rb_ivar_get_at as *const u8, vec![recv, Opnd::UImm((ivar_index as u32).into()), Opnd::UImm(ivar_name)])
}
asm.ccall(rb_ivar_get_at as *const u8, vec![recv, Opnd::UImm((ivar_index as u32).into()), Opnd::UImm(ivar_name)])
};
// Push the ivar on the stack

View File

@ -1116,6 +1116,7 @@ extern "C" {
pub fn rb_shape_get_iv_index(shape_id: shape_id_t, id: ID, value: *mut attr_index_t) -> bool;
pub fn rb_shape_transition_add_ivar_no_warnings(obj: VALUE, id: ID) -> shape_id_t;
pub fn rb_ivar_get_at(obj: VALUE, index: attr_index_t, id: ID) -> VALUE;
pub fn rb_ivar_get_at_no_ractor_check(obj: VALUE, index: attr_index_t) -> VALUE;
pub fn rb_gvar_get(arg1: ID) -> VALUE;
pub fn rb_gvar_set(arg1: ID, arg2: VALUE) -> VALUE;
pub fn rb_ensure_iv_list_size(obj: VALUE, current_len: u32, newsize: u32);