Bug 774364 - Part 3: Move Math.random() to macro assembler. r=sstangl,hev,nbp, f=rankov
authorTooru Fujisawa <arai_a@mac.com>
Fri, 07 Aug 2015 07:41:16 +0900
changeset 296094 ef13876b06a6558b7999a382f23c70f1c4b9526a
parent 296093 41cce993981073d8319cab239570192c3aacd3d1
child 296095 17f698573ccc32ac312350f896e962d6d9760a33
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssstangl, hev, nbp
bugs774364
milestone43.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 774364 - Part 3: Move Math.random() to macro assembler. r=sstangl,hev,nbp, f=rankov
js/src/jit/CodeGenerator.cpp
js/src/jit/CodeGenerator.h
js/src/jit/MacroAssembler.h
js/src/jit/Registers.h
js/src/jit/arm/CodeGenerator-arm.cpp
js/src/jit/arm/CodeGenerator-arm.h
js/src/jit/arm/LIR-arm.h
js/src/jit/arm/Lowering-arm.cpp
js/src/jit/arm/MacroAssembler-arm-inl.h
js/src/jit/arm/MacroAssembler-arm.cpp
js/src/jit/arm/MacroAssembler-arm.h
js/src/jit/arm64/CodeGenerator-arm64.cpp
js/src/jit/arm64/CodeGenerator-arm64.h
js/src/jit/arm64/LIR-arm64.h
js/src/jit/arm64/Lowering-arm64.cpp
js/src/jit/arm64/MacroAssembler-arm64-inl.h
js/src/jit/arm64/MacroAssembler-arm64.h
js/src/jit/mips-shared/LIR-mips-shared.h
js/src/jit/mips-shared/Lowering-mips-shared.cpp
js/src/jit/mips32/CodeGenerator-mips32.cpp
js/src/jit/mips32/CodeGenerator-mips32.h
js/src/jit/mips32/Lowering-mips32.cpp
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/none/CodeGenerator-none.h
js/src/jit/none/LIR-none.h
js/src/jit/none/Lowering-none.h
js/src/jit/shared/Assembler-shared.h
js/src/jit/shared/LIR-shared.h
js/src/jit/x64/CodeGenerator-x64.cpp
js/src/jit/x64/CodeGenerator-x64.h
js/src/jit/x64/LIR-x64.h
js/src/jit/x64/Lowering-x64.cpp
js/src/jit/x64/MacroAssembler-x64-inl.h
js/src/jit/x64/MacroAssembler-x64.h
js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp
js/src/jit/x86-shared/CodeGenerator-x86-shared.h
js/src/jit/x86-shared/Encoding-x86-shared.h
js/src/jit/x86/Assembler-x86.h
js/src/jit/x86/BaseAssembler-x86.h
js/src/jit/x86/CodeGenerator-x86.cpp
js/src/jit/x86/CodeGenerator-x86.h
js/src/jit/x86/LIR-x86.h
js/src/jit/x86/Lowering-x86.cpp
js/src/jit/x86/MacroAssembler-x86-inl.h
js/src/jit/x86/MacroAssembler-x86.cpp
js/src/jit/x86/MacroAssembler-x86.h
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -10299,10 +10299,133 @@ CodeGenerator::visitNewTarget(LNewTarget
     masm.bind(&actualArgsSufficient);
 
     BaseValueIndex newTarget(masm.getStackPointer(), argvLen, frameSize() + JitFrameLayout::offsetOfActualArgs());
     masm.loadValue(newTarget, output);
 
     masm.bind(&done);
 }
 
+// Out-of-line math_random_no_outparam call for LRandom.
+class OutOfLineRandom : public OutOfLineCodeBase<CodeGenerator>
+{
+    LRandom* lir_;
+
+  public:
+    explicit OutOfLineRandom(LRandom* lir)
+      : lir_(lir)
+    { }
+
+    void accept(CodeGenerator* codegen) {
+        codegen->visitOutOfLineRandom(this);
+    }
+
+    LRandom* lir() const {
+        return lir_;
+    }
+};
+
+static const uint64_t RNG_HIGH_MASK = (0xFFFFFFFFFFFFFFFFULL >>
+                                       (RNG_STATE_WIDTH - RNG_HIGH_BITS)) << RNG_LOW_BITS;
+static const double RNG_DSCALE_INV = 1 / RNG_DSCALE;
+
+void
+CodeGenerator::visitRandom(LRandom* ins)
+{
+    FloatRegister output = ToFloatRegister(ins->output());
+    Register JSCompartmentReg = ToRegister(ins->temp1());
+#ifdef JS_PUNBOX64
+    Register64 rngStateReg = Register64(ToRegister(ins->tempMaybeEAX()));
+    Register64 highReg = Register64(ToRegister(ins->tempMaybeEDX()));
+#else
+    Register64 rngStateReg = Register64(ToRegister(ins->temp2()), ToRegister(ins->temp3()));
+    Register64 highReg = Register64(ToRegister(ins->tempMaybeEAX()), ToRegister(ins->tempMaybeEDX()));
+#endif
+    // tempReg is used only on x86.
+    Register tempReg = ToRegister(ins->tempMaybeEAX());
+
+    // rngState = cx->compartment()->rngState;
+    masm.loadJSContext(JSCompartmentReg);
+    masm.loadPtr(Address(JSCompartmentReg, JSContext::offsetOfCompartment()), JSCompartmentReg);
+    masm.load64(Address(JSCompartmentReg, JSCompartment::offsetOfRngState()), rngStateReg);
+
+    // if rngState == 0, escape from inlined code and call
+    // math_random_no_outparam.
+    OutOfLineRandom* ool = new(alloc()) OutOfLineRandom(ins);
+    addOutOfLineCode(ool, ins->mir());
+    masm.branchTest64(Assembler::Zero, rngStateReg, rngStateReg, tempReg, ool->entry());
+
+    // rngState = rngState * RNG_MULTIPLIER;
+    masm.mul64(Imm64(RNG_MULTIPLIER), rngStateReg);
+
+    // rngState += RNG_ADDEND;
+    masm.add64(Imm32(RNG_ADDEND), rngStateReg);
+
+    // rngState &= RNG_MASK;
+    masm.and64(Imm64(RNG_MASK), rngStateReg);
+
+    // if rngState == 0, escape from inlined code and call
+    // math_random_no_outparam.
+    masm.branchTest64(Assembler::Zero, rngStateReg, rngStateReg, tempReg, ool->entry());
+
+    // high = (rngState >> (RNG_STATE_WIDTH - RNG_HIGH_BITS)) << RNG_LOW_BITS;
+    masm.move64(rngStateReg, highReg);
+    masm.lshift64(Imm32(RNG_LOW_BITS - (RNG_STATE_WIDTH - RNG_HIGH_BITS)), highReg);
+    masm.and64(Imm64(RNG_HIGH_MASK), highReg);
+#ifdef JS_CODEGEN_X86
+    // eax and edx are overwritten by mul64 on x86.
+    masm.push64(highReg);
+#endif
+
+    // rngState = rngState * RNG_MULTIPLIER;
+    masm.mul64(Imm64(RNG_MULTIPLIER), rngStateReg);
+
+    // rngState += RNG_ADDEND;
+    masm.add64(Imm32(RNG_ADDEND), rngStateReg);
+
+    // rngState &= RNG_MASK;
+    masm.and64(Imm64(RNG_MASK), rngStateReg);
+
+    // cx->compartment()->rngState = rngState;
+    masm.store64(rngStateReg, Address(JSCompartmentReg, JSCompartment::offsetOfRngState()));
+
+    // low = rngState >> (RNG_STATE_WIDTH - RNG_LOW_BITS);
+    const Register64& lowReg = rngStateReg;
+    masm.rshift64(Imm32(RNG_STATE_WIDTH - RNG_LOW_BITS), lowReg);
+
+    // output = double(high | low);
+#ifdef JS_CODEGEN_X86
+    masm.pop64(highReg);
+#endif
+    masm.or64(highReg, lowReg);
+    masm.convertUInt64ToDouble(lowReg, tempReg, output);
+
+    // output = output * RNG_DSCALE_INV;
+    masm.mulDoublePtr(ImmPtr(&RNG_DSCALE_INV), tempReg, output);
+
+    masm.bind(ool->rejoin());
+}
+
+void
+CodeGenerator::visitOutOfLineRandom(OutOfLineRandom* ool)
+{
+    LRandom* ins = ool->lir();
+    Register temp1 = ToRegister(ins->tempMaybeEAX());
+    Register temp2 = ToRegister(ins->tempMaybeEDX());
+    MOZ_ASSERT(ToFloatRegister(ins->output()) == ReturnDoubleReg);
+
+    LiveRegisterSet regs;
+    setReturnDoubleRegs(&regs);
+    saveVolatile(regs);
+
+    masm.loadJSContext(temp1);
+
+    masm.setupUnalignedABICall(temp2);
+    masm.passABIArg(temp1);
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, math_random_no_outparam), MoveOp::DOUBLE);
+
+    restoreVolatile(regs);
+
+    masm.jump(ool->rejoin());
+}
+
 } // namespace jit
 } // namespace js
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -40,16 +40,17 @@ class OutOfLineUnboxFloatingPoint;
 class OutOfLineStoreElementHole;
 class OutOfLineTypeOfV;
 class OutOfLineUpdateCache;
 class OutOfLineCallPostWriteBarrier;
 class OutOfLineIsCallable;
 class OutOfLineRegExpExec;
 class OutOfLineRegExpTest;
 class OutOfLineLambdaArrow;
+class OutOfLineRandom;
 
 class CodeGenerator : public CodeGeneratorSpecific
 {
     void generateArgumentsChecks(bool bailout = true);
     bool generateBody();
 
   public:
     CodeGenerator(MIRGenerator* gen, LIRGraph* graph, MacroAssembler* masm = nullptr);
@@ -377,16 +378,19 @@ class CodeGenerator : public CodeGenerat
     void visitAssertResultT(LAssertResultT* ins);
     void emitAssertResultV(const ValueOperand output, const TemporaryTypeSet* typeset);
     void emitAssertObjectOrStringResult(Register input, MIRType type, const TemporaryTypeSet* typeset);
 
     void visitInterruptCheck(LInterruptCheck* lir);
     void visitAsmJSInterruptCheck(LAsmJSInterruptCheck* lir);
     void visitRecompileCheck(LRecompileCheck* ins);
 
+    void visitRandom(LRandom* ins);
+    void visitOutOfLineRandom(OutOfLineRandom* ool);
+
     IonScriptCounts* extractScriptCounts() {
         IonScriptCounts* counts = scriptCounts_;
         scriptCounts_ = nullptr;  // prevent delete in dtor
         return counts;
     }
 
   private:
     void addGetPropertyCache(LInstruction* ins, LiveRegisterSet liveRegs, Register objReg,
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -675,23 +675,27 @@ class MacroAssembler : public MacroAssem
     inline void and32(Imm32 imm, Register dest) PER_SHARED_ARCH;
     inline void and32(Imm32 imm, Register src, Register dest) DEFINED_ON(arm64);
     inline void and32(Imm32 imm, const Address& dest) PER_SHARED_ARCH;
     inline void and32(const Address& src, Register dest) PER_SHARED_ARCH;
 
     inline void andPtr(Register src, Register dest) PER_ARCH;
     inline void andPtr(Imm32 imm, Register dest) PER_ARCH;
 
+    inline void and64(Imm64 imm, Register64 dest) PER_ARCH;
+
     inline void or32(Register src, Register dest) PER_SHARED_ARCH;
     inline void or32(Imm32 imm, Register dest) PER_SHARED_ARCH;
     inline void or32(Imm32 imm, const Address& dest) PER_SHARED_ARCH;
 
     inline void orPtr(Register src, Register dest) PER_ARCH;
     inline void orPtr(Imm32 imm, Register dest) PER_ARCH;
 
+    inline void or64(Register64 src, Register64 dest) PER_ARCH;
+
     inline void xor32(Register src, Register dest) DEFINED_ON(x86_shared);
     inline void xor32(Imm32 imm, Register dest) PER_SHARED_ARCH;
 
     inline void xorPtr(Register src, Register dest) PER_ARCH;
     inline void xorPtr(Imm32 imm, Register dest) PER_ARCH;
 
     //}}} check_macroassembler_style
   public:
--- a/js/src/jit/Registers.h
+++ b/js/src/jit/Registers.h
@@ -88,16 +88,36 @@ struct Register {
     static uint32_t FirstBit(SetType x) {
         return Codes::FirstBit(x);
     }
     static uint32_t LastBit(SetType x) {
         return Codes::LastBit(x);
     }
 };
 
+struct Register64
+{
+#ifdef JS_PUNBOX64
+    Register reg;
+#else
+    Register high;
+    Register low;
+#endif
+
+#ifdef JS_PUNBOX64
+    explicit MOZ_CONSTEXPR Register64(Register r)
+      : reg(r)
+    {}
+#else
+    MOZ_CONSTEXPR Register64(Register h, Register l)
+      : high(h), low(l)
+    {}
+#endif
+};
+
 class RegisterDump
 {
   public:
     typedef mozilla::Array<Registers::RegisterContent, Registers::Total> GPRArray;
     typedef mozilla::Array<FloatRegisters::RegisterContent, FloatRegisters::TotalPhys> FPUArray;
 
   protected: // Silence Clang warning.
     GPRArray regs_;
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -5,17 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jit/arm/CodeGenerator-arm.h"
 
 #include "mozilla/MathAlgorithms.h"
 
 #include "jscntxt.h"
 #include "jscompartment.h"
-#include "jsmath.h"
 #include "jsnum.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"
@@ -2670,21 +2669,17 @@ CodeGeneratorARM::memoryBarrier(MemoryBa
 
 void
 CodeGeneratorARM::visitMemoryBarrier(LMemoryBarrier* ins)
 {
     memoryBarrier(ins->type());
 }
 
 void
-CodeGeneratorARM::visitRandom(LRandom* ins)
+CodeGeneratorARM::setReturnDoubleRegs(LiveRegisterSet* regs)
 {
-    Register temp = ToRegister(ins->temp());
-    Register temp2 = ToRegister(ins->temp2());
-
-    masm.loadJSContext(temp);
-
-    masm.setupUnalignedABICall(temp2);
-    masm.passABIArg(temp);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, math_random_no_outparam), MoveOp::DOUBLE);
-
-    MOZ_ASSERT(ToFloatRegister(ins->output()) == ReturnDoubleReg);
+    MOZ_ASSERT(ReturnFloat32Reg.code_ == FloatRegisters::s0);
+    MOZ_ASSERT(ReturnDoubleReg.code_ == FloatRegisters::s0);
+    FloatRegister s1 = {FloatRegisters::s1, VFPRegister::Single};
+    regs->add(ReturnFloat32Reg);
+    regs->add(s1);
+    regs->add(ReturnDoubleReg);
 }
--- a/js/src/jit/arm/CodeGenerator-arm.h
+++ b/js/src/jit/arm/CodeGenerator-arm.h
@@ -211,17 +211,17 @@ class CodeGeneratorARM : public CodeGene
     void visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr* ins);
     void visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc* ins);
     void visitAsmJSPassStackArg(LAsmJSPassStackArg* ins);
 
     void visitMemoryBarrier(LMemoryBarrier* ins);
 
     void generateInvalidateEpilogue();
 
-    void visitRandom(LRandom* ins);
+    void setReturnDoubleRegs(LiveRegisterSet* regs);
 
     // Generating a result.
     template<typename S, typename T>
     void atomicBinopToTypedIntArray(AtomicOp op, Scalar::Type arrayType, const S& value,
                                     const T& mem, Register flagTemp, Register outTemp,
                                     AnyRegister output);
 
     // Generating no result.
--- a/js/src/jit/arm/LIR-arm.h
+++ b/js/src/jit/arm/LIR-arm.h
@@ -492,29 +492,12 @@ class LAsmJSAtomicBinopCallout : public 
         return getOperand(1);
     }
 
     const MAsmJSAtomicBinopHeap* mir() const {
         return mir_->toAsmJSAtomicBinopHeap();
     }
 };
 
-// Math.random().
-class LRandom : public LCallInstructionHelper<1, 0, 2>
-{
-  public:
-    LIR_HEADER(Random)
-    LRandom(const LDefinition& temp, const LDefinition& temp2) {
-        setTemp(0, temp);
-        setTemp(1, temp2);
-    }
-    const LDefinition* temp() {
-        return getTemp(0);
-    }
-    const LDefinition* temp2() {
-        return getTemp(1);
-    }
-};
-
 } // namespace jit
 } // namespace js
 
 #endif /* jit_arm_LIR_arm_h */
--- a/js/src/jit/arm/Lowering-arm.cpp
+++ b/js/src/jit/arm/Lowering-arm.cpp
@@ -736,11 +736,15 @@ LIRGeneratorARM::visitSubstr(MSubstr* in
                                          tempByteOpRegister());
     define(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
 LIRGeneratorARM::visitRandom(MRandom* ins)
 {
-    LRandom* lir = new(alloc()) LRandom(tempFixed(CallTempReg0), tempFixed(CallTempReg1));
-    defineReturn(lir, ins);
+    LRandom *lir = new(alloc()) LRandom(temp(),
+                                        temp(),
+                                        temp(),
+                                        temp(),
+                                        temp());
+    defineFixed(lir, ins, LFloatReg(ReturnDoubleReg));
 }
--- a/js/src/jit/arm/MacroAssembler-arm-inl.h
+++ b/js/src/jit/arm/MacroAssembler-arm-inl.h
@@ -59,16 +59,23 @@ MacroAssembler::andPtr(Register src, Reg
 
 void
 MacroAssembler::andPtr(Imm32 imm, Register dest)
 {
     ma_and(imm, dest);
 }
 
 void
+MacroAssembler::and64(Imm64 imm, Register64 dest)
+{
+    and32(Imm32(imm.value & 0xFFFFFFFFL), dest.low);
+    and32(Imm32((imm.value >> 32) & 0xFFFFFFFFL), dest.high);
+}
+
+void
 MacroAssembler::or32(Register src, Register dest)
 {
     ma_orr(src, dest);
 }
 
 void
 MacroAssembler::or32(Imm32 imm, Register dest)
 {
@@ -92,16 +99,23 @@ MacroAssembler::orPtr(Register src, Regi
 
 void
 MacroAssembler::orPtr(Imm32 imm, Register dest)
 {
     ma_orr(imm, dest);
 }
 
 void
+MacroAssembler::or64(Register64 src, Register64 dest)
+{
+    or32(src.low, dest.low);
+    or32(src.high, dest.high);
+}
+
+void
 MacroAssembler::xor32(Imm32 imm, Register dest)
 {
     ma_eor(imm, dest, SetCC);
 }
 
 void
 MacroAssembler::xorPtr(Register src, Register dest)
 {
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -85,16 +85,29 @@ void
 MacroAssemblerARM::convertUInt32ToDouble(Register src, FloatRegister dest_)
 {
     // Direct conversions aren't possible.
     VFPRegister dest = VFPRegister(dest_);
     as_vxfer(src, InvalidReg, dest.uintOverlay(), CoreToFloat);
     as_vcvt(dest, dest.uintOverlay());
 }
 
+static const double TO_DOUBLE_HIGH_SCALE = 0x100000000;
+
+void
+MacroAssemblerARMCompat::convertUInt64ToDouble(Register64 src, Register temp, FloatRegister dest)
+{
+    convertUInt32ToDouble(src.high, dest);
+    movePtr(ImmPtr(&TO_DOUBLE_HIGH_SCALE), ScratchRegister);
+    loadDouble(Address(ScratchRegister, 0), ScratchDoubleReg);
+    mulDouble(ScratchDoubleReg, dest);
+    convertUInt32ToDouble(src.low, ScratchDoubleReg);
+    addDouble(ScratchDoubleReg, dest);
+}
+
 void
 MacroAssemblerARM::convertUInt32ToFloat32(Register src, FloatRegister dest_)
 {
     // Direct conversions aren't possible.
     VFPRegister dest = VFPRegister(dest_);
     as_vxfer(src, InvalidReg, dest.uintOverlay(), CoreToFloat);
     as_vcvt(VFPRegister(dest).singleOverlay(), dest.uintOverlay());
 }
@@ -3368,16 +3381,32 @@ MacroAssemblerARMCompat::storeUnboxedVal
 template void
 MacroAssemblerARMCompat::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const Address& dest,
                                            MIRType slotType);
 
 template void
 MacroAssemblerARMCompat::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const BaseIndex& dest,
                                            MIRType slotType);
 
+
+void
+MacroAssemblerARMCompat::branchTest64(Condition cond, Register64 lhs, Register64 rhs,
+                                      Register temp, Label* label)
+{
+    if (cond == Assembler::Zero) {
+        MOZ_ASSERT(lhs.low == rhs.low);
+        MOZ_ASSERT(lhs.high == rhs.high);
+        mov(lhs.low, ScratchRegister);
+        asMasm().or32(lhs.high, ScratchRegister);
+        branchTestPtr(cond, ScratchRegister, ScratchRegister, label);
+    } else {
+        MOZ_CRASH("Unsupported condition");
+    }
+}
+
 void
 MacroAssemblerARMCompat::moveValue(const Value& val, Register type, Register data)
 {
     jsval_layout jv = JSVAL_TO_IMPL(val);
     ma_mov(Imm32(jv.s.tag), type);
     if (val.isMarkable())
         ma_mov(ImmGCPtr(reinterpret_cast<gc::Cell*>(val.toGCThing())), data);
     else
--- a/js/src/jit/arm/MacroAssembler-arm.h
+++ b/js/src/jit/arm/MacroAssembler-arm.h
@@ -982,16 +982,17 @@ class MacroAssemblerARMCompat : public M
     }
     void branchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) {
         branch32(cond, lhs, imm, label);
     }
     void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) {
         subPtr(imm, lhs);
         branch32(cond, lhs, Imm32(0), label);
     }
+    void branchTest64(Condition cond, Register64 lhs, Register64 rhs, Register temp, Label* label);
     void moveValue(const Value& val, Register type, Register data);
 
     CodeOffsetJump jumpWithPatch(RepatchLabel* label, Condition cond = Always,
                                  Label* documentation = nullptr);
     CodeOffsetJump backedgeJump(RepatchLabel* label, Label* documentation) {
         return jumpWithPatch(label, Always, documentation);
     }
     template <typename T>
@@ -1198,41 +1199,54 @@ class MacroAssemblerARMCompat : public M
     template <typename T>
     void branchSub32(Condition cond, T src, Register dest, Label* label) {
         sub32(src, dest);
         j(cond, label);
     }
 
     void addPtr(Register src, Register dest);
     void addPtr(const Address& src, Register dest);
+    void add64(Imm32 imm, Register64 dest) {
+        ma_add(imm, dest.low, SetCC);
+        ma_adc(Imm32(0), dest.high, LeaveCC);
+    }
+    void not32(Register reg);
 
     void move32(Imm32 imm, Register dest);
     void move32(Register src, Register dest);
 
     void movePtr(Register src, Register dest);
     void movePtr(ImmWord imm, Register dest);
     void movePtr(ImmPtr imm, Register dest);
     void movePtr(AsmJSImmPtr imm, Register dest);
     void movePtr(ImmGCPtr imm, Register dest);
+    void move64(Register64 src, Register64 dest) {
+        move32(src.low, dest.low);
+        move32(src.high, dest.high);
+    }
 
     void load8SignExtend(const Address& address, Register dest);
     void load8SignExtend(const BaseIndex& src, Register dest);
 
     void load8ZeroExtend(const Address& address, Register dest);
     void load8ZeroExtend(const BaseIndex& src, Register dest);
 
     void load16SignExtend(const Address& address, Register dest);
     void load16SignExtend(const BaseIndex& src, Register dest);
 
     void load16ZeroExtend(const Address& address, Register dest);
     void load16ZeroExtend(const BaseIndex& src, Register dest);
 
     void load32(const Address& address, Register dest);
     void load32(const BaseIndex& address, Register dest);
     void load32(AbsoluteAddress address, Register dest);
+    void load64(const Address& address, Register64 dest) {
+        load32(address, dest.low);
+        load32(Address(address.base, address.offset + 4), dest.high);
+    }
 
     void loadPtr(const Address& address, Register dest);
     void loadPtr(const BaseIndex& src, Register dest);
     void loadPtr(AbsoluteAddress address, Register dest);
     void loadPtr(AsmJSAbsoluteAddress address, Register dest);
 
     void loadPrivate(const Address& address, Register dest);
 
@@ -1289,16 +1303,21 @@ class MacroAssemblerARMCompat : public M
     void store32(Register src, AbsoluteAddress address);
     void store32(Register src, const Address& address);
     void store32(Register src, const BaseIndex& address);
     void store32(Imm32 src, const Address& address);
     void store32(Imm32 src, const BaseIndex& address);
 
     void store32_NoSecondScratch(Imm32 src, const Address& address);
 
+    void store64(Register64 src, Address address) {
+        store32(src.low, address);
+        store32(src.high, Address(address.base, address.offset + 4));
+    }
+
     template <typename T> void storePtr(ImmWord imm, T address);
     template <typename T> void storePtr(ImmPtr imm, T address);
     template <typename T> void storePtr(ImmGCPtr imm, T address);
     void storePtr(Register src, const Address& address);
     void storePtr(Register src, const BaseIndex& address);
     void storePtr(Register src, AbsoluteAddress dest);
     void storeDouble(FloatRegister src, Address addr) {
         ma_vstr(src, addr);
@@ -1637,16 +1656,49 @@ class MacroAssemblerARMCompat : public M
         addPtr(Imm32(imm.value), dest);
     }
     void addPtr(ImmPtr imm, const Register dest) {
         addPtr(ImmWord(uintptr_t(imm.value)), dest);
     }
     void mulBy3(const Register& src, const Register& dest) {
         as_add(dest, src, lsl(src, 1));
     }
+    void mul64(Imm64 imm, const Register64& dest) {
+        // LOW32  = LOW(LOW(dest) * LOW(imm));
+        // HIGH32 = LOW(HIGH(dest) * LOW(imm)) [multiply imm into upper bits]
+        //        + LOW(LOW(dest) * HIGH(imm)) [multiply dest into upper bits]
+        //        + HIGH(LOW(dest) * LOW(imm)) [carry]
+
+        // HIGH(dest) = LOW(HIGH(dest) * LOW(imm));
+        ma_mov(Imm32(imm.value & 0xFFFFFFFFL), ScratchRegister);
+        as_mul(dest.high, dest.high, ScratchRegister);
+
+        // high:low = LOW(dest) * LOW(imm);
+        as_umull(secondScratchReg_, ScratchRegister, dest.low, ScratchRegister);
+
+        // HIGH(dest) += high;
+        as_add(dest.high, dest.high, O2Reg(secondScratchReg_));
+
+        // HIGH(dest) += LOW(LOW(dest) * HIGH(imm));
+        if (((imm.value >> 32) & 0xFFFFFFFFL) == 5)
+            as_add(secondScratchReg_, dest.low, lsl(dest.low, 2));
+        else
+            MOZ_CRASH("Not supported imm");
+        as_add(dest.high, dest.high, O2Reg(secondScratchReg_));
+
+        // LOW(dest) = low;
+        ma_mov(ScratchRegister, dest.low);
+    }
+
+    void convertUInt64ToDouble(Register64 src, Register temp, FloatRegister dest);
+    void mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest) {
+        movePtr(imm, ScratchRegister);
+        loadDouble(Address(ScratchRegister, 0), ScratchDoubleReg);
+        mulDouble(ScratchDoubleReg, dest);
+    }
 
     void setStackArg(Register reg, uint32_t arg);
 
     void breakpoint();
     // Conditional breakpoint.
     void breakpoint(Condition cc);
 
     // Trigger the simulator's interactive read-eval-print loop.
@@ -1665,19 +1717,29 @@ class MacroAssemblerARMCompat : public M
     void checkStackAlignment();
 
     void rshiftPtr(Imm32 imm, Register dest) {
         ma_lsr(imm, dest, dest);
     }
     void rshiftPtrArithmetic(Imm32 imm, Register dest) {
         ma_asr(imm, dest, dest);
     }
+    void rshift64(Imm32 imm, Register64 dest) {
+        as_mov(dest.low, lsr(dest.low, imm.value));
+        as_orr(dest.low, dest.low, lsl(dest.high, 32 - imm.value));
+        as_mov(dest.high, lsr(dest.high, imm.value));
+    }
     void lshiftPtr(Imm32 imm, Register dest) {
         ma_lsl(imm, dest, dest);
     }
