Bug 507156 - JSOP_TABLESWITCH always aborts, sometimes without an abort message. r=dmandelin.
This commit is contained in:
Родитель
9b03833130
Коммит
702f3daabf
|
@ -7225,24 +7225,26 @@ TraceRecorder::ifop()
|
|||
* "first" time we hit the op. Later, when we start traces after exiting that
|
||||
* trace, we just patch.
|
||||
*/
|
||||
JS_REQUIRES_STACK LIns*
|
||||
JS_REQUIRES_STACK JSRecordingStatus
|
||||
TraceRecorder::tableswitch()
|
||||
{
|
||||
jsval& v = stackval(-1);
|
||||
|
||||
/* No need to guard if the condition can't match any of the cases. */
|
||||
if (!isNumber(v))
|
||||
return NULL;
|
||||
return JSRS_CONTINUE;
|
||||
|
||||
/* No need to guard if the condition is constant. */
|
||||
LIns* v_ins = f2i(get(&v));
|
||||
if (v_ins->isconst() || v_ins->isconstq())
|
||||
return NULL;
|
||||
return JSRS_CONTINUE;
|
||||
|
||||
jsbytecode* pc = cx->fp->regs->pc;
|
||||
/* Starting a new trace after exiting a trace via switch. */
|
||||
if (anchor &&
|
||||
(anchor->exitType == CASE_EXIT || anchor->exitType == DEFAULT_EXIT) &&
|
||||
fragment->ip == pc) {
|
||||
return NULL;
|
||||
return JSRS_CONTINUE;
|
||||
}
|
||||
|
||||
/* Decode jsop. */
|
||||
|
@ -7263,14 +7265,8 @@ TraceRecorder::tableswitch()
|
|||
* Really large tables won't fit in a page. This is a conservative check.
|
||||
* If it matters in practice we need to go off-page.
|
||||
*/
|
||||
if ((high + 1 - low) * sizeof(intptr_t*) + 128 > (unsigned) LARGEST_UNDERRUN_PROT) {
|
||||
/*
|
||||
* This throws away the return value of switchop but it seems ok
|
||||
* because switchop always returns true.
|
||||
*/
|
||||
(void) switchop();
|
||||
return NULL;
|
||||
}
|
||||
if ((high + 1 - low) * sizeof(intptr_t*) + 128 > (unsigned) LARGEST_UNDERRUN_PROT)
|
||||
return switchop();
|
||||
|
||||
/* Generate switch LIR. */
|
||||
LIns* si_ins = lir_buf_writer->insSkip(sizeof(SwitchInfo));
|
||||
|
@ -7284,7 +7280,10 @@ TraceRecorder::tableswitch()
|
|||
lir->insStorei(diff, lir->insImmPtr(&si->index), 0);
|
||||
VMSideExit* exit = snapshot(CASE_EXIT);
|
||||
exit->switchInfo = si;
|
||||
return lir->insGuard(LIR_xtbl, diff, createGuardRecord(exit));
|
||||
LIns* guardIns = lir->insGuard(LIR_xtbl, diff, createGuardRecord(exit));
|
||||
fragment->lastIns = guardIns;
|
||||
compile(&JS_TRACE_MONITOR(cx));
|
||||
return JSRS_STOP;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -11073,12 +11072,7 @@ TraceRecorder::record_JSOP_TABLESWITCH()
|
|||
{
|
||||
#ifdef NANOJIT_IA32
|
||||
/* Handle tableswitches specially -- prepare a jump table if needed. */
|
||||
LIns* guardIns = tableswitch();
|
||||
if (guardIns) {
|
||||
fragment->lastIns = guardIns;
|
||||
compile(&JS_TRACE_MONITOR(cx));
|
||||
}
|
||||
return JSRS_STOP;
|
||||
return tableswitch();
|
||||
#else
|
||||
return switchop();
|
||||
#endif
|
||||
|
|
|
@ -678,7 +678,7 @@ class TraceRecorder : public avmplus::GCObject {
|
|||
JS_REQUIRES_STACK JSRecordingStatus ifop();
|
||||
JS_REQUIRES_STACK JSRecordingStatus switchop();
|
||||
#ifdef NANOJIT_IA32
|
||||
JS_REQUIRES_STACK nanojit::LIns* tableswitch();
|
||||
JS_REQUIRES_STACK JSRecordingStatus tableswitch();
|
||||
#endif
|
||||
JS_REQUIRES_STACK JSRecordingStatus inc(jsval& v, jsint incr, bool pre = true);
|
||||
JS_REQUIRES_STACK JSRecordingStatus inc(jsval& v, nanojit::LIns*& v_ins, jsint incr,
|
||||
|
|
|
@ -4365,6 +4365,49 @@ function testSwitchUndefined()
|
|||
testSwitchUndefined.expected = 5;
|
||||
test(testSwitchUndefined);
|
||||
|
||||
function testTableSwitch1() {
|
||||
var x = 'miss';
|
||||
var i, j = 0;
|
||||
for (i = 0; i < RUNLOOP + 10; i++) {
|
||||
switch (x) {
|
||||
case 1: case 2: case 3: case 4: case 5: throw "FAIL";
|
||||
default: j++;
|
||||
}
|
||||
}
|
||||
assertEq(i, j);
|
||||
}
|
||||
testTableSwitch1.jitstats = {
|
||||
recorderStarted: 1,
|
||||
sideExitIntoInterpreter: 1,
|
||||
recorderAborted: 0,
|
||||
traceCompleted: 1
|
||||
};
|
||||
test(testTableSwitch1);
|
||||
|
||||
function testTableSwitch2() {
|
||||
var arr = [2, 2, 2, 2, 2, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5];
|
||||
var s = '';
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
switch (arr[i]) {
|
||||
case 0: case 1: case 3: case 4:
|
||||
throw "FAIL";
|
||||
case 2:
|
||||
s += '2';
|
||||
break;
|
||||
case 5:
|
||||
s += '5';
|
||||
}
|
||||
}
|
||||
assertEq(s, arr.join(""));
|
||||
}
|
||||
testTableSwitch2.jitstats = {
|
||||
recorderStarted: 1,
|
||||
sideExitIntoInterpreter: 4,
|
||||
recorderAborted: 0,
|
||||
traceCompleted: 3
|
||||
};
|
||||
test(testTableSwitch2);
|
||||
|
||||
function testGeneratorDeepBail() {
|
||||
function g() { yield 2; }
|
||||
var iterables = [[1], [], [], [], g()];
|
||||
|
|
Загрузка…
Ссылка в новой задаче