mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
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.
This commit is contained in:
parent
e3cb3e11af
commit
7fc874bf4c
5 changed files with 36 additions and 17 deletions
|
@ -1892,6 +1892,7 @@ VALUE rb_funcallv_public(VALUE, ID, int, const VALUE*);
|
||||||
#define rb_funcall3 rb_funcallv_public
|
#define rb_funcall3 rb_funcallv_public
|
||||||
VALUE rb_funcall_passing_block(VALUE, ID, int, const VALUE*);
|
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(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*, ...);
|
int rb_scan_args(int, const VALUE*, const char*, ...);
|
||||||
VALUE rb_call_super(int, const VALUE*);
|
VALUE rb_call_super(int, const VALUE*);
|
||||||
VALUE rb_current_receiver(void);
|
VALUE rb_current_receiver(void);
|
||||||
|
|
|
@ -996,7 +996,7 @@ vm_to_proc(VALUE proc)
|
||||||
rb_callable_method_entry_with_refinements(CLASS_OF(proc), idTo_proc, NULL);
|
rb_callable_method_entry_with_refinements(CLASS_OF(proc), idTo_proc, NULL);
|
||||||
|
|
||||||
if (me) {
|
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 {
|
else {
|
||||||
/* NOTE: calling method_missing */
|
/* NOTE: calling method_missing */
|
||||||
|
@ -1047,7 +1047,7 @@ refine_sym_proc_call(RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg))
|
||||||
if (!me) {
|
if (!me) {
|
||||||
return method_missing(obj, mid, argc, argv, MISSING_NOENTRY);
|
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
|
static VALUE
|
||||||
|
|
42
vm_eval.c
42
vm_eval.c
|
@ -32,6 +32,7 @@ typedef enum call_type {
|
||||||
CALL_PUBLIC,
|
CALL_PUBLIC,
|
||||||
CALL_FCALL,
|
CALL_FCALL,
|
||||||
CALL_VCALL,
|
CALL_VCALL,
|
||||||
|
CALL_PUBLIC_KW,
|
||||||
CALL_TYPE_MAX
|
CALL_TYPE_MAX
|
||||||
} call_type;
|
} call_type;
|
||||||
|
|
||||||
|
@ -41,7 +42,7 @@ static VALUE vm_call0_body(rb_execution_context_t* ec, struct rb_calling_info *c
|
||||||
#ifndef MJIT_HEADER
|
#ifndef MJIT_HEADER
|
||||||
|
|
||||||
MJIT_FUNC_EXPORTED VALUE
|
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_calling_info calling_entry, *calling;
|
||||||
struct rb_call_info ci_entry;
|
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
|
||||||
|
|
||||||
calling = &calling_entry;
|
calling = &calling_entry;
|
||||||
|
|
||||||
ci_entry.flag = 0;
|
ci_entry.flag = kw_splat ? VM_CALL_KW_SPLAT : 0;
|
||||||
ci_entry.mid = id;
|
ci_entry.mid = id;
|
||||||
|
|
||||||
cc_entry.me = me;
|
cc_entry.me = me;
|
||||||
|
|
||||||
calling->recv = recv;
|
calling->recv = recv;
|
||||||
calling->argc = argc;
|
calling->argc = argc;
|
||||||
calling->kw_splat = 0;
|
calling->kw_splat = kw_splat;
|
||||||
|
|
||||||
return vm_call0_body(ec, calling, &ci_entry, &cc_entry, argv);
|
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
|
||||||
VALUE
|
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)
|
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
|
static inline VALUE
|
||||||
|
@ -231,7 +232,7 @@ vm_call_super(rb_execution_context_t *ec, int argc, const VALUE *argv)
|
||||||
return method_missing(recv, id, argc, argv, MISSING_SUPER);
|
return method_missing(recv, id, argc, argv, MISSING_SUPER);
|
||||||
}
|
}
|
||||||
else {
|
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
|
||||||
static inline VALUE
|
static inline VALUE
|
||||||
rb_call0(rb_execution_context_t *ec,
|
rb_call0(rb_execution_context_t *ec,
|
||||||
VALUE recv, ID mid, int argc, const VALUE *argv,
|
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;
|
const rb_callable_method_entry_t *me;
|
||||||
enum method_missing_reason call_status;
|
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) {
|
if (scope == CALL_PUBLIC) {
|
||||||
me = rb_callable_method_entry_with_refinements(CLASS_OF(recv), mid, NULL);
|
me = rb_callable_method_entry_with_refinements(CLASS_OF(recv), mid, NULL);
|
||||||
|
@ -307,7 +315,7 @@ rb_call0(rb_execution_context_t *ec,
|
||||||
return method_missing(recv, mid, argc, argv, call_status);
|
return method_missing(recv, mid, argc, argv, call_status);
|
||||||
}
|
}
|
||||||
stack_check(ec);
|
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 {
|
struct rescue_funcall_args {
|
||||||
|
@ -434,7 +442,7 @@ rb_check_funcall_default(VALUE recv, ID mid, int argc, const VALUE *argv, VALUE
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
stack_check(ec);
|
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
|
VALUE
|
||||||
|
@ -460,7 +468,7 @@ rb_check_funcall_with_hook(VALUE recv, ID mid, int argc, const VALUE *argv,
|
||||||
}
|
}
|
||||||
stack_check(ec);
|
stack_check(ec);
|
||||||
(*hook)(TRUE, recv, mid, argc, argv, arg);
|
(*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 *
|
const char *
|
||||||
|
@ -766,7 +774,7 @@ method_missing(VALUE obj, ID id, int argc, const VALUE *argv, enum method_missin
|
||||||
me = rb_callable_method_entry(klass, idMethodMissing);
|
me = rb_callable_method_entry(klass, idMethodMissing);
|
||||||
if (!me || METHOD_ENTRY_BASIC(me)) goto missing;
|
if (!me || METHOD_ENTRY_BASIC(me)) goto missing;
|
||||||
vm_passed_block_handler_set(ec, block_handler);
|
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);
|
if (work) ALLOCV_END(work);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -884,7 +892,7 @@ rb_funcallv_with_cc(struct rb_call_cache_and_mid *cc, VALUE recv, ID mid, int ar
|
||||||
vm_search_method(&ci, &cc->cc, recv);
|
vm_search_method(&ci, &cc->cc, recv);
|
||||||
|
|
||||||
if (LIKELY(! UNDEFINED_METHOD_ENTRY_P(cc->cc.me))) {
|
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
|
||||||
return rb_call(recv, mid, argc, argv, CALL_PUBLIC);
|
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 *
|
static VALUE *
|
||||||
current_vm_stack_arg(const rb_execution_context_t *ec, const VALUE *argv)
|
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)
|
||||||
goto again;
|
goto again;
|
||||||
case block_handler_type_symbol:
|
case block_handler_type_symbol:
|
||||||
return rb_sym_proc_call(SYM2ID(VM_BH_TO_SYMBOL(block_handler)),
|
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;
|
new_captured.self = self;
|
||||||
|
|
|
@ -1576,7 +1576,7 @@ rb_eql_opt(VALUE obj1, VALUE obj2)
|
||||||
return opt_eql_func(obj1, obj2, &ci, &cc);
|
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
|
static VALUE
|
||||||
check_match(rb_execution_context_t *ec, VALUE pattern, VALUE target, enum vm_check_match_type type)
|
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
|
||||||
const rb_callable_method_entry_t *me =
|
const rb_callable_method_entry_t *me =
|
||||||
rb_callable_method_entry_with_refinements(CLASS_OF(pattern), idEqq, NULL);
|
rb_callable_method_entry_with_refinements(CLASS_OF(pattern), idEqq, NULL);
|
||||||
if (me) {
|
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 {
|
else {
|
||||||
/* fallback to funcall (e.g. method_missing) */
|
/* fallback to funcall (e.g. method_missing) */
|
||||||
|
|
|
@ -1921,7 +1921,7 @@ call_method_entry(rb_execution_context_t *ec, VALUE defined_class, VALUE obj, ID
|
||||||
const rb_callable_method_entry_t *cme =
|
const rb_callable_method_entry_t *cme =
|
||||||
prepare_callable_method_entry(defined_class, id, me);
|
prepare_callable_method_entry(defined_class, id, me);
|
||||||
VALUE passed_block_handler = vm_passed_block_handler(ec);
|
VALUE passed_block_handler = vm_passed_block_handler(ec);
|
||||||
VALUE result = rb_vm_call0(ec, obj, id, argc, argv, cme);
|
VALUE result = rb_vm_call0(ec, obj, id, argc, argv, cme, VM_NO_KEYWORDS);
|
||||||
vm_passed_block_handler_set(ec, passed_block_handler);
|
vm_passed_block_handler_set(ec, passed_block_handler);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue