зеркало из https://github.com/mozilla/gecko-dev.git
Destructuring decompilation (346642, anticipating r=mrbkap).
This commit is contained in:
Родитель
4975edd6b9
Коммит
9ab0984ab2
175
js/src/jsemit.c
175
js/src/jsemit.c
|
@ -2123,7 +2123,9 @@ CheckSideEffects(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
||||||
case PN_LIST:
|
case PN_LIST:
|
||||||
if (pn->pn_type == TOK_NEW ||
|
if (pn->pn_type == TOK_NEW ||
|
||||||
pn->pn_type == TOK_LP ||
|
pn->pn_type == TOK_LP ||
|
||||||
pn->pn_type == TOK_LB) {
|
pn->pn_type == TOK_LB ||
|
||||||
|
pn->pn_type == TOK_RB ||
|
||||||
|
pn->pn_type == TOK_RC) {
|
||||||
/*
|
/*
|
||||||
* All invocation operations (construct: TOK_NEW, call: TOK_LP)
|
* All invocation operations (construct: TOK_NEW, call: TOK_LP)
|
||||||
* are presumed to be useful, because they may have side effects
|
* are presumed to be useful, because they may have side effects
|
||||||
|
@ -2134,6 +2136,10 @@ CheckSideEffects(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
||||||
* to be useful because each index operation could invoke a getter
|
* to be useful because each index operation could invoke a getter
|
||||||
* (the JSOP_ARGUMENTS special case below, in the PN_BINARY case,
|
* (the JSOP_ARGUMENTS special case below, in the PN_BINARY case,
|
||||||
* does not apply here: arguments[i][j] might invoke a getter).
|
* does not apply here: arguments[i][j] might invoke a getter).
|
||||||
|
*
|
||||||
|
* Array and object initializers (TOK_RB and TOK_RC lists) must be
|
||||||
|
* considered useful, because they are sugar for constructor calls
|
||||||
|
* (to Array and Object, respectively).
|
||||||
*/
|
*/
|
||||||
*answer = JS_TRUE;
|
*answer = JS_TRUE;
|
||||||
} else {
|
} else {
|
||||||
|
@ -2425,9 +2431,9 @@ EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
|
||||||
/*
|
/*
|
||||||
* Set left and right so pn appears to be a TOK_LB node, instead
|
* Set left and right so pn appears to be a TOK_LB node, instead
|
||||||
* of a TOK_DOT node. See the TOK_FOR/IN case in js_EmitTree, and
|
* of a TOK_DOT node. See the TOK_FOR/IN case in js_EmitTree, and
|
||||||
* EmitDestructuring nearer below. In the destructuring case, the
|
* EmitDestructuringOps nearer below. In the destructuring case,
|
||||||
* base expression (pn_expr) of the name may be null, which means
|
* the base expression (pn_expr) of the name may be null, which
|
||||||
* we have to emit a JSOP_BINDNAME.
|
* means we have to emit a JSOP_BINDNAME.
|
||||||
*/
|
*/
|
||||||
left = pn->pn_expr;
|
left = pn->pn_expr;
|
||||||
if (!left) {
|
if (!left) {
|
||||||
|
@ -2440,7 +2446,10 @@ EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
|
||||||
}
|
}
|
||||||
right = &rtmp;
|
right = &rtmp;
|
||||||
right->pn_type = TOK_STRING;
|
right->pn_type = TOK_STRING;
|
||||||
right->pn_op = JSOP_STRING;
|
JS_ASSERT(ATOM_IS_STRING(pn->pn_atom));
|
||||||
|
right->pn_op = js_IsIdentifier(ATOM_TO_STRING(pn->pn_atom))
|
||||||
|
? JSOP_QNAMEPART
|
||||||
|
: JSOP_STRING;
|
||||||
right->pn_arity = PN_NULLARY;
|
right->pn_arity = PN_NULLARY;
|
||||||
right->pn_pos = pn->pn_pos;
|
right->pn_pos = pn->pn_pos;
|
||||||
right->pn_atom = pn->pn_atom;
|
right->pn_atom = pn->pn_atom;
|
||||||
|
@ -3326,7 +3335,6 @@ EmitDestructuringOpsHelper(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
{
|
{
|
||||||
jsuint index;
|
jsuint index;
|
||||||
JSParseNode *pn2, *pn3;
|
JSParseNode *pn2, *pn3;
|
||||||
ptrdiff_t top;
|
|
||||||
JSBool doElemOp;
|
JSBool doElemOp;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -3336,19 +3344,17 @@ EmitDestructuringOpsHelper(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
JS_ASSERT(pn->pn_type == TOK_RB || pn->pn_type == TOK_RC);
|
JS_ASSERT(pn->pn_type == TOK_RB || pn->pn_type == TOK_RC);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (pn->pn_count == 0) {
|
||||||
|
/* Emit a DUP;POP sequence for the decompiler. */
|
||||||
|
return js_Emit1(cx, cg, JSOP_DUP) >= 0 &&
|
||||||
|
js_Emit1(cx, cg, JSOP_POP) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
index = 0;
|
index = 0;
|
||||||
for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
|
for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
|
||||||
/* Nullary comma node makes a hole in the array destructurer. */
|
|
||||||
if (pn2->pn_type == TOK_COMMA && pn2->pn_arity == PN_NULLARY) {
|
|
||||||
JS_ASSERT(pn->pn_type == TOK_RB);
|
|
||||||
++index;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Duplicate the value being destructured to use as a reference base.
|
* Duplicate the value being destructured to use as a reference base.
|
||||||
*/
|
*/
|
||||||
top = CG_OFFSET(cg);
|
|
||||||
if (js_Emit1(cx, cg, JSOP_DUP) < 0)
|
if (js_Emit1(cx, cg, JSOP_DUP) < 0)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
|
@ -3373,10 +3379,8 @@ EmitDestructuringOpsHelper(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
* annotate the index op with SRC_INITPROP so we know we are
|
* annotate the index op with SRC_INITPROP so we know we are
|
||||||
* not decompiling an array initialiser.
|
* not decompiling an array initialiser.
|
||||||
*/
|
*/
|
||||||
if (pn->pn_type == TOK_RC &&
|
if (js_NewSrcNote(cx, cg, SRC_INITPROP) < 0)
|
||||||
js_NewSrcNote(cx, cg, SRC_INITPROP) < 0) {
|
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
|
||||||
if (!EmitNumberOp(cx, pn3->pn_dval, cg))
|
if (!EmitNumberOp(cx, pn3->pn_dval, cg))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
} else {
|
} else {
|
||||||
|
@ -3395,15 +3399,21 @@ EmitDestructuringOpsHelper(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
* that value on top of the value being destructured, so the stack
|
* that value on top of the value being destructured, so the stack
|
||||||
* is one deeper than when we started.
|
* is one deeper than when we started.
|
||||||
*/
|
*/
|
||||||
if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0)
|
|
||||||
return JS_FALSE;
|
|
||||||
if (js_Emit1(cx, cg, JSOP_GETELEM) < 0)
|
if (js_Emit1(cx, cg, JSOP_GETELEM) < 0)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
JS_ASSERT(cg->stackDepth == stackDepth + 1);
|
JS_ASSERT(cg->stackDepth == stackDepth + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!EmitDestructuringLHS(cx, cg, pn3, JS_TRUE))
|
/* Nullary comma node makes a hole in the array destructurer. */
|
||||||
return JS_FALSE;
|
if (pn3->pn_type == TOK_COMMA && pn3->pn_arity == PN_NULLARY) {
|
||||||
|
JS_ASSERT(pn->pn_type == TOK_RB);
|
||||||
|
JS_ASSERT(pn2 == pn3);
|
||||||
|
if (js_Emit1(cx, cg, JSOP_POP) < 0)
|
||||||
|
return JS_FALSE;
|
||||||
|
} else {
|
||||||
|
if (!EmitDestructuringLHS(cx, cg, pn3, JS_TRUE))
|
||||||
|
return JS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
JS_ASSERT(cg->stackDepth == stackDepth);
|
JS_ASSERT(cg->stackDepth == stackDepth);
|
||||||
++index;
|
++index;
|
||||||
|
@ -3412,35 +3422,33 @@ EmitDestructuringOpsHelper(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ptrdiff_t
|
||||||
|
OpToDeclType(JSOp op)
|
||||||
|
{
|
||||||
|
switch (op) {
|
||||||
|
case JSOP_NOP:
|
||||||
|
return SRC_DECL_LET;
|
||||||
|
case JSOP_DEFCONST:
|
||||||
|
return SRC_DECL_CONST;
|
||||||
|
case JSOP_DEFVAR:
|
||||||
|
return SRC_DECL_VAR;
|
||||||
|
default:
|
||||||
|
return SRC_DECL_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static JSBool
|
static JSBool
|
||||||
EmitDestructuringOps(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp,
|
EmitDestructuringOps(JSContext *cx, JSCodeGenerator *cg, JSOp declOp,
|
||||||
JSParseNode *pn)
|
JSParseNode *pn)
|
||||||
{
|
{
|
||||||
ptrdiff_t declType;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we're called from a variable declaration, help the decompiler by
|
* If we're called from a variable declaration, help the decompiler by
|
||||||
* annotating the first JSOP_DUP that EmitDestructuringOpsHelper emits.
|
* annotating the first JSOP_DUP that EmitDestructuringOpsHelper emits.
|
||||||
* The parser ensures that a destructuring initialiser has at least one
|
* If the destructuring initialiser is empty, our helper will emit a
|
||||||
* element lvalue, so we know that JSOP_DUP will be emitted.
|
* JSOP_DUP followed by a JSOP_POP for the decompiler.
|
||||||
*/
|
*/
|
||||||
switch (prologOp) {
|
if (js_NewSrcNote2(cx, cg, SRC_DESTRUCT, OpToDeclType(declOp)) < 0)
|
||||||
case JSOP_DEFCONST:
|
return JS_FALSE;
|
||||||
declType = SRC_DECL_CONST;
|
|
||||||
goto emit_decl_note;
|
|
||||||
|
|
||||||
case JSOP_DEFVAR:
|
|
||||||
declType = SRC_DECL_VAR;
|
|
||||||
emit_decl_note:
|
|
||||||
if (js_NewSrcNote2(cx, cg, SRC_DECL, declType) < 0)
|
|
||||||
return JS_FALSE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (js_NewSrcNote(cx, cg, SRC_ASSIGNOP) < 0)
|
|
||||||
return JS_FALSE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Call our recursive helper to emit the destructuring assignments and
|
* Call our recursive helper to emit the destructuring assignments and
|
||||||
|
@ -3450,8 +3458,8 @@ EmitDestructuringOps(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp,
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSBool
|
static JSBool
|
||||||
EmitGroupAssignment(JSContext *cx, JSCodeGenerator *cg, JSParseNode *lhs,
|
EmitGroupAssignment(JSContext *cx, JSCodeGenerator *cg, JSOp declOp,
|
||||||
JSParseNode *rhs)
|
JSParseNode *lhs, JSParseNode *rhs)
|
||||||
{
|
{
|
||||||
jsuint depth, limit, slot;
|
jsuint depth, limit, slot;
|
||||||
JSParseNode *pn;
|
JSParseNode *pn;
|
||||||
|
@ -3475,6 +3483,9 @@ EmitGroupAssignment(JSContext *cx, JSCodeGenerator *cg, JSParseNode *lhs,
|
||||||
++limit;
|
++limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (js_NewSrcNote2(cx, cg, SRC_GROUPASSIGN, OpToDeclType(declOp)) < 0)
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
slot = depth;
|
slot = depth;
|
||||||
for (pn = lhs->pn_head; pn; pn = pn->pn_next) {
|
for (pn = lhs->pn_head; pn; pn = pn->pn_next) {
|
||||||
if (pn->pn_type != TOK_COMMA) {
|
if (pn->pn_type != TOK_COMMA) {
|
||||||
|
@ -3501,8 +3512,8 @@ EmitGroupAssignment(JSContext *cx, JSCodeGenerator *cg, JSParseNode *lhs,
|
||||||
* we set *pop to JSOP_NOP so callers can veto emitting pn followed by a pop.
|
* we set *pop to JSOP_NOP so callers can veto emitting pn followed by a pop.
|
||||||
*/
|
*/
|
||||||
static JSBool
|
static JSBool
|
||||||
MaybeEmitGroupAssignment(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
|
MaybeEmitGroupAssignment(JSContext *cx, JSCodeGenerator *cg, JSOp declOp,
|
||||||
JSOp *pop)
|
JSParseNode *pn, JSOp *pop)
|
||||||
{
|
{
|
||||||
JSParseNode *lhs, *rhs;
|
JSParseNode *lhs, *rhs;
|
||||||
|
|
||||||
|
@ -3511,7 +3522,7 @@ MaybeEmitGroupAssignment(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
|
||||||
lhs = pn->pn_left;
|
lhs = pn->pn_left;
|
||||||
rhs = pn->pn_right;
|
rhs = pn->pn_right;
|
||||||
if (lhs->pn_type == TOK_RB && rhs->pn_type == TOK_RB) {
|
if (lhs->pn_type == TOK_RB && rhs->pn_type == TOK_RB) {
|
||||||
if (!EmitGroupAssignment(cx, cg, lhs, rhs))
|
if (!EmitGroupAssignment(cx, cg, declOp, lhs, rhs))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
*pop = JSOP_NOP;
|
*pop = JSOP_NOP;
|
||||||
}
|
}
|
||||||
|
@ -3553,7 +3564,7 @@ EmitVariables(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
|
||||||
*/
|
*/
|
||||||
tc = &cg->treeContext;
|
tc = &cg->treeContext;
|
||||||
let = (pn->pn_op == JSOP_NOP);
|
let = (pn->pn_op == JSOP_NOP);
|
||||||
forInVar = (pn->pn_extra & PNX_FORINVAR);
|
forInVar = (pn->pn_extra & PNX_FORINVAR) != 0;
|
||||||
#if JS_HAS_BLOCK_SCOPE
|
#if JS_HAS_BLOCK_SCOPE
|
||||||
forInLet = let && forInVar;
|
forInLet = let && forInVar;
|
||||||
popScope = (inLetHead || (let && (tc->flags & TCF_IN_FOR_INIT)));
|
popScope = (inLetHead || (let && (tc->flags & TCF_IN_FOR_INIT)));
|
||||||
|
@ -3588,15 +3599,20 @@ EmitVariables(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
|
||||||
* the head of the loop.
|
* the head of the loop.
|
||||||
*/
|
*/
|
||||||
JS_ASSERT(pn2->pn_type == TOK_ASSIGN);
|
JS_ASSERT(pn2->pn_type == TOK_ASSIGN);
|
||||||
if (pn->pn_count == 1) {
|
if (pn->pn_count == 1 && !forInLet) {
|
||||||
/*
|
/*
|
||||||
* If this is the only destructuring assignment in the list,
|
* If this is the only destructuring assignment in the list,
|
||||||
* try to optimize to a group assignment.
|
* try to optimize to a group assignment. If we're in a let
|
||||||
|
* head, pass JSOP_POP rather than the pseudo-prolog JSOP_NOP
|
||||||
|
* in pn->pn_op, to suppress a second (and misplaced) 'let'.
|
||||||
*/
|
*/
|
||||||
JS_ASSERT(noteIndex < 0 && !pn2->pn_next);
|
JS_ASSERT(noteIndex < 0 && !pn2->pn_next);
|
||||||
op = JSOP_POP;
|
op = JSOP_POP;
|
||||||
if (!MaybeEmitGroupAssignment(cx, cg, pn2, &op))
|
if (!MaybeEmitGroupAssignment(cx, cg,
|
||||||
|
inLetHead ? JSOP_POP : pn->pn_op,
|
||||||
|
pn2, &op)) {
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
}
|
||||||
if (op == JSOP_NOP) {
|
if (op == JSOP_NOP) {
|
||||||
pn->pn_extra = (pn->pn_extra & ~PNX_POPVAR) | PNX_GROUPINIT;
|
pn->pn_extra = (pn->pn_extra & ~PNX_POPVAR) | PNX_GROUPINIT;
|
||||||
break;
|
break;
|
||||||
|
@ -3638,16 +3654,25 @@ EmitVariables(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
|
||||||
* This has the effect of hoisting the evaluation of i out of the
|
* This has the effect of hoisting the evaluation of i out of the
|
||||||
* for-in loop, without hoisting the let variables, which must of
|
* for-in loop, without hoisting the let variables, which must of
|
||||||
* course be scoped by the loop. Set PNX_POPVAR to cause JSOP_POP
|
* course be scoped by the loop. Set PNX_POPVAR to cause JSOP_POP
|
||||||
* to be emitted, just before the bottom of this function.
|
* to be emitted, just before returning from this function.
|
||||||
*/
|
*/
|
||||||
if (forInLet) {
|
if (forInVar) {
|
||||||
pn->pn_extra |= PNX_POPVAR;
|
pn->pn_extra |= PNX_POPVAR;
|
||||||
break;
|
if (forInLet)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!EmitDestructuringOps(cx, cg, pn->pn_op, pn3))
|
/*
|
||||||
|
* Veto pn->pn_op if inLetHead to avoid emitting a SRC_DESTRUCT
|
||||||
|
* that's redundant with respect to the SRC_DECL/SRC_DECL_LET that
|
||||||
|
* we will emit at the bottom of this function.
|
||||||
|
*/
|
||||||
|
if (!EmitDestructuringOps(cx, cg,
|
||||||
|
inLetHead ? JSOP_POP : pn->pn_op,
|
||||||
|
pn3)) {
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
}
|
||||||
goto emit_note_pop;
|
goto emit_note_pop;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -3794,7 +3819,8 @@ EmitVariables(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
|
||||||
*headNoteIndex = js_NewSrcNote(cx, cg, SRC_DECL);
|
*headNoteIndex = js_NewSrcNote(cx, cg, SRC_DECL);
|
||||||
if (*headNoteIndex < 0)
|
if (*headNoteIndex < 0)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
JS_ASSERT(pn->pn_extra & PNX_POPVAR);
|
if (!(pn->pn_extra & PNX_POPVAR))
|
||||||
|
return js_Emit1(cx, cg, JSOP_NOP) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return !(pn->pn_extra & PNX_POPVAR) || js_Emit1(cx, cg, JSOP_POP) >= 0;
|
return !(pn->pn_extra & PNX_POPVAR) || js_Emit1(cx, cg, JSOP_POP) >= 0;
|
||||||
|
@ -4214,9 +4240,18 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
if (js_Emit1(cx, cg, pn->pn_op) < 0)
|
if (js_Emit1(cx, cg, pn->pn_op) < 0)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
/* Compile a JSOP_FOR* bytecode based on the left hand side. */
|
/*
|
||||||
|
* Compile a JSOP_FOR* bytecode based on the left hand side.
|
||||||
|
*
|
||||||
|
* Initialize op to JSOP_SETNAME in case of |for ([a, b] in o)...|
|
||||||
|
* or similar, to signify assignment, rather than declaration, to
|
||||||
|
* the decompiler. EmitDestructuringOps takes a prolog bytecode
|
||||||
|
* parameter and emits the appropriate source note, defaulting to
|
||||||
|
* assignment, so JSOP_SETNAME is not critical here; many similar
|
||||||
|
* ops could be used -- just not JSOP_NOP (which means 'let').
|
||||||
|
*/
|
||||||
emitIFEQ = JS_TRUE;
|
emitIFEQ = JS_TRUE;
|
||||||
op = JSOP_NOP;
|
op = JSOP_SETNAME;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
#if JS_HAS_BLOCK_SCOPE
|
#if JS_HAS_BLOCK_SCOPE
|
||||||
case TOK_LET:
|
case TOK_LET:
|
||||||
|
@ -4400,7 +4435,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
#if JS_HAS_DESTRUCTURING
|
#if JS_HAS_DESTRUCTURING
|
||||||
pn3 = pn2->pn_kid1;
|
pn3 = pn2->pn_kid1;
|
||||||
if (pn3->pn_type == TOK_ASSIGN &&
|
if (pn3->pn_type == TOK_ASSIGN &&
|
||||||
!MaybeEmitGroupAssignment(cx, cg, pn3, &op)) {
|
!MaybeEmitGroupAssignment(cx, cg, op, pn3, &op)) {
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -4472,7 +4507,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
op = JSOP_POP;
|
op = JSOP_POP;
|
||||||
#if JS_HAS_DESTRUCTURING
|
#if JS_HAS_DESTRUCTURING
|
||||||
if (pn3->pn_type == TOK_ASSIGN &&
|
if (pn3->pn_type == TOK_ASSIGN &&
|
||||||
!MaybeEmitGroupAssignment(cx, cg, pn3, &op)) {
|
!MaybeEmitGroupAssignment(cx, cg, op, pn3, &op)) {
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -5043,6 +5078,16 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
ok = js_PopStatementCG(cx, cg);
|
ok = js_PopStatementCG(cx, cg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TOK_BODY:
|
||||||
|
JS_ASSERT(pn->pn_arity == PN_LIST);
|
||||||
|
js_PushStatement(&cg->treeContext, &stmtInfo, STMT_BODY, top);
|
||||||
|
for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
|
||||||
|
if (!js_EmitTree(cx, cg, pn2))
|
||||||
|
return JS_FALSE;
|
||||||
|
}
|
||||||
|
ok = js_PopStatementCG(cx, cg);
|
||||||
|
break;
|
||||||
|
|
||||||
case TOK_SEMI:
|
case TOK_SEMI:
|
||||||
pn2 = pn->pn_kid;
|
pn2 = pn->pn_kid;
|
||||||
if (pn2) {
|
if (pn2) {
|
||||||
|
@ -5083,7 +5128,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
#if JS_HAS_DESTRUCTURING
|
#if JS_HAS_DESTRUCTURING
|
||||||
if (!wantval &&
|
if (!wantval &&
|
||||||
pn2->pn_type == TOK_ASSIGN &&
|
pn2->pn_type == TOK_ASSIGN &&
|
||||||
!MaybeEmitGroupAssignment(cx, cg, pn2, &op)) {
|
!MaybeEmitGroupAssignment(cx, cg, op, pn2, &op)) {
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -5323,7 +5368,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
#if JS_HAS_DESTRUCTURING
|
#if JS_HAS_DESTRUCTURING
|
||||||
case TOK_RB:
|
case TOK_RB:
|
||||||
case TOK_RC:
|
case TOK_RC:
|
||||||
if (!EmitDestructuringOps(cx, cg, JSOP_NOP, pn2))
|
if (!EmitDestructuringOps(cx, cg, JSOP_SETNAME, pn2))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
@ -6274,7 +6319,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX get rid of offsetBias altogether, it's used only by SRC_FOR */
|
/* XXX get rid of offsetBias, it's used only by SRC_FOR and SRC_DECL */
|
||||||
JS_FRIEND_DATA(JSSrcNoteSpec) js_SrcNoteSpec[] = {
|
JS_FRIEND_DATA(JSSrcNoteSpec) js_SrcNoteSpec[] = {
|
||||||
{"null", 0, 0, 0},
|
{"null", 0, 0, 0},
|
||||||
{"if", 0, 0, 0},
|
{"if", 0, 0, 0},
|
||||||
|
@ -6282,7 +6327,7 @@ JS_FRIEND_DATA(JSSrcNoteSpec) js_SrcNoteSpec[] = {
|
||||||
{"while", 1, 0, 1},
|
{"while", 1, 0, 1},
|
||||||
{"for", 3, 1, 1},
|
{"for", 3, 1, 1},
|
||||||
{"continue", 0, 0, 0},
|
{"continue", 0, 0, 0},
|
||||||
{"decl", 1, 0, 1},
|
{"decl", 1, 1, 1},
|
||||||
{"pcdelta", 1, 0, 1},
|
{"pcdelta", 1, 0, 1},
|
||||||
{"assignop", 0, 0, 0},
|
{"assignop", 0, 0, 0},
|
||||||
{"cond", 1, 0, 1},
|
{"cond", 1, 0, 1},
|
||||||
|
|
|
@ -65,6 +65,8 @@ typedef enum JSStmtType {
|
||||||
STMT_LABEL, /* labeled statement: L: s */
|
STMT_LABEL, /* labeled statement: L: s */
|
||||||
STMT_IF, /* if (then) statement */
|
STMT_IF, /* if (then) statement */
|
||||||
STMT_ELSE, /* else clause of if statement */
|
STMT_ELSE, /* else clause of if statement */
|
||||||
|
STMT_BODY, /* synthetic body of function with
|
||||||
|
destructuring formal parameters */
|
||||||
STMT_BLOCK, /* compound statement: { s1[;... sN] } */
|
STMT_BLOCK, /* compound statement: { s1[;... sN] } */
|
||||||
STMT_SWITCH, /* switch statement */
|
STMT_SWITCH, /* switch statement */
|
||||||
STMT_WITH, /* with statement */
|
STMT_WITH, /* with statement */
|
||||||
|
@ -81,15 +83,19 @@ typedef enum JSStmtType {
|
||||||
#define STMT_TYPE_IN_RANGE(t,b,e) ((uint)((t) - (b)) <= (uintN)((e) - (b)))
|
#define STMT_TYPE_IN_RANGE(t,b,e) ((uint)((t) - (b)) <= (uintN)((e) - (b)))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
* A comment on the encoding of the JSStmtType enum and type-testing macros:
|
||||||
|
*
|
||||||
* STMT_TYPE_MAYBE_SCOPE tells whether a statement type is always, or may
|
* STMT_TYPE_MAYBE_SCOPE tells whether a statement type is always, or may
|
||||||
* become, a lexical scope. It therefore includes block and switch (the two
|
* become, a lexical scope. It therefore includes block and switch (the two
|
||||||
* "maybe" scopes) and excludes with (which has dynamic scope, pending the
|
* low-numbered "maybe" scope types) and excludes with (with has dynamic scope
|
||||||
* "reformed with" in ES4/JS2). It includes all try-catch-finally types.
|
* pending the "reformed with" in ES4/JS2). It includes all try-catch-finally
|
||||||
|
* types, which are high-numbered maybe-scope types.
|
||||||
*
|
*
|
||||||
* STMT_TYPE_LINKS_SCOPE tells whether a JSStmtInfo of the given type eagerly
|
* STMT_TYPE_LINKS_SCOPE tells whether a JSStmtInfo of the given type eagerly
|
||||||
* links to other scoping statement info records. It excludes the two "maybe"
|
* links to other scoping statement info records. It excludes the two early
|
||||||
* types, block and switch, as well as the try and both finally types, since
|
* "maybe" types, block and switch, as well as the try and both finally types,
|
||||||
* try, etc., don't need block scope unless they contain let declarations.
|
* since try and the other trailing maybe-scope types don't need block scope
|
||||||
|
* unless they contain let declarations.
|
||||||
*
|
*
|
||||||
* We treat with as a static scope because it prevents lexical binding from
|
* We treat with as a static scope because it prevents lexical binding from
|
||||||
* continuing further up the static scope chain. With the "reformed with"
|
* continuing further up the static scope chain. With the "reformed with"
|
||||||
|
@ -523,9 +529,12 @@ typedef enum JSSrcNoteType {
|
||||||
also used on JSOP_ENDINIT if extra comma
|
also used on JSOP_ENDINIT if extra comma
|
||||||
at end of array literal: [1,2,,] */
|
at end of array literal: [1,2,,] */
|
||||||
SRC_DECL = 6, /* type of a declaration (var, const, let*) */
|
SRC_DECL = 6, /* type of a declaration (var, const, let*) */
|
||||||
|
SRC_DESTRUCT = 6, /* JSOP_DUP starting a destructuring assignment
|
||||||
|
operation, with SRC_DECL_* offset operand */
|
||||||
SRC_PCDELTA = 7, /* distance forward from comma-operator to
|
SRC_PCDELTA = 7, /* distance forward from comma-operator to
|
||||||
next POP, or from CONDSWITCH to first CASE
|
next POP, or from CONDSWITCH to first CASE
|
||||||
opcode, etc. -- always a forward delta */
|
opcode, etc. -- always a forward delta */
|
||||||
|
SRC_GROUPASSIGN = 7, /* SRC_DESTRUCT variant for [a, b] = [c, d] */
|
||||||
SRC_ASSIGNOP = 8, /* += or another assign-op follows */
|
SRC_ASSIGNOP = 8, /* += or another assign-op follows */
|
||||||
SRC_COND = 9, /* JSOP_IFEQ is from conditional ?: operator */
|
SRC_COND = 9, /* JSOP_IFEQ is from conditional ?: operator */
|
||||||
SRC_BRACE = 10, /* mandatory brace, for scope or to avoid
|
SRC_BRACE = 10, /* mandatory brace, for scope or to avoid
|
||||||
|
@ -559,11 +568,13 @@ typedef enum JSSrcNoteType {
|
||||||
* instruction, so can be used to denote distinct declaration syntaxes to the
|
* instruction, so can be used to denote distinct declaration syntaxes to the
|
||||||
* decompiler.
|
* decompiler.
|
||||||
*
|
*
|
||||||
* NB: the var_prefix array in jsopcode.c depends on these dense indexes.
|
* NB: the var_prefix array in jsopcode.c depends on these dense indexes from
|
||||||
|
* SRC_DECL_VAR through SRC_DECL_LET.
|
||||||
*/
|
*/
|
||||||
#define SRC_DECL_VAR 0
|
#define SRC_DECL_VAR 0
|
||||||
#define SRC_DECL_CONST 1
|
#define SRC_DECL_CONST 1
|
||||||
#define SRC_DECL_LET 2
|
#define SRC_DECL_LET 2
|
||||||
|
#define SRC_DECL_NONE 3
|
||||||
|
|
||||||
#define SN_TYPE_BITS 5
|
#define SN_TYPE_BITS 5
|
||||||
#define SN_DELTA_BITS 3
|
#define SN_DELTA_BITS 3
|
||||||
|
|
|
@ -5330,7 +5330,6 @@ interrupt:
|
||||||
* Getters and setters are just like watchpoints from an access
|
* Getters and setters are just like watchpoints from an access
|
||||||
* control point of view.
|
* control point of view.
|
||||||
*/
|
*/
|
||||||
SAVE_SP_AND_PC(fp);
|
|
||||||
ok = OBJ_CHECK_ACCESS(cx, obj, id, JSACC_WATCH, &rtmp, &attrs);
|
ok = OBJ_CHECK_ACCESS(cx, obj, id, JSACC_WATCH, &rtmp, &attrs);
|
||||||
if (!ok)
|
if (!ok)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -80,7 +80,7 @@
|
||||||
* 14 *, /, % JSOP_MUL, JSOP_DIV, JSOP_MOD
|
* 14 *, /, % JSOP_MUL, JSOP_DIV, JSOP_MOD
|
||||||
* 15 !, ~, etc. JSOP_NOT, JSOP_BITNOT, etc.
|
* 15 !, ~, etc. JSOP_NOT, JSOP_BITNOT, etc.
|
||||||
* 16 0, function(){} etc. JSOP_ZERO, JSOP_ANONFUNOBJ, etc.
|
* 16 0, function(){} etc. JSOP_ZERO, JSOP_ANONFUNOBJ, etc.
|
||||||
* 17 new JSOP_NEW
|
* 17 delete, new JSOP_DEL*, JSOP_NEW
|
||||||
* 18 x.y, f(), etc. JSOP_GETPROP, JSOP_CALL, etc.
|
* 18 x.y, f(), etc. JSOP_GETPROP, JSOP_CALL, etc.
|
||||||
* 19 x, null, etc. JSOP_NAME, JSOP_NULL, etc.
|
* 19 x, null, etc. JSOP_NAME, JSOP_NULL, etc.
|
||||||
*
|
*
|
||||||
|
@ -139,9 +139,9 @@ OPDEF(JSOP_NOT, 32, "not", "!", 1, 1, 1, 15, JOF_BYTE|J
|
||||||
OPDEF(JSOP_BITNOT, 33, "bitnot", "~", 1, 1, 1, 15, JOF_BYTE)
|
OPDEF(JSOP_BITNOT, 33, "bitnot", "~", 1, 1, 1, 15, JOF_BYTE)
|
||||||
OPDEF(JSOP_NEG, 34, "neg", "- ", 1, 1, 1, 15, JOF_BYTE)
|
OPDEF(JSOP_NEG, 34, "neg", "- ", 1, 1, 1, 15, JOF_BYTE)
|
||||||
OPDEF(JSOP_NEW, 35, js_new_str, NULL, 3, -1, 1, 17, JOF_UINT16)
|
OPDEF(JSOP_NEW, 35, js_new_str, NULL, 3, -1, 1, 17, JOF_UINT16)
|
||||||
OPDEF(JSOP_DELNAME, 36, "delname", NULL, 3, 0, 1, 15, JOF_CONST|JOF_NAME|JOF_DEL)
|
OPDEF(JSOP_DELNAME, 36, "delname", NULL, 3, 0, 1, 17, JOF_CONST|JOF_NAME|JOF_DEL)
|
||||||
OPDEF(JSOP_DELPROP, 37, "delprop", NULL, 3, 1, 1, 18, JOF_CONST|JOF_PROP|JOF_DEL)
|
OPDEF(JSOP_DELPROP, 37, "delprop", NULL, 3, 1, 1, 17, JOF_CONST|JOF_PROP|JOF_DEL)
|
||||||
OPDEF(JSOP_DELELEM, 38, "delelem", NULL, 1, 2, 1, 18, JOF_BYTE |JOF_ELEM|JOF_DEL)
|
OPDEF(JSOP_DELELEM, 38, "delelem", NULL, 1, 2, 1, 17, JOF_BYTE |JOF_ELEM|JOF_DEL)
|
||||||
OPDEF(JSOP_TYPEOF, 39, js_typeof_str,NULL, 1, 1, 1, 15, JOF_BYTE|JOF_DETECTING)
|
OPDEF(JSOP_TYPEOF, 39, js_typeof_str,NULL, 1, 1, 1, 15, JOF_BYTE|JOF_DETECTING)
|
||||||
OPDEF(JSOP_VOID, 40, js_void_str, NULL, 1, 1, 1, 15, JOF_BYTE)
|
OPDEF(JSOP_VOID, 40, js_void_str, NULL, 1, 1, 1, 15, JOF_BYTE)
|
||||||
OPDEF(JSOP_INCNAME, 41, "incname", NULL, 3, 0, 1, 15, JOF_CONST|JOF_NAME|JOF_INC)
|
OPDEF(JSOP_INCNAME, 41, "incname", NULL, 3, 0, 1, 15, JOF_CONST|JOF_NAME|JOF_INC)
|
||||||
|
@ -239,7 +239,7 @@ OPDEF(JSOP_FORELEM, 106,"forelem", NULL, 1, 2, 4, 18, JOF_BYTE |
|
||||||
OPDEF(JSOP_POP2, 107,"pop2", NULL, 1, 2, 0, 0, JOF_BYTE)
|
OPDEF(JSOP_POP2, 107,"pop2", NULL, 1, 2, 0, 0, JOF_BYTE)
|
||||||
|
|
||||||
/* ECMA-compliant assignment ops. */
|
/* ECMA-compliant assignment ops. */
|
||||||
OPDEF(JSOP_BINDNAME, 108,"bindname", NULL, 3, 0, 1, 3, JOF_CONST|JOF_NAME|JOF_SET|JOF_ASSIGNING)
|
OPDEF(JSOP_BINDNAME, 108,"bindname", NULL, 3, 0, 1, 0, JOF_CONST|JOF_NAME|JOF_SET|JOF_ASSIGNING)
|
||||||
OPDEF(JSOP_SETNAME, 109,"setname", NULL, 3, 2, 1, 3, JOF_CONST|JOF_NAME|JOF_SET|JOF_ASSIGNING|JOF_DETECTING)
|
OPDEF(JSOP_SETNAME, 109,"setname", NULL, 3, 2, 1, 3, JOF_CONST|JOF_NAME|JOF_SET|JOF_ASSIGNING|JOF_DETECTING)
|
||||||
|
|
||||||
/* Exception handling ops. */
|
/* Exception handling ops. */
|
||||||
|
@ -400,7 +400,7 @@ OPDEF(JSOP_XMLPI, 183,"xmlpi", NULL, 3, 1, 1, 19, JOF_CONST)
|
||||||
OPDEF(JSOP_GETMETHOD, 184,"getmethod", NULL, 3, 1, 1, 18, JOF_CONST|JOF_PROP)
|
OPDEF(JSOP_GETMETHOD, 184,"getmethod", NULL, 3, 1, 1, 18, JOF_CONST|JOF_PROP)
|
||||||
OPDEF(JSOP_GETFUNNS, 185,"getfunns", NULL, 1, 0, 1, 19, JOF_BYTE)
|
OPDEF(JSOP_GETFUNNS, 185,"getfunns", NULL, 1, 0, 1, 19, JOF_BYTE)
|
||||||
OPDEF(JSOP_FOREACH, 186,"foreach", NULL, 1, 0, 0, 0, JOF_BYTE)
|
OPDEF(JSOP_FOREACH, 186,"foreach", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||||
OPDEF(JSOP_DELDESC, 187,"deldesc", NULL, 1, 2, 1, 18, JOF_BYTE |JOF_ELEM|JOF_DEL)
|
OPDEF(JSOP_DELDESC, 187,"deldesc", NULL, 1, 2, 1, 17, JOF_BYTE |JOF_ELEM|JOF_DEL)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Opcodes for extended literal addressing, using unsigned 24-bit immediate
|
* Opcodes for extended literal addressing, using unsigned 24-bit immediate
|
||||||
|
|
112
js/src/jsparse.c
112
js/src/jsparse.c
|
@ -960,6 +960,22 @@ BindLocalVariable(JSContext *cx, BindData *data, JSAtom *atom)
|
||||||
{
|
{
|
||||||
JSFunction *fun;
|
JSFunction *fun;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Can't increase fun->nvars in an active frame, so insist that getter is
|
||||||
|
* js_GetLocalVariable, not js_GetCallVariable or anything else.
|
||||||
|
*/
|
||||||
|
if (data->u.var.getter != js_GetLocalVariable)
|
||||||
|
return JS_TRUE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Don't bind a variable with the hidden name 'arguments', per ECMA-262.
|
||||||
|
* Instead 'var arguments' always restates the predefined property of the
|
||||||
|
* activation objects with unhidden name 'arguments'. Assignment to such
|
||||||
|
* a variable must be handled specially.
|
||||||
|
*/
|
||||||
|
if (atom == cx->runtime->atomState.argumentsAtom)
|
||||||
|
return JS_TRUE;
|
||||||
|
|
||||||
fun = data->u.var.fun;
|
fun = data->u.var.fun;
|
||||||
if (!js_AddHiddenProperty(cx, data->obj, ATOM_TO_JSID(atom),
|
if (!js_AddHiddenProperty(cx, data->obj, ATOM_TO_JSID(atom),
|
||||||
data->u.var.getter, data->u.var.setter,
|
data->u.var.getter, data->u.var.setter,
|
||||||
|
@ -1022,16 +1038,8 @@ BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom,
|
||||||
}
|
}
|
||||||
OBJ_DROP_PROPERTY(cx, pobj, prop);
|
OBJ_DROP_PROPERTY(cx, pobj, prop);
|
||||||
} else {
|
} else {
|
||||||
/*
|
if (!BindLocalVariable(cx, data, atom))
|
||||||
* Don't bind a variable with hidden name 'arguments', per ECMA-262.
|
|
||||||
* Instead, var arguments always restates the predefined property of
|
|
||||||
* the activation objects with unhidden name 'arguments'. Assignment
|
|
||||||
* to such a variable must be handled specially.
|
|
||||||
*/
|
|
||||||
if (atom != cx->runtime->atomState.argumentsAtom &&
|
|
||||||
!BindLocalVariable(cx, data, atom)) {
|
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
@ -1308,10 +1316,28 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
||||||
#if JS_HAS_DESTRUCTURING
|
#if JS_HAS_DESTRUCTURING
|
||||||
/*
|
/*
|
||||||
* If there were destructuring formal parameters, prepend the initializing
|
* If there were destructuring formal parameters, prepend the initializing
|
||||||
* comma expression that we synthesized to body.
|
* comma expression that we synthesized to body. If the body is a lexical
|
||||||
|
* scope node, we must make a special TOK_BODY node, to prepend the formal
|
||||||
|
* parameter destructuring code without bracing the decompilation of the
|
||||||
|
* function body's lexical scope.
|
||||||
*/
|
*/
|
||||||
if (list) {
|
if (list) {
|
||||||
JS_ASSERT(body->pn_arity == PN_LIST);
|
if (body->pn_arity != PN_LIST) {
|
||||||
|
JSParseNode *block;
|
||||||
|
|
||||||
|
JS_ASSERT(body->pn_type == TOK_LEXICALSCOPE);
|
||||||
|
JS_ASSERT(body->pn_arity == PN_NAME);
|
||||||
|
|
||||||
|
block = NewParseNode(cx, ts, PN_LIST, tc);
|
||||||
|
if (!block)
|
||||||
|
return NULL;
|
||||||
|
block->pn_type = TOK_BODY;
|
||||||
|
block->pn_pos = body->pn_pos;
|
||||||
|
PN_INIT_LIST_1(block, body);
|
||||||
|
|
||||||
|
body = block;
|
||||||
|
}
|
||||||
|
|
||||||
item = NewParseNode(cx, ts, PN_UNARY, tc);
|
item = NewParseNode(cx, ts, PN_UNARY, tc);
|
||||||
if (!item)
|
if (!item)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1683,7 +1709,7 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
|
||||||
JSObject *obj, *pobj;
|
JSObject *obj, *pobj;
|
||||||
JSProperty *prop;
|
JSProperty *prop;
|
||||||
JSBool ok;
|
JSBool ok;
|
||||||
JSPropertyOp currentGetter, currentSetter;
|
JSPropertyOp getter, setter;
|
||||||
JSScopeProperty *sprop;
|
JSScopeProperty *sprop;
|
||||||
|
|
||||||
stmt = js_LexicalLookup(tc, atom, NULL, JS_FALSE);
|
stmt = js_LexicalLookup(tc, atom, NULL, JS_FALSE);
|
||||||
|
@ -1738,8 +1764,8 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
|
||||||
}
|
}
|
||||||
|
|
||||||
ok = JS_TRUE;
|
ok = JS_TRUE;
|
||||||
currentGetter = data->u.var.getter;
|
getter = data->u.var.getter;
|
||||||
currentSetter = data->u.var.setter;
|
setter = data->u.var.setter;
|
||||||
|
|
||||||
if (prop && pobj == obj && OBJ_IS_NATIVE(pobj)) {
|
if (prop && pobj == obj && OBJ_IS_NATIVE(pobj)) {
|
||||||
sprop = (JSScopeProperty *)prop;
|
sprop = (JSScopeProperty *)prop;
|
||||||
|
@ -1755,8 +1781,8 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
|
||||||
name);
|
name);
|
||||||
ok = JS_FALSE;
|
ok = JS_FALSE;
|
||||||
} else {
|
} else {
|
||||||
currentGetter = js_GetArgument;
|
getter = js_GetArgument;
|
||||||
currentSetter = js_SetArgument;
|
setter = js_SetArgument;
|
||||||
ok = js_ReportCompileErrorNumber(cx,
|
ok = js_ReportCompileErrorNumber(cx,
|
||||||
BIND_DATA_REPORT_ARGS(data,
|
BIND_DATA_REPORT_ARGS(data,
|
||||||
JSREPORT_WARNING |
|
JSREPORT_WARNING |
|
||||||
|
@ -1765,6 +1791,8 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
|
||||||
name);
|
name);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
JS_ASSERT(getter == js_GetLocalVariable);
|
||||||
|
|
||||||
if (fun) {
|
if (fun) {
|
||||||
/* Not an argument, must be a redeclared local var. */
|
/* Not an argument, must be a redeclared local var. */
|
||||||
if (data->u.var.clasp == &js_FunctionClass) {
|
if (data->u.var.clasp == &js_FunctionClass) {
|
||||||
|
@ -1786,16 +1814,15 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
|
||||||
* use the special getters and setters since we can't
|
* use the special getters and setters since we can't
|
||||||
* allocate a slot in the frame.
|
* allocate a slot in the frame.
|
||||||
*/
|
*/
|
||||||
currentGetter = sprop->getter;
|
getter = sprop->getter;
|
||||||
currentSetter = sprop->setter;
|
setter = sprop->setter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Override the old getter and setter, to handle eval. */
|
/* Override the old getter and setter, to handle eval. */
|
||||||
sprop = js_ChangeNativePropertyAttrs(cx, obj, sprop,
|
sprop = js_ChangeNativePropertyAttrs(cx, obj, sprop,
|
||||||
0, sprop->attrs,
|
0, sprop->attrs,
|
||||||
currentGetter,
|
getter, setter);
|
||||||
currentSetter);
|
|
||||||
if (!sprop)
|
if (!sprop)
|
||||||
ok = JS_FALSE;
|
ok = JS_FALSE;
|
||||||
}
|
}
|
||||||
|
@ -1816,14 +1843,8 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
|
||||||
OBJ_DROP_PROPERTY(cx, pobj, prop);
|
OBJ_DROP_PROPERTY(cx, pobj, prop);
|
||||||
prop = NULL;
|
prop = NULL;
|
||||||
}
|
}
|
||||||
if (currentGetter == js_GetCallVariable) {
|
|
||||||
/* Can't increase fun->nvars in an active frame! */
|
if (cx->fp->scopeChain == obj &&
|
||||||
currentGetter = data->u.var.clasp->getProperty;
|
|
||||||
currentSetter = data->u.var.clasp->setProperty;
|
|
||||||
}
|
|
||||||
if (currentGetter == js_GetLocalVariable &&
|
|
||||||
atom != cx->runtime->atomState.argumentsAtom &&
|
|
||||||
cx->fp->scopeChain == obj &&
|
|
||||||
!js_InWithStatement(tc) &&
|
!js_InWithStatement(tc) &&
|
||||||
!BindLocalVariable(cx, data, atom)) {
|
!BindLocalVariable(cx, data, atom)) {
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
@ -2078,7 +2099,6 @@ CheckDestructuring(JSContext *cx, BindData *data,
|
||||||
JSBool ok;
|
JSBool ok;
|
||||||
FindPropValData fpvd;
|
FindPropValData fpvd;
|
||||||
JSParseNode *lhs, *rhs, *pn, *pn2;
|
JSParseNode *lhs, *rhs, *pn, *pn2;
|
||||||
uint32 count;
|
|
||||||
|
|
||||||
if (left->pn_type == TOK_ARRAYCOMP) {
|
if (left->pn_type == TOK_ARRAYCOMP) {
|
||||||
js_ReportCompileErrorNumber(cx, left, JSREPORT_PN | JSREPORT_ERROR,
|
js_ReportCompileErrorNumber(cx, left, JSREPORT_PN | JSREPORT_ERROR,
|
||||||
|
@ -2089,8 +2109,8 @@ CheckDestructuring(JSContext *cx, BindData *data,
|
||||||
ok = JS_TRUE;
|
ok = JS_TRUE;
|
||||||
fpvd.table.ops = NULL;
|
fpvd.table.ops = NULL;
|
||||||
lhs = left->pn_head;
|
lhs = left->pn_head;
|
||||||
if (left->pn_count == 0 || lhs->pn_type == TOK_DEFSHARP) {
|
if (lhs && lhs->pn_type == TOK_DEFSHARP) {
|
||||||
pn = left;
|
pn = lhs;
|
||||||
goto no_var_name;
|
goto no_var_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2099,7 +2119,6 @@ CheckDestructuring(JSContext *cx, BindData *data,
|
||||||
? right->pn_head
|
? right->pn_head
|
||||||
: NULL;
|
: NULL;
|
||||||
|
|
||||||
count = 0;
|
|
||||||
while (lhs) {
|
while (lhs) {
|
||||||
pn = lhs, pn2 = rhs;
|
pn = lhs, pn2 = rhs;
|
||||||
if (!data) {
|
if (!data) {
|
||||||
|
@ -2128,18 +2147,12 @@ CheckDestructuring(JSContext *cx, BindData *data,
|
||||||
}
|
}
|
||||||
if (!ok)
|
if (!ok)
|
||||||
goto out;
|
goto out;
|
||||||
++count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lhs = lhs->pn_next;
|
lhs = lhs->pn_next;
|
||||||
if (rhs)
|
if (rhs)
|
||||||
rhs = rhs->pn_next;
|
rhs = rhs->pn_next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count == 0) {
|
|
||||||
pn = left;
|
|
||||||
goto no_var_name;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(left->pn_type == TOK_RC);
|
JS_ASSERT(left->pn_type == TOK_RC);
|
||||||
fpvd.numvars = left->pn_count;
|
fpvd.numvars = left->pn_count;
|
||||||
|
@ -2250,6 +2263,8 @@ ContainsStmt(JSParseNode *pn, JSTokenType tt)
|
||||||
if (pn->pn_op != JSOP_NOP)
|
if (pn->pn_op != JSOP_NOP)
|
||||||
return NULL;
|
return NULL;
|
||||||
return ContainsStmt(pn->pn_kid, tt);
|
return ContainsStmt(pn->pn_kid, tt);
|
||||||
|
case PN_NAME:
|
||||||
|
return ContainsStmt(pn->pn_expr, tt);
|
||||||
default:;
|
default:;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -2787,11 +2802,20 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||||
/* Check that the left side of the 'in' is valid. */
|
/* Check that the left side of the 'in' is valid. */
|
||||||
JS_ASSERT(!TOKEN_TYPE_IS_DECL(tt) || pn1->pn_type == tt);
|
JS_ASSERT(!TOKEN_TYPE_IS_DECL(tt) || pn1->pn_type == tt);
|
||||||
if (TOKEN_TYPE_IS_DECL(tt)
|
if (TOKEN_TYPE_IS_DECL(tt)
|
||||||
? (pn1->pn_count > 1 || pn1->pn_op == JSOP_DEFCONST)
|
? (pn1->pn_count > 1 || pn1->pn_op == JSOP_DEFCONST
|
||||||
|
#if JS_HAS_DESTRUCTURING
|
||||||
|
|| pn1->pn_head->pn_type == TOK_RC
|
||||||
|
|| (pn1->pn_head->pn_type == TOK_RB &&
|
||||||
|
pn1->pn_head->pn_count != 2)
|
||||||
|
|| (pn1->pn_head->pn_type == TOK_ASSIGN &&
|
||||||
|
(pn1->pn_head->pn_left->pn_type != TOK_RB ||
|
||||||
|
pn1->pn_head->pn_left->pn_count != 2))
|
||||||
|
#endif
|
||||||
|
)
|
||||||
: (pn1->pn_type != TOK_NAME &&
|
: (pn1->pn_type != TOK_NAME &&
|
||||||
pn1->pn_type != TOK_DOT &&
|
pn1->pn_type != TOK_DOT &&
|
||||||
#if JS_HAS_DESTRUCTURING
|
#if JS_HAS_DESTRUCTURING
|
||||||
pn1->pn_type != TOK_RB && pn1->pn_type != TOK_RC &&
|
(pn1->pn_type != TOK_RB || pn1->pn_count != 2) &&
|
||||||
#endif
|
#endif
|
||||||
#if JS_HAS_LVALUE_RETURN
|
#if JS_HAS_LVALUE_RETURN
|
||||||
pn1->pn_type != TOK_LP &&
|
pn1->pn_type != TOK_LP &&
|
||||||
|
@ -5314,6 +5338,14 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
||||||
if (!pnlet)
|
if (!pnlet)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
if (pnlet->pn_type != TOK_RB || pnlet->pn_count != 2) {
|
||||||
|
js_ReportCompileErrorNumber(cx, ts,
|
||||||
|
JSREPORT_TS |
|
||||||
|
JSREPORT_ERROR,
|
||||||
|
JSMSG_BAD_FOR_LEFTSIDE);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Destructuring requires [key, value] enumeration. */
|
/* Destructuring requires [key, value] enumeration. */
|
||||||
if (pn2->pn_op != JSOP_FOREACH)
|
if (pn2->pn_op != JSOP_FOREACH)
|
||||||
pn2->pn_op = JSOP_FOREACHKEYVAL;
|
pn2->pn_op = JSOP_FOREACHKEYVAL;
|
||||||
|
|
|
@ -136,6 +136,8 @@ typedef enum JSTokenType {
|
||||||
TOK_ARRAYPUSH = 81, /* array push within comprehension */
|
TOK_ARRAYPUSH = 81, /* array push within comprehension */
|
||||||
TOK_LEXICALSCOPE = 82, /* block scope AST node label */
|
TOK_LEXICALSCOPE = 82, /* block scope AST node label */
|
||||||
TOK_LET = 83, /* let keyword */
|
TOK_LET = 83, /* let keyword */
|
||||||
|
TOK_BODY = 84, /* synthetic body of function with
|
||||||
|
destructuring formal parameters */
|
||||||
TOK_RESERVED, /* reserved keywords */
|
TOK_RESERVED, /* reserved keywords */
|
||||||
TOK_LIMIT /* domain size */
|
TOK_LIMIT /* domain size */
|
||||||
} JSTokenType;
|
} JSTokenType;
|
||||||
|
|
|
@ -200,7 +200,7 @@ JS_XDRFindClassById(JSXDRState *xdr, uint32 id);
|
||||||
* before deserialization of bytecode. If the saved version does not match
|
* before deserialization of bytecode. If the saved version does not match
|
||||||
* the current version, abort deserialization and invalidate the file.
|
* the current version, abort deserialization and invalidate the file.
|
||||||
*/
|
*/
|
||||||
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 3)
|
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 4)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Library-private functions.
|
* Library-private functions.
|
||||||
|
|
Загрузка…
Ссылка в новой задаче