Skip to content

Commit ab19268

Browse files
committed
YJIT: Fix leaks by skipping objects with singleton class
1 parent 557b69e commit ab19268

File tree

4 files changed

+21
-0
lines changed

4 files changed

+21
-0
lines changed

yjit/bindgen/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,7 @@ fn main() {
446446
.allowlist_function("rb_obj_is_proc")
447447
.allowlist_function("rb_vm_base_ptr")
448448
.allowlist_function("rb_ec_stack_check")
449+
.allowlist_function("rb_vm_top_self")
449450

450451
// We define VALUE manually, don't import it
451452
.blocklist_type("VALUE")

yjit/src/codegen.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7321,6 +7321,17 @@ fn gen_send_general(
73217321
assert_eq!(RUBY_T_CLASS, comptime_recv_klass.builtin_type(),
73227322
"objects visible to ruby code should have a T_CLASS in their klass field");
73237323

7324+
7325+
// Don't compile calls through singleton classes to avoid retaining the recevier.
7326+
// Make a special exception for top_self to help tests.
7327+
if VALUE(0) != unsafe { FL_TEST(comptime_recv_klass, VALUE(RUBY_FL_SINGLETON as usize)) }
7328+
&& comptime_recv != unsafe { rb_vm_top_self() }
7329+
&& !unsafe { RB_TYPE_P(comptime_recv, RUBY_T_CLASS) }
7330+
&& !unsafe { RB_TYPE_P(comptime_recv, RUBY_T_MODULE) } {
7331+
gen_counter_incr(asm, Counter::send_singleton_class);
7332+
return None;
7333+
}
7334+
73247335
// Points to the receiver operand on the stack
73257336
let recv = asm.stack_opnd(recv_idx);
73267337
let recv_opnd: YARVOpnd = recv.into();
@@ -8094,6 +8105,12 @@ fn gen_invokesuper_specialized(
80948105
return None;
80958106
}
80968107

8108+
// Don't compile `super` on objects with singleton class to avoid retaining the receiver.
8109+
if VALUE(0) != unsafe { FL_TEST(comptime_recv.class_of(), VALUE(RUBY_FL_SINGLETON as usize)) } {
8110+
gen_counter_incr(asm, Counter::invokesuper_singleton_class);
8111+
return None;
8112+
}
8113+
80978114
// Do method lookup
80988115
let cme = unsafe { rb_callable_method_entry(comptime_superclass, mid) };
80998116
if cme.is_null() {

yjit/src/cruby_bindings.inc.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -974,6 +974,7 @@ extern "C" {
974974
n: ::std::os::raw::c_long,
975975
elts: *const VALUE,
976976
) -> VALUE;
977+
pub fn rb_vm_top_self() -> VALUE;
977978
pub static mut rb_vm_insns_count: u64;
978979
pub fn rb_method_entry_at(obj: VALUE, id: ID) -> *const rb_method_entry_t;
979980
pub fn rb_callable_method_entry(klass: VALUE, id: ID) -> *const rb_callable_method_entry_t;

yjit/src/stats.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,7 @@ make_counters! {
300300
// Method calls that fallback to dynamic dispatch
301301
send_keywords,
302302
send_kw_splat,
303+
send_singleton_class,
303304
send_args_splat_super,
304305
send_iseq_zsuper,
305306
send_block_arg,
@@ -388,6 +389,7 @@ make_counters! {
388389
invokesuper_no_me,
389390
invokesuper_not_iseq_or_cfunc,
390391
invokesuper_refinement,
392+
invokesuper_singleton_class,
391393

392394
invokeblock_megamorphic,
393395
invokeblock_none,

0 commit comments

Comments
 (0)