summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2015-12-31 00:11:37 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2015-12-31 00:11:37 +0900
commit3531fe179c0d58125e13dd08c53fe1ab084339c0 (patch)
tree2b0828f0080c6b95f50d3d098f8c4f00f82c373e
parent4fdec33ff44a5d443014a73caaa2d30a09fb9438 (diff)
downloadmruby-3531fe179c0d58125e13dd08c53fe1ab084339c0.tar.gz
mruby-3531fe179c0d58125e13dd08c53fe1ab084339c0.zip
GC must scan env from fibers even when it's not yet copied to heap; fix #3063
-rw-r--r--include/mruby/proc.h2
-rw-r--r--src/gc.c26
-rw-r--r--src/vm.c25
3 files changed, 33 insertions, 20 deletions
diff --git a/include/mruby/proc.h b/include/mruby/proc.h
index 24f0f319f..5965a2b39 100644
--- a/include/mruby/proc.h
+++ b/include/mruby/proc.h
@@ -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 {
diff --git a/src/gc.c b/src/gc.c
index 02e058f88..e31ec2f33 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -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;
diff --git a/src/vm.c b/src/vm.c
index b2149b250..58c73e4dd 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -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--;