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

ruby-changes:57577

From: Jeremy <ko1@a...>
Date: Fri, 6 Sep 2019 09:51:00 +0900 (JST)
Subject: [ruby-changes:57577] 7fc874bf4c (master): Add rb_funcall_with_block_kw

https://git.ruby-lang.org/ruby.git/commit/?id=7fc874bf4c

From 7fc874bf4cbdd87b3d6fe05dc5959175f3fe94b8 Mon Sep 17 00:00:00 2001
From: Jeremy Evans <code@j...>
Date: Tue, 3 Sep 2019 14:49:03 -0700
Subject: Add rb_funcall_with_block_kw

This is needed for C functions to call methods with keyword arguments.
This is a copy of rb_funcall_with_block with an extra argument for
the keyword flag.

There isn't a clean way to implement this that doesn't involve
changing a lot of function signatures, because rb_call doesn't
support a way to mark that the call has keyword arguments.  So hack
this in using a CALL_PUBLIC_KW call_type, which we switch for
CALL_PUBLIC later in the call stack.

We do need to modify rm_vm_call0 to take an argument for whether
keyword arguments are used, since the call_type is no longer
available at that point.  Use the passed in value to set the
appropriate keyword flag in both calling and ci_entry.

diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h
index 947b3d4..893bd2b 100644
--- a/include/ruby/ruby.h
+++ b/include/ruby/ruby.h
@@ -1892,6 +1892,7 @@ VALUE rb_funcallv_public(VALUE, ID, int, const VALUE*); https://github.com/ruby/ruby/blob/trunk/include/ruby/ruby.h#L1892
 #define rb_funcall3 rb_funcallv_public
 VALUE rb_funcall_passing_block(VALUE, ID, int, const VALUE*);
 VALUE rb_funcall_with_block(VALUE, ID, int, const VALUE*, VALUE);
+VALUE rb_funcall_with_block_kw(VALUE, ID, int, const VALUE*, VALUE, int);
 int rb_scan_args(int, const VALUE*, const char*, ...);
 VALUE rb_call_super(int, const VALUE*);
 VALUE rb_current_receiver(void);
diff --git a/vm_args.c b/vm_args.c
index 17eee5e..a80100e 100644
--- a/vm_args.c
+++ b/vm_args.c
@@ -996,7 +996,7 @@ vm_to_proc(VALUE proc) https://github.com/ruby/ruby/blob/trunk/vm_args.c#L996
 	    rb_callable_method_entry_with_refinements(CLASS_OF(proc), idTo_proc, NULL);
 
 	if (me) {
-            b = rb_vm_call0(GET_EC(), proc, idTo_proc, 0, NULL, me);
+            b = rb_vm_call0(GET_EC(), proc, idTo_proc, 0, NULL, me, VM_NO_KEYWORDS);
 	}
 	else {
 	    /* NOTE: calling method_missing */
@@ -1047,7 +1047,7 @@ refine_sym_proc_call(RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)) https://github.com/ruby/ruby/blob/trunk/vm_args.c#L1047
     if (!me) {
 	return method_missing(obj, mid, argc, argv, MISSING_NOENTRY);
     }
-    return rb_vm_call0(ec, obj, mid, argc, argv, me);
+    return rb_vm_call0(ec, obj, mid, argc, argv, me, VM_NO_KEYWORDS);
 }
 
 static VALUE
diff --git a/vm_eval.c b/vm_eval.c
index e826661..4a304e3 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -32,6 +32,7 @@ typedef enum call_type { https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L32
     CALL_PUBLIC,
     CALL_FCALL,
     CALL_VCALL,
+    CALL_PUBLIC_KW,
     CALL_TYPE_MAX
 } call_type;
 
