summaryrefslogtreecommitdiff
path: root/yjit/bindgen/src
AgeCommit message (Collapse)Author
2025-12-18YJIT: Support calling bmethods in RactorsJohn Hawthorn
Co-authored-by: Luke Gruber <luke.gru@gmail.com>
2025-12-09ZJIT: Add codegen for FixnumDiv (#15452)Abrar Habib
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-05YJIT: Fix including stats for ZJIT instructions when ZJIT not in buildAlan Wu
2025-12-01ZJIT: Specialize String#<< with FixnumMax Bernstein
Append a codepoint.
2025-11-18Extract `KW_SPECIFIED_BITS_MAX` for JITs (GH-15039)Jacob
Rename to `VM_KW_SPECIFIED_BITS_MAX` now that it's in `vm_core.h`.
2025-10-22ZJIT: Fetch Primitive.attr!(leaf) for InvokeBuiltinMax Bernstein
Fix https://github.com/Shopify/ruby/issues/670
2025-10-21YJIT: ZJIT: Extract common bindings to jit.c and remove unnamed enums.Alan Wu
The type name bindgen picks for anonymous enums creates desync issues on the bindgen CI checks.
2025-10-20ZJIT: Implement codegen for FixnumMod (#14857)Max Bernstein
This is mostly to see what happens to the loops-times benchmark.
2025-10-20ZJIT: Implement expandarray (#14847)Max Bernstein
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-09-12ZJIT: Share more code with YJIT in jit.c (#14520)Takashi Kokubun
* ZJIT: Share more code with YJIT in jit.c * Fix ZJIT references to JIT
2025-09-11ZJIT, YJIT: Drop "// From xxx.h" comments in bindgen (#14519)Takashi Kokubun
2025-09-02ZJIT: Clear jit entry from iseqs after TracePoint activation (#14407)Stan Lo
ZJIT: Remove JITed code after TracePoint is enabled
2025-08-29Add rb_jit_vm_unlock and share it in ZJIT and YJITStan Lo
2025-08-29Add rb_jit_vm_lock_then_barrier and share it in ZJIT and YJITStan Lo
2025-08-29Add rb_jit_multi_ractor_p and share it in ZJIT and YJITStan Lo
2025-08-29ZJIT: Specialize monomorphic GetIvar (#14388)Max Bernstein
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-29YJIT: rb_ivar_get_at skip ractor checksJean Boussier
Using `assume_single_ractor_mode` we can skip all ractor safety checks if we're in single ractor mode. ``` compare-ruby: ruby 3.5.0dev (2025-08-27T14:58:58Z merge-vm-setivar-d.. 5b749d8e53) +YJIT +PRISM [arm64-darwin24] built-ruby: ruby 3.5.0dev (2025-08-28T21:23:38Z yjit-get-exivar 3cc21b76d4) +YJIT +PRISM [arm64-darwin24] | |compare-ruby|built-ruby| |:--------------------------|-----------:|---------:| |vm_ivar_get_on_obj | 975.981| 975.772| | | 1.00x| -| |vm_ivar_get_on_class | 136.214| 470.912| | | -| 3.46x| |vm_ivar_get_on_generic | 148.315| 299.122| | | -| 2.02x| ```
2025-08-29YJIT: getinstancevariable cache indexes for types other than T_OBJECTJean Boussier
While accessing the ivars of other types is too complicated to realistically generate the ASM for it, we can at least provide the ivar index as to not have to lookup the shape tree every time. ``` compare-ruby: ruby 3.5.0dev (2025-08-27T14:58:58Z merge-vm-setivar-d.. 5b749d8e53) +YJIT +PRISM [arm64-darwin24] built-ruby: ruby 3.5.0dev (2025-08-28T17:58:32Z yjit-get-exivar efaa8c9b09) +YJIT +PRISM [arm64-darwin24] | |compare-ruby|built-ruby| |:--------------------------|-----------:|---------:| |vm_ivar_get_on_obj | 930.458| 936.865| | | -| 1.01x| |vm_ivar_get_on_class | 134.471| 431.622| | | -| 3.21x| |vm_ivar_get_on_generic | 146.679| 284.408| | | -| 1.94x| ``` Co-Authored-By: Aaron Patterson <tenderlove@ruby-lang.org>
2025-08-27ZJIT: Implement side exit stats (#14357)Takashi Kokubun
2025-07-28YJIT: Call YJIT hooks before enabling YJIT (#14032)Takashi Kokubun
2025-07-16YJIT: Side-exit on String#dup when it's not leaf (#13921)Takashi Kokubun
* YJIT: Side-exit on String#dup when it's not leaf * Use an enum instead of a macro for bindgen
2025-07-09ZJIT: Mark profiled objects when marking ISEQ (#13784)Takashi Kokubun
2025-06-13Add SHAPE_ID_HAS_IVAR_MASK for quick ivar checkJean Boussier
This allow checking if an object has ivars with just a shape_id mask. Notes: Merged: https://github.com/ruby/ruby/pull/13606
2025-06-12Get rid of `rb_shape_lookup`Jean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13596
2025-06-05Refactor raw accesses to rb_shape_t.capacityJean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13524
2025-06-04Get rid of TOO_COMPLEX shape typeJean Boussier
Instead it's now a `shape_id` flag. This allows to check if an object is complex without having to chase the `rb_shape_t` pointer. Notes: Merged: https://github.com/ruby/ruby/pull/13511
2025-05-27Get rid of `rb_shape_id(rb_shape_t *)`Jean Boussier
We should avoid conversions from `rb_shape_t *` into `shape_id_t` outside of `shape.c` as the short term goal is to have `shape_id_t` contain tags. Notes: Merged: https://github.com/ruby/ruby/pull/13448
2025-05-09Rename `RB_OBJ_SHAPE` -> `rb_obj_shape`Jean Boussier
As well as `RB_OBJ_SHAPE_ID` -> `rb_obj_shape_id` and `RSHAPE` is now a simple alias for `rb_shape_lookup`. I tried to turn all these into `static inline` but I'm having trouble with `RUBY_EXTERN rb_shape_tree_t *rb_shape_tree_ptr;` not being exposed as I'd expect. Notes: Merged: https://github.com/ruby/ruby/pull/13283
2025-05-09Rename `rb_shape_get_shape_id` -> `RB_OBJ_SHAPE_ID`Jean Boussier
And `rb_shape_get_shape` -> `RB_OBJ_SHAPE`. Notes: Merged: https://github.com/ruby/ruby/pull/13283
2025-05-09Refactor `rb_shape_get_next` to return an IDJean Boussier
Also rename it, and change parameters to be consistent with other transition functions. Notes: Merged: https://github.com/ruby/ruby/pull/13283
2025-05-09Rename `rb_shape_obj_too_complex` -> `rb_shape_obj_too_complex_p`Jean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13283
2025-05-09Rename `rb_shape_get_shape_by_id` -> `RSHAPE`Jean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13283
2025-05-08Refactor OBJ_TOO_COMPLEX_SHAPE_ID to not be referenced outside shape.hJean Boussier
Also refactor checks for `->type == SHAPE_OBJ_TOO_COMPLEX`. Notes: Merged: https://github.com/ruby/ruby/pull/13159
2025-05-02YJIT: ZJIT: Share identical glue functionsAlan Wu
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. Notes: Merged: https://github.com/ruby/ruby/pull/13229
2025-04-25Inline Class#new.Aaron Patterson
This commit inlines instructions for Class#new. To make this work, we added a new YARV instructions, `opt_new`. `opt_new` checks whether or not the `new` method is the default allocator method. If it is, it allocates the object, and pushes the instance on the stack. If not, the instruction jumps to the "slow path" method call instructions. Old instructions: ``` > ruby --dump=insns -e'Object.new' == disasm: #<ISeq:<main>@-e:1 (1,0)-(1,10)> 0000 opt_getconstant_path <ic:0 Object> ( 1)[Li] 0002 opt_send_without_block <calldata!mid:new, argc:0, ARGS_SIMPLE> 0004 leave ``` New instructions: ``` > ./miniruby --dump=insns -e'Object.new' == disasm: #<ISeq:<main>@-e:1 (1,0)-(1,10)> 0000 opt_getconstant_path <ic:0 Object> ( 1)[Li] 0002 putnil 0003 swap 0004 opt_new <calldata!mid:new, argc:0, ARGS_SIMPLE>, 11 0007 opt_send_without_block <calldata!mid:initialize, argc:0, FCALL|ARGS_SIMPLE> 0009 jump 14 0011 opt_send_without_block <calldata!mid:new, argc:0, ARGS_SIMPLE> 0013 swap 0014 pop 0015 leave ``` This commit speeds up basic object allocation (`Foo.new`) by 60%, but classes that take keyword parameters see an even bigger benefit because no hash is allocated when instantiating the object (3x to 6x faster). Here is an example that uses `Hash.new(capacity: 0)`: ``` > hyperfine "ruby --disable-gems -e'i = 0; while i < 10_000_000; Hash.new(capacity: 0); i += 1; end'" "./ruby --disable-gems -e'i = 0; while i < 10_000_000; Hash.new(capacity: 0); i += 1; end'" Benchmark 1: ruby --disable-gems -e'i = 0; while i < 10_000_000; Hash.new(capacity: 0); i += 1; end' Time (mean ± σ): 1.082 s ± 0.004 s [User: 1.074 s, System: 0.008 s] Range (min … max): 1.076 s … 1.088 s 10 runs Benchmark 2: ./ruby --disable-gems -e'i = 0; while i < 10_000_000; Hash.new(capacity: 0); i += 1; end' Time (mean ± σ): 627.9 ms ± 3.5 ms [User: 622.7 ms, System: 4.8 ms] Range (min … max): 622.7 ms … 633.2 ms 10 runs Summary ./ruby --disable-gems -e'i = 0; while i < 10_000_000; Hash.new(capacity: 0); i += 1; end' ran 1.72 ± 0.01 times faster than ruby --disable-gems -e'i = 0; while i < 10_000_000; Hash.new(capacity: 0); i += 1; end' ``` This commit changes the backtrace for `initialize`: ``` aaron@tc ~/g/ruby (inline-new)> cat test.rb class Foo def initialize puts caller end end def hello Foo.new end hello aaron@tc ~/g/ruby (inline-new)> ruby -v test.rb ruby 3.4.2 (2025-02-15 revision d2930f8e7a) +PRISM [arm64-darwin24] test.rb:8:in 'Class#new' test.rb:8:in 'Object#hello' test.rb:11:in '<main>' aaron@tc ~/g/ruby (inline-new)> ./miniruby -v test.rb ruby 3.5.0dev (2025-03-28T23:59:40Z inline-new c4157884e4) +PRISM [arm64-darwin24] test.rb:8:in 'Object#hello' test.rb:11:in '<main>' ``` It also increases memory usage for calls to `new` by 122 bytes: ``` aaron@tc ~/g/ruby (inline-new)> cat test.rb require "objspace" class Foo def initialize puts caller end end def hello Foo.new end puts ObjectSpace.memsize_of(RubyVM::InstructionSequence.of(method(:hello))) aaron@tc ~/g/ruby (inline-new)> make runruby RUBY_ON_BUG='gdb -x ./.gdbinit -p' ./miniruby -I./lib -I. -I.ext/common ./tool/runruby.rb --extout=.ext -- --disable-gems ./test.rb 656 aaron@tc ~/g/ruby (inline-new)> ruby -v test.rb ruby 3.4.2 (2025-02-15 revision d2930f8e7a) +PRISM [arm64-darwin24] 544 ``` Thanks to @ko1 for coming up with this idea! Co-Authored-By: John Hawthorn <john@hawthorn.email>
2025-04-18Fix yjit-bindgenTakashi Kokubun
Notes: Merged: https://github.com/ruby/ruby/pull/13131
2025-04-18Move a couple of bindgen targets to ZJIT bindgenTakashi Kokubun
We filed https://github.com/Shopify/zjit/pull/65 and https://github.com/Shopify/zjit/pull/64 concurrently. Notes: Merged: https://github.com/ruby/ruby/pull/13131
2025-04-18Rust tests: Load builtins (core library written in ruby)Alan Wu
Key here is calling rb_call_builtin_inits(), which sticking to public API for robustness is done by calling ruby_options(). Fixes: https://github.com/Shopify/zjit/issues/61 Notes: Merged: https://github.com/ruby/ruby/pull/13131
2025-04-18Print Ruby exception in test utilsMax Bernstein
Notes: Merged: https://github.com/ruby/ruby/pull/13131
2025-04-18Add compact Type latticeMax Bernstein
This will be used for local type inference and potentially SCCP. Notes: Merged: https://github.com/ruby/ruby/pull/13131
2025-04-18Add zjit_* instructions to profile the interpreter ↵Takashi Kokubun
(https://github.com/Shopify/zjit/pull/16) * Add zjit_* instructions to profile the interpreter * Rename FixnumPlus to FixnumAdd * Update a comment about Invalidate * Rename Guard to GuardType * Rename Invalidate to PatchPoint * Drop unneeded debug!() * Plan on profiling the types * Use the output of GuardType as type refined outputs Notes: Merged: https://github.com/ruby/ruby/pull/13131
2025-04-18boot_vm boots and runsAlan Wu
Notes: Merged: https://github.com/ruby/ruby/pull/13131
2025-04-18bindgen works in --enable-zjit=dev mode.Alan Wu
Notes: Merged: https://github.com/ruby/ruby/pull/13131
2025-04-18make zjit-bindgen runs, but doesn't graft the right things yetAlan Wu
Notes: Merged: https://github.com/ruby/ruby/pull/13131
2025-02-16Remove undefined function from bindgenAaron Patterson
`rb_get_iseq_body_total_calls` was removed in cd8d20cd1fbcf9bf9d438b306beb65b2417fcc04, but it's still in the YJIT bindgen file. This commit just removes it from bindgen Notes: Merged: https://github.com/ruby/ruby/pull/12760
2025-02-14Only count VM instructions in YJIT stats buildsAaron Patterson
The instruction counter is slowing multi-Ractor applications. I had changed it to use a thread local, but using a thread local is slowing single threaded applications. This commit only enables the instruction counter in YJIT stats builds until we can figure out a way to gather the information with lower overhead. Co-authored-by: Randy Stauner <randy.stauner@shopify.com> Notes: Merged: https://github.com/ruby/ruby/pull/12670
2025-01-10Make rb_vm_insns_count a thread local variableAaron Patterson
`rb_vm_insns_count` is a global variable used for reporting YJIT statistics. It is a counter that tallies the number of interpreter instructions that have been executed, this way we can approximate how much time we're spending in YJIT compared to the interpreter. Unfortunately keeping this statistic means that every instruction executed in the interpreter loop must increment the counter. Normally this isn't a problem, but in multi-threaded situations (when Ractors are used), incrementing this counter can become quite costly due to page caching issues. Additionally, since there is no locking when incrementing this global, the count can't really make sense in a multi-threaded environment. This commit changes `rb_vm_insns_count` to a thread local. That way each Ractor has it's own copy of the counter and incrementing the counter becomes quite cheap. Of course this means that in multi-threaded situations, the value doesn't really make sense (but it didn't make sense before because of the lack of locking). The counter is used for YJIT statistics, and since YJIT is basically disabled when Ractors are in use, I don't think we care about inaccuracies (for the time being). We can revisit this counter when we give YJIT multi-threading support, but for the time being this commit restores multi-threaded performance. To test this, I used the benchmark in [Bug #20489]. Here is the performance on Ruby 3.2: ``` $ time RUBY_MAX_CPU=12 ./miniruby -v ../test.rb 8 8 ruby 3.2.0 (2022-12-25 revision a528908271) [x86_64-linux] [0...1, 1...2, 2...3, 3...4, 4...5, 5...6, 6...7, 7...8] ../test.rb:43: warning: Ractor is experimental, and the behavior may change in future versions of Ruby! Also there are many implementation issues. ________________________________________________________ Executed in 2.53 secs fish external usr time 19.86 secs 370.00 micros 19.86 secs sys time 0.02 secs 320.00 micros 0.02 secs ``` We can see the regression in performance on the master branch: ``` $ time RUBY_MAX_CPU=12 ./miniruby -v ../test.rb 8 8 ruby 3.5.0dev (2025-01-10T16:22:26Z master 4a2702dafb) +PRISM [x86_64-linux] [0...1, 1...2, 2...3, 3...4, 4...5, 5...6, 6...7, 7...8] ../test.rb:43: warning: Ractor is experimental, and the behavior may change in future versions of Ruby! Also there are many implementation issues. ________________________________________________________ Executed in 24.87 secs fish external usr time 195.55 secs 0.00 micros 195.55 secs sys time 0.00 secs 716.00 micros 0.00 secs ``` Here are the stats after this commit: ``` $ time RUBY_MAX_CPU=12 ./miniruby -v ../test.rb 8 8 ruby 3.5.0dev (2025-01-10T20:37:06Z tl 3ef0432779) +PRISM [x86_64-linux] [0...1, 1...2, 2...3, 3...4, 4...5, 5...6, 6...7, 7...8] ../test.rb:43: warning: Ractor is experimental, and the behavior may change in future versions of Ruby! Also there are many implementation issues. ________________________________________________________ Executed in 2.46 secs fish external usr time 19.34 secs 381.00 micros 19.34 secs sys time 0.01 secs 321.00 micros 0.01 secs ``` [Bug #20489] Notes: Merged: https://github.com/ruby/ruby/pull/12549
2024-11-13YJIT: Specialize `String#[]` (`String#slice`) with fixnum arguments (#12069)Randy Stauner
* YJIT: Specialize `String#[]` (`String#slice`) with fixnum arguments String#[] is in the top few C calls of several YJIT benchmarks: liquid-compile rubocop mail sudoku This speeds up these benchmarks by 1-2%. * YJIT: Try harder to get type info for `String#[]` In the large generated code of the mail gem the context doesn't have the type info. In that case if we peek at the stack and add a guard we can still apply the specialization and it speeds up the mail benchmark by 5%. Co-authored-by: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@shopify.com> Co-authored-by: Takashi Kokubun (k0kubun) <takashikkbn@gmail.com> --------- Co-authored-by: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@shopify.com> Co-authored-by: Takashi Kokubun (k0kubun) <takashikkbn@gmail.com> Notes: Merged-By: maximecb <maximecb@ruby-lang.org>
2024-10-22YJIT: Implement specialization for no-op `{Kernel,Numeric}#dup`Alan Wu
Type information in the context for no additional work! This is the `if (special_object_p(obj)) return obj;` path in rb_obj_dup() and for Numeric#dup, it's always the identity function. Notes: Merged: https://github.com/ruby/ruby/pull/11926
2024-10-18YJIT: Allow shareable consts in multi-ractor mode (#11917)John Hawthorn
* Update yjit-bindgen deps * YJIT: Allow shareable consts in multi-ractor mode * Update yjit/src/codegen.rs Co-authored-by: Alan Wu <XrXr@users.noreply.github.com> --------- Co-authored-by: Alan Wu <XrXr@users.noreply.github.com> Notes: Merged-By: maximecb <maximecb@ruby-lang.org>