Skip to content

Commit

Permalink
YJIT: Fix leaks by skipping objects with singleton class
Browse files Browse the repository at this point in the history
  • Loading branch information
XrXr committed Jan 23, 2024
1 parent 557b69e commit ab19268
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 0 deletions.
1 change: 1 addition & 0 deletions yjit/bindgen/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,7 @@ fn main() {
.allowlist_function("rb_obj_is_proc")
.allowlist_function("rb_vm_base_ptr")
.allowlist_function("rb_ec_stack_check")
.allowlist_function("rb_vm_top_self")

// We define VALUE manually, don't import it
.blocklist_type("VALUE")
Expand Down
17 changes: 17 additions & 0 deletions yjit/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7321,6 +7321,17 @@ fn gen_send_general(
assert_eq!(RUBY_T_CLASS, comptime_recv_klass.builtin_type(),
"objects visible to ruby code should have a T_CLASS in their klass field");


// Don't compile calls through singleton classes to avoid retaining the recevier.
// Make a special exception for top_self to help tests.
if VALUE(0) != unsafe { FL_TEST(comptime_recv_klass, VALUE(RUBY_FL_SINGLETON as usize)) }
&& comptime_recv != unsafe { rb_vm_top_self() }
&& !unsafe { RB_TYPE_P(comptime_recv, RUBY_T_CLASS) }
&& !unsafe { RB_TYPE_P(comptime_recv, RUBY_T_MODULE) } {
gen_counter_incr(asm, Counter::send_singleton_class);
return None;
}

// Points to the receiver operand on the stack
let recv = asm.stack_opnd(recv_idx);
let recv_opnd: YARVOpnd = recv.into();
Expand Down Expand Up @@ -8094,6 +8105,12 @@ fn gen_invokesuper_specialized(
return None;
}

// Don't compile `super` on objects with singleton class to avoid retaining the receiver.
if VALUE(0) != unsafe { FL_TEST(comptime_recv.class_of(), VALUE(RUBY_FL_SINGLETON as usize)) } {
gen_counter_incr(asm, Counter::invokesuper_singleton_class);
return None;
}

// Do method lookup
let cme = unsafe { rb_callable_method_entry(comptime_superclass, mid) };
if cme.is_null() {
Expand Down
1 change: 1 addition & 0 deletions yjit/src/cruby_bindings.inc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,7 @@ extern "C" {
n: ::std::os::raw::c_long,
elts: *const VALUE,
) -> VALUE;
pub fn rb_vm_top_self() -> VALUE;
pub static mut rb_vm_insns_count: u64;
pub fn rb_method_entry_at(obj: VALUE, id: ID) -> *const rb_method_entry_t;
pub fn rb_callable_method_entry(klass: VALUE, id: ID) -> *const rb_callable_method_entry_t;
Expand Down
2 changes: 2 additions & 0 deletions yjit/src/stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ make_counters! {
// Method calls that fallback to dynamic dispatch
send_keywords,
send_kw_splat,
send_singleton_class,
send_args_splat_super,
send_iseq_zsuper,
send_block_arg,
Expand Down Expand Up @@ -388,6 +389,7 @@ make_counters! {
invokesuper_no_me,
invokesuper_not_iseq_or_cfunc,
invokesuper_refinement,
invokesuper_singleton_class,

invokeblock_megamorphic,
invokeblock_none,
Expand Down

0 comments on commit ab19268

Please sign in to comment.