Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@nozomemein
Copy link

@nozomemein nozomemein commented Dec 27, 2025

Closes: Shopify#804

Benchmark

optcarrot

  • wall-clock time
    • before patch: Average of last 10, non-warmup iters: 7019ms
    • after patch: Average of last 10, non-warmup iters: 6931ms
  • zjit stats below
before patch
***ZJIT: Printing ZJIT statistics on exit***
Top-20 not inlined C methods (100.0% of total 152,051,106):
             Integer#[]: 73,418,673 (48.3%)
              Array#[]=: 39,375,756 (25.9%)
          Array#rotate!: 38,357,428 (25.2%)
             Integer#<=:    405,116 ( 0.3%)
              Method#[]:    397,510 ( 0.3%)
             Integer#>>:     38,868 ( 0.0%)
            Array#clear:     14,913 ( 0.0%)
            Array#shift:      4,971 ( 0.0%)
  Process.clock_gettime:      4,971 ( 0.0%)
               Float#**:      4,971 ( 0.0%)
           Array#concat:      4,971 ( 0.0%)
            Fiber.yield:      4,971 ( 0.0%)
                Float#-:      4,971 ( 0.0%)
                Float#/:      4,971 ( 0.0%)
       Numeric#nonzero?:      1,686 ( 0.0%)
             File.file?:        737 ( 0.0%)
               String#+:        737 ( 0.0%)
             Array#any?:        593 ( 0.0%)
          Regexp#match?:        565 ( 0.0%)
            Float#floor:        483 ( 0.0%)
Top-20 calls to C functions from JIT code (100.0% of total 1,628,197,525):
                          rb_ary_entry: 425,336,671 (26.1%)
          rb_vm_opt_send_without_block: 390,605,606 (24.0%)
  rb_zjit_writebarrier_check_immediate: 330,061,301 (20.3%)
             rb_vm_getinstancevariable: 201,447,225 (12.4%)
                            Integer#[]:  73,418,673 ( 4.5%)
             rb_vm_setinstancevariable:  55,673,852 ( 3.4%)
                     rb_vm_splat_array:  48,937,000 ( 3.0%)
                             Array#[]=:  39,375,756 ( 2.4%)
                         Array#rotate!:  38,357,428 ( 2.4%)
                    rb_jit_fix_div_fix:  11,105,867 ( 0.7%)
            rb_vm_opt_getconstant_path:   4,663,515 ( 0.3%)
                           rb_ary_push:   3,841,256 ( 0.2%)
                            Array#size:   3,700,369 ( 0.2%)
                            Integer#<=:     405,116 ( 0.0%)
                             Method#[]:     397,510 ( 0.0%)
                                _bi125:     215,032 ( 0.0%)
                          rb_hash_aref:     197,218 ( 0.0%)
                     rb_vm_invokesuper:     117,844 ( 0.0%)
                        rb_fix_mod_fix:     115,073 ( 0.0%)
             rb_ec_ary_new_from_values:     101,649 ( 0.0%)
after patch
***ZJIT: Printing ZJIT statistics on exit***
Top-20 not inlined C methods (100.0% of total 151,032,778):
             Integer#[]: 73,418,673 (48.6%)
          Array#rotate!: 38,357,428 (25.4%)
              Array#[]=: 38,357,428 (25.4%)
             Integer#<=:    405,116 ( 0.3%)
              Method#[]:    397,510 ( 0.3%)
             Integer#>>:     38,868 ( 0.0%)
            Array#clear:     14,913 ( 0.0%)
            Array#shift:      4,971 ( 0.0%)
                Float#/:      4,971 ( 0.0%)
  Process.clock_gettime:      4,971 ( 0.0%)
                Float#-:      4,971 ( 0.0%)
            Fiber.yield:      4,971 ( 0.0%)
               Float#**:      4,971 ( 0.0%)
           Array#concat:      4,971 ( 0.0%)
       Numeric#nonzero?:      1,686 ( 0.0%)
               String#+:        737 ( 0.0%)
             File.file?:        737 ( 0.0%)
             Array#any?:        593 ( 0.0%)
          Regexp#match?:        565 ( 0.0%)
            Float#floor:        483 ( 0.0%)
Top-20 calls to C functions from JIT code (100.0% of total 1,628,197,525):
                          rb_ary_entry: 425,336,671 (26.1%)
          rb_vm_opt_send_without_block: 390,605,606 (24.0%)
  rb_zjit_writebarrier_check_immediate: 330,061,301 (20.3%)
             rb_vm_getinstancevariable: 201,447,225 (12.4%)
                            Integer#[]:  73,418,673 ( 4.5%)
             rb_vm_setinstancevariable:  55,673,852 ( 3.4%)
                     rb_vm_splat_array:  48,937,000 ( 3.0%)
                         Array#rotate!:  38,357,428 ( 2.4%)
                             Array#[]=:  38,357,428 ( 2.4%)
                    rb_jit_fix_div_fix:  11,105,867 ( 0.7%)
            rb_vm_opt_getconstant_path:   4,663,515 ( 0.3%)
                           rb_ary_push:   3,841,256 ( 0.2%)
                            Array#size:   3,700,369 ( 0.2%)
                          rb_ary_store:   1,018,328 ( 0.1%)
                            Integer#<=:     405,116 ( 0.0%)
                             Method#[]:     397,510 ( 0.0%)
                                _bi125:     215,032 ( 0.0%)
                          rb_hash_aref:     197,218 ( 0.0%)
                     rb_vm_invokesuper:     117,844 ( 0.0%)
                        rb_fix_mod_fix:     115,073 ( 0.0%)

@nozomemein nozomemein force-pushed the zjit-specialize-array-set branch 2 times, most recently from c3280a3 to a7e915e Compare December 27, 2025 09:47
self.assert_subtype(insn_id, index, types::Fixnum)
}
Insn::ArrayAsetFixnum { array, index, .. } => {
self.assert_subtype(insn_id, array, types::Array)?;
Copy link
Author

@nozomemein nozomemein Dec 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’m not sure we should optimize for subclasses here, since it seems we don’t for Hash. Maybe Array should follow the same rule? (ArrayArefFixnum currently allows the subclasses to be optimized though.)

let index = fun.coerce_to(block, index, types::Fixnum, state);
let val = fun.coerce_to(block, val, types::BasicObject, state);

let _ = fun.push_insn(block, hir::Insn::ArrayAsetFixnum { array: recv, index, val, state });
Copy link
Author

@nozomemein nozomemein Dec 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although Max’s comment in the original issue suggested adding a length check here, I thought this might be sufficient since the called C function will handle it anyway.
That said, I’m not entirely confident, please let me know if I’m missing something.

Also, if we want to make this leaf/nogc, do we need additional guards for not frozen / not shared before treating it as leaf/nogc...?

Copy link
Author

@nozomemein nozomemein Dec 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NOTE: Below is the breakdown of in-bounds vs. out-of-bounds for the inline Array#[]= path using several benchmarks. (related to Shopify#804 (comment))

Terms:

  • array_aset_fixnum_inline_count: Number of times we took the inline Array#[]= fast path with a Fixnum index
  • array_aset_fixnum_inline_in_bounds_count: Among those inline calls, how many had an index within bounds (0 <= idx < len or -len <= idx < 0).
  • array_aset_fixnum_inline_oob_count: Among those inline calls, how many had an out-of-bounds index.

Results:

  • optcarrot
          array_aset_fixnum_inline_count:     1,018,328
array_aset_fixnum_inline_in_bounds_count:     1,016,305
      array_aset_fixnum_inline_oob_count:         2,023
  • liquid-render
          array_aset_fixnum_inline_count:          35
array_aset_fixnum_inline_in_bounds_count:           0
      array_aset_fixnum_inline_oob_count:          35
  • railsbench
          array_aset_fixnum_inline_count:     131,681
array_aset_fixnum_inline_in_bounds_count:     131,681
      array_aset_fixnum_inline_oob_count:           0

@nozomemein nozomemein force-pushed the zjit-specialize-array-set branch from a7e915e to 5ef58f9 Compare December 31, 2025 06:21
@launchable-app

This comment has been minimized.

@nozomemein nozomemein force-pushed the zjit-specialize-array-set branch 2 times, most recently from 64f31f5 to a7a557d Compare December 31, 2025 23:54
@nozomemein nozomemein force-pushed the zjit-specialize-array-set branch from a7a557d to 19d5b63 Compare January 1, 2026 00:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ZJIT: Inline Array#[]= into HIR

1 participant