Skip to content

Commit ae9e1ae

Browse files
Call rb_ivar_set instead of exiting for many ivars
Previously, when we have a lot of ivars defined, we would exit via `jit_chain_guard` for megamorphic ivars. Now if we have more than the max depth of ivars we can call `rb_ivar_set` instead of exiting. Using the following script: ```ruby class A def initialize @A = 1 end def a @A end end N = 30 N.times do |i| eval <<-eorb class A#{i} < A def initialize @A#{i} = 1 super end end eorb end klasses = N.times.map { Object.const_get(:"A#{_1}") } 1000.times do klasses.each do |k| k.new.a end end ``` Exits before this change show exits for `setinstancevariable`: ``` ***YJIT: Printing YJIT statistics on exit*** method call exit reasons: klass_megamorphic: 24,975 (100.0%) invokeblock exit reasons: (all relevant counters are zero) invokesuper exit reasons: (all relevant counters are zero) leave exit reasons: interp_return: 26,948 (100.0%) se_interrupt: 1 ( 0.0%) getblockparamproxy exit reasons: (all relevant counters are zero) getinstancevariable exit reasons: megamorphic: 13,986 (100.0%) setinstancevariable exit reasons: megamorphic: 19,980 (100.0%) opt_aref exit reasons: (all relevant counters are zero) expandarray exit reasons: (all relevant counters are zero) opt_getinlinecache exit reasons: (all relevant counters are zero) invalidation reasons: (all relevant counters are zero) num_send: 155,823 num_send_known_class: 0 ( 0.0%) num_send_polymorphic: 119,880 (76.9%) bindings_allocations: 0 bindings_set: 0 compiled_iseq_count: 36 compiled_block_count: 158 compiled_branch_count: 240 block_next_count: 10 defer_count: 70 freed_iseq_count: 0 invalidation_count: 0 constant_state_bumps: 0 inline_code_size: 29,216 outlined_code_size: 27,948 freed_code_size: 0 code_region_size: 65,536 live_context_size: 8,322 live_context_count: 219 live_page_count: 4 freed_page_count: 0 code_gc_count: 0 num_gc_obj_refs: 130 object_shape_count: 295 side_exit_count: 58,942 total_exit_count: 85,890 yjit_insns_count: 1,023,581 avg_len_in_yjit: 11.2 Top-4 most frequent exit ops (100.0% of exits): opt_send_without_block: 24,975 (42.4%) setinstancevariable: 19,980 (33.9%) getinstancevariable: 13,986 (23.7%) leave: 1 ( 0.0%) ``` Exits after this change show we have no exits for `setinstancevariable`. ``` ***YJIT: Printing YJIT statistics on exit*** method call exit reasons: klass_megamorphic: 24,975 (100.0%) invokeblock exit reasons: (all relevant counters are zero) invokesuper exit reasons: (all relevant counters are zero) leave exit reasons: interp_return: 60,912 (100.0%) se_interrupt: 3 ( 0.0%) getblockparamproxy exit reasons: (all relevant counters are zero) getinstancevariable exit reasons: (all relevant counters are zero) setinstancevariable exit reasons: (all relevant counters are zero) opt_aref exit reasons: (all relevant counters are zero) expandarray exit reasons: (all relevant counters are zero) opt_getinlinecache exit reasons: (all relevant counters are zero) invalidation reasons: (all relevant counters are zero) num_send: 155,823 num_send_known_class: 0 ( 0.0%) num_send_polymorphic: 119,880 (76.9%) bindings_allocations: 0 bindings_set: 0 compiled_iseq_count: 36 compiled_block_count: 179 compiled_branch_count: 240 block_next_count: 11 defer_count: 70 freed_iseq_count: 0 invalidation_count: 0 constant_state_bumps: 0 inline_code_size: 31,032 outlined_code_size: 29,708 freed_code_size: 0 code_region_size: 65,536 live_context_size: 8,360 live_context_count: 220 live_page_count: 4 freed_page_count: 0 code_gc_count: 0 num_gc_obj_refs: 130 object_shape_count: 295 side_exit_count: 24,978 total_exit_count: 85,890 yjit_insns_count: 1,076,966 avg_len_in_yjit: 12.2 Top-2 most frequent exit ops (100.0% of exits): opt_send_without_block: 24,975 (100.0%) leave: 3 ( 0.0%) ``` Co-authored-by: Aaron Patterson <tenderlove@ruby-lang.org>
1 parent 9f8056a commit ae9e1ae

File tree

1 file changed

+1
-1
lines changed

1 file changed

+1
-1
lines changed

yjit/src/codegen.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2182,7 +2182,7 @@ fn gen_setinstancevariable(
21822182
// If the receiver isn't a T_OBJECT, or uses a custom allocator,
21832183
// then just write out the IV write as a function call.
21842184
// too-complex shapes can't use index access, so we use rb_ivar_get for them too.
2185-
if !receiver_t_object || uses_custom_allocator || comptime_receiver.shape_too_complex() {
2185+
if !receiver_t_object || uses_custom_allocator || comptime_receiver.shape_too_complex() || (ctx.get_chain_depth() as i32) >= SET_IVAR_MAX_DEPTH {
21862186
asm.comment("call rb_vm_setinstancevariable()");
21872187

21882188
let ic = jit.get_arg(1).as_u64(); // type IVC

0 commit comments

Comments
 (0)