diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/gc.c | 26 | ||||
| -rw-r--r-- | src/vm.c | 25 |
2 files changed, 31 insertions, 20 deletions
@@ -613,14 +613,11 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) case MRB_TT_ENV: { struct REnv *e = (struct REnv*)obj; + mrb_int i, len; - if (!MRB_ENV_STACK_SHARED_P(e)) { - mrb_int i, len; - - len = MRB_ENV_STACK_LEN(e); - for (i=0; i<len; i++) { - mrb_gc_mark_value(mrb, e->stack[i]); - } + len = MRB_ENV_STACK_LEN(e); + for (i=0; i<len; i++) { + mrb_gc_mark_value(mrb, e->stack[i]); } } break; @@ -725,9 +722,18 @@ obj_free(mrb_state *mrb, struct RBasic *obj) case MRB_TT_FIBER: { struct mrb_context *c = ((struct RFiber*)obj)->cxt; - - if (c != mrb->root_c) - mrb_free_context(mrb, c); + if (c && c != mrb->root_c) { + mrb_callinfo *ci = c->ci; + mrb_callinfo *ce = c->cibase; + + while (ce <= ci) { + struct REnv *e = ci->env; + if (e && !is_dead(&mrb->gc, e) && MRB_ENV_STACK_SHARED_P(e)) { + mrb_env_unshare(mrb, e); + } + ci--; + } + } } break; @@ -237,22 +237,27 @@ cipush(mrb_state *mrb) return ci; } +MRB_API void +mrb_env_unshare(mrb_state *mrb, struct REnv *e) +{ + size_t len = (size_t)MRB_ENV_STACK_LEN(e); + mrb_value *p = (mrb_value *)mrb_malloc(mrb, sizeof(mrb_value)*len); + + MRB_ENV_UNSHARE_STACK(e); + if (len > 0) { + stack_copy(p, e->stack, len); + } + e->stack = p; + mrb_write_barrier(mrb, (struct RBasic *)e); +} + static void cipop(mrb_state *mrb) { struct mrb_context *c = mrb->c; if (c->ci->env) { - struct REnv *e = c->ci->env; - size_t len = (size_t)MRB_ENV_STACK_LEN(e); - mrb_value *p = (mrb_value *)mrb_malloc(mrb, sizeof(mrb_value)*len); - - MRB_ENV_UNSHARE_STACK(e); - if (len > 0) { - stack_copy(p, e->stack, len); - } - e->stack = p; - mrb_write_barrier(mrb, (struct RBasic *)e); + mrb_env_unshare(mrb, c->ci->env); } c->ci--; |
