diff options
| author | Nozomi Hijikata <121233810+nozomemein@users.noreply.github.com> | 2026-06-03 22:42:20 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-06-03 09:42:20 -0400 |
| commit | f717edca05fa42e122b7fb8148aa6a728b3aa582 (patch) | |
| tree | 2a8910e56b7ea8b362eb64a8c6c597408d91ddcd /lib/test/unit/ui/testrunnerutilities.rb | |
| parent | 464e5665a4b02760196867406f1291261ea08fbe (diff) | |
* ZJIT: Implement Polymorphic Definedivar
Closes: https://github.com/Shopify/ruby/issues/980
Build polymorphic shape/type branches for definedivar in HIR. For each profiled T_OBJECT shape, specialize defined?(`@ivar`) to a constant pushval or nil based on the compile-time ivar index check.
DefinedIvar already profiles self on monomorphic shape guard failures for recompilation, so the recompiled HIR can use the collected polymorphic shapes while keeping a generic DefinedIvar fallback for misses and unsupported shapes.
## Benchmark
### lobsters
Summary:
```diff
- dynamic_definedivar_count: 1,294,854 ( 0.7%)
+ dynamic_definedivar_count: 503,058 ( 0.3%)
ratio_in_zjit: 88.4%
```
```
zjit-master: ruby 4.1.0dev (2026-05-23T00:08:49Z master 5855d61ee4) +ZJIT stats +PRISM [arm64-darwin25]
zjit-polymorphic-definedivar: ruby 4.1.0dev (2026-05-23T07:11:22Z zjit-polymorphic-d.. f75a82e7f1) +ZJIT stats +PRISM [arm64-darwin25]
last_commit=ZJIT: Implement Polymorphic Definedivar
-------- ---------------- --------------------------------- ------------------------------------ ----------------------------------------
bench zjit-master (ms) zjit-polymorphic-definedivar (ms) zjit-polymorphic-definedivar 1st itr zjit-master/zjit-polymorphic-definedivar
lobsters 529.9 ± 3.6% 504.2 ± 7.7% 1.148 1.051
-------- ---------------- --------------------------------- ------------------------------------ ----------------------------------------
```
Full stats details below:
<details>
<summary>before patch</summary>
```
Top-2 not optimized method types for send (100.0% of total 65,120):
null: 44,877 (68.9%)
optimized: 20,243 (31.1%)
Top-3 not optimized method types for send_without_block (100.0% of total 716,678):
optimized_send: 711,905 (99.3%)
optimized_block_call: 4,299 ( 0.6%)
zsuper: 474 ( 0.1%)
Top-1 not optimized method types for super (100.0% of total 3,678):
attrset: 3,678 (100.0%)
Top-1 instructions with uncategorized fallback reason (100.0% of total 65,868):
opt_send_without_block: 65,868 (100.0%)
Top-20 send fallback reasons (99.5% of total 22,386,632):
invokeblock_not_specialized: 5,946,612 (26.6%)
one_or_more_complex_arg_pass: 4,376,419 (19.5%)
send_without_block_polymorphic: 3,748,855 (16.7%)
send_without_block_no_profiles: 2,830,116 (12.6%)
send_without_block_megamorphic: 1,108,467 ( 5.0%)
sendforward_not_specialized: 971,957 ( 4.3%)
send_polymorphic: 806,862 ( 3.6%)
send_without_block_not_optimized_method_type_optimized: 716,204 ( 3.2%)
super_polymorphic: 337,181 ( 1.5%)
too_many_args_for_lir: 333,633 ( 1.5%)
send_not_optimized_need_permission: 238,842 ( 1.1%)
send_without_block_not_optimized_need_permission: 180,946 ( 0.8%)
send_no_profiles: 177,008 ( 0.8%)
argc_param_mismatch: 124,061 ( 0.6%)
super_complex_args_pass: 89,280 ( 0.4%)
invokesuperforward_not_specialized: 80,729 ( 0.4%)
uncategorized: 65,868 ( 0.3%)
send_not_optimized_method_type: 65,120 ( 0.3%)
super_from_block: 43,185 ( 0.2%)
obj_to_string_not_string: 42,731 ( 0.2%)
Top-4 setivar fallback reasons (100.0% of total 4,182,333):
not_monomorphic: 3,969,254 (94.9%)
not_t_object: 119,505 ( 2.9%)
complex: 93,131 ( 2.2%)
new_shape_needs_extension: 443 ( 0.0%)
Top-2 getivar fallback reasons (100.0% of total 11,716,846):
not_monomorphic: 11,537,525 (98.5%)
complex: 179,321 ( 1.5%)
Top-3 definedivar fallback reasons (100.0% of total 1,294,854):
not_monomorphic: 1,289,423 (99.6%)
complex: 5,122 ( 0.4%)
not_t_object: 309 ( 0.0%)
Top-5 invokeblock handler (100.0% of total 6,968,323):
monomorphic_ifunc: 4,143,418 (59.5%)
monomorphic_other: 1,444,525 (20.7%)
monomorphic_iseq: 865,749 (12.4%)
polymorphic: 508,677 ( 7.3%)
megamorphic: 5,954 ( 0.1%)
Top-6 getblockparamproxy handler (100.0% of total 3,321,873):
polymorphic: 2,370,458 (71.4%)
nil: 492,185 (14.8%)
iseq: 242,627 ( 7.3%)
no_profiles: 168,826 ( 5.1%)
proc: 40,245 ( 1.2%)
megamorphic: 7,532 ( 0.2%)
Top-7 popular complex argument-parameter features not optimized (100.0% of total 4,677,994):
caller_blockarg: 3,092,361 (66.1%)
param_forwardable: 697,044 (14.9%)
param_rest: 409,311 ( 8.7%)
caller_kwarg: 193,462 ( 4.1%)
param_kwrest: 143,181 ( 3.1%)
caller_kw_splat: 85,992 ( 1.8%)
caller_splat: 56,643 ( 1.2%)
Top-3 compile error reasons (100.0% of total 196,397):
exception_handler: 192,000 (97.8%)
native_stack_too_large: 4,342 ( 2.2%)
validation_mismatched_block_arity: 55 ( 0.0%)
Top-2 unhandled HIR insns (100.0% of total 229,881):
throw: 194,104 (84.4%)
invokebuiltin: 35,777 (15.6%)
Top-19 side exit reasons (100.0% of total 8,637,525):
guard_type_failure: 7,692,359 (89.1%)
unhandled_hir_insn: 229,881 ( 2.7%)
compile_error: 196,397 ( 2.3%)
patchpoint_method_redefined: 118,680 ( 1.4%)
block_param_proxy_fallback_miss: 112,551 ( 1.3%)
no_profile_send: 93,334 ( 1.1%)
block_param_proxy_not_nil: 75,195 ( 0.9%)
patchpoint_stable_constant_names: 55,819 ( 0.6%)
patchpoint_no_singleton_class: 19,352 ( 0.2%)
unhandled_block_arg: 14,541 ( 0.2%)
block_param_proxy_not_iseq_or_ifunc: 13,401 ( 0.2%)
fixnum_lshift_overflow: 10,165 ( 0.1%)
guard_less_failure: 3,120 ( 0.0%)
guard_shape_failure: 1,302 ( 0.0%)
guard_greater_eq_failure: 941 ( 0.0%)
guard_super_method_entry: 407 ( 0.0%)
interrupt: 49 ( 0.0%)
obj_to_string_fallback: 30 ( 0.0%)
guard_not_shared_failure: 1 ( 0.0%)
send_count: 182,469,185
dynamic_send_count: 22,386,632 (12.3%)
optimized_send_count: 160,082,553 (87.7%)
dynamic_setivar_count: 4,182,333 ( 2.3%)
dynamic_getivar_count: 11,716,846 ( 6.4%)
dynamic_definedivar_count: 1,294,854 ( 0.7%)
iseq_optimized_send_count: 54,154,353 (29.7%)
inline_cfunc_optimized_send_count: 74,812,159 (41.0%)
inline_iseq_optimized_send_count: 6,346,705 ( 3.5%)
non_variadic_cfunc_optimized_send_count: 13,789,249 ( 7.6%)
variadic_cfunc_optimized_send_count: 10,980,087 ( 6.0%)
compiled_iseq_count: 6,166
compiled_side_exit_count: 80,485
failed_iseq_count: 3
compile_time: 2,462ms
compile_side_exit_time: 113ms
compile_side_exit_time_ratio: 4.6%
compile_hir_time: 798ms
compile_hir_build_time: 238ms
compile_hir_strength_reduce_time: 322ms
compile_hir_canonicalize_time: 49ms
compile_hir_fold_constants_time: 37ms
compile_hir_clean_cfg_time: 26ms
compile_hir_eliminate_dead_code_time: 30ms
compile_lir_time: 1,525ms
profile_time: 39ms
gc_time: 33ms
invalidation_time: 14ms
vm_write_jit_frame_count: 137,433,269
vm_write_sp_count: 137,433,269
vm_write_locals_count: 131,272,119
vm_write_stack_count: 131,272,119
vm_write_to_parent_iseq_local_count: 688,492
guard_type_count: 145,711,992
guard_type_exit_ratio: 5.3%
guard_shape_count: 36,890,099
guard_shape_exit_ratio: 0.0%
load_field_count: 210,155,590
store_field_count: 15,758,742
side_exit_size: 13,563,708
code_region_bytes: 33,505,280
side_exit_size_ratio: 40.5%
zjit_alloc_bytes: 22,783,024
total_mem_bytes: 56,288,304
side_exit_count: 8,637,525
total_insn_count: 995,180,861
vm_insn_count: 115,515,525
zjit_insn_count: 879,665,336
ratio_in_zjit: 88.4%
```
</details>
<details>
<summary>after patch</summary>
```
Top-2 not optimized method types for send (100.0% of total 65,119):
null: 44,877 (68.9%)
optimized: 20,242 (31.1%)
Top-3 not optimized method types for send_without_block (100.0% of total 716,636):
optimized_send: 711,869 (99.3%)
optimized_block_call: 4,293 ( 0.6%)
zsuper: 474 ( 0.1%)
Top-1 not optimized method types for super (100.0% of total 3,676):
attrset: 3,676 (100.0%)
Top-1 instructions with uncategorized fallback reason (100.0% of total 65,866):
opt_send_without_block: 65,866 (100.0%)
Top-20 send fallback reasons (99.5% of total 22,409,237):
invokeblock_not_specialized: 5,946,405 (26.5%)
one_or_more_complex_arg_pass: 4,376,457 (19.5%)
send_without_block_polymorphic: 3,775,975 (16.9%)
send_without_block_no_profiles: 2,830,029 (12.6%)
send_without_block_megamorphic: 1,104,527 ( 4.9%)
sendforward_not_specialized: 971,924 ( 4.3%)
send_polymorphic: 806,852 ( 3.6%)
send_without_block_not_optimized_method_type_optimized: 716,162 ( 3.2%)
super_polymorphic: 337,178 ( 1.5%)
too_many_args_for_lir: 333,625 ( 1.5%)
send_not_optimized_need_permission: 238,842 ( 1.1%)
send_without_block_not_optimized_need_permission: 180,949 ( 0.8%)
send_no_profiles: 176,799 ( 0.8%)
argc_param_mismatch: 124,064 ( 0.6%)
super_complex_args_pass: 89,280 ( 0.4%)
invokesuperforward_not_specialized: 80,723 ( 0.4%)
uncategorized: 65,866 ( 0.3%)
send_not_optimized_method_type: 65,119 ( 0.3%)
super_from_block: 43,182 ( 0.2%)
obj_to_string_not_string: 42,725 ( 0.2%)
Top-4 setivar fallback reasons (100.0% of total 4,182,216):
not_monomorphic: 3,969,159 (94.9%)
not_t_object: 119,484 ( 2.9%)
complex: 93,131 ( 2.2%)
new_shape_needs_extension: 442 ( 0.0%)
Top-2 getivar fallback reasons (100.0% of total 11,716,471):
not_monomorphic: 11,537,150 (98.5%)
complex: 179,321 ( 1.5%)
Top-3 definedivar fallback reasons (100.0% of total 503,058):
not_monomorphic: 498,173 (99.0%)
complex: 4,576 ( 0.9%)
not_t_object: 309 ( 0.1%)
Top-5 invokeblock handler (100.0% of total 6,968,099):
monomorphic_ifunc: 4,143,324 (59.5%)
monomorphic_other: 1,444,457 (20.7%)
monomorphic_iseq: 865,705 (12.4%)
polymorphic: 508,659 ( 7.3%)
megamorphic: 5,954 ( 0.1%)
Top-6 getblockparamproxy handler (100.0% of total 3,321,803):
polymorphic: 2,370,425 (71.4%)
nil: 492,172 (14.8%)
iseq: 242,810 ( 7.3%)
no_profiles: 168,625 ( 5.1%)
proc: 40,239 ( 1.2%)
megamorphic: 7,532 ( 0.2%)
Top-7 popular complex argument-parameter features not optimized (100.0% of total 4,678,011):
caller_blockarg: 3,092,480 (66.1%)
param_forwardable: 697,011 (14.9%)
param_rest: 409,285 ( 8.7%)
caller_kwarg: 193,450 ( 4.1%)
param_kwrest: 143,179 ( 3.1%)
caller_kw_splat: 85,971 ( 1.8%)
caller_splat: 56,635 ( 1.2%)
Top-3 compile error reasons (100.0% of total 196,386):
exception_handler: 191,989 (97.8%)
native_stack_too_large: 4,342 ( 2.2%)
validation_mismatched_block_arity: 55 ( 0.0%)
Top-2 unhandled HIR insns (100.0% of total 229,876):
throw: 194,101 (84.4%)
invokebuiltin: 35,775 (15.6%)
Top-19 side exit reasons (100.0% of total 8,638,646):
guard_type_failure: 7,693,566 (89.1%)
unhandled_hir_insn: 229,876 ( 2.7%)
compile_error: 196,386 ( 2.3%)
patchpoint_method_redefined: 118,676 ( 1.4%)
block_param_proxy_fallback_miss: 112,548 ( 1.3%)
no_profile_send: 93,330 ( 1.1%)
block_param_proxy_not_nil: 75,195 ( 0.9%)
patchpoint_stable_constant_names: 55,792 ( 0.6%)
patchpoint_no_singleton_class: 19,326 ( 0.2%)
unhandled_block_arg: 14,540 ( 0.2%)
block_param_proxy_not_iseq_or_ifunc: 13,401 ( 0.2%)
fixnum_lshift_overflow: 10,165 ( 0.1%)
guard_less_failure: 3,119 ( 0.0%)
guard_shape_failure: 1,302 ( 0.0%)
guard_greater_eq_failure: 941 ( 0.0%)
guard_super_method_entry: 407 ( 0.0%)
interrupt: 45 ( 0.0%)
obj_to_string_fallback: 30 ( 0.0%)
guard_not_shared_failure: 1 ( 0.0%)
send_count: 182,477,537
dynamic_send_count: 22,409,237 (12.3%)
optimized_send_count: 160,068,300 (87.7%)
dynamic_setivar_count: 4,182,216 ( 2.3%)
dynamic_getivar_count: 11,716,471 ( 6.4%)
dynamic_definedivar_count: 503,058 ( 0.3%)
iseq_optimized_send_count: 54,138,292 (29.7%)
inline_cfunc_optimized_send_count: 74,815,196 (41.0%)
inline_iseq_optimized_send_count: 6,346,484 ( 3.5%)
non_variadic_cfunc_optimized_send_count: 13,788,597 ( 7.6%)
variadic_cfunc_optimized_send_count: 10,979,731 ( 6.0%)
compiled_iseq_count: 6,167
compiled_side_exit_count: 80,471
failed_iseq_count: 3
compile_time: 2,711ms
compile_side_exit_time: 125ms
compile_side_exit_time_ratio: 4.6%
compile_hir_time: 870ms
compile_hir_build_time: 266ms
compile_hir_strength_reduce_time: 347ms
compile_hir_canonicalize_time: 52ms
compile_hir_fold_constants_time: 40ms
compile_hir_clean_cfg_time: 27ms
compile_hir_eliminate_dead_code_time: 32ms
compile_lir_time: 1,680ms
profile_time: 48ms
gc_time: 32ms
invalidation_time: 15ms
vm_write_jit_frame_count: 137,425,789
vm_write_sp_count: 137,425,789
vm_write_locals_count: 131,264,963
vm_write_stack_count: 131,264,963
vm_write_to_parent_iseq_local_count: 688,457
guard_type_count: 146,412,455
guard_type_exit_ratio: 5.3%
guard_shape_count: 36,937,934
guard_shape_exit_ratio: 0.0%
load_field_count: 211,394,883
store_field_count: 15,778,119
side_exit_size: 13,563,624
code_region_bytes: 33,505,280
side_exit_size_ratio: 40.5%
zjit_alloc_bytes: 22,870,223
total_mem_bytes: 56,375,503
side_exit_count: 8,638,646
total_insn_count: 995,144,390
vm_insn_count: 115,472,694
zjit_insn_count: 879,671,696
ratio_in_zjit: 88.4%
```
</details>
* ZJIT: Add TODO for deduplicating DefinedIvar specialization
* ZJIT: Add more DefinedIvar HIR tests
Cover unsupported receiver profiles and a mixed polymorphic profile with a generic DefinedIvar fallback.
* ZJIT: Add more DefinedIvar polymorphic HIR test
Cover polymorphic definedivar profiles with:
- complex path
- non-T_OBJECT path
Diffstat (limited to 'lib/test/unit/ui/testrunnerutilities.rb')
0 files changed, 0 insertions, 0 deletions