+    void lshift64(Imm32 imm, Register64 dest) {
+        as_mov(dest.high, lsl(dest.high, imm.value));
+        as_orr(dest.high, dest.high, lsr(dest.low, 32 - imm.value));
+        as_mov(dest.low, lsl(dest.low, imm.value));
+    }
 
     // If source is a double, load it into dest. If source is int32, convert it
     // to double. Else, branch to failure.
     void ensureDouble(const ValueOperand& source, FloatRegister dest, Label* failure);
 
     void
     emitSet(Assembler::Condition cond, Register dest)
     {
--- a/js/src/jit/arm64/CodeGenerator-arm64.cpp
+++ b/js/src/jit/arm64/CodeGenerator-arm64.cpp
@@ -603,22 +603,16 @@ CodeGeneratorARM64::visitInterruptCheck(
 }
 
 void
 CodeGeneratorARM64::generateInvalidateEpilogue()
 {
     MOZ_CRASH("generateInvalidateEpilogue");
 }
 
-void
-CodeGeneratorARM64::visitRandom(LRandom* ins)
-{
-    MOZ_CRASH("visitRandom");
-}
-
 template <class U>
 Register
 getBase(U* mir)
 {
     switch (mir->base()) {
       case U::Heap: return HeapReg;
       case U::Global: return GlobalReg;
     }
@@ -727,8 +721,19 @@ CodeGeneratorARM64::visitNegD(LNegD* ins
     MOZ_CRASH("visitNegD");
 }
 
 void
 CodeGeneratorARM64::visitNegF(LNegF* ins)
 {
     MOZ_CRASH("visitNegF");
 }
+
+void
+CodeGeneratorARM64::setReturnDoubleRegs(LiveRegisterSet* regs)
+{
+    MOZ_ASSERT(ReturnFloat32Reg.code_ == FloatRegisters::s0);
+    MOZ_ASSERT(ReturnDoubleReg.code_ == FloatRegisters::d0);
+    FloatRegister s1 = {FloatRegisters::s1, FloatRegisters::Single};
+    regs->add(ReturnFloat32Reg);
+    regs->add(s1);
+    regs->add(ReturnDoubleReg);
+}
--- a/js/src/jit/arm64/CodeGenerator-arm64.h
+++ b/js/src/jit/arm64/CodeGenerator-arm64.h
@@ -215,17 +215,17 @@ class CodeGeneratorARM64 : public CodeGe
     void visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar* ins);
     void visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar* ins);
     void visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr* ins);
     void visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc* ins);
     void visitAsmJSPassStackArg(LAsmJSPassStackArg* ins);
 
     void generateInvalidateEpilogue();
 
-    void visitRandom(LRandom* ins);
+    void setReturnDoubleRegs(LiveRegisterSet* regs);
 
   protected:
     void postAsmJSCall(LAsmJSCall* lir) {
         MOZ_CRASH("postAsmJSCall");
     }
 
     void visitEffectiveAddress(LEffectiveAddress* ins);
     void visitUDiv(LUDiv* ins);
--- a/js/src/jit/arm64/LIR-arm64.h
+++ b/js/src/jit/arm64/LIR-arm64.h
@@ -402,29 +402,12 @@ class LAsmJSLoadFuncPtr : public LInstru
     const LAllocation* index() {
         return getOperand(0);
     }
     const LDefinition* temp() {
         return getTemp(0);
     }
 };
 
-// Math.random().
-class LRandom : public LCallInstructionHelper<1, 0, 2>
-{
-  public:
-    LIR_HEADER(Random)
-    LRandom(const LDefinition& temp, const LDefinition& temp2) {
-        setTemp(0, temp);
-        setTemp(1, temp2);
-    }
-    const LDefinition* temp() {
-        return getTemp(0);
-    }
-    const LDefinition* temp2() {
-        return getTemp(1);
-    }
-};
-
 } // namespace jit
 } // namespace js
 
 #endif /* jit_arm64_LIR_arm64_h */
--- a/js/src/jit/arm64/Lowering-arm64.cpp
+++ b/js/src/jit/arm64/Lowering-arm64.cpp
@@ -299,10 +299,13 @@ void
 LIRGeneratorARM64::visitSubstr(MSubstr* ins)
 {
     MOZ_CRASH("visitSubstr");
 }
 
 void
 LIRGeneratorARM64::visitRandom(MRandom* ins)
 {
-    MOZ_CRASH("visitRandom");
+    LRandom *lir = new(alloc()) LRandom(temp(),
+                                        temp(),
+                                        temp());
+    defineFixed(lir, ins, LFloatReg(ReturnDoubleReg));
 }
--- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h
+++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h
@@ -69,16 +69,25 @@ MacroAssembler::andPtr(Register src, Reg
 
 void
 MacroAssembler::andPtr(Imm32 imm, Register dest)
 {
     And(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(imm.value));
 }
 
 void
+MacroAssembler::and64(Imm64 imm, Register64 dest)
+{
+    vixl::UseScratchRegisterScope temps(this);
+    const Register scratch = temps.AcquireX().asUnsized();
+    mov(ImmWord(imm.value), scratch);
+    andPtr(scratch, dest.reg);
+}
+
+void
 MacroAssembler::or32(Imm32 imm, Register dest)
 {
     Orr(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(imm.value));
 }
 
 void
 MacroAssembler::or32(Register src, Register dest)
 {
@@ -104,16 +113,22 @@ MacroAssembler::orPtr(Register src, Regi
 
 void
 MacroAssembler::orPtr(Imm32 imm, Register dest)
 {
     Orr(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(imm.value));
 }
 
 void
+MacroAssembler::or64(Register64 src, Register64 dest)
+{
+    orPtr(src.reg, dest.reg);
+}
+
+void
 MacroAssembler::xor32(Imm32 imm, Register dest)
 {
     Eor(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(imm.value));
 }
 
 void
 MacroAssembler::xorPtr(Register src, Register dest)
 {
--- a/js/src/jit/arm64/MacroAssembler-arm64.h
+++ b/js/src/jit/arm64/MacroAssembler-arm64.h
@@ -779,16 +779,19 @@ class MacroAssemblerCompat : public vixl
     void movePtr(AsmJSImmPtr imm, Register dest) {
         BufferOffset off = movePatchablePtr(ImmWord(0xffffffffffffffffULL), dest);
         append(AsmJSAbsoluteLink(CodeOffsetLabel(off.getOffset()), imm.kind()));
     }
     void movePtr(ImmGCPtr imm, Register dest) {
         BufferOffset load = movePatchablePtr(ImmPtr(imm.value), dest);
         writeDataRelocation(imm, load);
     }
+    void move64(Register64 src, Register64 dest) {
+        movePtr(src.reg, dest.reg);
+    }
 
     void mov(ImmWord imm, Register dest) {
         movePtr(imm, dest);
     }
     void mov(ImmPtr imm, Register dest) {
         movePtr(imm, dest);
     }
     void mov(AsmJSImmPtr imm, Register dest) {
@@ -984,16 +987,20 @@ class MacroAssemblerCompat : public vixl
         temps.Exclude(ARMRegister(ScratchReg2, 32)); // Disallow ScratchReg2.
         const ARMRegister scratch32 = temps.AcquireW();
 
         MOZ_ASSERT(scratch32.asUnsized() != address.base);
         Mov(scratch32, uint64_t(imm.value));
         Str(scratch32, MemOperand(ARMRegister(address.base, 64), address.offset));
     }
 
+    void store64(Register64 src, Address address) {
+        storePtr(src.reg, address);
+    }
+
     // SIMD.
     void loadInt32x1(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void loadInt32x1(const BaseIndex& addr, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void loadInt32x2(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void loadInt32x2(const BaseIndex& addr, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void loadInt32x3(const Address& src, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void loadInt32x3(const BaseIndex& src, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void storeInt32x1(FloatRegister src, const Address& dest) { MOZ_CRASH("NYI"); }
@@ -1063,23 +1070,29 @@ class MacroAssemblerCompat : public vixl
     }
 
     void rshiftPtr(Imm32 imm, Register dest) {
         Lsr(ARMRegister(dest, 64), ARMRegister(dest, 64), imm.value);
     }
     void rshiftPtr(Imm32 imm, Register src, Register dest) {
         Lsr(ARMRegister(dest, 64), ARMRegister(src, 64), imm.value);
     }
+    void rshift64(Imm32 imm, Register64 dest) {
+        rshiftPtr(imm, dest.reg);
+    }
 
     void rshiftPtrArithmetic(Imm32 imm, Register dest) {
         Asr(ARMRegister(dest, 64), ARMRegister(dest, 64), imm.value);
     }
     void lshiftPtr(Imm32 imm, Register dest) {
         Lsl(ARMRegister(dest, 64), ARMRegister(dest, 64), imm.value);
     }
+    void lshift64(Imm32 imm, Register64 dest) {
+        lshiftPtr(imm, dest.reg);
+    }
 
     void testPtr(Register lhs, Register rhs) {
         Tst(ARMRegister(lhs, 64), Operand(ARMRegister(rhs, 64)));
     }
     void test32(Register lhs, Register rhs) {
         Tst(ARMRegister(lhs, 32), Operand(ARMRegister(rhs, 32)));
     }
     void test32(const Address& addr, Imm32 imm) {
@@ -1157,17 +1170,17 @@ class MacroAssemblerCompat : public vixl
         vixl::UseScratchRegisterScope temps(this);
         const Register scratch = temps.AcquireX().asUnsized();
         MOZ_ASSERT(scratch != lhs.base);
         loadPtr(lhs, scratch);
         cmpPtr(scratch, rhs);
     }
 
     void loadDouble(const Address& src, FloatRegister dest) {
-        Ldr(ARMFPRegister(dest, 64), MemOperand(ARMRegister(src.base,64), src.offset));
+        Ldr(ARMFPRegister(dest, 64), MemOperand(src));
     }
     void loadDouble(const BaseIndex& src, FloatRegister dest) {
         ARMRegister base(src.base, 64);
         ARMRegister index(src.index, 64);
 
         if (src.offset == 0) {
             Ldr(ARMFPRegister(dest, 64), MemOperand(base, index, vixl::LSL, unsigned(src.scale)));
             return;
@@ -1301,16 +1314,19 @@ class MacroAssemblerCompat : public vixl
         doBaseIndex(ARMRegister(dest, 32), src, vixl::LDR_w);
     }
     void load32(AbsoluteAddress address, Register dest) {
         vixl::UseScratchRegisterScope temps(this);
         const ARMRegister scratch64 = temps.AcquireX();
         movePtr(ImmWord((uintptr_t)address.addr), scratch64.asUnsized());
         ldr(ARMRegister(dest, 32), MemOperand(scratch64));
     }
+    void load64(const Address& address, Register64 dest) {
+        loadPtr(address, dest.reg);
+    }
 
     void load8SignExtend(const Address& address, Register dest) {
         Ldrsb(ARMRegister(dest, 32), MemOperand(ARMRegister(address.base, 64), address.offset));
     }
     void load8SignExtend(const BaseIndex& src, Register dest) {
         doBaseIndex(ARMRegister(dest, 32), src, vixl::LDRSB_w);
     }
 
@@ -1361,16 +1377,19 @@ class MacroAssemblerCompat : public vixl
         vixl::UseScratchRegisterScope temps(this);
         const ARMRegister scratch32 = temps.AcquireW();
         MOZ_ASSERT(scratch32.asUnsized() != dest.base);
 
         Ldr(scratch32, MemOperand(ARMRegister(dest.base, 64), dest.offset));
         Adds(scratch32, scratch32, Operand(imm.value));
         Str(scratch32, MemOperand(ARMRegister(dest.base, 64), dest.offset));
     }
+    void add64(Imm32 imm, Register64 dest) {
+        Add(ARMRegister(dest.reg, 64), ARMRegister(dest.reg, 64), Operand(imm.value));
+    }
 
     void sub32(Imm32 imm, Register dest) {
         Sub(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(imm.value));
     }
     void sub32(Register src, Register dest) {
         Sub(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(ARMRegister(src, 32)));
     }
 
@@ -1906,16 +1925,19 @@ class MacroAssemblerCompat : public vixl
         vixl::UseScratchRegisterScope temps(this);
         const ARMRegister scratch64 = temps.AcquireX();
         MOZ_ASSERT(scratch64.asUnsized() != valaddr.base);
         MOZ_ASSERT(scratch64.asUnsized() != value.valueReg());
         loadValue(valaddr, scratch64.asUnsized());
         Cmp(ARMRegister(value.valueReg(), 64), Operand(scratch64));
         B(label, cond);
     }
+    void branchTest64(Condition cond, Register64 lhs, Register64 rhs, Register temp, Label* label) {
+        branchTestPtr(cond, lhs.reg, rhs.reg, label);
+    }
 
     void compareDouble(DoubleCondition cond, FloatRegister lhs, FloatRegister rhs) {
         Fcmp(ARMFPRegister(lhs, 64), ARMFPRegister(rhs, 64));
     }
     void branchDouble(DoubleCondition cond, FloatRegister lhs, FloatRegister rhs, Label* label) {
         compareDouble(cond, lhs, rhs);
         switch (cond) {
           case DoubleNotEqual: {
@@ -2953,16 +2975,37 @@ class MacroAssemblerCompat : public vixl
     }
 
     void mulBy3(Register src, Register dest) {
         ARMRegister xdest(dest, 64);
         ARMRegister xsrc(src, 64);
         Add(xdest, xsrc, Operand(xsrc, vixl::LSL, 1));
     }
 
+    void mul64(Imm64 imm, const Register64& dest) {
+        vixl::UseScratchRegisterScope temps(this);
+        const ARMRegister scratch64 = temps.AcquireX();
+        MOZ_ASSERT(dest.reg != scratch64.asUnsized());
+        mov(ImmWord(imm.value), scratch64.asUnsized());
+        Mul(ARMRegister(dest.reg, 64), ARMRegister(dest.reg, 64), scratch64);
+    }
+
+    void convertUInt64ToDouble(Register64 src, Register temp, FloatRegister dest) {
+        Ucvtf(ARMFPRegister(dest, 64), ARMRegister(src.reg, 64));
+    }
+    void mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest) {
+        vixl::UseScratchRegisterScope temps(this);
+        const Register scratch = temps.AcquireX().asUnsized();
+        MOZ_ASSERT(temp != scratch);
+        movePtr(imm, scratch);
+        const ARMFPRegister scratchDouble = temps.AcquireD();
+        Ldr(scratchDouble, MemOperand(Address(scratch, 0)));
+        fmul(ARMFPRegister(dest, 64), ARMFPRegister(dest, 64), scratchDouble);
+    }
+
     template <typename T>
     void branchAdd32(Condition cond, T src, Register dest, Label* label) {
         adds32(src, dest);
         branch(cond, label);
     }
 
     template <typename T>
     void branchSub32(Condition cond, T src, Register dest, Label* label) {
--- a/js/src/jit/mips-shared/LIR-mips-shared.h
+++ b/js/src/jit/mips-shared/LIR-mips-shared.h
@@ -279,29 +279,12 @@ class LAsmJSLoadFuncPtr : public LInstru
     const MAsmJSLoadFuncPtr* mir() const {
         return mir_->toAsmJSLoadFuncPtr();
     }
     const LAllocation* index() {
         return getOperand(0);
     }
 };
 
-// Math.random().
-class LRandom : public LCallInstructionHelper<1, 0, 2>
-{
-  public:
-    LIR_HEADER(Random)
-    LRandom(const LDefinition& temp, const LDefinition& temp2) {
-        setTemp(0, temp);
-        setTemp(1, temp2);
-    }
-    const LDefinition* temp() {
-        return getTemp(0);
-    }
-    const LDefinition* temp2() {
-        return getTemp(1);
-    }
-};
-
 } // namespace jit
 } // namespace js
 
 #endif /* jit_mips_shared_LIR_mips_shared_h */
--- a/js/src/jit/mips-shared/Lowering-mips-shared.cpp
+++ b/js/src/jit/mips-shared/Lowering-mips-shared.cpp
@@ -410,11 +410,15 @@ void
 LIRGeneratorMIPSShared::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins)
 {
     MOZ_CRASH("NYI");
 }
 
 void
 LIRGeneratorMIPSShared::visitRandom(MRandom* ins)
 {
-    LRandom* lir = new(alloc()) LRandom(tempFixed(CallTempReg0), tempFixed(CallTempReg1));
-    defineReturn(lir, ins);
+    LRandom *lir = new(alloc()) LRandom(temp(),
+                                        temp(),
+                                        temp(),
+                                        temp(),
+                                        temp());
+    defineFixed(lir, ins, LFloatReg(ReturnDoubleReg));
 }
--- a/js/src/jit/mips32/CodeGenerator-mips32.cpp
+++ b/js/src/jit/mips32/CodeGenerator-mips32.cpp
@@ -5,17 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jit/mips32/CodeGenerator-mips32.h"
 
 #include "mozilla/MathAlgorithms.h"
 
 #include "jscntxt.h"
 #include "jscompartment.h"
-#include "jsmath.h"
 #include "jsnum.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"
@@ -2115,21 +2114,15 @@ CodeGeneratorMIPS::visitNegF(LNegF* ins)
 {
     FloatRegister input = ToFloatRegister(ins->input());
     FloatRegister output = ToFloatRegister(ins->output());
 
     masm.as_negs(output, input);
 }
 
 void
-CodeGeneratorMIPS::visitRandom(LRandom* ins)
+CodeGeneratorMIPS::setReturnDoubleRegs(LiveRegisterSet* regs)
 {
-    Register temp = ToRegister(ins->temp());
-    Register temp2 = ToRegister(ins->temp2());
-
-    masm.loadJSContext(temp);
-
-    masm.setupUnalignedABICall(temp2);
-    masm.passABIArg(temp);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, math_random_no_outparam), MoveOp::DOUBLE);
-
-    MOZ_ASSERT(ToFloatRegister(ins->output()) == ReturnDoubleReg);
+    MOZ_ASSERT(ReturnFloat32Reg.code_ == ReturnDoubleReg.code_);
+    regs->add(ReturnFloat32Reg);
+    regs->add(ReturnDoubleReg.singleOverlay(1));
+    regs->add(ReturnDoubleReg);
 }
--- a/js/src/jit/mips32/CodeGenerator-mips32.h
+++ b/js/src/jit/mips32/CodeGenerator-mips32.h
@@ -236,17 +236,17 @@ class CodeGeneratorMIPS : public CodeGen
     void visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar* ins);
     void visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr* ins);
     void visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc* ins);
 
     void visitAsmJSPassStackArg(LAsmJSPassStackArg* ins);
 
     void generateInvalidateEpilogue();
 
-    void visitRandom(LRandom* ins);
+    void setReturnDoubleRegs(LiveRegisterSet* regs);
 
   protected:
     void visitEffectiveAddress(LEffectiveAddress* ins);
     void visitUDivOrMod(LUDivOrMod* ins);
 
   public:
     // Unimplemented SIMD instructions
     void visitSimdSplatX4(LSimdSplatX4* lir) { MOZ_CRASH("NYI"); }
--- a/js/src/jit/mips32/Lowering-mips32.cpp
+++ b/js/src/jit/mips32/Lowering-mips32.cpp
@@ -168,8 +168,19 @@ LIRGeneratorMIPS::lowerTruncateDToInt32(
 void
 LIRGeneratorMIPS::lowerTruncateFToInt32(MTruncateToInt32* ins)
 {
     MDefinition* opd = ins->input();
     MOZ_ASSERT(opd->type() == MIRType_Float32);
 
     define(new(alloc()) LTruncateFToInt32(useRegister(opd), LDefinition::BogusTemp()), ins);
 }
+
+void
+LIRGeneratorMIPS::visitRandom(MRandom* ins)
+{
+    LRandom *lir = new(alloc()) LRandom(temp(),
+                                        temp(),
+                                        temp(),
+                                        temp(),
+                                        temp());
+    defineFixed(lir, ins, LFloatReg(ReturnDoubleReg));
+}
--- a/js/src/jit/mips32/MacroAssembler-mips32-inl.h
+++ b/js/src/jit/mips32/MacroAssembler-mips32-inl.h
@@ -57,16 +57,23 @@ MacroAssembler::andPtr(Register src, Reg
 
 void
 MacroAssembler::andPtr(Imm32 imm, Register dest)
 {
     ma_and(dest, imm);
 }
 
 void
+MacroAssembler::and64(Imm64 imm, Register64 dest)
+{
+    and32(Imm32(imm.value & LOW_32_MASK), dest.low);
+    and32(Imm32((imm.value >> 32) & LOW_32_MASK), dest.high);
+}
+
+void
 MacroAssembler::or32(Register src, Register dest)
 {
     ma_or(dest, src);
 }
 
 void
 MacroAssembler::or32(Imm32 imm, Register dest)
 {
@@ -89,16 +96,23 @@ MacroAssembler::orPtr(Register src, Regi
 
 void
 MacroAssembler::orPtr(Imm32 imm, Register dest)
 {
     ma_or(dest, imm);
 }
 
 void
+MacroAssembler::or64(Register64 src, Register64 dest)
+{
+    or32(src.low, dest.low);
+    or32(src.high, dest.high);
+}
+
+void
 MacroAssembler::xor32(Imm32 imm, Register dest)
 {
     ma_xor(dest, imm);
 }
 
 void
 MacroAssembler::xorPtr(Register src, Register dest)
 {
--- a/js/src/jit/mips32/MacroAssembler-mips32.cpp
+++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp
@@ -73,16 +73,73 @@ MacroAssemblerMIPSCompat::convertUInt32T
     as_cvtdw(dest, dest);
 
     // Add unsigned value of INT32_MIN
     ma_lid(SecondScratchDoubleReg, 2147483648.0);
     as_addd(dest, dest, SecondScratchDoubleReg);
 }
 
 void
+MacroAssemblerMIPSCompat::mul64(Imm64 imm, const Register64& dest)
+{
+    // LOW32  = LOW(LOW(dest) * LOW(imm));
+    // HIGH32 = LOW(HIGH(dest) * LOW(imm)) [multiply imm into upper bits]
+    //        + LOW(LOW(dest) * HIGH(imm)) [multiply dest into upper bits]
+    //        + HIGH(LOW(dest) * LOW(imm)) [carry]
+
+    // HIGH(dest) = LOW(HIGH(dest) * LOW(imm));
+    ma_li(ScratchRegister, Imm32(imm.value & LOW_32_MASK));
+    as_multu(dest.high, ScratchRegister);
+    as_mflo(dest.high);
+
+    // mfhi:mflo = LOW(dest) * LOW(imm);
+    as_multu(dest.low, ScratchRegister);
+
+    // HIGH(dest) += mfhi;
+    as_mfhi(ScratchRegister);
+    as_addu(dest.high, dest.high, ScratchRegister);
+
+    if (((imm.value >> 32) & LOW_32_MASK) == 5) {
+        // Optimized case for Math.random().
+
+        // HIGH(dest) += LOW(LOW(dest) * HIGH(imm));
+        as_sll(ScratchRegister, dest.low, 2);
+        as_addu(ScratchRegister, ScratchRegister, dest.low);
+        as_addu(dest.high, dest.high, ScratchRegister);
+
+        // LOW(dest) = mflo;
+        as_mflo(dest.low);
+    } else {
+        // tmp = mflo
+        as_mflo(SecondScratchReg);
+
+        // HIGH(dest) += LOW(LOW(dest) * HIGH(imm));
+        ma_li(ScratchRegister, Imm32((imm.value >> 32) & LOW_32_MASK));
+        as_multu(dest.low, ScratchRegister);
+        as_mflo(ScratchRegister);
+        as_addu(dest.high, dest.high, ScratchRegister);
+
+        // LOW(dest) = tmp;
+        ma_move(dest.low, SecondScratchReg);
+    }
+}
+
+static const double TO_DOUBLE_HIGH_SCALE = 0x100000000;
+
+void
+MacroAssemblerMIPSCompat::convertUInt64ToDouble(Register64 src, Register temp, FloatRegister dest)
+{
+    convertUInt32ToDouble(src.high, dest);
+    loadConstantDouble(TO_DOUBLE_HIGH_SCALE, ScratchDoubleReg);
+    mulDouble(ScratchDoubleReg, dest);
+    convertUInt32ToDouble(src.low, ScratchDoubleReg);
+    addDouble(ScratchDoubleReg, dest);
+}
+
+void
 MacroAssemblerMIPSCompat::convertUInt32ToFloat32(Register src, FloatRegister dest)
 {
     Label positive, done;
     ma_b(src, src, &positive, NotSigned, ShortJump);
 
     // We cannot do the same as convertUInt32ToDouble because float32 doesn't
     // have enough precision.
     convertUInt32ToDouble(src, dest);
@@ -2553,16 +2610,30 @@ MacroAssemblerMIPSCompat::branchTestDoub
 
 void
 MacroAssemblerMIPSCompat::branchTestBooleanTruthy(bool b, const ValueOperand& operand,
                                                   Label* label)
 {
     ma_b(operand.payloadReg(), operand.payloadReg(), label, b ? NonZero : Zero);
 }
 
+void
+MacroAssemblerMIPSCompat::branchTest64(Condition cond, Register64 lhs, Register64 rhs,
+                                       Register temp, Label* label)
+{
+    if (cond == Assembler::Zero) {
+        MOZ_ASSERT(lhs.low == rhs.low);
+        MOZ_ASSERT(lhs.high == rhs.high);
+        as_or(ScratchRegister, lhs.low, lhs.high);
+        branchTestPtr(cond, ScratchRegister, ScratchRegister, label);
+    } else {
+        MOZ_CRASH("Unsupported condition");
+    }
+}
+
 Register
 MacroAssemblerMIPSCompat::extractObject(const Address& address, Register scratch)
 {
     ma_lw(scratch, Address(address.base, address.offset + PAYLOAD_OFFSET));
     return scratch;
 }
 
 Register
--- a/js/src/jit/mips32/MacroAssembler-mips32.h
+++ b/js/src/jit/mips32/MacroAssembler-mips32.h
@@ -60,16 +60,20 @@ struct ImmType : public ImmTag
 
 static const ValueOperand JSReturnOperand = ValueOperand(JSReturnReg_Type, JSReturnReg_Data);
 static const ValueOperand softfpReturnOperand = ValueOperand(v1, v0);
 
 static Register CallReg = t9;
 static const int defaultShift = 3;
 static_assert(1 << defaultShift == sizeof(JS::Value), "The defaultShift is wrong");
 
+static const uint32_t LOW_32_MASK = (1LL << 32) - 1;
+static const int32_t LOW_32_OFFSET = 0;
+static const int32_t HIGH_32_OFFSET = 4;
+
 class MacroAssemblerMIPS : public Assembler
 {
   protected:
     // Perform a downcast. Should be removed by Bug 996602.
     MacroAssembler& asMasm();
     const MacroAssembler& asMasm() const;
 
     void branchWithCode(InstImm code, Label* label, JumpKind jumpKind);
@@ -671,16 +675,18 @@ class MacroAssemblerMIPSCompat : public 
     void branchTestPtr(Condition cond, Register lhs, const Imm32 rhs, Label* label) {
         ma_li(ScratchRegister, rhs);
         branchTestPtr(cond, lhs, ScratchRegister, label);
     }
     void branchTestPtr(Condition cond, const Address& lhs, Imm32 imm, Label* label) {
         loadPtr(lhs, SecondScratchReg);
         branchTestPtr(cond, SecondScratchReg, imm, label);
     }
+    void branchTest64(Condition cond, Register64 lhs, Register64 rhs, Register temp,
+                      Label* label);
     void branchPtr(Condition cond, Register lhs, Register rhs, Label* label) {
         ma_b(lhs, rhs, label, cond);
     }
     void branchPtr(Condition cond, Register lhs, ImmGCPtr ptr, Label* label) {
         ma_b(lhs, ptr, label, cond);
     }
     void branchPtr(Condition cond, Register lhs, ImmWord imm, Label* label) {
         ma_b(lhs, imm, label, cond);
@@ -1096,16 +1102,21 @@ class MacroAssemblerMIPSCompat : public 
     template <typename T, typename S>
     void atomicXor32(const T& value, const S& mem) {
         MOZ_CRASH("NYI");
     }
 
     void add32(Register src, Register dest);
     void add32(Imm32 imm, Register dest);
     void add32(Imm32 imm, const Address& dest);
+    void add64(Imm32 imm, Register64 dest) {
+        as_addiu(dest.low, dest.low, imm.value);
+        as_sltiu(ScratchRegister, dest.low, imm.value);
+        as_addu(dest.high, dest.high, ScratchRegister);
+    }
     void sub32(Imm32 imm, Register dest);
     void sub32(Register src, Register dest);
 
     void incrementInt32Value(const Address& addr) {
         add32(Imm32(1), ToPayload(addr));
     }
 
     template <typename T>
@@ -1135,16 +1146,20 @@ class MacroAssemblerMIPSCompat : public 
     }
 
     void addPtr(Register src, Register dest);
     void subPtr(Register src, Register dest);
     void addPtr(const Address& src, Register dest);
 
     void move32(Imm32 imm, Register dest);
     void move32(Register src, Register dest);
+    void move64(Register64 src, Register64 dest) {
+        move32(src.low, dest.low);
+        move32(src.high, dest.high);
+    }
 
     void movePtr(Register src, Register dest);
     void movePtr(ImmWord imm, Register dest);
     void movePtr(ImmPtr imm, Register dest);
     void movePtr(AsmJSImmPtr imm, Register dest);
     void movePtr(ImmGCPtr imm, Register dest);
 
     void load8SignExtend(const Address& address, Register dest);
@@ -1158,16 +1173,20 @@ class MacroAssemblerMIPSCompat : public 
 
     void load16ZeroExtend(const Address& address, Register dest);
     void load16ZeroExtend(const BaseIndex& src, Register dest);
 
     void load32(const Address& address, Register dest);
     void load32(const BaseIndex& address, Register dest);
     void load32(AbsoluteAddress address, Register dest);
     void load32(AsmJSAbsoluteAddress address, Register dest);
+    void load64(const Address& address, Register64 dest) {
+        load32(Address(address.base, address.offset + LOW_32_OFFSET), dest.low);
+        load32(Address(address.base, address.offset + HIGH_32_OFFSET), dest.high);
+    }
 
     void loadPtr(const Address& address, Register dest);
     void loadPtr(const BaseIndex& src, Register dest);
     void loadPtr(AbsoluteAddress address, Register dest);
     void loadPtr(AsmJSAbsoluteAddress address, Register dest);
 
     void loadPrivate(const Address& address, Register dest);
 
@@ -1228,16 +1247,21 @@ class MacroAssemblerMIPSCompat : public 
     void store32(Imm32 src, const BaseIndex& address);
 
     // NOTE: This will use second scratch on MIPS. Only ARM needs the
     // implementation without second scratch.
     void store32_NoSecondScratch(Imm32 src, const Address& address) {
         store32(src, address);
     }
 
+    void store64(Register64 src, Address address) {
+        store32(src.low, Address(address.base, address.offset + LOW_32_OFFSET));
+        store32(src.high, Address(address.base, address.offset + HIGH_32_OFFSET));
+    }
+
     template <typename T> void storePtr(ImmWord imm, T address);
     template <typename T> void storePtr(ImmPtr imm, T address);
     template <typename T> void storePtr(ImmGCPtr imm, T address);
     void storePtr(Register src, const Address& address);
     void storePtr(Register src, const BaseIndex& address);
     void storePtr(Register src, AbsoluteAddress dest);
     void storeDouble(FloatRegister src, Address addr) {
         ma_sd(src, addr);
@@ -1297,16 +1321,25 @@ class MacroAssemblerMIPSCompat : public 
     void addPtr(ImmPtr imm, const Register dest) {
         addPtr(ImmWord(uintptr_t(imm.value)), dest);
     }
     void mulBy3(const Register& src, const Register& dest) {
         as_addu(dest, src, src);
         as_addu(dest, dest, src);
     }
 
+    void mul64(Imm64 imm, const Register64& dest);
+
+    void convertUInt64ToDouble(Register64 src, Register temp, FloatRegister dest);
+    void mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest) {
+        movePtr(imm, ScratchRegister);
+        loadDouble(Address(ScratchRegister, 0), ScratchDoubleReg);
+        mulDouble(ScratchDoubleReg, dest);
+    }
+
     void breakpoint();
 
     void branchDouble(DoubleCondition cond, FloatRegister lhs, FloatRegister rhs,
                       Label* label);
 
     void branchFloat(DoubleCondition cond, FloatRegister lhs, FloatRegister rhs,
                      Label* label);
 
@@ -1317,19 +1350,31 @@ class MacroAssemblerMIPSCompat : public 
     static void calculateAlignedStackPointer(void** stackPointer);
 
     void rshiftPtr(Imm32 imm, Register dest) {
         ma_srl(dest, dest, imm);
     }
     void rshiftPtrArithmetic(Imm32 imm, Register dest) {
         ma_sra(dest, dest, imm);
     }
+    void rshift64(Imm32 imm, Register64 dest) {
+        as_srl(dest.low, dest.low, imm.value);
+        as_sll(ScratchRegister, dest.high, 32 - imm.value);
+        as_or(dest.low, dest.low, ScratchRegister);
+        as_srl(dest.high, dest.high, imm.value);
+    }
     void lshiftPtr(Imm32 imm, Register dest) {
         ma_sll(dest, dest, imm);
     }
+    void lshift64(Imm32 imm, Register64 dest) {
+        as_sll(dest.high, dest.high, imm.value);
+        as_srl(ScratchRegister, dest.low, 32 - imm.value);
+        as_or(dest.high, dest.high, ScratchRegister);
+        as_sll(dest.low, dest.low, imm.value);
+    }
 
     // If source is a double, load it into dest. If source is int32,
     // convert it to double. Else, branch to failure.
     void ensureDouble(const ValueOperand& source, FloatRegister dest, Label* failure);
 
     template <typename T1, typename T2>
     void cmpPtrSet(Assembler::Condition cond, T1 lhs, T2 rhs, Register dest)
     {
--- a/js/src/jit/none/CodeGenerator-none.h
+++ b/js/src/jit/none/CodeGenerator-none.h
@@ -46,16 +46,17 @@ class CodeGeneratorNone : public CodeGen
     void testZeroEmitBranch(Assembler::Condition, Register, MBasicBlock*, MBasicBlock*) {
         MOZ_CRASH();
     }
     void emitTableSwitchDispatch(MTableSwitch*, Register, Register) { MOZ_CRASH(); }
     ValueOperand ToValue(LInstruction*, size_t) { MOZ_CRASH(); }
     ValueOperand ToOutValue(LInstruction*) { MOZ_CRASH(); }
     ValueOperand ToTempValue(LInstruction*, size_t) { MOZ_CRASH(); }
     void generateInvalidateEpilogue() { MOZ_CRASH(); }
+    void setReturnDoubleRegs(LiveRegisterSet* regs) { MOZ_CRASH(); }
 };
 
 typedef CodeGeneratorNone CodeGeneratorSpecific;
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_none_CodeGenerator_none_h */
--- a/js/src/jit/none/LIR-none.h
+++ b/js/src/jit/none/LIR-none.h
@@ -107,14 +107,13 @@ class LModPowTwoI : public LInstructionH
     int32_t shift() { MOZ_CRASH(); }
     LModPowTwoI(const LAllocation& lhs, int32_t shift) { MOZ_CRASH(); }
     MMod* mir() const { MOZ_CRASH(); }
 };
 
 class LGuardShape : public LInstruction {};
 class LGuardObjectGroup : public LInstruction {};
 class LMulI : public LInstruction {};
-class LRandom : public LInstructionHelper<1, 0, 5> {};
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_none_LIR_none_h */
--- a/js/src/jit/none/Lowering-none.h
+++ b/js/src/jit/none/Lowering-none.h
@@ -82,17 +82,16 @@ class LIRGeneratorNone : public LIRGener
 
     LTableSwitch* newLTableSwitch(LAllocation, LDefinition, MTableSwitch*) { MOZ_CRASH(); }
     LTableSwitchV* newLTableSwitchV(MTableSwitch*) { MOZ_CRASH(); }
     void visitSimdSelect(MSimdSelect* ins) { MOZ_CRASH(); }
     void visitSimdSplatX4(MSimdSplatX4* ins) { MOZ_CRASH(); }
     void visitSimdValueX4(MSimdValueX4* lir) { MOZ_CRASH(); }
     void visitSubstr(MSubstr*) { MOZ_CRASH(); }
     void visitSimdBinaryArith(js::jit::MSimdBinaryArith*) { MOZ_CRASH(); }
-    void visitRandom(MRandom* ) { MOZ_CRASH(); }
 
 };
 
 typedef LIRGeneratorNone LIRGeneratorSpecific;
 
 } // namespace jit
 } // namespace js
 
--- a/js/src/jit/shared/Assembler-shared.h
+++ b/js/src/jit/shared/Assembler-shared.h
@@ -120,16 +120,25 @@ struct Imm32
 struct ImmWord
 {
     uintptr_t value;
 
     explicit ImmWord(uintptr_t value) : value(value)
     { }
 };
 
+// Used for 64-bit immediates which do not require relocation.
+struct Imm64
+{
+    uint64_t value;
+
+    explicit Imm64(uint64_t value) : value(value)
+    { }
+};
+
 #ifdef DEBUG
 static inline bool
 IsCompilingAsmJS()
 {
     // asm.js compilation pushes a JitContext with a null JSCompartment.
     JitContext* jctx = MaybeGetJitContext();
     return jctx && jctx->compartment == nullptr;
 }
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -7171,12 +7171,63 @@ class LArrowNewTarget : public LInstruct
 
     LIR_HEADER(ArrowNewTarget)
 
     const LAllocation* callee() {
         return getOperand(0);
     }
 };
 
+// Math.random().
+#ifdef JS_PUNBOX64
+# define LRANDOM_NUM_TEMPS 3
+#else
+# define LRANDOM_NUM_TEMPS 5
+#endif
+
+class LRandom : public LInstructionHelper<1, 0, LRANDOM_NUM_TEMPS>
+{
+  public:
+    LIR_HEADER(Random)
+    LRandom(const LDefinition &tempMaybeEAX, const LDefinition &tempMaybeEDX,
+            const LDefinition &temp1
+#ifndef JS_PUNBOX64
+            , const LDefinition &temp2, const LDefinition &temp3
+#endif
+            )
+    {
+        setTemp(0, tempMaybeEAX);
+        setTemp(1, tempMaybeEDX);
+        setTemp(2, temp1);
+#ifndef JS_PUNBOX64
+        setTemp(3, temp2);
+        setTemp(4, temp3);
+#endif
+    }
+    // On x86, following 2 methods return eax and edx necessary for mull.
+    // On others, following 2 methods return ordinary temporary registers.
+    const LDefinition* tempMaybeEAX() {
+        return getTemp(0);
+    }
+    const LDefinition* tempMaybeEDX() {
+        return getTemp(1);
+    }
+    const LDefinition *temp1() {
+        return getTemp(2);
+    }
+#ifndef JS_PUNBOX64
+    const LDefinition *temp2() {
+        return getTemp(3);
+    }
+    const LDefinition *temp3() {
+        return getTemp(4);
+    }
+#endif
+
+    MRandom* mir() const {
+        return mir_->toRandom();
+    }
+};
+
 } // namespace jit
 } // namespace js
 
 #endif /* jit_shared_LIR_shared_h */
