Backed out changeset e283310058ba (bug 1432446) for build bustage at /builds/worker/workspace/build/src/js/src/jit/x86/Trampoline-x86.cpp:185 on a CLOSED TREE
authorAndreea Pavel <apavel@mozilla.com>
Wed, 28 Feb 2018 03:22:39 +0200
changeset 450153 24c4795c13be364230a324c525de51eabea481da
parent 450152 24cfdecfcc9314644907faf6c77aabe4c17566f1
child 450154 4e09c5d2d68487516af11877d9c69ced4f8266d0
push id146
push userfmarier@mozilla.com
push dateFri, 02 Mar 2018 02:16:17 +0000
bugs1432446
milestone60.0a1
backs oute283310058ba4a0358fd3ea844d88cd66d72fd20
Backed out changeset e283310058ba (bug 1432446) for build bustage at /builds/worker/workspace/build/src/js/src/jit/x86/Trampoline-x86.cpp:185 on a CLOSED TREE
js/src/jit/CodeGenerator.cpp
js/src/jit/arm/Assembler-arm.cpp
js/src/jit/arm/Assembler-arm.h
js/src/jit/arm/CodeGenerator-arm.cpp
js/src/jit/arm64/Assembler-arm64.h
js/src/jit/mips-shared/Assembler-mips-shared.h
js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp
js/src/jit/mips-shared/CodeGenerator-mips-shared.h
js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h
js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp
js/src/jit/mips32/Assembler-mips32.cpp
js/src/jit/mips32/Assembler-mips32.h
js/src/jit/mips32/CodeGenerator-mips32.cpp
js/src/jit/mips32/CodeGenerator-mips32.h
js/src/jit/mips32/MacroAssembler-mips32-inl.h
js/src/jit/mips32/MacroAssembler-mips32.cpp
js/src/jit/mips32/MacroAssembler-mips32.h
js/src/jit/mips32/Trampoline-mips32.cpp
js/src/jit/mips64/Assembler-mips64.cpp
js/src/jit/mips64/Assembler-mips64.h
js/src/jit/mips64/CodeGenerator-mips64.cpp
js/src/jit/mips64/CodeGenerator-mips64.h
js/src/jit/mips64/MacroAssembler-mips64-inl.h
js/src/jit/mips64/MacroAssembler-mips64.cpp
js/src/jit/mips64/MacroAssembler-mips64.h
js/src/jit/mips64/Trampoline-mips64.cpp
js/src/jit/none/MacroAssembler-none.h
js/src/jit/shared/Assembler-shared.h
js/src/jit/x64/Assembler-x64.h
js/src/jit/x64/Trampoline-x64.cpp
js/src/jit/x86-shared/Assembler-x86-shared.cpp
js/src/jit/x86-shared/Assembler-x86-shared.h
js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp
js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp
js/src/jit/x86/Assembler-x86.h
js/src/jit/x86/Trampoline-x86.cpp
js/src/wasm/WasmBaselineCompile.cpp
js/src/wasm/WasmCode.cpp
js/src/wasm/WasmGenerator.cpp
js/src/wasm/WasmModule.h
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -11365,31 +11365,31 @@ class OutOfLineSwitch : public OutOfLine
             base = ::js::jit::pc;
 #else
             MOZ_CRASH("NYI: SwitchTableType::Inline");
 #endif
         } else {
 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)
             MOZ_CRASH("NYI: SwitchTableType::OutOfLine");
 #else
