Bug 1501316 - Remove Baseline's TableSwitch IC, use resume entries instead. r=tcampbell
authorJan de Mooij <jdemooij@mozilla.com>
Fri, 09 Nov 2018 06:53:06 +0000
changeset 445375 7283b13fd2d209e706e47b053278b43b0ea2fa84
parent 445374 9caefcf2df2f1d3ef9585eaec388c1e124db7a90
child 445376 e84c675467af087d09eab41ec950af592c9a8608
push id35015
push userdluca@mozilla.com
push dateFri, 09 Nov 2018 17:45:20 +0000
treeherdermozilla-central@2f1158e5e0ce [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstcampbell
bugs1501316
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1501316 - Remove Baseline's TableSwitch IC, use resume entries instead. r=tcampbell To not affect Baseline code size too much, this adds a trampoline for the double-to-int32 Value conversion. Depends on D11019 Differential Revision: https://phabricator.services.mozilla.com/D11039
js/src/frontend/BytecodeEmitter.cpp
js/src/jit/BaselineCompiler.cpp
js/src/jit/BaselineIC.cpp
js/src/jit/BaselineIC.h
js/src/jit/BaselineICList.h
js/src/jit/BaselineJIT.cpp
js/src/jit/CodeGenerator.cpp
js/src/jit/Ion.cpp
js/src/jit/JitRealm.h
js/src/jit/arm/SharedICHelpers-arm.h
js/src/jit/arm64/SharedICHelpers-arm64.h
js/src/jit/mips-shared/SharedICHelpers-mips-shared.h
js/src/jit/none/SharedICHelpers-none.h
js/src/jit/x64/SharedICHelpers-x64.h
js/src/jit/x86/SharedICHelpers-x86.h
js/src/vm/Opcodes.h
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -2191,16 +2191,19 @@ BytecodeEmitter::isRunOnceLambda()
 
 bool
 BytecodeEmitter::allocateResumeIndex(ptrdiff_t offset, uint32_t* resumeIndex)
 {
     static constexpr uint32_t MaxResumeIndex = JS_BITMASK(24);
 
     static_assert(MaxResumeIndex < uint32_t(GeneratorObject::RESUME_INDEX_CLOSING),
                   "resumeIndex should not include magic GeneratorObject resumeIndex values");
+    static_assert(MaxResumeIndex <= INT32_MAX / sizeof(uintptr_t),
+                  "resumeIndex * sizeof(uintptr_t) must fit in an int32. JIT code relies "
+                  "on this when loading resume entries from BaselineScript");
 
     *resumeIndex = resumeOffsetList.length();
     if (*resumeIndex > MaxResumeIndex) {
         reportError(nullptr, JSMSG_TOO_MANY_RESUME_INDEXES);
         return false;
     }
 
     return resumeOffsetList.append(offset);
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -3944,16 +3944,28 @@ BaselineCompiler::emit_JSOP_GOSUB()
 {
     // Jump to the finally block.
     frame.syncStack(0);
     jsbytecode* target = pc + GET_JUMP_OFFSET(pc);
     masm.jump(labelOf(target));
     return true;
 }
 
+static void
+LoadBaselineScriptResumeEntries(MacroAssembler& masm, JSScript* script, Register dest,
+                                Register scratch)
+{
+    MOZ_ASSERT(dest != scratch);
+
+    masm.movePtr(ImmGCPtr(script), dest);
+    masm.loadPtr(Address(dest, JSScript::offsetOfBaselineScript()), dest);
+    masm.load32(Address(dest, BaselineScript::offsetOfResumeEntriesOffset()), scratch);
+    masm.addPtr(scratch, dest);
+}
+
 bool
 BaselineCompiler::emit_JSOP_RETSUB()
 {
     frame.popRegsAndSync(2);
 
     Label isReturn;
     masm.branchTestBooleanTruthy(/* branchIfTrue = */ false, R0, &isReturn);
 
@@ -3964,20 +3976,17 @@ BaselineCompiler::emit_JSOP_RETSUB()
         return false;
     }
 
     masm.bind(&isReturn);
 
     // R0 is |false|. R1 contains the resumeIndex to jump to.
     Register scratch1 = R2.scratchReg();
     Register scratch2 = R0.scratchReg();
-    masm.movePtr(ImmGCPtr(script), scratch1);
-    masm.loadPtr(Address(scratch1, JSScript::offsetOfBaselineScript()), scratch1);
-    masm.load32(Address(scratch1, BaselineScript::offsetOfResumeEntriesOffset()), scratch2);
-    masm.addPtr(scratch2, scratch1);
+    LoadBaselineScriptResumeEntries(masm, script, scratch1, scratch2);
     masm.unboxInt32(R1, scratch2);
     masm.loadPtr(BaseIndex(scratch1, scratch2, ScaleFromElemWidth(sizeof(uintptr_t))), scratch1);
     masm.jump(scratch1);
     return true;
 }
 
 typedef bool (*PushLexicalEnvFn)(JSContext*, BaselineFrame*, Handle<LexicalScope*>);
 static const VMFunction PushLexicalEnvInfo =
@@ -4483,19 +4492,54 @@ BaselineCompiler::emit_JSOP_TOSTRING()
     return true;
 }
 
 bool
 BaselineCompiler::emit_JSOP_TABLESWITCH()
 {
     frame.popRegsAndSync(1);
 
-    // Call IC.
-    ICTableSwitch::Compiler compiler(cx, script, pc);
-    return emitOpIC(compiler.getStub(&stubSpace_));
+    jsbytecode* defaultpc = pc + GET_JUMP_OFFSET(pc);
+    Label* defaultLabel = labelOf(defaultpc);
+
+    int32_t low = GET_JUMP_OFFSET(pc + 1 * JUMP_OFFSET_LEN);
+    int32_t high = GET_JUMP_OFFSET(pc + 2 * JUMP_OFFSET_LEN);
+    uint32_t firstResumeIndex = GET_RESUMEINDEX(pc + 3 * JUMP_OFFSET_LEN);
+    int32_t length = high - low + 1;
+
+    Register key = R0.scratchReg();
+    Register scratch1 = R1.scratchReg();
+    Register scratch2 = R2.scratchReg();
+
+    // Call a stub to convert R0 from double to int32 if needed.
+    // Note: this stub may clobber scratch1.
+    masm.call(cx->runtime()->jitRuntime()->getDoubleToInt32ValueStub());
+
+    // Jump to the 'default' pc if not int32 (tableswitch is only used when
+    // all cases are int32).
+    masm.branchTestInt32(Assembler::NotEqual, R0, defaultLabel);
+    masm.unboxInt32(R0, key);
+
+    // Subtract 'low'. Bounds check.
+    if (low != 0) {
+        masm.sub32(Imm32(low), key);
+    }
+    masm.branch32(Assembler::AboveOrEqual, key, Imm32(length), defaultLabel);
+
+    // Jump to resumeEntries[firstResumeIndex + key].
+    //
+    // Note: BytecodeEmitter::allocateResumeIndex static_asserts
+    // |firstResumeIndex * sizeof(uintptr_t)| fits in int32_t.
+
+    LoadBaselineScriptResumeEntries(masm, script, scratch1, scratch2);
+    masm.loadPtr(BaseIndex(scratch1, key, ScaleFromElemWidth(sizeof(uintptr_t)),
+                           firstResumeIndex * sizeof(uintptr_t)), scratch1);
+    masm.jump(scratch1);
+
+    return true;
 }
 
 bool
 BaselineCompiler::emit_JSOP_ITER()
 {
     frame.popRegsAndSync(1);
 
     ICGetIterator_Fallback::Compiler compiler(cx);
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -5137,101 +5137,16 @@ ICCall_ScriptedFunCall::Compiler::genera
     // Enter type monitor IC to type-check result.
     EmitEnterTypeMonitorIC(masm);
 
     masm.bind(&failure);
     EmitStubGuardFailure(masm);
     return true;
 }
 
-bool
-ICTableSwitch::Compiler::generateStubCode(MacroAssembler& masm)
-{
-    Label isInt32, notInt32, outOfRange;
-    Register scratch = R1.scratchReg();
-
-    masm.branchTestInt32(Assembler::NotEqual, R0, &notInt32);
-
-    Register key = masm.extractInt32(R0, ExtractTemp0);
-
-    masm.bind(&isInt32);
-
-    masm.load32(Address(ICStubReg, offsetof(ICTableSwitch, min_)), scratch);
-    masm.sub32(scratch, key);
-    masm.branch32(Assembler::BelowOrEqual,
-                  Address(ICStubReg, offsetof(ICTableSwitch, length_)), key, &outOfRange);
-
-    masm.loadPtr(Address(ICStubReg, offsetof(ICTableSwitch, table_)), scratch);
-    masm.loadPtr(BaseIndex(scratch, key, ScalePointer), scratch);
-
-    EmitChangeICReturnAddress(masm, scratch);
-    EmitReturnFromIC(masm);
-
-    masm.bind(&notInt32);
-
-    masm.branchTestDouble(Assembler::NotEqual, R0, &outOfRange);
-    masm.unboxDouble(R0, FloatReg0);
-
-    // N.B. -0 === 0, so convert -0 to a 0 int32.
-    masm.convertDoubleToInt32(FloatReg0, key, &outOfRange, /* negativeZeroCheck = */ false);
-    masm.jump(&isInt32);
-
-    masm.bind(&outOfRange);
-
-    masm.loadPtr(Address(ICStubReg, offsetof(ICTableSwitch, defaultTarget_)), scratch);
-
-    EmitChangeICReturnAddress(masm, scratch);
-    EmitReturnFromIC(masm);
-    return true;
-}
-
-ICStub*
-ICTableSwitch::Compiler::getStub(ICStubSpace* space)
-{
-    JitCode* code = getStubCode();
-    if (!code) {
-        return nullptr;
-    }
-
-    jsbytecode* pc = pc_;
-    pc += JUMP_OFFSET_LEN;
-    int32_t low = GET_JUMP_OFFSET(pc);
-    pc += JUMP_OFFSET_LEN;
-    int32_t high = GET_JUMP_OFFSET(pc);
-    int32_t length = high - low + 1;
-    pc += JUMP_OFFSET_LEN;
-
-    void** table = (void**) space->alloc(sizeof(void*) * length);
-    if (!table) {
-        ReportOutOfMemory(cx);
-        return nullptr;
-    }
-
-    jsbytecode* defaultpc = pc_ + GET_JUMP_OFFSET(pc_);
-
-    for (int32_t i = 0; i < length; i++) {
-        table[i] = script_->tableSwitchCasePC(pc_, i);
-    }
-
-    return newStub<ICTableSwitch>(space, code, table, low, length, defaultpc);
-}
-
-void
-ICTableSwitch::fixupJumpTable(JSScript* script, BaselineScript* baseline)
-{
-    PCMappingSlotInfo slotInfo;
-    defaultTarget_ = baseline->nativeCodeForPC(script, (jsbytecode*) defaultTarget_, &slotInfo);
-    MOZ_ASSERT(slotInfo.isStackSynced());
-
-    for (int32_t i = 0; i < length_; i++) {
-        table_[i] = baseline->nativeCodeForPC(script, (jsbytecode*) table_[i], &slotInfo);
-        MOZ_ASSERT(slotInfo.isStackSynced());
-    }
-}
-
 //
 // GetIterator_Fallback
 //
 
 static bool
 DoGetIteratorFallback(JSContext* cx, BaselineFrame* frame, ICGetIterator_Fallback* stub,
                       HandleValue value, MutableHandleValue res)
 {
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -2608,52 +2608,16 @@ class ICCall_IsSuspendedGenerator : publ
           : ICStubCompiler(cx, ICStub::Call_IsSuspendedGenerator)
         {}
         ICStub* getStub(ICStubSpace* space) override {
             return newStub<ICCall_IsSuspendedGenerator>(space, getStubCode());
         }
    };
 };
 
-// Stub for performing a TableSwitch, updating the IC's return address to jump
-// to whatever point the switch is branching to.
-class ICTableSwitch : public ICStub
-{
-    friend class ICStubSpace;
-
-  protected: // Protected to silence Clang warning.
-    void** table_;
-    int32_t min_;
-    int32_t length_;
-    void* defaultTarget_;
-
-    ICTableSwitch(JitCode* stubCode, void** table,
-                  int32_t min, int32_t length, void* defaultTarget)
-      : ICStub(TableSwitch, stubCode), table_(table),
-        min_(min), length_(length), defaultTarget_(defaultTarget)
-    {}
-
-  public:
-    void fixupJumpTable(JSScript* script, BaselineScript* baseline);
-
-    class Compiler : public ICStubCompiler {
-        MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-
-        JSScript* script_;
-        jsbytecode* pc_;
-
-      public:
-        Compiler(JSContext* cx, JSScript* script, jsbytecode* pc)
-          : ICStubCompiler(cx, ICStub::TableSwitch), script_(script), pc_(pc)
-        {}
-
-        ICStub* getStub(ICStubSpace* space) override;
-    };
-};
-
 // IC for constructing an iterator from an input value.
 class ICGetIterator_Fallback : public ICFallbackStub
 {
     friend class ICStubSpace;
 
     explicit ICGetIterator_Fallback(JitCode* stubCode)
       : ICFallbackStub(ICStub::GetIterator_Fallback, stubCode)
     { }
--- a/js/src/jit/BaselineICList.h
+++ b/js/src/jit/BaselineICList.h
@@ -56,18 +56,16 @@ namespace jit {
     _(GetName_Fallback)                          \
                                                  \
     _(BindName_Fallback)                         \
                                                  \
     _(GetIntrinsic_Fallback)                     \
                                                  \
     _(SetProp_Fallback)                          \
                                                  \
-    _(TableSwitch)                               \
-                                                 \
     _(GetIterator_Fallback)                      \
     _(IteratorMore_Fallback)                     \
     _(IteratorMore_Native)                       \
     _(IteratorClose_Fallback)                    \
                                                  \
     _(InstanceOf_Fallback)                       \
     _(InstanceOf_Function)                       \
                                                  \
--- a/js/src/jit/BaselineJIT.cpp
+++ b/js/src/jit/BaselineJIT.cpp
@@ -815,21 +815,16 @@ BaselineScript::copyICEntries(JSScript* 
         if (realEntry.firstStub()->isFallback()) {
             realEntry.firstStub()->toFallbackStub()->fixupICEntry(&realEntry);
         }
 
         if (realEntry.firstStub()->isTypeMonitor_Fallback()) {
             ICTypeMonitor_Fallback* stub = realEntry.firstStub()->toTypeMonitor_Fallback();
             stub->fixupICEntry(&realEntry);
         }
-
-        if (realEntry.firstStub()->isTableSwitch()) {
-            ICTableSwitch* stub = realEntry.firstStub()->toTableSwitch();
-            stub->fixupJumpTable(script, this);
-        }
     }
 }
 
 void
 BaselineScript::copyRetAddrEntries(JSScript* script, const RetAddrEntry* entries)
 {
     for (uint32_t i = 0; i < numRetAddrEntries(); i++) {
         retAddrEntry(i) = entries[i];
@@ -1145,17 +1140,17 @@ BaselineScript::purgeOptimizedStubs(Zone
                     lastStub->toMonitoredFallbackStub()->maybeFallbackMonitorStub();
                 if (lastMonStub) {
                     lastMonStub->resetMonitorStubChain(zone);
                 }
             }
         } else if (lastStub->isTypeMonitor_Fallback()) {
             lastStub->toTypeMonitor_Fallback()->resetMonitorStubChain(zone);
         } else {
-            MOZ_ASSERT(lastStub->isTableSwitch());
+            MOZ_CRASH("Unknown fallback stub");
         }
     }
 
 #ifdef DEBUG
     // All remaining stubs must be allocated in the fallback space.
     for (size_t i = 0; i < numICEntries(); i++) {
         ICEntry& entry = icEntry(i);
         ICStub* stub = entry.firstStub();
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -9003,16 +9003,33 @@ JitRuntime::generateInterpreterStub(Macr
 
     // InvokeFromInterpreterStub stores the return value in argv[0], where the
     // caller stored |this|.
     masm.loadValue(Address(masm.getStackPointer(), JitFrameLayout::offsetOfThis()),
                    JSReturnOperand);
     masm.ret();
 }
 
+void
+JitRuntime::generateDoubleToInt32ValueStub(MacroAssembler& masm)
+{
+    doubleToInt32ValueStubOffset_ = startTrampolineCode(masm);
+
+    Label done;
+    masm.branchTestDouble(Assembler::NotEqual, R0, &done);
+
+    masm.unboxDouble(R0, FloatReg0);
+    masm.convertDoubleToInt32(FloatReg0, R1.scratchReg(), &done,
+                              /* negativeZeroCheck = */ false);
+    masm.tagValue(JSVAL_TYPE_INT32, R1.scratchReg(), R0);
+
+    masm.bind(&done);
+    masm.abiret();
+}
+
 bool
 JitRuntime::generateTLEventVM(MacroAssembler& masm, const VMFunction& f, bool enter)
 {
 #ifdef JS_TRACE_LOGGING
     bool vmEventEnabled = TraceLogTextIdEnabled(TraceLogger_VM);
     bool vmSpecificEventEnabled = TraceLogTextIdEnabled(TraceLogger_VMSpecific);
 
     if (vmEventEnabled || vmSpecificEventEnabled) {
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -174,16 +174,17 @@ JitRuntime::JitRuntime()
     profilerExitFrameTailOffset_(0),
     enterJITOffset_(0),
     bailoutHandlerOffset_(0),
     argumentsRectifierOffset_(0),
     argumentsRectifierReturnOffset_(0),
     invalidatorOffset_(0),
     lazyLinkStubOffset_(0),
     interpreterStubOffset_(0),
+    doubleToInt32ValueStubOffset_(0),
     debugTrapHandler_(nullptr),
     baselineDebugModeOSRHandler_(nullptr),
     trampolineCode_(nullptr),
     functionWrappers_(nullptr),
     jitcodeGlobalTable_(nullptr),
 #ifdef DEBUG
     ionBailAfter_(0),
 #endif
@@ -297,16 +298,19 @@ JitRuntime::initialize(JSContext* cx)
     generateFreeStub(masm);
 
     JitSpew(JitSpew_Codegen, "# Emitting lazy link stub");
     generateLazyLinkStub(masm);
 
     JitSpew(JitSpew_Codegen, "# Emitting interpreter stub");
     generateInterpreterStub(masm);
 
+    JitSpew(JitSpew_Codegen, "# Emitting double-to-int32-value stub");
+    generateDoubleToInt32ValueStub(masm);
+
     JitSpew(JitSpew_Codegen, "# Emitting VM function wrappers");
     for (VMFunction* fun = VMFunction::functions; fun; fun = fun->next) {
         if (functionWrappers_->has(fun)) {
             // Duplicate VMFunction definition. See VMFunction::hash.
             continue;
         }
         JitSpew(JitSpew_Codegen, "# VM function wrapper (%s)", fun->name());
         if (!generateVMWrapper(cx, masm, *fun)) {
--- a/js/src/jit/JitRealm.h
+++ b/js/src/jit/JitRealm.h
@@ -122,16 +122,20 @@ class JitRuntime
     WriteOnceData<uint32_t> freeStubOffset_;
 
     // Thunk called to finish compilation of an IonScript.
     WriteOnceData<uint32_t> lazyLinkStubOffset_;
 
     // Thunk to enter the interpreter from JIT code.
     WriteOnceData<uint32_t> interpreterStubOffset_;
 
+    // Thunk to convert the value in R0 to int32 if it's a double.
+    // Note: this stub treats -0 as +0 and may clobber R1.scratchReg().
+    WriteOnceData<uint32_t> doubleToInt32ValueStubOffset_;
+
     // Thunk used by the debugger for breakpoint and step mode.
     WriteOnceData<JitCode*> debugTrapHandler_;
 
     // Thunk used to fix up on-stack recompile of baseline scripts.
     WriteOnceData<JitCode*> baselineDebugModeOSRHandler_;
     WriteOnceData<void*> baselineDebugModeOSRHandlerNoFrameRegPopAddr_;
 
     // Code for trampolines and VMFunction wrappers.
@@ -164,16 +168,17 @@ class JitRuntime
     MainThreadData<size_t> ionLazyLinkListSize_;
 
     // Counter used to help dismbiguate stubs in CacheIR
     MainThreadData<uint64_t> disambiguationId_;
 
   private:
     void generateLazyLinkStub(MacroAssembler& masm);
     void generateInterpreterStub(MacroAssembler& masm);
+    void generateDoubleToInt32ValueStub(MacroAssembler& masm);
     void generateProfilerExitFrameTailStub(MacroAssembler& masm, Label* profilerExitTail);
     void generateExceptionTailStub(MacroAssembler& masm, void* handler, Label* profilerExitTail);
     void generateBailoutTailStub(MacroAssembler& masm, Label* bailoutTail);
     void generateEnterJIT(JSContext* cx, MacroAssembler& masm);
     void generateArgumentsRectifier(MacroAssembler& masm);
     BailoutTable generateBailoutTable(MacroAssembler& masm, Label* bailoutTail, uint32_t frameClass);
     void generateBailoutHandler(MacroAssembler& masm, Label* bailoutTail);
     void generateInvalidator(MacroAssembler& masm, Label* bailoutTail);
@@ -285,16 +290,20 @@ class JitRuntime
 
     TrampolinePtr lazyLinkStub() const {
         return trampolineCode(lazyLinkStubOffset_);
     }
     TrampolinePtr interpreterStub() const {
         return trampolineCode(interpreterStubOffset_);
     }
 
+    TrampolinePtr getDoubleToInt32ValueStub() const {
+        return trampolineCode(doubleToInt32ValueStubOffset_);
+    }
+
     bool hasJitcodeGlobalTable() const {
         return jitcodeGlobalTable_ != nullptr;
     }
 
     JitcodeGlobalTable* getJitcodeGlobalTable() {
         MOZ_ASSERT(hasJitcodeGlobalTable());
         return jitcodeGlobalTable_;
     }
--- a/js/src/jit/arm/SharedICHelpers-arm.h
+++ b/js/src/jit/arm/SharedICHelpers-arm.h
@@ -69,22 +69,16 @@ EmitEnterTypeMonitorIC(MacroAssembler& m
 
 inline void
 EmitReturnFromIC(MacroAssembler& masm)
 {
     masm.ma_mov(lr, pc);
 }
 
 inline void
-EmitChangeICReturnAddress(MacroAssembler& masm, Register reg)
-{
-    masm.ma_mov(reg, lr);
-}
-
-inline void
 EmitBaselineLeaveStubFrame(MacroAssembler& masm, bool calledIntoIon = false)
 {
     ScratchRegisterScope scratch(masm);
 
     // Ion frames do not save and restore the frame pointer. If we called into
     // Ion, we have to restore the stack pointer from the frame descriptor. If
     // we performed a VM call, the descriptor has been popped already so in that
     // case we use the frame pointer.
--- a/js/src/jit/arm64/SharedICHelpers-arm64.h
+++ b/js/src/jit/arm64/SharedICHelpers-arm64.h
@@ -69,22 +69,16 @@ EmitEnterTypeMonitorIC(MacroAssembler& m
 
 inline void
 EmitReturnFromIC(MacroAssembler& masm)
 {
     masm.abiret(); // Defaults to lr.
 }
 
 inline void
-EmitChangeICReturnAddress(MacroAssembler& masm, Register reg)
-{
-    masm.movePtr(reg, lr);
-}
-
-inline void
 EmitBaselineLeaveStubFrame(MacroAssembler& masm, bool calledIntoIon = false)
 {
     vixl::UseScratchRegisterScope temps(&masm.asVIXL());
     const ARMRegister scratch64 = temps.AcquireX();
 
     // Ion frames do not save and restore the frame pointer. If we called
     // into Ion, we have to restore the stack pointer from the frame descriptor.
     // If we performed a VM call, the descriptor has been popped already so
--- a/js/src/jit/mips-shared/SharedICHelpers-mips-shared.h
+++ b/js/src/jit/mips-shared/SharedICHelpers-mips-shared.h
@@ -79,22 +79,16 @@ EmitEnterTypeMonitorIC(MacroAssembler& m
 
 inline void
 EmitReturnFromIC(MacroAssembler& masm)
 {
     masm.branch(ra);
 }
 
 inline void
-EmitChangeICReturnAddress(MacroAssembler& masm, Register reg)
-{
-    masm.movePtr(reg, ra);
-}
-
-inline void
 EmitBaselineLeaveStubFrame(MacroAssembler& masm, bool calledIntoIon = false)
 {
     // Ion frames do not save and restore the frame pointer. If we called
     // into Ion, we have to restore the stack pointer from the frame descriptor.
     // If we performed a VM call, the descriptor has been popped already so
     // in that case we use the frame pointer.
     if (calledIntoIon) {
         masm.pop(ScratchRegister);
--- a/js/src/jit/none/SharedICHelpers-none.h
+++ b/js/src/jit/none/SharedICHelpers-none.h
@@ -12,17 +12,16 @@ namespace jit {
 
 static const size_t ICStackValueOffset = 0;
 
 inline void EmitRestoreTailCallReg(MacroAssembler&) { MOZ_CRASH(); }
 inline void EmitRepushTailCallReg(MacroAssembler&) { MOZ_CRASH(); }
 inline void EmitCallIC(MacroAssembler&, CodeOffset*, CodeOffset*) { MOZ_CRASH(); }
 inline void EmitEnterTypeMonitorIC(MacroAssembler&, size_t v = 0) { MOZ_CRASH(); }
 inline void EmitReturnFromIC(MacroAssembler&) { MOZ_CRASH(); }
-inline void EmitChangeICReturnAddress(MacroAssembler&, Register) { MOZ_CRASH(); }
 inline void EmitBaselineLeaveStubFrame(MacroAssembler&, bool v = false) { MOZ_CRASH(); }
 inline void EmitStubGuardFailure(MacroAssembler&) { MOZ_CRASH(); }
 
 template <typename T> inline void EmitPreBarrier(MacroAssembler&, T, MIRType) { MOZ_CRASH(); }
 
 } // namespace jit
 } // namespace js
 
--- a/js/src/jit/x64/SharedICHelpers-x64.h
+++ b/js/src/jit/x64/SharedICHelpers-x64.h
@@ -60,22 +60,16 @@ EmitEnterTypeMonitorIC(MacroAssembler& m
 
 inline void
 EmitReturnFromIC(MacroAssembler& masm)
 {
     masm.ret();
 }
 
 inline void
-EmitChangeICReturnAddress(MacroAssembler& masm, Register reg)
-{
-    masm.storePtr(reg, Address(StackPointer, 0));
-}
-
-inline void
 EmitBaselineLeaveStubFrame(MacroAssembler& masm, bool calledIntoIon = false)
 {
     // Ion frames do not save and restore the frame pointer. If we called
     // into Ion, we have to restore the stack pointer from the frame descriptor.
     // If we performed a VM call, the descriptor has been popped already so
     // in that case we use the frame pointer.
     if (calledIntoIon) {
         ScratchRegisterScope scratch(masm);
--- a/js/src/jit/x86/SharedICHelpers-x86.h
+++ b/js/src/jit/x86/SharedICHelpers-x86.h
@@ -61,22 +61,16 @@ EmitEnterTypeMonitorIC(MacroAssembler& m
 
 inline void
 EmitReturnFromIC(MacroAssembler& masm)
 {
     masm.ret();
 }
 
 inline void
-EmitChangeICReturnAddress(MacroAssembler& masm, Register reg)
-{
-    masm.storePtr(reg, Address(StackPointer, 0));
-}
-
-inline void
 EmitBaselineLeaveStubFrame(MacroAssembler& masm, bool calledIntoIon = false)
 {
     // Ion frames do not save and restore the frame pointer. If we called
     // into Ion, we have to restore the stack pointer from the frame descriptor.
     // If we performed a VM call, the descriptor has been popped already so
     // in that case we use the frame pointer.
     if (calledIntoIon) {
         Register scratch = ICStubReg;
--- a/js/src/vm/Opcodes.h
+++ b/js/src/vm/Opcodes.h
@@ -700,17 +700,17 @@
      *
      *   Category: Statements
      *   Type: Switch Statement
      *   Operands: int32_t len, int32_t low, int32_t high,
      *             uint24_t firstResumeIndex
      *   Stack: i =>
      *   len: len
      */ \
-    macro(JSOP_TABLESWITCH, 70, "tableswitch", NULL, 16, 1, 0, JOF_TABLESWITCH|JOF_DETECTING|JOF_IC) \
+    macro(JSOP_TABLESWITCH, 70, "tableswitch", NULL, 16, 1, 0, JOF_TABLESWITCH|JOF_DETECTING) \
     /*
      * Prologue emitted in scripts expected to run once, which deoptimizes code
      * if it executes multiple times.
      *
      *   Category: Statements
      *   Type: Function
      *   Operands:
      *   Stack: =>