зеркало из https://github.com/mozilla/gecko-dev.git
Fix to 58946.
Make try { ... } catch(exn) { return exn } work by ensuring that the return value (exn) is maintained on the stack as we pop off scopes to return from the try/catch/finally. The newly added JSOP_SWAP opcode helps us bubble. This fixes a regression uncovered by the fix to 56716. (I've noticed that this causes *depend* builds of the standalone JS shell to crash on this construct, but I've tested in the Mozilla build, and the dependencies seem to solve the problem there.) r=brendan.mozilla.org sr=jband@netscape.com
This commit is contained in:
Родитель
390cd6d680
Коммит
ea579e0496
|
@ -306,11 +306,16 @@ js_PushStatement(JSTreeContext *tc, JSStmtInfo *stmt, JSStmtType type,
|
|||
|
||||
/* Emit additional bytecode(s) for non-local jumps. */
|
||||
static JSBool
|
||||
EmitNonLocalJumpFixup(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt)
|
||||
EmitNonLocalJumpFixup(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt,
|
||||
JSBool preserveTop)
|
||||
{
|
||||
JSStmtInfo *stmt;
|
||||
ptrdiff_t jmp;
|
||||
|
||||
/*
|
||||
* If we're here as part of processing a return, emit JSOP_SWAP to preserve
|
||||
* the top element.
|
||||
*/
|
||||
for (stmt = cg->treeContext.topStmt; stmt != toStmt; stmt = stmt->down) {
|
||||
switch (stmt->type) {
|
||||
case STMT_FINALLY:
|
||||
|
@ -322,6 +327,10 @@ EmitNonLocalJumpFixup(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt)
|
|||
break;
|
||||
case STMT_WITH:
|
||||
case STMT_CATCH:
|
||||
if (preserveTop) {
|
||||
if (js_Emit1(cx, cg, JSOP_SWAP) < 0)
|
||||
return JS_FALSE;
|
||||
}
|
||||
if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)
|
||||
return JS_FALSE;
|
||||
cg->stackDepth++;
|
||||
|
@ -329,11 +338,21 @@ EmitNonLocalJumpFixup(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt)
|
|||
return JS_FALSE;
|
||||
break;
|
||||
case STMT_FOR_IN_LOOP:
|
||||
if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)
|
||||
return JS_FALSE;
|
||||
cg->stackDepth += 2;
|
||||
if (preserveTop) {
|
||||
if (js_Emit1(cx, cg, JSOP_SWAP) < 0 ||
|
||||
js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 ||
|
||||
js_Emit1(cx, cg, JSOP_POP) < 0 ||
|
||||
js_Emit1(cx, cg, JSOP_SWAP) < 0 ||
|
||||
js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 ||
|
||||
js_Emit1(cx, cg, JSOP_POP) < 0) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
} else {
|
||||
/* JSOP_POP2 isn't decompiled, and doesn't need a src note. */
|
||||
if (js_Emit1(cx, cg, JSOP_POP2) < 0)
|
||||
return JS_FALSE;
|
||||
}
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
|
@ -349,7 +368,7 @@ EmitGoto(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt,
|
|||
intN index;
|
||||
ptrdiff_t jmp;
|
||||
|
||||
if (!EmitNonLocalJumpFixup(cx, cg, toStmt))
|
||||
if (!EmitNonLocalJumpFixup(cx, cg, toStmt, JS_FALSE))
|
||||
return -1;
|
||||
|
||||
if (label) {
|
||||
|
@ -1822,8 +1841,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
break;
|
||||
|
||||
case TOK_RETURN:
|
||||
if (!EmitNonLocalJumpFixup(cx, cg, NULL))
|
||||
return JS_FALSE;
|
||||
/* Push a return value */
|
||||
pn2 = pn->pn_kid;
|
||||
if (pn2) {
|
||||
if (!js_EmitTree(cx, cg, pn2))
|
||||
|
@ -1832,6 +1850,13 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
if (js_Emit1(cx, cg, JSOP_PUSH) < 0)
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* EmitNonLocalJumpFixup emits JSOP_SWAPs to maintain the return value
|
||||
* at the top of the stack, so the return still executes OK.
|
||||
*/
|
||||
if (!EmitNonLocalJumpFixup(cx, cg, NULL, JS_TRUE))
|
||||
return JS_FALSE;
|
||||
if (js_Emit1(cx, cg, JSOP_RETURN) < 0)
|
||||
return JS_FALSE;
|
||||
break;
|
||||
|
|
|
@ -1322,6 +1322,18 @@ js_Interpret(JSContext *cx, jsval *result)
|
|||
sp -= 2;
|
||||
break;
|
||||
|
||||
case JSOP_SWAP:
|
||||
/*
|
||||
* N.B. JSOP_SWAP doesn't swap the corresponding pc stack
|
||||
* generating pcs, as they're not needed for the current use of
|
||||
* preserving the top-of-stack return value when popping scopes
|
||||
* while returning from catch blocks.
|
||||
*/
|
||||
ltmp = sp[-1];
|
||||
sp[-1] = sp[-2];
|
||||
sp[-2] = ltmp;
|
||||
break;
|
||||
|
||||
case JSOP_POPV:
|
||||
*result = POP_OPND();
|
||||
break;
|
||||
|
|
|
@ -281,3 +281,11 @@ OPDEF(JSOP_SETCALL, 132, "setcall", NULL, 3, -1, 2, 11, JOF_UINT16
|
|||
*/
|
||||
OPDEF(JSOP_TRY, 133,"try", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||
OPDEF(JSOP_FINALLY, 134,"finally", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||
|
||||
/*
|
||||
* Swap the top two stack elements.
|
||||
* N.B. JSOP_SWAP doesn't swap the corresponding pc stack generating pcs, as
|
||||
* they're not needed for the current use of preserving the top-of-stack return
|
||||
* value when popping scopes while returning from catch blocks.
|
||||
*/
|
||||
OPDEF(JSOP_SWAP, 135,"swap", NULL, 1, 2, 2, 0, JOF_BYTE)
|
||||
|
|
Загрузка…
Ссылка в новой задаче