-            masm.mov(start(), temp);
+            masm.mov(start_.patchAt(), temp);
             base = temp;
 #endif
         }
         BaseIndex jumpTarget(base, index, ScalePointer);
         masm.branchToComputedAddress(jumpTarget);
     }
 
     // Register an entry in the switch table.
     void addTableEntry(MacroAssembler& masm) {
         if ((!isOutOfLine_ && tableType == SwitchTableType::Inline) ||
             (isOutOfLine_ && tableType == SwitchTableType::OutOfLine))
         {
             CodeLabel cl;
-            masm.writeCodePointer(&cl);
+            masm.writeCodePointer(cl.patchAt());
             masm.propagateOOM(codeLabels_.append(mozilla::Move(cl)));
         }
     }
     // Register the code, to which the table will jump to.
     void addCodeEntry(MacroAssembler& masm) {
         Label entry;
         masm.bind(&entry);
         masm.propagateOOM(labels_.append(mozilla::Move(entry)));
@@ -11407,17 +11407,17 @@ CodeGenerator::visitOutOfLineSwitch(OutO
     jumpTable->setOutOfLine();
     if (tableType == SwitchTableType::OutOfLine) {
 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)
         MOZ_CRASH("NYI: SwitchTableType::OutOfLine");
 #elif defined(JS_CODEGEN_NONE)
         MOZ_CRASH();
 #else
         masm.haltingAlign(sizeof(void*));
-        masm.bind(jumpTable->start());
+        masm.use(jumpTable->start()->target());
         masm.addCodeLabel(*jumpTable->start());
 #endif
     }
 
     // Add table entries if the table is inlined.
     auto& labels = jumpTable->labels();
     for (size_t i = 0, e = labels.length(); i < e; i++)
         jumpTable->addTableEntry(masm);
--- a/js/src/jit/arm/Assembler-arm.cpp
+++ b/js/src/jit/arm/Assembler-arm.cpp
@@ -957,34 +957,33 @@ Assembler::trace(JSTracer* trc)
         CompactBufferReader reader(dataRelocations_);
         ::TraceDataRelocations(trc, &m_buffer, reader);
     }
 }
 
 void
 Assembler::processCodeLabels(uint8_t* rawCode)
 {
-    for (const CodeLabel& label : codeLabels_) {
-        Bind(rawCode, label);
+    for (size_t i = 0; i < codeLabels_.length(); i++) {
+        CodeLabel label = codeLabels_[i];
+        Bind(rawCode, *label.patchAt(), *label.target());
     }
 }
 
 void
-Assembler::writeCodePointer(CodeLabel* label)
+Assembler::writeCodePointer(CodeOffset* label)
 {
     BufferOffset off = writeInst(-1);
-    label->patchAt()->bind(off.getOffset());
+    label->bind(off.getOffset());
 }
 
 void
-Assembler::Bind(uint8_t* rawCode, const CodeLabel& label)
+Assembler::Bind(uint8_t* rawCode, CodeOffset label, CodeOffset target)
 {
-    size_t offset = label.patchAt().offset();
-    size_t target = label.target().offset();
-    *reinterpret_cast<const void**>(rawCode + offset) = rawCode + target;
+    *reinterpret_cast<const void**>(rawCode + label.offset()) = rawCode + target.offset();
 }
 
 Assembler::Condition
 Assembler::InvertCondition(Condition cond)
 {
     const uint32_t ConditionInversionBit = 0x10000000;
     return Condition(ConditionInversionBit ^ cond);
 }
--- a/js/src/jit/arm/Assembler-arm.h
+++ b/js/src/jit/arm/Assembler-arm.h
@@ -1451,17 +1451,17 @@ class Assembler : public AssemblerShared
     // be overwritten subsequently.
     BufferOffset allocBranchInst();
 
     // A static variant for the cases where we don't want to have an assembler
     // object.
     static void WriteInstStatic(uint32_t x, uint32_t* dest);
 
   public:
-    void writeCodePointer(CodeLabel* label);
+    void writeCodePointer(CodeOffset* label);
 
     void haltingAlign(int alignment);
     void nopAlign(int alignment);
     BufferOffset as_nop();
     BufferOffset as_alu(Register dest, Register src1, Operand2 op2,
                         ALUOp op, SBit s = LeaveCC, Condition c = Always);
     BufferOffset as_mov(Register dest,
                         Operand2 op2, SBit s = LeaveCC, Condition c = Always);
@@ -1727,17 +1727,17 @@ class Assembler : public AssemblerShared
     void bindLater(Label* label, wasm::OldTrapDesc target);
     uint32_t currentOffset() {
         return nextOffset().getOffset();
     }
     void retarget(Label* label, Label* target);
     // I'm going to pretend this doesn't exist for now.
     void retarget(Label* label, void* target, Relocation::Kind reloc);
 
-    static void Bind(uint8_t* rawCode, const CodeLabel& label);
+    static void Bind(uint8_t* rawCode, CodeOffset label, CodeOffset target);
 
     void as_bkpt();
     BufferOffset as_illegal_trap();
 
   public:
     static void TraceJumpRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader);
     static void TraceDataRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader);
 
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -1197,17 +1197,17 @@ CodeGeneratorARM::emitTableSwitchDispatc
     masm.ma_b(defaultcase);
 
     // To fill in the CodeLabels for the case entries, we need to first generate
     // the case entries (we don't yet know their offsets in the instruction
     // stream).
     OutOfLineTableSwitch* ool = new(alloc()) OutOfLineTableSwitch(alloc(), mir);
     for (int32_t i = 0; i < cases; i++) {
         CodeLabel cl;
-        masm.writeCodePointer(&cl);
+        masm.writeCodePointer(cl.patchAt());
         masm.propagateOOM(ool->addCodeLabel(cl));
     }
     addOutOfLineCode(ool, mir);
 }
 
 void
 CodeGeneratorARM::visitMathD(LMathD* math)
 {
--- a/js/src/jit/arm64/Assembler-arm64.h
+++ b/js/src/jit/arm64/Assembler-arm64.h
@@ -240,25 +240,24 @@ class Assembler : public vixl::Assembler
     }
     size_t bytesNeeded() const {
         return SizeOfCodeGenerated() +
             jumpRelocationTableBytes() +
             dataRelocationTableBytes();
     }
 
     void processCodeLabels(uint8_t* rawCode) {
-        for (const CodeLabel& label : codeLabels_) {
-            Bind(rawCode, label);
+        for (size_t i = 0; i < codeLabels_.length(); i++) {
+            CodeLabel label = codeLabels_[i];
+            Bind(rawCode, *label.patchAt(), *label.target());
         }
     }
 
-    static void Bind(uint8_t* rawCode, const CodeLabel& label) {
-        size_t patchAtOffset = label.patchAt().offset();
-        size_t targetOffset = label.target().offset();
-        *reinterpret_cast<const void**>(rawCode + patchAtOffset) = rawCode + targetOffset;
+    static void Bind(uint8_t* rawCode, CodeOffset label, CodeOffset address) {
+        *reinterpret_cast<const void**>(rawCode + label.offset()) = rawCode + address.offset();
     }
 
     void retarget(Label* cur, Label* next);
 
     // The buffer is about to be linked. Ensure any constant pools or
     // excess bookkeeping has been flushed to the instruction stream.
     void flush() {
         armbuffer_.flushPool();
@@ -366,20 +365,20 @@ class Assembler : public vixl::Assembler
             return reinterpret_cast<Instruction*>(&ldr);
         }
     };
 
     // Offset of the patchable target for the given entry.
     static const size_t OffsetOfJumpTableEntryPointer = 8;
 
   public:
-    void writeCodePointer(CodeLabel* label) {
+    void writeCodePointer(CodeOffset* label) {
         uintptr_t x = uintptr_t(-1);
         BufferOffset off = EmitData(&x, sizeof(uintptr_t));
-        label->patchAt()->bind(off.getOffset());
+        label->bind(off.getOffset());
     }
 
 
     void verifyHeapAccessDisassembly(uint32_t begin, uint32_t end,
                                      const Disassembler::HeapAccess& heapAccess)
     {
         MOZ_CRASH("verifyHeapAccessDisassembly");
     }
--- a/js/src/jit/mips-shared/Assembler-mips-shared.h
+++ b/js/src/jit/mips-shared/Assembler-mips-shared.h
@@ -1251,18 +1251,21 @@ class AssemblerMIPSShared : public Assem
     BufferOffset as_tltu(Register rs, Register rt, uint32_t code = 0);
     BufferOffset as_teq(Register rs, Register rt, uint32_t code = 0);
     BufferOffset as_tne(Register rs, Register rt, uint32_t code = 0);
 
     // label operations
     void bind(Label* label, BufferOffset boff = BufferOffset());
     void bindLater(Label* label, wasm::OldTrapDesc target);
     virtual void bind(InstImm* inst, uintptr_t branch, uintptr_t target) = 0;
-    void bind(CodeLabel* label) {
-        label->target()->bind(currentOffset());
+    void bind(CodeOffset* label) {
+        label->bind(currentOffset());
+    }
+    void use(CodeOffset* label) {
+        label->bind(currentOffset());
     }
     uint32_t currentOffset() {
         return nextOffset().getOffset();
     }
     void retarget(Label* label, Label* target);
 
     void call(Label* label);
     void call(void* target);
@@ -1294,21 +1297,19 @@ class AssemblerMIPSShared : public Assem
     InstImm invertBranch(InstImm branch, BOffImm16 skipOffset);
     void addPendingJump(BufferOffset src, ImmPtr target, Relocation::Kind kind) {
         enoughMemory_ &= jumps_.append(RelativePatch(src, target.value, kind));
         if (kind == Relocation::JITCODE)
             writeRelocation(src);
     }
 
     void addLongJump(BufferOffset src, BufferOffset dst) {
-        CodeLabel cl;
-        cl.patchAt()->bind(src.getOffset());
-        cl.target()->bind(dst.getOffset());
-        cl.setLinkMode(CodeLabel::JumpImmediate);
-        addCodeLabel(mozilla::Move(cl));
+        CodeOffset patchAt(src.getOffset());
+        CodeOffset target(dst.getOffset());
+        addCodeLabel(CodeLabel(patchAt, target));
     }
 
   public:
     void flushBuffer() {
     }
 
     void comment(const char* msg) {
         spew("; %s", msg);
--- a/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp
+++ b/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp
@@ -1843,91 +1843,16 @@ CodeGeneratorMIPSShared::visitLoadTypedA
 }
 
 void
 CodeGeneratorMIPSShared::visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic* ins)
 {
     MOZ_CRASH("NYI");
 }
 
-class js::jit::OutOfLineTableSwitch : public OutOfLineCodeBase<CodeGeneratorMIPSShared>
-{
-    MTableSwitch* mir_;
-    CodeLabel jumpLabel_;
-
-    void accept(CodeGeneratorMIPSShared* codegen) {
-        codegen->visitOutOfLineTableSwitch(this);
-    }
-
-  public:
-    OutOfLineTableSwitch(MTableSwitch* mir)
-      : mir_(mir)
-    {}
-
-    MTableSwitch* mir() const {
-        return mir_;
-    }
-
-    CodeLabel* jumpLabel() {
-        return &jumpLabel_;
-    }
-};
-
-void
-CodeGeneratorMIPSShared::visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool)
-{
-    MTableSwitch* mir = ool->mir();
-
-    masm.haltingAlign(sizeof(void*));
-    masm.bind(ool->jumpLabel());
-    masm.addCodeLabel(*ool->jumpLabel());
-
-    for (size_t i = 0; i < mir->numCases(); i++) {
-        LBlock* caseblock = skipTrivialBlocks(mir->getCase(i))->lir();
-        Label* caseheader = caseblock->label();
-        uint32_t caseoffset = caseheader->offset();
-
-        // The entries of the jump table need to be absolute addresses and thus
-        // must be patched after codegen is finished.
-        CodeLabel cl;
-        masm.writeCodePointer(&cl);
-        cl.target()->bind(caseoffset);
-        masm.addCodeLabel(cl);
-    }
-}
-
-void
-CodeGeneratorMIPSShared::emitTableSwitchDispatch(MTableSwitch* mir, Register index,
-                                           Register base)
-{
-    Label* defaultcase = skipTrivialBlocks(mir->getDefault())->lir()->label();
-
-    // Lower value with low value
-    if (mir->low() != 0)
-        masm.subPtr(Imm32(mir->low()), index);
-
-    // Jump to default case if input is out of range
-    int32_t cases = mir->numCases();
-    masm.branchPtr(Assembler::AboveOrEqual, index, ImmWord(cases), defaultcase);
-
-    // To fill in the CodeLabels for the case entries, we need to first
-    // generate the case entries (we don't yet know their offsets in the
-    // instruction stream).
-    OutOfLineTableSwitch* ool = new(alloc()) OutOfLineTableSwitch(mir);
-    addOutOfLineCode(ool, mir);
-
-    // Compute the position where a pointer to the right case stands.
-    masm.ma_li(base, ool->jumpLabel());
-
-    BaseIndex pointer(base, index, ScalePointer);
-
-    // Jump to the right case
-    masm.branchToComputedAddress(pointer);
-}
-
 template <typename T>
 void
 CodeGeneratorMIPSShared::emitWasmLoad(T* lir)
 {
     const MWasmLoad* mir = lir->mir();
 
     Register ptrScratch = InvalidReg;
     if(!lir->ptrCopy()->isBogusTemp()){
--- a/js/src/jit/mips-shared/CodeGenerator-mips-shared.h
+++ b/js/src/jit/mips-shared/CodeGenerator-mips-shared.h
@@ -117,18 +117,16 @@ class CodeGeneratorMIPSShared : public C
         }
     }
     void testZeroEmitBranch(Assembler::Condition cond, Register reg,
                             MBasicBlock* ifTrue, MBasicBlock* ifFalse)
     {
         emitBranch(reg, Imm32(0), cond, ifTrue, ifFalse);
     }
 
-    void emitTableSwitchDispatch(MTableSwitch* mir, Register index, Register base);
-
     template <typename T>
     void emitWasmLoad(T* ins);
     template <typename T>
     void emitWasmStore(T* ins);
 
   public:
     // Instruction visitors.
     void visitMinMaxD(LMinMaxD* ins);
@@ -190,17 +188,16 @@ class CodeGeneratorMIPSShared : public C
     void visitRoundF(LRoundF* lir);
     void visitTruncateDToInt32(LTruncateDToInt32* ins);
     void visitTruncateFToInt32(LTruncateFToInt32* ins);
 
     void visitWasmTruncateToInt32(LWasmTruncateToInt32* lir);
 
     // Out of line visitors.
     void visitOutOfLineBailout(OutOfLineBailout* ool);
-    void visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool);
     void visitOutOfLineWasmTruncateCheck(OutOfLineWasmTruncateCheck* ool);
     void visitCopySignD(LCopySignD* ins);
     void visitCopySignF(LCopySignF* ins);
 
   public:
     CodeGeneratorMIPSShared(MIRGenerator* gen, LIRGraph* graph, MacroAssembler* masm);
 
     void visitValue(LValue* value);
--- a/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h
+++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h
@@ -965,23 +965,16 @@ void
 MacroAssembler::branchTestMagic(Condition cond, const BaseIndex& address, Label* label)
 {
     SecondScratchRegisterScope scratch2(*this);
     extractTag(address, scratch2);
     branchTestMagic(cond, scratch2, label);
 }
 
 void
