зеркало из https://github.com/github/ruby.git
Remove 1 allocation in Enumerable#each_with_index (#11868)
* Remove 1 allocation in Enumerable#each_with_index Previously, each call to Enumerable#each_with_index allocates 2 objects, one for the counting index, the other an imemo_ifunc passed to `self.each` as a block. Use `struct vm_ifunc::data` to hold the counting index directly to remove 1 allocation. * [DOC] Brief summary for usages of `struct vm_ifunc`
This commit is contained in:
Родитель
372bb990ac
Коммит
11e7ab79de
14
enum.c
14
enum.c
|
@ -2984,13 +2984,12 @@ enum_member(VALUE obj, VALUE val)
|
|||
}
|
||||
|
||||
static VALUE
|
||||
each_with_index_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, memo))
|
||||
each_with_index_i(RB_BLOCK_CALL_FUNC_ARGLIST(_, index))
|
||||
{
|
||||
struct MEMO *m = MEMO_CAST(memo);
|
||||
VALUE n = imemo_count_value(m);
|
||||
struct vm_ifunc *ifunc = rb_current_ifunc();
|
||||
ifunc->data = (const void *)rb_int_succ(index);
|
||||
|
||||
imemo_count_up(m);
|
||||
return rb_yield_values(2, rb_enum_values_pack(argc, argv), n);
|
||||
return rb_yield_values(2, rb_enum_values_pack(argc, argv), index);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3024,12 +3023,9 @@ each_with_index_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, memo))
|
|||
static VALUE
|
||||
enum_each_with_index(int argc, VALUE *argv, VALUE obj)
|
||||
{
|
||||
struct MEMO *memo;
|
||||
|
||||
RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_size);
|
||||
|
||||
memo = MEMO_NEW(0, 0, 0);
|
||||
rb_block_call(obj, id_each, argc, argv, each_with_index_i, (VALUE)memo);
|
||||
rb_block_call(obj, id_each, argc, argv, each_with_index_i, INT2FIX(0));
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
|
|
@ -79,7 +79,12 @@ struct vm_ifunc_argc {
|
|||
#endif
|
||||
};
|
||||
|
||||
/*! IFUNC (Internal FUNCtion) */
|
||||
/*! IFUNC (Internal FUNCtion)
|
||||
*
|
||||
* Bookkeeping for converting a C function and some closed-over data into a
|
||||
* block passable to methods. Like Ruby Proc, but not directly accessible at
|
||||
* Ruby level since this is an imemo. See rb_block_call() and friends.
|
||||
*/
|
||||
struct vm_ifunc {
|
||||
VALUE flags;
|
||||
VALUE *svar_lep;
|
||||
|
|
|
@ -77,6 +77,7 @@ VALUE rb_lambda_call(VALUE obj, ID mid, int argc, const VALUE *argv,
|
|||
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);
|
||||
struct vm_ifunc *rb_current_ifunc(void);
|
||||
|
||||
#if USE_YJIT
|
||||
/* vm_exec.c */
|
||||
|
|
11
vm_eval.c
11
vm_eval.c
|
@ -2702,6 +2702,17 @@ rb_current_realfilepath(void)
|
|||
return Qnil;
|
||||
}
|
||||
|
||||
// Assert that an internal function is running and return
|
||||
// the imemo object that represents it.
|
||||
struct vm_ifunc *
|
||||
rb_current_ifunc(void)
|
||||
{
|
||||
// Search VM_FRAME_MAGIC_IFUNC to see ifunc imemos put on the iseq field.
|
||||
VALUE ifunc = (VALUE)GET_EC()->cfp->iseq;
|
||||
RUBY_ASSERT_ALWAYS(imemo_type_p(ifunc, imemo_ifunc));
|
||||
return (struct vm_ifunc *)ifunc;
|
||||
}
|
||||
|
||||
void
|
||||
Init_vm_eval(void)
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче