Bug 507156 - JSOP_TABLESWITCH always aborts, sometimes without an abort message. r=dmandelin.

This commit is contained in:
Jason Orendorff 2009-07-30 13:06:15 -05:00
Родитель 9b03833130
Коммит 702f3daabf
3 изменённых файлов: 57 добавлений и 20 удалений

Просмотреть файл

@ -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()];