Fix js_LookupCompileTimeConstant to respect shadowing properties (238881, r=shaver, a=chofmann).

This commit is contained in:
brendan%mozilla.org 2004-03-29 01:11:24 +00:00
Родитель f02b607efc
Коммит a0a4104364
2 изменённых файлов: 64 добавлений и 44 удалений

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

@ -1433,6 +1433,7 @@ JSBool
js_LookupCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom,
jsval *vp)
{
JSBool ok;
JSStackFrame *fp;
JSAtomListElement *ale;
JSObject *obj, *pobj;
@ -1441,9 +1442,13 @@ js_LookupCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom,
/*
* fp chases cg down the stack, but only until we reach the outermost cg.
* All stack frames should be flagged with JSFRAME_COMPILING, so we check
* sanity here.
* This enables propagating consts from top-level into switch cases in a
* function compiled along with the top-level script. All stack frames
* with matching code generators should be flagged with JSFRAME_COMPILING;
* we check sanity here.
*/
*vp = JSVAL_VOID;
ok = JS_TRUE;
fp = cx->fp;
do {
JS_ASSERT(fp->flags & JSFRAME_COMPILING);
@ -1458,32 +1463,37 @@ js_LookupCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom,
return JS_TRUE;
}
if (fp->flags & (JSFRAME_EVAL | JSFRAME_COMPILE_N_GO)) {
/*
* We're compiling code that will be executed immediately,
* and not reexecuted against a different scope chain and/or
* variable object. Therefore we can get const values from
* our variable object here.
*
* Try looking in the variable object for a direct property
* that is readonly and permanent. We know such a property
* can't be shadowed by another property on obj's prototype
* chain, or a with object or catch variable; nor can prop's
* value be changed, nor can prop be deleted.
*/
if (!OBJ_LOOKUP_PROPERTY(cx, obj, (jsid)atom, &pobj, &prop))
return JS_FALSE;
if (pobj == obj) {
if (!OBJ_GET_ATTRIBUTES(cx, obj, (jsid)atom, prop, &attrs))
return JS_FALSE;
if ((~attrs & (JSPROP_READONLY | JSPROP_PERMANENT)) == 0)
return OBJ_GET_PROPERTY(cx, obj, (jsid)atom, vp);
/*
* Try looking in the variable object for a direct property that
* is readonly and permanent. We know such a property can't be
* shadowed by another property on obj's prototype chain, or a
* with object or catch variable; nor can prop's value be changed,
* nor can prop be deleted.
*/
prop = NULL;
ok = OBJ_LOOKUP_PROPERTY(cx, obj, (jsid)atom, &pobj, &prop);
if (ok) {
if (pobj == obj &&
(fp->flags & (JSFRAME_EVAL | JSFRAME_COMPILE_N_GO))) {
/*
* We're compiling code that will be executed immediately,
* not re-executed against a different scope chain and/or
* variable object. Therefore we can get constant values
* from our variable object here.
*/
ok = OBJ_GET_ATTRIBUTES(cx, obj, (jsid)atom, prop, &attrs);
if (ok && !(~attrs & (JSPROP_READONLY | JSPROP_PERMANENT)))
ok = OBJ_GET_PROPERTY(cx, obj, (jsid)atom, vp);
}
if (prop)
OBJ_DROP_PROPERTY(cx, pobj, prop);
}
if (!ok || prop)
break;
}
fp = fp->down;
} while ((cg = cg->parent) != NULL);
return JS_FALSE;
return ok;
}
/*
@ -1988,6 +1998,7 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
JSParseNode **table;
jsdouble d;
jsint i, low, high;
jsval v;
JSAtom *atom;
JSAtomListElement *ale;
intN noteIndex;
@ -2058,11 +2069,15 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
pn3->pn_val = ATOM_KEY(pn4->pn_atom);
break;
case TOK_NAME:
if (!pn4->pn_expr &&
js_LookupCompileTimeConstant(cx, cg, pn4->pn_atom,
&pn3->pn_val)) {
constPropagated = JS_TRUE;
break;
if (!pn4->pn_expr) {
ok = js_LookupCompileTimeConstant(cx, cg, pn4->pn_atom, &v);
if (!ok)
goto release;
if (!JSVAL_IS_VOID(v)) {
pn3->pn_val = v;
constPropagated = JS_TRUE;
break;
}
}
/* FALL THROUGH */
case TOK_PRIMARY:
@ -2245,18 +2260,20 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
* We free table if non-null at label out, so all control flow must
* exit this function through goto out or goto bad.
*/
tableSize = (size_t)tableLength * sizeof *table;
table = (JSParseNode **) JS_malloc(cx, tableSize);
if (!table)
return JS_FALSE;
memset(table, 0, tableSize);
for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
if (pn3->pn_type == TOK_DEFAULT)
continue;
i = JSVAL_TO_INT(pn3->pn_val);
i -= low;
JS_ASSERT((uint32)i < tableLength);
table[i] = pn3;
if (tableLength != 0) {
tableSize = (size_t)tableLength * sizeof *table;
table = (JSParseNode **) JS_malloc(cx, tableSize);
if (!table)
return JS_FALSE;
memset(table, 0, tableSize);
for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
if (pn3->pn_type == TOK_DEFAULT)
continue;
i = JSVAL_TO_INT(pn3->pn_val);
i -= low;
JS_ASSERT((uint32)i < tableLength);
table[i] = pn3;
}
}
} else {
JS_ASSERT(switchOp == JSOP_LOOKUPSWITCH);

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

@ -327,10 +327,13 @@ js_PopStatementCG(JSContext *cx, JSCodeGenerator *cg);
* Define and lookup a primitive jsval associated with the const named by atom.
* js_DefineCompileTimeConstant analyzes the constant-folded initializer at pn
* and saves the const's value in cg->constList, if it can be used at compile
* time. It returns true unless an error occurred. If the initializer's value
* could not be saved, any later js_LookupCompileTimeConstant calls will return
* false. js_LookupCompileTimeConstant tries to find a const value memorized
* for atom, returning true if found with *vp set, false otherwise.
* time. It returns true unless an error occurred.
*
* If the initializer's value could not be saved, js_LookupCompileTimeConstant
* calls will return the undefined value. js_LookupCompileTimeConstant tries
* to find a const value memorized for atom, returning true with *vp set to a
* value other than undefined if the constant was found, true with *vp set to
* JSVAL_VOID if not found, and false on error.
*/
extern JSBool
js_DefineCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom,