summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2017-10-26 01:13:57 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2017-10-28 00:29:30 +0900
commit93f5f225772c398be6e409da3d3ef0f07ffbe1cf (patch)
tree37198a8c50baaf1a5714a581e049167073249ddc
parent3f9d00ded3ce987927d975f7ce70637a973de1fc (diff)
downloadmruby-93f5f225772c398be6e409da3d3ef0f07ffbe1cf.tar.gz
mruby-93f5f225772c398be6e409da3d3ef0f07ffbe1cf.zip
Heavily refactored how lexical scope links are implemented; fix #3821
Instead of `irep` links, we added a `upper` link to `struct RProc`. To make a space for the `upper` link, we moved `target_class` reference. If a `Proc` does not have `env`, `target_class` is saved in an `union` shared with `env` (if a `Proc` has env, you can tell it by `MRB_PROC_ENV_P()). Otherwise `target_class` is referenced from `env->c`. We removed links in `env` as well. This change removes 2 members from `mrb_irep` struct, thus saving 2 words per method/proc/block. This also fixes potential memory leaks due to the circular references caused by a link from `mrb_irep`.
-rw-r--r--include/mruby/irep.h3
-rw-r--r--include/mruby/proc.h43
-rw-r--r--mrbgems/mruby-bin-mirb/tools/mirb/mirb.c6
-rw-r--r--mrbgems/mruby-compiler/core/codegen.c3
-rw-r--r--mrbgems/mruby-compiler/core/parse.y2
-rw-r--r--mrbgems/mruby-eval/src/eval.c48
-rw-r--r--mrbgems/mruby-fiber/src/fiber.c4
-rw-r--r--src/class.c7
-rw-r--r--src/gc.c13
-rw-r--r--src/kernel.c42
-rw-r--r--src/proc.c74
-rw-r--r--src/state.c9
-rw-r--r--src/variable.c30
-rw-r--r--src/vm.c250
14 files changed, 264 insertions, 270 deletions
diff --git a/include/mruby/irep.h b/include/mruby/irep.h
index 91ca8b54d..efd226793 100644
--- a/include/mruby/irep.h
+++ b/include/mruby/irep.h
@@ -45,9 +45,6 @@ typedef struct mrb_irep {
struct mrb_irep_debug_info* debug_info;
int ilen, plen, slen, rlen, refcnt;
-
- struct mrb_irep *outer; /* Refers outer scope */
- struct RClass *target_class;
} mrb_irep;
#define MRB_ISEQ_NO_FREE 1
diff --git a/include/mruby/proc.h b/include/mruby/proc.h
index 5a6741610..24c9b0c21 100644
--- a/include/mruby/proc.h
+++ b/include/mruby/proc.h
@@ -18,17 +18,19 @@ MRB_BEGIN_DECL
struct REnv {
MRB_OBJECT_HEADER;
mrb_value *stack;
- ptrdiff_t cioff;
- union {
- mrb_sym mid;
- struct mrb_context *c;
- } cxt;
+ struct mrb_context *cxt;
+ // struct RProc *proc;
+ mrb_sym mid;
};
-#define MRB_SET_ENV_STACK_LEN(e,len) (e)->flags = (unsigned int)(len)
-#define MRB_ENV_STACK_LEN(e) ((mrb_int)(e)->flags)
-#define MRB_ENV_UNSHARE_STACK(e) ((e)->cioff = -1)
-#define MRB_ENV_STACK_SHARED_P(e) ((e)->cioff >= 0)
+/* flags (21bits): 1(shared flag):10(cioff/bidx):10(stack_len) */
+#define MRB_ENV_SET_STACK_LEN(e,len) (e)->flags = (((e)->flags & ~0x3ff)|(unsigned int)(len) & 0x3ff)
+#define MRB_ENV_STACK_LEN(e) ((mrb_int)((e)->flags & 0x3ff))
+#define MRB_ENV_STACK_UNSHARED (1<<20)
+#define MRB_ENV_UNSHARE_STACK(e) (e)->flags |= MRB_ENV_STACK_UNSHARED
+#define MRB_ENV_STACK_SHARED_P(e) (((e)->flags & MRB_ENV_STACK_UNSHARED) == 0)
+#define MRB_ENV_BIDX(e) (((e)->flags >> 10) & 0x3ff)
+#define MRB_ENV_SET_BIDX(e,idx) (e)->flags = (((e)->flags & ~(0x3ff<<10))|((unsigned int)(idx) & 0x3ff)<<10)
void mrb_env_unshare(mrb_state*, struct REnv*);
@@ -38,8 +40,11 @@ struct RProc {
mrb_irep *irep;
mrb_func_t func;
} body;
- struct RClass *target_class;
- struct REnv *env;
+ struct RProc *upper;
+ union {
+ struct RClass *target_class;
+ struct REnv *env;
+ } e;
};
/* aspec access */
@@ -57,6 +62,22 @@ struct RProc {
#define MRB_PROC_STRICT_P(p) (((p)->flags & MRB_PROC_STRICT) != 0)
#define MRB_PROC_ORPHAN 512
#define MRB_PROC_ORPHAN_P(p) (((p)->flags & MRB_PROC_ORPHAN) != 0)
+#define MRB_PROC_ENVSET 1024
+#define MRB_PROC_ENV_P(p) (((p)->flags & MRB_PROC_ENVSET) != 0)
+#define MRB_PROC_ENV(p) (MRB_PROC_ENV_P(p) ? (p)->e.env : NULL)
+#define MRB_PROC_TARGET_CLASS(p) (MRB_PROC_ENV_P(p) ? (p)->e.env->c : (p)->e.target_class )
+#define MRB_PROC_SET_TARGET_CLASS(p,tc) do {\
+ if (MRB_PROC_ENV_P(p)) {\
+ (p)->e.env->c = (tc);\
+ mrb_field_write_barrier(mrb, (struct RBasic*)(p)->e.env, (struct RBasic*)tc);\
+ }\
+ else {\
+ (p)->e.target_class = (tc);\
+ mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)tc);\
+ }\
+} while (0)
+#define MRB_PROC_SCOPE 2048
+#define MRB_PROC_SCOPE_P(p) (((p)->flags & MRB_PROC_SCOPE) != 0)
#define mrb_proc_ptr(v) ((struct RProc*)(mrb_ptr(v)))
diff --git a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c
index 891259a3f..3feb4270a 100644
--- a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c
+++ b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c
@@ -544,11 +544,11 @@ done:
if (args.verbose) {
mrb_codedump_all(mrb, proc);
}
- /* adjest stack length of toplevel environment */
+ /* adjust stack length of toplevel environment */
if (mrb->c->cibase->env) {
struct REnv *e = mrb->c->cibase->env;
- if (MRB_ENV_STACK_LEN(e) < proc->body.irep->nlocals) {
- MRB_SET_ENV_STACK_LEN(e, proc->body.irep->nlocals);
+ if (e && MRB_ENV_STACK_LEN(e) < proc->body.irep->nlocals) {
+ MRB_ENV_SET_STACK_LEN(e, proc->body.irep->nlocals);
}
}
/* pass a proc for evaluation */
diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c
index d9902a02e..da29077b0 100644
--- a/mrbgems/mruby-compiler/core/codegen.c
+++ b/mrbgems/mruby-compiler/core/codegen.c
@@ -3034,6 +3034,9 @@ mrb_generate_code(mrb_state *mrb, parser_state *p)
mrb_irep_decref(mrb, scope->irep);
mrb_pool_close(scope->mpool);
proc->c = NULL;
+ if (mrb->c->cibase && mrb->c->cibase->proc == proc->upper) {
+ proc->upper = NULL;
+ }
mrb->jmp = prev_jmp;
return proc;
}
diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y
index bf9d3fe85..e5017b677 100644
--- a/mrbgems/mruby-compiler/core/parse.y
+++ b/mrbgems/mruby-compiler/core/parse.y
@@ -5825,7 +5825,7 @@ mrb_load_exec(mrb_state *mrb, struct mrb_parser_state *p, mrbc_context *c)
c->keep_lv = TRUE;
}
}
- proc->target_class = target;
+ MRB_PROC_SET_TARGET_CLASS(proc, target);
if (mrb->c->ci) {
mrb->c->ci->target_class = target;
}
diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c
index 7fd4f1437..7061565ea 100644
--- a/mrbgems/mruby-eval/src/eval.c
+++ b/mrbgems/mruby-eval/src/eval.c
@@ -13,11 +13,9 @@ static struct mrb_irep *
get_closure_irep(mrb_state *mrb, int level)
{
struct mrb_context *c = mrb->c;
- struct REnv *e = c->ci[-1].proc->env;
- struct RProc *proc;
+ struct RProc *proc = c->ci[-1].proc;
if (level == 0) {
- proc = c->ci[-1].proc;
if (MRB_PROC_CFUNC_P(proc)) {
return NULL;
}
@@ -25,16 +23,11 @@ get_closure_irep(mrb_state *mrb, int level)
}
while (--level) {
- e = (struct REnv*)e->c;
- if (!e) return NULL;
+ proc = proc->upper;
+ if (!proc) return NULL;
}
- if (!e) return NULL;
- if (!MRB_ENV_STACK_SHARED_P(e)) return NULL;
- c = e->cxt.c;
- proc = c->cibase[e->cioff].proc;
-
- if (!proc || MRB_PROC_CFUNC_P(proc)) {
+ if (MRB_PROC_CFUNC_P(proc)) {
return NULL;
}
return proc->body.irep;
@@ -204,7 +197,9 @@ create_proc_from_string(mrb_state *mrb, char *s, mrb_int len, mrb_value binding,
struct mrb_parser_state *p;
struct RProc *proc;
struct REnv *e;
- struct mrb_context *c = mrb->c;
+ mrb_callinfo *ci = mrb->c->ci;
+ struct RClass *target_class = NULL;
+ int bidx;
if (!mrb_nil_p(binding)) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "Binding of eval must be nil.");
@@ -251,19 +246,19 @@ create_proc_from_string(mrb_state *mrb, char *s, mrb_int len, mrb_value binding,
mrbc_context_free(mrb, cxt);
mrb_raise(mrb, E_SCRIPT_ERROR, "codegen error");
}
- if (c->ci[-1].proc->target_class) {
- proc->target_class = c->ci[-1].proc->target_class;
- }
- e = c->ci[-1].proc->env;
- if (!e) e = c->ci[-1].env;
- e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, (struct RClass*)e);
- e->cxt.c = c;
- e->cioff = c->ci - c->cibase;
- e->stack = c->ci->stackent;
- MRB_SET_ENV_STACK_LEN(e, c->ci->proc->body.irep->nlocals);
- c->ci->target_class = proc->target_class;
- c->ci->env = 0;
- proc->env = e;
+ target_class = MRB_PROC_TARGET_CLASS(ci[-1].proc);
+ e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV,
+ (struct RClass*)target_class);
+ e->mid = ci->mid;
+ e->stack = ci->stackent;
+ MRB_ENV_SET_STACK_LEN(e, ci->proc->body.irep->nlocals);
+ bidx = ci->argc;
+ if (ci->argc < 0) bidx = 2;
+ else bidx += 1;
+ MRB_ENV_SET_BIDX(e, bidx);
+ proc->e.env = e;
+ proc->flags |= MRB_PROC_ENVSET;
+ ci->target_class = target_class;
patch_irep(mrb, proc->body.irep, 0, proc->body.irep);
/* mrb_codedump_all(mrb, proc); */
@@ -322,8 +317,7 @@ f_instance_eval(mrb_state *mrb, mrb_value self)
mrb_get_args(mrb, "s|zi", &s, &len, &file, &line);
cv = mrb_singleton_class(mrb, self);
proc = create_proc_from_string(mrb, s, len, mrb_nil_value(), file, line);
- proc->target_class = mrb_class_ptr(cv);
- mrb->c->ci->env = NULL;
+ MRB_PROC_SET_TARGET_CLASS(proc, mrb_class_ptr(cv));
mrb_assert(!MRB_PROC_CFUNC_P(proc));
return exec_irep(mrb, self, proc);
}
diff --git a/mrbgems/mruby-fiber/src/fiber.c b/mrbgems/mruby-fiber/src/fiber.c
index 57fe9401c..be9033063 100644
--- a/mrbgems/mruby-fiber/src/fiber.c
+++ b/mrbgems/mruby-fiber/src/fiber.c
@@ -123,7 +123,7 @@ fiber_init(mrb_state *mrb, mrb_value self)
/* adjust return callinfo */
ci = c->ci;
- ci->target_class = p->target_class;
+ ci->target_class = MRB_PROC_TARGET_CLASS(p);
ci->proc = p;
mrb_field_write_barrier(mrb, (struct RBasic*)mrb_obj_ptr(self), (struct RBasic*)p);
ci->pc = p->body.irep->iseq;
@@ -213,7 +213,7 @@ fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mr
*b++ = *a++;
}
c->cibase->argc = (int)len;
- value = c->stack[0] = c->ci->proc->env->stack[0];
+ value = c->stack[0] = MRB_PROC_ENV(c->ci->proc)->stack[0];
}
else {
value = fiber_result(mrb, a, len);
diff --git a/src/class.c b/src/class.c
index a35eb4c92..77a7050da 100644
--- a/src/class.c
+++ b/src/class.c
@@ -436,8 +436,11 @@ mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, struct RPro
k = kh_put(mt, mrb, h, mid);
kh_value(h, k) = p;
if (p) {
+ p->flags |= MRB_PROC_SCOPE;
p->c = NULL;
- mrb_field_write_barrier(mrb, (struct RBasic *)c, (struct RBasic *)p);
+ mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)p);
+ MRB_PROC_SET_TARGET_CLASS(p, c);
+ mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)c);
}
mc_clear_by_id(mrb, c, mid);
}
@@ -449,7 +452,7 @@ mrb_define_method_id(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_func_t f
int ai = mrb_gc_arena_save(mrb);
p = mrb_proc_new_cfunc(mrb, func);
- p->target_class = c;
+ MRB_PROC_SET_TARGET_CLASS(p, c);
mrb_define_method_raw(mrb, c, mid, p);
mrb_gc_arena_restore(mrb, ai);
}
diff --git a/src/gc.c b/src/gc.c
index 0f95d25ef..a3a638ae3 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -647,11 +647,8 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
{
struct RProc *p = (struct RProc*)obj;
- mrb_gc_mark(mrb, (struct RBasic*)p->env);
- mrb_gc_mark(mrb, (struct RBasic*)p->target_class);
- if (!MRB_PROC_CFUNC_P(p) && p->body.irep) {
- mrb_gc_mark(mrb, (struct RBasic*)p->body.irep->target_class);
- }
+ mrb_gc_mark(mrb, (struct RBasic*)p->upper);
+ mrb_gc_mark(mrb, (struct RBasic*)p->e.env);
}
break;
@@ -660,12 +657,6 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
struct REnv *e = (struct REnv*)obj;
mrb_int i, len;
- if (MRB_ENV_STACK_SHARED_P(e)) {
- if (e->cxt.c->fib) {
- mrb_gc_mark(mrb, (struct RBasic*)e->cxt.c->fib);
- }
- break;
- }
len = MRB_ENV_STACK_LEN(e);
for (i=0; i<len; i++) {
mrb_gc_mark_value(mrb, e->stack[i]);
diff --git a/src/kernel.c b/src/kernel.c
index 33d142184..1e5a74222 100644
--- a/src/kernel.c
+++ b/src/kernel.c
@@ -136,6 +136,7 @@ mrb_f_block_given_p_m(mrb_state *mrb, mrb_value self)
{
mrb_callinfo *ci = mrb->c->ci;
mrb_value *bp;
+ struct RProc *p;
bp = ci->stackent + 1;
ci--;
@@ -143,24 +144,20 @@ mrb_f_block_given_p_m(mrb_state *mrb, mrb_value self)
return mrb_false_value();
}
/* block_given? called within block; check upper scope */
- if (ci->proc->env) {
- struct REnv *e = ci->proc->env;
-
- while (e->c) {
- e = (struct REnv*)e->c;
- }
+ p = ci->proc;
+ while (p) {
+ if (MRB_PROC_SCOPE_P(p)) break;
+ p = p->upper;
+ }
+ /* top-level does not have block slot (always false) */
+ if (p == NULL) return mrb_false_value();
+ if (MRB_PROC_ENV_P(p)) {
+ struct REnv *e = MRB_PROC_ENV(p);
/* top-level does not have block slot (always false) */
if (e->stack == mrb->c->stbase)
return mrb_false_value();
- if (e->stack && e->cioff < 0) {
- /* use saved block arg position */
- bp = &e->stack[-e->cioff];
- ci = 0; /* no callinfo available */
- }
- else {
- ci = e->cxt.c->cibase + e->cioff;
- bp = ci[1].stackent + 1;
- }
+ /* use saved block arg position */
+ bp = &e->stack[MRB_ENV_BIDX(e)];
}
if (ci && ci->argc > 0) {
bp += ci->argc;
@@ -655,7 +652,7 @@ method_entry_loop(mrb_state *mrb, struct RClass* klass, khash_t(st)* set)
khint_t i;
khash_t(mt) *h = klass->mt;
- if (!h) return;
+ if (!h || kh_size(h) == 0) return;
for (i=0;i<kh_end(h);i++) {
if (kh_exist(h, i) && kh_value(h, i)) {
kh_put(st, mrb, set, kh_key(h, i));
@@ -690,7 +687,7 @@ mrb_class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* kl
klass = klass->super;
}
- ary = mrb_ary_new(mrb);
+ ary = mrb_ary_new_capa(mrb, kh_size(set));
for (i=0;i<kh_end(set);i++) {
if (kh_exist(set, i)) {
mrb_ary_push(mrb, ary, mrb_symbol_value(kh_key(set, i)));
@@ -1161,16 +1158,19 @@ mrb_local_variables(mrb_state *mrb, mrb_value self)
return mrb_ary_new(mrb);
}
vars = mrb_hash_new(mrb);
- irep = proc->body.irep;
- while (irep) {
+ while (proc) {
+ if (MRB_PROC_CFUNC_P(proc)) break;
+ irep = proc->body.irep;
if (!irep->lv) break;
for (i = 0; i + 1 < irep->nlocals; ++i) {
if (irep->lv[i].name) {
mrb_hash_set(mrb, vars, mrb_symbol_value(irep->lv[i].name), mrb_true_value());
}
}
- if (!proc->env) break;
- irep = irep->outer;
+ if (!MRB_PROC_ENV_P(proc)) break;
+ proc = proc->upper;
+ // if (MRB_PROC_SCOPE_P(proc)) break;
+ if (!proc->c) break;
}
return mrb_hash_keys(mrb, vars);
diff --git a/src/proc.c b/src/proc.c
index a6214f1fc..69a9c0299 100644
--- a/src/proc.c
+++ b/src/proc.c
@@ -20,15 +20,19 @@ mrb_proc_new(mrb_state *mrb, mrb_irep *irep)
mrb_callinfo *ci = mrb->c->ci;
p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class);
- p->target_class = 0;
if (ci) {
- if (ci->proc)
- p->target_class = ci->proc->target_class;
- if (!p->target_class)
- p->target_class = ci->target_class;
+ struct RClass *tc = NULL;
+
+ if (ci->proc) {
+ tc = MRB_PROC_TARGET_CLASS(ci->proc);
+ }
+ if (tc == NULL) {
+ tc = ci->target_class;
+ }
+ p->upper = ci->proc;
+ p->e.target_class = tc;
}
p->body.irep = irep;
- p->env = 0;
mrb_irep_incref(mrb, irep);
return p;
@@ -38,30 +42,45 @@ static struct REnv*
env_new(mrb_state *mrb, mrb_int nlocals)
{
struct REnv *e;
-
- e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, (struct RClass*)mrb->c->ci->proc->env);
- MRB_SET_ENV_STACK_LEN(e, nlocals);
- e->cxt.c = mrb->c;
- e->cioff = mrb->c->ci - mrb->c->cibase;
+ mrb_callinfo *ci = mrb->c->ci;
+ int bidx;
+
+ e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, NULL);
+ MRB_ENV_SET_STACK_LEN(e, nlocals);
+ bidx = ci->argc;
+ if (ci->argc < 0) bidx = 2;
+ else bidx += 1;
+ MRB_ENV_SET_BIDX(e, bidx);
+ e->mid = ci->mid;
e->stack = mrb->c->stack;
+ e->cxt = mrb->c;
return e;
}
static void
-closure_setup(mrb_state *mrb, struct RProc *p, int nlocals)
+closure_setup(mrb_state *mrb, struct RProc *p)
{
+ mrb_callinfo *ci = mrb->c->ci;
+ struct RProc *up = p->upper;
struct REnv *e;
- if (!mrb->c->ci->env) {
- e = env_new(mrb, nlocals);
- mrb->c->ci->env = e;
+ if (ci->env) {
+ e = ci->env;
}
else {
- e = mrb->c->ci->env;
+ struct RClass *tc = MRB_PROC_TARGET_CLASS(up);
+
+ e = env_new(mrb, up->body.irep->nlocals);
+ ci->env = e;
+ if (tc) {
+ e->c = tc;
+ mrb_field_write_barrier(mrb, (struct RBasic*)e, (struct RBasic*)tc);
+ }
}
- p->env = e;
- mrb_field_write_barrier(mrb, (struct RBasic *)p, (struct RBasic *)p->env);
+ p->e.env = e;
+ p->flags |= MRB_PROC_ENVSET;
+ mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)e);
}
struct RProc*
@@ -69,7 +88,7 @@ mrb_closure_new(mrb_state *mrb, mrb_irep *irep)
{
struct RProc *p = mrb_proc_new(mrb, irep);
- closure_setup(mrb, p, mrb->c->ci->proc->body.irep->nlocals);
+ closure_setup(mrb, p);
return p;
}
@@ -81,7 +100,8 @@ mrb_proc_new_cfunc(mrb_state *mrb, mrb_func_t func)
p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class);
p->body.func = func;
p->flags |= MRB_PROC_CFUNC;
- p->env = 0;
+ p->upper = 0;
+ p->e.target_class = 0;
return p;
}
@@ -93,8 +113,9 @@ mrb_proc_new_cfunc_with_env(mrb_state *mrb, mrb_func_t func, mrb_int argc, const
struct REnv *e;
int i;
- p->env = e = env_new(mrb, argc);
- mrb_field_write_barrier(mrb, (struct RBasic *)p, (struct RBasic *)p->env);
+ p->e.env = e = env_new(mrb, argc);
+ p->flags |= MRB_PROC_ENVSET;
+ mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)e);
MRB_ENV_UNSHARE_STACK(e);
e->stack = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value) * argc);
if (argv) {
@@ -120,7 +141,7 @@ MRB_API mrb_value
mrb_proc_cfunc_env_get(mrb_state *mrb, mrb_int idx)
{
struct RProc *p = mrb->c->ci->proc;
- struct REnv *e = p->env;
+ struct REnv *e = MRB_PROC_ENV(p);
if (!MRB_PROC_CFUNC_P(p)) {
mrb_raise(mrb, E_TYPE_ERROR, "Can't get cfunc env from non-cfunc proc.");
@@ -148,8 +169,9 @@ mrb_proc_copy(struct RProc *a, struct RProc *b)
if (!MRB_PROC_CFUNC_P(a) && a->body.irep) {
a->body.irep->refcnt++;
}
- a->target_class = b->target_class;
- a->env = b->env;
+ a->upper = b->upper;
+ a->e.env = b->e.env;
+ /* a->e.target_class = a->e.target_class; */
}
static mrb_value
@@ -169,7 +191,7 @@ mrb_proc_s_new(mrb_state *mrb, mrb_value proc_class)
proc = mrb_obj_value(p);
mrb_funcall_with_block(mrb, proc, mrb_intern_lit(mrb, "initialize"), 0, NULL, proc);
if (!MRB_PROC_STRICT_P(p) &&
- mrb->c->ci > mrb->c->cibase && p->env == mrb->c->ci[-1].env) {
+ mrb->c->ci > mrb->c->cibase && MRB_PROC_ENV(p) == mrb->c->ci[-1].env) {
p->flags |= MRB_PROC_ORPHAN;
}
return proc;
diff --git a/src/state.c b/src/state.c
index 596eecafa..44bcc0656 100644
--- a/src/state.c
+++ b/src/state.c
@@ -139,11 +139,6 @@ mrb_irep_cutref(mrb_state *mrb, mrb_irep *irep)
irep->reps[i] = NULL;
if (tmp) mrb_irep_decref(mrb, tmp);
}
- if (irep->outer) {
- tmp = irep->outer;
- irep->outer = NULL;
- if (tmp) mrb_irep_decref(mrb, tmp);
- }
}
void
@@ -170,10 +165,6 @@ mrb_irep_free(mrb_state *mrb, mrb_irep *irep)
if (irep->reps[i])
mrb_irep_decref(mrb, irep->reps[i]);
}
- if (irep->outer) {
- if (irep->outer)
- mrb_irep_decref(mrb, irep->outer);
- }
mrb_free(mrb, irep->reps);
mrb_free(mrb, irep->lv);
if (irep->own_filename) {
diff --git a/src/variable.c b/src/variable.c
index 4fbe82dd9..3e84c573c 100644
--- a/src/variable.c
+++ b/src/variable.c
@@ -632,18 +632,19 @@ mrb_cv_defined(mrb_state *mrb, mrb_value mod, mrb_sym sym)
mrb_value
mrb_vm_cv_get(mrb_state *mrb, mrb_sym sym)
{
- struct RClass *c = mrb->c->ci->proc->target_class;
+ struct RClass *c;
+ c = MRB_PROC_TARGET_CLASS(mrb->c->ci->proc);
if (!c) c = mrb->c->ci->target_class;
-
return mrb_mod_cv_get(mrb, c, sym);
}
void
mrb_vm_cv_set(mrb_state *mrb, mrb_sym sym, mrb_value v)
{
- struct RClass *c = mrb->c->ci->proc->target_class;
+ struct RClass *c;
+ c = MRB_PROC_TARGET_CLASS(mrb->c->ci->proc);
if (!c) c = mrb->c->ci->target_class;
mrb_mod_cv_set(mrb, c, sym, v);
}
@@ -700,11 +701,12 @@ mrb_const_get(mrb_state *mrb, mrb_value mod, mrb_sym sym)
mrb_value
mrb_vm_const_get(mrb_state *mrb, mrb_sym sym)
{
- struct RClass *c = mrb->c->ci->proc->target_class;
+ struct RClass *c;
struct RClass *c2;
mrb_value v;
- mrb_irep *irep;
+ struct RProc *proc;
+ c = MRB_PROC_TARGET_CLASS(mrb->c->ci->proc);
if (!c) c = mrb->c->ci->target_class;
mrb_assert(c != NULL);
@@ -720,15 +722,13 @@ mrb_vm_const_get(mrb_state *mrb, mrb_sym sym)
}
if (c2->tt == MRB_TT_CLASS || c2->tt == MRB_TT_MODULE) c = c2;
mrb_assert(!MRB_PROC_CFUNC_P(mrb->c->ci->proc));
- irep = mrb->c->ci->proc->body.irep;
- while (irep) {
- if (irep->target_class) {
- c2 = irep->target_class;
- if (c2->iv && iv_get(mrb, c2->iv, sym, &v)) {
- return v;
- }
+ proc = mrb->c->ci->proc;
+ while (proc) {
+ c2 = MRB_PROC_TARGET_CLASS(proc);
+ if (c2 && c2->iv && iv_get(mrb, c2->iv, sym, &v)) {
+ return v;
}
- irep = irep->outer;
+ proc = proc->upper;
}
return const_get(mrb, c, sym, TRUE);
}
@@ -746,9 +746,7 @@ mrb_const_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v)
void
mrb_vm_const_set(mrb_state *mrb, mrb_sym sym, mrb_value v)
{
- struct RClass *c = mrb->c->ci->proc->target_class;
-
- if (!c) c = mrb->c->ci->target_class;
+ struct RClass *c = mrb->c->ci->target_class;
mrb_obj_iv_set(mrb, (struct RObject*)c, sym, v);
}
diff --git a/src/vm.c b/src/vm.c
index 196b2934e..734d225ba 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -151,6 +151,9 @@ envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase, size_t size)
e->stack = newbase + off;
}
+ else if (e && MRB_ENV_STACK_SHARED_P(e)) {
+ fprintf(stderr, "bingo! %p\n", e);
+ }
ci->stackent = newbase + (ci->stackent - oldbase);
ci++;
}
@@ -208,41 +211,33 @@ stack_extend(mrb_state *mrb, int room)
}
}
+static int nenv = 0;
+
static inline struct REnv*
uvenv(mrb_state *mrb, int up)
{
- struct REnv *e = mrb->c->ci->proc->env;
+ struct RProc *proc = mrb->c->ci->proc;
+ struct REnv *e;
- while (up--) {
+ nenv++;
+ do {
+ e = MRB_PROC_ENV(proc);
if (!e) return NULL;
- e = (struct REnv*)e->c;
- }
+ proc = proc->upper;
+ if (!proc) return NULL;
+ } while (up--);
return e;
}
-static inline mrb_bool
-is_strict(mrb_state *mrb, struct REnv *e)
+static inline struct RProc*
+top_proc(mrb_state *mrb, struct RProc *proc)
{
- ptrdiff_t cioff = e->cioff;
-
- if (MRB_ENV_STACK_SHARED_P(e) && e->cxt.c->cibase[cioff].proc &&
- MRB_PROC_STRICT_P(e->cxt.c->cibase[cioff].proc)) {
- return TRUE;
+ while (proc->upper) {
+ if (MRB_PROC_SCOPE_P(proc) || MRB_PROC_STRICT_P(proc))
+ return proc;
+ proc = proc->upper;
}
- return FALSE;
-}
-
-static inline struct REnv*
-top_env(mrb_state *mrb, struct RProc *proc)
-{
- struct REnv *e = proc->env;
-
- if (is_strict(mrb, e)) return e;
- while (e->c) {
- e = (struct REnv*)e->c;
- if (is_strict(mrb, e)) return e;
- }
- return e;
+ return proc;
}
#define CI_ACC_SKIP -1
@@ -279,19 +274,11 @@ mrb_env_unshare(mrb_state *mrb, struct REnv *e)
if (e == NULL) return;
else {
size_t len = (size_t)MRB_ENV_STACK_LEN(e);
- ptrdiff_t cioff = e->cioff;
mrb_value *p;
if (!MRB_ENV_STACK_SHARED_P(e)) return;
- if (e->cxt.c != mrb->c) return;
- if (e->cioff == 0 && e->cxt.c == mrb->root_c) return;
+ if (e->cxt != mrb->c) return;
MRB_ENV_UNSHARE_STACK(e);
- if (!e->c) {
- /* save block argument position (negated) */
- e->cioff = -e->cxt.c->cibase[cioff].argc-1;
- if (e->cioff == 0) e->cioff = -2; /* blkarg position for vararg (1:args, 2:blk) */
- }
- e->cxt.mid = e->cxt.c->cibase[cioff].mid;
p = (mrb_value *)mrb_malloc(mrb, sizeof(mrb_value)*len);
if (len > 0) {
stack_copy(p, e->stack, len);
@@ -317,20 +304,22 @@ static void
ecall(mrb_state *mrb, int i)
{
struct RProc *p;
- mrb_callinfo *ci = mrb->c->ci;
- mrb_value *self = mrb->c->stack;
+ struct mrb_context *c = mrb->c;
+ mrb_callinfo *ci = c->ci;
struct RObject *exc;
+ struct REnv *env;
ptrdiff_t cioff;
int ai = mrb_gc_arena_save(mrb);
if (i<0) return;
- if (ci - mrb->c->cibase > MRB_FUNCALL_DEPTH_MAX) {
+ if (ci - c->cibase > MRB_FUNCALL_DEPTH_MAX) {
mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err));
}
- p = mrb->c->ensure[i];
+ p = c->ensure[i];
if (!p) return;
- mrb->c->ensure[i] = NULL;
- cioff = ci - mrb->c->cibase;
+ mrb_assert(!MRB_PROC_CFUNC_P(p));
+ c->ensure[i] = NULL;
+ cioff = ci - c->cibase;
ci = cipush(mrb);
ci->stackent = mrb->c->stack;
ci->mid = ci[-1].mid;
@@ -338,14 +327,17 @@ ecall(mrb_state *mrb, int i)
ci->argc = 0;
ci->proc = p;
ci->nregs = p->body.irep->nregs;
- ci->target_class = p->target_class;
- mrb->c->stack = mrb->c->stack + ci[-1].nregs;
+ ci->target_class = MRB_PROC_TARGET_CLASS(p);
+ env = MRB_PROC_ENV(p);
+ mrb_assert(env);
+ c->stack = c->stack + p->body.irep->nregs;
exc = mrb->exc; mrb->exc = 0;
if (exc) {
mrb_gc_protect(mrb, mrb_obj_value(exc));
}
- mrb_run(mrb, p, *self);
- mrb->c->ci = mrb->c->cibase + cioff;
+ mrb_run(mrb, p, env->stack[0]);
+ c = mrb->c;
+ c->ci = c->cibase + cioff;
if (!mrb->exc) mrb->exc = exc;
mrb_gc_arena_restore(mrb, ai);
}
@@ -497,7 +489,7 @@ mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p)
mrb->c->stack[0] = self;
ci->proc = p;
- ci->target_class = p->target_class;
+ ci->target_class = MRB_PROC_TARGET_CLASS(p);
if (MRB_PROC_CFUNC_P(p)) {
return p->body.func(mrb, self);
}
@@ -732,7 +724,7 @@ mrb_yield_argv(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv)
{
struct RProc *p = mrb_proc_ptr(b);
- return mrb_yield_with_class(mrb, b, argc, argv, p->env->stack[0], p->target_class);
+ return mrb_yield_with_class(mrb, b, argc, argv, MRB_PROC_ENV(p)->stack[0], MRB_PROC_TARGET_CLASS(p));
}
MRB_API mrb_value
@@ -740,7 +732,7 @@ mrb_yield(mrb_state *mrb, mrb_value b, mrb_value arg)
{
struct RProc *p = mrb_proc_ptr(b);
- return mrb_yield_with_class(mrb, b, 1, &arg, p->env->stack[0], p->target_class);
+ return mrb_yield_with_class(mrb, b, 1, &arg, MRB_PROC_ENV(p)->stack[0], MRB_PROC_TARGET_CLASS(p));
}
mrb_value
@@ -770,23 +762,23 @@ mrb_value
mrb_mod_s_nesting(mrb_state *mrb, mrb_value mod)
{
struct RProc *proc;
- mrb_irep *irep;
mrb_value ary;
- struct RClass *c;
+ struct RClass *c = NULL;
mrb_get_args(mrb, "");
ary = mrb_ary_new(mrb);
proc = mrb->c->ci[-1].proc; /* callee proc */
- c = proc->target_class;
- mrb_ary_push(mrb, ary, mrb_obj_value(c));
mrb_assert(!MRB_PROC_CFUNC_P(proc));
- irep = proc->body.irep;
- while (irep) {
- if (irep->target_class && irep->target_class != c) {
- c = irep->target_class;
- mrb_ary_push(mrb, ary, mrb_obj_value(c));
+ while (proc) {
+ if (MRB_PROC_SCOPE_P(proc)) {
+ struct RClass *c2 = MRB_PROC_TARGET_CLASS(proc);
+
+ if (c2 != c) {
+ c = c2;
+ mrb_ary_push(mrb, ary, mrb_obj_value(c));
+ }
}
- irep = irep->outer;
+ proc = proc->upper;
}
return ary;
}
@@ -852,18 +844,6 @@ argnum_error(mrb_state *mrb, mrb_int num)
mrb_exc_set(mrb, exc);
}
-void
-irep_uplink(mrb_state *mrb, mrb_irep *outer, mrb_irep *irep)
-{
- if (irep->outer != outer) {
- if (irep->outer) {
- mrb_irep_decref(mrb, irep->outer);
- }
- irep->outer = outer;
- mrb_irep_incref(mrb, outer);
- }
-}
-
#define ERR_PC_SET(mrb, pc) mrb->c->ci->err = pc;
#define ERR_PC_CLR(mrb) mrb->c->ci->err = 0;
#ifdef MRB_ENABLE_DEBUG_HOOK
@@ -1319,9 +1299,10 @@ RETRY_TRY_BLOCK:
CASE(OP_EPOP) {
/* A A.times{ensure_pop().call} */
int a = GETARG_A(i);
- int n, epos = mrb->c->ci->epos;
- mrb_callinfo *ci;
+ mrb_callinfo *ci = mrb->c->ci;
+ int n, epos = ci->epos;
mrb_value self = regs[0];
+ struct RClass *target_class = ci->target_class;
if (mrb->c->eidx == epos) {
NEXT;
@@ -1339,7 +1320,7 @@ RETRY_TRY_BLOCK:
ci->proc = proc;
ci->stackent = mrb->c->stack;
ci->nregs = irep->nregs;
- ci->target_class = proc->target_class;
+ ci->target_class = target_class;
ci->pc = pc;
ci->acc = ci[-1].nregs;
mrb->c->stack += ci->acc;
@@ -1441,7 +1422,7 @@ RETRY_TRY_BLOCK:
if (GET_OPCODE(i) == OP_SENDB) {
if (mrb_type(blk) == MRB_TT_PROC) {
struct RProc *p = mrb_proc_ptr(blk);
- if (p && !MRB_PROC_STRICT_P(p) && p->env == ci[-1].env) {
+ if (p && !MRB_PROC_STRICT_P(p) && MRB_PROC_ENV(p) == ci[-1].env) {
p->flags |= MRB_PROC_ORPHAN;
}
}
@@ -1493,20 +1474,16 @@ RETRY_TRY_BLOCK:
/* replace callinfo */
ci = mrb->c->ci;
- ci->target_class = m->target_class;
+ ci->target_class = MRB_PROC_TARGET_CLASS(m);
ci->proc = m;
- if (m->env) {
+ if (MRB_PROC_ENV_P(m)) {
mrb_sym mid;
+ struct REnv *e = MRB_PROC_ENV(m);
- if (MRB_ENV_STACK_SHARED_P(m->env)) {
- mid = m->env->cxt.c->cibase[m->env->cioff].mid;
- }
- else {
- mid = m->env->cxt.mid;
- }
+ mid = e->mid;
if (mid) ci->mid = mid;
- if (!m->env->stack) {
- m->env->stack = mrb->c->stack;
+ if (!e->stack) {
+ e->stack = mrb->c->stack;
}
}
@@ -1547,8 +1524,8 @@ RETRY_TRY_BLOCK:
else if (ci->argc+2 < irep->nregs) {
stack_clear(regs+ci->argc+2, irep->nregs-ci->argc-2);
}
- if (m->env) {
- regs[0] = m->env->stack[0];
+ if (MRB_PROC_ENV_P(m)) {
+ regs[0] = MRB_PROC_ENV(m)->stack[0];
}
pc = irep->iseq;
JUMP;
@@ -1833,6 +1810,12 @@ RETRY_TRY_BLOCK:
/* A B return R(A) (B=normal,in-block return/break) */
mrb_callinfo *ci;
+#define ecall_adjust() do {\
+ ptrdiff_t cioff = ci - mrb->c->cibase;\
+ ecall(mrb, --mrb->c->eidx);\
+ ci = mrb->c->cibase + cioff;\
+} while (0)
+
ci = mrb->c->ci;
if (ci->mid) {
mrb_value blk;
@@ -1847,18 +1830,17 @@ RETRY_TRY_BLOCK:
struct RProc *p = mrb_proc_ptr(blk);
if (!MRB_PROC_STRICT_P(p) &&
- ci > mrb->c->cibase && p->env == ci[-1].env) {
+ ci > mrb->c->cibase && MRB_PROC_ENV(p) == ci[-1].env) {
p->flags |= MRB_PROC_ORPHAN;
}
}
}
if (mrb->exc) {
- mrb_callinfo *ci0;
mrb_value *stk;
L_RAISE:
- ci0 = ci = mrb->c->ci;
+ ci = mrb->c->ci;
if (ci == mrb->c->cibase) {
if (ci->ridx == 0) goto L_FTOP;
goto L_RESCUE;
@@ -1897,8 +1879,7 @@ RETRY_TRY_BLOCK:
if (ci[0].ridx == ci[-1].ridx) {
mrb_value *org_stbase = mrb->c->stbase;
while (mrb->c->eidx > ci->epos) {
- ecall(mrb, --mrb->c->eidx);
- ci = mrb->c->ci;
+ ecall_adjust();
if (org_stbase != mrb->c->stbase) {
stk = mrb->c->stack;
}
@@ -1911,46 +1892,43 @@ RETRY_TRY_BLOCK:
irep = proc->body.irep;
pool = irep->pool;
syms = irep->syms;
- if (ci != ci0) {
- mrb->c->stack = ci[1].stackent;
- }
+ mrb->c->stack = ci[1].stackent;
stack_extend(mrb, irep->nregs);
pc = mrb->c->rescue[--ci->ridx];
}
else {
int acc;
mrb_value v;
+ struct RProc *dst;
+ ci = mrb->c->ci;
v = regs[GETARG_A(i)];
mrb_gc_protect(mrb, v);
switch (GETARG_B(i)) {
case OP_R_RETURN:
/* Fall through to OP_R_NORMAL otherwise */
- if (ci->acc >=0 && proc->env && !MRB_PROC_STRICT_P(proc)) {
- struct REnv *e = top_env(mrb, proc);
- mrb_callinfo *ce;
+ if (ci->acc >=0 && MRB_PROC_ENV_P(proc) && !MRB_PROC_STRICT_P(proc)) {
+ dst = top_proc(mrb, proc);
- if (!MRB_ENV_STACK_SHARED_P(e) || e->cxt.c != mrb->c) {
- localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
- goto L_RAISE;
+ if (MRB_PROC_ENV_P(dst)) {
+ struct REnv *e = MRB_PROC_ENV(dst);
+
+ if (!MRB_ENV_STACK_SHARED_P(e) || e->cxt != mrb->c) {
+ localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
+ goto L_RAISE;
+ }
}
-
- ce = mrb->c->cibase + e->cioff;
- while (ci > ce) {
- mrb_env_unshare(mrb, ci->env);
+ while (ci->proc != dst) {
if (ci->acc < 0) {
localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
goto L_RAISE;
}
ci--;
}
- mrb_env_unshare(mrb, ci->env);
- if (ce == mrb->c->cibase) {
+ if (ci == mrb->c->cibase) {
localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
goto L_RAISE;
}
- mrb->c->stack = mrb->c->ci->stackent;
- mrb->c->ci = ce;
break;
}
case OP_R_NORMAL:
@@ -1966,14 +1944,14 @@ RETRY_TRY_BLOCK:
goto L_RAISE;
}
while (mrb->c->eidx > 0) {
- ecall(mrb, --mrb->c->eidx);
+ ecall_adjust();
}
/* automatic yield at the end */
mrb->c->status = MRB_FIBER_TERMINATED;
mrb->c = mrb->c->prev;
mrb->c->status = MRB_FIBER_RUNNING;
+ ci = mrb->c->ci;
}
- ci = mrb->c->ci;
break;
case OP_R_BREAK:
if (MRB_PROC_STRICT_P(proc)) goto NORMAL_RETURN;
@@ -1986,23 +1964,23 @@ RETRY_TRY_BLOCK:
mrb_exc_set(mrb, exc);
goto L_RAISE;
}
- if (!proc->env || !MRB_ENV_STACK_SHARED_P(proc->env)) {
+ if (!MRB_PROC_ENV_P(proc) || !MRB_ENV_STACK_SHARED_P(MRB_PROC_ENV(proc))) {
goto L_BREAK_ERROR;
}
- if (proc->env->cxt.c != mrb->c) {
+ if (MRB_PROC_ENV(proc)->cxt != mrb->c) {
goto L_BREAK_ERROR;
}
- while (mrb->c->eidx > mrb->c->ci->epos) {
- ecall(mrb, --mrb->c->eidx);
- }
/* break from fiber block */
- if (mrb->c->ci == mrb->c->cibase && mrb->c->ci->pc) {
+ if (ci == mrb->c->cibase && ci->pc) {
struct mrb_context *c = mrb->c;
+ while (c->eidx > c->ci->epos) {
+ ecall_adjust();
+ }
mrb->c = c->prev;
c->prev = NULL;
+ ci = mrb->c->ci;
}
- ci = mrb->c->ci;
if (ci->acc < 0) {
mrb_gc_arena_restore(mrb, ai);
mrb->c->vmexec = FALSE;
@@ -2018,31 +1996,32 @@ RETRY_TRY_BLOCK:
ci = mrb->c->ci;
}
mrb->c->stack = ci->stackent;
- mrb->c->ci = mrb->c->cibase + proc->env->cioff + 1;
- while (ci > mrb->c->ci) {
- mrb_env_unshare(mrb, ci->env);
+ proc = proc->upper;
+ while (mrb->c->cibase < ci && ci[-1].proc != proc) {
if (ci[-1].acc == CI_ACC_SKIP) {
mrb->c->ci = ci;
goto L_BREAK_ERROR;
}
ci--;
}
- mrb_env_unshare(mrb, ci->env);
break;
default:
/* cannot happen */
break;
}
- while (mrb->c->eidx > mrb->c->ci->epos) {
- ecall(mrb, --mrb->c->eidx);
+ while (mrb->c->eidx > ci->epos) {
+ ecall_adjust();
}
- if (mrb->c->vmexec && !mrb->c->ci->target_class) {
+ if (mrb->c->vmexec && !ci->target_class) {
mrb_gc_arena_restore(mrb, ai);
mrb->c->vmexec = FALSE;
mrb->jmp = prev_jmp;
return v;
}
- ci = mrb->c->ci;
+ while (ci < mrb->c->ci) {
+ mrb_env_unshare(mrb, mrb->c->ci->env);
+ mrb->c->ci--;
+ }
acc = ci->acc;
mrb->c->stack = ci->stackent;
cipop(mrb);
@@ -2052,6 +2031,7 @@ RETRY_TRY_BLOCK:
return v;
}
pc = ci->pc;
+ ci = mrb->c->ci;
DEBUG(fprintf(stderr, "from :%s\n", mrb_sym2name(mrb, ci->mid)));
proc = mrb->c->ci->proc;
irep = proc->body.irep;
@@ -2152,8 +2132,7 @@ RETRY_TRY_BLOCK:
if (lv == 0) stack = regs + 1;
else {
struct REnv *e = uvenv(mrb, lv-1);
- if (!e || e->cioff == 0 ||
- (!MRB_ENV_STACK_SHARED_P(e) && e->cxt.mid == 0) ||
+ if (!e || (!MRB_ENV_STACK_SHARED_P(e) && e->mid == 0) ||
MRB_ENV_STACK_LEN(e) <= m1+r+m2+1) {
localjump_error(mrb, LOCALJUMP_ERROR_YIELD);
goto L_RAISE;
@@ -2689,7 +2668,6 @@ RETRY_TRY_BLOCK:
int c = GETARG_c(i);
mrb_irep *nirep = irep->reps[b];
- irep_uplink(mrb, irep, nirep);
if (c & OP_L_CAPTURE) {
p = mrb_closure_new(mrb, nirep);
}
@@ -2718,9 +2696,7 @@ RETRY_TRY_BLOCK:
base = regs[a];
super = regs[a+1];
if (mrb_nil_p(base)) {
- baseclass = mrb->c->ci->proc->target_class;
- if (!baseclass) baseclass = mrb->c->ci->target_class;
-
+ baseclass = mrb->c->ci->target_class;
base = mrb_obj_value(baseclass);
}
c = mrb_vm_define_class(mrb, base, super, id);
@@ -2738,9 +2714,7 @@ RETRY_TRY_BLOCK:
base = regs[a];
if (mrb_nil_p(base)) {
- baseclass = mrb->c->ci->proc->target_class;
- if (!baseclass) baseclass = mrb->c->ci->target_class;
-
+ baseclass = mrb->c->ci->target_class;
base = mrb_obj_value(baseclass);
}
c = mrb_vm_define_module(mrb, base, id);
@@ -2758,11 +2732,12 @@ RETRY_TRY_BLOCK:
struct RProc *p;
mrb_irep *nirep = irep->reps[bx];
- irep_uplink(mrb, irep, nirep);
- nirep->target_class = mrb_class_ptr(recv);
/* prepare closure */
- p = mrb_closure_new(mrb, nirep);
+ p = mrb_proc_new(mrb, nirep);
p->c = NULL;
+ mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)proc);
+ MRB_PROC_SET_TARGET_CLASS(p, mrb_class_ptr(recv));
+ p->flags |= MRB_PROC_SCOPE;
/* prepare stack */
ci = cipush(mrb);
@@ -2777,7 +2752,7 @@ RETRY_TRY_BLOCK:
mrb->c->stack += a;
/* setup closure */
- p->target_class = ci->target_class;
+ MRB_PROC_SET_TARGET_CLASS(p, ci->target_class);
ci->proc = p;
irep = p->body.irep;
@@ -2908,7 +2883,6 @@ mrb_top_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int sta
return mrb_vm_run(mrb, proc, self, stack_keep);
}
if (mrb->c->ci == mrb->c->cibase) {
- mrb->c->ci->env = NULL;
return mrb_vm_run(mrb, proc, self, stack_keep);
}
ci = cipush(mrb);