YJIT: Side-exit on String#dup when it's not leaf (#13921)

* YJIT: Side-exit on String#dup when it's not leaf

* Use an enum instead of a macro for bindgen
This commit is contained in:
Takashi Kokubun 2025-07-16 15:59:32 -07:00 committed by GitHub
parent 15cf72dade
commit 571a8d2753
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 13 additions and 6 deletions

View file

@ -22,8 +22,7 @@ path = "jit.rs"
[features] [features]
disasm = ["yjit?/disasm", "zjit?/disasm"] disasm = ["yjit?/disasm", "zjit?/disasm"]
# TODO(GH-642) Turning this on trips a btest failure. runtime_checks = ["yjit?/runtime_checks", "zjit?/runtime_checks"]
runtime_checks = [] # ["yjit?/runtime_checks", "zjit?/runtime_checks"]
yjit = [ "dep:yjit" ] yjit = [ "dep:yjit" ]
zjit = [ "dep:zjit" ] zjit = [ "dep:zjit" ]

View file

@ -48,7 +48,9 @@ enum shape_id_fl_type {
// This masks allows to check if a shape_id contains any ivar. // This masks allows to check if a shape_id contains any ivar.
// It rely on ROOT_SHAPE_WITH_OBJ_ID==1. // It rely on ROOT_SHAPE_WITH_OBJ_ID==1.
#define SHAPE_ID_HAS_IVAR_MASK (SHAPE_ID_FL_TOO_COMPLEX | (SHAPE_ID_OFFSET_MASK - 1)) enum {
SHAPE_ID_HAS_IVAR_MASK = SHAPE_ID_FL_TOO_COMPLEX | (SHAPE_ID_OFFSET_MASK - 1),
};
// The interpreter doesn't care about frozen status or slot size when reading ivars. // The interpreter doesn't care about frozen status or slot size when reading ivars.
// So we normalize shape_id by clearing these bits to improve cache hits. // So we normalize shape_id by clearing these bits to improve cache hits.

View file

@ -103,6 +103,7 @@ fn main() {
.allowlist_function("rb_yjit_shape_capacity") .allowlist_function("rb_yjit_shape_capacity")
.allowlist_function("rb_yjit_shape_index") .allowlist_function("rb_yjit_shape_index")
.allowlist_var("SHAPE_ID_NUM_BITS") .allowlist_var("SHAPE_ID_NUM_BITS")
.allowlist_var("SHAPE_ID_HAS_IVAR_MASK")
// From ruby/internal/intern/object.h // From ruby/internal/intern/object.h
.allowlist_function("rb_obj_is_kind_of") .allowlist_function("rb_obj_is_kind_of")
@ -228,7 +229,6 @@ fn main() {
.allowlist_function("rb_obj_as_string_result") .allowlist_function("rb_obj_as_string_result")
.allowlist_function("rb_str_byte_substr") .allowlist_function("rb_str_byte_substr")
.allowlist_function("rb_str_substr_two_fixnums") .allowlist_function("rb_str_substr_two_fixnums")
.allowlist_function("rb_str_dup_m")
// From include/ruby/internal/intern/parse.h // From include/ruby/internal/intern/parse.h
.allowlist_function("rb_backref_get") .allowlist_function("rb_backref_get")

View file

@ -6278,9 +6278,14 @@ fn jit_rb_str_dup(
let recv_opnd = asm.stack_pop(1); let recv_opnd = asm.stack_pop(1);
let recv_opnd = asm.load(recv_opnd); let recv_opnd = asm.load(recv_opnd);
let shape_id_offset = unsafe { rb_shape_id_offset() };
let shape_opnd = Opnd::mem(64, recv_opnd, shape_id_offset);
asm.test(shape_opnd, Opnd::UImm(SHAPE_ID_HAS_IVAR_MASK as u64));
asm.jnz(Target::side_exit(Counter::send_str_dup_exivar));
// Call rb_str_dup // Call rb_str_dup
let stack_ret = asm.stack_push(Type::CString); let stack_ret = asm.stack_push(Type::CString);
let ret_opnd = asm.ccall(rb_str_dup_m as *const u8, vec![recv_opnd]); let ret_opnd = asm.ccall(rb_str_dup as *const u8, vec![recv_opnd]);
asm.mov(stack_ret, ret_opnd); asm.mov(stack_ret, ret_opnd);
true true

View file

@ -689,6 +689,8 @@ pub const VM_ENV_FLAG_ISOLATED: vm_frame_env_flags = 16;
pub type vm_frame_env_flags = u32; pub type vm_frame_env_flags = u32;
pub type attr_index_t = u16; pub type attr_index_t = u16;
pub type shape_id_t = u32; pub type shape_id_t = u32;
pub const SHAPE_ID_HAS_IVAR_MASK: _bindgen_ty_37 = 134742014;
pub type _bindgen_ty_37 = u32;
#[repr(C)] #[repr(C)]
pub struct rb_cvar_class_tbl_entry { pub struct rb_cvar_class_tbl_entry {
pub index: u32, pub index: u32,
@ -1120,7 +1122,6 @@ extern "C" {
pub fn rb_gvar_set(arg1: ID, arg2: VALUE) -> 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); pub fn rb_ensure_iv_list_size(obj: VALUE, current_len: u32, newsize: u32);
pub fn rb_vm_barrier(); pub fn rb_vm_barrier();
pub fn rb_str_dup_m(str_: VALUE) -> VALUE;
pub fn rb_str_byte_substr(str_: VALUE, beg: VALUE, len: VALUE) -> VALUE; pub fn rb_str_byte_substr(str_: VALUE, beg: VALUE, len: VALUE) -> VALUE;
pub fn rb_str_substr_two_fixnums( pub fn rb_str_substr_two_fixnums(
str_: VALUE, str_: VALUE,