mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-18 15:55:36 +00:00
Bug 696108 - hoist EmitFor, EmitForIn, EmitNormalFor out of EmitTree (r=jorendorff)
--HG-- extra : rebase_source : bec844e4a62f0492c33d3447fb31ca460768c62a
This commit is contained in:
parent
4c1a947967
commit
f53995c346
@ -5556,13 +5556,301 @@ EmitWith(JSContext *cx, CodeGenerator *cg, ParseNode *pn, JSBool &ok)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitForIn(JSContext *cx, CodeGenerator *cg, ParseNode *pn, ptrdiff_t top)
|
||||
{
|
||||
StmtInfo stmtInfo;
|
||||
PushStatement(cg, &stmtInfo, STMT_FOR_IN_LOOP, top);
|
||||
|
||||
ParseNode *forHead = pn->pn_left;
|
||||
ParseNode *forBody = pn->pn_right;
|
||||
|
||||
/*
|
||||
* If the left part is 'var x', emit code to define x if necessary
|
||||
* using a prolog opcode, but do not emit a pop. If the left part
|
||||
* was originally 'var x = i', the parser will have rewritten it;
|
||||
* see Parser::forStatement. 'for (let x = i in o)' is mercifully
|
||||
* banned.
|
||||
*/
|
||||
bool forLet = false;
|
||||
if (ParseNode *decl = forHead->pn_kid1) {
|
||||
JS_ASSERT(TokenKindIsDecl(decl->getKind()));
|
||||
forLet = decl->isKind(TOK_LET);
|
||||
cg->flags |= TCF_IN_FOR_INIT;
|
||||
if (!EmitTree(cx, cg, decl))
|
||||
return false;
|
||||
cg->flags &= ~TCF_IN_FOR_INIT;
|
||||
}
|
||||
|
||||
/* Compile the object expression to the right of 'in'. */
|
||||
{
|
||||
TempPopScope tps;
|
||||
if (forLet && !tps.popBlock(cx, cg))
|
||||
return false;
|
||||
if (!EmitTree(cx, cg, forHead->pn_kid3))
|
||||
return false;
|
||||
if (forLet && !tps.repushBlock(cx, cg))
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Emit a bytecode to convert top of stack value to the iterator
|
||||
* object depending on the loop variant (for-in, for-each-in, or
|
||||
* destructuring for-in).
|
||||
*/
|
||||
JS_ASSERT(pn->isOp(JSOP_ITER));
|
||||
if (Emit2(cx, cg, JSOP_ITER, (uint8) pn->pn_iflags) < 0)
|
||||
return false;
|
||||
|
||||
/* Annotate so the decompiler can find the loop-closing jump. */
|
||||
intN noteIndex = NewSrcNote(cx, cg, SRC_FOR_IN);
|
||||
if (noteIndex < 0)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Jump down to the loop condition to minimize overhead assuming at
|
||||
* least one iteration, as the other loop forms do.
|
||||
*/
|
||||
ptrdiff_t jmp = EmitJump(cx, cg, JSOP_GOTO, 0);
|
||||
if (jmp < 0)
|
||||
return false;
|
||||
|
||||
intN noteIndex2 = NewSrcNote(cx, cg, SRC_TRACE);
|
||||
if (noteIndex2 < 0)
|
||||
return false;
|
||||
|
||||
top = CG_OFFSET(cg);
|
||||
SET_STATEMENT_TOP(&stmtInfo, top);
|
||||
if (EmitTraceOp(cx, cg, NULL) < 0)
|
||||
return false;
|
||||
|
||||
#ifdef DEBUG
|
||||
intN loopDepth = cg->stackDepth;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Emit code to get the next enumeration value and assign it to the
|
||||
* left hand side. The JSOP_POP after this assignment is annotated
|
||||
* so that the decompiler can distinguish 'for (x in y)' from
|
||||
* 'for (var x in y)'.
|
||||
*/
|
||||
if (!EmitAssignment(cx, cg, forHead->pn_kid2, JSOP_NOP, NULL))
|
||||
return false;
|
||||
ptrdiff_t tmp2 = CG_OFFSET(cg);
|
||||
if (forHead->pn_kid1 && NewSrcNote2(cx, cg, SRC_DECL,
|
||||
(forHead->pn_kid1->isOp(JSOP_DEFVAR))
|
||||
? SRC_DECL_VAR
|
||||
: SRC_DECL_LET) < 0) {
|
||||
return false;
|
||||
}
|
||||
if (Emit1(cx, cg, JSOP_POP) < 0)
|
||||
return false;
|
||||
|
||||
/* The stack should be balanced around the assignment opcode sequence. */
|
||||
JS_ASSERT(cg->stackDepth == loopDepth);
|
||||
|
||||
/* Emit code for the loop body. */
|
||||
if (!EmitTree(cx, cg, forBody))
|
||||
return false;
|
||||
|
||||
/* Set loop and enclosing "update" offsets, for continue. */
|
||||
StmtInfo *stmt = &stmtInfo;
|
||||
do {
|
||||
stmt->update = CG_OFFSET(cg);
|
||||
} while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL);
|
||||
|
||||
/*
|
||||
* Fixup the goto that starts the loop to jump down to JSOP_MOREITER.
|
||||
*/
|
||||
CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);
|
||||
if (Emit1(cx, cg, JSOP_MOREITER) < 0)
|
||||
return false;
|
||||
ptrdiff_t beq = EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg));
|
||||
if (beq < 0)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Be careful: We must set noteIndex2 before noteIndex in case the noteIndex
|
||||
* note gets bigger.
|
||||
*/
|
||||
if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex2, 0, beq - top))
|
||||
return false;
|
||||
/* Set the first srcnote offset so we can find the start of the loop body. */
|
||||
if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp2 - jmp))
|
||||
return false;
|
||||
/* Set the second srcnote offset so we can find the closing jump. */
|
||||
if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1, beq - jmp))
|
||||
return false;
|
||||
|
||||
/* Now fixup all breaks and continues (before the JSOP_ENDITER). */
|
||||
if (!PopStatementCG(cx, cg))
|
||||
return false;
|
||||
|
||||
if (!NewTryNote(cx, cg, JSTRY_ITER, cg->stackDepth, top, CG_OFFSET(cg)))
|
||||
return false;
|
||||
|
||||
return Emit1(cx, cg, JSOP_ENDITER) >= 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitNormalFor(JSContext *cx, CodeGenerator *cg, ParseNode *pn, ptrdiff_t top)
|
||||
{
|
||||
StmtInfo stmtInfo;
|
||||
PushStatement(cg, &stmtInfo, STMT_FOR_LOOP, top);
|
||||
|
||||
ParseNode *forHead = pn->pn_left;
|
||||
ParseNode *forBody = pn->pn_right;
|
||||
|
||||
/* C-style for (init; cond; update) ... loop. */
|
||||
JSOp op = JSOP_POP;
|
||||
ParseNode *pn3 = forHead->pn_kid1;
|
||||
if (!pn3) {
|
||||
/* No initializer: emit an annotated nop for the decompiler. */
|
||||
op = JSOP_NOP;
|
||||
} else {
|
||||
cg->flags |= TCF_IN_FOR_INIT;
|
||||
#if JS_HAS_DESTRUCTURING
|
||||
if (pn3->isKind(TOK_ASSIGN) &&
|
||||
!MaybeEmitGroupAssignment(cx, cg, op, pn3, &op)) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
if (op == JSOP_POP) {
|
||||
if (!EmitTree(cx, cg, pn3))
|
||||
return false;
|
||||
if (TokenKindIsDecl(pn3->getKind())) {
|
||||
/*
|
||||
* Check whether a destructuring-initialized var decl
|
||||
* was optimized to a group assignment. If so, we do
|
||||
* not need to emit a pop below, so switch to a nop,
|
||||
* just for the decompiler.
|
||||
*/
|
||||
JS_ASSERT(pn3->isArity(PN_LIST));
|
||||
if (pn3->pn_xflags & PNX_GROUPINIT)
|
||||
op = JSOP_NOP;
|
||||
}
|
||||
}
|
||||
cg->flags &= ~TCF_IN_FOR_INIT;
|
||||
}
|
||||
|
||||
/*
|
||||
* NB: the SRC_FOR note has offsetBias 1 (JSOP_{NOP,POP}_LENGTH).
|
||||
* Use tmp to hold the biased srcnote "top" offset, which differs
|
||||
* from the top local variable by the length of the JSOP_GOTO{,X}
|
||||
* emitted in between tmp and top if this loop has a condition.
|
||||
*/
|
||||
intN noteIndex = NewSrcNote(cx, cg, SRC_FOR);
|
||||
if (noteIndex < 0 || Emit1(cx, cg, op) < 0)
|
||||
return false;
|
||||
ptrdiff_t tmp = CG_OFFSET(cg);
|
||||
|
||||
ptrdiff_t jmp = -1;
|
||||
if (forHead->pn_kid2) {
|
||||
/* Goto the loop condition, which branches back to iterate. */
|
||||
jmp = EmitJump(cx, cg, JSOP_GOTO, 0);
|
||||
if (jmp < 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
top = CG_OFFSET(cg);
|
||||
SET_STATEMENT_TOP(&stmtInfo, top);
|
||||
|
||||
intN noteIndex2 = NewSrcNote(cx, cg, SRC_TRACE);
|
||||
if (noteIndex2 < 0)
|
||||
return false;
|
||||
|
||||
/* Emit code for the loop body. */
|
||||
if (EmitTraceOp(cx, cg, forBody) < 0)
|
||||
return false;
|
||||
if (!EmitTree(cx, cg, forBody))
|
||||
return false;
|
||||
|
||||
/* Set the second note offset so we can find the update part. */
|
||||
JS_ASSERT(noteIndex != -1);
|
||||
ptrdiff_t tmp2 = CG_OFFSET(cg);
|
||||
|
||||
/* Set loop and enclosing "update" offsets, for continue. */
|
||||
StmtInfo *stmt = &stmtInfo;
|
||||
do {
|
||||
stmt->update = CG_OFFSET(cg);
|
||||
} while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL);
|
||||
|
||||
/* Check for update code to do before the condition (if any). */
|
||||
pn3 = forHead->pn_kid3;
|
||||
if (pn3) {
|
||||
op = JSOP_POP;
|
||||
#if JS_HAS_DESTRUCTURING
|
||||
if (pn3->isKind(TOK_ASSIGN) &&
|
||||
!MaybeEmitGroupAssignment(cx, cg, op, pn3, &op)) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
if (op == JSOP_POP && !EmitTree(cx, cg, pn3))
|
||||
return false;
|
||||
|
||||
/* Always emit the POP or NOP, to help the decompiler. */
|
||||
if (Emit1(cx, cg, op) < 0)
|
||||
return false;
|
||||
|
||||
/* Restore the absolute line number for source note readers. */
|
||||
ptrdiff_t lineno = pn->pn_pos.end.lineno;
|
||||
if (CG_CURRENT_LINE(cg) != (uintN) lineno) {
|
||||
if (NewSrcNote2(cx, cg, SRC_SETLINE, lineno) < 0)
|
||||
return false;
|
||||
CG_CURRENT_LINE(cg) = (uintN) lineno;
|
||||
}
|
||||
}
|
||||
|
||||
ptrdiff_t tmp3 = CG_OFFSET(cg);
|
||||
|
||||
if (forHead->pn_kid2) {
|
||||
/* Fix up the goto from top to target the loop condition. */
|
||||
JS_ASSERT(jmp >= 0);
|
||||
CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);
|
||||
|
||||
if (!EmitTree(cx, cg, forHead->pn_kid2))
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Be careful: We must set noteIndex2 before noteIndex in case the noteIndex
|
||||
* note gets bigger.
|
||||
*/
|
||||
if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex2, 0, CG_OFFSET(cg) - top))
|
||||
return false;
|
||||
/* Set the first note offset so we can find the loop condition. */
|
||||
if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp3 - tmp))
|
||||
return false;
|
||||
if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1, tmp2 - tmp))
|
||||
return false;
|
||||
/* The third note offset helps us find the loop-closing jump. */
|
||||
if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 2, CG_OFFSET(cg) - tmp))
|
||||
return false;
|
||||
|
||||
/* If no loop condition, just emit a loop-closing jump. */
|
||||
op = forHead->pn_kid2 ? JSOP_IFNE : JSOP_GOTO;
|
||||
if (EmitJump(cx, cg, op, top - CG_OFFSET(cg)) < 0)
|
||||
return false;
|
||||
|
||||
/* Now fixup all breaks and continues. */
|
||||
return PopStatementCG(cx, cg);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
EmitFor(JSContext *cx, CodeGenerator *cg, ParseNode *pn, ptrdiff_t top)
|
||||
{
|
||||
return pn->pn_left->isKind(TOK_IN)
|
||||
? EmitForIn(cx, cg, pn, top)
|
||||
: EmitNormalFor(cx, cg, pn, top);
|
||||
}
|
||||
|
||||
JSBool
|
||||
EmitTree(JSContext *cx, CodeGenerator *cg, ParseNode *pn)
|
||||
{
|
||||
JSBool useful, wantval;
|
||||
StmtInfo stmtInfo;
|
||||
StmtInfo *stmt;
|
||||
ptrdiff_t top, off, tmp, beq, jmp, tmp2, tmp3;
|
||||
ptrdiff_t top, off, tmp, beq, jmp;
|
||||
ParseNode *pn2, *pn3;
|
||||
JSAtom *atom;
|
||||
jsatomid atomIndex;
|
||||
@ -5860,280 +6148,7 @@ EmitTree(JSContext *cx, CodeGenerator *cg, ParseNode *pn)
|
||||
break;
|
||||
|
||||
case TOK_FOR:
|
||||
beq = 0; /* suppress gcc warnings */
|
||||
jmp = -1;
|
||||
pn2 = pn->pn_left;
|
||||
PushStatement(cg, &stmtInfo, STMT_FOR_LOOP, top);
|
||||
|
||||
if (pn2->isKind(TOK_IN)) {
|
||||
/* Set stmtInfo type for later testing. */
|
||||
stmtInfo.type = STMT_FOR_IN_LOOP;
|
||||
|
||||
/*
|
||||
* If the left part is 'var x', emit code to define x if necessary
|
||||
* using a prolog opcode, but do not emit a pop. If the left part
|
||||
* was originally 'var x = i', the parser will have rewritten it;
|
||||
* see Parser::forStatement. 'for (let x = i in o)' is mercifully
|
||||
* banned.
|
||||
*/
|
||||
bool forLet = false;
|
||||
if (ParseNode *decl = pn2->pn_kid1) {
|
||||
JS_ASSERT(TokenKindIsDecl(decl->getKind()));
|
||||
forLet = decl->isKind(TOK_LET);
|
||||
cg->flags |= TCF_IN_FOR_INIT;
|
||||
if (!EmitTree(cx, cg, decl))
|
||||
return JS_FALSE;
|
||||
cg->flags &= ~TCF_IN_FOR_INIT;
|
||||
}
|
||||
|
||||
/* Compile the object expression to the right of 'in'. */
|
||||
{
|
||||
TempPopScope tps;
|
||||
if (forLet && !tps.popBlock(cx, cg))
|
||||
return JS_FALSE;
|
||||
if (!EmitTree(cx, cg, pn2->pn_kid3))
|
||||
return JS_FALSE;
|
||||
if (forLet && !tps.repushBlock(cx, cg))
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Emit a bytecode to convert top of stack value to the iterator
|
||||
* object depending on the loop variant (for-in, for-each-in, or
|
||||
* destructuring for-in).
|
||||
*/
|
||||
JS_ASSERT(pn->isOp(JSOP_ITER));
|
||||
if (Emit2(cx, cg, JSOP_ITER, (uint8) pn->pn_iflags) < 0)
|
||||
return JS_FALSE;
|
||||
|
||||
/* Annotate so the decompiler can find the loop-closing jump. */
|
||||
noteIndex = NewSrcNote(cx, cg, SRC_FOR_IN);
|
||||
if (noteIndex < 0)
|
||||
return JS_FALSE;
|
||||
|
||||
/*
|
||||
* Jump down to the loop condition to minimize overhead assuming at
|
||||
* least one iteration, as the other loop forms do.
|
||||
*/
|
||||
jmp = EmitJump(cx, cg, JSOP_GOTO, 0);
|
||||
if (jmp < 0)
|
||||
return JS_FALSE;
|
||||
|
||||
noteIndex2 = NewSrcNote(cx, cg, SRC_TRACE);
|
||||
if (noteIndex2 < 0)
|
||||
return JS_FALSE;
|
||||
|
||||
top = CG_OFFSET(cg);
|
||||
SET_STATEMENT_TOP(&stmtInfo, top);
|
||||
if (EmitTraceOp(cx, cg, NULL) < 0)
|
||||
return JS_FALSE;
|
||||
|
||||
#ifdef DEBUG
|
||||
intN loopDepth = cg->stackDepth;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Emit code to get the next enumeration value and assign it to the
|
||||
* left hand side. The JSOP_POP after this assignment is annotated
|
||||
* so that the decompiler can distinguish 'for (x in y)' from
|
||||
* 'for (var x in y)'.
|
||||
*/
|
||||
if (!EmitAssignment(cx, cg, pn2->pn_kid2, JSOP_NOP, NULL))
|
||||
return false;
|
||||
tmp2 = CG_OFFSET(cg);
|
||||
if (pn2->pn_kid1 && NewSrcNote2(cx, cg, SRC_DECL, (pn2->pn_kid1->isOp(JSOP_DEFVAR))
|
||||
? SRC_DECL_VAR
|
||||
: SRC_DECL_LET) < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (Emit1(cx, cg, JSOP_POP) < 0)
|
||||
return false;
|
||||
|
||||
/* The stack should be balanced around the assignment opcode sequence. */
|
||||
JS_ASSERT(cg->stackDepth == loopDepth);
|
||||
|
||||
/* Emit code for the loop body. */
|
||||
if (!EmitTree(cx, cg, pn->pn_right))
|
||||
return JS_FALSE;
|
||||
|
||||
/* Set loop and enclosing "update" offsets, for continue. */
|
||||
stmt = &stmtInfo;
|
||||
do {
|
||||
stmt->update = CG_OFFSET(cg);
|
||||
} while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL);
|
||||
|
||||
/*
|
||||
* Fixup the goto that starts the loop to jump down to JSOP_MOREITER.
|
||||
*/
|
||||
CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);
|
||||
if (Emit1(cx, cg, JSOP_MOREITER) < 0)
|
||||
return JS_FALSE;
|
||||
beq = EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg));
|
||||
if (beq < 0)
|
||||
return JS_FALSE;
|
||||
|
||||
/*
|
||||
* Be careful: We must set noteIndex2 before noteIndex in case the noteIndex
|
||||
* note gets bigger.
|
||||
*/
|
||||
if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex2, 0, beq - top))
|
||||
return JS_FALSE;
|
||||
/* Set the first srcnote offset so we can find the start of the loop body. */
|
||||
if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp2 - jmp))
|
||||
return JS_FALSE;
|
||||
/* Set the second srcnote offset so we can find the closing jump. */
|
||||
if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1, beq - jmp))
|
||||
return JS_FALSE;
|
||||
} else {
|
||||
/* C-style for (init; cond; update) ... loop. */
|
||||
op = JSOP_POP;
|
||||
pn3 = pn2->pn_kid1;
|
||||
if (!pn3) {
|
||||
/* No initializer: emit an annotated nop for the decompiler. */
|
||||
op = JSOP_NOP;
|
||||
} else {
|
||||
cg->flags |= TCF_IN_FOR_INIT;
|
||||
#if JS_HAS_DESTRUCTURING
|
||||
if (pn3->isKind(TOK_ASSIGN) &&
|
||||
!MaybeEmitGroupAssignment(cx, cg, op, pn3, &op)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
#endif
|
||||
if (op == JSOP_POP) {
|
||||
if (!EmitTree(cx, cg, pn3))
|
||||
return JS_FALSE;
|
||||
if (TokenKindIsDecl(pn3->getKind())) {
|
||||
/*
|
||||
* Check whether a destructuring-initialized var decl
|
||||
* was optimized to a group assignment. If so, we do
|
||||
* not need to emit a pop below, so switch to a nop,
|
||||
* just for the decompiler.
|
||||
*/
|
||||
JS_ASSERT(pn3->isArity(PN_LIST));
|
||||
if (pn3->pn_xflags & PNX_GROUPINIT)
|
||||
op = JSOP_NOP;
|
||||
}
|
||||
}
|
||||
cg->flags &= ~TCF_IN_FOR_INIT;
|
||||
}
|
||||
|
||||
/*
|
||||
* NB: the SRC_FOR note has offsetBias 1 (JSOP_{NOP,POP}_LENGTH).
|
||||
* Use tmp to hold the biased srcnote "top" offset, which differs
|
||||
* from the top local variable by the length of the JSOP_GOTO{,X}
|
||||
* emitted in between tmp and top if this loop has a condition.
|
||||
*/
|
||||
noteIndex = NewSrcNote(cx, cg, SRC_FOR);
|
||||
if (noteIndex < 0 || Emit1(cx, cg, op) < 0)
|
||||
return JS_FALSE;
|
||||
tmp = CG_OFFSET(cg);
|
||||
|
||||
if (pn2->pn_kid2) {
|
||||
/* Goto the loop condition, which branches back to iterate. */
|
||||
jmp = EmitJump(cx, cg, JSOP_GOTO, 0);
|
||||
if (jmp < 0)
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
top = CG_OFFSET(cg);
|
||||
SET_STATEMENT_TOP(&stmtInfo, top);
|
||||
|
||||
noteIndex2 = NewSrcNote(cx, cg, SRC_TRACE);
|
||||
if (noteIndex2 < 0)
|
||||
return JS_FALSE;
|
||||
|
||||
/* Emit code for the loop body. */
|
||||
if (EmitTraceOp(cx, cg, pn->pn_right) < 0)
|
||||
return JS_FALSE;
|
||||
if (!EmitTree(cx, cg, pn->pn_right))
|
||||
return JS_FALSE;
|
||||
|
||||
/* Set the second note offset so we can find the update part. */
|
||||
JS_ASSERT(noteIndex != -1);
|
||||
tmp2 = CG_OFFSET(cg);
|
||||
|
||||
/* Set loop and enclosing "update" offsets, for continue. */
|
||||
stmt = &stmtInfo;
|
||||
do {
|
||||
stmt->update = CG_OFFSET(cg);
|
||||
} while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL);
|
||||
|
||||
/* Check for update code to do before the condition (if any). */
|
||||
pn3 = pn2->pn_kid3;
|
||||
if (pn3) {
|
||||
op = JSOP_POP;
|
||||
#if JS_HAS_DESTRUCTURING
|
||||
if (pn3->isKind(TOK_ASSIGN) &&
|
||||
!MaybeEmitGroupAssignment(cx, cg, op, pn3, &op)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
#endif
|
||||
if (op == JSOP_POP && !EmitTree(cx, cg, pn3))
|
||||
return JS_FALSE;
|
||||
|
||||
/* Always emit the POP or NOP, to help the decompiler. */
|
||||
if (Emit1(cx, cg, op) < 0)
|
||||
return JS_FALSE;
|
||||
|
||||
/* Restore the absolute line number for source note readers. */
|
||||
off = (ptrdiff_t) pn->pn_pos.end.lineno;
|
||||
if (CG_CURRENT_LINE(cg) != (uintN) off) {
|
||||
if (NewSrcNote2(cx, cg, SRC_SETLINE, off) < 0)
|
||||
return JS_FALSE;
|
||||
CG_CURRENT_LINE(cg) = (uintN) off;
|
||||
}
|
||||
}
|
||||
|
||||
tmp3 = CG_OFFSET(cg);
|
||||
|
||||
if (pn2->pn_kid2) {
|
||||
/* Fix up the goto from top to target the loop condition. */
|
||||
JS_ASSERT(jmp >= 0);
|
||||
CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);
|
||||
|
||||
if (!EmitTree(cx, cg, pn2->pn_kid2))
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Be careful: We must set noteIndex2 before noteIndex in case the noteIndex
|
||||
* note gets bigger.
|
||||
*/
|
||||
if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex2, 0, CG_OFFSET(cg) - top))
|
||||
return JS_FALSE;
|
||||
/* Set the first note offset so we can find the loop condition. */
|
||||
if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp3 - tmp))
|
||||
return JS_FALSE;
|
||||
if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1, tmp2 - tmp))
|
||||
return JS_FALSE;
|
||||
/* The third note offset helps us find the loop-closing jump. */
|
||||
if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 2, CG_OFFSET(cg) - tmp))
|
||||
return JS_FALSE;
|
||||
|
||||
if (pn2->pn_kid2) {
|
||||
beq = EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg));
|
||||
if (beq < 0)
|
||||
return JS_FALSE;
|
||||
} else {
|
||||
/* No loop condition -- emit the loop-closing jump. */
|
||||
jmp = EmitJump(cx, cg, JSOP_GOTO, top - CG_OFFSET(cg));
|
||||
if (jmp < 0)
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now fixup all breaks and continues (before for/in's JSOP_ENDITER). */
|
||||
if (!PopStatementCG(cx, cg))
|
||||
return JS_FALSE;
|
||||
|
||||
if (pn2->isKind(TOK_IN)) {
|
||||
if (!NewTryNote(cx, cg, JSTRY_ITER, cg->stackDepth, top, CG_OFFSET(cg)) ||
|
||||
Emit1(cx, cg, JSOP_ENDITER) < 0)
|
||||
{
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
ok = EmitFor(cx, cg, pn, top);
|
||||
break;
|
||||
|
||||
case TOK_BREAK: {
|
||||
|
Loading…
Reference in New Issue
Block a user