summaryrefslogtreecommitdiffhomepage
path: root/src/vm.c
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2017-09-04 06:51:31 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2017-09-04 06:51:31 +0900
commit3acaa44a70a44a816076dee65310f0f2487aeebd (patch)
treedb7b29708bd51a1521d2695d0debdf562101d99a /src/vm.c
parent8a5d783f2ee5ddccdb2b8de2edf5dc6b5ba1c3fc (diff)
downloadmruby-3acaa44a70a44a816076dee65310f0f2487aeebd.tar.gz
mruby-3acaa44a70a44a816076dee65310f0f2487aeebd.zip
Restructure `irep->outer` chain; fix #3804
Instead of `irep -> proc` chain, we use `irep -> irep` chain to avoid GC bugs like #3804. We added `target_class` reference to `mrb_irep` struct. That means one more word consumption per `irep`.
Diffstat (limited to 'src/vm.c')
-rw-r--r--src/vm.c36
1 files changed, 27 insertions, 9 deletions
diff --git a/src/vm.c b/src/vm.c
index 9486bd1f2..f413211e7 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -770,17 +770,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;
mrb_get_args(mrb, "");
ary = mrb_ary_new(mrb);
proc = mrb->c->ci[-1].proc; /* callee proc */
- while (proc) {
- mrb_assert(!MRB_PROC_CFUNC_P(proc));
- if (MRB_PROC_CLASS_P(proc) && proc->target_class) {
- mrb_ary_push(mrb, ary, mrb_obj_value(proc->target_class));
- }
- proc = proc->body.irep->outer;
+ 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));
+ }
+ irep = irep->outer;
}
return ary;
}
@@ -846,6 +852,18 @@ 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
@@ -2647,7 +2665,7 @@ RETRY_TRY_BLOCK:
int c = GETARG_c(i);
mrb_irep *nirep = irep->reps[b];
- nirep->outer = mrb->c->ci->proc;
+ irep_uplink(mrb, irep, nirep);
if (c & OP_L_CAPTURE) {
p = mrb_closure_new(mrb, nirep);
}
@@ -2716,11 +2734,11 @@ RETRY_TRY_BLOCK:
struct RProc *p;
mrb_irep *nirep = irep->reps[bx];
- nirep->outer = mrb->c->ci->proc;
+ irep_uplink(mrb, irep, nirep);
+ nirep->target_class = mrb_class_ptr(recv);
/* prepare closure */
p = mrb_closure_new(mrb, nirep);
p->c = NULL;
- p->flags |= MRB_PROC_CLASS;
/* prepare stack */
ci = cipush(mrb);