mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
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`.
This commit is contained in:
@@ -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
|
||||
|
||||
+32
-11
@@ -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)))
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
+5
-2
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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]);
|
||||
|
||||
+21
-21
@@ -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);
|
||||
|
||||
+47
-25
@@ -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;
|
||||
mrb_callinfo *ci = mrb->c->ci;
|
||||
int bidx;
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
+14
-16
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user