ref: aba272ac959329476ce73bc7d69d14ad7779c754
parent: 2e196dd0fc7344c175c9bdca79388acdfa1c15a2
author: Tor Andersson <[email protected]>
date: Wed Sep 24 12:02:04 EDT 2014
Fix bug where some environment records were not marked by GC. Environments when calling a function were saved in a local variable. Therefore the garbage collector did not see them in its list of roots to follow, resulting in environments being freed while still in use.
--- a/jsgc.c
+++ b/jsgc.c
@@ -120,6 +120,7 @@
int nenv = 0, nfun = 0, nobj = 0;
int genv = 0, gfun = 0, gobj = 0;
int mark;
+ int i;
mark = J->gcmark = J->gcmark == 1 ? 2 : 1;
@@ -129,6 +130,8 @@
jsG_markobject(J, mark, J->Boolean_prototype);
jsG_markobject(J, mark, J->Number_prototype);
jsG_markobject(J, mark, J->String_prototype);
+ jsG_markobject(J, mark, J->RegExp_prototype);
+ jsG_markobject(J, mark, J->Date_prototype);
jsG_markobject(J, mark, J->Error_prototype);
jsG_markobject(J, mark, J->EvalError_prototype);
@@ -142,7 +145,11 @@
jsG_markobject(J, mark, J->G);
jsG_markstack(J, mark);
+
jsG_markenvironment(J, mark, J->E);
+ jsG_markenvironment(J, mark, J->GE);
+ for (i = 0; i < J->envtop; ++i)
+ jsG_markenvironment(J, mark, J->envstack[i]);
prevnextenv = &J->gcenv;
for (env = J->gcenv; env; env = nextenv) {
--- a/jsi.h
+++ b/jsi.h
@@ -49,6 +49,7 @@
/* Limits */
#define JS_STACKSIZE 256 /* value stack size */
+#define JS_ENVLIMIT 64 /* environment stack size */
#define JS_TRYLIMIT 64 /* exception stack size */
#define JS_GCLIMIT 10000 /* run gc cycle every N allocations */
@@ -92,6 +93,7 @@
{
jmp_buf buf;
js_Environment *E;
+ int envtop;
int top, bot;
short *pc;
};
@@ -172,6 +174,10 @@
js_Environment *gcenv;
js_Function *gcfun;
js_Object *gcobj;
+
+ /* environments on the call stack but currently not in scope */
+ int envtop;
+ js_Environment *envstack[JS_ENVLIMIT];
/* exception stack */
int trylen;
--- a/jsrun.c
+++ b/jsrun.c
@@ -801,16 +801,26 @@
/* Function calls */
+static void jsR_savescope(js_State *J, js_Environment *newE)
+{
+ if (J->envtop + 1 >= JS_ENVLIMIT)
+ js_stackoverflow(J);
+ J->envstack[J->envtop++] = J->E;
+ J->E = newE;
+}
+
+static void jsR_restorescope(js_State *J)
+{
+ J->E = J->envstack[--J->envtop];
+}
+
static void jsR_calllwfunction(js_State *J, unsigned int n, js_Function *F, js_Environment *scope)
{
- js_Environment *saveE;
js_Value v;
unsigned int i;
- saveE = J->E;
+ jsR_savescope(J, scope);
- J->E = scope;
-
if (n > F->numparams) {
js_pop(J, F->numparams - n);
n = F->numparams;
@@ -823,18 +833,17 @@
TOP = --BOT; /* clear stack */
js_pushvalue(J, v);
- J->E = saveE;
+ jsR_restorescope(J);
}
static void jsR_callfunction(js_State *J, unsigned int n, js_Function *F, js_Environment *scope)
{
- js_Environment *saveE;
js_Value v;
unsigned int i;
- saveE = J->E;
+ scope = jsR_newenvironment(J, jsV_newobject(J, JS_COBJECT, NULL), scope);
- J->E = jsR_newenvironment(J, jsV_newobject(J, JS_COBJECT, NULL), scope);
+ jsR_savescope(J, scope);
if (F->arguments) {
js_newobject(J);
@@ -866,7 +875,7 @@
TOP = --BOT; /* clear stack */
js_pushvalue(J, v);
- J->E = saveE;
+ jsR_restorescope(J);
}
static void jsR_callscript(js_State *J, unsigned int n, js_Function *F)
@@ -991,6 +1000,7 @@
if (J->trylen == JS_TRYLIMIT)
js_error(J, "try: exception stack overflow");
J->trybuf[J->trylen].E = J->E;
+ J->trybuf[J->trylen].envtop = J->envtop;
J->trybuf[J->trylen].top = J->top;
J->trybuf[J->trylen].bot = J->bot;
J->trybuf[J->trylen].pc = pc;
@@ -1002,6 +1012,7 @@
js_Value v = js_tovalue(J, -1);
--J->trylen;
J->E = J->trybuf[J->trylen].E;
+ J->envtop = J->trybuf[J->trylen].envtop;
J->top = J->trybuf[J->trylen].top;
J->bot = J->trybuf[J->trylen].bot;
js_pushvalue(J, v);