ZJIT: Don't push frame for String#empty? (#14836)

lobsters before:

```
***ZJIT: Printing ZJIT statistics on exit***
Top-20 not inlined C methods (71.9% of total 15,247,103):
                                    Hash#[]: 4,516,006 (29.6%)
                              Class#current: 1,154,273 ( 7.6%)
                               Kernel#is_a?: 1,027,952 ( 6.7%)
                              Regexp#match?:   398,256 ( 2.6%)
                              String#empty?:   353,775 ( 2.3%)
                                  Hash#key?:   349,154 ( 2.3%)
                                   Hash#[]=:   344,347 ( 2.3%)
                         String#start_with?:   337,386 ( 2.2%)
                         Kernel#respond_to?:   316,003 ( 2.1%)
                 ObjectSpace::WeakKeyMap#[]:   238,978 ( 1.6%)
                              TrueClass#===:   235,771 ( 1.5%)
                             FalseClass#===:   231,144 ( 1.5%)
                             Array#include?:   211,339 ( 1.4%)
                                 Hash#fetch:   204,702 ( 1.3%)
                        Kernel#block_given?:   181,789 ( 1.2%)
         ActiveSupport::OrderedOptions#_get:   181,272 ( 1.2%)
                                 Kernel#dup:   179,336 ( 1.2%)
                             BasicObject#!=:   174,429 ( 1.1%)
                                  Class#new:   168,079 ( 1.1%)
                            Kernel#kind_of?:   165,600 ( 1.1%)
Top-20 not annotated C methods (72.5% of total 15,409,355):
                                    Hash#[]: 4,516,016 (29.3%)
                               Kernel#is_a?: 1,209,970 ( 7.9%)
                              Class#current: 1,154,273 ( 7.5%)
                              Regexp#match?:   398,256 ( 2.6%)
                              String#empty?:   361,013 ( 2.3%)
                                  Hash#key?:   349,154 ( 2.3%)
                                   Hash#[]=:   344,347 ( 2.2%)
                         String#start_with?:   337,386 ( 2.2%)
                         Kernel#respond_to?:   316,003 ( 2.1%)
                 ObjectSpace::WeakKeyMap#[]:   238,978 ( 1.6%)
                              TrueClass#===:   235,771 ( 1.5%)
                             FalseClass#===:   231,144 ( 1.5%)
                             Array#include?:   211,339 ( 1.4%)
                                 Hash#fetch:   204,702 ( 1.3%)
                        Kernel#block_given?:   191,658 ( 1.2%)
         ActiveSupport::OrderedOptions#_get:   181,272 ( 1.2%)
                                 Kernel#dup:   179,343 ( 1.2%)
                             BasicObject#!=:   174,613 ( 1.1%)
                                  Class#new:   168,079 ( 1.1%)
                            Kernel#kind_of?:   165,634 ( 1.1%)
Top-2 not optimized method types for send (100.0% of total 71,083):
  cfunc: 47,637 (67.0%)
   iseq: 23,446 (33.0%)
Top-6 not optimized method types for send_without_block (100.0% of total 4,482,446):
       iseq: 2,227,443 (49.7%)
    bmethod:   985,679 (22.0%)
  optimized:   952,914 (21.3%)
      alias:   310,750 ( 6.9%)
       null:     5,106 ( 0.1%)
      cfunc:       554 ( 0.0%)
Top-13 not optimized instructions (100.0% of total 4,264,922):
             invokesuper: 2,346,296 (55.0%)
             invokeblock:   809,163 (19.0%)
             sendforward:   505,446 (11.9%)
                  opt_eq:   454,244 (10.7%)
                opt_plus:    74,059 ( 1.7%)
               opt_minus:    36,227 ( 0.8%)
  opt_send_without_block:    21,396 ( 0.5%)
                 opt_neq:     7,247 ( 0.2%)
                opt_mult:     6,752 ( 0.2%)
                  opt_or:     3,617 ( 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 27,366,538):
                send_without_block_polymorphic: 9,222,828 (33.7%)
                              send_no_profiles: 5,892,897 (21.5%)
  send_without_block_not_optimized_method_type: 4,482,446 (16.4%)
                     not_optimized_instruction: 4,264,922 (15.6%)
                send_without_block_no_profiles: 3,407,046 (12.4%)
                send_not_optimized_method_type:    71,083 ( 0.3%)
       send_without_block_cfunc_array_variadic:    15,135 ( 0.1%)
                      obj_to_string_not_string:     9,919 ( 0.0%)
       send_without_block_direct_too_many_args:       262 ( 0.0%)
Top-9 unhandled YARV insns (100.0% of total 688,292):
         expandarray: 328,369 (47.7%)
        checkkeyword: 190,697 (27.7%)
    getclassvariable:  59,286 ( 8.6%)
       getblockparam:  48,651 ( 7.1%)
  invokesuperforward:  48,162 ( 7.0%)
   opt_duparray_send:  11,978 ( 1.7%)
         getconstant:     840 ( 0.1%)
          checkmatch:     290 ( 0.0%)
                once:      19 ( 0.0%)
Top-2 compile error reasons (100.0% of total 3,675,808):
  register_spill_on_alloc: 3,459,950 (94.1%)
  register_spill_on_ccall:   215,858 ( 5.9%)
Top-14 side exit reasons (100.0% of total 10,732,532):
                        compile_error: 3,675,808 (34.2%)
                   guard_type_failure: 2,616,693 (24.4%)
                  guard_shape_failure: 1,902,102 (17.7%)
                  unhandled_yarv_insn:   688,292 ( 6.4%)
  block_param_proxy_not_iseq_or_ifunc:   534,943 ( 5.0%)
                      unhandled_kwarg:   421,996 ( 3.9%)
                           patchpoint:   359,831 ( 3.4%)
                unknown_newarray_send:   314,665 ( 2.9%)
                      unhandled_splat:   121,910 ( 1.1%)
                   unhandled_hir_insn:    76,393 ( 0.7%)
           block_param_proxy_modified:    19,193 ( 0.2%)
                            interrupt:       528 ( 0.0%)
               obj_to_string_fallback:       156 ( 0.0%)
               guard_type_not_failure:        22 ( 0.0%)
                             send_count: 66,343,482
                     dynamic_send_count: 27,366,538 (41.2%)
                   optimized_send_count: 38,976,944 (58.8%)
              iseq_optimized_send_count: 17,935,768 (27.0%)
      inline_cfunc_optimized_send_count:  5,794,073 ( 8.7%)
non_variadic_cfunc_optimized_send_count: 12,588,582 (19.0%)
    variadic_cfunc_optimized_send_count:  2,658,521 ( 4.0%)
dynamic_getivar_count:                        7,321,990
dynamic_setivar_count:                        7,231,183
compiled_iseq_count:                              4,770
failed_iseq_count:                                  468
compile_time:                                   7,466ms
profile_time:                                      52ms
gc_time:                                           33ms
invalidation_time:                                116ms
vm_write_pc_count:                           64,768,186
vm_write_sp_count:                           63,445,066
vm_write_locals_count:                       63,445,066
vm_write_stack_count:                        63,445,066
vm_write_to_parent_iseq_local_count:            292,445
vm_read_from_parent_iseq_local_count:         6,461,354
code_region_bytes:                           22,446,080
side_exit_count:                             10,732,532
total_insn_count:                           515,600,654
vm_insn_count:                              163,640,874
zjit_insn_count:                            351,959,780
ratio_in_zjit:                                    68.3%
```

