vm.c: use `prepare_missing` in `mrb_funcall_with_block`
Remove code duplication.
MODIFY
src/vm.c
src/vm.c
@@ -430,6 +430,52 @@ mrb_ci_nregs(mrb_callinfo *ci)
return nregs;
}
+mrb_value mrb_obj_missing(mrb_state *mrb, mrb_value mod);
+
+static mrb_method_t
+prepare_missing(mrb_state *mrb, mrb_value recv, mrb_sym mid, struct RClass **clsp, uint32_t a, uint16_t *c, mrb_value blk, int super)
+{
+ mrb_sym missing = MRB_SYM(method_missing);
+ mrb_callinfo *ci = mrb->c->ci;
+ uint16_t b = *c;
+ mrb_int n = b & 0xf;
+ mrb_int nk = (b>>4) & 0xf;
+ mrb_value *argv = &ci->stack[a+1];
+ mrb_value args;
+ mrb_method_t m;
+
+ /* pack positional arguments */
+ if (n == 15) args = argv[0];
+ else args = mrb_ary_new_from_values(mrb, n, argv);
+
+ if (mrb_func_basic_p(mrb, recv, missing, mrb_obj_missing)) {
+ method_missing:
+ if (super) mrb_no_method_error(mrb, mid, args, "no superclass method '%n'", mid);
+ else mrb_method_missing(mrb, mid, recv, args);
+ /* not reached */
+ }
+ if (mid != missing) {
+ *clsp = mrb_class(mrb, recv);
+ }
+ m = mrb_method_search_vm(mrb, clsp, missing);
+ if (MRB_METHOD_UNDEF_P(m)) goto method_missing; /* just in case */
+ mrb_stack_extend(mrb, a+4);
+
+ argv = &ci->stack[a+1]; /* maybe reallocated */
+ argv[0] = args;
+ if (nk == 0) {
+ argv[1] = blk;
+ }
+ else {
+ mrb_assert(nk == 15);
+ argv[1] = argv[n];
+ argv[2] = blk;
+ }
+ *c = 15 | (nk<<4);
+ mrb_ary_unshift(mrb, args, mrb_symbol_value(mid));
+ return m;
+}
+
MRB_API mrb_value
mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc, const mrb_value *argv, mrb_value blk)
{
@@ -478,24 +524,15 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc
c = mrb_class(mrb, self);
m = mrb_method_search_vm(mrb, &c, mid);
mrb_stack_extend(mrb, n + argc + 3);
- if (MRB_METHOD_UNDEF_P(m) || argc >= 15) {
- mrb_value args = mrb_ary_new_from_values(mrb, argc, argv);
-
- ci->stack[n+1] = args;
+ if (argc >= 15) {
+ ci->stack[n+1] = mrb_ary_new_from_values(mrb, argc, argv);
argc = 15;
}
if (MRB_METHOD_UNDEF_P(m)) {
- mrb_sym missing = MRB_SYM(method_missing);
- mrb_value args = ci->stack[n+1];
-
- m = mrb_method_search_vm(mrb, &c, missing);
- if (MRB_METHOD_UNDEF_P(m)) {
- mrb_method_missing(mrb, mid, self, args);
- }
- mrb_ary_unshift(mrb, args, mrb_symbol_value(mid));
- mrb_stack_extend(mrb, n+2);
- ci->stack[n+1] = args;
- argc = 15;
+ uint16_t ac = (uint16_t)argc;
+ m = prepare_missing(mrb, self, mid, &c, n, &ac, mrb_nil_value(), 0);
+ argc = (mrb_int)ac;
+ mid = MRB_SYM(method_missing);
}
ci = cipush(mrb, n, 0, c, NULL, mid, argc);
if (MRB_METHOD_PROC_P(m)) {
@@ -1123,52 +1160,6 @@ hash_new_from_values(mrb_state *mrb, mrb_int argc, mrb_value *regs)
return hash;
}
-mrb_value mrb_obj_missing(mrb_state *mrb, mrb_value mod);
-
-static mrb_method_t
-prepare_missing(mrb_state *mrb, mrb_value recv, mrb_sym mid, struct RClass **clsp, uint32_t a, uint16_t *c, mrb_value blk, int super)
-{
- mrb_sym missing = MRB_SYM(method_missing);
- mrb_callinfo *ci = mrb->c->ci;
- uint16_t b = *c;
- mrb_int n = b & 0xf;
- mrb_int nk = (b>>4) & 0xf;
- mrb_value *argv = &ci->stack[a+1];
- mrb_value args;
- mrb_method_t m;
-
- /* pack positional arguments */
- if (n == 15) args = argv[0];
- else args = mrb_ary_new_from_values(mrb, n, argv);
-
- if (mrb_func_basic_p(mrb, recv, missing, mrb_obj_missing)) {
- method_missing:
- if (super) mrb_no_method_error(mrb, mid, args, "no superclass method '%n'", mid);
- else mrb_method_missing(mrb, mid, recv, args);
- /* not reached */
- }
- if (mid != missing) {
- *clsp = mrb_class(mrb, recv);
- }
- m = mrb_method_search_vm(mrb, clsp, missing);
- if (MRB_METHOD_UNDEF_P(m)) goto method_missing; /* just in case */
- mrb_stack_extend(mrb, a+4);
-
- argv = &ci->stack[a+1]; /* maybe reallocated */
- argv[0] = args;
- if (nk == 0) {
- argv[1] = blk;
- }
- else {
- mrb_assert(nk == 15);
- argv[1] = argv[n];
- argv[2] = blk;
- }
- *c = 15 | (nk<<4);
- mrb_ary_unshift(mrb, args, mrb_symbol_value(mid));
- return m;
-}
-
void mrb_method_added(mrb_state *mrb, struct RClass *c, mrb_sym mid);
mrb_value mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value idx, mrb_value len);

vm.c: use `prepare_missing` in `mrb_funcall_with_block`

Remove code duplication.