-MacroAssembler::branchToComputedAddress(const BaseIndex& addr)
-{
-    loadPtr(addr, ScratchRegister);
-    branch(ScratchRegister);
-}
-
-void
 MacroAssembler::cmp32Move32(Condition cond, Register lhs, Register rhs, Register src,
                             Register dest)
 {
     MOZ_CRASH();
 }
 
 void
 MacroAssembler::cmp32MovePtr(Condition cond, Register lhs, Imm32 rhs, Register src,
--- a/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp
+++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp
@@ -1650,19 +1650,19 @@ MacroAssembler::popReturnAddress()
 // ===============================================================
 // Jit Frames.
 
 uint32_t
 MacroAssembler::pushFakeReturnAddress(Register scratch)
 {
     CodeLabel cl;
 
-    ma_li(scratch, &cl);
+    ma_li(scratch, cl.patchAt());
     Push(scratch);
-    bind(&cl);
+    bind(cl.target());
     uint32_t retAddr = currentOffset();
 
     addCodeLabel(cl);
     return retAddr;
 }
 
 void
 MacroAssembler::loadStoreBuffer(Register ptr, Register buffer)
--- a/js/src/jit/mips32/Assembler-mips32.cpp
+++ b/js/src/jit/mips32/Assembler-mips32.cpp
@@ -289,32 +289,22 @@ Assembler::trace(JSTracer* trc)
     }
     if (dataRelocations_.length()) {
         CompactBufferReader reader(dataRelocations_);
         ::TraceDataRelocations(trc, &m_buffer, reader);
     }
 }
 
 void
-Assembler::Bind(uint8_t* rawCode, const CodeLabel& label)
+Assembler::Bind(uint8_t* rawCode, CodeOffset label, CodeOffset target)
 {
-    if (label.patchAt().bound()) {
-
-        auto mode = label.linkMode();
-        intptr_t offset = label.patchAt().offset();
-        intptr_t target = label.target().offset();
-
-        if (mode == CodeLabel::RawPointer) {
-            *reinterpret_cast<const void**>(rawCode + offset) = rawCode + target;
-        } else {
-            MOZ_ASSERT(mode == CodeLabel::MoveImmediate || mode == CodeLabel::JumpImmediate);
-            Instruction* inst = (Instruction*) (rawCode + offset);
-            AssemblerMIPSShared::UpdateLuiOriValue(inst, inst->next(),
-                                                  (uint32_t)(rawCode + target));
-        }
+    if (label.bound()) {
+        intptr_t offset = label.offset();
+        Instruction* inst = (Instruction*) (rawCode + offset);
+        AssemblerMIPSShared::UpdateLuiOriValue(inst, inst->next(), (uint32_t)(rawCode + target.offset()));
     }
 }
 
 void
 Assembler::bind(InstImm* inst, uintptr_t branch, uintptr_t target)
 {
     int32_t offset = target - branch;
     InstImm inst_bgezal = InstImm(op_regimm, zero, rt_bgezal, BOffImm16(0));
@@ -436,18 +426,19 @@ Assembler::bind(RepatchLabel* label)
         }
     }
     label->bind(dest.getOffset());
 }
 
 void
 Assembler::processCodeLabels(uint8_t* rawCode)
 {
-    for (const CodeLabel& label : codeLabels_) {
-        Bind(rawCode, label);
+    for (size_t i = 0; i < codeLabels_.length(); i++) {
+        CodeLabel label = codeLabels_[i];
+        Bind(rawCode, *label.patchAt(), *label.target());
     }
 }
 
 uint32_t
 Assembler::PatchWrite_NearCallSize()
 {
     return 4 * sizeof(uint32_t);
 }
--- a/js/src/jit/mips32/Assembler-mips32.h
+++ b/js/src/jit/mips32/Assembler-mips32.h
@@ -170,17 +170,17 @@ class Assembler : public AssemblerMIPSSh
         FloatRegister odd(reg.id() | 1, FloatRegister::Single);
         return odd;
     }
 
   public:
     using AssemblerMIPSShared::bind;
 
     void bind(RepatchLabel* label);
-    static void Bind(uint8_t* rawCode, const CodeLabel& label);
+    static void Bind(uint8_t* rawCode, CodeOffset label, CodeOffset target);
 
     void processCodeLabels(uint8_t* rawCode);
 
     static void TraceJumpRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader);
     static void TraceDataRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader);
 
     void bind(InstImm* inst, uintptr_t branch, uintptr_t target);
 
--- a/js/src/jit/mips32/CodeGenerator-mips32.cpp
+++ b/js/src/jit/mips32/CodeGenerator-mips32.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jit/mips32/CodeGenerator-mips32.h"
 
+#include "mozilla/ArrayUtils.h"
 #include "mozilla/MathAlgorithms.h"
 
 #include "jit/CodeGenerator.h"
 #include "jit/JitCompartment.h"
 #include "jit/JitFrames.h"
 #include "jit/MIR.h"
 #include "jit/MIRGraph.h"
 #include "js/Conversions.h"
@@ -18,16 +19,92 @@
 #include "vm/TraceLogging.h"
 
 #include "jit/MacroAssembler-inl.h"
 #include "jit/shared/CodeGenerator-shared-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
+class js::jit::OutOfLineTableSwitch : public OutOfLineCodeBase<CodeGeneratorMIPS>
+{
+    MTableSwitch* mir_;
+    CodeLabel jumpLabel_;
+
+    void accept(CodeGeneratorMIPS* codegen) {
+        codegen->visitOutOfLineTableSwitch(this);
+    }
+
+  public:
+    OutOfLineTableSwitch(MTableSwitch* mir)
+      : mir_(mir)
+    {}
+
+    MTableSwitch* mir() const {
+        return mir_;
+    }
+
+    CodeLabel* jumpLabel() {
+        return &jumpLabel_;
+    }
+};
+
+void
+CodeGeneratorMIPS::visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool)
+{
+    MTableSwitch* mir = ool->mir();
+
+    masm.haltingAlign(sizeof(void*));
+    masm.bind(ool->jumpLabel()->target());
+    masm.addCodeLabel(*ool->jumpLabel());
+
+    for (size_t i = 0; i < mir->numCases(); i++) {
+        LBlock* caseblock = skipTrivialBlocks(mir->getCase(i))->lir();
+        Label* caseheader = caseblock->label();
+        uint32_t caseoffset = caseheader->offset();
+
+        // The entries of the jump table need to be absolute addresses and thus
+        // must be patched after codegen is finished.
+        CodeLabel cl;
+        masm.ma_li(ScratchRegister, cl.patchAt());
+        masm.branch(ScratchRegister);
+        cl.target()->bind(caseoffset);
+        masm.addCodeLabel(cl);
+    }
+}
+
+void
+CodeGeneratorMIPS::emitTableSwitchDispatch(MTableSwitch* mir, Register index,
+                                           Register address)
+{
+    Label* defaultcase = skipTrivialBlocks(mir->getDefault())->lir()->label();
+
+    // Lower value with low value
+    if (mir->low() != 0)
+        masm.subPtr(Imm32(mir->low()), index);
+
+    // Jump to default case if input is out of range
+    int32_t cases = mir->numCases();
+    masm.branchPtr(Assembler::AboveOrEqual, index, ImmWord(cases), defaultcase);
+
+    // To fill in the CodeLabels for the case entries, we need to first
+    // generate the case entries (we don't yet know their offsets in the
+    // instruction stream).
+    OutOfLineTableSwitch* ool = new(alloc()) OutOfLineTableSwitch(mir);
+    addOutOfLineCode(ool, mir);
+
+    // Compute the position where a pointer to the right case stands.
+    masm.ma_li(address, ool->jumpLabel()->patchAt());
+    masm.lshiftPtr(Imm32(4), index);
+    masm.addPtr(index, address);
+
+    masm.branch(address);
+}
+
+
 ValueOperand
 CodeGeneratorMIPS::ToValue(LInstruction* ins, size_t pos)
 {
     Register typeReg = ToRegister(ins->getOperand(pos + TYPE_INDEX));
     Register payloadReg = ToRegister(ins->getOperand(pos + PAYLOAD_INDEX));
     return ValueOperand(typeReg, payloadReg);
 }
 
--- a/js/src/jit/mips32/CodeGenerator-mips32.h
+++ b/js/src/jit/mips32/CodeGenerator-mips32.h
@@ -26,16 +26,18 @@ class CodeGeneratorMIPS : public CodeGen
         emitBranch(value.typeReg(), (Imm32)ImmType(JSVAL_TYPE_UNDEFINED), cond, ifTrue, ifFalse);
     }
     void testObjectEmitBranch(Assembler::Condition cond, const ValueOperand& value,
                               MBasicBlock* ifTrue, MBasicBlock* ifFalse)
     {
         emitBranch(value.typeReg(), (Imm32)ImmType(JSVAL_TYPE_OBJECT), cond, ifTrue, ifFalse);
     }
 
+    void emitTableSwitchDispatch(MTableSwitch* mir, Register index, Register base);
+
     template <typename T>
     void emitWasmLoadI64(T* ins);
     template <typename T>
     void emitWasmStoreI64(T* ins);
 
   public:
     void visitCompareB(LCompareB* lir);
     void visitCompareBAndBranch(LCompareBAndBranch* lir);
@@ -59,16 +61,17 @@ class CodeGeneratorMIPS : public CodeGen
     void visitCtzI64(LCtzI64* ins);
     void visitNotI64(LNotI64* ins);
     void visitWasmTruncateToInt64(LWasmTruncateToInt64* ins);
     void visitInt64ToFloatingPoint(LInt64ToFloatingPoint* lir);
     void visitTestI64AndBranch(LTestI64AndBranch* lir);
 
     // Out of line visitors.
     void visitOutOfLineBailout(OutOfLineBailout* ool);
