Add rb_block_call2, a flexible variant of rb_block_call

This function accepts flags:

RB_NO_KEYWORDS, RB_PASS_KEYWORDS, RB_PASS_CALLED_KEYWORDS:
Works as the same as rb_block_call_kw.

RB_BLOCK_NO_USE_PACKED_ARGS:
The given block ("bl_proc") does not use "yielded_arg" of rb_block_call_func_t.
Instead, the block accesses the yielded arguments via "argc" and "argv".
This flag allows the called method to yield arguments without allocating an Array.
This commit is contained in:
Yusuke Endoh 2024-07-09 18:27:02 +09:00
Родитель 77b12a8aaf
Коммит 114e32b357
5 изменённых файлов: 41 добавлений и 1 удалений

Просмотреть файл

@ -75,7 +75,7 @@
* Pass keywords if current method is called with keywords, useful for argument
* delegation
*/
#define RB_PASS_CALLED_KEYWORDS rb_keyword_given_p()
#define RB_PASS_CALLED_KEYWORDS !!rb_keyword_given_p()
/** @} */

Просмотреть файл

@ -87,6 +87,7 @@ struct vm_ifunc {
const void *data;
struct vm_ifunc_argc argc;
};
#define IFUNC_YIELD_OPTIMIZABLE IMEMO_FL_USER0
struct rb_imemo_tmpbuf_struct {
VALUE flags;

Просмотреть файл

@ -77,6 +77,8 @@ VALUE rb_lambda_call(VALUE obj, ID mid, int argc, const VALUE *argv,
rb_block_call_func_t bl_proc, int min_argc, int max_argc,
VALUE data2);
void rb_check_stack_overflow(void);
#define RB_BLOCK_NO_USE_PACKED_ARGS 2
VALUE rb_block_call2(VALUE obj, ID mid, int argc, const VALUE *argv, rb_block_call_func_t bl_proc, VALUE data2, long flags);
#if USE_YJIT
/* vm_exec.c */

6
proc.c
Просмотреть файл

@ -1159,6 +1159,12 @@ rb_block_pair_yield_optimizable(void)
return min > 1;
}
case block_handler_type_ifunc:
{
const struct vm_ifunc *ifunc = block.as.captured.code.ifunc;
if (ifunc->flags & IFUNC_YIELD_OPTIMIZABLE) return 1;
}
default:
return min > 1;
}

Просмотреть файл

@ -1558,6 +1558,37 @@ rb_block_call_kw(VALUE obj, ID mid, int argc, const VALUE * argv,
return rb_iterate_internal(iterate_method, (VALUE)&arg, bl_proc, data2);
}
/*
* A flexible variant of rb_block_call and rb_block_call_kw.
* This function accepts flags:
*
* RB_NO_KEYWORDS, RB_PASS_KEYWORDS, RB_PASS_CALLED_KEYWORDS:
* Works as the same as rb_block_call_kw.
*
* RB_BLOCK_NO_USE_PACKED_ARGS:
* The given block ("bl_proc") does not use "yielded_arg" of rb_block_call_func_t.
* Instead, the block accesses the yielded arguments via "argc" and "argv".
* This flag allows the called method to yield arguments without allocating an Array.
*/
VALUE
rb_block_call2(VALUE obj, ID mid, int argc, const VALUE *argv,
rb_block_call_func_t bl_proc, VALUE data2, long flags)
{
struct iter_method_arg arg;
arg.obj = obj;
arg.mid = mid;
arg.argc = argc;
arg.argv = argv;
arg.kw_splat = flags & 1;
struct vm_ifunc *ifunc = rb_vm_ifunc_proc_new(bl_proc, (void *)data2);
if (flags & RB_BLOCK_NO_USE_PACKED_ARGS)
ifunc->flags |= IFUNC_YIELD_OPTIMIZABLE;
return rb_iterate0(iterate_method, (VALUE)&arg, ifunc, GET_EC());
}
VALUE
rb_lambda_call(VALUE obj, ID mid, int argc, const VALUE *argv,
rb_block_call_func_t bl_proc, int min_argc, int max_argc,