[Bug 428706] Making sure that all let blocks has non-zero stack depth. r=brendan a1.9=beltzner

This commit is contained in:
igor@mir2.org 2008-04-18 00:31:48 -07:00
parent e05963a7da
commit 1301d0403b
2 changed files with 35 additions and 40 deletions

View File

@ -1976,7 +1976,7 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
if (!(sprop->flags & SPROP_HAS_SHORTID))
continue;
if (sprop->id == ATOM_TO_JSID(cx->runtime->atomState.emptyAtom)) {
/* See comments before EnsureNonEmptyLet from jsparse.c. */
/* See comments in CheckDestructuring from jsparse.c. */
JS_ASSERT(sprop->shortid == 0);
continue;
}

View File

@ -1658,37 +1658,6 @@ BindLet(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
NULL);
}
#if JS_HAS_DESTRUCTURING
/*
* The catch/finally handler implementation in the interpreter assumes that
* any operation that introduces a new scope (like a "let" or "with" block)
* increases the stack depth. This way, it is possible to restore the scope
* chain based on stack depth of the handler alone. A let block with an empty
* destructuring pattern like in
*
* let [] = 1;
*
* would violate this assumption as the there would be no let locals to store
* on the stack. To satisfy it we add an empty property to such blocks so
* OBJ_BLOCK_COUNT(cx, blockObj), that gives the number of slots, would be
* always positive.
*/
static JSBool
EnsureNonEmptyLet(JSContext *cx, JSTreeContext *tc)
{
jsid id;
if (OBJ_BLOCK_COUNT(cx, tc->blockChain) != 0)
return JS_TRUE;
id = ATOM_TO_JSID(cx->runtime->atomState.emptyAtom);
return js_DefineNativeProperty(cx, tc->blockChain, id,
JSVAL_VOID, NULL, NULL,
JSPROP_PERMANENT | JSPROP_READONLY,
SPROP_HAS_SHORTID, 0, NULL);
}
#endif
static JSBool
BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
{
@ -2058,7 +2027,6 @@ CheckDestructuring(JSContext *cx, BindData *data,
return JS_FALSE;
}
ok = JS_TRUE;
fpvd.table.ops = NULL;
lhs = left->pn_head;
if (lhs && lhs->pn_type == TOK_DEFSHARP) {
@ -2145,12 +2113,43 @@ CheckDestructuring(JSContext *cx, BindData *data,
}
}
out:
/*
* The catch/finally handler implementation in the interpreter assumes
* that any operation that introduces a new scope (like a "let" or "with"
* block) increases the stack depth. This way, it is possible to restore
* the scope chain based on stack depth of the handler alone. "let" with
* an empty destructuring pattern like in
*
* let [] = 1;
*
* would violate this assumption as the there would be no let locals to
* store on the stack. To satisfy it we add an empty property to such
* blocks so that OBJ_BLOCK_COUNT(cx, blockObj), which gives the number of
* slots, would be always positive.
*
* Note that we add such a property even if the block has locals due to
* later let declarations in it. We optimize for code simplicity here,
* not the fastest runtime performance with empty [] or {}.
*/
if (data->binder == BindLet && OBJ_BLOCK_COUNT(cx, tc->blockChain) == 0) {
ok = js_DefineNativeProperty(cx, tc->blockChain,
ATOM_TO_JSID(cx->runtime->
atomState.emptyAtom),
JSVAL_VOID, NULL, NULL,
JSPROP_PERMANENT | JSPROP_READONLY,
SPROP_HAS_SHORTID, 0, NULL);
if (!ok)
goto out;
}
ok = JS_TRUE;
out:
if (fpvd.table.ops)
JS_DHashTableFinish(&fpvd.table);
return ok;
no_var_name:
no_var_name:
js_ReportCompileErrorNumber(cx, TS(tc->parseContext), pn, JSREPORT_ERROR,
JSMSG_NO_VARIABLE_NAME);
ok = JS_FALSE;
@ -3002,7 +3001,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
case TOK_LB:
case TOK_LC:
pn3 = DestructuringExpr(cx, &data, tc, tt);
if (!pn3 || !EnsureNonEmptyLet(cx, tc))
if (!pn3)
return NULL;
break;
#endif
@ -3619,10 +3618,6 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
tc->flags |= TCF_FUN_HEAVYWEIGHT;
}
} while (js_MatchToken(cx, ts, TOK_COMMA));
#if JS_HAS_DESTRUCTURING
if (let && !EnsureNonEmptyLet(cx, tc))
return NULL;
#endif
pn->pn_pos.end = PN_LAST(pn)->pn_pos.end;
return pn;