--- a/js/src/jit/x64/CodeGenerator-x64.cpp
+++ b/js/src/jit/x64/CodeGenerator-x64.cpp
@@ -836,134 +836,8 @@ CodeGeneratorX64::visitTruncateFToInt32(
     FloatRegister input = ToFloatRegister(ins->input());
     Register output = ToRegister(ins->output());
 
     // On x64, branchTruncateFloat32 uses vcvttss2sq. Unlike the x86
     // implementation, this should handle most floats and we can just
     // call a stub if it fails.
     emitTruncateFloat32(input, output, ins->mir());
 }
-
-namespace js {
-namespace jit {
-
-// Out-of-line math_random_no_outparam call for LRandom.
-class OutOfLineRandom : public OutOfLineCodeBase<CodeGeneratorX64>
-{
-    LRandom* lir_;
-
-  public:
-    explicit OutOfLineRandom(LRandom* lir)
-      : lir_(lir)
-    { }
-
-    void accept(CodeGeneratorX64* codegen) {
-        codegen->visitOutOfLineRandom(this);
-    }
-
-    LRandom* lir() const {
-        return lir_;
-    }
-};
-
-} // namespace jit
-} // namespace js
-
-static const double RNG_DSCALE_INV = 1 / RNG_DSCALE;
-
-void
-CodeGeneratorX64::visitRandom(LRandom* ins)
-{
-    FloatRegister output = ToFloatRegister(ins->output());
-
-    Register JSCompartmentReg = ToRegister(ins->temp());
-    Register rngStateReg = ToRegister(ins->temp2());
-    Register highReg = ToRegister(ins->temp3());
-    Register lowReg = ToRegister(ins->temp4());
-    Register rngMaskReg = ToRegister(ins->temp5());
-
-    // rngState = cx->compartment()->rngState
-    masm.loadJSContext(JSCompartmentReg);
-    masm.loadPtr(Address(JSCompartmentReg, JSContext::offsetOfCompartment()), JSCompartmentReg);
-    masm.loadPtr(Address(JSCompartmentReg, JSCompartment::offsetOfRngState()), rngStateReg);
-
-    // if rngState == 0, escape from inlined code and call
-    // math_random_no_outparam.
-    OutOfLineRandom* ool = new(alloc()) OutOfLineRandom(ins);
-    addOutOfLineCode(ool, ins->mir());
-    masm.branchTestPtr(Assembler::Zero, rngStateReg, rngStateReg, ool->entry());
-
-    // nextstate = rngState * RNG_MULTIPLIER;
-    Register& rngMultiplierReg = lowReg;
-    masm.movq(ImmWord(RNG_MULTIPLIER), rngMultiplierReg);
-    masm.imulq(rngMultiplierReg, rngStateReg);
-
-    // nextstate += RNG_ADDEND;
-    masm.addq(Imm32(RNG_ADDEND), rngStateReg);
-
-    // nextstate &= RNG_MASK;
-    masm.movq(ImmWord(RNG_MASK), rngMaskReg);
-    masm.andq(rngMaskReg, rngStateReg);
-
-    // rngState = nextstate
-
-    // if rngState == 0, escape from inlined code and call
-    // math_random_no_outparam.
-    masm.j(Assembler::Zero, ool->entry());
-
-    // high = (nextstate >> (RNG_STATE_WIDTH - RNG_HIGH_BITS)) << RNG_LOW_BITS;
-    masm.movq(rngStateReg, highReg);
-    masm.shrq(Imm32(RNG_STATE_WIDTH - RNG_HIGH_BITS), highReg);
-    masm.shlq(Imm32(RNG_LOW_BITS), highReg);
-
-    // nextstate = rngState * RNG_MULTIPLIER;
-    masm.imulq(rngMultiplierReg, rngStateReg);
-
-    // nextstate += RNG_ADDEND;
-    masm.addq(Imm32(RNG_ADDEND), rngStateReg);
-
-    // nextstate &= RNG_MASK;
-    masm.andq(rngMaskReg, rngStateReg);
-
-    // low = nextstate >> (RNG_STATE_WIDTH - RNG_LOW_BITS);
-    masm.movq(rngStateReg, lowReg);
-    masm.shrq(Imm32(RNG_STATE_WIDTH - RNG_LOW_BITS), lowReg);
-
-    // output = double(high | low);
-    masm.orq(highReg, lowReg);
-    masm.vcvtsi2sdq(lowReg, output);
-
-    // output = output * RNG_DSCALE_INV;
-    Register& rngDscaleInvReg = lowReg;
-    masm.movq(ImmPtr(&RNG_DSCALE_INV), rngDscaleInvReg);
-    masm.vmulsd(Operand(rngDscaleInvReg, 0), output, output);
-
-    // cx->compartment()->rngState = nextstate
-    masm.storePtr(rngStateReg, Address(JSCompartmentReg, JSCompartment::offsetOfRngState()));
-
-    masm.bind(ool->rejoin());
-}
-
-void
-CodeGeneratorX64::visitOutOfLineRandom(OutOfLineRandom* ool)
-{
-    LRandom* ins = ool->lir();
-    Register temp = ToRegister(ins->temp());
-    Register temp2 = ToRegister(ins->temp2());
-    MOZ_ASSERT(ToFloatRegister(ins->output()) == ReturnDoubleReg);
-
-    LiveRegisterSet regs;
-    regs.add(ReturnFloat32Reg);
-    regs.add(ReturnDoubleReg);
-    regs.add(ReturnInt32x4Reg);
-    regs.add(ReturnFloat32x4Reg);
-    saveVolatile(regs);
-
-    masm.loadJSContext(temp);
-
-    masm.setupUnalignedABICall(temp2);
-    masm.passABIArg(temp);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, math_random_no_outparam), MoveOp::DOUBLE);
-
-    restoreVolatile(regs);
-
-    masm.jump(ool->rejoin());
-}
--- a/js/src/jit/x64/CodeGenerator-x64.h
+++ b/js/src/jit/x64/CodeGenerator-x64.h
@@ -7,18 +7,16 @@
 #ifndef jit_x64_CodeGenerator_x64_h
 #define jit_x64_CodeGenerator_x64_h
 
 #include "jit/x86-shared/CodeGenerator-x86-shared.h"
 
 namespace js {
 namespace jit {
 
-class OutOfLineRandom;
-
 class CodeGeneratorX64 : public CodeGeneratorX86Shared
 {
     CodeGeneratorX64* thisFromCtor() {
         return this;
     }
 
   protected:
     ValueOperand ToValue(LInstruction* ins, size_t pos);
@@ -56,18 +54,16 @@ class CodeGeneratorX64 : public CodeGene
     void visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap* ins);
     void visitAsmJSAtomicBinopHeapForEffect(LAsmJSAtomicBinopHeapForEffect* ins);
     void visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar* ins);
     void visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar* ins);
     void visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr* ins);
     void visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc* ins);
     void visitAsmJSUInt32ToDouble(LAsmJSUInt32ToDouble* lir);
     void visitAsmJSUInt32ToFloat32(LAsmJSUInt32ToFloat32* lir);