+    void visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool);
   protected:
     ValueOperand ToValue(LInstruction* ins, size_t pos);
     ValueOperand ToTempValue(LInstruction* ins, size_t pos);
 
     // Functions for LTestVAndBranch.
     void splitTagForTest(const ValueOperand& value, ScratchTagScope& tag);
 
   public:
--- a/js/src/jit/mips32/MacroAssembler-mips32-inl.h
+++ b/js/src/jit/mips32/MacroAssembler-mips32-inl.h
@@ -974,16 +974,34 @@ MacroAssembler::branchTestMagic(Conditio
     else
         branchTestMagic(Assembler::NotEqual, valaddr, label);
 
     branch32(cond, ToPayload(valaddr), Imm32(why), label);
     bind(&notMagic);
 }
 
 void
+MacroAssembler::branchToComputedAddress(const BaseIndex& addr)
+{
+    int32_t shift = Imm32::ShiftOf(addr.scale).value;
+    if (shift) {
+        // 4 instructions : lui ori jr nop
+        as_sll(ScratchRegister, addr.index, 4);
+        as_addu(ScratchRegister, addr.base, ScratchRegister);
+    } else {
+        as_addu(ScratchRegister, addr.base, addr.index);
+    }
+
+    if (addr.offset)
+        asMasm().addPtr(Imm32(addr.offset), ScratchRegister);
+    as_jr(ScratchRegister);
+    as_nop();
+}
+
+void
 MacroAssembler::branchTruncateDoubleMaybeModUint32(FloatRegister src, Register dest, Label* fail)
 {
     as_truncwd(ScratchFloat32Reg, src);
     as_cfc1(ScratchRegister, Assembler::FCSR);
     moveFromFloat32(ScratchFloat32Reg, dest);
     ma_ext(ScratchRegister, ScratchRegister, Assembler::CauseV, 1);
     ma_b(ScratchRegister, Imm32(0), fail, Assembler::NotEqual);
 }
--- a/js/src/jit/mips32/MacroAssembler-mips32.cpp
+++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp
@@ -175,22 +175,21 @@ MacroAssemblerMIPSCompat::convertInt32To
 void
 MacroAssemblerMIPSCompat::convertInt32ToFloat32(const Address& src, FloatRegister dest)
 {
     ma_ls(dest, src);
     as_cvtsw(dest, dest);
 }
 
 void
-MacroAssemblerMIPS::ma_li(Register dest, CodeLabel* label)
+MacroAssemblerMIPS::ma_li(Register dest, CodeOffset* label)
 {
     BufferOffset bo = m_buffer.nextOffset();
     ma_liPatchable(dest, ImmWord(/* placeholder */ 0));
-    label->patchAt()->bind(bo.getOffset());
-    label->setLinkMode(CodeLabel::MoveImmediate);
+    label->bind(bo.getOffset());
 }
 
 void
 MacroAssemblerMIPS::ma_li(Register dest, ImmWord imm)
 {
     ma_li(dest, Imm32(uint32_t(imm.value)));
 }
 
--- a/js/src/jit/mips32/MacroAssembler-mips32.h
+++ b/js/src/jit/mips32/MacroAssembler-mips32.h
@@ -75,17 +75,17 @@ class MacroAssemblerMIPS : public MacroA
     using MacroAssemblerMIPSShared::ma_ls;
     using MacroAssemblerMIPSShared::ma_ld;
     using MacroAssemblerMIPSShared::ma_load;
     using MacroAssemblerMIPSShared::ma_store;
     using MacroAssemblerMIPSShared::ma_cmp_set;
     using MacroAssemblerMIPSShared::ma_subTestOverflow;
     using MacroAssemblerMIPSShared::ma_liPatchable;
 
-    void ma_li(Register dest, CodeLabel* label);
+    void ma_li(Register dest, CodeOffset* label);
 
     void ma_li(Register dest, ImmWord imm);
     void ma_liPatchable(Register dest, ImmPtr imm);
     void ma_liPatchable(Register dest, ImmWord imm);
 
     // load
     void ma_load(Register dest, Address address, LoadStoreSize size = SizeWord,
                  LoadStoreExtension extension = SignExtend);
@@ -219,17 +219,17 @@ class MacroAssemblerMIPSCompat : public 
         as_ori(dest, src, 0);
     }
     void mov(ImmWord imm, Register dest) {
         ma_li(dest, imm);
     }
     void mov(ImmPtr imm, Register dest) {
         mov(ImmWord(uintptr_t(imm.value)), dest);
     }
-    void mov(CodeLabel* label, Register dest) {
+    void mov(CodeOffset* label, Register dest) {
         ma_li(dest, label);
     }
     void mov(Register src, Address dest) {
         MOZ_CRASH("NYI-IC");
     }
     void mov(Address src, Register dest) {
         MOZ_CRASH("NYI-IC");
     }
@@ -307,20 +307,21 @@ class MacroAssemblerMIPSCompat : public 
         CodeOffset label = CodeOffset(currentOffset());
         ma_liPatchable(dest, imm);
         return label;
     }
     CodeOffset movWithPatch(ImmPtr imm, Register dest) {
         return movWithPatch(ImmWord(uintptr_t(imm.value)), dest);
     }
 
