diff options
author | Étienne Barrié <[email protected]> | 2024-08-05 12:31:24 +0200 |
---|---|---|
committer | Jean Boussier <[email protected]> | 2024-09-05 12:46:02 +0200 |
commit | bf9879791af11a20e50921551220c08d1c7f7f02 () | |
tree | 68732e79fac871a629fc815b525f0cc20ed1c8bc | |
parent | a99707cd9c6a1d53cf8ebc883dc210219bd67a28 (diff) |
Optimized instruction for Hash#freeze
If a Hash which is empty or only using literals is frozen, we detect this as a peephole optimization and change the instructions to be `opt_hash_freeze`. [Feature #20684] Co-authored-by: Jean Boussier <[email protected]>
Notes: Merged: https://.com/ruby/ruby/pull/11406
-rw-r--r-- | compile.c | 49 | ||||
-rw-r--r-- | hash.c | 6 | ||||
-rw-r--r-- | insns.def | 15 | ||||
-rw-r--r-- | internal/hash.h | 1 | ||||
-rw-r--r-- | lib/ruby_vm/rjit/insn_compiler.rb | 19 | ||||
-rw-r--r-- | test/ruby/test_optimization.rb | 46 | ||||
-rw-r--r-- | vm.c | 2 | ||||
-rw-r--r-- | vm_insnhelper.c | 11 | ||||
-rw-r--r-- | yjit/src/codegen.rs | 18 | ||||
-rw-r--r-- | yjit/src/cruby_bindings.inc.rs | 316 |
10 files changed, 325 insertions, 158 deletions
@@ -3430,6 +3430,32 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal } /* * newarray 0 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil * => @@ -3452,6 +3478,29 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal } } if (IS_INSN_ID(iobj, branchif) || IS_INSN_ID(iobj, branchnil) || IS_INSN_ID(iobj, branchunless)) { @@ -103,6 +103,7 @@ static VALUE rb_hash_s_try_convert(VALUE, VALUE); * 2. Insert WBs */ VALUE rb_hash_freeze(VALUE hash) { @@ -110,6 +111,7 @@ rb_hash_freeze(VALUE hash) } VALUE rb_cHash; static VALUE envtbl; static ID id_hash, id_flatten_bang; @@ -7118,6 +7120,7 @@ Init_Hash(void) rb_define_singleton_method(rb_cHash, "try_convert", rb_hash_s_try_convert, 1); rb_define_method(rb_cHash, "initialize_copy", rb_hash_replace, 1); rb_define_method(rb_cHash, "rehash", rb_hash_rehash, 0); rb_define_method(rb_cHash, "to_hash", rb_hash_to_hash, 0); rb_define_method(rb_cHash, "to_h", rb_hash_to_h, 0); @@ -7204,6 +7207,9 @@ Init_Hash(void) rb_define_singleton_method(rb_cHash, "ruby2_keywords_hash?", rb_hash_s_ruby2_keywords_hash_p, 1); rb_define_singleton_method(rb_cHash, "ruby2_keywords_hash", rb_hash_s_ruby2_keywords_hash, 1); /* Document-class: ENV * * +ENV+ is a hash-like accessor for environment variables. @@ -935,6 +935,21 @@ opt_ary_freeze } DEFINE_INSN opt_str_freeze (VALUE str, CALL_DATA cd) () @@ -88,6 +88,7 @@ int rb_hash_stlike_foreach_with_replace(VALUE hash, st_foreach_check_callback_fu int rb_hash_stlike_update(VALUE hash, st_data_t key, st_update_callback_func *func, st_data_t arg); VALUE rb_ident_hash_new_with_size(st_index_t size); void rb_hash_free(VALUE hash); static inline unsigned RHASH_AR_TABLE_SIZE_RAW(VALUE h); static inline VALUE RHASH_IFNONE(VALUE h); @@ -91,6 +91,7 @@ module RubyVM::RJIT when :objtostring then objtostring(jit, ctx, asm) when :opt_str_freeze then opt_str_freeze(jit, ctx, asm) when :opt_ary_freeze then opt_ary_freeze(jit, ctx, asm) when :opt_nil_p then opt_nil_p(jit, ctx, asm) # opt_str_uminus when :opt_newarray_send then opt_newarray_send(jit, ctx, asm) @@ -1512,6 +1513,24 @@ module RubyVM::RJIT # @param jit [RubyVM::RJIT::JITState] # @param ctx [RubyVM::RJIT::Context] # @param asm [RubyVM::RJIT::Assembler] def opt_str_freeze(jit, ctx, asm) unless Invariants.assume_bop_not_redefined(jit, C::STRING_REDEFINED_OP_FLAG, C::BOP_FREEZE) return CantCompile; @@ -795,6 +795,52 @@ class TestRubyOptimization < Test::Unit::TestCase RUBY end def test_branch_condition_backquote bug = '[ruby-core:80740] [Bug #13444] redefined backquote should be called' class << self @@ -2232,7 +2232,7 @@ vm_init_redefined_flag(void) OP(EmptyP, EMPTY_P), (C(Array), C(String), C(Hash)); OP(Succ, SUCC), (C(Integer), C(String)); OP(EqTilde, MATCH), (C(Regexp), C(String)); - OP(Freeze, FREEZE), (C(String), C(Array)); OP(UMinus, UMINUS), (C(String)); OP(Max, MAX), (C(Array)); OP(Min, MIN), (C(Array)); @@ -6121,6 +6121,17 @@ vm_opt_ary_freeze(VALUE ary, int bop, ID id) } static VALUE vm_opt_str_freeze(VALUE str, int bop, ID id) { if (BASIC_OP_UNREDEFINED_P(bop, STRING_REDEFINED_OP_FLAG)) { @@ -4204,6 +4204,23 @@ fn gen_opt_ary_freeze( Some(KeepCompiling) } fn gen_opt_str_uminus( jit: &mut JITState, asm: &mut Assembler, @@ -10246,6 +10263,7 @@ fn get_gen_fn(opcode: VALUE) -> Option<InsnGenFn> { YARVINSN_opt_ge => Some(gen_opt_ge), YARVINSN_opt_mod => Some(gen_opt_mod), YARVINSN_opt_ary_freeze => Some(gen_opt_ary_freeze), YARVINSN_opt_str_freeze => Some(gen_opt_str_freeze), YARVINSN_opt_str_uminus => Some(gen_opt_str_uminus), YARVINSN_opt_newarray_send => Some(gen_opt_newarray_send), @@ -784,163 +784,165 @@ pub const YARVINSN_sendforward: ruby_vminsn_type = 56; pub const YARVINSN_opt_send_without_block: ruby_vminsn_type = 57; pub const YARVINSN_objtostring: ruby_vminsn_type = 58; pub const YARVINSN_opt_ary_freeze: ruby_vminsn_type = 59; -pub const YARVINSN_opt_str_freeze: ruby_vminsn_type = 60; -pub const YARVINSN_opt_nil_p: ruby_vminsn_type = 61; -pub const YARVINSN_opt_str_uminus: ruby_vminsn_type = 62; -pub const YARVINSN_opt_newarray_send: ruby_vminsn_type = 63; -pub const YARVINSN_invokesuper: ruby_vminsn_type = 64; -pub const YARVINSN_invokesuperforward: ruby_vminsn_type = 65; -pub const YARVINSN_invokeblock: ruby_vminsn_type = 66; -pub const YARVINSN_leave: ruby_vminsn_type = 67; -pub const YARVINSN_throw: ruby_vminsn_type = 68; -pub const YARVINSN_jump: ruby_vminsn_type = 69; -pub const YARVINSN_branchif: ruby_vminsn_type = 70; -pub const YARVINSN_branchunless: ruby_vminsn_type = 71; -pub const YARVINSN_branchnil: ruby_vminsn_type = 72; -pub const YARVINSN_once: ruby_vminsn_type = 73; -pub const YARVINSN_opt_case_dis: ruby_vminsn_type = 74; -pub const YARVINSN_opt_plus: ruby_vminsn_type = 75; -pub const YARVINSN_opt_minus: ruby_vminsn_type = 76; -pub const YARVINSN_opt_mult: ruby_vminsn_type = 77; -pub const YARVINSN_opt_div: ruby_vminsn_type = 78; -pub const YARVINSN_opt_mod: ruby_vminsn_type = 79; -pub const YARVINSN_opt_eq: ruby_vminsn_type = 80; -pub const YARVINSN_opt_neq: ruby_vminsn_type = 81; -pub const YARVINSN_opt_lt: ruby_vminsn_type = 82; -pub const YARVINSN_opt_le: ruby_vminsn_type = 83; -pub const YARVINSN_opt_gt: ruby_vminsn_type = 84; -pub const YARVINSN_opt_ge: ruby_vminsn_type = 85; -pub const YARVINSN_opt_ltlt: ruby_vminsn_type = 86; -pub const YARVINSN_opt_and: ruby_vminsn_type = 87; -pub const YARVINSN_opt_or: ruby_vminsn_type = 88; -pub const YARVINSN_opt_aref: ruby_vminsn_type = 89; -pub const YARVINSN_opt_aset: ruby_vminsn_type = 90; -pub const YARVINSN_opt_aset_with: ruby_vminsn_type = 91; -pub const YARVINSN_opt_aref_with: ruby_vminsn_type = 92; -pub const YARVINSN_opt_length: ruby_vminsn_type = 93; -pub const YARVINSN_opt_size: ruby_vminsn_type = 94; -pub const YARVINSN_opt_empty_p: ruby_vminsn_type = 95; -pub const YARVINSN_opt_succ: ruby_vminsn_type = 96; -pub const YARVINSN_opt_not: ruby_vminsn_type = 97; -pub const YARVINSN_opt_regexpmatch2: ruby_vminsn_type = 98; -pub const YARVINSN_invokebuiltin: ruby_vminsn_type = 99; -pub const YARVINSN_opt_invokebuiltin_delegate: ruby_vminsn_type = 100; -pub const YARVINSN_opt_invokebuiltin_delegate_leave: ruby_vminsn_type = 101; -pub const YARVINSN_getlocal_WC_0: ruby_vminsn_type = 102; -pub const YARVINSN_getlocal_WC_1: ruby_vminsn_type = 103; -pub const YARVINSN_setlocal_WC_0: ruby_vminsn_type = 104; -pub const YARVINSN_setlocal_WC_1: ruby_vminsn_type = 105; -pub const YARVINSN_putobject_INT2FIX_0_: ruby_vminsn_type = 106; -pub const YARVINSN_putobject_INT2FIX_1_: ruby_vminsn_type = 107; -pub const YARVINSN_trace_nop: ruby_vminsn_type = 108; -pub const YARVINSN_trace_getlocal: ruby_vminsn_type = 109; -pub const YARVINSN_trace_setlocal: ruby_vminsn_type = 110; -pub const YARVINSN_trace_getblockparam: ruby_vminsn_type = 111; -pub const YARVINSN_trace_setblockparam: ruby_vminsn_type = 112; -pub const YARVINSN_trace_getblockparamproxy: ruby_vminsn_type = 113; -pub const YARVINSN_trace_getspecial: ruby_vminsn_type = 114; -pub const YARVINSN_trace_setspecial: ruby_vminsn_type = 115; -pub const YARVINSN_trace_getinstancevariable: ruby_vminsn_type = 116; -pub const YARVINSN_trace_setinstancevariable: ruby_vminsn_type = 117; -pub const YARVINSN_trace_getclassvariable: ruby_vminsn_type = 118; -pub const YARVINSN_trace_setclassvariable: ruby_vminsn_type = 119; -pub const YARVINSN_trace_opt_getconstant_path: ruby_vminsn_type = 120; -pub const YARVINSN_trace_getconstant: ruby_vminsn_type = 121; -pub const YARVINSN_trace_setconstant: ruby_vminsn_type = 122; -pub const YARVINSN_trace_getglobal: ruby_vminsn_type = 123; -pub const YARVINSN_trace_setglobal: ruby_vminsn_type = 124; -pub const YARVINSN_trace_putnil: ruby_vminsn_type = 125; -pub const YARVINSN_trace_putself: ruby_vminsn_type = 126; -pub const YARVINSN_trace_putobject: ruby_vminsn_type = 127; -pub const YARVINSN_trace_putspecialobject: ruby_vminsn_type = 128; -pub const YARVINSN_trace_putstring: ruby_vminsn_type = 129; -pub const YARVINSN_trace_putchilledstring: ruby_vminsn_type = 130; -pub const YARVINSN_trace_concatstrings: ruby_vminsn_type = 131; -pub const YARVINSN_trace_anytostring: ruby_vminsn_type = 132; -pub const YARVINSN_trace_toregexp: ruby_vminsn_type = 133; -pub const YARVINSN_trace_intern: ruby_vminsn_type = 134; -pub const YARVINSN_trace_newarray: ruby_vminsn_type = 135; -pub const YARVINSN_trace_pushtoarraykwsplat: ruby_vminsn_type = 136; -pub const YARVINSN_trace_duparray: ruby_vminsn_type = 137; -pub const YARVINSN_trace_duphash: ruby_vminsn_type = 138; -pub const YARVINSN_trace_expandarray: ruby_vminsn_type = 139; -pub const YARVINSN_trace_concatarray: ruby_vminsn_type = 140; -pub const YARVINSN_trace_concattoarray: ruby_vminsn_type = 141; -pub const YARVINSN_trace_pushtoarray: ruby_vminsn_type = 142; -pub const YARVINSN_trace_splatarray: ruby_vminsn_type = 143; -pub const YARVINSN_trace_splatkw: ruby_vminsn_type = 144; -pub const YARVINSN_trace_newhash: ruby_vminsn_type = 145; -pub const YARVINSN_trace_newrange: ruby_vminsn_type = 146; -pub const YARVINSN_trace_pop: ruby_vminsn_type = 147; -pub const YARVINSN_trace_dup: ruby_vminsn_type = 148; -pub const YARVINSN_trace_dupn: ruby_vminsn_type = 149; -pub const YARVINSN_trace_swap: ruby_vminsn_type = 150; -pub const YARVINSN_trace_opt_reverse: ruby_vminsn_type = 151; -pub const YARVINSN_trace_topn: ruby_vminsn_type = 152; -pub const YARVINSN_trace_setn: ruby_vminsn_type = 153; -pub const YARVINSN_trace_adjuststack: ruby_vminsn_type = 154; -pub const YARVINSN_trace_defined: ruby_vminsn_type = 155; -pub const YARVINSN_trace_definedivar: ruby_vminsn_type = 156; -pub const YARVINSN_trace_checkmatch: ruby_vminsn_type = 157; -pub const YARVINSN_trace_checkkeyword: ruby_vminsn_type = 158; -pub const YARVINSN_trace_checktype: ruby_vminsn_type = 159; -pub const YARVINSN_trace_defineclass: ruby_vminsn_type = 160; -pub const YARVINSN_trace_definemethod: ruby_vminsn_type = 161; -pub const YARVINSN_trace_definesmethod: ruby_vminsn_type = 162; -pub const YARVINSN_trace_send: ruby_vminsn_type = 163; -pub const YARVINSN_trace_sendforward: ruby_vminsn_type = 164; -pub const YARVINSN_trace_opt_send_without_block: ruby_vminsn_type = 165; -pub const YARVINSN_trace_objtostring: ruby_vminsn_type = 166; -pub const YARVINSN_trace_opt_ary_freeze: ruby_vminsn_type = 167; -pub const YARVINSN_trace_opt_str_freeze: ruby_vminsn_type = 168; -pub const YARVINSN_trace_opt_nil_p: ruby_vminsn_type = 169; -pub const YARVINSN_trace_opt_str_uminus: ruby_vminsn_type = 170; -pub const YARVINSN_trace_opt_newarray_send: ruby_vminsn_type = 171; -pub const YARVINSN_trace_invokesuper: ruby_vminsn_type = 172; -pub const YARVINSN_trace_invokesuperforward: ruby_vminsn_type = 173; -pub const YARVINSN_trace_invokeblock: ruby_vminsn_type = 174; -pub const YARVINSN_trace_leave: ruby_vminsn_type = 175; -pub const YARVINSN_trace_throw: ruby_vminsn_type = 176; -pub const YARVINSN_trace_jump: ruby_vminsn_type = 177; -pub const YARVINSN_trace_branchif: ruby_vminsn_type = 178; -pub const YARVINSN_trace_branchunless: ruby_vminsn_type = 179; -pub const YARVINSN_trace_branchnil: ruby_vminsn_type = 180; -pub const YARVINSN_trace_once: ruby_vminsn_type = 181; -pub const YARVINSN_trace_opt_case_dis: ruby_vminsn_type = 182; -pub const YARVINSN_trace_opt_plus: ruby_vminsn_type = 183; -pub const YARVINSN_trace_opt_minus: ruby_vminsn_type = 184; -pub const YARVINSN_trace_opt_mult: ruby_vminsn_type = 185; -pub const YARVINSN_trace_opt_div: ruby_vminsn_type = 186; -pub const YARVINSN_trace_opt_mod: ruby_vminsn_type = 187; -pub const YARVINSN_trace_opt_eq: ruby_vminsn_type = 188; -pub const YARVINSN_trace_opt_neq: ruby_vminsn_type = 189; -pub const YARVINSN_trace_opt_lt: ruby_vminsn_type = 190; -pub const YARVINSN_trace_opt_le: ruby_vminsn_type = 191; -pub const YARVINSN_trace_opt_gt: ruby_vminsn_type = 192; -pub const YARVINSN_trace_opt_ge: ruby_vminsn_type = 193; -pub const YARVINSN_trace_opt_ltlt: ruby_vminsn_type = 194; -pub const YARVINSN_trace_opt_and: ruby_vminsn_type = 195; -pub const YARVINSN_trace_opt_or: ruby_vminsn_type = 196; -pub const YARVINSN_trace_opt_aref: ruby_vminsn_type = 197; -pub const YARVINSN_trace_opt_aset: ruby_vminsn_type = 198; -pub const YARVINSN_trace_opt_aset_with: ruby_vminsn_type = 199; -pub const YARVINSN_trace_opt_aref_with: ruby_vminsn_type = 200; -pub const YARVINSN_trace_opt_length: ruby_vminsn_type = 201; -pub const YARVINSN_trace_opt_size: ruby_vminsn_type = 202; -pub const YARVINSN_trace_opt_empty_p: ruby_vminsn_type = 203; -pub const YARVINSN_trace_opt_succ: ruby_vminsn_type = 204; -pub const YARVINSN_trace_opt_not: ruby_vminsn_type = 205; -pub const YARVINSN_trace_opt_regexpmatch2: ruby_vminsn_type = 206; -pub const YARVINSN_trace_invokebuiltin: ruby_vminsn_type = 207; -pub const YARVINSN_trace_opt_invokebuiltin_delegate: ruby_vminsn_type = 208; -pub const YARVINSN_trace_opt_invokebuiltin_delegate_leave: ruby_vminsn_type = 209; -pub const YARVINSN_trace_getlocal_WC_0: ruby_vminsn_type = 210; -pub const YARVINSN_trace_getlocal_WC_1: ruby_vminsn_type = 211; -pub const YARVINSN_trace_setlocal_WC_0: ruby_vminsn_type = 212; -pub const YARVINSN_trace_setlocal_WC_1: ruby_vminsn_type = 213; -pub const YARVINSN_trace_putobject_INT2FIX_0_: ruby_vminsn_type = 214; -pub const YARVINSN_trace_putobject_INT2FIX_1_: ruby_vminsn_type = 215; -pub const VM_INSTRUCTION_SIZE: ruby_vminsn_type = 216; pub type ruby_vminsn_type = u32; pub type rb_iseq_callback = ::std::option::Option< unsafe extern "C" fn(arg1: *const rb_iseq_t, arg2: *mut ::std::os::raw::c_void), |