diff --git a/js/src/methodjit/Compiler.cpp b/js/src/methodjit/Compiler.cpp index 750c45a27c3..bd015c6d829 100644 --- a/js/src/methodjit/Compiler.cpp +++ b/js/src/methodjit/Compiler.cpp @@ -727,6 +727,15 @@ mjit::Compiler::generateMethod() } END_CASE(JSOP_AND) + BEGIN_CASE(JSOP_TABLESWITCH) + frame.forgetEverything(); + masm.move(ImmPtr(PC), Registers::ArgReg1); + stubCall(stubs::TableSwitch, Uses(1), Defs(0)); + masm.jump(Registers::ReturnReg); + PC += js_GetVariableBytecodeLength(PC); + break; + END_CASE(JSOP_TABLESWITCH) + BEGIN_CASE(JSOP_LOOKUPSWITCH) frame.forgetEverything(); masm.move(ImmPtr(PC), Registers::ArgReg1); diff --git a/js/src/methodjit/StubCalls.cpp b/js/src/methodjit/StubCalls.cpp index 37a471b667c..077d381b407 100644 --- a/js/src/methodjit/StubCalls.cpp +++ b/js/src/methodjit/StubCalls.cpp @@ -2725,3 +2725,52 @@ stubs::LookupSwitch(VMFrame &f, jsbytecode *pc) return script->nmap[offs]; } +void * JS_FASTCALL +stubs::TableSwitch(VMFrame &f, jsbytecode *origPc) +{ + jsbytecode * const originalPC = origPc; + jsbytecode *pc = originalPC; + JSScript *script = f.fp->script; + uint32 jumpOffset = GET_JUMP_OFFSET(pc); + pc += JUMP_OFFSET_LEN; + + /* Note: compiler adjusts the stack beforehand. */ + Value rval = f.regs.sp[-1]; + + jsint tableIdx; + if (rval.isInt32()) { + tableIdx = rval.asInt32(); + } else if (rval.isDouble()) { + double d = rval.asDouble(); + if (d == 0) { + /* Treat -0 (double) as 0. */ + tableIdx = 0; + } else if (!JSDOUBLE_IS_INT32(d, tableIdx)) { + goto finally; + } + } else { + goto finally; + } + + { + uint32 low = GET_JUMP_OFFSET(pc); + pc += JUMP_OFFSET_LEN; + uint32 high = GET_JUMP_OFFSET(pc); + pc += JUMP_OFFSET_LEN; + + tableIdx -= low; + if ((jsuint) tableIdx < (jsuint)(high - low + 1)) { + pc += JUMP_OFFSET_LEN * tableIdx; + uint32 candidateOffset = GET_JUMP_OFFSET(pc); + if (candidateOffset) + jumpOffset = candidateOffset; + } + } + +finally: + /* Provide the native address. */ + ptrdiff_t offset = (originalPC + jumpOffset) - script->code; + JS_ASSERT(script->nmap[offset]); + return script->nmap[offset]; +} + diff --git a/js/src/methodjit/StubCalls.h b/js/src/methodjit/StubCalls.h index 6baeb7f98ed..d6dc2d416d8 100644 --- a/js/src/methodjit/StubCalls.h +++ b/js/src/methodjit/StubCalls.h @@ -63,6 +63,7 @@ void * JS_FASTCALL New(VMFrame &f, uint32 argc); void * JS_FASTCALL Return(VMFrame &f); void JS_FASTCALL Throw(VMFrame &f); void * JS_FASTCALL LookupSwitch(VMFrame &f, jsbytecode *pc); +void * JS_FASTCALL TableSwitch(VMFrame &f, jsbytecode *origPc); void JS_FASTCALL BindName(VMFrame &f); void JS_FASTCALL SetName(VMFrame &f, uint32 index);