-    void visitRandom(LRandom* ins);
-    void visitOutOfLineRandom(OutOfLineRandom* ool);
 };
 
 typedef CodeGeneratorX64 CodeGeneratorSpecific;
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_x64_CodeGenerator_x64_h */
--- a/js/src/jit/x64/LIR-x64.h
+++ b/js/src/jit/x64/LIR-x64.h
@@ -94,47 +94,12 @@ class LAsmJSLoadFuncPtr : public LInstru
     const LAllocation* index() {
         return getOperand(0);
     }
     const LDefinition* temp() {
         return getTemp(0);
     }
 };
 
-// Math.random().
-class LRandom : public LInstructionHelper<1, 0, 5>
-{
-  public:
-    LIR_HEADER(Random)
-    LRandom(const LDefinition &temp, const LDefinition &temp2, const LDefinition &temp3,
-            const LDefinition &temp4, const LDefinition &temp5)
-    {
-        setTemp(0, temp);
-        setTemp(1, temp2);
-        setTemp(2, temp3);
-        setTemp(3, temp4);
-        setTemp(4, temp5);
-    }
-    const LDefinition* temp() {
-        return getTemp(0);
-    }
-    const LDefinition* temp2() {
-        return getTemp(1);
-    }
-    const LDefinition *temp3() {
-        return getTemp(2);
-    }
-    const LDefinition *temp4() {
-        return getTemp(3);
-    }
-    const LDefinition *temp5() {
-        return getTemp(4);
-    }
-
-    MRandom* mir() const {
-        return mir_->toRandom();
-    }
-};
-
 } // namespace jit
 } // namespace js
 
 #endif /* jit_x64_LIR_x64_h */
--- a/js/src/jit/x64/Lowering-x64.cpp
+++ b/js/src/jit/x64/Lowering-x64.cpp
@@ -333,13 +333,11 @@ LIRGeneratorX64::visitStoreTypedArrayEle
     MOZ_CRASH("NYI");
 }
 
 void
 LIRGeneratorX64::visitRandom(MRandom* ins)
 {
     LRandom *lir = new(alloc()) LRandom(temp(),
                                         temp(),
-                                        temp(),
-                                        temp(),
                                         temp());
     defineFixed(lir, ins, LFloatReg(ReturnDoubleReg));
 }
--- a/js/src/jit/x64/MacroAssembler-x64-inl.h
+++ b/js/src/jit/x64/MacroAssembler-x64-inl.h
@@ -25,28 +25,41 @@ MacroAssembler::andPtr(Register src, Reg
 
 void
 MacroAssembler::andPtr(Imm32 imm, Register dest)
 {
     andq(imm, dest);
 }
 
 void
+MacroAssembler::and64(Imm64 imm, Register64 dest)
+{
+    movq(ImmWord(uintptr_t(imm.value)), ScratchReg);
+    andq(ScratchReg, dest.reg);
+}
+
+void
 MacroAssembler::orPtr(Register src, Register dest)
 {
     orq(src, dest);
 }
 
 void
 MacroAssembler::orPtr(Imm32 imm, Register dest)
 {
     orq(imm, dest);
 }
 
 void
+MacroAssembler::or64(Register64 src, Register64 dest)
+{
+    orq(src.reg, dest.reg);
+}
+
+void
 MacroAssembler::xorPtr(Register src, Register dest)
 {
     xorq(src, dest);
 }
 
 void
 MacroAssembler::xorPtr(Imm32 imm, Register dest)
 {
--- a/js/src/jit/x64/MacroAssembler-x64.h
+++ b/js/src/jit/x64/MacroAssembler-x64.h
@@ -599,31 +599,38 @@ class MacroAssemblerX64 : public MacroAs
         }
     }
     void addPtr(ImmPtr imm, Register dest) {
         addPtr(ImmWord(uintptr_t(imm.value)), dest);
     }
     void addPtr(const Address& src, Register dest) {
         addq(Operand(src), dest);
     }
+    void add64(Imm32 imm, Register64 dest) {
+        addq(imm, dest.reg);
+    }
     void subPtr(Imm32 imm, Register dest) {
         subq(imm, dest);
     }
     void subPtr(Register src, Register dest) {
         subq(src, dest);
     }
     void subPtr(const Address& addr, Register dest) {
         subq(Operand(addr), dest);
     }
     void subPtr(Register src, const Address& dest) {
         subq(src, Operand(dest));
     }
     void mulBy3(const Register& src, const Register& dest) {
         lea(Operand(src, src, TimesTwo), dest);
     }
+    void mul64(Imm64 imm, const Register64& dest) {
+        movq(ImmWord(uintptr_t(imm.value)), ScratchReg);
+        imulq(ScratchReg, dest.reg);
+    }
 
     void branch32(Condition cond, AbsoluteAddress lhs, Imm32 rhs, Label* label) {
         if (X86Encoding::IsAddressImmediate(lhs.addr)) {
             branch32(cond, Operand(lhs), rhs, label);
         } else {
             ScratchRegisterScope scratch(asMasm());
             mov(ImmPtr(lhs.addr), scratch);
             branch32(cond, Address(scratch, 0), rhs, label);
@@ -736,16 +743,20 @@ class MacroAssemblerX64 : public MacroAs
         testPtr(Operand(lhs), imm);
         j(cond, label);
     }
     void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) {
         subPtr(imm, lhs);
         j(cond, label);
     }
 
+    void branchTest64(Condition cond, Register64 lhs, Register64 rhs, Register temp, Label* label) {
+        branchTestPtr(cond, lhs.reg, rhs.reg, label);
+    }
+
     void movePtr(Register src, Register dest) {
         movq(src, dest);
     }
     void movePtr(Register src, const Operand& dest) {
         movq(src, dest);
     }
     void movePtr(ImmWord imm, Register dest) {
         mov(imm, dest);
@@ -754,16 +765,19 @@ class MacroAssemblerX64 : public MacroAs
         mov(imm, dest);
     }
     void movePtr(AsmJSImmPtr imm, Register dest) {
         mov(imm, dest);
     }
     void movePtr(ImmGCPtr imm, Register dest) {
         movq(imm, dest);
     }
+    void move64(Register64 src, Register64 dest) {
+        movq(src.reg, dest.reg);
+    }
     void loadPtr(AbsoluteAddress address, Register dest) {
         if (X86Encoding::IsAddressImmediate(address.addr)) {
             movq(Operand(address), dest);
         } else {
             ScratchRegisterScope scratch(asMasm());
             mov(ImmPtr(address.addr), scratch);
             loadPtr(Address(scratch, 0x0), dest);
         }
@@ -785,16 +799,19 @@ class MacroAssemblerX64 : public MacroAs
         if (X86Encoding::IsAddressImmediate(address.addr)) {
             movl(Operand(address), dest);
         } else {
             ScratchRegisterScope scratch(asMasm());
             mov(ImmPtr(address.addr), scratch);
             load32(Address(scratch, 0x0), dest);
         }
     }
+    void load64(const Address& address, Register64 dest) {
+        movq(Operand(address), dest.reg);
+    }
     template <typename T>
     void storePtr(ImmWord imm, T address) {
         if ((intptr_t)imm.value <= INT32_MAX && (intptr_t)imm.value >= INT32_MIN) {
             movq(Imm32((int32_t)imm.value), Operand(address));
         } else {
             ScratchRegisterScope scratch(asMasm());
             mov(imm, scratch);
             movq(scratch, Operand(address));
@@ -832,25 +849,34 @@ class MacroAssemblerX64 : public MacroAs
         if (X86Encoding::IsAddressImmediate(address.addr)) {
             movl(src, Operand(address));
         } else {
             ScratchRegisterScope scratch(asMasm());
             mov(ImmPtr(address.addr), scratch);
             store32(src, Address(scratch, 0x0));
         }
     }
+    void store64(Register64 src, Address address) {
+        movq(src.reg, Operand(address));
+    }
     void rshiftPtr(Imm32 imm, Register dest) {
         shrq(imm, dest);
     }
     void rshiftPtrArithmetic(Imm32 imm, Register dest) {
         sarq(imm, dest);
     }
+    void rshift64(Imm32 imm, Register64 dest) {
+        shrq(imm, dest.reg);
+    }
     void lshiftPtr(Imm32 imm, Register dest) {
         shlq(imm, dest);
     }
+    void lshift64(Imm32 imm, Register64 dest) {
+        shlq(imm, dest.reg);
+    }
 
     void splitTag(Register src, Register dest) {
         if (src != dest)
             movq(src, dest);
         shrq(Imm32(JSVAL_TAG_SHIFT), dest);
     }
     void splitTag(const ValueOperand& operand, Register dest) {
         splitTag(operand.valueReg(), dest);
@@ -1365,16 +1391,25 @@ class MacroAssemblerX64 : public MacroAs
     void convertUInt32ToDouble(Register src, FloatRegister dest) {
         vcvtsq2sd(src, dest, dest);
     }
 
     void convertUInt32ToFloat32(Register src, FloatRegister dest) {
         vcvtsq2ss(src, dest, dest);
     }
 
+    void convertUInt64ToDouble(Register64 src, Register temp, FloatRegister dest) {
+        vcvtsi2sdq(src.reg, dest);
+    }
+
+    void mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest) {
+        movq(imm, ScratchReg);
+        vmulsd(Operand(ScratchReg, 0), dest, dest);
+    }
+
     void inc64(AbsoluteAddress dest) {
         if (X86Encoding::IsAddressImmediate(dest.addr)) {
             addPtr(Imm32(1), Operand(dest));
         } else {
             ScratchRegisterScope scratch(asMasm());
             mov(ImmPtr(dest.addr), scratch);
             addPtr(Imm32(1), Address(scratch, 0));
         }
--- a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp
@@ -3639,10 +3639,23 @@ CodeGeneratorX86Shared::visitAtomicTyped
 
 void
 CodeGeneratorX86Shared::visitMemoryBarrier(LMemoryBarrier* ins)
 {
     if (ins->type() & MembarStoreLoad)
         masm.storeLoadFence();
 }
 
+void
+CodeGeneratorX86Shared::setReturnDoubleRegs(LiveRegisterSet* regs)
+{
+    MOZ_ASSERT(ReturnFloat32Reg.encoding() == X86Encoding::xmm0);
+    MOZ_ASSERT(ReturnDoubleReg.encoding() == X86Encoding::xmm0);
+    MOZ_ASSERT(ReturnInt32x4Reg.encoding() == X86Encoding::xmm0);
+    MOZ_ASSERT(ReturnFloat32x4Reg.encoding() == X86Encoding::xmm0);
+    regs->add(ReturnFloat32Reg);
+    regs->add(ReturnDoubleReg);
+    regs->add(ReturnInt32x4Reg);
+    regs->add(ReturnFloat32x4Reg);
+}
+
 } // namespace jit
 } // namespace js
--- a/js/src/jit/x86-shared/CodeGenerator-x86-shared.h
+++ b/js/src/jit/x86-shared/CodeGenerator-x86-shared.h
@@ -295,16 +295,18 @@ class CodeGeneratorX86Shared : public Co
     // Generating a result.
     template<typename S, typename T>
     void atomicBinopToTypedIntArray(AtomicOp op, Scalar::Type arrayType, const S& value,
                                     const T& mem, Register temp1, Register temp2, AnyRegister output);
 
     // Generating no result.
     template<typename S, typename T>
     void atomicBinopToTypedIntArray(AtomicOp op, Scalar::Type arrayType, const S& value, const T& mem);
