Skip to content

Commit

Permalink
GC must scan env from fibers even when it's not yet copied to heap; fix
Browse files Browse the repository at this point in the history
  • Loading branch information
matz committed Dec 30, 2015
1 parent 4fdec33 commit 3531fe1
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 20 deletions.
2 changes: 2 additions & 0 deletions include/mruby/proc.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ struct REnv {
#define MRB_ENV_UNSHARE_STACK(e) ((e)->cioff = -1)
#define MRB_ENV_STACK_SHARED_P(e) ((e)->cioff >= 0)

MRB_API void mrb_env_unshare(mrb_state*, struct REnv*);

struct RProc {
MRB_OBJECT_HEADER;
union {
Expand Down
26 changes: 16 additions & 10 deletions src/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand Down
25 changes: 15 additions & 10 deletions src/vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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--;
Expand Down

0 comments on commit 3531fe1

Please sign in to comment.