diff --git a/enum.c b/enum.c index dcb374778e..30f374ad7b 100644 --- a/enum.c +++ b/enum.c @@ -322,16 +322,32 @@ enum_count(int argc, VALUE *argv, VALUE obj) return imemo_count_value(memo); } +NORETURN(static void found(VALUE i, VALUE memop)); +static void +found(VALUE i, VALUE memop) { + struct MEMO *memo = MEMO_CAST(memop); + MEMO_V1_SET(memo, i); + memo->u3.cnt = 1; + rb_iter_break(); +} + +static VALUE +find_i_fast(RB_BLOCK_CALL_FUNC_ARGLIST(i, memop)) +{ + if (RTEST(rb_yield_values2(argc, argv))) { + ENUM_WANT_SVALUE(); + found(i, memop); + } + return Qnil; +} + static VALUE find_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, memop)) { ENUM_WANT_SVALUE(); if (RTEST(enum_yield(argc, i))) { - struct MEMO *memo = MEMO_CAST(memop); - MEMO_V1_SET(memo, i); - memo->u3.cnt = 1; - rb_iter_break(); + found(i, memop); } return Qnil; } @@ -366,7 +382,10 @@ enum_find(int argc, VALUE *argv, VALUE obj) if_none = rb_check_arity(argc, 0, 1) ? argv[0] : Qnil; RETURN_ENUMERATOR(obj, argc, argv); memo = MEMO_NEW(Qundef, 0, 0); - rb_block_call(obj, id_each, 0, 0, find_i, (VALUE)memo); + if (rb_block_pair_yield_optimizable()) + rb_block_call2(obj, id_each, 0, 0, find_i_fast, (VALUE)memo, RB_BLOCK_NO_USE_PACKED_ARGS); + else + rb_block_call2(obj, id_each, 0, 0, find_i, (VALUE)memo, RB_BLOCK_NO_USE_PACKED_ARGS); if (memo->u3.cnt) { return memo->v1; } @@ -1817,7 +1836,7 @@ enum_all(int argc, VALUE *argv, VALUE obj) { struct MEMO *memo = MEMO_ENUM_NEW(Qtrue); WARN_UNUSED_BLOCK(argc); - rb_block_call(obj, id_each, 0, 0, ENUMFUNC(all), (VALUE)memo); + rb_block_call2(obj, id_each, 0, 0, ENUMFUNC(all), (VALUE)memo, RB_BLOCK_NO_USE_PACKED_ARGS); return memo->v1; } @@ -1879,7 +1898,7 @@ enum_any(int argc, VALUE *argv, VALUE obj) { struct MEMO *memo = MEMO_ENUM_NEW(Qfalse); WARN_UNUSED_BLOCK(argc); - rb_block_call(obj, id_each, 0, 0, ENUMFUNC(any), (VALUE)memo); + rb_block_call2(obj, id_each, 0, 0, ENUMFUNC(any), (VALUE)memo, RB_BLOCK_NO_USE_PACKED_ARGS); return memo->v1; } @@ -2168,7 +2187,7 @@ enum_one(int argc, VALUE *argv, VALUE obj) VALUE result; WARN_UNUSED_BLOCK(argc); - rb_block_call(obj, id_each, 0, 0, ENUMFUNC(one), (VALUE)memo); + rb_block_call2(obj, id_each, 0, 0, ENUMFUNC(one), (VALUE)memo, RB_BLOCK_NO_USE_PACKED_ARGS); result = memo->v1; if (UNDEF_P(result)) return Qfalse; return result; @@ -2229,7 +2248,7 @@ enum_none(int argc, VALUE *argv, VALUE obj) struct MEMO *memo = MEMO_ENUM_NEW(Qtrue); WARN_UNUSED_BLOCK(argc); - rb_block_call(obj, id_each, 0, 0, ENUMFUNC(none), (VALUE)memo); + rb_block_call2(obj, id_each, 0, 0, ENUMFUNC(none), (VALUE)memo, RB_BLOCK_NO_USE_PACKED_ARGS); return memo->v1; }