+
+    void setReturnDoubleRegs(LiveRegisterSet* regs);
 };
 
 // An out-of-line bailout thunk.
 class OutOfLineBailout : public OutOfLineCodeBase<CodeGeneratorX86Shared>
 {
     LSnapshot* snapshot_;
 
   public:
--- a/js/src/jit/x86-shared/Encoding-x86-shared.h
+++ b/js/src/jit/x86-shared/Encoding-x86-shared.h
@@ -171,32 +171,36 @@ enum TwoByteOpcodeID {
     OP2_SQRTSD_VsdWsd   = 0x51,
     OP2_SQRTSS_VssWss   = 0x51,
     OP2_SQRTPS_VpsWps   = 0x51,
     OP2_RSQRTPS_VpsWps  = 0x52,
     OP2_RCPPS_VpsWps    = 0x53,
     OP2_ANDPD_VpdWpd    = 0x54,
     OP2_ORPD_VpdWpd     = 0x56,
     OP2_XORPD_VpdWpd    = 0x57,
+    OP2_PUNPCKLDQ       = 0x62,
     OP2_PCMPGTD_VdqWdq  = 0x66,
     OP2_MOVD_VdEd       = 0x6E,
     OP2_MOVDQ_VsdWsd    = 0x6F,
     OP2_MOVDQ_VdqWdq    = 0x6F,
     OP2_PSHUFD_VdqWdqIb = 0x70,
     OP2_PSLLD_UdqIb     = 0x72,
     OP2_PSRAD_UdqIb     = 0x72,
     OP2_PSRLD_UdqIb     = 0x72,
     OP2_PSRLDQ_Vd       = 0x73,
     OP2_PCMPEQW         = 0x75,
     OP2_PCMPEQD_VdqWdq  = 0x76,
+    OP2_HADDPD          = 0x7C,
     OP2_MOVD_EdVd       = 0x7E,
     OP2_MOVQ_VdWd       = 0x7E,
     OP2_MOVDQ_WdqVdq    = 0x7F,
     OP2_JCC_rel32       = 0x80,
     OP_SETCC            = 0x90,
+    OP2_SHLD            = 0xA4,
+    OP2_SHRD            = 0xAC,
     OP_FENCE            = 0xAE,
     OP2_IMUL_GvEv       = 0xAF,
     OP2_CMPXCHG_GvEb    = 0xB0,
     OP2_CMPXCHG_GvEw    = 0xB1,
     OP2_BSR_GvEv        = 0xBD,
     OP2_MOVSX_GvEb      = 0xBE,
     OP2_MOVSX_GvEw      = 0xBF,
     OP2_MOVZX_GvEb      = 0xB6,
--- a/js/src/jit/x86/Assembler-x86.h
+++ b/js/src/jit/x86/Assembler-x86.h
@@ -46,16 +46,17 @@ static MOZ_CONSTEXPR_VAR Register FrameP
 static MOZ_CONSTEXPR_VAR Register ReturnReg = eax;
 static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloat32Reg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Single);
 static MOZ_CONSTEXPR_VAR FloatRegister ReturnDoubleReg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Double);
 static MOZ_CONSTEXPR_VAR FloatRegister ReturnInt32x4Reg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Int32x4);
 static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloat32x4Reg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Float32x4);
 static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloat32Reg = FloatRegister(X86Encoding::xmm7, FloatRegisters::Single);
 static MOZ_CONSTEXPR_VAR FloatRegister ScratchDoubleReg = FloatRegister(X86Encoding::xmm7, FloatRegisters::Double);
 static MOZ_CONSTEXPR_VAR FloatRegister ScratchSimdReg = xmm7;
+static MOZ_CONSTEXPR_VAR FloatRegister ScratchInt32x4Reg = FloatRegister(X86Encoding::xmm7, FloatRegisters::Int32x4);
 
 // Avoid ebp, which is the FramePointer, which is unavailable in some modes.
 static MOZ_CONSTEXPR_VAR Register ArgumentsRectifierReg = esi;
 static MOZ_CONSTEXPR_VAR Register CallTempReg0 = edi;
 static MOZ_CONSTEXPR_VAR Register CallTempReg1 = eax;
 static MOZ_CONSTEXPR_VAR Register CallTempReg2 = ebx;
 static MOZ_CONSTEXPR_VAR Register CallTempReg3 = ecx;
 static MOZ_CONSTEXPR_VAR Register CallTempReg4 = esi;
@@ -370,16 +371,76 @@ class Assembler : public AssemblerX86Sha
         masm.cmpl_rm_disp32(rhs.encoding(), (void*)-1);
         append(AsmJSAbsoluteLink(CodeOffsetLabel(masm.currentOffset()), lhs.kind()));
     }
     void cmpl(Imm32 rhs, AsmJSAbsoluteAddress lhs) {
         JmpSrc src = masm.cmpl_im_disp32(rhs.value, (void*)-1);
         append(AsmJSAbsoluteLink(CodeOffsetLabel(src.offset()), lhs.kind()));
     }
 
+    void adcl(Imm32 imm, Register dest) {
+        masm.adcl_ir(imm.value, dest.encoding());
+    }
+
+    void mull(Register multiplier) {
+        masm.mull_r(multiplier.encoding());
+    }
+
+    void shldl(const Imm32 imm, Register src, Register dest) {
+        masm.shldl_irr(imm.value, src.encoding(), dest.encoding());
+    }
+    void shrdl(const Imm32 imm, Register src, Register dest) {
+        masm.shrdl_irr(imm.value, src.encoding(), dest.encoding());
+    }
+
+    void vhaddpd(FloatRegister src, FloatRegister dest) {
+        MOZ_ASSERT(HasSSE2());
+        MOZ_ASSERT(src.size() == 16);
+        MOZ_ASSERT(dest.size() == 16);
+        masm.vhaddpd_rr(src.encoding(), dest.encoding());
+    }
+    void vsubpd(const Operand& src1, FloatRegister src0, FloatRegister dest) {
+        MOZ_ASSERT(HasSSE2());
+        MOZ_ASSERT(src0.size() == 16);
+        MOZ_ASSERT(dest.size() == 16);
+        switch (src1.kind()) {
+          case Operand::MEM_REG_DISP:
+            masm.vsubpd_mr(src1.disp(), src1.base(), src0.encoding(), dest.encoding());
+            break;
+          case Operand::MEM_ADDRESS32:
+            masm.vsubpd_mr(src1.address(), src0.encoding(), dest.encoding());
+            break;
+          default:
+            MOZ_CRASH("unexpected operand kind");
+        }
+    }
+
+    void vpunpckldq(FloatRegister src1, FloatRegister src0, FloatRegister dest) {
+        MOZ_ASSERT(HasSSE2());
+        MOZ_ASSERT(src0.size() == 16);
+        MOZ_ASSERT(src1.size() == 16);
+        MOZ_ASSERT(dest.size() == 16);
+        masm.vpunpckldq_rr(src1.encoding(), src0.encoding(), dest.encoding());
+    }
+    void vpunpckldq(const Operand& src1, FloatRegister src0, FloatRegister dest) {
+        MOZ_ASSERT(HasSSE2());
+        MOZ_ASSERT(src0.size() == 16);
+        MOZ_ASSERT(dest.size() == 16);
+        switch (src1.kind()) {
+          case Operand::MEM_REG_DISP:
+            masm.vpunpckldq_mr(src1.disp(), src1.base(), src0.encoding(), dest.encoding());
+            break;
+          case Operand::MEM_ADDRESS32:
+            masm.vpunpckldq_mr(src1.address(), src0.encoding(), dest.encoding());
+            break;
+          default:
+            MOZ_CRASH("unexpected operand kind");
+        }
+    }
+
     void jmp(ImmPtr target, Relocation::Kind reloc = Relocation::HARDCODED) {
         JmpSrc src = masm.jmp();
         addPendingJump(src, target, reloc);
     }
     void j(Condition cond, ImmPtr target,
            Relocation::Kind reloc = Relocation::HARDCODED) {
         JmpSrc src = masm.jCC(static_cast<X86Encoding::Condition>(cond));
         addPendingJump(src, target, reloc);
--- a/js/src/jit/x86/BaseAssembler-x86.h
+++ b/js/src/jit/x86/BaseAssembler-x86.h
@@ -15,16 +15,24 @@ namespace jit {
 namespace X86Encoding {
 
 class BaseAssemblerX86 : public BaseAssembler
 {
   public:
 
     // Arithmetic operations:
 
+    void adcl_ir(int32_t imm, RegisterID dst)
+    {
+        spew("adcl       $%d, %s", imm, GPReg32Name(dst));
+        MOZ_ASSERT(CAN_SIGN_EXTEND_8_32(imm));
+        m_formatter.oneByteOp(OP_GROUP1_EvIb, dst, GROUP1_OP_ADC);
+        m_formatter.immediate8s(imm);
+    }
+
     void adcl_im(int32_t imm, const void* addr)
     {
         spew("adcl       %d, %p", imm, addr);
         if (CAN_SIGN_EXTEND_8_32(imm)) {
             m_formatter.oneByteOp(OP_GROUP1_EvIb, addr, GROUP1_OP_ADC);
             m_formatter.immediate8s(imm);
         } else {
             m_formatter.oneByteOp(OP_GROUP1_EvIz, addr, GROUP1_OP_ADC);
@@ -66,16 +74,32 @@ class BaseAssemblerX86 : public BaseAsse
             m_formatter.oneByteOp(OP_GROUP1_EvIb, addr, GROUP1_OP_SUB);
             m_formatter.immediate8s(imm);
         } else {
             m_formatter.oneByteOp(OP_GROUP1_EvIz, addr, GROUP1_OP_SUB);
             m_formatter.immediate32(imm);
         }
     }
 
+    void shldl_irr(int32_t imm, RegisterID src, RegisterID dst)
+    {
+        MOZ_ASSERT(imm < 32);
+        spew("shldl      $%d, %s, %s", imm, GPReg32Name(src), GPReg32Name(dst));
+        m_formatter.twoByteOp8(OP2_SHLD, dst, src);
+        m_formatter.immediate8u(imm);
+    }
+
+    void shrdl_irr(int32_t imm, RegisterID src, RegisterID dst)
+    {
+        MOZ_ASSERT(imm < 32);
+        spew("shrdl      $%d, %s, %s", imm, GPReg32Name(src), GPReg32Name(dst));
+        m_formatter.twoByteOp8(OP2_SHRD, dst, src);
+        m_formatter.immediate8u(imm);
+    }
+
     // SSE operations:
 
     using BaseAssembler::vcvtsi2sd_mr;
     void vcvtsi2sd_mr(const void* address, XMMRegisterID src0, XMMRegisterID dst)
     {
         twoByteOpSimd("vcvtsi2sd", VEX_SD, OP2_CVTSI2SD_VsdEd, address, src0, dst);
     }
 
@@ -86,16 +110,46 @@ class BaseAssemblerX86 : public BaseAsse
     }
 
     using BaseAssembler::vmovdqa_mr;
     void vmovdqa_mr(const void* address, XMMRegisterID dst)
     {
         twoByteOpSimd("vmovdqa", VEX_PD, OP2_MOVDQ_VdqWdq, address, invalid_xmm, dst);
     }
 
+    void vhaddpd_rr(XMMRegisterID src, XMMRegisterID dst)
+    {
+        twoByteOpSimdFlags("vhaddpd", VEX_PD, OP2_HADDPD, src, dst);
+    }
+
+    void vsubpd_rr(XMMRegisterID src1, XMMRegisterID src0, XMMRegisterID dst)
+    {
+        twoByteOpSimd("vsubpd", VEX_PD, OP2_SUBPS_VpsWps, src1, src0, dst);
+    }
+    void vsubpd_mr(int32_t offset, RegisterID base, XMMRegisterID src0, XMMRegisterID dst)
+    {
+        twoByteOpSimd("vsubpd", VEX_PD, OP2_SUBPS_VpsWps, offset, base, src0, dst);
+    }
+    void vsubpd_mr(const void* address, XMMRegisterID src0, XMMRegisterID dst)
+    {
+        twoByteOpSimd("vsubpd", VEX_PD, OP2_SUBPS_VpsWps, address, src0, dst);
+    }
+
+    void vpunpckldq_rr(XMMRegisterID src1, XMMRegisterID src0, XMMRegisterID dst) {
+        twoByteOpSimd("vpunpckldq", VEX_PD, OP2_PUNPCKLDQ, src1, src0, dst);
+    }
+    void vpunpckldq_mr(int32_t offset, RegisterID base, XMMRegisterID src0, XMMRegisterID dst)
+    {
+        twoByteOpSimd("vpunpckldq", VEX_PD, OP2_PUNPCKLDQ, offset, base, src0, dst);
+    }
+    void vpunpckldq_mr(const void* addr, XMMRegisterID src0, XMMRegisterID dst)
+    {
+        twoByteOpSimd("vpunpckldq", VEX_PD, OP2_PUNPCKLDQ, addr, src0, dst);
+    }
+
     // Misc instructions:
 
     void pusha()
     {
         spew("pusha");
         m_formatter.oneByteOp(OP_PUSHA);
     }
 
--- a/js/src/jit/x86/CodeGenerator-x86.cpp
+++ b/js/src/jit/x86/CodeGenerator-x86.cpp
@@ -4,17 +4,16 @@
  * 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/x86/CodeGenerator-x86.h"
 
 #include "mozilla/Casting.h"
 #include "mozilla/DebugOnly.h"
 
-#include "jsmath.h"
 #include "jsnum.h"
 
 #include "jit/IonCaches.h"
 #include "jit/MIR.h"
 #include "jit/MIRGraph.h"
 #include "js/Conversions.h"
 #include "vm/Shape.h"
 
@@ -1100,23 +1099,8 @@ CodeGeneratorX86::visitOutOfLineTruncate
         masm.storeCallResult(output);
         masm.pop(input);
 
         restoreVolatile(output);
     }
 
     masm.jump(ool->rejoin());
 }
-
-void
-CodeGeneratorX86::visitRandom(LRandom* ins)
-{
-    Register temp = ToRegister(ins->temp());
-    Register temp2 = ToRegister(ins->temp2());
-
-    masm.loadJSContext(temp);
-
-    masm.setupUnalignedABICall(temp2);
-    masm.passABIArg(temp);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, math_random_no_outparam), MoveOp::DOUBLE);
-
-    MOZ_ASSERT(ToFloatRegister(ins->output()) == ReturnDoubleReg);
-}
--- a/js/src/jit/x86/CodeGenerator-x86.h
+++ b/js/src/jit/x86/CodeGenerator-x86.h
@@ -67,18 +67,16 @@ class CodeGeneratorX86 : public CodeGene
     void visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar* ins);
     void visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar* ins);
     void visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr* ins);
     void visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc* ins);
 
     void visitOutOfLineTruncate(OutOfLineTruncate* ool);
     void visitOutOfLineTruncateFloat32(OutOfLineTruncateFloat32* ool);
 
-    void visitRandom(LRandom* ins);
-
   private:
     void asmJSAtomicComputeAddress(Register addrTemp, Register ptrReg, bool boundsCheck,
                                    int32_t offset, int32_t endOffset);
 };
 
 typedef CodeGeneratorX86 CodeGeneratorSpecific;
 
 } // namespace jit
--- a/js/src/jit/x86/LIR-x86.h
+++ b/js/src/jit/x86/LIR-x86.h
@@ -117,29 +117,12 @@ class LAsmJSLoadFuncPtr : public LInstru
     MAsmJSLoadFuncPtr* mir() const {
         return mir_->toAsmJSLoadFuncPtr();
     }
     const LAllocation* index() {
         return getOperand(0);
     }
 };
 
-// Math.random().
-class LRandom : public LCallInstructionHelper<1, 0, 2>
-{
-  public:
-    LIR_HEADER(Random)
-    LRandom(const LDefinition& temp, const LDefinition& temp2) {
-        setTemp(0, temp);
-        setTemp(1, temp2);
-    }
-    const LDefinition* temp() {
-        return getTemp(0);
-    }
-    const LDefinition* temp2() {
-        return getTemp(1);
-    }
-};
-
 } // namespace jit
 } // namespace js
 
 #endif /* jit_x86_LIR_x86_h */