@@ -41,7 +42,7 @@ static VALUE vm_call0_body(rb_execution_context_t* ec, struct rb_calling_info *c https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L42
 #ifndef MJIT_HEADER
 
 MJIT_FUNC_EXPORTED VALUE
-rb_vm_call0(rb_execution_context_t *ec, VALUE recv, ID id, int argc, const VALUE *argv, const rb_callable_method_entry_t *me)
+rb_vm_call0(rb_execution_context_t *ec, VALUE recv, ID id, int argc, const VALUE *argv, const rb_callable_method_entry_t *me, int kw_splat)
 {
     struct rb_calling_info calling_entry, *calling;
     struct rb_call_info ci_entry;
@@ -49,14 +50,14 @@ rb_vm_call0(rb_execution_context_t *ec, VALUE recv, ID id, int argc, const VALUE https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L50
 
     calling = &calling_entry;
 
-    ci_entry.flag = 0;
+    ci_entry.flag = kw_splat ? VM_CALL_KW_SPLAT : 0;
     ci_entry.mid = id;
 
     cc_entry.me = me;
 
     calling->recv = recv;
     calling->argc = argc;
-    calling->kw_splat = 0;
+    calling->kw_splat = kw_splat;
 
     return vm_call0_body(ec, calling, &ci_entry, &cc_entry, argv);
 }
@@ -206,7 +207,7 @@ vm_call0_body(rb_execution_context_t *ec, struct rb_calling_info *calling, const https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L207
 VALUE
 rb_vm_call(rb_execution_context_t *ec, VALUE recv, VALUE id, int argc, const VALUE *argv, const rb_callable_method_entry_t *me)
 {
-    return rb_vm_call0(ec, recv, id, argc, argv, me);
+    return rb_vm_call0(ec, recv, id, argc, argv, me, VM_NO_KEYWORDS);
 }
 
 static inline VALUE
@@ -231,7 +232,7 @@ vm_call_super(rb_execution_context_t *ec, int argc, const VALUE *argv) https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L232
 	return method_missing(recv, id, argc, argv, MISSING_SUPER);
     }
     else {
-        return rb_vm_call0(ec, recv, id, argc, argv, me);
+        return rb_vm_call0(ec, recv, id, argc, argv, me, VM_NO_KEYWORDS);
     }
 }
 
@@ -290,10 +291,17 @@ static inline enum method_missing_reason rb_method_call_status(rb_execution_cont https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L291
 static inline VALUE
 rb_call0(rb_execution_context_t *ec,
 	 VALUE recv, ID mid, int argc, const VALUE *argv,
-	 call_type scope, VALUE self)
+         call_type call_scope, VALUE self)
 {
     const rb_callable_method_entry_t *me;
     enum method_missing_reason call_status;
+    call_type scope = call_scope;
+    int kw_splat = VM_NO_KEYWORDS;
+
+    if (scope == CALL_PUBLIC_KW) {
+        scope = CALL_PUBLIC;
+        kw_splat = 1;
+    }
 
     if (scope == CALL_PUBLIC) {
         me = rb_callable_method_entry_with_refinements(CLASS_OF(recv), mid, NULL);
@@ -307,7 +315,7 @@ rb_call0(rb_execution_context_t *ec, https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L315
 	return method_missing(recv, mid, argc, argv, call_status);
     }
     stack_check(ec);
-    return rb_vm_call0(ec, recv, mid, argc, argv, me);
+    return rb_vm_call0(ec, recv, mid, argc, argv, me, kw_splat);
 }
 
 struct rescue_funcall_args {
@@ -434,7 +442,7 @@ rb_check_funcall_default(VALUE recv, ID mid, int argc, const VALUE *argv, VALUE https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L442
 	return ret;
     }
     stack_check(ec);
-    return rb_vm_call0(ec, recv, mid, argc, argv, me);
+    return rb_vm_call0(ec, recv, mid, argc, argv, me, VM_NO_KEYWORDS);
 }
 
 VALUE
@@ -460,7 +468,7 @@ rb_check_funcall_with_hook(VALUE recv, ID mid, int argc, const VALUE *argv, https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L468
     }
     stack_check(ec);
     (*hook)(TRUE, recv, mid, argc, argv, arg);
-    return rb_vm_call0(ec, recv, mid, argc, argv, me);
+    return rb_vm_call0(ec, recv, mid, argc, argv, me, VM_NO_KEYWORDS);
 }
 
 const char *
@@ -766,7 +774,7 @@ method_missing(VALUE obj, ID id, int argc, const VALUE *argv, enum method_missin https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L774
     me = rb_callable_method_entry(klass, idMethodMissing);
     if (!me || METHOD_ENTRY_BASIC(me)) goto missing;
     vm_passed_block_handler_set(ec, block_handler);
-    result = rb_vm_call0(ec, obj, idMethodMissing, argc, argv, me);
+    result = rb_vm_call0(ec, obj, idMethodMissing, argc, argv, me, VM_NO_KEYWORDS);
     if (work) ALLOCV_END(work);
     return result;
 }
@@ -884,7 +892,7 @@ rb_funcallv_with_cc(struct rb_call_cache_and_mid *cc, VALUE recv, ID mid, int ar https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L892
         vm_search_method(&ci, &cc->cc, recv);
 
         if (LIKELY(! UNDEFINED_METHOD_ENTRY_P(cc->cc.me))) {
-            return rb_vm_call0(GET_EC(), recv, mid, argc, argv, cc->cc.me);
+            return rb_vm_call0(GET_EC(), recv, mid, argc, argv, cc->cc.me, VM_NO_KEYWORDS);
         }
     }
 
@@ -909,6 +917,16 @@ rb_funcall_with_block(VALUE recv, ID mid, int argc, const VALUE *argv, VALUE pas https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L917
     return rb_call(recv, mid, argc, argv, CALL_PUBLIC);
 }
 
+VALUE
+rb_funcall_with_block_kw(VALUE recv, ID mid, int argc, const VALUE *argv, VALUE passed_procval, int kw_splat)
+{
+    if (!NIL_P(passed_procval)) {
+        vm_passed_block_handler_set(GET_EC(), passed_procval);
+    }
+
+    return rb_call(recv, mid, argc, argv, kw_splat ? CALL_PUBLIC_KW : CALL_PUBLIC);
+}
+
 static VALUE *
 current_vm_stack_arg(const rb_execution_context_t *ec, const VALUE *argv)
 {
@@ -1601,7 +1619,7 @@ yield_under(VALUE under, VALUE self, int argc, const VALUE *argv) https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L1619
 	    goto again;
 	  case block_handler_type_symbol:
 	    return rb_sym_proc_call(SYM2ID(VM_BH_TO_SYMBOL(block_handler)),
-				    argc, argv, VM_BLOCK_HANDLER_NONE);
+                                    argc, argv, VM_NO_KEYWORDS, VM_BLOCK_HANDLER_NONE);
 	}
 
 	new_captured.self = self;
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 2d10b58..de5a192 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -1576,7 +1576,7 @@ rb_eql_opt(VALUE obj1, VALUE obj2) https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L1576
     return opt_eql_func(obj1, obj2, &ci, &cc);
 }
 
