[pull] master from ruby:master#1076
Merged
Merged
Conversation
* ZJIT: Implement Polymorphic Definedivar Closes: Shopify#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 5855d61) +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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )