summaryrefslogtreecommitdiffhomepage
path: root/mrbgems
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 /mrbgems
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`.
Diffstat (limited to 'mrbgems')
-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
5 files changed, 30 insertions, 33 deletions
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);