lobsters after:

```
***ZJIT: Printing ZJIT statistics on exit***
Top-20 not inlined C methods (72.3% of total 14,893,304):
                                    Hash#[]: 4,515,997 (30.3%)
                              Class#current: 1,154,273 ( 7.8%)
                               Kernel#is_a?: 1,027,957 ( 6.9%)
                              Regexp#match?:   398,259 ( 2.7%)
                                  Hash#key?:   349,149 ( 2.3%)
                                   Hash#[]=:   344,347 ( 2.3%)
                         String#start_with?:   337,386 ( 2.3%)
                         Kernel#respond_to?:   316,003 ( 2.1%)
                 ObjectSpace::WeakKeyMap#[]:   238,978 ( 1.6%)
                              TrueClass#===:   235,771 ( 1.6%)
                             FalseClass#===:   231,144 ( 1.6%)
                             Array#include?:   211,333 ( 1.4%)
                                 Hash#fetch:   204,703 ( 1.4%)
                        Kernel#block_given?:   181,781 ( 1.2%)
         ActiveSupport::OrderedOptions#_get:   181,272 ( 1.2%)
                                 Kernel#dup:   179,337 ( 1.2%)
                             BasicObject#!=:   174,429 ( 1.2%)
                                  Class#new:   168,079 ( 1.1%)
                            Kernel#kind_of?:   165,600 ( 1.1%)
                                  String#==:   154,751 ( 1.0%)
Top-20 not annotated C methods (72.9% of total 15,048,318):
                                    Hash#[]: 4,516,007 (30.0%)
                               Kernel#is_a?: 1,209,975 ( 8.0%)
                              Class#current: 1,154,273 ( 7.7%)
                              Regexp#match?:   398,259 ( 2.6%)
                                  Hash#key?:   349,149 ( 2.3%)
                                   Hash#[]=:   344,347 ( 2.3%)
                         String#start_with?:   337,386 ( 2.2%)
                         Kernel#respond_to?:   316,003 ( 2.1%)
                 ObjectSpace::WeakKeyMap#[]:   238,978 ( 1.6%)
                              TrueClass#===:   235,771 ( 1.6%)
                             FalseClass#===:   231,144 ( 1.5%)
                             Array#include?:   211,333 ( 1.4%)
                                 Hash#fetch:   204,703 ( 1.4%)
                        Kernel#block_given?:   191,650 ( 1.3%)
         ActiveSupport::OrderedOptions#_get:   181,272 ( 1.2%)
                                 Kernel#dup:   179,344 ( 1.2%)
                             BasicObject#!=:   174,613 ( 1.2%)
                                  Class#new:   168,079 ( 1.1%)
                            Kernel#kind_of?:   165,634 ( 1.1%)
                                  String#==:   160,682 ( 1.1%)
Top-2 not optimized method types for send (100.0% of total 71,084):
  cfunc: 47,638 (67.0%)
   iseq: 23,446 (33.0%)
Top-6 not optimized method types for send_without_block (100.0% of total 4,482,444):
       iseq: 2,227,440 (49.7%)
    bmethod:   985,679 (22.0%)
  optimized:   952,916 (21.3%)
      alias:   310,749 ( 6.9%)
       null:     5,106 ( 0.1%)
      cfunc:       554 ( 0.0%)
Top-13 not optimized instructions (100.0% of total 4,264,913):
             invokesuper: 2,346,301 (55.0%)
             invokeblock:   809,153 (19.0%)
             sendforward:   505,445 (11.9%)
                  opt_eq:   454,244 (10.7%)
                opt_plus:    74,056 ( 1.7%)
               opt_minus:    36,227 ( 0.8%)
  opt_send_without_block:    21,396 ( 0.5%)
                 opt_neq:     7,247 ( 0.2%)
                opt_mult:     6,752 ( 0.2%)
                  opt_or:     3,617 ( 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 27,366,491):
                send_without_block_polymorphic: 9,222,820 (33.7%)
                              send_no_profiles: 5,892,885 (21.5%)
  send_without_block_not_optimized_method_type: 4,482,444 (16.4%)
                     not_optimized_instruction: 4,264,913 (15.6%)
                send_without_block_no_profiles: 3,407,030 (12.4%)
                send_not_optimized_method_type:    71,084 ( 0.3%)
       send_without_block_cfunc_array_variadic:    15,134 ( 0.1%)
                      obj_to_string_not_string:     9,919 ( 0.0%)
       send_without_block_direct_too_many_args:       262 ( 0.0%)
Top-9 unhandled YARV insns (100.0% of total 688,291):
         expandarray: 328,368 (47.7%)
        checkkeyword: 190,697 (27.7%)
    getclassvariable:  59,286 ( 8.6%)
       getblockparam:  48,651 ( 7.1%)
  invokesuperforward:  48,162 ( 7.0%)
   opt_duparray_send:  11,978 ( 1.7%)
         getconstant:     840 ( 0.1%)
          checkmatch:     290 ( 0.0%)
                once:      19 ( 0.0%)
Top-2 compile error reasons (100.0% of total 3,675,807):
  register_spill_on_alloc: 3,459,949 (94.1%)
  register_spill_on_ccall:   215,858 ( 5.9%)
Top-14 side exit reasons (100.0% of total 10,732,546):
                        compile_error: 3,675,807 (34.2%)
                   guard_type_failure: 2,616,699 (24.4%)
                  guard_shape_failure: 1,902,100 (17.7%)
                  unhandled_yarv_insn:   688,291 ( 6.4%)
  block_param_proxy_not_iseq_or_ifunc:   534,950 ( 5.0%)
                      unhandled_kwarg:   421,993 ( 3.9%)
                           patchpoint:   359,837 ( 3.4%)
                unknown_newarray_send:   314,667 ( 2.9%)
                      unhandled_splat:   121,913 ( 1.1%)
                   unhandled_hir_insn:    76,393 ( 0.7%)
           block_param_proxy_modified:    19,193 ( 0.2%)
                            interrupt:       525 ( 0.0%)
               obj_to_string_fallback:       156 ( 0.0%)
               guard_type_not_failure:        22 ( 0.0%)
                             send_count: 66,343,388
                     dynamic_send_count: 27,366,491 (41.2%)
                   optimized_send_count: 38,976,897 (58.8%)
              iseq_optimized_send_count: 17,935,730 (27.0%)
      inline_cfunc_optimized_send_count:  6,147,863 ( 9.3%)
non_variadic_cfunc_optimized_send_count: 12,234,780 (18.4%)
    variadic_cfunc_optimized_send_count:  2,658,524 ( 4.0%)
dynamic_getivar_count:                        7,321,987
dynamic_setivar_count:                        7,231,160
compiled_iseq_count:                              4,770
failed_iseq_count:                                  468
compile_time:                                   7,223ms
profile_time:                                      51ms
gc_time:                                           32ms
invalidation_time:                                107ms
vm_write_pc_count:                           64,414,293
vm_write_sp_count:                           63,091,183
vm_write_locals_count:                       63,091,183
vm_write_stack_count:                        63,091,183
vm_write_to_parent_iseq_local_count:            292,443
vm_read_from_parent_iseq_local_count:         6,461,326
code_region_bytes:                           22,446,080
side_exit_count:                             10,732,546
total_insn_count:                           515,600,823
vm_insn_count:                              163,641,263
zjit_insn_count:                            351,959,560
ratio_in_zjit:                                    68.3%
```
This commit is contained in:
Jacob 2025-10-17 13:26:03 -04:00 committed by GitHub
parent 5298e97954
commit 0e5cb74a00
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
Notes: git 2025-10-17 17:26:30 +00:00
Merged-By: tekknolagi <donotemailthisaddress@bernsteinbear.com>
2 changed files with 60 additions and 0 deletions