-extern VALUE rb_vm_call0(rb_execution_context_t *ec, VALUE, ID, int, const VALUE*, const rb_callable_method_entry_t *);
+extern VALUE rb_vm_call0(rb_execution_context_t *ec, VALUE, ID, int, const VALUE*, const rb_callable_method_entry_t *, int kw_splat);
 
 static VALUE
 check_match(rb_execution_context_t *ec, VALUE pattern, VALUE target, enum vm_check_match_type type)
@@ -1593,7 +1593,7 @@ check_match(rb_execution_context_t *ec, VALUE pattern, VALUE target, enum vm_che https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L1593
 	const rb_callable_method_entry_t *me =
 	    rb_callable_method_entry_with_refinements(CLASS_OF(pattern), idEqq, NULL);
 	if (me) {
-            return rb_vm_call0(ec, pattern, idEqq, 1, &target, me);
+            return rb_vm_call0(ec, pattern, idEqq, 1, &target, me, VM_NO_KEYWORDS);
 	}
 	else {
 	    /* fallback to funcall (e.g. method_missing) */
diff --git a/vm_method.c b/vm_method.c
index cd91cad..7421bc9 100644
--- a/vm_method.c
+++ b/vm_method.c
@@ -1921,7 +1921,7 @@ call_method_entry(rb_execution_context_t *ec, VALUE defined_class, VALUE obj, ID https://github.com/ruby/ruby/blob/trunk/vm_method.c#L1921
     const rb_callable_method_entry_t *cme =
 	prepare_callable_method_entr (... truncated)

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

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