Bug 673070 - Fix name lookups in let scopes a bit more ("Assertion failure: sharedBlock" with e4x after fixing bug 646968). r=brendan.

This commit is contained in:
Jason Orendorff 2011-08-03 20:13:56 -05:00
parent 4a430a805c
commit e5002b3bc3
7 changed files with 67 additions and 22 deletions

View File

@ -3093,7 +3093,7 @@ AllocateSwitchConstant(JSContext *cx)
/*
* Sometimes, let-slots are pushed to the JS stack before we logically enter
* the let scope. For example,
* for (let x = EXPR;;) BODY
* let (x = EXPR) BODY
* compiles to roughly {enterblock; EXPR; setlocal x; BODY; leaveblock} even
* though EXPR is evaluated in the enclosing scope; it does not see x.
*
@ -4184,10 +4184,6 @@ EmitVariables(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
*/
let = (pn->pn_op == JSOP_NOP);
forInVar = (pn->pn_xflags & PNX_FORINVAR) != 0;
#if JS_HAS_BLOCK_SCOPE
bool popScope = (inLetHead || (let && (cg->flags & TCF_IN_FOR_INIT)));
JS_ASSERT_IF(popScope, let);
#endif
off = noteIndex = -1;
for (pn2 = pn->pn_head; ; pn2 = next) {
@ -4320,23 +4316,11 @@ EmitVariables(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
return JS_FALSE;
}
#if JS_HAS_BLOCK_SCOPE
/* Evaluate expr in the outer lexical scope if requested. */
TempPopScope tps;
if (popScope && !tps.popBlock(cx, cg))
return JS_FALSE;
#endif
oldflags = cg->flags;
cg->flags &= ~TCF_IN_FOR_INIT;
if (!js_EmitTree(cx, cg, pn3))
return JS_FALSE;
cg->flags |= oldflags & TCF_IN_FOR_INIT;
#if JS_HAS_BLOCK_SCOPE
if (popScope && !tps.repushBlock(cx, cg))
return JS_FALSE;
#endif
}
}
@ -6681,8 +6665,18 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
}
#if JS_HAS_BLOCK_SCOPE
case TOK_LET:
/* Let statements have their variable declarations on the left. */
case TOK_LET: {
/*
* pn represents one of these syntactic constructs:
* let-expression: (let (x = y) EXPR)
* let-statement: let (x = y) { ... }
* let-declaration in statement context: let x = y;
* let-declaration in for-loop head: for (let ...) ...
*
* Let-expressions and let-statements are represented as binary nodes
* with their variable declarations on the left and the body on the
* right.
*/
if (pn->pn_arity == PN_BINARY) {
pn2 = pn->pn_right;
pn = pn->pn_left;
@ -6690,13 +6684,27 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
pn2 = NULL;
}
/* Non-null pn2 means that pn is the variable list from a let head. */
/*
* Non-null pn2 means that pn is the variable list from a let head.
*
* Use TempPopScope to evaluate the expressions in the enclosing scope.
* This also causes the initializing assignments to be emitted in the
* enclosing scope, but the assignment opcodes emitted here
* (essentially just setlocal, though destructuring assignment uses
* other additional opcodes) do not care about the block chain.
*/
JS_ASSERT(pn->pn_arity == PN_LIST);
TempPopScope tps;
bool popScope = pn2 || (cg->flags & TCF_IN_FOR_INIT);
if (popScope && !tps.popBlock(cx, cg))
return JS_FALSE;
if (!EmitVariables(cx, cg, pn, pn2 != NULL, &noteIndex))
return JS_FALSE;
tmp = CG_OFFSET(cg);
if (popScope && !tps.repushBlock(cx, cg))
return JS_FALSE;
/* Thus non-null pn2 is the body of the let block or expression. */
tmp = CG_OFFSET(cg);
if (pn2 && !js_EmitTree(cx, cg, pn2))
return JS_FALSE;
@ -6706,6 +6714,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
return JS_FALSE;
}
break;
}
#endif /* JS_HAS_BLOCK_SCOPE */
#if JS_HAS_GENERATORS

View File

@ -2527,6 +2527,15 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
rval = OFF2STR(&ss->sprinter, todo);
todo = -2;
pc2 = pc + oplen;
/* Skip a block chain annotation if one appears here. */
if (*pc2 == JSOP_NOP) {
if (pc2[JSOP_NOP_LENGTH] == JSOP_NULLBLOCKCHAIN)
pc2 += JSOP_NOP_LENGTH + JSOP_NULLBLOCKCHAIN_LENGTH;
else if (pc2[JSOP_NOP_LENGTH] == JSOP_BLOCKCHAIN)
pc2 += JSOP_NOP_LENGTH + JSOP_BLOCKCHAIN_LENGTH;
}
if (*pc2 == JSOP_NOP) {
sn = js_GetSrcNote(jp->script, pc2);
if (sn) {

View File

@ -222,7 +222,7 @@ JS_XDRFindClassById(JSXDRState *xdr, uint32 id);
* before deserialization of bytecode. If the saved version does not match
* the current version, abort deserialization and invalidate the file.
*/
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 92)
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 93)
/*
* Library-private functions.

View File

@ -108,3 +108,6 @@ script regress-643222.js
script regress-614714.js
script regress-665355.js
script regress-666599.js
script regress-673070-1.js
script regress-673070-2.js
script regress-673070-3.js

View File

@ -0,0 +1,8 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
var q = [2];
let ([q] = eval("q"))
assertEq(q, 2);
reportCompare(0, 0, 'ok');

View File

@ -0,0 +1,8 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
var q = 1;
let ([q] = [eval("q")])
assertEq(q, 1);
reportCompare(0, 0, 'ok');

View File

@ -0,0 +1,8 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
let (x = 1) {
let ([] = [<x/>], r = <x/>) {}
}
reportCompare(0, 0, 'ok');