View File

@ -191,6 +191,7 @@ pub fn init() -> Annotations {
annotate!(rb_cString, "bytesize", types::Fixnum, no_gc, leaf);
annotate!(rb_cString, "to_s", types::StringExact);
annotate!(rb_cString, "getbyte", inline_string_getbyte);
annotate!(rb_cString, "empty?", types::BoolExact, no_gc, leaf, elidable);
annotate!(rb_cModule, "name", types::StringExact.union(types::NilClass), no_gc, leaf, elidable);
annotate!(rb_cModule, "===", types::BoolExact, no_gc, leaf);
annotate!(rb_cArray, "length", types::Fixnum, no_gc, leaf, elidable);

View File

@ -13255,6 +13255,65 @@ mod opt_tests {
");
}
#[test]
fn test_specialize_string_empty() {
eval(r#"
def test(s)
s.empty?
end
test("asdf")
"#);
assert_snapshot!(hir_string("test"), @r"
fn test@<compiled>:3:
bb0():
EntryPoint interpreter
v1:BasicObject = LoadSelf
v2:BasicObject = GetLocal l0, SP@4
Jump bb2(v1, v2)
bb1(v5:BasicObject, v6:BasicObject):
EntryPoint JIT(0)
Jump bb2(v5, v6)
bb2(v8:BasicObject, v9:BasicObject):
PatchPoint MethodRedefined(String@0x1000, empty?@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(String@0x1000)
v25:StringExact = GuardType v9, StringExact
IncrCounter inline_cfunc_optimized_send_count
v27:BoolExact = CCall empty?@0x1038, v25
CheckInterrupts
Return v27
");
}
#[test]
fn test_eliminate_string_empty() {
eval(r#"
def test(s)
s.empty?
4
end
test("this should get removed")
"#);
assert_snapshot!(hir_string("test"), @r"
fn test@<compiled>:3:
bb0():
EntryPoint interpreter
v1:BasicObject = LoadSelf
v2:BasicObject = GetLocal l0, SP@4
Jump bb2(v1, v2)
bb1(v5:BasicObject, v6:BasicObject):
EntryPoint JIT(0)
Jump bb2(v5, v6)
bb2(v8:BasicObject, v9:BasicObject):
PatchPoint MethodRedefined(String@0x1000, empty?@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(String@0x1000)
v28:StringExact = GuardType v9, StringExact
IncrCounter inline_cfunc_optimized_send_count
v19:Fixnum[4] = Const Value(4)
CheckInterrupts
Return v19
");
}
#[test]
fn test_inline_integer_succ_with_fixnum() {
eval("