mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-19 08:15:31 +00:00
Destructuring catch variables, plus TOK_LEXICALSCOPE cleanup (336379, r=mrbkap).
This commit is contained in:
parent
6e01d43af8
commit
df41627c20
@ -3130,10 +3130,17 @@ EmitDestructuringLHS(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
|
||||
return JS_FALSE;
|
||||
break;
|
||||
|
||||
case JSOP_SETLOCAL:
|
||||
if (wantpop) {
|
||||
slot = (jsuint) pn->pn_slot;
|
||||
EMIT_UINT16_IMM_OP(JSOP_SETLOCALPOP, slot);
|
||||
break;
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
|
||||
case JSOP_SETARG:
|
||||
case JSOP_SETVAR:
|
||||
case JSOP_SETGVAR:
|
||||
case JSOP_SETLOCAL:
|
||||
slot = (jsuint) pn->pn_slot;
|
||||
EMIT_UINT16_IMM_OP(pn->pn_op, slot);
|
||||
if (wantpop && js_Emit1(cx, cg, JSOP_POP) < 0)
|
||||
@ -4386,17 +4393,14 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
/*
|
||||
* The emitted code for a catch block looks like:
|
||||
*
|
||||
* [ popscope ] only if 2nd+ catch block
|
||||
* name Object
|
||||
* pushobj
|
||||
* newinit
|
||||
* [ leaveblock ] only if 2nd+ catch block
|
||||
* enterblock with SRC_CATCH
|
||||
* exception
|
||||
* initcatchvar <atom>
|
||||
* enterwith
|
||||
* setlocalpop <slot> or destructuring code
|
||||
* [< catchguard code >] if there's a catchguard
|
||||
* [ifeq <offset to next catch block>] " "
|
||||
* < catch block contents >
|
||||
* leavewith
|
||||
* leaveblock
|
||||
* goto <end of catch blocks> non-local; finally applies
|
||||
*
|
||||
* If there's no catch block without a catchguard, the last
|
||||
@ -4639,15 +4643,30 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
stmt = stmt->down;
|
||||
JS_ASSERT(stmt->type == STMT_TRY || stmt->type == STMT_FINALLY);
|
||||
|
||||
/*
|
||||
* Pick up the pending exception and bind it to the catch variable.
|
||||
* Inline BindNameToSlot, fixing up the slot by adding block depth.
|
||||
*/
|
||||
/* Pick up the pending exception and bind it to the catch variable. */
|
||||
if (js_Emit1(cx, cg, JSOP_EXCEPTION) < 0)
|
||||
return JS_FALSE;
|
||||
pn2 = pn->pn_kid1;
|
||||
pn2->pn_slot += OBJ_BLOCK_DEPTH(cx, ATOM_TO_OBJECT(atom));
|
||||
EMIT_UINT16_IMM_OP(JSOP_INITCATCHVAR, pn2->pn_slot);
|
||||
switch (pn2->pn_type) {
|
||||
#if JS_HAS_DESTRUCTURING
|
||||
case TOK_RB:
|
||||
case TOK_RC:
|
||||
if (!EmitDestructuringOps(cx, cg, JSOP_NOP, pn2))
|
||||
return JS_FALSE;
|
||||
if (js_Emit1(cx, cg, JSOP_POP) < 0)
|
||||
return JS_FALSE;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case TOK_NAME:
|
||||
/* Inline BindNameToSlot, adding block depth to pn2->pn_slot. */
|
||||
pn2->pn_slot += OBJ_BLOCK_DEPTH(cx, ATOM_TO_OBJECT(atom));
|
||||
EMIT_UINT16_IMM_OP(JSOP_SETLOCALPOP, pn2->pn_slot);
|
||||
break;
|
||||
|
||||
default:
|
||||
JS_ASSERT(0);
|
||||
}
|
||||
|
||||
/* Emit the guard expression, if there is one. */
|
||||
if (pn->pn_kid2) {
|
||||
@ -5022,7 +5041,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
return JS_FALSE;
|
||||
break;
|
||||
#endif
|
||||
default:;
|
||||
default:
|
||||
JS_ASSERT(0);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -5421,11 +5441,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
if (!js_EmitTree(cx, cg, pn->pn_expr))
|
||||
return JS_FALSE;
|
||||
|
||||
op = (pn->pn_extra & PNX_BLOCKEXPR)
|
||||
? JSOP_LEAVEBLOCKEXPR
|
||||
: JSOP_LEAVEBLOCK;
|
||||
EMIT_UINT16_IMM_OP(op, count);
|
||||
|
||||
/* Emit the JSOP_LEAVEBLOCK or JSOP_LEAVEBLOCKEXPR opcode. */
|
||||
EMIT_UINT16_IMM_OP(pn->pn_op, count);
|
||||
cg->stackDepth -= count;
|
||||
|
||||
ok = js_PopStatementCG(cx, cg);
|
||||
|
@ -5488,7 +5488,7 @@ interrupt:
|
||||
/* let the code at out try to catch the exception. */
|
||||
goto out;
|
||||
|
||||
BEGIN_CASE(JSOP_INITCATCHVAR)
|
||||
BEGIN_CASE(JSOP_SETLOCALPOP)
|
||||
/*
|
||||
* The stack must have a block with at least one local slot below
|
||||
* the exception object.
|
||||
@ -5497,7 +5497,7 @@ interrupt:
|
||||
slot = GET_UINT16(pc);
|
||||
JS_ASSERT(slot + 1 < (uintN)depth);
|
||||
fp->spbase[slot] = POP_OPND();
|
||||
END_CASE(JSOP_INITCATCHVAR)
|
||||
END_CASE(JSOP_SETLOCALPOP)
|
||||
|
||||
BEGIN_CASE(JSOP_INSTANCEOF)
|
||||
SAVE_SP_AND_PC(fp);
|
||||
|
@ -2017,6 +2017,9 @@ block_xdrObject(JSXDRState *xdr, JSObject **objp)
|
||||
JSBool ok;
|
||||
|
||||
cx = xdr->cx;
|
||||
#ifdef __GNUC__
|
||||
obj = NULL; /* quell GCC overwarning */
|
||||
#endif
|
||||
|
||||
atomMap = &xdr->script->atomMap;
|
||||
if (xdr->mode == JSXDR_ENCODE) {
|
||||
|
@ -1325,7 +1325,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
||||
|
||||
case SRC_DECL:
|
||||
/* This pop is at the end of the head of a let form. */
|
||||
pc += js_CodeSpec[JSOP_POP].length;
|
||||
pc += JSOP_POP_LENGTH;
|
||||
len = js_GetSrcNoteOffset(sn, 0);
|
||||
if (pc[len] == JSOP_LEAVEBLOCK) {
|
||||
js_printf(jp, "\tlet (%s) {\n", POP_STR());
|
||||
@ -1441,9 +1441,9 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
||||
pc += oplen;
|
||||
LOCAL_ASSERT(*pc == JSOP_EXCEPTION);
|
||||
pc += JSOP_EXCEPTION_LENGTH;
|
||||
LOCAL_ASSERT(*pc == JSOP_INITCATCHVAR);
|
||||
LOCAL_ASSERT(*pc == JSOP_SETLOCALPOP);
|
||||
i = GET_UINT16(pc);
|
||||
pc += JSOP_INITCATCHVAR_LENGTH;
|
||||
pc += JSOP_SETLOCALPOP_LENGTH;
|
||||
str = ATOM_TO_STRING(atomv[i]);
|
||||
rval = QuoteString(&ss->sprinter, str, 0);
|
||||
if (!rval) {
|
||||
|
@ -277,7 +277,7 @@ OPDEF(JSOP_NAMEDFUNOBJ, 129, "namedfunobj", NULL, 3, 0, 1, 13, JOF_CONST)
|
||||
* Like JSOP_SETLOCAL, but specialized to avoid requiring JSOP_POP immediately
|
||||
* after to throw away the exception value.
|
||||
*/
|
||||
OPDEF(JSOP_INITCATCHVAR,130, "initcatchvar",NULL, 3, 1, 0, 0, JOF_LOCAL|JOF_NAME|JOF_SET)
|
||||
OPDEF(JSOP_SETLOCALPOP, 130, "setlocalpop", NULL, 3, 1, 0, 0, JOF_LOCAL|JOF_NAME|JOF_SET)
|
||||
|
||||
/* ECMA-mandated parenthesization opcode, which nulls the reference base register, obj; see jsinterp.c. */
|
||||
OPDEF(JSOP_GROUP, 131, "group", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||
|
@ -2330,10 +2330,9 @@ PushLexicalScope(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
||||
|
||||
js_PushBlockScope(tc, stmtInfo, atom, -1);
|
||||
pn->pn_type = TOK_LEXICALSCOPE;
|
||||
pn->pn_op = JSOP_NOP;
|
||||
pn->pn_op = JSOP_LEAVEBLOCK;
|
||||
pn->pn_atom = atom;
|
||||
pn->pn_expr = NULL;
|
||||
pn->pn_extra = 0;
|
||||
return pn;
|
||||
}
|
||||
|
||||
@ -2382,6 +2381,11 @@ LetBlock(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, JSBool statement)
|
||||
pn1->pn_kid = pn;
|
||||
pn = pn1;
|
||||
|
||||
/*
|
||||
* Change pnblock's opcode to the variant that propagates the last
|
||||
* result down after popping the block, and clear statement.
|
||||
*/
|
||||
pnblock->pn_op = JSOP_LEAVEBLOCKEXPR;
|
||||
statement = JS_FALSE;
|
||||
}
|
||||
|
||||
@ -2391,8 +2395,6 @@ LetBlock(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, JSBool statement)
|
||||
|
||||
if (statement)
|
||||
MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_LET);
|
||||
else
|
||||
pnblock->pn_extra = PNX_BLOCKEXPR;
|
||||
|
||||
js_PopStatement(tc);
|
||||
return pn;
|
||||
@ -2892,11 +2894,11 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
* kid2 is the catch guard or null if no guard
|
||||
* kid3 is the catch block
|
||||
*
|
||||
* catch discriminant nodes are binary
|
||||
* atom is the receptacle
|
||||
* expr is the discriminant code
|
||||
* catch lvalue nodes are either:
|
||||
* TOK_NAME for a single identifier
|
||||
* TOK_RB or TOK_RC for a destructuring left-hand side
|
||||
*
|
||||
* finally nodes are unary (just the finally expression)
|
||||
* finally nodes are TOK_LC Statement lists.
|
||||
*/
|
||||
pn = NewParseNode(cx, ts, PN_TERNARY, tc);
|
||||
if (!pn)
|
||||
@ -2953,18 +2955,13 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
if (!pn2)
|
||||
return NULL;
|
||||
pnblock->pn_expr = pn2;
|
||||
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_CATCH);
|
||||
|
||||
/*
|
||||
* We use a PN_NAME for the variable node, in pn2->pn_kid1.
|
||||
* If there is a guard expression, it goes in pn2->pn_kid2.
|
||||
* Contrary to ECMA Ed. 3, the catch variable is lexically
|
||||
* scoped, not a property of a new Object instance. This is
|
||||
* an intentional change that anticipates ECMA Ed. 4.
|
||||
*/
|
||||
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_CATCH);
|
||||
MUST_MATCH_TOKEN(TOK_NAME, JSMSG_CATCH_IDENTIFIER);
|
||||
label = CURRENT_TOKEN(ts).t_atom;
|
||||
|
||||
data.pn = NULL;
|
||||
data.ts = ts;
|
||||
data.obj = ATOM_TO_OBJECT(pnblock->pn_atom);
|
||||
@ -2972,18 +2969,44 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
data.binder = BindLet;
|
||||
data.u.let.index = 0;
|
||||
data.u.let.overflow = JSMSG_TOO_MANY_CATCH_VARS;
|
||||
if (!data.binder(cx, &data, label, tc))
|
||||
return NULL;
|
||||
|
||||
pn3 = NewParseNode(cx, ts, PN_NAME, tc);
|
||||
if (!pn3)
|
||||
tt = js_GetToken(cx, ts);
|
||||
switch (tt) {
|
||||
#if JS_HAS_DESTRUCTURING
|
||||
case TOK_LB:
|
||||
case TOK_LC:
|
||||
pn3 = PrimaryExpr(cx, ts, tc, tt, JS_FALSE);
|
||||
if (!pn3)
|
||||
return NULL;
|
||||
|
||||
if (!CheckDestructuring(cx, &data, pn3, NULL, tc))
|
||||
return NULL;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case TOK_NAME:
|
||||
label = CURRENT_TOKEN(ts).t_atom;
|
||||
if (!data.binder(cx, &data, label, tc))
|
||||
return NULL;
|
||||
|
||||
pn3 = NewParseNode(cx, ts, PN_NAME, tc);
|
||||
if (!pn3)
|
||||
return NULL;
|
||||
pn3->pn_atom = label;
|
||||
pn3->pn_expr = NULL;
|
||||
pn3->pn_slot = 0;
|
||||
pn3->pn_attrs = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
js_ReportCompileErrorNumber(cx, ts,
|
||||
JSREPORT_TS | JSREPORT_ERROR,
|
||||
JSMSG_CATCH_IDENTIFIER);
|
||||
return NULL;
|
||||
pn3->pn_atom = label;
|
||||
pn3->pn_expr = NULL;
|
||||
pn3->pn_slot = 0;
|
||||
}
|
||||
|
||||
pn2->pn_kid1 = pn3;
|
||||
pn2->pn_kid2 = NULL;
|
||||
|
||||
#if JS_HAS_CATCH_GUARD
|
||||
/*
|
||||
* We use 'catch (x if x === 5)' (not 'catch (x : x === 5)')
|
||||
@ -3191,7 +3214,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
/* Check for a let statement or let expression. */
|
||||
if (js_PeekToken(cx, ts) == TOK_LP) {
|
||||
pn = LetBlock(cx, ts, tc, JS_TRUE);
|
||||
if (!pn || !(pn->pn_extra & PNX_BLOCKEXPR))
|
||||
if (!pn || pn->pn_op == JSOP_LEAVEBLOCK)
|
||||
return pn;
|
||||
/* Let expressions require automatic semicolon insertion. */
|
||||
break;
|
||||
@ -3264,7 +3287,6 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
pn1->pn_pos = tc->blockNode->pn_pos;
|
||||
pn1->pn_atom = atom;
|
||||
pn1->pn_expr = tc->blockNode;
|
||||
pn1->pn_extra = 0;
|
||||
tc->blockNode = pn1;
|
||||
}
|
||||
|
||||
@ -3526,7 +3548,7 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
pn2->pn_atom = atom;
|
||||
pn2->pn_expr = NULL;
|
||||
pn2->pn_slot = -1;
|
||||
pn2->pn_attrs = !let ? data.u.var.attrs : 0;
|
||||
pn2->pn_attrs = let ? 0 : data.u.var.attrs;
|
||||
PN_APPEND(pn, pn2);
|
||||
|
||||
if (js_MatchToken(cx, ts, TOK_ASSIGN)) {
|
||||
|
@ -106,8 +106,8 @@ JS_BEGIN_EXTERN_C
|
||||
* TOK_LEXICALSCOPE nodes, each with pn_expr pointing
|
||||
* to a TOK_CATCH node
|
||||
* pn_kid3: null or finally block
|
||||
* TOK_CATCH ternary pn_kid1: TOK_NAME, TOK_LB, or TOK_LC catch var node
|
||||
* (TOK_LB or TOK_LC if destructuring)
|
||||
* TOK_CATCH ternary pn_kid1: TOK_NAME, TOK_RB, or TOK_RC catch var node
|
||||
* (TOK_RB or TOK_RC if destructuring)
|
||||
* pn_kid2: null or the catch guard expression
|
||||
* pn_kid3: catch block statements
|
||||
* TOK_BREAK name pn_atom: label or null
|
||||
@ -245,7 +245,8 @@ JS_BEGIN_EXTERN_C
|
||||
*
|
||||
* Label Variant Members
|
||||
* ----- ------- -------
|
||||
* TOK_LEXICALSCOPE name pn_atom: block object
|
||||
* TOK_LEXICALSCOPE name pn_op: JSOP_LEAVEBLOCK or JSOP_LEAVEBLOCKEXPR
|
||||
* pn_atom: block object
|
||||
* pn_expr: block body
|
||||
* TOK_ARRAYCOMP list pn_head: list of pn_count (1 or 2) elements
|
||||
* if pn_count is 2, first element is #n=[...]
|
||||
@ -283,7 +284,7 @@ struct JSParseNode {
|
||||
JSParseNode *head; /* first node in list */
|
||||
JSParseNode **tail; /* ptr to ptr to last node in list */
|
||||
uint32 count; /* number of nodes in list */
|
||||
uint32 extra; /* extra comma flag for [1,2,,] */
|
||||
uint32 extra; /* extra flags, see below */
|
||||
} list;
|
||||
struct { /* ternary: if, for(;;), ?: */
|
||||
JSParseNode *kid1; /* condition, discriminant, etc. */
|
||||
@ -350,8 +351,7 @@ struct JSParseNode {
|
||||
which is left kid of TOK_FOR */
|
||||
#define PNX_ENDCOMMA 0x10 /* array literal has comma at end */
|
||||
#define PNX_XMLROOT 0x20 /* top-most node in XML literal tree */
|
||||
#define PNX_BLOCKEXPR 0x40 /* this block is an expression */
|
||||
#define PNX_GROUPINIT 0x80 /* var [a, b] = [c, d]; unit list */
|
||||
#define PNX_GROUPINIT 0x40 /* var [a, b] = [c, d]; unit list */
|
||||
|
||||
/*
|
||||
* Move pn2 into pn, preserving pn->pn_pos and pn->pn_offset and handing off
|
||||
|
Loading…
Reference in New Issue
Block a user