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:
parent
372bb990ac
commit
11e7ab79de
Notes:
git
2024-10-11 14:23:03 +00:00
Merged-By: maximecb <maximecb@ruby-lang.org>
14
enum.c
14
enum.c
@ -2984,13 +2984,12 @@ enum_member(VALUE obj, VALUE val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
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);
|
struct vm_ifunc *ifunc = rb_current_ifunc();
|
||||||
VALUE n = imemo_count_value(m);
|
ifunc->data = (const void *)rb_int_succ(index);
|
||||||
|
|
||||||
imemo_count_up(m);
|
return rb_yield_values(2, rb_enum_values_pack(argc, argv), index);
|
||||||
return rb_yield_values(2, rb_enum_values_pack(argc, argv), n);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3024,12 +3023,9 @@ each_with_index_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, memo))
|
|||||||
static VALUE
|
static VALUE
|
||||||
enum_each_with_index(int argc, VALUE *argv, VALUE obj)
|
enum_each_with_index(int argc, VALUE *argv, VALUE obj)
|
||||||
{
|
{
|
||||||
struct MEMO *memo;
|
|
||||||
|
|
||||||
RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_size);
|
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, INT2FIX(0));
|
||||||
rb_block_call(obj, id_each, argc, argv, each_with_index_i, (VALUE)memo);
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +79,12 @@ struct vm_ifunc_argc {
|
|||||||
#endif
|
#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 {
|
struct vm_ifunc {
|
||||||
VALUE flags;
|
VALUE flags;
|
||||||
VALUE *svar_lep;
|
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);
|
void rb_check_stack_overflow(void);
|
||||||
#define RB_BLOCK_NO_USE_PACKED_ARGS 2
|
#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);
|
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
|
#if USE_YJIT
|
||||||
/* vm_exec.c */
|
/* vm_exec.c */
|
||||||
|
11
vm_eval.c
11
vm_eval.c
@ -2702,6 +2702,17 @@ rb_current_realfilepath(void)
|
|||||||
return Qnil;
|
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
|
void
|
||||||
Init_vm_eval(void)
|
Init_vm_eval(void)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user