Protect near-newborns from GC when defining function objects, and fix stack local root management under JSOP_INITCATCHVAR for similar reasons -- to avoid last-ditch GC nesting and collecting a near-newborn (271716, r=shaver).

This commit is contained in:
brendan%mozilla.org 2004-12-12 04:46:01 +00:00
Родитель b3aef294f3
Коммит 0e46cdaae6
1 изменённых файлов: 73 добавлений и 32 удалений

Просмотреть файл

@ -4338,8 +4338,8 @@ js_Interpret(JSContext *cx, jsval *result)
* in the same compilation unit (ECMA Program).
*
* However, we could be in a Program being eval'd from inside a
* with statement, so we need to distinguish variables object from
* scope chain head. Hence the two assignments to parent below.
* with statement, so we need to distinguish scope chain head from
* variables object. Hence the obj2 vs. parent distinction below.
* First we make sure the function object we're defining has the
* right scope chain. Then we define its name in fp->varobj.
*
@ -4361,15 +4361,23 @@ js_Interpret(JSContext *cx, jsval *result)
* promote compile-cost sharing and amortizing, and because Script
* is not and will not be standardized.
*/
parent = fp->scopeChain;
if (OBJ_GET_PARENT(cx, obj) != parent) {
obj = js_CloneFunctionObject(cx, obj, parent);
obj2 = fp->scopeChain;
if (OBJ_GET_PARENT(cx, obj) != obj2) {
obj = js_CloneFunctionObject(cx, obj, obj2);
if (!obj) {
ok = JS_FALSE;
goto out;
}
}
/*
* Protect obj from any GC hiding below OBJ_DEFINE_PROPERTY. All
* paths from here must flow through the "Restore fp->scopeChain"
* code below the OBJ_DEFINE_PROPERTY call.
*/
fp->scopeChain = obj;
rval = OBJECT_TO_JSVAL(obj);
/*
* ECMA requires functions defined when entering Global code to be
* permanent, and functions defined when entering Eval code to be
@ -4385,8 +4393,10 @@ js_Interpret(JSContext *cx, jsval *result)
* in the property itself, not in obj->slots.
*/
flags = fun->flags & (JSFUN_GETTER | JSFUN_SETTER);
if (flags)
if (flags) {
attrs |= flags | JSPROP_SHARED;
rval = JSVAL_VOID;
}
/*
* Check for a const property of the same name -- or any kind
@ -4396,21 +4406,23 @@ js_Interpret(JSContext *cx, jsval *result)
*/
parent = fp->varobj;
ok = js_CheckRedeclaration(cx, parent, id, attrs, NULL, NULL);
if (ok) {
ok = OBJ_DEFINE_PROPERTY(cx, parent, id, rval,
(flags & JSFUN_GETTER)
? (JSPropertyOp) obj
: NULL,
(flags & JSFUN_SETTER)
? (JSPropertyOp) obj
: NULL,
attrs,
&prop);
}
/* Restore fp->scopeChain now that obj is defined in fp->varobj. */
fp->scopeChain = obj2;
if (!ok)
goto out;
ok = OBJ_DEFINE_PROPERTY(cx, parent, id,
flags ? JSVAL_VOID : OBJECT_TO_JSVAL(obj),
(flags & JSFUN_GETTER)
? (JSPropertyOp) obj
: NULL,
(flags & JSFUN_SETTER)
? (JSPropertyOp) obj
: NULL,
attrs,
&prop);
if (!ok)
goto out;
if (attrs == (JSPROP_ENUMERATE | JSPROP_PERMANENT) &&
script->numGlobalVars) {
/*
@ -4484,8 +4496,9 @@ js_Interpret(JSContext *cx, jsval *result)
* of the Function object clone.
*/
SAVE_SP(fp);
parent = js_ConstructObject(cx, &js_ObjectClass, NULL,
fp->scopeChain, 0, NULL);
obj2 = fp->scopeChain;
parent = js_ConstructObject(cx, &js_ObjectClass, NULL, obj2,
0, NULL);
if (!parent) {
ok = JS_FALSE;
goto out;
@ -4503,6 +4516,14 @@ js_Interpret(JSContext *cx, jsval *result)
goto out;
}
/*
* Protect obj from any GC hiding below OBJ_DEFINE_PROPERTY. All
* paths from here must flow through the "Restore fp->scopeChain"
* code below the OBJ_DEFINE_PROPERTY call.
*/
fp->scopeChain = obj;
rval = OBJECT_TO_JSVAL(obj);
/*
* 4. Create a property in the object Result(1). The property's
* name is [fun->atom, the identifier parsed by the compiler],
@ -4510,10 +4531,11 @@ js_Interpret(JSContext *cx, jsval *result)
*/
fun = (JSFunction *) JS_GetPrivate(cx, obj);
attrs = fun->flags & (JSFUN_GETTER | JSFUN_SETTER);
if (attrs)
if (attrs) {
attrs |= JSPROP_SHARED;
ok = OBJ_DEFINE_PROPERTY(cx, parent, ATOM_TO_JSID(fun->atom),
attrs ? JSVAL_VOID : OBJECT_TO_JSVAL(obj),
rval = JSVAL_VOID;
}
ok = OBJ_DEFINE_PROPERTY(cx, parent, ATOM_TO_JSID(fun->atom), rval,
(attrs & JSFUN_GETTER)
? (JSPropertyOp) obj
: NULL,
@ -4524,6 +4546,9 @@ js_Interpret(JSContext *cx, jsval *result)
JSPROP_ENUMERATE | JSPROP_PERMANENT |
JSPROP_READONLY,
NULL);
/* Restore fp->scopeChain now that obj is defined in parent. */
fp->scopeChain = obj2;
if (!ok) {
cx->newborn[GCX_OBJECT] = NULL;
goto out;
@ -4561,15 +4586,23 @@ js_Interpret(JSContext *cx, jsval *result)
* well-scoped function object.
*/
SAVE_SP(fp);
parent = fp->scopeChain;
if (OBJ_GET_PARENT(cx, obj) != parent) {
obj = js_CloneFunctionObject(cx, obj, parent);
obj2 = fp->scopeChain;
if (OBJ_GET_PARENT(cx, obj) != obj2) {
obj = js_CloneFunctionObject(cx, obj, obj2);
if (!obj) {
ok = JS_FALSE;
goto out;
}
}
/*
* Protect obj from any GC hiding below OBJ_DEFINE_PROPERTY. All
* paths from here must flow through the "Restore fp->scopeChain"
* code below the OBJ_DEFINE_PROPERTY call.
*/
fp->scopeChain = obj;
rval = OBJECT_TO_JSVAL(obj);
/*
* Make a property in fp->varobj with id fun->atom and value obj,
* unless fun is a getter or setter (in which case, obj is cast to
@ -4577,11 +4610,12 @@ js_Interpret(JSContext *cx, jsval *result)
*/
fun = (JSFunction *) JS_GetPrivate(cx, obj);
attrs = fun->flags & (JSFUN_GETTER | JSFUN_SETTER);
if (attrs)
if (attrs) {
attrs |= JSPROP_SHARED;
rval = JSVAL_VOID;
}
parent = fp->varobj;
ok = OBJ_DEFINE_PROPERTY(cx, parent, ATOM_TO_JSID(fun->atom),
attrs ? JSVAL_VOID : OBJECT_TO_JSVAL(obj),
ok = OBJ_DEFINE_PROPERTY(cx, parent, ATOM_TO_JSID(fun->atom), rval,
(attrs & JSFUN_GETTER)
? (JSPropertyOp) obj
: NULL,
@ -4591,10 +4625,14 @@ js_Interpret(JSContext *cx, jsval *result)
attrs | JSPROP_ENUMERATE
| JSPROP_PERMANENT,
&prop);
/* Restore fp->scopeChain now that obj is defined in fp->varobj. */
fp->scopeChain = obj2;
if (!ok) {
cx->newborn[GCX_OBJECT] = NULL;
goto out;
}
if (attrs == 0 && script->numGlobalVars) {
/*
* As with JSOP_DEFVAR and JSOP_DEFCONST (above), fast globals
@ -4860,16 +4898,16 @@ js_Interpret(JSContext *cx, jsval *result)
goto out;
case JSOP_INITCATCHVAR:
/* Pop the property's value into rval. */
/* Load the value into rval, while keeping it live on stack. */
JS_ASSERT(sp - fp->spbase >= 2);
rval = POP_OPND();
rval = FETCH_OPND(-1);
/* Get the immediate catch variable name into id. */
atom = GET_ATOM(cx, script, pc);
id = ATOM_TO_JSID(atom);
/* Find the object being initialized at top of stack. */
lval = FETCH_OPND(-1);
lval = FETCH_OPND(-2);
JS_ASSERT(JSVAL_IS_OBJECT(lval));
obj = JSVAL_TO_OBJECT(lval);
@ -4879,6 +4917,9 @@ js_Interpret(JSContext *cx, jsval *result)
JSPROP_PERMANENT, NULL);
if (!ok)
goto out;
/* Now that we're done with rval, pop it. */
sp--;
break;
#endif /* JS_HAS_EXCEPTIONS */