diff --git a/b/a b/b/a new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/compile.c b/compile.c index e46035a7e042d4..072427ba0c3421 100644 --- a/compile.c +++ b/compile.c @@ -2213,11 +2213,17 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor) struct rb_kwarg_call_data *cd_kw = &kw_calls[ISEQ_COMPILE_DATA(iseq)->ci_kw_index++]; cd_kw->ci_kw = *((struct rb_call_info_with_kwarg *)source_ci); cd = (struct rb_call_data *)cd_kw; + cd->cc.orig_argc = cd->ci.orig_argc; + cd->cc.flag = cd->ci.flag; + cd->cc.mid = cd->ci.mid; assert(ISEQ_COMPILE_DATA(iseq)->ci_kw_index <= body->ci_kw_size); } else { cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++]; cd->ci = *source_ci; + cd->cc.orig_argc = cd->ci.orig_argc; + cd->cc.flag = cd->ci.flag; + cd->cc.mid = cd->ci.mid; assert(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size); } @@ -10320,6 +10326,9 @@ ibf_load_ci_entries(const struct ibf_load *load, calls[i].ci.mid = ibf_load_id(load, mid_index); calls[i].ci.flag = (unsigned int)ibf_load_small_value(load, &reading_pos); calls[i].ci.orig_argc = (int)ibf_load_small_value(load, &reading_pos); + calls[i].cc.flag = calls[i].ci.flag; + calls[i].cc.orig_argc = calls[i].ci.orig_argc; + calls[i].cc.mid = calls[i].ci.mid; } for (i = 0; i < ci_kw_size; i++) { @@ -10328,6 +10337,9 @@ ibf_load_ci_entries(const struct ibf_load *load, kw_calls[i].ci_kw.ci.mid = ibf_load_id(load, mid_index); kw_calls[i].ci_kw.ci.flag = (unsigned int)ibf_load_small_value(load, &reading_pos); kw_calls[i].ci_kw.ci.orig_argc = (int)ibf_load_small_value(load, &reading_pos); + kw_calls[i].cc.flag = kw_calls[i].ci_kw.ci.flag; + kw_calls[i].cc.orig_argc = kw_calls[i].ci_kw.ci.orig_argc; + kw_calls[i].cc.mid = kw_calls[i].ci_kw.ci.mid; int keyword_len = (int)ibf_load_small_value(load, &reading_pos); diff --git a/insns.def b/insns.def index bd1bffbe02d8d4..a4f09f877fe0bf 100644 --- a/insns.def +++ b/insns.def @@ -778,7 +778,7 @@ send // attr rb_snum_t sp_inc = sp_inc_of_sendish(&cd->ci); // attr rb_snum_t comptime_sp_inc = sp_inc_of_sendish(ci); { - VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), &cd->ci, blockiseq, false); + VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), &cd->cc, blockiseq, false); val = vm_sendish(ec, GET_CFP(), cd, bh, vm_search_method_wrap); if (val == Qundef) { @@ -884,7 +884,7 @@ invokesuper // attr rb_snum_t sp_inc = sp_inc_of_sendish(&cd->ci); // attr rb_snum_t comptime_sp_inc = sp_inc_of_sendish(ci); { - VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), &cd->ci, blockiseq, true); + VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), &cd->cc, blockiseq, true); val = vm_sendish(ec, GET_CFP(), cd, bh, vm_search_super_method); if (val == Qundef) { diff --git a/internal.h b/internal.h index 77101d0195a8de..572e0d30d993ad 100644 --- a/internal.h +++ b/internal.h @@ -2341,7 +2341,7 @@ struct rb_call_cache { (CACHELINE - sizeof(rb_serial_t) /* method_state */ - sizeof(struct rb_callable_method_entry_struct *) /* me */ - - sizeof(struct rb_callable_method_definition_struct *) /* def */ + - sizeof(ID) /* mid */ - sizeof(enum method_missing_reason) /* aux */ - sizeof(VALUE (*)( /* call */ struct rb_execution_context_struct *e, @@ -2353,13 +2353,15 @@ struct rb_call_cache { /* inline cache: values */ const struct rb_callable_method_entry_struct *me; - const struct rb_method_definition_struct *def; + ID mid; VALUE (*call)(struct rb_execution_context_struct *ec, struct rb_control_frame_struct *cfp, struct rb_calling_info *calling, struct rb_call_data *cd); - + /* cache call info argc and flags in the 4 byte cache line padding */ + unsigned short int orig_argc; + unsigned short int flag; union { unsigned int index; /* used by ivar */ enum method_missing_reason method_missing_reason; /* used by method_missing */ @@ -2369,8 +2371,8 @@ STATIC_ASSERT(cachelined, sizeof(struct rb_call_cache) <= CACHELINE); struct rb_call_info { /* fixed at compile time */ ID mid; - unsigned int flag; - int orig_argc; + unsigned short int flag; + unsigned short int orig_argc; }; struct rb_call_data { struct rb_call_cache cc; diff --git a/mjit_compile.c b/mjit_compile.c index f379a896a8782c..b985149552a272 100644 --- a/mjit_compile.c +++ b/mjit_compile.c @@ -100,7 +100,7 @@ fastpath_applied_iseq_p(const CALL_INFO ci, const CALL_CACHE cc, const rb_iseq_t return iseq != NULL && !(ci->flag & VM_CALL_KW_SPLAT) && rb_simple_iseq_p(iseq) // Top of vm_callee_setup_arg. In this case, opt_pc is 0. && ci->orig_argc == iseq->body->param.lead_num // exclude argument_arity_error (assumption: `calling->argc == ci->orig_argc` in send insns) - && vm_call_iseq_optimizable_p(ci, cc); // CC_SET_FASTPATH condition + && vm_call_iseq_optimizable_p(cc); // CC_SET_FASTPATH condition } static int diff --git a/tool/ruby_vm/views/_mjit_compile_send.erb b/tool/ruby_vm/views/_mjit_compile_send.erb index ec8eec5589c42a..0958af12429e3f 100644 --- a/tool/ruby_vm/views/_mjit_compile_send.erb +++ b/tool/ruby_vm/views/_mjit_compile_send.erb @@ -59,7 +59,7 @@ fprintf(f, " {\n"); fprintf(f, " struct rb_calling_info calling;\n"); % if insn.name == 'send' - fprintf(f, " calling.block_handler = vm_caller_setup_arg_block(ec, reg_cfp, (CALL_INFO)0x%"PRIxVALUE", (rb_iseq_t *)0x%"PRIxVALUE", FALSE);\n", (VALUE)ci, (VALUE)blockiseq); + fprintf(f, " calling.block_handler = vm_caller_setup_arg_block(ec, reg_cfp, (CALL_CACHE)0x%"PRIxVALUE", (rb_iseq_t *)0x%"PRIxVALUE", FALSE);\n", (VALUE)cc_copy, (VALUE)blockiseq); % else fprintf(f, " calling.block_handler = VM_BLOCK_HANDLER_NONE;\n"); % end diff --git a/vm_args.c b/vm_args.c index c6c111865ee20d..1f74d0ed2113ba 100644 --- a/vm_args.c +++ b/vm_args.c @@ -1191,9 +1191,9 @@ refine_sym_proc_call(RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)) static VALUE vm_caller_setup_arg_block(const rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, - const struct rb_call_info *ci, const rb_iseq_t *blockiseq, const int is_super) + const struct rb_call_cache *cc, const rb_iseq_t *blockiseq, const int is_super) { - if (ci->flag & VM_CALL_ARGS_BLOCKARG) { + if (cc->flag & VM_CALL_ARGS_BLOCKARG) { VALUE block_code = *(--reg_cfp->sp); if (NIL_P(block_code)) { diff --git a/vm_core.h b/vm_core.h index 4b1b9e43d02604..d4d95e74d045db 100644 --- a/vm_core.h +++ b/vm_core.h @@ -250,8 +250,8 @@ struct rb_call_info_with_kwarg { struct rb_calling_info { VALUE block_handler; VALUE recv; - int argc; - int kw_splat; + short int argc; + short int kw_splat; }; struct rb_kwarg_call_data { @@ -1095,6 +1095,7 @@ enum vm_call_flag_bits { VM_CALL_SUPER_bit, /* super */ VM_CALL_ZSUPER_bit, /* zsuper */ VM_CALL_OPT_SEND_bit, /* internal flag */ + VM_CALL_UNREFINED_bit, /* refined */ VM_CALL__END }; @@ -1110,6 +1111,7 @@ enum vm_call_flag_bits { #define VM_CALL_SUPER (0x01 << VM_CALL_SUPER_bit) #define VM_CALL_ZSUPER (0x01 << VM_CALL_ZSUPER_bit) #define VM_CALL_OPT_SEND (0x01 << VM_CALL_OPT_SEND_bit) +#define VM_CALL_UNREFINED (0x01 << VM_CALL_UNREFINED_bit) enum vm_special_object_type { VM_SPECIAL_OBJECT_VMCORE = 1, diff --git a/vm_eval.c b/vm_eval.c index b0179423d88728..3543219d14bdb0 100644 --- a/vm_eval.c +++ b/vm_eval.c @@ -47,15 +47,16 @@ rb_vm_call0(rb_execution_context_t *ec, VALUE recv, ID id, int argc, const VALUE { struct rb_calling_info calling = { Qundef, recv, argc, kw_splat, }; struct rb_call_info ci = { id, (kw_splat ? VM_CALL_KW_SPLAT : 0), argc, }; - struct rb_call_cache cc = { 0, { 0, }, me, me->def, vm_call_general, { 0, }, }; + struct rb_call_cache cc = { 0, { 0, }, me, id, vm_call_general, argc, ci.flag, { 0, }, }; struct rb_call_data cd = { cc, ci, }; + cc.flag = ci.flag; + if (LIKELY(me->def->type != VM_METHOD_TYPE_REFINED)) cc.flag |= VM_CALL_UNREFINED; return vm_call0_body(ec, &calling, &cd, argv); } static VALUE vm_call0_cfunc_with_frame(rb_execution_context_t* ec, struct rb_calling_info *calling, struct rb_call_data *cd, const VALUE *argv) { - const struct rb_call_info *ci = &cd->ci; const struct rb_call_cache *cc = &cd->cc; VALUE val; const rb_callable_method_entry_t *me = cc->me; @@ -63,7 +64,7 @@ vm_call0_cfunc_with_frame(rb_execution_context_t* ec, struct rb_calling_info *ca int len = cfunc->argc; VALUE recv = calling->recv; int argc = calling->argc; - ID mid = ci->mid; + ID mid = cc->mid; VALUE block_handler = calling->block_handler; int frame_flags = VM_FRAME_MAGIC_CFUNC | VM_FRAME_FLAG_CFRAME | VM_ENV_FLAG_LOCAL; @@ -109,7 +110,6 @@ vm_call0_cfunc(rb_execution_context_t *ec, struct rb_calling_info *calling, stru static VALUE vm_call0_body(rb_execution_context_t *ec, struct rb_calling_info *calling, struct rb_call_data *cd, const VALUE *argv) { - const struct rb_call_info *ci = &cd->ci; struct rb_call_cache *cc = &cd->cc; VALUE ret; @@ -180,15 +180,15 @@ vm_call0_body(rb_execution_context_t *ec, struct rb_calling_info *calling, struc } else if (cc->me->def->body.refined.orig_me) { cc->me = refined_method_callable_without_refinement(cc->me); - goto again; + goto again; } super_class = RCLASS_SUPER(super_class); - if (!super_class || !(cc->me = rb_callable_method_entry(super_class, ci->mid))) { - enum method_missing_reason ex = (type == VM_METHOD_TYPE_ZSUPER) ? MISSING_SUPER : 0; - ret = method_missing(calling->recv, ci->mid, calling->argc, argv, ex, calling->kw_splat); - goto success; + if (!super_class || !(cc->me = rb_callable_method_entry(super_class, cc->mid))) { + enum method_missing_reason ex = (type == VM_METHOD_TYPE_ZSUPER) ? MISSING_SUPER : 0; + ret = method_missing(calling->recv, cc->mid, calling->argc, argv, ex, calling->kw_splat); + goto success; } RUBY_VM_CHECK_INTS(ec); goto again; @@ -199,7 +199,7 @@ vm_call0_body(rb_execution_context_t *ec, struct rb_calling_info *calling, struc case VM_METHOD_TYPE_MISSING: { vm_passed_block_handler_set(ec, calling->block_handler); - return method_missing(calling->recv, ci->mid, calling->argc, + return method_missing(calling->recv, cc->mid, calling->argc, argv, MISSING_NOENTRY, calling->kw_splat); } case VM_METHOD_TYPE_OPTIMIZED: @@ -1006,10 +1006,9 @@ rb_funcallv_public_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int kw_sp VALUE rb_funcallv_with_cc(struct rb_call_data *cd, VALUE recv, ID mid, int argc, const VALUE *argv) { - const struct rb_call_info *ci = &cd->ci; struct rb_call_cache *cc = &cd->cc; - if (LIKELY(ci->mid == mid)) { + if (LIKELY(cc->mid == mid)) { vm_search_method(cd, recv); if (LIKELY(! UNDEFINED_METHOD_ENTRY_P(cc->me))) { diff --git a/vm_insnhelper.c b/vm_insnhelper.c index c8ea3f9b1bb6fd..410748c1b9c815 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -1430,10 +1430,9 @@ __attribute__((__artificial__)) #endif #endif static inline vm_call_handler -calccall(const struct rb_call_data *cd, const rb_callable_method_entry_t *me) +calccall(struct rb_call_data *cd, const rb_callable_method_entry_t *me) { - const struct rb_call_info *ci = &cd->ci; - const struct rb_call_cache *cc = &cd->cc; + struct rb_call_cache *cc = &cd->cc; if (UNLIKELY(!me)) { RB_DEBUG_COUNTER_INC(mc_miss_by_nome); @@ -1443,16 +1442,17 @@ calccall(const struct rb_call_data *cd, const rb_callable_method_entry_t *me) RB_DEBUG_COUNTER_INC(mc_miss_by_distinct); return vm_call_general; /* normal cases */ } - else if (UNLIKELY(cc->def != me->def)) { + else if (UNLIKELY(cc->flag & VM_CALL_UNREFINED && cc->me->def->type == VM_METHOD_TYPE_REFINED)) { RB_DEBUG_COUNTER_INC(mc_miss_by_refine); + cc->flag &= ~VM_CALL_UNREFINED; return vm_call_general; /* cc->me was refined elsewhere */ } /* "Calling a formerly-public method, which is now privatised, with an * explicit receiver" is the only situation we have to check here. A * formerly-private method now publicised is an absolutely safe thing. * Calling a private method without specifying a receiver is also safe. */ - else if ((METHOD_ENTRY_VISI(cc->me) != METHOD_VISI_PUBLIC) && - !(ci->flag & VM_CALL_FCALL)) { + else if (UNLIKELY((METHOD_ENTRY_VISI(cc->me) != METHOD_VISI_PUBLIC) && + !(cc->flag & VM_CALL_FCALL))) { RB_DEBUG_COUNTER_INC(mc_miss_by_visi); return vm_call_general; } @@ -1474,9 +1474,12 @@ rb_vm_search_method_slowpath(struct rb_call_data *cd, VALUE klass) GET_GLOBAL_METHOD_STATE(), { RCLASS_SERIAL(klass) }, me, - me ? me->def : NULL, + ci->mid, call, + ci->orig_argc, + ci->flag }; + if (LIKELY(me && me->def->type != VM_METHOD_TYPE_REFINED)) buf.flag |= VM_CALL_UNREFINED; if (call != vm_call_general) { for (int i = 0; i < numberof(cc->class_serial) - 1; i++) { buf.class_serial[i + 1] = cc->class_serial[i]; @@ -1498,6 +1501,8 @@ rb_vm_search_method_slowpath(struct rb_call_data *cd, VALUE klass) * rb_callable_method_entry_t *me; * rb_method_definition_struct *def; * vm_call_handler call; + * short int orig_argc; + * short int flag; * union { ... snip ... } aux; * }; * ``` @@ -1980,8 +1985,7 @@ CALLER_SETUP_ARG(struct rb_control_frame_struct *restrict cfp, static inline void CALLER_REMOVE_EMPTY_KW_SPLAT(struct rb_control_frame_struct *restrict cfp, - struct rb_calling_info *restrict calling, - const struct rb_call_info *restrict ci) + struct rb_calling_info *restrict calling) { if (UNLIKELY(calling->kw_splat)) { /* This removes the last Hash object if it is empty. @@ -2109,10 +2113,9 @@ vm_call_iseq_setup_kwparm_nokwarg(rb_execution_context_t *ec, rb_control_frame_t struct rb_calling_info *calling, struct rb_call_data *cd) { - const struct rb_call_info *MAYBE_UNUSED(ci) = &cd->ci; const struct rb_call_cache *cc = &cd->cc; - VM_ASSERT((ci->flag & VM_CALL_KWARG) == 0); + VM_ASSERT((cc->flag & VM_CALL_KWARG) == 0); RB_DEBUG_COUNTER_INC(ccf_iseq_kw2); const rb_iseq_t *iseq = def_iseq_ptr(cc->me->def); @@ -2141,23 +2144,23 @@ vm_callee_setup_arg(rb_execution_context_t *ec, struct rb_calling_info *calling, const struct rb_call_info *ci = &cd->ci; struct rb_call_cache *cc = &cd->cc; - if (LIKELY(!(ci->flag & VM_CALL_KW_SPLAT))) { + if (LIKELY(!(cc->flag & VM_CALL_KW_SPLAT))) { if (LIKELY(rb_simple_iseq_p(iseq))) { rb_control_frame_t *cfp = ec->cfp; CALLER_SETUP_ARG(cfp, calling, ci); - CALLER_REMOVE_EMPTY_KW_SPLAT(cfp, calling, ci); + CALLER_REMOVE_EMPTY_KW_SPLAT(cfp, calling); if (calling->argc != iseq->body->param.lead_num) { argument_arity_error(ec, iseq, calling->argc, iseq->body->param.lead_num, iseq->body->param.lead_num); } - CC_SET_FASTPATH(cc, vm_call_iseq_setup_func(ci, param_size, local_size), vm_call_iseq_optimizable_p(&cd->ci, &cd->cc)); + CC_SET_FASTPATH(cc, vm_call_iseq_setup_func(ci, param_size, local_size), vm_call_iseq_optimizable_p(&cd->cc)); return 0; } else if (rb_iseq_only_optparam_p(iseq)) { rb_control_frame_t *cfp = ec->cfp; CALLER_SETUP_ARG(cfp, calling, ci); - CALLER_REMOVE_EMPTY_KW_SPLAT(cfp, calling, ci); + CALLER_REMOVE_EMPTY_KW_SPLAT(cfp, calling); const int lead_num = iseq->body->param.lead_num; const int opt_num = iseq->body->param.opt_num; @@ -2168,14 +2171,14 @@ vm_callee_setup_arg(rb_execution_context_t *ec, struct rb_calling_info *calling, argument_arity_error(ec, iseq, argc, lead_num, lead_num + opt_num); } - if (LIKELY(!(ci->flag & VM_CALL_TAILCALL))) { + if (LIKELY(!(cc->flag & VM_CALL_TAILCALL))) { CC_SET_FASTPATH(cc, vm_call_iseq_setup_normal_opt_start, - !IS_ARGS_SPLAT(ci) && !IS_ARGS_KEYWORD(ci) && + !IS_ARGS_SPLAT(cc) && !IS_ARGS_KEYWORD(cc) && !(METHOD_ENTRY_VISI(cc->me) == METHOD_VISI_PROTECTED)); } else { CC_SET_FASTPATH(cc, vm_call_iseq_setup_tailcall_opt_start, - !IS_ARGS_SPLAT(ci) && !IS_ARGS_KEYWORD(ci) && + !IS_ARGS_SPLAT(cc) && !IS_ARGS_KEYWORD(cc) && !(METHOD_ENTRY_VISI(cc->me) == METHOD_VISI_PROTECTED)); } @@ -2186,12 +2189,12 @@ vm_callee_setup_arg(rb_execution_context_t *ec, struct rb_calling_info *calling, } return (int)iseq->body->param.opt_table[opt]; } - else if (rb_iseq_only_kwparam_p(iseq) && !IS_ARGS_SPLAT(ci)) { + else if (rb_iseq_only_kwparam_p(iseq) && !IS_ARGS_SPLAT(cc)) { const int lead_num = iseq->body->param.lead_num; const int argc = calling->argc; const struct rb_iseq_param_keyword *kw_param = iseq->body->param.keyword; - if (ci->flag & VM_CALL_KWARG) { + if (cc->flag & VM_CALL_KWARG) { const struct rb_call_info_kw_arg *kw_arg = ((struct rb_call_info_with_kwarg *)ci)->kw_arg; if (argc - kw_arg->keyword_len == lead_num) { @@ -2245,10 +2248,9 @@ static inline VALUE vm_call_iseq_setup_2(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling, struct rb_call_data *cd, int opt_pc, int param_size, int local_size) { - const struct rb_call_info *ci = &cd->ci; const struct rb_call_cache *cc = &cd->cc; - if (LIKELY(!(ci->flag & VM_CALL_TAILCALL))) { + if (LIKELY(!(cc->flag & VM_CALL_TAILCALL))) { return vm_call_iseq_setup_normal(ec, cfp, calling, cc->me, opt_pc, param_size, local_size); } else { @@ -2480,7 +2482,6 @@ vm_method_cfunc_entry(const rb_callable_method_entry_t *me) static VALUE vm_call_cfunc_with_frame(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling, struct rb_call_data *cd, int empty_kw_splat) { - const struct rb_call_info *ci = &cd->ci; const struct rb_call_cache *cc = &cd->cc; VALUE val; const rb_callable_method_entry_t *me = cc->me; @@ -2501,7 +2502,7 @@ vm_call_cfunc_with_frame(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp } RUBY_DTRACE_CMETHOD_ENTRY_HOOK(ec, me->owner, me->def->original_id); - EXEC_EVENT_HOOK(ec, RUBY_EVENT_C_CALL, recv, me->def->original_id, ci->mid, me->owner, Qundef); + EXEC_EVENT_HOOK(ec, RUBY_EVENT_C_CALL, recv, me->def->original_id, cc->mid, me->owner, Qundef); vm_push_frame(ec, NULL, frame_type, recv, block_handler, (VALUE)me, @@ -2516,7 +2517,7 @@ vm_call_cfunc_with_frame(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp rb_vm_pop_frame(ec); - EXEC_EVENT_HOOK(ec, RUBY_EVENT_C_RETURN, recv, me->def->original_id, ci->mid, me->owner, val); + EXEC_EVENT_HOOK(ec, RUBY_EVENT_C_RETURN, recv, me->def->original_id, cc->mid, me->owner, val); RUBY_DTRACE_CMETHOD_RETURN_HOOK(ec, me->owner, me->def->original_id); return val; @@ -2531,7 +2532,7 @@ vm_call_cfunc(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb CALLER_SETUP_ARG(reg_cfp, calling, ci); empty_kw_splat = calling->kw_splat; - CALLER_REMOVE_EMPTY_KW_SPLAT(reg_cfp, calling, ci); + CALLER_REMOVE_EMPTY_KW_SPLAT(reg_cfp, calling); if (empty_kw_splat && calling->kw_splat) { empty_kw_splat = 0; } @@ -2590,12 +2591,12 @@ vm_call_bmethod(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_c } static enum method_missing_reason -ci_missing_reason(const struct rb_call_info *ci) +cc_missing_reason(const struct rb_call_cache *cc) { enum method_missing_reason stat = MISSING_NOENTRY; - if (ci->flag & VM_CALL_VCALL) stat |= MISSING_VCALL; - if (ci->flag & VM_CALL_FCALL) stat |= MISSING_FCALL; - if (ci->flag & VM_CALL_SUPER) stat |= MISSING_SUPER; + if (cc->flag & VM_CALL_VCALL) stat |= MISSING_VCALL; + if (cc->flag & VM_CALL_FCALL) stat |= MISSING_FCALL; + if (cc->flag & VM_CALL_SUPER) stat |= MISSING_SUPER; return stat; } @@ -2644,7 +2645,7 @@ vm_call_opt_send(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct } TOPN(i) = rb_str_intern(sym); ci->mid = idMethodMissing; - ec->method_missing_reason = cc->aux.method_missing_reason = ci_missing_reason(ci); + ec->method_missing_reason = cc->aux.method_missing_reason = cc_missing_reason(cc); } else { /* shift arguments */ @@ -2656,7 +2657,8 @@ vm_call_opt_send(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct } cc->me = rb_callable_method_entry_with_refinements(CLASS_OF(calling->recv), ci->mid, NULL); - ci->flag = VM_CALL_FCALL | VM_CALL_OPT_SEND | (calling->kw_splat ? VM_CALL_KW_SPLAT : 0); + cc->flag = ci->flag = VM_CALL_FCALL | VM_CALL_OPT_SEND | (calling->kw_splat ? VM_CALL_KW_SPLAT : 0); + cc->mid = ci->mid; return vm_call_method(ec, reg_cfp, calling, (CALL_DATA)&cd); } @@ -2727,6 +2729,10 @@ vm_call_method_missing(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, cd.cc.me = rb_callable_method_entry_without_refinements(CLASS_OF(calling->recv), idMethodMissing, NULL); + // Cached on rb_call_cache to fit into the same cache line + cd.cc.flag = cd.ci.flag; + cd.cc.orig_argc = argc; + cd.cc.mid = cd.ci.mid; calling->argc = argc; @@ -2749,12 +2755,11 @@ vm_call_zsuper(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_ca { RB_DEBUG_COUNTER_INC(ccf_method_missing); - const struct rb_call_info *ci = &cd->ci; struct rb_call_cache *cc = &cd->cc; klass = RCLASS_SUPER(klass); - cc->me = klass ? rb_callable_method_entry(klass, ci->mid) : NULL; + cc->me = klass ? rb_callable_method_entry(klass, cc->mid) : NULL; - if (!cc->me) { + if (UNLIKELY(!cc->me)) { return vm_call_method_nome(ec, cfp, calling, cd); } if (cc->me->def->type == VM_METHOD_TYPE_REFINED && @@ -2929,20 +2934,20 @@ vm_call_method_each_type(rb_execution_context_t *ec, rb_control_frame_t *cfp, st rb_warn_keyword_to_last_hash(ec, calling, ci, NULL); } else { - CALLER_REMOVE_EMPTY_KW_SPLAT(cfp, calling, ci); + CALLER_REMOVE_EMPTY_KW_SPLAT(cfp, calling); } rb_check_arity(calling->argc, 1, 1); cc->aux.index = 0; - CC_SET_FASTPATH(cc, vm_call_attrset, !((ci->flag & VM_CALL_ARGS_SPLAT) || (ci->flag & VM_CALL_KWARG))); + CC_SET_FASTPATH(cc, vm_call_attrset, !((cc->flag & VM_CALL_ARGS_SPLAT) || (cc->flag & VM_CALL_KWARG))); return vm_call_attrset(ec, cfp, calling, cd); case VM_METHOD_TYPE_IVAR: CALLER_SETUP_ARG(cfp, calling, ci); - CALLER_REMOVE_EMPTY_KW_SPLAT(cfp, calling, ci); + CALLER_REMOVE_EMPTY_KW_SPLAT(cfp, calling); rb_check_arity(calling->argc, 0, 0); cc->aux.index = 0; - CC_SET_FASTPATH(cc, vm_call_ivar, !(ci->flag & VM_CALL_ARGS_SPLAT)); + CC_SET_FASTPATH(cc, vm_call_ivar, !(cc->flag & VM_CALL_ARGS_SPLAT)); return vm_call_ivar(ec, cfp, calling, cd); case VM_METHOD_TYPE_MISSING: @@ -2982,7 +2987,7 @@ vm_call_method_each_type(rb_execution_context_t *ec, rb_control_frame_t *cfp, st return vm_call_zsuper(ec, cfp, calling, cd, RCLASS_ORIGIN(cc->me->defined_class)); case VM_METHOD_TYPE_REFINED: - if (search_refined_method(ec, cfp, ci->mid, cc)) + if (search_refined_method(ec, cfp, cc->mid, cc)) return vm_call_method(ec, cfp, calling, cd); else return vm_call_method_nome(ec, cfp, calling, cd); @@ -2997,11 +3002,10 @@ static VALUE vm_call_method_nome(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling, struct rb_call_data *cd) { /* method missing */ - const struct rb_call_info *ci = &cd->ci; struct rb_call_cache *cc = &cd->cc; - const int stat = ci_missing_reason(ci); + const int stat = cc_missing_reason(cc); - if (ci->mid == idMethodMissing) { + if (cc->mid == idMethodMissing) { rb_control_frame_t *reg_cfp = cfp; VALUE *argv = STACK_ADDR_FROM_TOP(calling->argc); vm_raise_method_missing(ec, calling->argc, argv, calling->recv, stat); @@ -3016,7 +3020,6 @@ vm_call_method_nome(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct static inline VALUE vm_call_method(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling, struct rb_call_data *cd) { - const struct rb_call_info *ci = &cd->ci; struct rb_call_cache *cc = &cd->cc; VM_ASSERT(callable_method_entry_p(cc->me)); @@ -3027,9 +3030,9 @@ vm_call_method(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_ca return vm_call_method_each_type(ec, cfp, calling, cd); case METHOD_VISI_PRIVATE: - if (!(ci->flag & VM_CALL_FCALL)) { + if (!(cc->flag & VM_CALL_FCALL)) { enum method_missing_reason stat = MISSING_PRIVATE; - if (ci->flag & VM_CALL_VCALL) stat |= MISSING_VCALL; + if (cc->flag & VM_CALL_VCALL) stat |= MISSING_VCALL; cc->aux.method_missing_reason = stat; CC_SET_FASTPATH(cc, vm_call_method_missing, TRUE); @@ -3038,7 +3041,7 @@ vm_call_method(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_ca return vm_call_method_each_type(ec, cfp, calling, cd); case METHOD_VISI_PROTECTED: - if (!(ci->flag & VM_CALL_OPT_SEND)) { + if (!(cc->flag & VM_CALL_OPT_SEND)) { if (!rb_obj_is_kind_of(cfp->self, cc->me->defined_class)) { cc->aux.method_missing_reason = MISSING_PROTECTED; return vm_call_method_missing(ec, cfp, calling, cd); @@ -3046,7 +3049,7 @@ vm_call_method(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_ca else { /* caching method info to dummy cc */ VM_ASSERT(cc->me != NULL); - if (ci->flag & VM_CALL_KWARG) { + if (cc->flag & VM_CALL_KWARG) { struct rb_kwarg_call_data *kcd = (void *)cd; struct rb_kwarg_call_data cd_entry = *kcd; return vm_call_method_each_type(ec, cfp, calling, (void *)&cd_entry); @@ -3138,14 +3141,14 @@ vm_search_super_method(const rb_control_frame_t *reg_cfp, struct rb_call_data *c rb_obj_class(recv), m); } - if (me->def->type == VM_METHOD_TYPE_BMETHOD && (ci->flag & VM_CALL_ZSUPER)) { + if (me->def->type == VM_METHOD_TYPE_BMETHOD && (cc->flag & VM_CALL_ZSUPER)) { rb_raise(rb_eRuntimeError, "implicit argument passing of super from method defined" " by define_method() is not supported." " Specify all arguments explicitly."); } - ci->mid = me->def->original_id; + ci->mid = cc->mid = me->def->original_id; klass = vm_search_normal_superclass(me->defined_class); if (!klass) { @@ -3155,7 +3158,7 @@ vm_search_super_method(const rb_control_frame_t *reg_cfp, struct rb_call_data *c } else { /* TODO: use inline cache */ - cc->me = rb_callable_method_entry(klass, ci->mid); + cc->me = rb_callable_method_entry(klass, cc->mid); CC_SET_FASTPATH(cc, vm_call_super_method, TRUE); } } @@ -3267,7 +3270,7 @@ vm_callee_setup_block_arg(rb_execution_context_t *ec, struct rb_calling_info *ca rb_warn_keyword_to_last_hash(ec, calling, ci, iseq); } else { - CALLER_REMOVE_EMPTY_KW_SPLAT(cfp, calling, ci); + CALLER_REMOVE_EMPTY_KW_SPLAT(cfp, calling); } if (arg_setup_type == arg_setup_block && @@ -3368,7 +3371,7 @@ vm_invoke_ifunc_block(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, int argc; int kw_splat = calling->kw_splat; CALLER_SETUP_ARG(ec->cfp, calling, ci); - CALLER_REMOVE_EMPTY_KW_SPLAT(ec->cfp, calling, ci); + CALLER_REMOVE_EMPTY_KW_SPLAT(ec->cfp, calling); if (kw_splat && !calling->kw_splat) { kw_splat = 2; } @@ -4004,15 +4007,14 @@ vm_sendish( struct rb_call_data *cd, VALUE recv)) { - CALL_INFO ci = &cd->ci; - CALL_CACHE cc = &cd->cc; + const CALL_CACHE cc = &cd->cc; VALUE val; - int argc = ci->orig_argc; + int argc = cc->orig_argc; VALUE recv = TOPN(argc); struct rb_calling_info calling; calling.block_handler = block_handler; - calling.kw_splat = IS_ARGS_KW_SPLAT(ci) > 0; + calling.kw_splat = IS_ARGS_KW_SPLAT(cc) > 0; calling.recv = recv; calling.argc = argc; diff --git a/vm_insnhelper.h b/vm_insnhelper.h index 99555fd4ed1d71..ecbac1f71ed8b2 100644 --- a/vm_insnhelper.h +++ b/vm_insnhelper.h @@ -238,17 +238,18 @@ THROW_DATA_CONSUMED_SET(struct vm_throw_data *obj) } } -#define IS_ARGS_SPLAT(ci) ((ci)->flag & VM_CALL_ARGS_SPLAT) -#define IS_ARGS_KEYWORD(ci) ((ci)->flag & VM_CALL_KWARG) -#define IS_ARGS_KW_SPLAT(ci) ((ci)->flag & VM_CALL_KW_SPLAT) -#define IS_ARGS_KW_OR_KW_SPLAT(ci) ((ci)->flag & (VM_CALL_KWARG | VM_CALL_KW_SPLAT)) +// Macro argument can be either rb_call_info or rb_call_cache +#define IS_ARGS_SPLAT(c) ((c)->flag & VM_CALL_ARGS_SPLAT) +#define IS_ARGS_KEYWORD(c) ((c)->flag & VM_CALL_KWARG) +#define IS_ARGS_KW_SPLAT(c) ((c)->flag & VM_CALL_KW_SPLAT) +#define IS_ARGS_KW_OR_KW_SPLAT(c) ((c)->flag & (VM_CALL_KWARG | VM_CALL_KW_SPLAT)) /* If this returns true, an optimized function returned by `vm_call_iseq_setup_func` can be used as a fastpath. */ static bool -vm_call_iseq_optimizable_p(const struct rb_call_info *ci, const struct rb_call_cache *cc) +vm_call_iseq_optimizable_p( const struct rb_call_cache *cc) { - return !IS_ARGS_SPLAT(ci) && !IS_ARGS_KEYWORD(ci) && + return !IS_ARGS_SPLAT(cc) && !IS_ARGS_KEYWORD(cc) && !(METHOD_ENTRY_VISI(cc->me) == METHOD_VISI_PROTECTED); }