--- a/js/src/jit/x86/Lowering-x86.cpp
+++ b/js/src/jit/x86/Lowering-x86.cpp
@@ -436,11 +436,16 @@ LIRGeneratorX86::visitSubstr(MSubstr* in
                                          tempByteOpRegister());
     define(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
 LIRGeneratorX86::visitRandom(MRandom* ins)
 {
-    LRandom* lir = new(alloc()) LRandom(tempFixed(CallTempReg0), tempFixed(CallTempReg1));
-    defineReturn(lir, ins);
+    // eax and edx are necessary for mull.
+    LRandom *lir = new(alloc()) LRandom(tempFixed(eax),
+                                        tempFixed(edx),
+                                        temp(),
+                                        temp(),
+                                        temp());
+    defineFixed(lir, ins, LFloatReg(ReturnDoubleReg));
 }
--- a/js/src/jit/x86/MacroAssembler-x86-inl.h
+++ b/js/src/jit/x86/MacroAssembler-x86-inl.h
@@ -25,28 +25,42 @@ MacroAssembler::andPtr(Register src, Reg
 
 void
 MacroAssembler::andPtr(Imm32 imm, Register dest)
 {
     andl(imm, dest);
 }
 
 void
+MacroAssembler::and64(Imm64 imm, Register64 dest)
+{
+    andl(Imm32(imm.value & 0xFFFFFFFFL), dest.low);
+    andl(Imm32((imm.value >> 32) & 0xFFFFFFFFL), dest.high);
+}
+
+void
 MacroAssembler::orPtr(Register src, Register dest)
 {
     orl(src, dest);
 }
 
 void
 MacroAssembler::orPtr(Imm32 imm, Register dest)
 {
     orl(imm, dest);
 }
 
 void
+MacroAssembler::or64(Register64 src, Register64 dest)
+{
+    orl(src.low, dest.low);
+    orl(src.high, dest.high);
+}
+
+void
 MacroAssembler::xorPtr(Register src, Register dest)
 {
     xorl(src, dest);
 }
 
 void
 MacroAssembler::xorPtr(Imm32 imm, Register dest)
 {
--- a/js/src/jit/x86/MacroAssembler-x86.cpp
+++ b/js/src/jit/x86/MacroAssembler-x86.cpp
@@ -1,30 +1,87 @@
 /* -*- 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/x86/MacroAssembler-x86.h"
 
+#include "mozilla/Alignment.h"
 #include "mozilla/Casting.h"
 
 #include "jit/Bailouts.h"
 #include "jit/BaselineFrame.h"
 #include "jit/JitFrames.h"
 #include "jit/MacroAssembler.h"
 #include "jit/MoveEmitter.h"
 
 #include "jsscriptinlines.h"
 #include "jit/MacroAssembler-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
+// vpunpckldq requires 16-byte boundary for memory operand.
+// See convertUInt64ToDouble for the details.
+MOZ_ALIGNED_DECL(static const uint64_t, 16) TO_DOUBLE[4] = {
+    0x4530000043300000LL,
+    0x0LL,
+    0x4330000000000000LL,
+    0x4530000000000000LL
+};
+
+void
+MacroAssemblerX86::convertUInt64ToDouble(Register64 src, Register temp, FloatRegister dest)
+{
+    // Following operation uses entire 128-bit of dest XMM register.
+    // Currently higher 64-bit is free when we have access to lower 64-bit.
+    MOZ_ASSERT(dest.size() == 8);
+    FloatRegister dest128 = FloatRegister(dest.encoding(), FloatRegisters::Int32x4);
+
+    // Assume that src is represented as following:
+    //   src      = 0x HHHHHHHH LLLLLLLL
+
+    // Move src to dest (=dest128) and ScratchInt32x4Reg (=scratch):
+    //   dest     = 0x 00000000 00000000  00000000 LLLLLLLL
+    //   scratch  = 0x 00000000 00000000  00000000 HHHHHHHH
+    vmovd(src.low, dest128);
+    vmovd(src.high, ScratchInt32x4Reg);
+
+    // Unpack and interleave dest and scratch to dest:
+    //   dest     = 0x 00000000 00000000  HHHHHHHH LLLLLLLL
+    vpunpckldq(ScratchInt32x4Reg, dest128, dest128);
+
+    // Unpack and interleave dest and a constant C1 to dest:
+    //   C1       = 0x 00000000 00000000  45300000 43300000
+    //   dest     = 0x 45300000 HHHHHHHH  43300000 LLLLLLLL
+    // here, each 64-bit part of dest represents following double:
+    //   HI(dest) = 0x 1.00000HHHHHHHH * 2**84 == 2**84 + 0x HHHHHHHH 00000000
+    //   LO(dest) = 0x 1.00000LLLLLLLL * 2**52 == 2**52 + 0x 00000000 LLLLLLLL
+    movePtr(ImmPtr(TO_DOUBLE), temp);
+    vpunpckldq(Operand(temp, 0), dest128, dest128);
+
+    // Subtract a constant C2 from dest, for each 64-bit part:
+    //   C2       = 0x 45300000 00000000  43300000 00000000
+    // here, each 64-bit part of C2 represents following double:
+    //   HI(C2)   = 0x 1.0000000000000 * 2**84 == 2**84
+    //   LO(C2)   = 0x 1.0000000000000 * 2**52 == 2**52
+    // after the operation each 64-bit part of dest represents following:
+    //   HI(dest) = double(0x HHHHHHHH 00000000)
+    //   LO(dest) = double(0x 00000000 LLLLLLLL)
+    vsubpd(Operand(temp, sizeof(uint64_t) * 2), dest128, dest128);
+
+    // Add HI(dest) and LO(dest) in double and store it into LO(dest),
+    //   LO(dest) = double(0x HHHHHHHH 00000000) + double(0x 00000000 LLLLLLLL)
+    //            = double(0x HHHHHHHH LLLLLLLL)
+    //            = double(src)
+    vhaddpd(dest128, dest128);
+}
+
 MacroAssemblerX86::Double*
 MacroAssemblerX86::getDouble(double d)
 {
     if (!doubleMap_.initialized()) {
         enoughMemory_ &= doubleMap_.init();
         if (!enoughMemory_)
             return nullptr;
     }
--- a/js/src/jit/x86/MacroAssembler-x86.h
+++ b/js/src/jit/x86/MacroAssembler-x86.h
@@ -235,16 +235,24 @@ class MacroAssemblerX86 : public MacroAs
     void pushValue(JSValueType type, Register reg) {
         push(ImmTag(JSVAL_TYPE_TO_TAG(type)));
         push(reg);
     }
     void pushValue(const Address& addr) {
         push(tagOf(addr));
         push(payloadOfAfterStackPush(addr));
     }
+    void push64(Register64 src) {
+        push(src.high);
+        push(src.low);
+    }
+    void pop64(Register64 dest) {
+        pop(dest.low);
+        pop(dest.high);
+    }
     void storePayload(const Value& val, Operand dest) {
         jsval_layout jv = JSVAL_TO_IMPL(val);
         if (val.isMarkable())
             movl(ImmGCPtr((gc::Cell*)jv.s.payload.ptr), ToPayload(dest));
         else
             movl(Imm32(jv.s.payload.i32), ToPayload(dest));
     }
     void storePayload(Register src, Operand dest) {
@@ -602,31 +610,67 @@ class MacroAssemblerX86 : public MacroAs
         add32(imm, Operand(dest));
     }
     void addPtr(Imm32 imm, const Operand& dest) {
         add32(imm, dest);
     }
     void addPtr(const Address& src, Register dest) {
         addl(Operand(src), dest);
     }
+    void add64(Imm32 imm, Register64 dest) {
+        addl(imm, dest.low);
+        adcl(Imm32(0), dest.high);
+    }
     void subPtr(Imm32 imm, Register dest) {
         sub32(imm, dest);
     }
     void subPtr(Register src, Register dest) {
         sub32(src, dest);
     }
     void subPtr(const Address& addr, Register dest) {
         sub32(Operand(addr), dest);
     }
     void subPtr(Register src, const Address& dest) {
         sub32(src, Operand(dest));
     }
     void mulBy3(const Register& src, const Register& dest) {
         lea(Operand(src, src, TimesTwo), dest);
     }
+    // Note: this function clobbers eax and edx.
+    void mul64(Imm64 imm, const Register64& dest) {
+        // LOW32  = LOW(LOW(dest) * LOW(imm));
+        // HIGH32 = LOW(HIGH(dest) * LOW(imm)) [multiply imm into upper bits]
+        //        + LOW(LOW(dest) * HIGH(imm)) [multiply dest into upper bits]
+        //        + HIGH(LOW(dest) * LOW(imm)) [carry]
+
+        MOZ_ASSERT(dest.low != eax && dest.low != edx);
+        MOZ_ASSERT(dest.high != eax && dest.high != edx);
+
+        // HIGH(dest) = LOW(HIGH(dest) * LOW(imm));
+        movl(Imm32(imm.value & 0xFFFFFFFFL), edx);
+        imull(edx, dest.high);
+
+        // edx:eax = LOW(dest) * LOW(imm);
+        movl(Imm32(imm.value & 0xFFFFFFFFL), edx);
+        movl(dest.low, eax);
+        mull(edx);
+
+        // HIGH(dest) += edx;
+        addl(edx, dest.high);
+
+        // HIGH(dest) += LOW(LOW(dest) * HIGH(imm));
+        if (((imm.value >> 32) & 0xFFFFFFFFL) == 5)
+            leal(Operand(dest.low, dest.low, TimesFour), edx);
+        else
+            MOZ_CRASH("Unsupported imm");
+        addl(edx, dest.high);
+
+        // LOW(dest) = eax;
+        movl(eax, dest.low);
+    }
 
     void branch32(Condition cond, AbsoluteAddress lhs, Imm32 rhs, Label* label) {
         cmp32(Operand(lhs), rhs);
         j(cond, label);
     }
     void branch32(Condition cond, AsmJSAbsoluteAddress lhs, Imm32 rhs, Label* label) {
         cmpl(rhs, lhs);
         j(cond, label);
@@ -707,28 +751,44 @@ class MacroAssemblerX86 : public MacroAs
         testPtr(Operand(lhs), imm);
         j(cond, label);
     }
     void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) {
         subPtr(imm, lhs);
         j(cond, label);
     }
 
+    void branchTest64(Condition cond, Register64 lhs, Register64 rhs, Register temp, Label* label) {
+        if (cond == Assembler::Zero) {
+            MOZ_ASSERT(lhs.low == rhs.low);
+            MOZ_ASSERT(lhs.high == rhs.high);
+            movl(lhs.low, temp);
+            orl(lhs.high, temp);
+            branchTestPtr(cond, temp, temp, label);
+        } else {
+            MOZ_CRASH("Unsupported condition");
+        }
+    }
+
     void movePtr(ImmWord imm, Register dest) {
         movl(Imm32(imm.value), dest);
     }
     void movePtr(ImmPtr imm, Register dest) {
         movl(imm, dest);
     }
     void movePtr(AsmJSImmPtr imm, Register dest) {
         mov(imm, dest);
     }
     void movePtr(ImmGCPtr imm, Register dest) {
         movl(imm, dest);
     }
+    void move64(Register64 src, Register64 dest) {
+        movl(src.low, dest.low);
+        movl(src.high, dest.high);
+    }
     void loadPtr(const Address& address, Register dest) {
         movl(Operand(address), dest);
     }
     void loadPtr(const Operand& src, Register dest) {
         movl(src, dest);
     }
     void loadPtr(const BaseIndex& src, Register dest) {
         movl(Operand(src), dest);
@@ -737,16 +797,20 @@ class MacroAssemblerX86 : public MacroAs
         movl(Operand(address), dest);
     }
     void loadPrivate(const Address& src, Register dest) {
         movl(payloadOf(src), dest);
     }
     void load32(AbsoluteAddress address, Register dest) {
         movl(Operand(address), dest);
     }
+    void load64(const Address& address, Register64 dest) {
+        movl(Operand(address), dest.low);
+        movl(Operand(Address(address.base, address.offset + 4)), dest.high);
+    }
     template <typename T>
     void storePtr(ImmWord imm, T address) {
         movl(Imm32(imm.value), Operand(address));
     }
     template <typename T>
     void storePtr(ImmPtr imm, T address) {
         storePtr(ImmWord(uintptr_t(imm.value)), address);
     }
@@ -764,16 +828,20 @@ class MacroAssemblerX86 : public MacroAs
         movl(src, dest);
     }
     void storePtr(Register src, AbsoluteAddress address) {
         movl(src, Operand(address));
     }
     void store32(Register src, AbsoluteAddress address) {
         movl(src, Operand(address));
     }
+    void store64(Register64 src, Address address) {
+        movl(src.low, Operand(address));
+        movl(src.high, Operand(Address(address.base, address.offset + 4)));
+    }
 
     void setStackArg(Register reg, uint32_t arg) {
         movl(reg, Operand(esp, arg * sizeof(intptr_t)));
     }
 
     // Type testing instructions can take a tag in a register or a
     // ValueOperand.
     template <typename T>
@@ -1055,19 +1123,27 @@ class MacroAssemblerX86 : public MacroAs
     }
 
     void rshiftPtr(Imm32 imm, Register dest) {
         shrl(imm, dest);
     }
     void rshiftPtrArithmetic(Imm32 imm, Register dest) {
         sarl(imm, dest);
     }
+    void rshift64(Imm32 imm, Register64 dest) {
+        shrdl(imm, dest.high, dest.low);
+        shrl(imm, dest.high);
+    }
     void lshiftPtr(Imm32 imm, Register dest) {
         shll(imm, dest);
     }
+    void lshift64(Imm32 imm, Register64 dest) {
+        shldl(imm, dest.low, dest.high);
+        shll(imm, dest.low);
+    }
 
     void loadInstructionPointerAfterCall(Register dest) {
         movl(Operand(StackPointer, 0x0), dest);
     }
 
     // Note: this function clobbers the source register.
     void convertUInt32ToDouble(Register src, FloatRegister dest) {
         // src is [0, 2^32-1]
@@ -1082,16 +1158,23 @@ class MacroAssemblerX86 : public MacroAs
     }
 
     // Note: this function clobbers the source register.
     void convertUInt32ToFloat32(Register src, FloatRegister dest) {
         convertUInt32ToDouble(src, dest);
         convertDoubleToFloat32(dest, dest);
     }
 
+    void convertUInt64ToDouble(Register64 src, Register temp, FloatRegister dest);
+
+    void mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest) {
+        movl(imm, temp);
+        vmulsd(Operand(temp, 0), dest, dest);
+    }
+
     void inc64(AbsoluteAddress dest) {
         addl(Imm32(1), Operand(dest));
         Label noOverflow;
         j(NonZero, &noOverflow);
         addl(Imm32(1), Operand(dest.offset(4)));
         bind(&noOverflow);
     }