[前][次][番号順一覧][スレッド一覧]

ruby-changes:69240

From: Kevin <ko1@a...>
Date: Thu, 21 Oct 2021 08:24:20 +0900 (JST)
Subject: [ruby-changes:69240] 885bb972bf (master): Get kwargs working for all passed in the correct order

https://git.ruby-lang.org/ruby.git/commit/?id=885bb972bf

From 885bb972bfd80cb1c6ca4e5f521e823a1ae14c4a Mon Sep 17 00:00:00 2001
From: Kevin Newton <kddnewton@g...>
Date: Tue, 28 Sep 2021 14:45:35 -0400
Subject: Get kwargs working for all passed in the correct order

---
 yjit_codegen.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 61 insertions(+), 8 deletions(-)

diff --git a/yjit_codegen.c b/yjit_codegen.c
index e16a41f425..4e3bb353c6 100644
--- a/yjit_codegen.c
+++ b/yjit_codegen.c
@@ -3358,6 +3358,7 @@ gen_send_iseq(jitstate_t *jit, ctx_t *ctx, const struct rb_callinfo *ci, const r https://github.com/ruby/ruby/blob/trunk/yjit_codegen.c#L3358
     // Arity handling and optional parameter setup
     int num_params = iseq->body->param.size;
     uint32_t start_pc_offset = 0;
+
     if (iseq_lead_only_arg_setup_p(iseq)) {
         num_params = iseq->body->param.lead_num;
 
@@ -3387,9 +3388,58 @@ gen_send_iseq(jitstate_t *jit, ctx_t *ctx, const struct rb_callinfo *ci, const r https://github.com/ruby/ruby/blob/trunk/yjit_codegen.c#L3388
         start_pc_offset = (uint32_t)iseq->body->param.opt_table[opts_filled];
     }
     else if (rb_iseq_only_kwparam_p(iseq)) {
-        // vm_callee_setup_arg() has a fast path for this.
-        GEN_COUNTER_INC(cb, send_iseq_only_keywords);
-        return YJIT_CANT_COMPILE;
+        const int required_num = iseq->body->param.lead_num;
+
+        if (vm_ci_flag(ci) & VM_CALL_KWARG) {
+            // Calling a method with keyword parameters and specifying keyword
+            // arguments
+
+            const struct rb_callinfo_kwarg *kw_arg = vm_ci_kwarg(ci);
+
+            if (argc - kw_arg->keyword_len != required_num) {
+                // There is a mix of required and optional keyword arguments and
+                // not every one is specified
+
+                GEN_COUNTER_INC(cb, send_iseq_kwargs_req_and_opt_missing);
+                return YJIT_CANT_COMPILE;
+            }
+
+            const int req_key_num = iseq->body->param.keyword->required_num;
+            RUBY_ASSERT(req_key_num == kw_arg->keyword_len);
+
+            // callee expects keyword arguments
+            // caller is sending the correct number of positional arguments
+            // caller is sending keyword arguments
+
+            const ID *acceptable_keywords = iseq->body->param.keyword->table;
+            const VALUE * const ci_keywords = kw_arg->keywords;
+
+            // Check that the names of the given keyword arguments match up to
+            // the names of the keyword parameters and that they were passed in
+            // the exact same order
+            for (int i = 0; i < req_key_num; i++) {
+                if (ID2SYM(acceptable_keywords[i]) != ci_keywords[i]) {
+                    GEN_COUNTER_INC(cb, send_iseq_kwargs_need_shuffling);
+                    return YJIT_CANT_COMPILE;
+                }
+            }
+
+            // caller and callee specified all the same keywords in the exact
+            // same order
+
+            // Kwargs adds a special weird little local that specifies a bitmap
+            // that corresponds to the keyword arguments that are not passed.
+            num_params--;
+        } else if (argc == required_num) {
+            // Calling a method that accepts keyword parameters but not
+            // specifying any keyword arguments
+
+            GEN_COUNTER_INC(cb, send_iseq_kwargs_none_passed);
+            return YJIT_CANT_COMPILE;
+        } else {
+            GEN_COUNTER_INC(cb, send_iseq_complex_callee);
+            return YJIT_CANT_COMPILE;
+        }
     }
     else {
         // Only handle iseqs that have simple parameter setup.
@@ -3605,10 +3655,6 @@ gen_send_general(jitstate_t *jit, ctx_t *ctx, struct rb_call_data *cd, rb_iseq_t https://github.com/ruby/ruby/blob/trunk/yjit_codegen.c#L3655
         GEN_COUNTER_INC(cb, send_args_splat);
         return YJIT_CANT_COMPILE;
     }
-    if ((vm_ci_flag(ci) & VM_CALL_KWARG) != 0) {
-        GEN_COUNTER_INC(cb, send_keywords);
-        return YJIT_CANT_COMPILE;
-    }
     if ((vm_ci_flag(ci) & VM_CALL_ARGS_BLOCKARG) != 0) {
         GEN_COUNTER_INC(cb, send_block_arg);
         return YJIT_CANT_COMPILE;
@@ -3671,6 +3717,10 @@ gen_send_general(jitstate_t *jit, ctx_t *ctx, struct rb_call_data *cd, rb_iseq_t https://github.com/ruby/ruby/blob/trunk/yjit_codegen.c#L3717
           case VM_METHOD_TYPE_ISEQ:
             return gen_send_iseq(jit, ctx, ci, cme, block, argc);
           case VM_METHOD_TYPE_CFUNC:
+            if ((vm_ci_flag(ci) & VM_CALL_KWARG) != 0) {
+                GEN_COUNTER_INC(cb, send_cfunc_kwargs);
+                return YJIT_CANT_COMPILE;
+            }
             return gen_send_cfunc(jit, ctx, ci, cme, block, argc, &comptime_recv_klass);
           case VM_METHOD_TYPE_IVAR:
             if (argc != 0) {
@@ -3685,7 +3735,10 @@ gen_send_general(jitstate_t *jit, ctx_t *ctx, struct rb_call_data *cd, rb_iseq_t https://github.com/ruby/ruby/blob/trunk/yjit_codegen.c#L3735
                 return gen_get_ivar(jit, ctx, SEND_MAX_DEPTH, comptime_recv, ivar_name, recv_opnd, side_exit);
             }
           case VM_METHOD_TYPE_ATTRSET:
-            if (argc != 1 || !RB_TYPE_P(comptime_recv, T_OBJECT)) {
+            if ((vm_ci_flag(ci) & VM_CALL_KWARG) != 0) {
+                GEN_COUNTER_INC(cb, send_attrset_keywords);
+                return YJIT_CANT_COMPILE;
+            } else if (argc != 1 || !RB_TYPE_P(comptime_recv, T_OBJECT)) {
                 GEN_COUNTER_INC(cb, send_ivar_set_method);
                 return YJIT_CANT_COMPILE;
             }
-- 
cgit v1.2.1


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]