From fbaa5db44a3b0622e2755fd00e0519a603aa9bcb Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Thu, 15 Dec 2022 10:46:24 -0800 Subject: Use a BOP for Hash#default On a hash miss we need to call default if it is redefined in order to return the default value to be used. Previously we checked this with rb_method_basic_definition_p, which avoids the method call but requires a method lookup. This commit replaces the previous check with BASIC_OP_UNREDEFINED_P and a new BOP_DEFAULT. We still need to fall back to rb_method_basic_definition_p when called on a subclasss of hash. | |compare-ruby|built-ruby| |:---------------|-----------:|---------:| |hash_aref_miss | 2.692| 3.531| | | -| 1.31x| Co-authored-by: Daniel Colson Co-authored-by: "Ian C. Anderson" Co-authored-by: Jack McCracken --- defs/id.def | 1 + hash.c | 20 +++++++++++++++++--- internal/basic_operators.h | 1 + vm.c | 1 + yjit/src/cruby_bindings.inc.rs | 41 ++++++++++++++++++++++------------------- 5 files changed, 42 insertions(+), 22 deletions(-) diff --git a/defs/id.def b/defs/id.def index a3a383f532..ebf00506ea 100644 --- a/defs/id.def +++ b/defs/id.def @@ -76,6 +76,7 @@ firstline, predefined = __LINE__+1, %[\ "/*NULL*/" NULL empty? eql? + default respond_to? Respond_to respond_to_missing? Respond_to_missing diff --git a/hash.c b/hash.c index a577e77985..1923c63eb3 100644 --- a/hash.c +++ b/hash.c @@ -28,6 +28,7 @@ #include "internal.h" #include "internal/array.h" #include "internal/bignum.h" +#include "internal/basic_operators.h" #include "internal/class.h" #include "internal/cont.h" #include "internal/error.h" @@ -93,9 +94,11 @@ rb_hash_freeze(VALUE hash) VALUE rb_cHash; static VALUE envtbl; -static ID id_hash, id_default, id_flatten_bang; +static ID id_hash, id_flatten_bang; static ID id_hash_iter_lev; +#define id_default idDefault + VALUE rb_hash_set_ifnone(VALUE hash, VALUE ifnone) { @@ -2070,10 +2073,22 @@ call_default_proc(VALUE proc, VALUE hash, VALUE key) return rb_proc_call_with_block(proc, 2, args, Qnil); } +static bool +rb_hash_default_unredefined(VALUE hash) +{ + VALUE klass = RBASIC_CLASS(hash); + if (LIKELY(klass == rb_cHash)) { + return !!BASIC_OP_UNREDEFINED_P(BOP_DEFAULT, HASH_REDEFINED_OP_FLAG); + } + else { + return LIKELY(rb_method_basic_definition_p(klass, id_default)); + } +} + VALUE rb_hash_default_value(VALUE hash, VALUE key) { - if (LIKELY(rb_method_basic_definition_p(CLASS_OF(hash), id_default))) { + if (LIKELY(rb_hash_default_unredefined(hash))) { VALUE ifnone = RHASH_IFNONE(hash); if (!FL_TEST(hash, RHASH_PROC_DEFAULT)) return ifnone; if (UNDEF_P(key)) return Qnil; @@ -7164,7 +7179,6 @@ void Init_Hash(void) { id_hash = rb_intern_const("hash"); - id_default = rb_intern_const("default"); id_flatten_bang = rb_intern_const("flatten!"); id_hash_iter_lev = rb_make_internal_id(); diff --git a/internal/basic_operators.h b/internal/basic_operators.h index aa63c455b7..2cd9f50073 100644 --- a/internal/basic_operators.h +++ b/internal/basic_operators.h @@ -35,6 +35,7 @@ enum ruby_basic_operators { BOP_AND, BOP_OR, BOP_CMP, + BOP_DEFAULT, BOP_LAST_ }; diff --git a/vm.c b/vm.c index 8daed5d474..2821f58adb 100644 --- a/vm.c +++ b/vm.c @@ -2054,6 +2054,7 @@ vm_init_redefined_flag(void) OP(Or, OR), (C(Integer)); OP(NilP, NIL_P), (C(NilClass)); OP(Cmp, CMP), (C(Integer), C(Float), C(String)); + OP(Default, DEFAULT), (C(Hash)); #undef C #undef OP } diff --git a/yjit/src/cruby_bindings.inc.rs b/yjit/src/cruby_bindings.inc.rs index f20dc04966..759c4d0ec7 100644 --- a/yjit/src/cruby_bindings.inc.rs +++ b/yjit/src/cruby_bindings.inc.rs @@ -418,21 +418,22 @@ pub const tNUMPARAM_6: ruby_method_ids = 234; pub const tNUMPARAM_7: ruby_method_ids = 235; pub const tNUMPARAM_8: ruby_method_ids = 236; pub const tNUMPARAM_9: ruby_method_ids = 237; -pub const tTOKEN_LOCAL_END: ruby_method_ids = 238; -pub const tTOKEN_INSTANCE_BEGIN: ruby_method_ids = 237; -pub const tTOKEN_INSTANCE_END: ruby_method_ids = 238; -pub const tTOKEN_GLOBAL_BEGIN: ruby_method_ids = 237; -pub const tLASTLINE: ruby_method_ids = 238; -pub const tBACKREF: ruby_method_ids = 239; -pub const tERROR_INFO: ruby_method_ids = 240; -pub const tTOKEN_GLOBAL_END: ruby_method_ids = 241; -pub const tTOKEN_CONST_BEGIN: ruby_method_ids = 240; -pub const tTOKEN_CONST_END: ruby_method_ids = 241; -pub const tTOKEN_CLASS_BEGIN: ruby_method_ids = 240; -pub const tTOKEN_CLASS_END: ruby_method_ids = 241; -pub const tTOKEN_ATTRSET_BEGIN: ruby_method_ids = 240; -pub const tTOKEN_ATTRSET_END: ruby_method_ids = 241; -pub const tNEXT_ID: ruby_method_ids = 241; +pub const tDefault: ruby_method_ids = 238; +pub const tTOKEN_LOCAL_END: ruby_method_ids = 239; +pub const tTOKEN_INSTANCE_BEGIN: ruby_method_ids = 238; +pub const tTOKEN_INSTANCE_END: ruby_method_ids = 239; +pub const tTOKEN_GLOBAL_BEGIN: ruby_method_ids = 238; +pub const tLASTLINE: ruby_method_ids = 239; +pub const tBACKREF: ruby_method_ids = 240; +pub const tERROR_INFO: ruby_method_ids = 241; +pub const tTOKEN_GLOBAL_END: ruby_method_ids = 242; +pub const tTOKEN_CONST_BEGIN: ruby_method_ids = 241; +pub const tTOKEN_CONST_END: ruby_method_ids = 242; +pub const tTOKEN_CLASS_BEGIN: ruby_method_ids = 241; +pub const tTOKEN_CLASS_END: ruby_method_ids = 242; +pub const tTOKEN_ATTRSET_BEGIN: ruby_method_ids = 241; +pub const tTOKEN_ATTRSET_END: ruby_method_ids = 242; +pub const tNEXT_ID: ruby_method_ids = 242; pub const idMax: ruby_method_ids = 2721; pub const idMin: ruby_method_ids = 2737; pub const idFreeze: ruby_method_ids = 2753; @@ -501,9 +502,10 @@ pub const idNUMPARAM_6: ruby_method_ids = 3745; pub const idNUMPARAM_7: ruby_method_ids = 3761; pub const idNUMPARAM_8: ruby_method_ids = 3777; pub const idNUMPARAM_9: ruby_method_ids = 3793; -pub const idLASTLINE: ruby_method_ids = 3815; -pub const idBACKREF: ruby_method_ids = 3831; -pub const idERROR_INFO: ruby_method_ids = 3847; +pub const idDefault: ruby_method_ids = 3809; +pub const idLASTLINE: ruby_method_ids = 3831; +pub const idBACKREF: ruby_method_ids = 3847; +pub const idERROR_INFO: ruby_method_ids = 3863; pub const tLAST_OP_ID: ruby_method_ids = 169; pub const idLAST_OP_ID: ruby_method_ids = 10; pub type ruby_method_ids = u32; @@ -537,7 +539,8 @@ pub const BOP_CALL: ruby_basic_operators = 26; pub const BOP_AND: ruby_basic_operators = 27; pub const BOP_OR: ruby_basic_operators = 28; pub const BOP_CMP: ruby_basic_operators = 29; -pub const BOP_LAST_: ruby_basic_operators = 30; +pub const BOP_DEFAULT: ruby_basic_operators = 30; +pub const BOP_LAST_: ruby_basic_operators = 31; pub type ruby_basic_operators = u32; pub type rb_serial_t = ::std::os::raw::c_ulonglong; pub const imemo_env: imemo_type = 0; -- cgit v1.2.1