From ad576f1e7512bcf2217a7b17fb771af0438dd5b0 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 30 Jun 2024 21:01:45 +0900 Subject: [PATCH] Revert "Delegate the care of a directly given block from `cipop()` to `cipush()`" This reverts commit ad2e626e7a937fb4de9a1647aa58ea45aa3936ec. Because of the changes made by #6282, the following code caused a problem. ```ruby b = proc { break "BAD!" } p self.tap { b.call } # (expected) => break from proc-closure (LocalJumpError) # (after #6282) => "BAD!" ``` I revived the `mrb_callinfo::blk` field to fix this, but it did not overcome the following problem. ```ruby def m(&b); b = b.clone; GC.start; b.call; end p m { break "OK!" } # (expected) => "OK!" # (revived blk) => break from proc-closure (LocalJumpError) ``` --- include/mruby.h | 2 +- include/mruby/internal.h | 3 --- src/vm.c | 19 +++++++++---------- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index 490f344ac..3b4a1fc72 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -176,9 +176,9 @@ typedef struct { uint8_t n:4; /* (15=*) c=n|nk<<4 */ uint8_t nk:4; /* (15=*) */ uint8_t cci; /* called from C function */ - uint8_t flags; /* MRB_CI_COMPANION_BLOCK or zero */ mrb_sym mid; const struct RProc *proc; + struct RProc *blk; mrb_value *stack; const mrb_code *pc; /* current address on iseq of this proc */ union { diff --git a/include/mruby/internal.h b/include/mruby/internal.h index d8e81eafe..9f8453eaa 100644 --- a/include/mruby/internal.h +++ b/include/mruby/internal.h @@ -195,9 +195,6 @@ mrb_value mrb_obj_instance_eval(mrb_state*, mrb_value); mrb_value mrb_mod_module_eval(mrb_state*, mrb_value); mrb_value mrb_f_send(mrb_state *mrb, mrb_value self); -/* mrb_callinfo::flags */ -#define MRB_CI_COMPANION_BLOCK 0x01 /* it means `method { ... }`, not `method(&blk)` */ - #ifdef MRB_USE_BIGINT mrb_value mrb_bint_new_int(mrb_state *mrb, mrb_int x); #ifdef MRB_INT64 diff --git a/src/vm.c b/src/vm.c index 3a30f65bd..d9416d41b 100644 --- a/src/vm.c +++ b/src/vm.c @@ -349,15 +349,9 @@ cipush(mrb_state *mrb, mrb_int push_stacks, uint8_t cci, struct RClass *target_c c->ciend = c->cibase + size * 2; } ci = ++c->ci; - ci->flags = 0; - if (blk && (blk->flags & (MRB_PROC_CFUNC_FL | MRB_PROC_ENVSET | MRB_PROC_ORPHAN)) == MRB_PROC_ENVSET && - blk->e.env == ci[-1].u.env) { - mrb_assert(blk->color != MRB_GC_RED); // no exist red object with env set - ci->flags = MRB_CI_COMPANION_BLOCK; - blk->flags |= MRB_PROC_ORPHAN; - } ci->mid = mid; CI_PROC_SET(ci, proc); + ci->blk = blk; ci->stack = ci[-1].stack + push_stacks; ci->n = argc & 0xf; ci->nk = (argc>>4) & 0xf; @@ -465,6 +459,11 @@ cipop(mrb_state *mrb) struct REnv *env = CI_ENV(ci); ci_env_set(ci, NULL); // make possible to free env by GC if not needed + struct RProc *b = ci->blk; + if (b && !mrb_object_dead_p(mrb, (struct RBasic*)b) && b->tt == MRB_TT_PROC && + !MRB_PROC_STRICT_P(b) && MRB_PROC_ENV(b) == CI_ENV(&ci[-1])) { + b->flags |= MRB_PROC_ORPHAN; + } if (env && !mrb_env_unshare(mrb, env, TRUE)) { c->ci--; // exceptions are handled at the method caller; see #3087 mrb_exc_raise(mrb, mrb_obj_value(mrb->nomem_err)); @@ -2291,7 +2290,7 @@ RETRY_TRY_BLOCK: } if (MRB_PROC_STRICT_P(proc)) goto NORMAL_RETURN; - if (!MRB_PROC_ENV_P(proc)) { + if (MRB_PROC_ORPHAN_P(proc) || !MRB_PROC_ENV_P(proc) || !MRB_ENV_ONSTACK_P(MRB_PROC_ENV(proc))) { L_BREAK_ERROR: RAISE_LIT(mrb, E_LOCALJUMP_ERROR, "break from proc-closure"); } @@ -2307,7 +2306,7 @@ RETRY_TRY_BLOCK: while (mrb->c->cibase < ci && ci[-1].proc != proc) { ci--; } - if (ci == mrb->c->cibase || !(ci->flags & MRB_CI_COMPANION_BLOCK)) { + if (ci == mrb->c->cibase) { goto L_BREAK_ERROR; } c = a; // release the "a" variable, which can handle 32-bit values @@ -2333,7 +2332,7 @@ RETRY_TRY_BLOCK: if (MRB_PROC_ENV_P(dst)) { struct REnv *e = MRB_PROC_ENV(dst); - if (e->cxt != mrb->c) { + if (!MRB_ENV_ONSTACK_P(e) || e->cxt != mrb->c) { localjump_error(mrb, LOCALJUMP_ERROR_RETURN); goto L_RAISE; }