-    void writeCodePointer(CodeLabel* label) {
-        BufferOffset off = writeInst(-1);
-        label->patchAt()->bind(off.getOffset());
-        label->setLinkMode(CodeLabel::RawPointer);
+    void writeCodePointer(CodeOffset* label) {
+        label->bind(currentOffset());
+        ma_liPatchable(ScratchRegister, ImmWord(0));
+        as_jr(ScratchRegister);
+        as_nop();
     }
 
     void jump(Label* label) {
         ma_b(label);
     }
     void jump(Register reg) {
         as_jr(reg);
         as_nop();
--- a/js/src/jit/mips32/Trampoline-mips32.cpp
+++ b/js/src/jit/mips32/Trampoline-mips32.cpp
@@ -223,17 +223,17 @@ JitRuntime::generateEnterJIT(JSContext* 
 
         Register scratch = regs.takeAny();
 
         Register numStackValues = regs.takeAny();
         masm.load32(slotNumStackValues, numStackValues);
 
         // Push return address.
         masm.subPtr(Imm32(sizeof(uintptr_t)), StackPointer);
-        masm.ma_li(scratch, &returnLabel);
+        masm.ma_li(scratch, returnLabel.patchAt());
         masm.storePtr(scratch, Address(StackPointer, 0));
 
         // Push previous frame pointer.
         masm.subPtr(Imm32(sizeof(uintptr_t)), StackPointer);
         masm.storePtr(BaselineFrameReg, Address(StackPointer, 0));
 
         // Reserve frame.
         Register framePtr = BaselineFrameReg;
@@ -296,17 +296,17 @@ JitRuntime::generateEnterJIT(JSContext* 
         masm.jump(jitcode);
 
         // OOM: load error value, discard return address and previous frame
         // pointer and return.
         masm.bind(&error);
         masm.movePtr(framePtr, StackPointer);
         masm.addPtr(Imm32(2 * sizeof(uintptr_t)), StackPointer);
         masm.moveValue(MagicValue(JS_ION_ERROR), JSReturnOperand);
-        masm.ma_li(scratch, &oomReturnLabel);
+        masm.ma_li(scratch, oomReturnLabel.patchAt());
         masm.jump(scratch);
 
         masm.bind(&notOsr);
         // Load the scope chain in R1.
         MOZ_ASSERT(R1.scratchReg() != reg_code);
         masm.loadPtr(slotScopeChain, R1.scratchReg());
     }
 
@@ -314,19 +314,19 @@ JitRuntime::generateEnterJIT(JSContext* 
     // the stack would be aligned once the call is complete.
     masm.assertStackAlignment(JitStackAlignment, sizeof(uintptr_t));
 
     // Call the function with pushing return address to stack.
     masm.callJitNoProfiler(reg_code);
 
     {
         // Interpreter -> Baseline OSR will return here.
-        masm.bind(&returnLabel);
+        masm.bind(returnLabel.target());
         masm.addCodeLabel(returnLabel);
-        masm.bind(&oomReturnLabel);
+        masm.bind(oomReturnLabel.target());
         masm.addCodeLabel(oomReturnLabel);
     }
 
     // Pop arguments off the stack.
     // s0 <- 8*argc (size of all arguments we pushed on the stack)
     masm.pop(s0);
     masm.rshiftPtr(Imm32(FRAMESIZE_SHIFT), s0);
     masm.addPtr(s0, StackPointer);
--- a/js/src/jit/mips64/Assembler-mips64.cpp
+++ b/js/src/jit/mips64/Assembler-mips64.cpp
@@ -222,31 +222,22 @@ Assembler::trace(JSTracer* trc)
     }
     if (dataRelocations_.length()) {
         CompactBufferReader reader(dataRelocations_);
         ::TraceDataRelocations(trc, &m_buffer, reader);
     }
 }
 
 void
-Assembler::Bind(uint8_t* rawCode, const CodeLabel& label)
+Assembler::Bind(uint8_t* rawCode, CodeOffset label, CodeOffset target)
 {
-    if (label.patchAt().bound()) {
-
-        auto mode = label.linkMode();
-        intptr_t offset = label.patchAt().offset();
-        intptr_t target = label.target().offset();
-
-        if (mode == CodeLabel::RawPointer) {
-            *reinterpret_cast<const void**>(rawCode + offset) = rawCode + target;
-        } else {
-            MOZ_ASSERT(mode == CodeLabel::MoveImmediate || mode == CodeLabel::JumpImmediate);
-            Instruction* inst = (Instruction*) (rawCode + offset);
-            Assembler::UpdateLoad64Value(inst, (uint64_t)(rawCode + target));
-        }
+    if (label.bound()) {
+        intptr_t offset = label.offset();
+        Instruction* inst = (Instruction*) (rawCode + offset);
+        Assembler::UpdateLoad64Value(inst, (uint64_t)(rawCode + target.offset()));
     }
 }
 
 void
 Assembler::bind(InstImm* inst, uintptr_t branch, uintptr_t target)
 {
     int64_t offset = target - branch;
     InstImm inst_bgezal = InstImm(op_regimm, zero, rt_bgezal, BOffImm16(0));
@@ -368,18 +359,19 @@ Assembler::bind(RepatchLabel* label)
         }
     }
     label->bind(dest.getOffset());
 }
 
 void
 Assembler::processCodeLabels(uint8_t* rawCode)
 {
-    for (const CodeLabel& label : codeLabels_) {
-        Bind(rawCode, label);
+    for (size_t i = 0; i < codeLabels_.length(); i++) {
+        CodeLabel label = codeLabels_[i];
+        Bind(rawCode, *label.patchAt(), *label.target());
     }
 }
 
 uint32_t
 Assembler::PatchWrite_NearCallSize()
 {
     // Load an address needs 4 instructions, and a jump with a delay slot.
     return (4 + 2) * sizeof(uint32_t);
--- a/js/src/jit/mips64/Assembler-mips64.h
+++ b/js/src/jit/mips64/Assembler-mips64.h
@@ -167,17 +167,17 @@ class Assembler : public AssemblerMIPSSh
     // MacroAssemblers hold onto gcthings, so they are traced by the GC.
     void trace(JSTracer* trc);
 
     static uintptr_t GetPointer(uint8_t*);
 
     using AssemblerMIPSShared::bind;
 
     void bind(RepatchLabel* label);
-    static void Bind(uint8_t* rawCode, const CodeLabel& label);
+    static void Bind(uint8_t* rawCode, CodeOffset label, CodeOffset target);
 
     void processCodeLabels(uint8_t* rawCode);
 
     static void TraceJumpRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader);
     static void TraceDataRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader);
 
     void bind(InstImm* inst, uintptr_t branch, uintptr_t target);
 
--- a/js/src/jit/mips64/CodeGenerator-mips64.cpp
+++ b/js/src/jit/mips64/CodeGenerator-mips64.cpp
@@ -18,16 +18,96 @@
 #include "vm/TraceLogging.h"
 
 #include "jit/MacroAssembler-inl.h"
 #include "jit/shared/CodeGenerator-shared-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
+class js::jit::OutOfLineTableSwitch : public OutOfLineCodeBase<CodeGeneratorMIPS64>
+{
+    MTableSwitch* mir_;
+    CodeLabel jumpLabel_;
+
+    void accept(CodeGeneratorMIPS64* codegen) {
+        codegen->visitOutOfLineTableSwitch(this);
+    }
+
+  public:
+    OutOfLineTableSwitch(MTableSwitch* mir)
+      : mir_(mir)
+    {}
+
+    MTableSwitch* mir() const {
+        return mir_;
+    }
+
+    CodeLabel* jumpLabel() {
+        return &jumpLabel_;
+    }
+};
+
+void
+CodeGeneratorMIPS64::visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool)
+{
+    MTableSwitch* mir = ool->mir();
+
+    masm.haltingAlign(sizeof(void*));
+    masm.bind(ool->jumpLabel()->target());
+    masm.addCodeLabel(*ool->jumpLabel());
+
+    for (size_t i = 0; i < mir->numCases(); i++) {
+        LBlock* caseblock = skipTrivialBlocks(mir->getCase(i))->lir();
+        Label* caseheader = caseblock->label();
+        uint32_t caseoffset = caseheader->offset();
+
+        // The entries of the jump table need to be absolute addresses and thus
+        // must be patched after codegen is finished. Each table entry uses 8
+        // instructions (4 for load address, 2 for branch, and 2 padding).
+        CodeLabel cl;
+        masm.ma_li(ScratchRegister, cl.patchAt());
+        masm.branch(ScratchRegister);
+        masm.as_nop();
+        masm.as_nop();
+        cl.target()->bind(caseoffset);
+        masm.addCodeLabel(cl);
+    }
+}
+
+void
+CodeGeneratorMIPS64::emitTableSwitchDispatch(MTableSwitch* mir, Register index,
+                                             Register address)
+{
+    Label* defaultcase = skipTrivialBlocks(mir->getDefault())->lir()->label();
+
+    // Lower value with low value
+    if (mir->low() != 0)
+        masm.subPtr(Imm32(mir->low()), index);
+
+    // Jump to default case if input is out of range
+    int32_t cases = mir->numCases();
+    masm.branch32(Assembler::AboveOrEqual, index, Imm32(cases), defaultcase);
+
+    // To fill in the CodeLabels for the case entries, we need to first
+    // generate the case entries (we don't yet know their offsets in the
+    // instruction stream).
+    OutOfLineTableSwitch* ool = new(alloc()) OutOfLineTableSwitch(mir);
+    addOutOfLineCode(ool, mir);
+
+    // Compute the position where a pointer to the right case stands.
+    masm.ma_li(address, ool->jumpLabel()->patchAt());
+    // index = size of table entry * index.
+    // See CodeGeneratorMIPS64::visitOutOfLineTableSwitch
+    masm.lshiftPtr(Imm32(5), index);
+    masm.addPtr(index, address);
+
+    masm.branch(address);
+}
+
 ValueOperand
 CodeGeneratorMIPS64::ToValue(LInstruction* ins, size_t pos)
 {
     return ValueOperand(ToRegister(ins->getOperand(pos)));
 }
 
 ValueOperand
 CodeGeneratorMIPS64::ToTempValue(LInstruction* ins, size_t pos)
--- a/js/src/jit/mips64/CodeGenerator-mips64.h
+++ b/js/src/jit/mips64/CodeGenerator-mips64.h
@@ -32,16 +32,17 @@ class CodeGeneratorMIPS64 : public CodeG
     void testObjectEmitBranch(Assembler::Condition cond, const ValueOperand& value,
                               MBasicBlock* ifTrue, MBasicBlock* ifFalse)
     {
         MOZ_ASSERT(value.valueReg() != SecondScratchReg);
         masm.splitTag(value.valueReg(), SecondScratchReg);
         emitBranch(SecondScratchReg, ImmTag(JSVAL_TAG_OBJECT), cond, ifTrue, ifFalse);
     }
 
+    void emitTableSwitchDispatch(MTableSwitch* mir, Register index, Register base);
 
     template <typename T>
     void emitWasmLoadI64(T* ins);
     template <typename T>
     void emitWasmStoreI64(T* ins);
 
   public:
     void visitCompareB(LCompareB* lir);
@@ -66,16 +67,17 @@ class CodeGeneratorMIPS64 : public CodeG
     void visitCtzI64(LCtzI64* lir);
     void visitNotI64(LNotI64* lir);
     void visitWasmTruncateToInt64(LWasmTruncateToInt64* lir);
     void visitInt64ToFloatingPoint(LInt64ToFloatingPoint* lir);
     void visitTestI64AndBranch(LTestI64AndBranch* lir);
 
     // Out of line visitors.
     void visitOutOfLineBailout(OutOfLineBailout* ool);
+    void visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool);
   protected:
     ValueOperand ToValue(LInstruction* ins, size_t pos);
     ValueOperand ToTempValue(LInstruction* ins, size_t pos);
 
     // Functions for LTestVAndBranch.
     void splitTagForTest(const ValueOperand& value, ScratchTagScope& tag);
 
   public:
