23 Commits
Author SHA1 Message Date
Takashi Kokubun e4beaa2c9c merge revision(s) 9efe557da5, 53f7189ff9: [Backport #22224]
[PATCH] ZJIT: Drop has_blockiseq guard on local variable access (#16113)

	So `has_blockiseq` was masking two other bugs.

	First, that we had only a static EP escape check for an iseq. We need to check
	both that an iseq is not known to statically escape them *and that it has not
	escaped them before*. Only then can we use SSA locals. This popped up in a
	weird PP unit test that was reducible to the test cases added in the PR. So I
	fixed that.

	Second, that we didn't VM lock when code patching for EP escape. That showed up
	in the Ractor btests in my previous PRs #14600 and #15254 #15316, and I had no
	idea what was going on at the time, so I dropped it. But if we add this lock,
	like all the other invariant patching cases have, the problem goes away. Seems
	reasonable.

	Finally, we can use normal full SSA locals even in the presence of a blockiseq.
	We still reload all of them after each send-with-block, but we can in a later
	PR reduce that to just the locals that are (recursively) visibly written to.

	[PATCH] [Bug #22224] Ractors, YJIT: Skip re-reporting recorded EP escapes to the JITs (#18176)

	* [22224] Ractors, YJIT: Skip re-reporting recorded EP escapes to the JITs

	vm_make_env_each reports every EP escape, and both
	rb_yjit_invalidate_ep_is_bp and rb_zjit_invalidate_no_ep_escape take
	the VM lock with a stop-all-Ractors barrier on every call. For a given
	iseq only the first report does anything: afterwards YJIT's
	no_ep_escape_iseqs entry is permanently an empty set and ZJIT's
	ep_escape_iseqs insert is a no-op, so the barrier is paid for nothing.
	Under multiple Ractors this serializes the whole process on every Proc
	created from an already-escaped iseq: a workload creating one lambda
	per iteration runs 150x slower on 8 Ractors than on 1 with YJIT
	enabled.

	Record the report in a jit_ep_escape_recorded flag on the iseq body,
	set by the active JIT while it holds the VM lock, and skip the calls
	in vm_make_env_each once it is set. The flag sits in existing padding
	and the body is ZALLOC'd, so it starts false and dies with the iseq.
	Setting it in the JIT rather than in the caller keeps mid-process
	RubyVM::YJIT.enable correct: escapes reported while no JIT is
	initialized are recorded by nobody and must not set the flag. The
	unlocked read is benign: a stale false causes one redundant,
	idempotent report.

	On the micro-benchmark from the bug, --yjit at 8 Ractors goes from
	0.04M to 11.07M iterations/s (277x).

	* [22224] Deduplicate the EP escape record onto the iseq body

	The jit_ep_escape_recorded flag introduced in the previous commit is
	now the JITs' only record of an EP escape: YJIT's no_ep_escape_iseqs
	keeps only iseqs with live assumptions (the empty-set escape markers
	are gone), and ZJIT's ep_escape_iseqs set is removed together with its
	update_ep_escape_iseqs compaction pass, since the flag lives in the
	iseq body, which the GC does not move. Both JITs read the flag back at
	compile time through a new rb_jit_iseq_ep_escape_recorded_p helper.

	Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>

Only the two correctness changes of 9efe557da5 are backported: the runtime
EP-escape check in iseq_to_hir() and the VM lock in
rb_zjit_invalidate_no_ep_escape().  Without the former, suppressing repeat
escape reports would leave NoEPEscape patch points registered after an
escape never invalidated, because ZJIT here registers them unconditionally.
Its has_blockiseq removal is an optimization and is left out; keeping
has_blockiseq is strictly more conservative.

ZJIT here keeps the name invariants::iseq_escapes_ep() rather than renaming
it to iseq_seen_ep_escape(), since e0184fff1a is not backported.
2026-09-14 15:48:53 -07:00
John HawthornandAlan Wu 73e930f9f9 JIT: Move EC offsets to jit_bindgen_constants
Co-authored-by: Alan Wu <alanwu@ruby-lang.org>
2025-12-18 13:43:45 -08:00
Abrar Habib edca81a1bb ZJIT: Add codegen for FixnumDiv (#15452)
Fixes https://github.com/Shopify/ruby/issues/902

This pull request adds code generation for dividing fixnums.
Testing confirms the normal case, flooring, and side-exiting on division by zero.
2025-12-09 12:41:09 +00:00
Alan Wu 02ca507aa3 JITs: rb_iseq_opcode_at_pc(): Accommodate switch-case interpreter 2025-12-05 15:49:25 -05:00
Max BernsteinandAaron Patterson 0af85a1fe2 ZJIT: Optimize setivar with shape transition (#15375)
Since we do a decent job of pre-sizing objects, don't handle the case where we would need to re-size an object. Also don't handle too-complex shapes.

lobsters stats before:

```
Top-20 calls to C functions from JIT code (79.4% of total 90,051,140):
                             rb_vm_opt_send_without_block: 19,762,433 (21.9%)
                                rb_vm_setinstancevariable:  7,698,314 ( 8.5%)
                                             rb_hash_aref:  6,767,461 ( 7.5%)
                                          rb_vm_env_write:  5,373,080 ( 6.0%)
                                               rb_vm_send:  5,049,229 ( 5.6%)
                                rb_vm_getinstancevariable:  4,535,259 ( 5.0%)
                                        rb_obj_is_kind_of:  3,746,306 ( 4.2%)
                           rb_ivar_get_at_no_ractor_check:  3,745,237 ( 4.2%)
                                        rb_vm_invokesuper:  3,037,467 ( 3.4%)
                                             rb_ary_entry:  2,351,983 ( 2.6%)
                               rb_vm_opt_getconstant_path:  1,344,740 ( 1.5%)
                                        rb_vm_invokeblock:  1,184,474 ( 1.3%)
                                                 Hash#[]=:  1,064,288 ( 1.2%)
                                       rb_gc_writebarrier:  1,006,972 ( 1.1%)
                                rb_ec_ary_new_from_values:    902,687 ( 1.0%)
                                                    fetch:    898,667 ( 1.0%)
                                        rb_str_buf_append:    833,787 ( 0.9%)
                               rb_class_allocate_instance:    822,024 ( 0.9%)
                                               Hash#fetch:    699,580 ( 0.8%)
                                                    _bi20:    682,068 ( 0.8%)
Top-4 setivar fallback reasons (100.0% of total 7,732,326):
  shape_transition: 6,032,109 (78.0%)
   not_monomorphic: 1,469,300 (19.0%)
      not_t_object:   172,636 ( 2.2%)
       too_complex:    58,281 ( 0.8%)
```

lobsters stats after:

```
Top-20 calls to C functions from JIT code (79.0% of total 88,322,656):
                             rb_vm_opt_send_without_block: 19,777,880 (22.4%)
                                             rb_hash_aref:  6,771,589 ( 7.7%)
                                          rb_vm_env_write:  5,372,789 ( 6.1%)
                                       rb_gc_writebarrier:  5,195,527 ( 5.9%)
                                               rb_vm_send:  5,049,145 ( 5.7%)
                                rb_vm_getinstancevariable:  4,538,485 ( 5.1%)
                                        rb_obj_is_kind_of:  3,746,241 ( 4.2%)
                           rb_ivar_get_at_no_ractor_check:  3,745,172 ( 4.2%)
                                        rb_vm_invokesuper:  3,037,157 ( 3.4%)
                                             rb_ary_entry:  2,351,968 ( 2.7%)
                                rb_vm_setinstancevariable:  1,703,337 ( 1.9%)
                               rb_vm_opt_getconstant_path:  1,344,730 ( 1.5%)
                                        rb_vm_invokeblock:  1,184,290 ( 1.3%)
                                                 Hash#[]=:  1,061,868 ( 1.2%)
                                rb_ec_ary_new_from_values:    902,666 ( 1.0%)
                                                    fetch:    898,666 ( 1.0%)
                                        rb_str_buf_append:    833,784 ( 0.9%)
                               rb_class_allocate_instance:    821,778 ( 0.9%)
                                               Hash#fetch:    755,913 ( 0.9%)
Top-4 setivar fallback reasons (100.0% of total 1,703,337):
            not_monomorphic: 1,472,405 (86.4%)
               not_t_object:   172,629 (10.1%)
                too_complex:    58,281 ( 3.4%)
  new_shape_needs_extension:        22 ( 0.0%)
```

I also noticed that primitive printing in HIR was broken so I fixed that.

Co-authored-by: Aaron Patterson <tenderlove@ruby-lang.org>
2025-12-03 21:27:56 -05:00
Max Bernstein 8aed311038 ZJIT: Specialize String#<< with Fixnum
Append a codepoint.
2025-12-01 15:19:26 -08:00
Max Bernstein fa5481bc06 ZJIT: Fetch Primitive.attr!(leaf) for InvokeBuiltin
Fix https://github.com/Shopify/ruby/issues/670
2025-10-22 17:10:14 -07:00
Max Bernstein 9ad902e55c ZJIT: Inline String#==, String#=== 2025-10-22 12:39:57 -07:00
Alan Wu bb7f3d17ed YJIT: ZJIT: Extract common bindings to jit.c and remove unnamed enums.
The type name bindgen picks for anonymous enums creates desync issues on
the bindgen CI checks.
2025-10-21 16:48:45 -04:00
Alan Wu 35c2230734 ZJIT: Fix binding to INVALID_SHAPE_ID under -std=c99 -pedantic
```
  /src/jit.c:19:5: error: ISO C restricts enumerator values to range of 'int' (4294967295 is too large) [-Werror,-Wpedantic]
     19 |     RB_INVALID_SHAPE_ID = INVALID_SHAPE_ID,
        |     ^                     ~~~~~~~~~~~~~~~~
```
2025-10-21 16:48:45 -04:00
Max Bernstein 17368234bf ZJIT: Implement codegen for FixnumMod (#14857)
This is mostly to see what happens to the loops-times benchmark.
2025-10-20 21:30:48 +00:00
Max Bernstein fba349e658 ZJIT: Implement expandarray (#14847)
Only support the simple case: no splat or rest.

lobsters before:

<details>

```
***ZJIT: Printing ZJIT statistics on exit***
Top-20 not inlined C methods (60.5% of total 11,039,954):
                               Kernel#is_a?: 1,030,769 ( 9.3%)
                                  String#<<:   851,954 ( 7.7%)
                                   Hash#[]=:   742,941 ( 6.7%)
                              Regexp#match?:   399,894 ( 3.6%)
                              String#empty?:   353,775 ( 3.2%)
                                  Hash#key?:   349,147 ( 3.2%)
                         String#start_with?:   334,961 ( 3.0%)
                         Kernel#respond_to?:   316,528 ( 2.9%)
                 ObjectSpace::WeakKeyMap#[]:   238,978 ( 2.2%)
                              TrueClass#===:   235,771 ( 2.1%)
                             FalseClass#===:   231,144 ( 2.1%)
                             Array#include?:   211,385 ( 1.9%)
                                 Hash#fetch:   204,702 ( 1.9%)
                        Kernel#block_given?:   181,797 ( 1.6%)
                                 Kernel#dup:   179,341 ( 1.6%)
                             BasicObject#!=:   175,997 ( 1.6%)
                                  Class#new:   168,079 ( 1.5%)
                            Kernel#kind_of?:   165,600 ( 1.5%)
                                  String#==:   157,735 ( 1.4%)
                       Module#clock_gettime:   144,992 ( 1.3%)
Top-20 not annotated C methods (61.4% of total 11,202,087):
                               Kernel#is_a?: 1,212,660 (10.8%)
                                  String#<<:   851,954 ( 7.6%)
                                   Hash#[]=:   743,120 ( 6.6%)
                              Regexp#match?:   399,894 ( 3.6%)
                              String#empty?:   361,013 ( 3.2%)
                                  Hash#key?:   349,147 ( 3.1%)
                         String#start_with?:   334,961 ( 3.0%)
                         Kernel#respond_to?:   316,528 ( 2.8%)
                 ObjectSpace::WeakKeyMap#[]:   238,978 ( 2.1%)
                              TrueClass#===:   235,771 ( 2.1%)
                             FalseClass#===:   231,144 ( 2.1%)
                             Array#include?:   211,385 ( 1.9%)
                                 Hash#fetch:   204,702 ( 1.8%)
                        Kernel#block_given?:   191,666 ( 1.7%)
                                 Kernel#dup:   179,348 ( 1.6%)
                             BasicObject#!=:   176,181 ( 1.6%)
                                  Class#new:   168,079 ( 1.5%)
                            Kernel#kind_of?:   165,634 ( 1.5%)
                                  String#==:   163,667 ( 1.5%)
                       Module#clock_gettime:   144,992 ( 1.3%)
Top-2 not optimized method types for send (100.0% of total 72,318):
  cfunc: 48,055 (66.4%)
   iseq: 24,263 (33.6%)
Top-6 not optimized method types for send_without_block (100.0% of total 4,523,682):
       iseq: 2,271,936 (50.2%)
    bmethod:   985,636 (21.8%)
  optimized:   949,703 (21.0%)
      alias:   310,747 ( 6.9%)
       null:     5,106 ( 0.1%)
      cfunc:       554 ( 0.0%)
Top-13 not optimized instructions (100.0% of total 4,293,171):
             invokesuper: 2,373,404 (55.3%)
             invokeblock:   811,926 (18.9%)
             sendforward:   505,452 (11.8%)
                  opt_eq:   451,754 (10.5%)
                opt_plus:    74,404 ( 1.7%)
               opt_minus:    36,228 ( 0.8%)
  opt_send_without_block:    21,792 ( 0.5%)
                 opt_neq:     7,231 ( 0.2%)
                opt_mult:     6,752 ( 0.2%)
                  opt_or:     3,753 ( 0.1%)
                  opt_lt:       348 ( 0.0%)
                  opt_ge:        91 ( 0.0%)
                  opt_gt:        36 ( 0.0%)
Top-9 send fallback reasons (100.0% of total 25,530,724):
                send_without_block_polymorphic: 9,722,491 (38.1%)
                              send_no_profiles: 5,894,788 (23.1%)
  send_without_block_not_optimized_method_type: 4,523,682 (17.7%)
                     not_optimized_instruction: 4,293,171 (16.8%)
                send_without_block_no_profiles:   998,746 ( 3.9%)
                send_not_optimized_method_type:    72,318 ( 0.3%)
       send_without_block_cfunc_array_variadic:    15,134 ( 0.1%)
                      obj_to_string_not_string:     9,765 ( 0.0%)
       send_without_block_direct_too_many_args:       629 ( 0.0%)
Top-9 unhandled YARV insns (100.0% of total 690,950):
         expandarray: 328,490 (47.5%)
        checkkeyword: 190,694 (27.6%)
    getclassvariable:  59,901 ( 8.7%)
  invokesuperforward:  49,503 ( 7.2%)
       getblockparam:  49,119 ( 7.1%)
   opt_duparray_send:  11,978 ( 1.7%)
         getconstant:     952 ( 0.1%)
          checkmatch:     290 ( 0.0%)
                once:      23 ( 0.0%)
Top-3 compile error reasons (100.0% of total 3,718,636):
  register_spill_on_alloc: 3,418,255 (91.9%)
  register_spill_on_ccall:   182,018 ( 4.9%)
        exception_handler:   118,363 ( 3.2%)
Top-14 side exit reasons (100.0% of total 10,860,385):
                        compile_error: 3,718,636 (34.2%)
                   guard_type_failure: 2,638,926 (24.3%)
                  guard_shape_failure: 1,917,209 (17.7%)
                  unhandled_yarv_insn:   690,950 ( 6.4%)
  block_param_proxy_not_iseq_or_ifunc:   535,789 ( 4.9%)
                      unhandled_kwarg:   455,347 ( 4.2%)
                           patchpoint:   370,476 ( 3.4%)
                unknown_newarray_send:   314,786 ( 2.9%)
                      unhandled_splat:   122,071 ( 1.1%)
                   unhandled_hir_insn:    76,397 ( 0.7%)
           block_param_proxy_modified:    19,193 ( 0.2%)
               obj_to_string_fallback:       566 ( 0.0%)
               guard_type_not_failure:        22 ( 0.0%)
                            interrupt:        17 ( 0.0%)
                             send_count: 62,244,604
                     dynamic_send_count: 25,530,724 (41.0%)
                   optimized_send_count: 36,713,880 (59.0%)
              iseq_optimized_send_count: 18,587,512 (29.9%)
      inline_cfunc_optimized_send_count:  7,086,414 (11.4%)
non_variadic_cfunc_optimized_send_count:  8,375,754 (13.5%)
    variadic_cfunc_optimized_send_count:  2,664,200 ( 4.3%)
dynamic_getivar_count:                        7,365,995
dynamic_setivar_count:                        7,245,005
compiled_iseq_count:                              4,796
failed_iseq_count:                                  447
compile_time:                                     814ms
profile_time:                                       9ms
gc_time:                                            9ms
invalidation_time:                                 72ms
vm_write_pc_count:                           64,156,223
vm_write_sp_count:                           62,812,449
vm_write_locals_count:                       62,812,449
vm_write_stack_count:                        62,812,449
vm_write_to_parent_iseq_local_count:            292,458
vm_read_from_parent_iseq_local_count:         6,599,701
code_region_bytes:                           22,953,984
side_exit_count:                             10,860,385
total_insn_count:                           517,606,340
vm_insn_count:                              162,979,530
zjit_insn_count:                            354,626,810
ratio_in_zjit:                                    68.5%
```

</details>

lobsters after:

<details>

```
***ZJIT: Printing ZJIT statistics on exit***
Top-20 not inlined C methods (59.9% of total 11,291,815):
                               Kernel#is_a?: 1,046,269 ( 9.3%)
                                  String#<<:   851,954 ( 7.5%)
                                   Hash#[]=:   743,274 ( 6.6%)
                              Regexp#match?:   399,894 ( 3.5%)
                              String#empty?:   353,775 ( 3.1%)
                                  Hash#key?:   349,147 ( 3.1%)
                         String#start_with?:   334,961 ( 3.0%)
                         Kernel#respond_to?:   316,502 ( 2.8%)
                 ObjectSpace::WeakKeyMap#[]:   238,978 ( 2.1%)
                              TrueClass#===:   235,771 ( 2.1%)
                             FalseClass#===:   231,144 ( 2.0%)
                                String#sub!:   219,579 ( 1.9%)
                             Array#include?:   211,385 ( 1.9%)
                                 Hash#fetch:   204,702 ( 1.8%)
                        Kernel#block_given?:   181,797 ( 1.6%)
                                 Kernel#dup:   179,341 ( 1.6%)
                             BasicObject#!=:   175,997 ( 1.6%)
                                  Class#new:   168,079 ( 1.5%)
                            Kernel#kind_of?:   165,600 ( 1.5%)
                                  String#==:   157,742 ( 1.4%)
Top-20 not annotated C methods (60.9% of total 11,466,928):
                               Kernel#is_a?: 1,239,923 (10.8%)
                                  String#<<:   851,954 ( 7.4%)
                                   Hash#[]=:   743,453 ( 6.5%)
                              Regexp#match?:   399,894 ( 3.5%)
                              String#empty?:   361,013 ( 3.1%)
                                  Hash#key?:   349,147 ( 3.0%)
                         String#start_with?:   334,961 ( 2.9%)
                         Kernel#respond_to?:   316,502 ( 2.8%)
                 ObjectSpace::WeakKeyMap#[]:   238,978 ( 2.1%)
                              TrueClass#===:   235,771 ( 2.1%)
                             FalseClass#===:   231,144 ( 2.0%)
                                String#sub!:   219,579 ( 1.9%)
                             Array#include?:   211,385 ( 1.8%)
                                 Hash#fetch:   204,702 ( 1.8%)
                        Kernel#block_given?:   191,666 ( 1.7%)
                                 Kernel#dup:   179,348 ( 1.6%)
                             BasicObject#!=:   176,181 ( 1.5%)
                                  Class#new:   168,079 ( 1.5%)
                            Kernel#kind_of?:   165,634 ( 1.4%)
                                  String#==:   163,674 ( 1.4%)
Top-2 not optimized method types for send (100.0% of total 72,318):
  cfunc: 48,055 (66.4%)
   iseq: 24,263 (33.6%)
Top-6 not optimized method types for send_without_block (100.0% of total 4,524,016):
       iseq: 2,272,269 (50.2%)
    bmethod:   985,636 (21.8%)
  optimized:   949,704 (21.0%)
      alias:   310,747 ( 6.9%)
       null:     5,106 ( 0.1%)
      cfunc:       554 ( 0.0%)
Top-13 not optimized instructions (100.0% of total 4,294,241):
             invokesuper: 2,375,446 (55.3%)
             invokeblock:   810,955 (18.9%)
             sendforward:   505,451 (11.8%)
                  opt_eq:   451,754 (10.5%)
                opt_plus:    74,404 ( 1.7%)
               opt_minus:    36,228 ( 0.8%)
  opt_send_without_block:    21,792 ( 0.5%)
                 opt_neq:     7,231 ( 0.2%)
                opt_mult:     6,752 ( 0.2%)
                  opt_or:     3,753 ( 0.1%)
                  opt_lt:       348 ( 0.0%)
                  opt_ge:        91 ( 0.0%)
                  opt_gt:        36 ( 0.0%)
Top-9 send fallback reasons (100.0% of total 25,534,542):
                send_without_block_polymorphic: 9,723,469 (38.1%)
                              send_no_profiles: 5,896,023 (23.1%)
  send_without_block_not_optimized_method_type: 4,524,016 (17.7%)
                     not_optimized_instruction: 4,294,241 (16.8%)
                send_without_block_no_profiles:   998,947 ( 3.9%)
                send_not_optimized_method_type:    72,318 ( 0.3%)
       send_without_block_cfunc_array_variadic:    15,134 ( 0.1%)
                      obj_to_string_not_string:     9,765 ( 0.0%)
       send_without_block_direct_too_many_args:       629 ( 0.0%)
Top-8 unhandled YARV insns (100.0% of total 362,460):
        checkkeyword: 190,694 (52.6%)
    getclassvariable:  59,901 (16.5%)
  invokesuperforward:  49,503 (13.7%)
       getblockparam:  49,119 (13.6%)
   opt_duparray_send:  11,978 ( 3.3%)
         getconstant:     952 ( 0.3%)
          checkmatch:     290 ( 0.1%)
                once:      23 ( 0.0%)
Top-3 compile error reasons (100.0% of total 3,798,744):
  register_spill_on_alloc: 3,495,669 (92.0%)
  register_spill_on_ccall:   184,712 ( 4.9%)
        exception_handler:   118,363 ( 3.1%)
Top-15 side exit reasons (100.0% of total 10,637,319):
                        compile_error: 3,798,744 (35.7%)
                   guard_type_failure: 2,655,504 (25.0%)
                  guard_shape_failure: 1,917,217 (18.0%)
  block_param_proxy_not_iseq_or_ifunc:   535,789 ( 5.0%)
                      unhandled_kwarg:   455,492 ( 4.3%)
                           patchpoint:   370,478 ( 3.5%)
                  unhandled_yarv_insn:   362,460 ( 3.4%)
                unknown_newarray_send:   314,786 ( 3.0%)
                      unhandled_splat:   122,071 ( 1.1%)
                   unhandled_hir_insn:    83,066 ( 0.8%)
           block_param_proxy_modified:    19,193 ( 0.2%)
             guard_int_equals_failure:     1,914 ( 0.0%)
               obj_to_string_fallback:       566 ( 0.0%)
               guard_type_not_failure:        22 ( 0.0%)
                            interrupt:        17 ( 0.0%)
                             send_count: 62,495,067
                     dynamic_send_count: 25,534,542 (40.9%)
                   optimized_send_count: 36,960,525 (59.1%)
              iseq_optimized_send_count: 18,582,072 (29.7%)
      inline_cfunc_optimized_send_count:  7,086,638 (11.3%)
non_variadic_cfunc_optimized_send_count:  8,392,657 (13.4%)
    variadic_cfunc_optimized_send_count:  2,899,158 ( 4.6%)
dynamic_getivar_count:                        7,365,994
dynamic_setivar_count:                        7,248,500
compiled_iseq_count:                              4,780
failed_iseq_count:                                  463
compile_time:                                     816ms
profile_time:                                       9ms
gc_time:                                           11ms
invalidation_time:                                 70ms
vm_write_pc_count:                           64,363,541
vm_write_sp_count:                           63,022,221
vm_write_locals_count:                       63,022,221
vm_write_stack_count:                        63,022,221
vm_write_to_parent_iseq_local_count:            292,458
vm_read_from_parent_iseq_local_count:         6,850,977
code_region_bytes:                           23,019,520
side_exit_count:                             10,637,319
total_insn_count:                           517,303,190
vm_insn_count:                              160,562,103
zjit_insn_count:                            356,741,087
ratio_in_zjit:                                    69.0%
```

</details>

railsbench before:

<details>

```
***ZJIT: Printing ZJIT statistics on exit***
Top-20 not inlined C methods (66.1% of total 25,524,934):
                                   Hash#[]=: 1,700,237 ( 6.7%)
                             String#getbyte: 1,572,123 ( 6.2%)
                                  String#<<: 1,494,022 ( 5.9%)
                               Kernel#is_a?: 1,429,930 ( 5.6%)
                              String#empty?: 1,370,323 ( 5.4%)
                              Regexp#match?: 1,235,067 ( 4.8%)
                         Kernel#respond_to?: 1,198,251 ( 4.7%)
                                  Hash#key?: 1,087,406 ( 4.3%)
                             String#setbyte:   810,022 ( 3.2%)
                                  Integer#^:   766,624 ( 3.0%)
                        Kernel#block_given?:   603,613 ( 2.4%)
                                  String#==:   590,409 ( 2.3%)
                                  Class#new:   506,216 ( 2.0%)
                                Hash#delete:   455,288 ( 1.8%)
                             BasicObject#!=:   428,771 ( 1.7%)
                                 Hash#fetch:   408,621 ( 1.6%)
                         String#ascii_only?:   373,915 ( 1.5%)
                 ObjectSpace::WeakKeyMap#[]:   287,957 ( 1.1%)
                               NilClass#===:   277,244 ( 1.1%)
                               Kernel#Array:   269,590 ( 1.1%)
Top-20 not annotated C methods (66.8% of total 25,392,654):
                                   Hash#[]=: 1,700,416 ( 6.7%)
                             String#getbyte: 1,572,123 ( 6.2%)
                               Kernel#is_a?: 1,515,672 ( 6.0%)
                                  String#<<: 1,494,022 ( 5.9%)
                              String#empty?: 1,370,478 ( 5.4%)
                              Regexp#match?: 1,235,067 ( 4.9%)
                         Kernel#respond_to?: 1,198,251 ( 4.7%)
                                  Hash#key?: 1,087,406 ( 4.3%)
                             String#setbyte:   810,022 ( 3.2%)
                                  Integer#^:   766,624 ( 3.0%)
                        Kernel#block_given?:   603,613 ( 2.4%)
                                  String#==:   601,115 ( 2.4%)
                                  Class#new:   506,216 ( 2.0%)
                                Hash#delete:   455,288 ( 1.8%)
                             BasicObject#!=:   428,876 ( 1.7%)
                                 Hash#fetch:   408,621 ( 1.6%)
                         String#ascii_only?:   373,915 ( 1.5%)
                 ObjectSpace::WeakKeyMap#[]:   287,957 ( 1.1%)
                               NilClass#===:   277,244 ( 1.1%)
                               Kernel#Array:   269,590 ( 1.1%)
Top-2 not optimized method types for send (100.0% of total 186,159):
   iseq: 112,747 (60.6%)
  cfunc:  73,412 (39.4%)
Top-6 not optimized method types for send_without_block (100.0% of total 8,142,248):
       iseq: 3,464,671 (42.6%)
  optimized: 2,632,884 (32.3%)
    bmethod: 1,290,701 (15.9%)
      alias:   706,020 ( 8.7%)
       null:    47,942 ( 0.6%)
      cfunc:        30 ( 0.0%)
Top-11 not optimized instructions (100.0% of total 8,394,873):
             invokesuper: 5,602,274 (66.7%)
             invokeblock: 1,764,936 (21.0%)
             sendforward:   551,832 ( 6.6%)
                  opt_eq:   441,959 ( 5.3%)
                opt_plus:    31,635 ( 0.4%)
  opt_send_without_block:     1,163 ( 0.0%)
                  opt_lt:       372 ( 0.0%)
                opt_mult:       251 ( 0.0%)
                  opt_ge:       193 ( 0.0%)
                 opt_neq:       149 ( 0.0%)
                  opt_or:       109 ( 0.0%)
Top-8 send fallback reasons (100.0% of total 40,748,753):
                send_without_block_polymorphic: 12,933,923 (31.7%)
                              send_no_profiles:  9,033,636 (22.2%)
                     not_optimized_instruction:  8,394,873 (20.6%)
  send_without_block_not_optimized_method_type:  8,142,248 (20.0%)
                send_without_block_no_profiles:  1,839,228 ( 4.5%)
       send_without_block_cfunc_array_variadic:    215,046 ( 0.5%)
                send_not_optimized_method_type:    186,159 ( 0.5%)
                      obj_to_string_not_string:      3,640 ( 0.0%)
Top-9 unhandled YARV insns (100.0% of total 1,604,456):
    getclassvariable: 458,136 (28.6%)
       getblockparam: 455,921 (28.4%)
        checkkeyword: 265,425 (16.5%)
  invokesuperforward: 239,383 (14.9%)
         expandarray: 137,305 ( 8.6%)
         getconstant:  48,100 ( 3.0%)
          checkmatch:     149 ( 0.0%)
                once:      23 ( 0.0%)
   opt_duparray_send:      14 ( 0.0%)
Top-3 compile error reasons (100.0% of total 5,570,130):
  register_spill_on_alloc: 4,994,130 (89.7%)
        exception_handler:   356,784 ( 6.4%)
  register_spill_on_ccall:   219,216 ( 3.9%)
Top-13 side exit reasons (100.0% of total 12,412,181):
                        compile_error: 5,570,130 (44.9%)
                  unhandled_yarv_insn: 1,604,456 (12.9%)
                  guard_shape_failure: 1,462,872 (11.8%)
                   guard_type_failure:   845,891 ( 6.8%)
  block_param_proxy_not_iseq_or_ifunc:   765,968 ( 6.2%)
                      unhandled_kwarg:   658,341 ( 5.3%)
                           patchpoint:   504,437 ( 4.1%)
                      unhandled_splat:   446,990 ( 3.6%)
                unknown_newarray_send:   332,740 ( 2.7%)
                   unhandled_hir_insn:   160,205 ( 1.3%)
           block_param_proxy_modified:    59,589 ( 0.5%)
               obj_to_string_fallback:       553 ( 0.0%)
                            interrupt:         9 ( 0.0%)
                             send_count: 119,067,587
                     dynamic_send_count:  40,748,753 (34.2%)
                   optimized_send_count:  78,318,834 (65.8%)
              iseq_optimized_send_count:  39,936,542 (33.5%)
      inline_cfunc_optimized_send_count:  12,857,358 (10.8%)
non_variadic_cfunc_optimized_send_count:  19,722,584 (16.6%)
    variadic_cfunc_optimized_send_count:   5,802,350 ( 4.9%)
dynamic_getivar_count:                      10,980,323
dynamic_setivar_count:                      12,962,726
compiled_iseq_count:                             2,531
failed_iseq_count:                                 245
compile_time:                                    414ms
profile_time:                                     21ms
gc_time:                                          33ms
invalidation_time:                                 5ms
vm_write_pc_count:                         129,093,714
vm_write_sp_count:                         126,023,084
vm_write_locals_count:                     126,023,084
vm_write_stack_count:                      126,023,084
vm_write_to_parent_iseq_local_count:           385,461
vm_read_from_parent_iseq_local_count:       11,266,484
code_region_bytes:                          12,156,928
side_exit_count:                            12,412,181
total_insn_count:                          866,780,158
vm_insn_count:                             216,821,134
zjit_insn_count:                           649,959,024
ratio_in_zjit:                                   75.0%
```

</details>

railsbench after:

<details>

```
***ZJIT: Printing ZJIT statistics on exit***
Top-20 not inlined C methods (66.0% of total 25,597,895):
                                   Hash#[]=: 1,724,042 ( 6.7%)
                             String#getbyte: 1,572,123 ( 6.1%)
                                  String#<<: 1,494,022 ( 5.8%)
                               Kernel#is_a?: 1,429,946 ( 5.6%)
                              String#empty?: 1,370,323 ( 5.4%)
                              Regexp#match?: 1,235,067 ( 4.8%)
                         Kernel#respond_to?: 1,198,251 ( 4.7%)
                                  Hash#key?: 1,087,406 ( 4.2%)
                             String#setbyte:   810,022 ( 3.2%)
                                  Integer#^:   766,624 ( 3.0%)
                        Kernel#block_given?:   603,613 ( 2.4%)
                                  String#==:   590,699 ( 2.3%)
                                  Class#new:   506,216 ( 2.0%)
                                Hash#delete:   455,288 ( 1.8%)
                             BasicObject#!=:   428,771 ( 1.7%)
                                 Hash#fetch:   408,621 ( 1.6%)
                         String#ascii_only?:   373,915 ( 1.5%)
                 ObjectSpace::WeakKeyMap#[]:   287,957 ( 1.1%)
                               NilClass#===:   277,244 ( 1.1%)
                               Kernel#Array:   269,590 ( 1.1%)
Top-20 not annotated C methods (66.7% of total 25,465,615):
                                   Hash#[]=: 1,724,221 ( 6.8%)
                             String#getbyte: 1,572,123 ( 6.2%)
                               Kernel#is_a?: 1,515,688 ( 6.0%)
                                  String#<<: 1,494,022 ( 5.9%)
                              String#empty?: 1,370,478 ( 5.4%)
                              Regexp#match?: 1,235,067 ( 4.8%)
                         Kernel#respond_to?: 1,198,251 ( 4.7%)
                                  Hash#key?: 1,087,406 ( 4.3%)
                             String#setbyte:   810,022 ( 3.2%)
                                  Integer#^:   766,624 ( 3.0%)
                        Kernel#block_given?:   603,613 ( 2.4%)
                                  String#==:   601,405 ( 2.4%)
                                  Class#new:   506,216 ( 2.0%)
                                Hash#delete:   455,288 ( 1.8%)
                             BasicObject#!=:   428,876 ( 1.7%)
                                 Hash#fetch:   408,621 ( 1.6%)
                         String#ascii_only?:   373,915 ( 1.5%)
                 ObjectSpace::WeakKeyMap#[]:   287,957 ( 1.1%)
                               NilClass#===:   277,244 ( 1.1%)
                               Kernel#Array:   269,590 ( 1.1%)
Top-2 not optimized method types for send (100.0% of total 186,159):
   iseq: 112,747 (60.6%)
  cfunc:  73,412 (39.4%)
Top-6 not optimized method types for send_without_block (100.0% of total 8,142,248):
       iseq: 3,464,671 (42.6%)
  optimized: 2,632,884 (32.3%)
    bmethod: 1,290,701 (15.9%)
      alias:   706,020 ( 8.7%)
       null:    47,942 ( 0.6%)
      cfunc:        30 ( 0.0%)
Top-11 not optimized instructions (100.0% of total 8,442,456):
             invokesuper: 5,649,857 (66.9%)
             invokeblock: 1,764,936 (20.9%)
             sendforward:   551,832 ( 6.5%)
                  opt_eq:   441,959 ( 5.2%)
                opt_plus:    31,635 ( 0.4%)
  opt_send_without_block:     1,163 ( 0.0%)
                  opt_lt:       372 ( 0.0%)
                opt_mult:       251 ( 0.0%)
                  opt_ge:       193 ( 0.0%)
                 opt_neq:       149 ( 0.0%)
                  opt_or:       109 ( 0.0%)
Top-8 send fallback reasons (100.0% of total 40,796,314):
                send_without_block_polymorphic: 12,933,921 (31.7%)
                              send_no_profiles:  9,033,616 (22.1%)
                     not_optimized_instruction:  8,442,456 (20.7%)
  send_without_block_not_optimized_method_type:  8,142,248 (20.0%)
                send_without_block_no_profiles:  1,839,228 ( 4.5%)
       send_without_block_cfunc_array_variadic:    215,046 ( 0.5%)
                send_not_optimized_method_type:    186,159 ( 0.5%)
                      obj_to_string_not_string:      3,640 ( 0.0%)
Top-8 unhandled YARV insns (100.0% of total 1,467,151):
    getclassvariable: 458,136 (31.2%)
       getblockparam: 455,921 (31.1%)
        checkkeyword: 265,425 (18.1%)
  invokesuperforward: 239,383 (16.3%)
         getconstant:  48,100 ( 3.3%)
          checkmatch:     149 ( 0.0%)
                once:      23 ( 0.0%)
   opt_duparray_send:      14 ( 0.0%)
Top-3 compile error reasons (100.0% of total 5,825,923):
  register_spill_on_alloc: 5,225,940 (89.7%)
        exception_handler:   356,784 ( 6.1%)
  register_spill_on_ccall:   243,199 ( 4.2%)
Top-13 side exit reasons (100.0% of total 12,530,763):
                        compile_error: 5,825,923 (46.5%)
                  unhandled_yarv_insn: 1,467,151 (11.7%)
                  guard_shape_failure: 1,462,876 (11.7%)
                   guard_type_failure:   845,913 ( 6.8%)
  block_param_proxy_not_iseq_or_ifunc:   765,968 ( 6.1%)
                      unhandled_kwarg:   658,341 ( 5.3%)
                           patchpoint:   504,437 ( 4.0%)
                      unhandled_splat:   446,990 ( 3.6%)
                unknown_newarray_send:   332,740 ( 2.7%)
                   unhandled_hir_insn:   160,273 ( 1.3%)
           block_param_proxy_modified:    59,589 ( 0.5%)
               obj_to_string_fallback:       553 ( 0.0%)
                            interrupt:         9 ( 0.0%)
                             send_count: 119,163,569
                     dynamic_send_count:  40,796,314 (34.2%)
                   optimized_send_count:  78,367,255 (65.8%)
              iseq_optimized_send_count:  39,911,967 (33.5%)
      inline_cfunc_optimized_send_count:  12,857,393 (10.8%)
non_variadic_cfunc_optimized_send_count:  19,770,401 (16.6%)
    variadic_cfunc_optimized_send_count:   5,827,494 ( 4.9%)
dynamic_getivar_count:                      10,980,323
dynamic_setivar_count:                      12,986,381
compiled_iseq_count:                             2,523
failed_iseq_count:                                 252
compile_time:                                    420ms
profile_time:                                     21ms
gc_time:                                          30ms
invalidation_time:                                 4ms
vm_write_pc_count:                         128,973,665
vm_write_sp_count:                         125,926,968
vm_write_locals_count:                     125,926,968
vm_write_stack_count:                      125,926,968
vm_write_to_parent_iseq_local_count:           385,752
vm_read_from_parent_iseq_local_count:       11,267,766
code_region_bytes:                          12,189,696
side_exit_count:                            12,530,763
total_insn_count:                          866,667,490
vm_insn_count:                             217,813,201
zjit_insn_count:                           648,854,289
ratio_in_zjit:                                   74.9%
```

</details>
2025-10-20 10:55:52 -04:00
Takashi Kokubun d3cb347a40 ZJIT: Share more code with YJIT in jit.c (#14520)
* ZJIT: Share more code with YJIT in jit.c

* Fix ZJIT references to JIT
2025-09-12 20:34:55 +00:00
Stan Lo 77a421fb05 ZJIT: Clear jit entry from iseqs after TracePoint activation (#14407)
ZJIT: Remove JITed code after TracePoint is enabled
2025-09-02 19:20:08 +00:00
Stan Lo 3f3a54efff Add rb_jit_vm_unlock and share it in ZJIT and YJIT 2025-08-29 12:55:14 -07:00
Stan Lo 561050496c Add rb_jit_vm_lock_then_barrier and share it in ZJIT and YJIT 2025-08-29 12:55:14 -07:00
Stan Lo 2f6a9c5167 Add rb_jit_multi_ractor_p and share it in ZJIT and YJIT 2025-08-29 12:55:14 -07:00
Max Bernstein b6f4b5399d ZJIT: Specialize monomorphic GetIvar (#14388)
Specialize monomorphic `GetIvar` into:

* `GuardType(HeapObject)`
* `GuardShape`
* `LoadIvarEmbedded` or `LoadIvarExtended`

This requires profiling self for `getinstancevariable` (it's not on the operand
stack).

This also optimizes `GetIvar`s that happen as a result of inlining
`attr_reader` and `attr_accessor`.

Also move some (newly) shared JIT helpers into jit.c.
2025-08-29 12:46:08 -04:00
Takashi Kokubun 12306c0c6f ZJIT: Stub JIT-to-JIT calls (#14052) 2025-07-31 12:57:59 -07:00
Takashi Kokubun f5085c70f2 ZJIT: Mark profiled objects when marking ISEQ (#13784) 2025-07-09 16:03:23 -07:00
Alan Wu 0828dff3f8 ZJIT: Codegen for defined?(yield)
Lots of stdlib methods such as Integer#times and Kernel#then use this,
so at least this will make writing tests slightly easier.
2025-06-28 00:03:42 +09:00
Max Bernstein 3a9bf4a2ae ZJIT: Optimize frozen array aref (#13666)
If we have a frozen array `[..., a, ...]` and a compile-time fixnum index `i`,
we can do the array load at compile-time.
2025-06-23 17:41:49 -05:00
Alan Wu 33909a1c69 YJIT: ZJIT: Share identical glue functions
Working towards having YJIT and ZJIT in the same build, we need to
deduplicate some glue code that would otherwise cause name collision.
Add jit.c for this and build it for YJIT and ZJIT builds. Update bindgen
to look at jit.c; some shuffling of functions in the output, but the set
of functions shouldn't have changed.
2025-05-02 23:47:57 +09:00