mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 677957 - Fix peculiarly dynamically-nested for-in loops. ("Assertion failure: !cx->iterValue.isMagic(JS_NO_ITER_VALUE), at jsiter.cpp:1017") r=dvander.
This commit is contained in:
parent
a622e35128
commit
08f5a5a5bd
4
js/src/jit-test/tests/basic/bug677957-1.js
Normal file
4
js/src/jit-test/tests/basic/bug677957-1.js
Normal file
@ -0,0 +1,4 @@
|
||||
function test() {
|
||||
for each (var i in []) {}
|
||||
}
|
||||
for each (new test().p in [0]) {}
|
13
js/src/jit-test/tests/basic/bug677957-2.js
Normal file
13
js/src/jit-test/tests/basic/bug677957-2.js
Normal file
@ -0,0 +1,13 @@
|
||||
var x = {f: 1, g: 0};
|
||||
function f() {
|
||||
for each (new f().nosuch.prop in x)
|
||||
throw 'FAIL';
|
||||
}
|
||||
|
||||
var e;
|
||||
try {
|
||||
f();
|
||||
} catch (exc) {
|
||||
e = exc;
|
||||
}
|
||||
assertEq(e instanceof InternalError, true);
|
@ -1,15 +1,15 @@
|
||||
// |jit-test| debug
|
||||
|
||||
f = (function() {
|
||||
function b() {
|
||||
"use strict";
|
||||
Object.defineProperty(this, "x", ({}));
|
||||
}
|
||||
for each(let d in [0, 0]) {
|
||||
try {
|
||||
b(d);
|
||||
} catch (e) {}
|
||||
}
|
||||
})
|
||||
trap(f, 54, undefined);
|
||||
f()
|
||||
function b() {
|
||||
"use strict";
|
||||
Object.defineProperty(this, "x", ({}));
|
||||
}
|
||||
for each(let d in [0, 0]) {
|
||||
try {
|
||||
b(d);
|
||||
} catch (e) {}
|
||||
}
|
||||
});
|
||||
trap(f, 53, undefined);
|
||||
f();
|
||||
|
@ -4640,7 +4640,8 @@ EmitAssignment(JSContext *cx, JSCodeGenerator *cg, JSParseNode *lhs, JSOp op, JS
|
||||
case TOK_LP:
|
||||
if (!js_EmitTree(cx, cg, lhs))
|
||||
return false;
|
||||
offset++;
|
||||
JS_ASSERT(lhs->pn_xflags & PNX_SETCALL);
|
||||
offset += 2;
|
||||
break;
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
case TOK_UNARYOP:
|
||||
@ -4717,8 +4718,13 @@ EmitAssignment(JSContext *cx, JSCodeGenerator *cg, JSParseNode *lhs, JSOp op, JS
|
||||
if (!js_EmitTree(cx, cg, rhs))
|
||||
return false;
|
||||
} else {
|
||||
/* The value to assign is the next enumeration value in a for-in loop. */
|
||||
if (js_Emit2(cx, cg, JSOP_ITERNEXT, offset) < 0)
|
||||
/*
|
||||
* The value to assign is the next enumeration value in a for-in loop.
|
||||
* That value is produced by a JSOP_ITERNEXT op, previously emitted.
|
||||
* If offset == 1, that slot is already at the top of the
|
||||
* stack. Otherwise, rearrange the stack to put that value on top.
|
||||
*/
|
||||
if (offset != 1 && js_Emit2(cx, cg, JSOP_PICK, offset - 1) < 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -5421,7 +5427,6 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
SET_STATEMENT_TOP(&stmtInfo, top);
|
||||
if (EmitTraceOp(cx, cg, NULL) < 0)
|
||||
return JS_FALSE;
|
||||
|
||||
#ifdef DEBUG
|
||||
intN loopDepth = cg->stackDepth;
|
||||
#endif
|
||||
@ -5432,6 +5437,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
* so that the decompiler can distinguish 'for (x in y)' from
|
||||
* 'for (var x in y)'.
|
||||
*/
|
||||
if (js_Emit1(cx, cg, JSOP_ITERNEXT) < 0)
|
||||
return false;
|
||||
if (!EmitAssignment(cx, cg, pn2->pn_kid2, JSOP_NOP, NULL))
|
||||
return false;
|
||||
tmp2 = CG_OFFSET(cg);
|
||||
|
@ -2697,11 +2697,10 @@ END_CASE(JSOP_MOREITER)
|
||||
|
||||
BEGIN_CASE(JSOP_ITERNEXT)
|
||||
{
|
||||
Value *itervp = regs.sp - GET_INT8(regs.pc);
|
||||
JS_ASSERT(itervp >= regs.fp()->base());
|
||||
JS_ASSERT(itervp->isObject());
|
||||
JS_ASSERT(regs.sp - 1 >= regs.fp()->base());
|
||||
JS_ASSERT(regs.sp[-1].isObject());
|
||||
PUSH_NULL();
|
||||
if (!IteratorNext(cx, &itervp->toObject(), ®s.sp[-1]))
|
||||
if (!IteratorNext(cx, ®s.sp[-2].toObject(), ®s.sp[-1]))
|
||||
goto error;
|
||||
}
|
||||
END_CASE(JSOP_ITERNEXT)
|
||||
|
@ -2723,6 +2723,26 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||
sn = NULL;
|
||||
break;
|
||||
|
||||
case JSOP_PICK:
|
||||
{
|
||||
uintN i = pc[1];
|
||||
LOCAL_ASSERT(ss->top > i + 1);
|
||||
uintN bottom = ss->top - (i + 1);
|
||||
|
||||
ptrdiff_t pickedOffset = ss->offsets[bottom];
|
||||
memmove(ss->offsets + bottom, ss->offsets + bottom + 1,
|
||||
i * sizeof(ss->offsets[0]));
|
||||
ss->offsets[ss->top - 1] = pickedOffset;
|
||||
|
||||
jsbytecode pickedOpcode = ss->opcodes[bottom];
|
||||
memmove(ss->opcodes + bottom, ss->opcodes + bottom + 1,
|
||||
i * sizeof(ss->opcodes[0]));
|
||||
ss->opcodes[ss->top - 1] = pickedOpcode;
|
||||
|
||||
todo = -2;
|
||||
break;
|
||||
}
|
||||
|
||||
case JSOP_ENTERWITH:
|
||||
LOCAL_ASSERT(!js_GetSrcNote(jp->script, pc));
|
||||
rval = POP_STR();
|
||||
@ -3231,7 +3251,9 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||
* <<RHS>>
|
||||
* iter
|
||||
* pc: goto/gotox C [src_for_in(B, D)]
|
||||
* A: <<LHS = iternext>>
|
||||
* A: trace
|
||||
* iternext
|
||||
* <<LHS = result_of_iternext>>
|
||||
* B: pop [maybe a src_decl_var/let]
|
||||
* <<S>>
|
||||
* C: moreiter
|
||||
@ -3254,11 +3276,14 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||
* JSOP_MOREITER or JSOP_IFNE, though we do quick asserts
|
||||
* to check that they are there.
|
||||
*/
|
||||
LOCAL_ASSERT(pc[-JSOP_ITER_LENGTH] == JSOP_ITER);
|
||||
LOCAL_ASSERT(pc[js_CodeSpec[op].length] == JSOP_TRACE);
|
||||
LOCAL_ASSERT(pc[js_CodeSpec[op].length + JSOP_TRACE_LENGTH] == JSOP_ITERNEXT);
|
||||
cond = GetJumpOffset(pc, pc);
|
||||
next = js_GetSrcNoteOffset(sn, 0);
|
||||
tail = js_GetSrcNoteOffset(sn, 1);
|
||||
JS_ASSERT(pc[next] == JSOP_POP);
|
||||
JS_ASSERT(pc[cond] == JSOP_MOREITER);
|
||||
LOCAL_ASSERT(pc[next] == JSOP_POP);
|
||||
LOCAL_ASSERT(pc[cond] == JSOP_MOREITER);
|
||||
DECOMPILE_CODE(pc + oplen, next - oplen);
|
||||
lval = POP_STR();
|
||||
|
||||
@ -3266,7 +3291,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||
* This string "<next>" comes from jsopcode.tbl. It stands
|
||||
* for the result pushed by JSOP_ITERNEXT.
|
||||
*/
|
||||
JS_ASSERT(strcmp(lval + strlen(lval) - 9, " = <next>") == 0);
|
||||
LOCAL_ASSERT(strcmp(lval + strlen(lval) - 9, " = <next>") == 0);
|
||||
const_cast<char *>(lval)[strlen(lval) - 9] = '\0';
|
||||
LOCAL_ASSERT(ss->top >= 1);
|
||||
|
||||
|
@ -199,8 +199,9 @@ OPDEF(JSOP_STRICTEQ, 72, "stricteq", "===", 1, 2, 1, 10, JOF_BYTE|J
|
||||
OPDEF(JSOP_STRICTNE, 73, "strictne", "!==", 1, 2, 1, 10, JOF_BYTE|JOF_DETECTING|JOF_LEFTASSOC)
|
||||
|
||||
/*
|
||||
* Host object extension: given 'o.item(i) = j', the left-hand side compiles
|
||||
* JSOP_SETCALL after JSOP_CALL, JSOP_EVAL, JSOP_FUNAPPLY, or JSOP_FUNCALL.
|
||||
* Sometimes web pages do 'o.Item(i) = j'. This is not an early SyntaxError,
|
||||
* for web compatibility. Instead we emit JSOP_SETCALL after the function call,
|
||||
* an opcode that always throws.
|
||||
*/
|
||||
OPDEF(JSOP_SETCALL, 74, "setcall", NULL, 1, 1, 2, 18, JOF_BYTE)
|
||||
|
||||
@ -218,7 +219,7 @@ OPDEF(JSOP_SETCALL, 74, "setcall", NULL, 1, 1, 2, 18, JOF_BYTE)
|
||||
*/
|
||||
OPDEF(JSOP_ITER, 75, "iter", NULL, 2, 1, 1, 0, JOF_UINT8)
|
||||
OPDEF(JSOP_MOREITER, 76, "moreiter", NULL, 1, 1, 2, 0, JOF_BYTE)
|
||||
OPDEF(JSOP_ITERNEXT, 77, "iternext", "<next>", 2, 0, 1, 0, JOF_UINT8)
|
||||
OPDEF(JSOP_ITERNEXT, 77, "iternext", "<next>", 1, 0, 1, 0, JOF_BYTE)
|
||||
OPDEF(JSOP_ENDITER, 78, "enditer", NULL, 1, 1, 0, 0, JOF_BYTE)
|
||||
|
||||
OPDEF(JSOP_FUNAPPLY, 79, "funapply", NULL, 3, -1, 1, 18, JOF_UINT16|JOF_INVOKE|JOF_TYPESET)
|
||||
|
@ -14862,7 +14862,7 @@ JS_REQUIRES_STACK AbortableRecordingStatus
|
||||
TraceRecorder::record_JSOP_ITERNEXT()
|
||||
{
|
||||
LIns* v_ins;
|
||||
Value &iterobj_val = stackval(-GET_INT8(cx->regs().pc));
|
||||
Value &iterobj_val = stackval(-1);
|
||||
CHECK_STATUS_A(unboxNextValue(iterobj_val, v_ins));
|
||||
stack(0, v_ins);
|
||||
return ARECORD_CONTINUE;
|
||||
|
@ -222,7 +222,7 @@ JS_XDRFindClassById(JSXDRState *xdr, uint32 id);
|
||||
* before deserialization of bytecode. If the saved version does not match
|
||||
* the current version, abort deserialization and invalidate the file.
|
||||
*/
|
||||
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 93)
|
||||
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 94)
|
||||
|
||||
/*
|
||||
* Library-private functions.
|
||||
|
@ -1682,7 +1682,7 @@ mjit::Compiler::generateMethod()
|
||||
END_CASE(JSOP_ARGUMENTS)
|
||||
|
||||
BEGIN_CASE(JSOP_ITERNEXT)
|
||||
iterNext(GET_INT8(PC));
|
||||
iterNext();
|
||||
END_CASE(JSOP_ITERNEXT)
|
||||
|
||||
BEGIN_CASE(JSOP_DUP)
|
||||
@ -5583,9 +5583,9 @@ mjit::Compiler::iter(uintN flags)
|
||||
* of a for-in loop to put the next value on the stack.
|
||||
*/
|
||||
void
|
||||
mjit::Compiler::iterNext(ptrdiff_t offset)
|
||||
mjit::Compiler::iterNext()
|
||||
{
|
||||
FrameEntry *fe = frame.peek(-offset);
|
||||
FrameEntry *fe = frame.peek(-1);
|
||||
RegisterID reg = frame.tempRegForData(fe);
|
||||
|
||||
/* Is it worth trying to pin this longer? Prolly not. */
|
||||
@ -5629,7 +5629,6 @@ mjit::Compiler::iterNext(ptrdiff_t offset)
|
||||
frame.freeReg(T2);
|
||||
|
||||
stubcc.leave();
|
||||
stubcc.masm.move(Imm32(offset), Registers::ArgReg1);
|
||||
OOL_STUBCALL(stubs::IterNext, REJOIN_FALLTHROUGH);
|
||||
|
||||
frame.pushUntypedPayload(JSVAL_TYPE_STRING, T3);
|
||||
|
@ -578,7 +578,7 @@ class Compiler : public BaseCompiler
|
||||
bool constantFoldBranch(jsbytecode *target, bool taken);
|
||||
bool emitStubCmpOp(BoolStub stub, jsbytecode *target, JSOp fused);
|
||||
bool iter(uintN flags);
|
||||
void iterNext(ptrdiff_t offset);
|
||||
void iterNext();
|
||||
bool iterMore(jsbytecode *target);
|
||||
void iterEnd();
|
||||
MaybeJump loadDouble(FrameEntry *fe, FPRegisterID *fpReg, bool *allocated);
|
||||
|
@ -1843,12 +1843,12 @@ stubs::InitMethod(VMFrame &f, JSAtom *atom)
|
||||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
stubs::IterNext(VMFrame &f, int32 offset)
|
||||
stubs::IterNext(VMFrame &f)
|
||||
{
|
||||
JS_ASSERT(f.regs.sp - offset >= f.fp()->base());
|
||||
JS_ASSERT(f.regs.sp[-offset].isObject());
|
||||
JS_ASSERT(f.regs.sp - 1 >= f.fp()->base());
|
||||
JS_ASSERT(f.regs.sp[-1].isObject());
|
||||
|
||||
JSObject *iterobj = &f.regs.sp[-offset].toObject();
|
||||
JSObject *iterobj = &f.regs.sp[-1].toObject();
|
||||
f.regs.sp[0].setNull();
|
||||
f.regs.sp++;
|
||||
if (!js_IteratorNext(f.cx, iterobj, &f.regs.sp[-1]))
|
||||
|
@ -192,7 +192,7 @@ void JS_FASTCALL StrictEq(VMFrame &f);
|
||||
void JS_FASTCALL StrictNe(VMFrame &f);
|
||||
|
||||
void JS_FASTCALL Iter(VMFrame &f, uint32 flags);
|
||||
void JS_FASTCALL IterNext(VMFrame &f, int32 offset);
|
||||
void JS_FASTCALL IterNext(VMFrame &f);
|
||||
JSBool JS_FASTCALL IterMore(VMFrame &f);
|
||||
void JS_FASTCALL EndIter(VMFrame &f);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user