--- a/js/src/jit/mips64/MacroAssembler-mips64-inl.h
+++ b/js/src/jit/mips64/MacroAssembler-mips64-inl.h
@@ -722,16 +722,34 @@ MacroAssembler::branchTestMagic(Conditio
 {
     uint64_t magic = MagicValue(why).asRawBits();
     SecondScratchRegisterScope scratch(*this);
     loadPtr(valaddr, scratch);
     ma_b(scratch, ImmWord(magic), label, cond);
 }
 
 void
+MacroAssembler::branchToComputedAddress(const BaseIndex& addr)
+{
+    int32_t shift = Imm32::ShiftOf(addr.scale).value;
+    if (shift) {
+        // 6 instructions : lui ori dror32 ori jr nop
+        ma_mul(ScratchRegister, addr.index, Imm32(6 * 4));
+        as_daddu(ScratchRegister, addr.base, ScratchRegister);
+    } else {
+        as_daddu(ScratchRegister, addr.base, addr.index);
+    }
+
+    if (addr.offset)
+        asMasm().addPtr(Imm32(addr.offset), ScratchRegister);
+    as_jr(ScratchRegister);
+    as_nop();
+}
+
+void
 MacroAssembler::branchTruncateDoubleMaybeModUint32(FloatRegister src, Register dest, Label* fail)
 {
     as_truncld(ScratchDoubleReg, src);
     as_cfc1(ScratchRegister, Assembler::FCSR);
     moveFromDouble(ScratchDoubleReg, dest);
     ma_ext(ScratchRegister, ScratchRegister, Assembler::CauseV, 1);
     ma_b(ScratchRegister, Imm32(0), fail, Assembler::NotEqual);
 
--- a/js/src/jit/mips64/MacroAssembler-mips64.cpp
+++ b/js/src/jit/mips64/MacroAssembler-mips64.cpp
@@ -161,22 +161,21 @@ MacroAssemblerMIPS64Compat::convertInt32
 
 void
 MacroAssemblerMIPS64Compat::movq(Register rs, Register rd)
 {
     ma_move(rd, rs);
 }
 
 void
-MacroAssemblerMIPS64::ma_li(Register dest, CodeLabel* label)
+MacroAssemblerMIPS64::ma_li(Register dest, CodeOffset* label)
 {
     BufferOffset bo = m_buffer.nextOffset();
     ma_liPatchable(dest, ImmWord(/* placeholder */ 0));
-    label->patchAt()->bind(bo.getOffset());
-    label->setLinkMode(CodeLabel::MoveImmediate);
+    label->bind(bo.getOffset());
 }
 
 void
 MacroAssemblerMIPS64::ma_li(Register dest, ImmWord imm)
 {
     int64_t value = imm.value;
 
     if (-1 == (value >> 15) || 0 == (value >> 15)) {
--- a/js/src/jit/mips64/MacroAssembler-mips64.h
+++ b/js/src/jit/mips64/MacroAssembler-mips64.h
@@ -76,17 +76,17 @@ class MacroAssemblerMIPS64 : public Macr
     using MacroAssemblerMIPSShared::ma_sd;
     using MacroAssemblerMIPSShared::ma_ls;
     using MacroAssemblerMIPSShared::ma_ld;
     using MacroAssemblerMIPSShared::ma_load;
     using MacroAssemblerMIPSShared::ma_store;
     using MacroAssemblerMIPSShared::ma_cmp_set;
     using MacroAssemblerMIPSShared::ma_subTestOverflow;
 
-    void ma_li(Register dest, CodeLabel* label);
+    void ma_li(Register dest, CodeOffset* label);
     void ma_li(Register dest, ImmWord imm);
     void ma_liPatchable(Register dest, ImmPtr imm);
     void ma_liPatchable(Register dest, ImmWord imm, LiFlags flags = Li48);
 
     // Negate
     void ma_dnegu(Register rd, Register rs);
 
     // Shift operations
@@ -231,17 +231,17 @@ class MacroAssemblerMIPS64Compat : publi
         as_ori(dest, src, 0);
     }
     void mov(ImmWord imm, Register dest) {
         ma_li(dest, imm);
     }
     void mov(ImmPtr imm, Register dest) {
         mov(ImmWord(uintptr_t(imm.value)), dest);
     }
-    void mov(CodeLabel* label, Register dest) {
+    void mov(CodeOffset* label, Register dest) {
         ma_li(dest, label);
     }
     void mov(Register src, Address dest) {
         MOZ_CRASH("NYI-IC");
     }
     void mov(Address src, Register dest) {
         MOZ_CRASH("NYI-IC");
     }
@@ -330,22 +330,21 @@ class MacroAssemblerMIPS64Compat : publi
         return offset;
     }
     CodeOffset movWithPatch(ImmPtr imm, Register dest) {
         CodeOffset offset = CodeOffset(currentOffset());
         ma_liPatchable(dest, imm);
         return offset;
     }
 
-    void writeCodePointer(CodeLabel* label) {
-        label->patchAt()->bind(currentOffset());
-        label->setLinkMode(CodeLabel::RawPointer);
-        m_buffer.ensureSpace(sizeof(void*));
-        writeInst(-1);
-        writeInst(-1);
+    void writeCodePointer(CodeOffset* label) {
+        label->bind(currentOffset());
+        ma_liPatchable(ScratchRegister, ImmWord(0));
+        as_jr(ScratchRegister);
+        as_nop();
     }
 
     void jump(Label* label) {
         ma_b(label);
     }
     void jump(Register reg) {
         as_jr(reg);
         as_nop();
--- a/js/src/jit/mips64/Trampoline-mips64.cpp
+++ b/js/src/jit/mips64/Trampoline-mips64.cpp
@@ -247,17 +247,17 @@ JitRuntime::generateEnterJIT(JSContext* 
         masm.ma_b(OsrFrameReg, OsrFrameReg, &notOsr, Assembler::Zero, ShortJump);
 
         Register numStackValues = reg_values;
         regs.take(numStackValues);
         Register scratch = regs.takeAny();
 
         // Push return address.
         masm.subPtr(Imm32(sizeof(uintptr_t)), StackPointer);
-        masm.ma_li(scratch, &returnLabel);
+        masm.ma_li(scratch, returnLabel.patchAt());
         masm.storePtr(scratch, Address(StackPointer, 0));
 
         // Push previous frame pointer.
         masm.subPtr(Imm32(sizeof(uintptr_t)), StackPointer);
         masm.storePtr(BaselineFrameReg, Address(StackPointer, 0));
 
         // Reserve frame.
         Register framePtr = BaselineFrameReg;
@@ -319,17 +319,17 @@ JitRuntime::generateEnterJIT(JSContext* 
         masm.jump(jitcode);
 
         // OOM: load error value, discard return address and previous frame
         // pointer and return.
         masm.bind(&error);
         masm.movePtr(framePtr, StackPointer);
         masm.addPtr(Imm32(2 * sizeof(uintptr_t)), StackPointer);
         masm.moveValue(MagicValue(JS_ION_ERROR), JSReturnOperand);
-        masm.ma_li(scratch, &oomReturnLabel);
+        masm.ma_li(scratch, oomReturnLabel.patchAt());
         masm.jump(scratch);
 
         masm.bind(&notOsr);
         // Load the scope chain in R1.
         MOZ_ASSERT(R1.scratchReg() != reg_code);
         masm.ma_move(R1.scratchReg(), reg_chain);
     }
 
@@ -337,19 +337,19 @@ JitRuntime::generateEnterJIT(JSContext* 
     // the stack would be aligned once the call is complete.
     masm.assertStackAlignment(JitStackAlignment, sizeof(uintptr_t));
 
     // Call the function with pushing return address to stack.
     masm.callJitNoProfiler(reg_code);
 
     {
         // Interpreter -> Baseline OSR will return here.
-        masm.bind(&returnLabel);
+        masm.bind(returnLabel.target());
         masm.addCodeLabel(returnLabel);
-        masm.bind(&oomReturnLabel);
+        masm.bind(oomReturnLabel.target());
         masm.addCodeLabel(oomReturnLabel);
     }
 
     // Pop arguments off the stack.
     // s0 <- 8*argc (size of all arguments we pushed on the stack)
     masm.pop(s0);
     masm.rshiftPtr(Imm32(FRAMESIZE_SHIFT), s0);
     masm.addPtr(s0, StackPointer);
--- a/js/src/jit/none/MacroAssembler-none.h
+++ b/js/src/jit/none/MacroAssembler-none.h
@@ -148,17 +148,17 @@ class Assembler : public AssemblerShared
 
     static void PatchWrite_NearCall(CodeLocationLabel, CodeLocationLabel) { MOZ_CRASH(); }
     static uint32_t PatchWrite_NearCallSize() { MOZ_CRASH(); }
 
     static void ToggleToJmp(CodeLocationLabel) { MOZ_CRASH(); }
     static void ToggleToCmp(CodeLocationLabel) { MOZ_CRASH(); }
     static void ToggleCall(CodeLocationLabel, bool) { MOZ_CRASH(); }
 
-    static void Bind(uint8_t*, const CodeLabel&) { MOZ_CRASH(); }
+    static void Bind(uint8_t*, CodeOffset, CodeOffset) { MOZ_CRASH(); }
 
     static uintptr_t GetPointer(uint8_t*) { MOZ_CRASH(); }
 
     static bool HasRoundInstruction(RoundingMode) { return false; }
 
     void verifyHeapAccessDisassembly(uint32_t begin, uint32_t end,
                                      const Disassembler::HeapAccess& heapAccess)
     {
@@ -226,17 +226,17 @@ class MacroAssemblerNone : public Assemb
     void processCodeLabels(uint8_t*) { MOZ_CRASH(); }
 
     void flushBuffer() { MOZ_CRASH(); }
 
     template <typename T> void bind(T) { MOZ_CRASH(); }
     void bindLater(Label*, wasm::OldTrapDesc) { MOZ_CRASH(); }
     template <typename T> void j(Condition, T) { MOZ_CRASH(); }
     template <typename T> void jump(T) { MOZ_CRASH(); }
-    void writeCodePointer(CodeLabel* label) { MOZ_CRASH(); }
+    void writeCodePointer(CodeOffset* label) { MOZ_CRASH(); }
     void haltingAlign(size_t) { MOZ_CRASH(); }
     void nopAlign(size_t) { MOZ_CRASH(); }
     void checkStackAlignment() { MOZ_CRASH(); }
     uint32_t currentOffset() { MOZ_CRASH(); }
     CodeOffset labelForPatch() { MOZ_CRASH(); }
 
     void nop() { MOZ_CRASH(); }
     void breakpoint() { MOZ_CRASH(); }
--- a/js/src/jit/shared/Assembler-shared.h
+++ b/js/src/jit/shared/Assembler-shared.h
@@ -27,20 +27,16 @@
 #endif
 
 #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)
 // JS_SMALL_BRANCH means the range on a branch instruction
 // is smaller than the whole address space
 # define JS_SMALL_BRANCH
 #endif
 
-#if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
-# define JS_CODELABEL_LINKMODE
-#endif
-
 using mozilla::CheckedInt;
 
 namespace js {
 namespace jit {
 
 namespace Disassembler {
 class HeapAccess;
 } // namespace Disassembler
@@ -528,41 +524,26 @@ class CodeOffset
         offset_ += delta;
     }
 };
 
 // A code label contains an absolute reference to a point in the code. Thus, it
 // cannot be patched until after linking.
 // When the source label is resolved into a memory address, this address is
 // patched into the destination address.
-// Some need to distinguish between multiple ways of patching that address.
-// See JS_CODELABEL_LINKMODE.
 class CodeLabel
 {
     // The destination position, where the absolute reference should get
     // patched into.
     CodeOffset patchAt_;
 
     // The source label (relative) in the code to where the destination should
     // get patched to.
     CodeOffset target_;
 
-#ifdef JS_CODELABEL_LINKMODE
-public:
-    enum LinkMode
-    {
-        Uninitialized = 0,
-        RawPointer,
-        MoveImmediate,
-        JumpImmediate
-    };
-private:
-    LinkMode linkMode_ = Uninitialized;
-#endif
-
   public:
     CodeLabel()
     { }
     explicit CodeLabel(const CodeOffset& patchAt)
       : patchAt_(patchAt)
     { }
     CodeLabel(const CodeOffset& patchAt, const CodeOffset& target)
       : patchAt_(patchAt),
@@ -575,24 +556,16 @@ private:
         return &target_;
     }
     CodeOffset patchAt() const {
         return patchAt_;
     }
     CodeOffset target() const {
         return target_;
     }
-#ifdef JS_CODELABEL_LINKMODE
-    LinkMode linkMode() const {
-        return linkMode_;
-    }
-    void setLinkMode(LinkMode value) {
-        linkMode_ = value;
-    }
-#endif
 };
 
 typedef Vector<CodeLabel, 0, SystemAllocPolicy> CodeLabelVector;
 
 // Location of a jump or label in a generated JitCode block, relative to the
 // start of the block.
 
 class CodeOffsetJump
--- a/js/src/jit/x64/Assembler-x64.h
+++ b/js/src/jit/x64/Assembler-x64.h
@@ -932,19 +932,19 @@ class Assembler : public AssemblerX86Sha
         movq(src, dest);
     }
     void mov(Imm32 imm32, const Operand& dest) {
         movq(imm32, dest);
     }
     void mov(Register src, Register dest) {
         movq(src, dest);
     }
-    void mov(CodeLabel* label, Register dest) {
+    void mov(CodeOffset* label, Register dest) {
         masm.movq_i64r(/* placeholder */ 0, dest.encoding());
-        label->patchAt()->bind(masm.size());
+        label->bind(masm.size());
     }
     void xchg(Register src, Register dest) {
         xchgq(src, dest);
     }
 
     void lea(const Operand& src, Register dest) {
         switch (src.kind()) {
           case Operand::MEM_REG_DISP:
--- a/js/src/jit/x64/Trampoline-x64.cpp
+++ b/js/src/jit/x64/Trampoline-x64.cpp
@@ -183,17 +183,17 @@ JitRuntime::generateEnterJIT(JSContext* 
 
         Label notOsr;
         masm.branchTestPtr(Assembler::Zero, OsrFrameReg, OsrFrameReg, &notOsr);
 
         Register numStackValues = regs.takeAny();
         masm.movq(numStackValuesAddr, numStackValues);
 
         // Push return address
-        masm.mov(&returnLabel, scratch);
+        masm.mov(returnLabel.patchAt(), scratch);
         masm.push(scratch);
 
         // Push previous frame pointer.
         masm.push(rbp);
 
         // Reserve frame.
         Register framePtr = rbp;
         masm.subPtr(Imm32(BaselineFrame::Size()), rsp);
@@ -273,35 +273,35 @@ JitRuntime::generateEnterJIT(JSContext* 
         masm.jump(reg_code);
 
         // OOM: load error value, discard return address and previous frame
         // pointer and return.
         masm.bind(&error);
         masm.mov(framePtr, rsp);
         masm.addPtr(Imm32(2 * sizeof(uintptr_t)), rsp);
         masm.moveValue(MagicValue(JS_ION_ERROR), JSReturnOperand);
-        masm.mov(&oomReturnLabel, scratch);
+        masm.mov(oomReturnLabel.patchAt(), scratch);
         masm.jump(scratch);
 
         masm.bind(&notOsr);
         masm.movq(scopeChain, R1.scratchReg());
     }
 
     // The call will push the return address on the stack, thus we check that
     // the stack would be aligned once the call is complete.
     masm.assertStackAlignment(JitStackAlignment, sizeof(uintptr_t));
 
     // Call function.
     masm.callJitNoProfiler(reg_code);
 
     {
         // Interpreter -> Baseline OSR will return here.
-        masm.bind(&returnLabel);
+        masm.use(returnLabel.target());
         masm.addCodeLabel(returnLabel);
-        masm.bind(&oomReturnLabel);
+        masm.use(oomReturnLabel.target());
         masm.addCodeLabel(oomReturnLabel);
     }
 
     // Pop arguments and padding from stack.
     masm.pop(r14);              // Pop and decode descriptor.
     masm.shrq(Imm32(FRAMESIZE_SHIFT), r14);
     masm.addq(r14, rsp);        // Remove arguments.
 
--- a/js/src/jit/x86-shared/Assembler-x86-shared.cpp
+++ b/js/src/jit/x86-shared/Assembler-x86-shared.cpp
@@ -133,18 +133,19 @@ AssemblerX86Shared::executableCopy(void*
         blackbox[4] = uintptr_t(0xFFFF8888);
         MOZ_CRASH("Corrupt code buffer");
     }
 }
 
 void
 AssemblerX86Shared::processCodeLabels(uint8_t* rawCode)
 {
-    for (const CodeLabel& label : codeLabels_) {
-        Bind(rawCode, label);
+    for (size_t i = 0; i < codeLabels_.length(); i++) {
+        CodeLabel label = codeLabels_[i];
+        Bind(rawCode, *label.patchAt(), *label.target());
     }
 }
 
 AssemblerX86Shared::Condition
 AssemblerX86Shared::InvertCondition(Condition cond)
 {
     switch (cond) {
       case Zero:
--- a/js/src/jit/x86-shared/Assembler-x86-shared.h
+++ b/js/src/jit/x86-shared/Assembler-x86-shared.h
@@ -444,20 +444,20 @@ class AssemblerX86Shared : public Assemb
 
   public:
     void haltingAlign(int alignment) {
         masm.haltingAlign(alignment);
     }
     void nopAlign(int alignment) {
         masm.nopAlign(alignment);
     }
-    void writeCodePointer(CodeLabel* label) {
+    void writeCodePointer(CodeOffset* label) {
         // Use -1 as dummy value. This will be patched after codegen.
         masm.jumpTablePointer(-1);
-        label->patchAt()->bind(masm.size());
+        label->bind(masm.size());
     }
     void cmovCCl(Condition cond, const Operand& src, Register dest) {
         X86Encoding::Condition cc = static_cast<X86Encoding::Condition>(cond);
         switch (src.kind()) {
           case Operand::REG:
             masm.cmovCCl_rr(cc, src.reg(), dest.encoding());
             break;
           case Operand::MEM_REG_DISP:
@@ -987,18 +987,18 @@ class AssemblerX86Shared : public Assemb
     void bind(RepatchLabel* label) {
         JmpDst dst(masm.label());
         if (label->used()) {
             JmpSrc jmp(label->offset());
             masm.linkJump(jmp, dst);
         }
         label->bind(dst.offset());
     }
-    void bind(CodeLabel* label) {
-        label->target()->bind(currentOffset());
+    void use(CodeOffset* label) {
+        label->bind(currentOffset());
     }
     uint32_t currentOffset() {
         return masm.label().offset();
     }
 
     // Re-routes pending jumps to a new label.
     void retarget(Label* label, Label* target) {
         if (!label->used())
@@ -1019,21 +1019,20 @@ class AssemblerX86Shared : public Assemb
                 target->use(jmp.offset());
                 masm.setNextJump(jmp, prev);
             }
             jmp = JmpSrc(next.offset());
         } while (more);
         label->reset();
     }
 
-    static void Bind(uint8_t* raw, const CodeLabel& label) {
-        if (label.patchAt().bound()) {
-            intptr_t offset = label.patchAt().offset();
-            intptr_t target = label.target().offset();
-            X86Encoding::SetPointer(raw + offset, raw + target);
+    static void Bind(uint8_t* raw, CodeOffset label, CodeOffset target) {
+        if (label.bound()) {
+            intptr_t offset = label.offset();
+            X86Encoding::SetPointer(raw + offset, raw + target.offset());
         }
     }
 
     void ret() {
         masm.ret();
     }
     void retn(Imm32 n) {
         // Remove the size of the return address which is included in the frame.
--- a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp
@@ -1842,28 +1842,28 @@ class OutOfLineTableSwitch : public OutO
 };
 
 void
 CodeGeneratorX86Shared::visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool)
 {
     MTableSwitch* mir = ool->mir();
 
     masm.haltingAlign(sizeof(void*));
-    masm.bind(ool->jumpLabel());
+    masm.use(ool->jumpLabel()->target());
     masm.addCodeLabel(*ool->jumpLabel());
 
     for (size_t i = 0; i < mir->numCases(); i++) {
         LBlock* caseblock = skipTrivialBlocks(mir->getCase(i))->lir();
         Label* caseheader = caseblock->label();
         uint32_t caseoffset = caseheader->offset();
 
         // The entries of the jump table need to be absolute addresses and thus
         // must be patched after codegen is finished.
         CodeLabel cl;
-        masm.writeCodePointer(&cl);
+        masm.writeCodePointer(cl.patchAt());
         cl.target()->bind(caseoffset);
         masm.addCodeLabel(cl);
     }
 }
 
 void
 CodeGeneratorX86Shared::emitTableSwitchDispatch(MTableSwitch* mir, Register index, Register base)
 {
@@ -1880,17 +1880,17 @@ CodeGeneratorX86Shared::emitTableSwitchD
 
     // To fill in the CodeLabels for the case entries, we need to first
     // generate the case entries (we don't yet know their offsets in the
     // instruction stream).
     OutOfLineTableSwitch* ool = new(alloc()) OutOfLineTableSwitch(mir);
     addOutOfLineCode(ool, mir);
 
     // Compute the position where a pointer to the right case stands.
-    masm.mov(ool->jumpLabel(), base);
+    masm.mov(ool->jumpLabel()->patchAt(), base);
     BaseIndex pointer(base, index, ScalePointer);
 
     // Jump to the right case
     masm.branchToComputedAddress(pointer);
 }
 
 void
 CodeGeneratorX86Shared::visitMathD(LMathD* math)
--- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp
+++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp
@@ -654,19 +654,19 @@ MacroAssembler::patchCallToNop(uint8_t* 
 // ===============================================================
 // Jit Frames.
 
 uint32_t
 MacroAssembler::pushFakeReturnAddress(Register scratch)
 {
     CodeLabel cl;
 
-    mov(&cl, scratch);
+    mov(cl.patchAt(), scratch);
     Push(scratch);
-    bind(&cl);
+    use(cl.target());
     uint32_t retAddr = currentOffset();
 
     addCodeLabel(cl);
     return retAddr;
 }
 
 // ===============================================================
 // WebAssembly
--- a/js/src/jit/x86/Assembler-x86.h
+++ b/js/src/jit/x86/Assembler-x86.h
@@ -345,20 +345,20 @@ class Assembler : public AssemblerX86Sha
         movl(src, dest);
     }
     void mov(Register src, const Operand& dest) {
         movl(src, dest);
     }
     void mov(Imm32 imm, const Operand& dest) {
         movl(imm, dest);
     }
-    void mov(CodeLabel* label, Register dest) {
+    void mov(CodeOffset* label, Register dest) {
         // Put a placeholder value in the instruction stream.
         masm.movl_i32r(0, dest.encoding());
-        label->patchAt()->bind(masm.size());
+        label->bind(masm.size());
     }
     void mov(Register src, Register dest) {
         movl(src, dest);
     }
     void xchg(Register src, Register dest) {
         xchgl(src, dest);
     }
     void lea(const Operand& src, Register dest) {
--- a/js/src/jit/x86/Trampoline-x86.cpp
+++ b/js/src/jit/x86/Trampoline-x86.cpp
@@ -283,19 +283,19 @@ JitRuntime::generateEnterJIT(JSContext* 
     /***************************************************************
         Call passed-in code, get return value and fill in the
         passed in return value pointer
     ***************************************************************/
     masm.call(Address(ebp, ARG_JITCODE));
 
     {
         // Interpreter -> Baseline OSR will return here.
-        masm.bind(&returnLabel);
+        masm.use(returnLabel.target());
         masm.addCodeLabel(returnLabel);
-        masm.bind(&oomReturnLabel);
+        masm.use(oomReturnLabel.target());
         masm.addCodeLabel(oomReturnLabel);
     }
 
     // Pop arguments off the stack.
     // eax <- 8*argc (size of all arguments we pushed on the stack)
     masm.pop(eax);
     masm.shrl(Imm32(FRAMESIZE_SHIFT), eax); // Unmark EntryFrame.
     masm.addl(eax, esp);
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -3381,30 +3381,30 @@ class BaseCompiler final : public BaseCo
         // Flush constant pools to ensure that the table is never interrupted by
         // constant pool entries.
         masm.flush();
 
         masm.bind(theTable);
 
         for (uint32_t i = 0; i < labels.length(); i++) {
             CodeLabel cl;
-            masm.writeCodePointer(&cl);
+            masm.writeCodePointer(cl.patchAt());
             cl.target()->bind(labels[i].offset());
             masm.addCodeLabel(cl);
         }
     }
 
     void tableSwitch(Label* theTable, RegI32 switchValue, Label* dispatchCode) {
         masm.bind(dispatchCode);
 
 #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86)
         ScratchI32 scratch(*this);
         CodeLabel tableCl;
 
-        masm.mov(&tableCl, scratch);
+        masm.mov(tableCl.patchAt(), scratch);
 
         tableCl.target()->bind(theTable->offset());
         masm.addCodeLabel(tableCl);
 
         masm.jmp(Operand(scratch, switchValue, ScalePointer));
 #elif defined(JS_CODEGEN_ARM)
         // Flush constant pools: offset must reflect the distance from the MOV
         // to the start of the table; as the address of the MOV is given by the
@@ -3430,22 +3430,28 @@ class BaseCompiler final : public BaseCo
 
         // Jump indirect via table element.
         masm.ma_ldr(DTRAddr(scratch, DtrRegImmShift(switchValue, LSL, 2)), pc, Offset,
                     Assembler::Always);
 #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
         ScratchI32 scratch(*this);
         CodeLabel tableCl;
 
-        masm.ma_li(scratch, &tableCl);
+        masm.ma_li(scratch, tableCl.patchAt());
+# ifdef JS_CODEGEN_MIPS32
+        masm.lshiftPtr(Imm32(4), switchValue);
+# else
+        masm.ma_mul(switchValue, switchValue, Imm32(6 * 4));
+# endif
+        masm.addPtr(switchValue, scratch);
 
         tableCl.target()->bind(theTable->offset());
         masm.addCodeLabel(tableCl);
 
-        masm.branchToComputedAddress(BaseIndex(scratch, switchValue, ScalePointer));
+        masm.branch(scratch);
 #else
         MOZ_CRASH("BaseCompiler platform hook: tableSwitch");
 #endif
     }
 
     RegI32 captureReturnedI32() {
         RegI32 r = RegI32(ReturnReg);
         MOZ_ASSERT(isAvailableI32(r));
--- a/js/src/wasm/WasmCode.cpp
+++ b/js/src/wasm/WasmCode.cpp
@@ -107,23 +107,19 @@ FreeCode::operator()(uint8_t* bytes)
 #endif
     DeallocateExecutableMemory(bytes, codeLength);
 }
 
 static bool
 StaticallyLink(const ModuleSegment& ms, const LinkDataTier& linkData)
 {
     for (LinkDataTier::InternalLink link : linkData.internalLinks) {
-        CodeLabel label;
-        label.patchAt()->bind(link.patchAtOffset);
-        label.target()->bind(link.targetOffset);
-#ifdef JS_CODELABEL_LINKMODE
-        label.setLinkMode(static_cast<CodeLabel::LinkMode>(link.mode));
-#endif
-        Assembler::Bind(ms.base(), label);
+        CodeOffset patchAt(link.patchAtOffset);
+        CodeOffset target(link.targetOffset);
+        Assembler::Bind(ms.base(), patchAt, target);
     }
 
     if (!EnsureBuiltinThunksInitialized())
         return false;
 
     for (auto imm : MakeEnumeratedRange(SymbolicAddress::Limit)) {
         const Uint32Vector& offsets = linkData.symbolicLinks[imm];
         if (offsets.empty())
@@ -140,23 +136,19 @@ StaticallyLink(const ModuleSegment& ms, 
 
     return true;
 }
 
 static void
 StaticallyUnlink(uint8_t* base, const LinkDataTier& linkData)
 {
     for (LinkDataTier::InternalLink link : linkData.internalLinks) {
-        CodeLabel label;
-        label.patchAt()->bind(link.patchAtOffset);
-        label.target()->bind(-size_t(base)); // to reset immediate to null
-#ifdef JS_CODELABEL_LINKMODE
-        label.setLinkMode(static_cast<CodeLabel::LinkMode>(link.mode));
-#endif
-        Assembler::Bind(base, label);
+        CodeOffset patchAt(link.patchAtOffset);
+        CodeOffset target(-size_t(base));  // to reset immediate to null
+        Assembler::Bind(base, patchAt, target);
     }
 
     for (auto imm : MakeEnumeratedRange(SymbolicAddress::Limit)) {
         const Uint32Vector& offsets = linkData.symbolicLinks[imm];
         if (offsets.empty())
             continue;
 
         void* target = SymbolicAddressTarget(imm);
--- a/js/src/wasm/WasmGenerator.cpp
+++ b/js/src/wasm/WasmGenerator.cpp
@@ -622,19 +622,16 @@ ModuleGenerator::linkCompiledCode(const 
         if (!linkDataTier_->symbolicLinks[access.target].append(patchAt))
             return false;
     }
 
     for (const CodeLabel& codeLabel : code.codeLabels) {
         LinkDataTier::InternalLink link;
         link.patchAtOffset = offsetInModule + codeLabel.patchAt().offset();
         link.targetOffset = offsetInModule + codeLabel.target().offset();
-#ifdef JS_CODELABEL_LINKMODE
-        link.mode = codeLabel.linkMode();
-#endif
         if (!linkDataTier_->internalLinks.append(link))
             return false;
     }
 
     return true;
 }
 
 static bool
--- a/js/src/wasm/WasmModule.h
+++ b/js/src/wasm/WasmModule.h
@@ -57,19 +57,16 @@ struct LinkDataTier : LinkDataTierCachea
     explicit LinkDataTier(Tier tier) : tier(tier) {}
 
     LinkDataTierCacheablePod& pod() { return *this; }
     const LinkDataTierCacheablePod& pod() const { return *this; }
 
     struct InternalLink {
         uint32_t patchAtOffset;
         uint32_t targetOffset;
-#ifdef JS_CODELABEL_LINKMODE
-        uint32_t mode;
-#endif
     };
     typedef Vector<InternalLink, 0, SystemAllocPolicy> InternalLinkVector;
 
     struct SymbolicLinkArray : EnumeratedArray<SymbolicAddress, SymbolicAddress::Limit, Uint32Vector> {
         WASM_DECLARE_SERIALIZABLE(SymbolicLinkArray)
     };
 
     InternalLinkVector  internalLinks;