mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 443071 - Assertion failure with "for (;;[]=[])" (r=mrbkap).
This commit is contained in:
parent
fa14a92fe7
commit
40acf84539
@ -3850,6 +3850,10 @@ EmitFunctionDefNop(JSContext *cx, JSCodeGenerator *cg, uintN index)
|
||||
js_Emit1(cx, cg, JSOP_NOP) >= 0;
|
||||
}
|
||||
|
||||
/* See the SRC_FOR source note offsetBias comments later in this file. */
|
||||
JS_STATIC_ASSERT(JSOP_NOP_LENGTH == 1);
|
||||
JS_STATIC_ASSERT(JSOP_POP_LENGTH == 1);
|
||||
|
||||
JSBool
|
||||
js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
{
|
||||
@ -4288,7 +4292,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
#endif
|
||||
(type == TOK_VAR && !pn3->pn_expr)) &&
|
||||
js_NewSrcNote2(cx, cg, SRC_DECL,
|
||||
type == TOK_VAR
|
||||
(type == TOK_VAR)
|
||||
? SRC_DECL_VAR
|
||||
: SRC_DECL_LET) < 0) {
|
||||
return JS_FALSE;
|
||||
@ -4441,11 +4445,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
}
|
||||
cg->treeContext.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 = js_NewSrcNote(cx, cg, SRC_FOR);
|
||||
if (noteIndex < 0 ||
|
||||
js_Emit1(cx, cg, op) < 0) {
|
||||
if (noteIndex < 0 || js_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. */
|
||||
@ -4453,6 +4463,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
if (jmp < 0)
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
top = CG_OFFSET(cg);
|
||||
SET_STATEMENT_TOP(&stmtInfo, top);
|
||||
|
||||
@ -4463,7 +4474,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
/* Set the second note offset so we can find the update part. */
|
||||
JS_ASSERT(noteIndex != -1);
|
||||
if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1,
|
||||
CG_OFFSET(cg) - top)) {
|
||||
CG_OFFSET(cg) - tmp)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
@ -4483,12 +4494,12 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
return JS_FALSE;
|
||||
}
|
||||
#endif
|
||||
if (op == JSOP_POP) {
|
||||
if (!js_EmitTree(cx, cg, pn3))
|
||||
return JS_FALSE;
|
||||
if (js_Emit1(cx, cg, op) < 0)
|
||||
return JS_FALSE;
|
||||
}
|
||||
if (op == JSOP_POP && !js_EmitTree(cx, cg, pn3))
|
||||
return JS_FALSE;
|
||||
|
||||
/* Always emit the POP or NOP, to help the decompiler. */
|
||||
if (js_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;
|
||||
@ -4501,7 +4512,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
|
||||
/* Set the first note offset so we can find the loop condition. */
|
||||
if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0,
|
||||
CG_OFFSET(cg) - top)) {
|
||||
CG_OFFSET(cg) - tmp)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
@ -4516,7 +4527,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
|
||||
/* The third note offset helps us find the loop-closing jump. */
|
||||
if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 2,
|
||||
CG_OFFSET(cg) - top)) {
|
||||
CG_OFFSET(cg) - tmp)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
@ -6356,7 +6367,10 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
return ok;
|
||||
}
|
||||
|
||||
/* XXX get rid of offsetBias, it's used only by SRC_FOR and SRC_DECL */
|
||||
/*
|
||||
* We should try to get rid of offsetBias (always 0 or 1, where 1 is
|
||||
* JSOP_{NOP,POP}_LENGTH), which is used only by SRC_FOR and SRC_DECL.
|
||||
*/
|
||||
JS_FRIEND_DATA(JSSrcNoteSpec) js_SrcNoteSpec[] = {
|
||||
{"null", 0, 0, 0},
|
||||
{"if", 0, 0, 0},
|
||||
|
@ -2090,8 +2090,10 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||
rval = "";
|
||||
|
||||
do_forloop:
|
||||
JS_ASSERT(SN_TYPE(sn) == SRC_FOR);
|
||||
|
||||
/* Skip the JSOP_NOP or JSOP_POP bytecode. */
|
||||
pc++;
|
||||
pc += JSOP_NOP_LENGTH;
|
||||
|
||||
/* Get the cond, next, and loop-closing tail offsets. */
|
||||
cond = js_GetSrcNoteOffset(sn, 0);
|
||||
@ -2102,13 +2104,12 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||
* If this loop has a condition, then pc points at a goto
|
||||
* targeting the condition.
|
||||
*/
|
||||
pc2 = pc;
|
||||
if (cond != tail) {
|
||||
LOCAL_ASSERT(*pc == JSOP_GOTO || *pc == JSOP_GOTOX);
|
||||
pc += (*pc == JSOP_GOTO)
|
||||
? JSOP_GOTO_LENGTH
|
||||
: JSOP_GOTOX_LENGTH;
|
||||
pc2 += (*pc == JSOP_GOTO) ? JSOP_GOTO_LENGTH : JSOP_GOTOX_LENGTH;
|
||||
}
|
||||
LOCAL_ASSERT(tail == -GetJumpOffset(pc+tail, pc+tail));
|
||||
LOCAL_ASSERT(tail + GetJumpOffset(pc+tail, pc+tail) == pc2 - pc);
|
||||
|
||||
/* Print the keyword and the possibly empty init-part. */
|
||||
js_printf(jp, "\tfor (%s;", rval);
|
||||
@ -2123,16 +2124,29 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||
js_puts(jp, ";");
|
||||
|
||||
if (next != cond) {
|
||||
/* Decompile the loop updater. */
|
||||
DECOMPILE_CODE(pc + next,
|
||||
cond - next - JSOP_POP_LENGTH);
|
||||
js_printf(jp, " %s", POP_STR());
|
||||
/*
|
||||
* Decompile the loop updater. It may end in a JSOP_POP
|
||||
* that we skip; or in a JSOP_POPN that we do not skip,
|
||||
* followed by a JSOP_NOP (skipped as if it's a POP).
|
||||
* We cope with the difference between these two cases
|
||||
* by checking for stack imbalance and popping if there
|
||||
* is an rval.
|
||||
*/
|
||||
uintN saveTop = ss->top;
|
||||
|
||||
DECOMPILE_CODE(pc + next, cond - next - JSOP_POP_LENGTH);
|
||||
LOCAL_ASSERT(ss->top - saveTop <= 1U);
|
||||
rval = (ss->top == saveTop)
|
||||
? ss->sprinter.base + ss->sprinter.offset
|
||||
: POP_STR();
|
||||
js_printf(jp, " %s", rval);
|
||||
}
|
||||
|
||||
/* Do the loop body. */
|
||||
js_printf(jp, ") {\n");
|
||||
jp->indent += 4;
|
||||
DECOMPILE_CODE(pc, next);
|
||||
next -= pc2 - pc;
|
||||
DECOMPILE_CODE(pc2, next);
|
||||
jp->indent -= 4;
|
||||
js_printf(jp, "\t}\n");
|
||||
|
||||
@ -2293,17 +2307,28 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Kill newtop before the end_groupassignment: label by
|
||||
* retracting/popping early. Control will either jump to
|
||||
* do_forloop: or do_letheadbody: or else break from our
|
||||
* case JSOP_POPN: after the switch (*pc2) below.
|
||||
* If this is an empty group assignment, we have no stack
|
||||
* budget into which we can push our result string. Adjust
|
||||
* ss->sprinter.offset so that our consumer can find the
|
||||
* empty group assignment decompilation.
|
||||
*/
|
||||
if (newtop < oldtop) {
|
||||
if (newtop == oldtop) {
|
||||
ss->sprinter.offset = todo;
|
||||
} else {
|
||||
/*
|
||||
* Kill newtop before the end_groupassignment: label by
|
||||
* retracting/popping early. Control will either jump
|
||||
* to do_forloop: or do_letheadbody: or else break from
|
||||
* our case JSOP_POPN: after the switch (*pc2) below.
|
||||
*/
|
||||
LOCAL_ASSERT(newtop < oldtop);
|
||||
ss->sprinter.offset = GetOff(ss, newtop);
|
||||
ss->top = newtop;
|
||||
}
|
||||
|
||||
end_groupassignment:
|
||||
LOCAL_ASSERT(*pc == JSOP_POPN);
|
||||
|
||||
/*
|
||||
* Thread directly to the next opcode if we can, to handle
|
||||
* the special cases of a group assignment in the first or
|
||||
@ -2318,15 +2343,15 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||
rval = OFF2STR(&ss->sprinter, todo);
|
||||
todo = -2;
|
||||
pc2 = pc + oplen;
|
||||
switch (*pc2) {
|
||||
case JSOP_NOP:
|
||||
/* First part of for(;;) or let block/expr head. */
|
||||
if (*pc2 == JSOP_NOP) {
|
||||
sn = js_GetSrcNote(jp->script, pc2);
|
||||
if (sn) {
|
||||
if (SN_TYPE(sn) == SRC_FOR) {
|
||||
op = JSOP_NOP;
|
||||
pc = pc2;
|
||||
goto do_forloop;
|
||||
}
|
||||
|
||||
if (SN_TYPE(sn) == SRC_DECL) {
|
||||
if (ss->top == StackDepth(jp->script)) {
|
||||
/*
|
||||
@ -2334,33 +2359,34 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||
* in the head of a let whose body block
|
||||
* is also empty.
|
||||
*/
|
||||
pc = pc2 + 1;
|
||||
pc = pc2 + JSOP_NOP_LENGTH;
|
||||
len = js_GetSrcNoteOffset(sn, 0);
|
||||
LOCAL_ASSERT(pc[len] == JSOP_LEAVEBLOCK);
|
||||
js_printf(jp, "\tlet (%s) {\n", rval);
|
||||
js_printf(jp, "\t}\n");
|
||||
goto end_popn;
|
||||
break;
|
||||
}
|
||||
todo = SprintCString(&ss->sprinter, rval);
|
||||
if (todo < 0 || !PushOff(ss, todo, JSOP_NOP))
|
||||
return NULL;
|
||||
op = JSOP_POP;
|
||||
pc = pc2 + 1;
|
||||
pc = pc2 + JSOP_NOP_LENGTH;
|
||||
goto do_letheadbody;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case JSOP_GOTO:
|
||||
case JSOP_GOTOX:
|
||||
/* Third part of for(;;) loop head. */
|
||||
cond = GetJumpOffset(pc2, pc2);
|
||||
sn = js_GetSrcNote(jp->script, pc2 + cond - 1);
|
||||
if (sn && SN_TYPE(sn) == SRC_FOR) {
|
||||
} else {
|
||||
/*
|
||||
* An unnannotated NOP following a POPN must be the
|
||||
* third part of for(;;) loop head. If the POPN's
|
||||
* immediate operand is 0, then we may have no slot
|
||||
* on the sprint-stack in which to push our result
|
||||
* string. In this case the result can be recovered
|
||||
* at ss->sprinter.base + ss->sprinter.offset.
|
||||
*/
|
||||
if (GET_UINT16(pc) == 0)
|
||||
break;
|
||||
todo = SprintCString(&ss->sprinter, rval);
|
||||
saveop = JSOP_NOP;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2369,7 +2395,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||
*/
|
||||
if (todo == -2)
|
||||
js_printf(jp, "\t%s;\n", rval);
|
||||
end_popn:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user