Bug 949668 - SpiderMonkey: Enum simplification. r=jandem
authorDan Gohman <sunfish@google.com>
Tue, 17 Dec 2013 08:46:37 -0800
changeset 160843 8754d98c1df44eae2fee2924da08779675666f5d
parent 160842 620f50eea597d310f419995185205e61e30b7a1b
child 160844 d3cb4aa974a765083799fdfe740208b551f1e076
push id37725
push usersunfish@google.com
push dateTue, 17 Dec 2013 16:58:57 +0000
treeherdermozilla-inbound@afe7a6c1c9b2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs949668
milestone29.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 949668 - SpiderMonkey: Enum simplification. r=jandem
js/src/jit/BaselineIC.cpp
js/src/jit/CodeGenerator.cpp
js/src/jit/IonMacroAssembler.h
js/src/jit/MoveResolver.h
js/src/jit/arm/MacroAssembler-arm.cpp
js/src/jit/arm/MacroAssembler-arm.h
js/src/jit/arm/MoveEmitter-arm.cpp
js/src/jit/arm/Trampoline-arm.cpp
js/src/jit/shared/CodeGenerator-shared.cpp
js/src/jit/shared/MoveEmitter-x86-shared.cpp
js/src/jit/x64/MacroAssembler-x64.cpp
js/src/jit/x64/MacroAssembler-x64.h
js/src/jit/x64/Trampoline-x64.cpp
js/src/jit/x86/CodeGenerator-x86.cpp
js/src/jit/x86/MacroAssembler-x86.cpp
js/src/jit/x86/MacroAssembler-x86.h
js/src/jit/x86/Trampoline-x86.cpp
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -2846,19 +2846,19 @@ ICBinaryArith_Double::Compiler::generate
       case JSOP_MUL:
         masm.mulDouble(FloatReg1, FloatReg0);
         break;
       case JSOP_DIV:
         masm.divDouble(FloatReg1, FloatReg0);
         break;
       case JSOP_MOD:
         masm.setupUnalignedABICall(2, R0.scratchReg());
-        masm.passABIArg(FloatReg0);
-        masm.passABIArg(FloatReg1);
-        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, NumberMod), MacroAssembler::DOUBLE);
+        masm.passABIArg(FloatReg0, MoveOp::DOUBLE);
+        masm.passABIArg(FloatReg1, MoveOp::DOUBLE);
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, NumberMod), MoveOp::DOUBLE);
         JS_ASSERT(ReturnFloatReg == FloatReg0);
         break;
       default:
         MOZ_ASSUME_UNREACHABLE("Unexpected op");
     }
 
     masm.boxDouble(FloatReg0, R0);
     EmitReturnFromIC(masm);
@@ -2973,17 +2973,17 @@ ICBinaryArith_DoubleWithInt32::Compiler:
         Label doneTruncate;
         Label truncateABICall;
         masm.branchTruncateDouble(FloatReg0, scratchReg, &truncateABICall);
         masm.jump(&doneTruncate);
 
         masm.bind(&truncateABICall);
         masm.push(intReg);
         masm.setupUnalignedABICall(1, scratchReg);
-        masm.passABIArg(FloatReg0);
+        masm.passABIArg(FloatReg0, MoveOp::DOUBLE);
         masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, js::ToInt32));
         masm.storeCallResult(scratchReg);
         masm.pop(intReg);
 
         masm.bind(&doneTruncate);
     }
 
     Register intReg2 = scratchReg;
@@ -3122,17 +3122,17 @@ ICUnaryArith_Double::Compiler::generateS
 
         Label doneTruncate;
         Label truncateABICall;
         masm.branchTruncateDouble(FloatReg0, scratchReg, &truncateABICall);
         masm.jump(&doneTruncate);
 
         masm.bind(&truncateABICall);
         masm.setupUnalignedABICall(1, scratchReg);
-        masm.passABIArg(FloatReg0);
+        masm.passABIArg(FloatReg0, MoveOp::DOUBLE);
         masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, js::ToInt32));
         masm.storeCallResult(scratchReg);
 
         masm.bind(&doneTruncate);
         masm.not32(scratchReg);
         masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0);
     }
 
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -1,9 +1,9 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+/* -*- Mnde: 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/CodeGenerator.h"
 
 #include "mozilla/Assertions.h"
@@ -1183,23 +1183,38 @@ CodeGenerator::visitMoveGroup(LMoveGroup
 
     MoveResolver &resolver = masm.moveResolver();
 
     for (size_t i = 0; i < group->numMoves(); i++) {
         const LMove &move = group->getMove(i);
 
         const LAllocation *from = move.from();
         const LAllocation *to = move.to();
+        LDefinition::Type type = move.type();
 
         // No bogus moves.
         JS_ASSERT(*from != *to);
         JS_ASSERT(!from->isConstant());
         JS_ASSERT(from->isDouble() == to->isDouble());
 
-        MoveOp::Kind kind = from->isDouble() ? MoveOp::DOUBLE : MoveOp::GENERAL;
+        MoveOp::Kind kind;
+        switch (type) {
+          case LDefinition::OBJECT:
+          case LDefinition::SLOTS:
+#ifdef JS_NUNBOX32
+          case LDefinition::TYPE:
+          case LDefinition::PAYLOAD:
+#else
+          case LDefinition::BOX:
+#endif
+          case LDefinition::GENERAL: kind = MoveOp::GENERAL; break;
+          case LDefinition::FLOAT32:
+          case LDefinition::DOUBLE:  kind = MoveOp::DOUBLE;  break;
+          default: MOZ_ASSUME_UNREACHABLE("Unexpected move type");
+        }
 
         if (!resolver.addMove(toMoveOperand(from), toMoveOperand(to), kind))
             return false;
     }
 
     if (!resolver.resolve())
         return false;
 
@@ -3200,34 +3215,34 @@ CodeGenerator::visitNewSlots(LNewSlots *
 
 bool CodeGenerator::visitAtan2D(LAtan2D *lir)
 {
     Register temp = ToRegister(lir->temp());
     FloatRegister y = ToFloatRegister(lir->y());
     FloatRegister x = ToFloatRegister(lir->x());
 
     masm.setupUnalignedABICall(2, temp);
-    masm.passABIArg(y);
-    masm.passABIArg(x);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ecmaAtan2), MacroAssembler::DOUBLE);
+    masm.passABIArg(y, MoveOp::DOUBLE);
+    masm.passABIArg(x, MoveOp::DOUBLE);
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ecmaAtan2), MoveOp::DOUBLE);
 
     JS_ASSERT(ToFloatRegister(lir->output()) == ReturnFloatReg);
     return true;
 }
 
 bool CodeGenerator::visitHypot(LHypot *lir)
 {
     Register temp = ToRegister(lir->temp());
     FloatRegister x = ToFloatRegister(lir->x());
     FloatRegister y = ToFloatRegister(lir->y());
 
     masm.setupUnalignedABICall(2, temp);
-    masm.passABIArg(x);
-    masm.passABIArg(y);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ecmaHypot), MacroAssembler::DOUBLE);
+    masm.passABIArg(x, MoveOp::DOUBLE);
+    masm.passABIArg(y, MoveOp::DOUBLE);
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ecmaHypot), MoveOp::DOUBLE);
 
     JS_ASSERT(ToFloatRegister(lir->output()) == ReturnFloatReg);
     return true;
 }
 
 bool
 CodeGenerator::visitNewArray(LNewArray *lir)
 {
@@ -3956,52 +3971,52 @@ CodeGenerator::visitPowI(LPowI *ins)
     Register temp = ToRegister(ins->temp());
 
     JS_ASSERT(power != temp);
 
     // In all implementations, setupUnalignedABICall() relinquishes use of
     // its scratch register. We can therefore save an input register by
     // reusing the scratch register to pass constants to callWithABI.
     masm.setupUnalignedABICall(2, temp);
-    masm.passABIArg(value);
+    masm.passABIArg(value, MoveOp::DOUBLE);
     masm.passABIArg(power);
 
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, js::powi), MacroAssembler::DOUBLE);
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, js::powi), MoveOp::DOUBLE);
     JS_ASSERT(ToFloatRegister(ins->output()) == ReturnFloatReg);
 
     return true;
 }
 
 bool
 CodeGenerator::visitPowD(LPowD *ins)
 {
     FloatRegister value = ToFloatRegister(ins->value());
     FloatRegister power = ToFloatRegister(ins->power());
     Register temp = ToRegister(ins->temp());
 
     masm.setupUnalignedABICall(2, temp);
-    masm.passABIArg(value);
-    masm.passABIArg(power);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ecmaPow), MacroAssembler::DOUBLE);
+    masm.passABIArg(value, MoveOp::DOUBLE);
+    masm.passABIArg(power, MoveOp::DOUBLE);
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ecmaPow), MoveOp::DOUBLE);
 
     JS_ASSERT(ToFloatRegister(ins->output()) == ReturnFloatReg);
     return true;
 }
 
 bool
 CodeGenerator::visitRandom(LRandom *ins)
 {
     Register temp = ToRegister(ins->temp());
     Register temp2 = ToRegister(ins->temp2());
 
     masm.loadJSContext(temp);
 
     masm.setupUnalignedABICall(1, temp2);
     masm.passABIArg(temp);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, math_random_no_outparam), MacroAssembler::DOUBLE);
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, math_random_no_outparam), MoveOp::DOUBLE);
 
     JS_ASSERT(ToFloatRegister(ins->output()) == ReturnFloatReg);
     return true;
 }
 
 bool
 CodeGenerator::visitMathFunctionD(LMathFunctionD *ins)
 {
@@ -4011,17 +4026,17 @@ CodeGenerator::visitMathFunctionD(LMathF
 
     const MathCache *mathCache = ins->mir()->cache();
 
     masm.setupUnalignedABICall(mathCache ? 2 : 1, temp);
     if (mathCache) {
         masm.movePtr(ImmPtr(mathCache), temp);
         masm.passABIArg(temp);
     }
-    masm.passABIArg(input);
+    masm.passABIArg(input, MoveOp::DOUBLE);
 
 #   define MAYBE_CACHED(fcn) (mathCache ? (void*)fcn ## _impl : (void*)fcn ## _uncached)
 
     void *funptr = nullptr;
     switch (ins->mir()->function()) {
       case MMathFunction::Log:
         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_log));
         break;
@@ -4092,66 +4107,66 @@ CodeGenerator::visitMathFunctionD(LMathF
         funptr = JS_FUNC_TO_DATA_PTR(void *, js::math_round_impl);
         break;
       default:
         MOZ_ASSUME_UNREACHABLE("Unknown math function");
     }
 
 #   undef MAYBE_CACHED
 
-    masm.callWithABI(funptr, MacroAssembler::DOUBLE);
+    masm.callWithABI(funptr, MoveOp::DOUBLE);
     return true;
 }
 
 bool
 CodeGenerator::visitMathFunctionF(LMathFunctionF *ins)
 {
     Register temp = ToRegister(ins->temp());
     FloatRegister input = ToFloatRegister(ins->input());
     JS_ASSERT(ToFloatRegister(ins->output()) == ReturnFloatReg);
 
     masm.setupUnalignedABICall(1, temp);
-    masm.passABIArg(input);
+    masm.passABIArg(input, MoveOp::DOUBLE);
 
     void *funptr = nullptr;
     switch (ins->mir()->function()) {
       case MMathFunction::Log:   funptr = JS_FUNC_TO_DATA_PTR(void *, logf);   break;
       case MMathFunction::Sin:   funptr = JS_FUNC_TO_DATA_PTR(void *, sinf);   break;
       case MMathFunction::Cos:   funptr = JS_FUNC_TO_DATA_PTR(void *, cosf);   break;
       case MMathFunction::Exp:   funptr = JS_FUNC_TO_DATA_PTR(void *, expf);   break;
       case MMathFunction::Tan:   funptr = JS_FUNC_TO_DATA_PTR(void *, tanf);   break;
       case MMathFunction::ATan:  funptr = JS_FUNC_TO_DATA_PTR(void *, atanf);  break;
       case MMathFunction::ASin:  funptr = JS_FUNC_TO_DATA_PTR(void *, asinf);  break;
       case MMathFunction::ACos:  funptr = JS_FUNC_TO_DATA_PTR(void *, acosf);  break;
       case MMathFunction::Floor: funptr = JS_FUNC_TO_DATA_PTR(void *, floorf); break;
       default:
         MOZ_ASSUME_UNREACHABLE("Unknown or unsupported float32 math function");
     }
 
-    masm.callWithABI(funptr, MacroAssembler::FLOAT);
+    masm.callWithABI(funptr, MoveOp::DOUBLE);
     return true;
 }
 
 bool
 CodeGenerator::visitModD(LModD *ins)
 {
     FloatRegister lhs = ToFloatRegister(ins->lhs());
     FloatRegister rhs = ToFloatRegister(ins->rhs());
     Register temp = ToRegister(ins->temp());
 
     JS_ASSERT(ToFloatRegister(ins->output()) == ReturnFloatReg);
 
     masm.setupUnalignedABICall(2, temp);
-    masm.passABIArg(lhs);
-    masm.passABIArg(rhs);
+    masm.passABIArg(lhs, MoveOp::DOUBLE);
+    masm.passABIArg(rhs, MoveOp::DOUBLE);
 
     if (gen->compilingAsmJS())
-        masm.callWithABI(AsmJSImm_ModD, MacroAssembler::DOUBLE);
+        masm.callWithABI(AsmJSImm_ModD, MoveOp::DOUBLE);
     else
-        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, NumberMod), MacroAssembler::DOUBLE);
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, NumberMod), MoveOp::DOUBLE);
     return true;
 }
 
 typedef bool (*BinaryFn)(JSContext *, MutableHandleValue, MutableHandleValue, Value *);
 typedef bool (*BinaryParFn)(ForkJoinSlice *, HandleValue, HandleValue, Value *);
 
 static const VMFunction AddInfo = FunctionInfo<BinaryFn>(js::AddValues);
 static const VMFunction SubInfo = FunctionInfo<BinaryFn>(js::SubValues);
--- a/js/src/jit/IonMacroAssembler.h
+++ b/js/src/jit/IonMacroAssembler.h
@@ -860,22 +860,22 @@ class MacroAssembler : public MacroAssem
     // These functions exist as small wrappers around sites where execution can
     // leave the currently running stream of instructions. They exist so that
     // instrumentation may be put in place around them if necessary and the
     // instrumentation is enabled. For the functions that return a uint32_t,
     // they are returning the offset of the assembler just after the call has
     // been made so that a safepoint can be made at that location.
 
     template <typename T>
-    void callWithABINoProfiling(const T &fun, Result result = GENERAL) {
+    void callWithABINoProfiling(const T &fun, MoveOp::Kind result = MoveOp::GENERAL) {
         MacroAssemblerSpecific::callWithABI(fun, result);
     }
 
     template <typename T>
-    void callWithABI(const T &fun, Result result = GENERAL) {
+    void callWithABI(const T &fun, MoveOp::Kind result = MoveOp::GENERAL) {
         leaveSPSFrame();
         callWithABINoProfiling(fun, result);
         reenterSPSFrame();
     }
 
     // see above comment for what is returned
     uint32_t callIon(const Register &callee) {
         leaveSPSFrame();
--- a/js/src/jit/MoveResolver.h
+++ b/js/src/jit/MoveResolver.h
@@ -13,95 +13,94 @@
 
 namespace js {
 namespace jit {
 
 // This is similar to Operand, but carries more information. We're also not
 // guaranteed that Operand looks like this on all ISAs.
 class MoveOperand
 {
+  public:
     enum Kind {
+        // A register in the "integer", aka "general purpose", class.
         REG,
+        // A register in the "float" register class.
         FLOAT_REG,
-        ADDRESS,
-        FLOAT_ADDRESS,
+        // A memory region.
+        MEMORY,
+        // The address of a memory region.
         EFFECTIVE_ADDRESS
     };
 
+  private:
     Kind kind_;
     uint32_t code_;
     int32_t disp_;
 
   public:
-    enum AddressKind {
-        MEMORY = ADDRESS,
-        EFFECTIVE = EFFECTIVE_ADDRESS,
-        FLOAT = FLOAT_ADDRESS
-    };
-
     MoveOperand()
     { }
     explicit MoveOperand(const Register &reg) : kind_(REG), code_(reg.code())
     { }
     explicit MoveOperand(const FloatRegister &reg) : kind_(FLOAT_REG), code_(reg.code())
     { }
-    MoveOperand(const Register &reg, int32_t disp, AddressKind addrKind = MEMORY)
-        : kind_((Kind) addrKind),
+    MoveOperand(const Register &reg, int32_t disp, Kind kind = MEMORY)
+        : kind_(kind),
         code_(reg.code()),
         disp_(disp)
     {
+        JS_ASSERT(isMemoryOrEffectiveAddress());
+
         // With a zero offset, this is a plain reg-to-reg move.
-        if (disp == 0 && addrKind == EFFECTIVE)
+        if (disp == 0 && kind_ == EFFECTIVE_ADDRESS)
             kind_ = REG;
     }
     MoveOperand(const MoveOperand &other)
       : kind_(other.kind_),
         code_(other.code_),
         disp_(other.disp_)
     { }
     bool isFloatReg() const {
         return kind_ == FLOAT_REG;
     }
     bool isGeneralReg() const {
         return kind_ == REG;
     }
-    bool isDouble() const {
-        return kind_ == FLOAT_REG || kind_ == FLOAT_ADDRESS;
-    }
     bool isMemory() const {
-        return kind_ == ADDRESS;
-    }
-    bool isFloatAddress() const {
-        return kind_ == FLOAT_ADDRESS;
+        return kind_ == MEMORY;
     }
     bool isEffectiveAddress() const {
         return kind_ == EFFECTIVE_ADDRESS;
     }
+    bool isMemoryOrEffectiveAddress() const {
+        return isMemory() || isEffectiveAddress();
+    }
     Register reg() const {
         JS_ASSERT(isGeneralReg());
         return Register::FromCode(code_);
     }
     FloatRegister floatReg() const {
         JS_ASSERT(isFloatReg());
         return FloatRegister::FromCode(code_);
     }
     Register base() const {
-        JS_ASSERT(isMemory() || isEffectiveAddress() || isFloatAddress());
+        JS_ASSERT(isMemoryOrEffectiveAddress());
         return Register::FromCode(code_);
     }
     int32_t disp() const {
+        JS_ASSERT(isMemoryOrEffectiveAddress());
         return disp_;
     }
 
     bool operator ==(const MoveOperand &other) const {
         if (kind_ != other.kind_)
             return false;
         if (code_ != other.code_)
             return false;
-        if (isMemory() || isEffectiveAddress())
+        if (isMemoryOrEffectiveAddress())
             return disp_ == other.disp_;
         return true;
     }
     bool operator !=(const MoveOperand &other) const {
         return !operator==(other);
     }
 };
 
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -3503,73 +3503,84 @@ MacroAssemblerARMCompat::setupUnalignedA
     ma_mov(sp, scratch);
 
     // Force sp to be aligned
     ma_and(Imm32(~(StackAlignment - 1)), sp, sp);
     ma_push(scratch);
 }
 #ifdef JS_CPU_ARM_HARDFP
 void
-MacroAssemblerARMCompat::passABIArg(const MoveOperand &from)
+MacroAssemblerARMCompat::passABIArg(const MoveOperand &from, MoveOp::Kind kind)
 {
     MoveOperand to;
     ++passedArgs_;
     if (!enoughMemory_)
         return;
-    if (from.isDouble()) {
+    switch (kind) {
+      case MoveOp::DOUBLE: {
         FloatRegister fr;
         if (GetFloatArgReg(usedIntSlots_, usedFloatSlots_, &fr)) {
             if (!from.isFloatReg() || from.floatReg() != fr) {
                 enoughMemory_ = moveResolver_.addMove(from, MoveOperand(fr), MoveOp::DOUBLE);
             }
             // else nothing to do; the value is in the right register already
         } else {
             // If (and only if) the integer registers have started spilling, do we
             // need to take the double register's alignment into account
             uint32_t disp = GetFloatArgStackDisp(usedIntSlots_, usedFloatSlots_, &padding_);
             enoughMemory_ = moveResolver_.addMove(from, MoveOperand(sp, disp), MoveOp::DOUBLE);
         }
         usedFloatSlots_++;
-    } else {
+        break;
+      }
+      case MoveOp::GENERAL: {
         Register r;
         if (GetIntArgReg(usedIntSlots_, usedFloatSlots_, &r)) {
             if (!from.isGeneralReg() || from.reg() != r) {
                 enoughMemory_ = moveResolver_.addMove(from, MoveOperand(r), MoveOp::GENERAL);
             }
             // else nothing to do; the value is in the right register already
         } else {
             uint32_t disp = GetIntArgStackDisp(usedIntSlots_, usedFloatSlots_, &padding_);
             enoughMemory_ = moveResolver_.addMove(from, MoveOperand(sp, disp), MoveOp::GENERAL);
         }
         usedIntSlots_++;
+        break;
+      }
+      default:
+        MOZ_ASSUME_UNREACHABLE("Unexpected argument kind");
     }
 
 }
 
 #else
 void
-MacroAssemblerARMCompat::passABIArg(const MoveOperand &from)
+MacroAssemblerARMCompat::passABIArg(const MoveOperand &from, MoveOp::Kind kind)
 {
     MoveOperand to;
     uint32_t increment = 1;
     bool useResolver = true;
     ++passedArgs_;
-    MoveOp::Kind kind = MoveOp::GENERAL;
-    if (from.isDouble()) {
+    switch (kind) {
+      case MoveOp::DOUBLE:
         // Double arguments need to be rounded up to the nearest doubleword
         // boundary, even if it is in a register!
         usedSlots_ = (usedSlots_ + 1) & ~1;
         increment = 2;
-        kind = MoveOp::DOUBLE;
+        break;
+      case MoveOp::GENERAL:
+        break;
+      default:
+        MOZ_ASSUME_UNREACHABLE("Unexpected argument kind");
     }
 
     Register destReg;
     MoveOperand dest;
     if (GetIntArgReg(usedSlots_, 0, &destReg)) {
-        if (from.isDouble()) {
+        if (kind == MoveOp::DOUBLE) {
             floatArgsInGPR[destReg.code() >> 1] = from;
             floatArgsInGPRValid[destReg.code() >> 1] = true;
             useResolver = false;
         } else if (from.isGeneralReg() && from.reg() == destReg) {
             // No need to move anything
             useResolver = false;
         } else {
             dest = MoveOperand(destReg);
@@ -3583,23 +3594,23 @@ MacroAssemblerARMCompat::passABIArg(cons
         enoughMemory_ = enoughMemory_ && moveResolver_.addMove(from, dest, kind);
     usedSlots_ += increment;
 }
 #endif
 
 void
 MacroAssemblerARMCompat::passABIArg(const Register &reg)
 {
-    passABIArg(MoveOperand(reg));
-}
-
-void
-MacroAssemblerARMCompat::passABIArg(const FloatRegister &freg)
-{
-    passABIArg(MoveOperand(freg));
+    passABIArg(MoveOperand(reg), MoveOp::GENERAL);
+}
+
+void
+MacroAssemblerARMCompat::passABIArg(const FloatRegister &freg, MoveOp::Kind kind)
+{
+    passABIArg(MoveOperand(freg), kind);
 }
 
 void MacroAssemblerARMCompat::checkStackAlignment()
 {
 #ifdef DEBUG
     ma_tst(sp, Imm32(StackAlignment - 1));
     breakpoint(NonZero);
 #endif
@@ -3637,17 +3648,17 @@ MacroAssemblerARMCompat::callWithABIPre(
     for (int i = 0; i < 2; i++) {
         if (floatArgsInGPRValid[i]) {
             MoveOperand from = floatArgsInGPR[i];
             Register to0 = Register::FromCode(i * 2), to1 = Register::FromCode(i * 2 + 1);
 
             if (from.isFloatReg()) {
                 ma_vxfer(VFPRegister(from.floatReg()), to0, to1);
             } else {
-                JS_ASSERT(from.isFloatAddress());
+                JS_ASSERT(from.isMemory());
                 // Note: We can safely use the MoveOperand's displacement here,
                 // even if the base is SP: MoveEmitter::toOperand adjusts
                 // SP-relative operands by the difference between the current
                 // stack usage and stackAdjust, which emitter.finish() resets
                 // to 0.
                 //
                 // Warning: if the offset isn't within [-255,+255] then this
                 // will assert-fail (or, if non-debug, load the wrong words).
@@ -3659,35 +3670,35 @@ MacroAssemblerARMCompat::callWithABIPre(
     checkStackAlignment();
 
     // Save the lr register if we need to preserve it.
     if (secondScratchReg_ != lr)
         ma_mov(lr, secondScratchReg_);
 }
 
 void
-MacroAssemblerARMCompat::callWithABIPost(uint32_t stackAdjust, Result result)
+MacroAssemblerARMCompat::callWithABIPost(uint32_t stackAdjust, MoveOp::Kind result)
 {
     if (secondScratchReg_ != lr)
         ma_mov(secondScratchReg_, lr);
 
     switch (result) {
-      case DOUBLE:
+      case MoveOp::DOUBLE:
 #ifndef JS_CPU_ARM_HARDFP
         // Move double from r0/r1 to ReturnFloatReg.
         as_vxfer(r0, r1, ReturnFloatReg, CoreToFloat);
         break;
 #endif
-      case FLOAT:
+      case MoveOp::FLOAT32:
 #ifndef JS_CPU_ARM_HARDFP
         // Move float32 from r0 to ReturnFloatReg.
         as_vxfer(r0, InvalidReg, VFPRegister(d0).singleOverlay(), CoreToFloat);
         break;
 #endif
-      case GENERAL:
+      case MoveOp::GENERAL:
         break;
 
       default:
         MOZ_ASSUME_UNREACHABLE("unexpected callWithABI result");
     }
 
     freeStack(stackAdjust);
 
@@ -3697,35 +3708,35 @@ MacroAssemblerARMCompat::callWithABIPost
         as_dtr(IsLoad, 32, Offset, sp, DTRAddr(sp, DtrOffImm(0)));
     }
 
     JS_ASSERT(inCall_);
     inCall_ = false;
 }
 
 void
-MacroAssemblerARMCompat::callWithABI(void *fun, Result result)
+MacroAssemblerARMCompat::callWithABI(void *fun, MoveOp::Kind result)
 {
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust);
     ma_call(ImmPtr(fun));
     callWithABIPost(stackAdjust, result);
 }
 
 void
-MacroAssemblerARMCompat::callWithABI(AsmJSImmPtr imm, Result result)
+MacroAssemblerARMCompat::callWithABI(AsmJSImmPtr imm, MoveOp::Kind result)
 {
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust);
     call(imm);
     callWithABIPost(stackAdjust, result);
 }
 
 void
-MacroAssemblerARMCompat::callWithABI(const Address &fun, Result result)
+MacroAssemblerARMCompat::callWithABI(const Address &fun, MoveOp::Kind result)
 {
     // Load the callee in r12, no instruction between the ldr and call
     // should clobber it. Note that we can't use fun.base because it may
     // be one of the IntArg registers clobbered before the call.
     ma_ldr(fun, r12);
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust);
     call(r12);
--- a/js/src/jit/arm/MacroAssembler-arm.h
+++ b/js/src/jit/arm/MacroAssembler-arm.h
@@ -480,22 +480,16 @@ class MacroAssemblerARMCompat : public M
     // reserved for unexpected spills or C++ function calls. It is maintained
     // by functions which track stack alignment, which for clear distinction
     // use StudlyCaps (for example, Push, Pop).
     uint32_t framePushed_;
     void adjustFrame(int value) {
         setFramePushed(framePushed_ + value);
     }
   public:
-    enum Result {
-        GENERAL,
-        DOUBLE,
-        FLOAT
-    };
-
     MacroAssemblerARMCompat()
       : inCall_(false),
         enoughMemory_(true),
         framePushed_(0)
     { }
     bool oom() const {
         return Assembler::oom() || !enoughMemory_;
     }
@@ -1404,33 +1398,33 @@ class MacroAssemblerARMCompat : public M
     // scratch register.
     void setupUnalignedABICall(uint32_t args, const Register &scratch);
 
     // Arguments must be assigned in a left-to-right order. This process may
     // temporarily use more stack, in which case esp-relative addresses will be
     // automatically adjusted. It is extremely important that esp-relative
     // addresses are computed *after* setupABICall(). Furthermore, no
     // operations should be emitted while setting arguments.
-    void passABIArg(const MoveOperand &from);
+    void passABIArg(const MoveOperand &from, MoveOp::Kind kind);
     void passABIArg(const Register &reg);
-    void passABIArg(const FloatRegister &reg);
+    void passABIArg(const FloatRegister &reg, MoveOp::Kind kind);
     void passABIArg(const ValueOperand &regs);
 
   protected:
     bool buildOOLFakeExitFrame(void *fakeReturnAddr);
 
   private:
     void callWithABIPre(uint32_t *stackAdjust);
-    void callWithABIPost(uint32_t stackAdjust, Result result);
+    void callWithABIPost(uint32_t stackAdjust, MoveOp::Kind result);
 
   public:
     // Emits a call to a C/C++ function, resolving all argument moves.
-    void callWithABI(void *fun, Result result = GENERAL);
-    void callWithABI(AsmJSImmPtr imm, Result result = GENERAL);
-    void callWithABI(const Address &fun, Result result = GENERAL);
+    void callWithABI(void *fun, MoveOp::Kind result = MoveOp::GENERAL);
+    void callWithABI(AsmJSImmPtr imm, MoveOp::Kind result = MoveOp::GENERAL);
+    void callWithABI(const Address &fun, MoveOp::Kind result = MoveOp::GENERAL);
 
     CodeOffsetLabel labelForPatch() {
         return CodeOffsetLabel(nextOffset().getOffset());
     }
 
     void computeEffectiveAddress(const Address &address, Register dest) {
         ma_add(address.base, Imm32(address.offset), dest, NoSetCond);
     }
--- a/js/src/jit/arm/MoveEmitter-arm.cpp
+++ b/js/src/jit/arm/MoveEmitter-arm.cpp
@@ -53,17 +53,17 @@ MoveEmitterARM::spillSlot() const
     int offset =  masm.framePushed() - pushedAtSpill_;
     JS_ASSERT(offset < 4096 && offset > -4096);
     return Operand(StackPointer, offset);
 }
 
 Operand
 MoveEmitterARM::toOperand(const MoveOperand &operand, bool isFloat) const
 {
-    if (operand.isMemory() || operand.isEffectiveAddress() || operand.isFloatAddress()) {
+    if (operand.isMemoryOrEffectiveAddress()) {
         if (operand.base() != StackPointer) {
             JS_ASSERT(operand.disp() < 1024 && operand.disp() > -1024);
             return Operand(operand.base(), operand.disp());
         }
 
         JS_ASSERT(operand.disp() >= 0);
 
         // Otherwise, the stack offset may need to be adjusted.
@@ -188,26 +188,26 @@ MoveEmitterARM::emitMove(const MoveOpera
             break;
           case Operand::MEM:
             masm.ma_str(from.reg(), toOperand(to, false));
             break;
           default:
             MOZ_ASSUME_UNREACHABLE("strange move!");
         }
     } else if (to.isGeneralReg()) {
-        JS_ASSERT(from.isMemory() || from.isEffectiveAddress());
+        JS_ASSERT(from.isMemoryOrEffectiveAddress());
         if (from.isMemory())
             masm.ma_ldr(toOperand(from, false), to.reg());
         else
             masm.ma_add(from.base(), Imm32(from.disp()), to.reg());
     } else {
         // Memory to memory gpr move.
         Register reg = tempReg();
 
-        JS_ASSERT(from.isMemory() || from.isEffectiveAddress());
+        JS_ASSERT(from.isMemoryOrEffectiveAddress());
         if (from.isMemory())
             masm.ma_ldr(toOperand(from, false), reg);
         else
             masm.ma_add(from.base(), Imm32(from.disp()), reg);
         JS_ASSERT(to.base() != reg);
         masm.ma_str(reg, toOperand(to, false));
     }
 }
--- a/js/src/jit/arm/Trampoline-arm.cpp
+++ b/js/src/jit/arm/Trampoline-arm.cpp
@@ -730,32 +730,32 @@ JitRuntime::generateVMWrapper(JSContext 
 
     size_t argDisp = 0;
 
     // Copy any arguments.
     for (uint32_t explicitArg = 0; explicitArg < f.explicitArgs; explicitArg++) {
         MoveOperand from;
         switch (f.argProperties(explicitArg)) {
           case VMFunction::WordByValue:
-            masm.passABIArg(MoveOperand(argsBase, argDisp));
+            masm.passABIArg(MoveOperand(argsBase, argDisp), MoveOp::GENERAL);
             argDisp += sizeof(void *);
             break;
           case VMFunction::DoubleByValue:
             // Values should be passed by reference, not by value, so we
             // assert that the argument is a double-precision float.
             JS_ASSERT(f.argPassedInFloatReg(explicitArg));
-            masm.passABIArg(MoveOperand(argsBase, argDisp, MoveOperand::FLOAT));
+            masm.passABIArg(MoveOperand(argsBase, argDisp), MoveOp::DOUBLE);
             argDisp += sizeof(double);
             break;
           case VMFunction::WordByRef:
-            masm.passABIArg(MoveOperand(argsBase, argDisp, MoveOperand::EFFECTIVE));
+            masm.passABIArg(MoveOperand(argsBase, argDisp, MoveOperand::EFFECTIVE_ADDRESS), MoveOp::GENERAL);
             argDisp += sizeof(void *);
             break;
           case VMFunction::DoubleByRef:
-            masm.passABIArg(MoveOperand(argsBase, argDisp, MoveOperand::EFFECTIVE));
+            masm.passABIArg(MoveOperand(argsBase, argDisp, MoveOperand::EFFECTIVE_ADDRESS), MoveOp::GENERAL);
             argDisp += 2 * sizeof(void *);
             break;
         }
     }
 
     // Copy the implicit outparam, if any.
     if (outReg != InvalidReg)
         masm.passABIArg(outReg);
--- a/js/src/jit/shared/CodeGenerator-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-shared.cpp
@@ -762,17 +762,17 @@ CodeGeneratorShared::visitOutOfLineTrunc
     saveVolatile(dest);
 
     if (ool->needFloat32Conversion()) {
         masm.push(src);
         masm.convertFloatToDouble(src, src);
     }
 
     masm.setupUnalignedABICall(1, dest);
-    masm.passABIArg(src);
+    masm.passABIArg(src, MoveOp::DOUBLE);
     if (gen->compilingAsmJS())
         masm.callWithABI(AsmJSImm_ToInt32);
     else
         masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, js::ToInt32));
     masm.storeCallResult(dest);
 
     if (ool->needFloat32Conversion())
         masm.pop(src);
--- a/js/src/jit/shared/MoveEmitter-x86-shared.cpp
+++ b/js/src/jit/shared/MoveEmitter-x86-shared.cpp
@@ -165,17 +165,17 @@ MoveEmitterX86::toAddress(const MoveOper
 }
 
 // Warning, do not use the resulting operand with pop instructions, since they
 // compute the effective destination address after altering the stack pointer.
 // Use toPopOperand if an Operand is needed for a pop.
 Operand
 MoveEmitterX86::toOperand(const MoveOperand &operand) const
 {
-    if (operand.isMemory() || operand.isEffectiveAddress() || operand.isFloatAddress())
+    if (operand.isMemoryOrEffectiveAddress())
         return Operand(toAddress(operand));
     if (operand.isGeneralReg())
         return Operand(operand.reg());
 
     JS_ASSERT(operand.isFloatReg());
     return Operand(operand.floatReg());
 }
 
@@ -250,17 +250,17 @@ MoveEmitterX86::completeCycle(const Move
 }
 
 void
 MoveEmitterX86::emitGeneralMove(const MoveOperand &from, const MoveOperand &to)
 {
     if (from.isGeneralReg()) {
         masm.mov(from.reg(), toOperand(to));
     } else if (to.isGeneralReg()) {
-        JS_ASSERT(from.isMemory() || from.isEffectiveAddress());
+        JS_ASSERT(from.isMemoryOrEffectiveAddress());
         if (from.isMemory())
             masm.loadPtr(toAddress(from), to.reg());
         else
             masm.lea(toOperand(from), to.reg());
     } else if (from.isMemory()) {
         // Memory to memory gpr move.
 #ifdef JS_CPU_X64
         // x64 has a ScratchReg. Use it.
--- a/js/src/jit/x64/MacroAssembler-x64.cpp
+++ b/js/src/jit/x64/MacroAssembler-x64.cpp
@@ -129,58 +129,68 @@ MacroAssemblerX64::setupUnalignedABICall
     dynamicAlignment_ = true;
 
     movq(rsp, scratch);
     andq(Imm32(~(StackAlignment - 1)), rsp);
     push(scratch);
 }
 
 void
-MacroAssemblerX64::passABIArg(const MoveOperand &from)
+MacroAssemblerX64::passABIArg(const MoveOperand &from, MoveOp::Kind kind)
 {
     MoveOperand to;
-    if (from.isDouble()) {
+    switch (kind) {
+      case MoveOp::DOUBLE: {
         FloatRegister dest;
         if (GetFloatArgReg(passedIntArgs_, passedFloatArgs_++, &dest)) {
             if (from.isFloatReg() && from.floatReg() == dest) {
                 // Nothing to do; the value is in the right register already
                 return;
             }
             to = MoveOperand(dest);
         } else {
             to = MoveOperand(StackPointer, stackForCall_);
-            stackForCall_ += sizeof(double);
+            switch (kind) {
+              case MoveOp::DOUBLE:  stackForCall_ += sizeof(double); break;
+              default: MOZ_ASSUME_UNREACHABLE("Unexpected float register class argument kind");
+            }
         }
         enoughMemory_ = moveResolver_.addMove(from, to, MoveOp::DOUBLE);
-    } else {
+        break;
+      }
+      case MoveOp::GENERAL: {
         Register dest;
         if (GetIntArgReg(passedIntArgs_++, passedFloatArgs_, &dest)) {
             if (from.isGeneralReg() && from.reg() == dest) {
                 // Nothing to do; the value is in the right register already
                 return;
             }
             to = MoveOperand(dest);
         } else {
             to = MoveOperand(StackPointer, stackForCall_);
             stackForCall_ += sizeof(int64_t);
         }
         enoughMemory_ = moveResolver_.addMove(from, to, MoveOp::GENERAL);
+        break;
+      }
+      default:
+        MOZ_ASSUME_UNREACHABLE("Unexpected argument kind");
     }
 }
 
 void
 MacroAssemblerX64::passABIArg(const Register &reg)
 {
-    passABIArg(MoveOperand(reg));
+    passABIArg(MoveOperand(reg), MoveOp::GENERAL);
 }
 
 void
-MacroAssemblerX64::passABIArg(const FloatRegister &reg)
+MacroAssemblerX64::passABIArg(const FloatRegister &reg, MoveOp::Kind kind)
 {
-    passABIArg(MoveOperand(reg));
+    passABIArg(MoveOperand(reg), kind);
 }
 
 void
 MacroAssemblerX64::callWithABIPre(uint32_t *stackAdjust)
 {
     JS_ASSERT(inCall_);
     JS_ASSERT(args_ == passedIntArgs_ + passedFloatArgs_);
 
@@ -214,37 +224,37 @@ MacroAssemblerX64::callWithABIPre(uint32
         j(Equal, &good);
         breakpoint();
         bind(&good);
     }
 #endif
 }
 
 void
-MacroAssemblerX64::callWithABIPost(uint32_t stackAdjust, Result result)
+MacroAssemblerX64::callWithABIPost(uint32_t stackAdjust, MoveOp::Kind result)
 {
     freeStack(stackAdjust);
     if (dynamicAlignment_)
         pop(rsp);
 
     JS_ASSERT(inCall_);
     inCall_ = false;
 }
 
 void
-MacroAssemblerX64::callWithABI(void *fun, Result result)
+MacroAssemblerX64::callWithABI(void *fun, MoveOp::Kind result)
 {
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust);
     call(ImmPtr(fun));
     callWithABIPost(stackAdjust, result);
 }
 
 void
-MacroAssemblerX64::callWithABI(AsmJSImmPtr imm, Result result)
+MacroAssemblerX64::callWithABI(AsmJSImmPtr imm, MoveOp::Kind result)
 {
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust);
     call(imm);
     callWithABIPost(stackAdjust, result);
 }
 
 static bool
@@ -254,17 +264,17 @@ IsIntArgReg(Register reg)
         if (IntArgRegs[i] == reg)
             return true;
     }
 
     return false;
 }
 
 void
-MacroAssemblerX64::callWithABI(Address fun, Result result)
+MacroAssemblerX64::callWithABI(Address fun, MoveOp::Kind result)
 {
     if (IsIntArgReg(fun.base)) {
         // Callee register may be clobbered for an argument. Move the callee to
         // r10, a volatile, non-argument register.
         moveResolver_.addMove(MoveOperand(fun.base), MoveOperand(r10), MoveOp::GENERAL);
         fun.base = r10;
     }
 
--- a/js/src/jit/x64/MacroAssembler-x64.h
+++ b/js/src/jit/x64/MacroAssembler-x64.h
@@ -74,22 +74,16 @@ class MacroAssemblerX64 : public MacroAs
 
   public:
     using MacroAssemblerX86Shared::call;
     using MacroAssemblerX86Shared::Push;
     using MacroAssemblerX86Shared::Pop;
     using MacroAssemblerX86Shared::callWithExitFrame;
     using MacroAssemblerX86Shared::branch32;
 
-    enum Result {
-        GENERAL,
-        DOUBLE,
-        FLOAT
-    };
-
     MacroAssemblerX64()
       : inCall_(false),
         enoughMemory_(true)
     {
     }
 
     // The buffer is about to be linked, make sure any constant pools or excess
     // bookkeeping has been flushed to the instruction stream.
@@ -1194,29 +1188,29 @@ class MacroAssemblerX64 : public MacroAs
     void setupUnalignedABICall(uint32_t args, const Register &scratch);
 
     // Arguments must be assigned to a C/C++ call in order. They are moved
     // in parallel immediately before performing the call. This process may
     // temporarily use more stack, in which case esp-relative addresses will be
     // automatically adjusted. It is extremely important that esp-relative
     // addresses are computed *after* setupABICall(). Furthermore, no
     // operations should be emitted while setting arguments.
-    void passABIArg(const MoveOperand &from);
+    void passABIArg(const MoveOperand &from, MoveOp::Kind kind);
     void passABIArg(const Register &reg);
-    void passABIArg(const FloatRegister &reg);
+    void passABIArg(const FloatRegister &reg, MoveOp::Kind kind);
 
   private:
     void callWithABIPre(uint32_t *stackAdjust);
-    void callWithABIPost(uint32_t stackAdjust, Result result);
+    void callWithABIPost(uint32_t stackAdjust, MoveOp::Kind result);
 
   public:
     // Emits a call to a C/C++ function, resolving all argument moves.
-    void callWithABI(void *fun, Result result = GENERAL);
-    void callWithABI(AsmJSImmPtr imm, Result result = GENERAL);
-    void callWithABI(Address fun, Result result = GENERAL);
+    void callWithABI(void *fun, MoveOp::Kind result = MoveOp::GENERAL);
+    void callWithABI(AsmJSImmPtr imm, MoveOp::Kind result = MoveOp::GENERAL);
+    void callWithABI(Address fun, MoveOp::Kind result = MoveOp::GENERAL);
 
     void handleFailureWithHandler(void *handler);
     void handleFailureWithHandlerTail();
 
     void makeFrameDescriptor(Register frameSizeReg, FrameType type) {
         shlq(Imm32(FRAMESIZE_SHIFT), frameSizeReg);
         orq(Imm32(type), frameSizeReg);
     }
--- a/js/src/jit/x64/Trampoline-x64.cpp
+++ b/js/src/jit/x64/Trampoline-x64.cpp
@@ -581,35 +581,34 @@ JitRuntime::generateVMWrapper(JSContext 
     }
 
     masm.setupUnalignedABICall(f.argc(), regs.getAny());
     masm.passABIArg(cxreg);
 
     size_t argDisp = 0;
 
     // Copy arguments.
-    if (f.explicitArgs) {
-        for (uint32_t explicitArg = 0; explicitArg < f.explicitArgs; explicitArg++) {
-            MoveOperand from;
-            switch (f.argProperties(explicitArg)) {
-              case VMFunction::WordByValue:
-                if (f.argPassedInFloatReg(explicitArg))
-                    masm.passABIArg(MoveOperand(argsBase, argDisp, MoveOperand::FLOAT));
-                else
-                    masm.passABIArg(MoveOperand(argsBase, argDisp));
-                argDisp += sizeof(void *);
-                break;
-              case VMFunction::WordByRef:
-                masm.passABIArg(MoveOperand(argsBase, argDisp, MoveOperand::EFFECTIVE));
-                argDisp += sizeof(void *);
-                break;
-              case VMFunction::DoubleByValue:
-              case VMFunction::DoubleByRef:
-                MOZ_ASSUME_UNREACHABLE("NYI: x64 callVM should not be used with 128bits values.");
-            }
+    for (uint32_t explicitArg = 0; explicitArg < f.explicitArgs; explicitArg++) {
+        MoveOperand from;
+        switch (f.argProperties(explicitArg)) {
+          case VMFunction::WordByValue:
+            if (f.argPassedInFloatReg(explicitArg))
+                masm.passABIArg(MoveOperand(argsBase, argDisp), MoveOp::DOUBLE);
+            else
+                masm.passABIArg(MoveOperand(argsBase, argDisp), MoveOp::GENERAL);
+            argDisp += sizeof(void *);
+            break;
+          case VMFunction::WordByRef:
+            masm.passABIArg(MoveOperand(argsBase, argDisp, MoveOperand::EFFECTIVE_ADDRESS),
+                            MoveOp::GENERAL);
+            argDisp += sizeof(void *);
+            break;
+          case VMFunction::DoubleByValue:
+          case VMFunction::DoubleByRef:
+            MOZ_ASSUME_UNREACHABLE("NYI: x64 callVM should not be used with 128bits values.");
         }
     }
 
     // Copy the implicit outparam, if any.
     if (outReg != InvalidReg)
         masm.passABIArg(outReg);
 
     masm.callWithABI(f.wrapped);
--- a/js/src/jit/x86/CodeGenerator-x86.cpp
+++ b/js/src/jit/x86/CodeGenerator-x86.cpp
@@ -895,17 +895,17 @@ CodeGeneratorX86::visitOutOfLineTruncate
         masm.j(Assembler::Equal, ool->rejoin());
     }
 
     masm.bind(&fail);
     {
         saveVolatile(output);
 
         masm.setupUnalignedABICall(1, output);
-        masm.passABIArg(input);
+        masm.passABIArg(input, MoveOp::DOUBLE);
         if (gen->compilingAsmJS())
             masm.callWithABI(AsmJSImm_ToInt32);
         else
             masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, js::ToInt32));
         masm.storeCallResult(output);
 
         restoreVolatile(output);
     }
@@ -986,17 +986,17 @@ CodeGeneratorX86::visitOutOfLineTruncate
 
     masm.bind(&fail);
     {
         saveVolatile(output);
 
         masm.push(input);
         masm.setupUnalignedABICall(1, output);
         masm.cvtss2sd(input, input);
-        masm.passABIArg(input);
+        masm.passABIArg(input, MoveOp::DOUBLE);
 
         if (gen->compilingAsmJS())
             masm.callWithABI(AsmJSImm_ToInt32);
         else
             masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, js::ToInt32));
 
         masm.storeCallResult(output);
         masm.pop(input);
--- a/js/src/jit/x86/MacroAssembler-x86.cpp
+++ b/js/src/jit/x86/MacroAssembler-x86.cpp
@@ -158,39 +158,44 @@ MacroAssemblerX86::setupUnalignedABICall
     dynamicAlignment_ = true;
 
     movl(esp, scratch);
     andl(Imm32(~(StackAlignment - 1)), esp);
     push(scratch);
 }
 
 void
-MacroAssemblerX86::passABIArg(const MoveOperand &from)
+MacroAssemblerX86::passABIArg(const MoveOperand &from, MoveOp::Kind kind)
 {
     ++passedArgs_;
     MoveOperand to = MoveOperand(StackPointer, stackForCall_);
-    if (from.isDouble()) {
+    switch (kind) {
+      case MoveOp::DOUBLE:
         stackForCall_ += sizeof(double);
         enoughMemory_ &= moveResolver_.addMove(from, to, MoveOp::DOUBLE);
-    } else {
+        break;
+      case MoveOp::GENERAL:
         stackForCall_ += sizeof(int32_t);
         enoughMemory_ &= moveResolver_.addMove(from, to, MoveOp::GENERAL);
+        break;
+      default:
+        MOZ_ASSUME_UNREACHABLE("Unexpected argument kind");
     }
 }
 
 void
 MacroAssemblerX86::passABIArg(const Register &reg)
 {
-    passABIArg(MoveOperand(reg));
+    passABIArg(MoveOperand(reg), MoveOp::GENERAL);
 }
 
 void
-MacroAssemblerX86::passABIArg(const FloatRegister &reg)
+MacroAssemblerX86::passABIArg(const FloatRegister &reg, MoveOp::Kind kind)
 {
-    passABIArg(MoveOperand(reg));
+    passABIArg(MoveOperand(reg), kind);
 }
 
 void
 MacroAssemblerX86::callWithABIPre(uint32_t *stackAdjust)
 {
     JS_ASSERT(inCall_);
     JS_ASSERT(args_ == passedArgs_);
 
@@ -225,58 +230,58 @@ MacroAssemblerX86::callWithABIPre(uint32
         j(Equal, &good);
         breakpoint();
         bind(&good);
     }
 #endif
 }
 
 void
-MacroAssemblerX86::callWithABIPost(uint32_t stackAdjust, Result result)
+MacroAssemblerX86::callWithABIPost(uint32_t stackAdjust, MoveOp::Kind result)
 {
     freeStack(stackAdjust);
-    if (result == DOUBLE) {
+    if (result == MoveOp::DOUBLE) {
         reserveStack(sizeof(double));
         fstp(Operand(esp, 0));
         loadDouble(Operand(esp, 0), ReturnFloatReg);
         freeStack(sizeof(double));
     }
-    if (result == FLOAT) {
+    if (result == MoveOp::FLOAT32) {
         reserveStack(sizeof(float));
         fstp32(Operand(esp, 0));
         loadFloat(Operand(esp, 0), ReturnFloatReg);
         freeStack(sizeof(float));
     }
     if (dynamicAlignment_)
         pop(esp);
 
     JS_ASSERT(inCall_);
     inCall_ = false;
 }
 
 void
-MacroAssemblerX86::callWithABI(void *fun, Result result)
+MacroAssemblerX86::callWithABI(void *fun, MoveOp::Kind result)
 {
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust);
     call(ImmPtr(fun));
     callWithABIPost(stackAdjust, result);
 }
 
 void
-MacroAssemblerX86::callWithABI(AsmJSImmPtr fun, Result result)
+MacroAssemblerX86::callWithABI(AsmJSImmPtr fun, MoveOp::Kind result)
 {
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust);
     call(fun);
     callWithABIPost(stackAdjust, result);
 }
 
 void
-MacroAssemblerX86::callWithABI(const Address &fun, Result result)
+MacroAssemblerX86::callWithABI(const Address &fun, MoveOp::Kind result)
 {
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust);
     call(Operand(fun));
     callWithABIPost(stackAdjust, result);
 }
 
 void
--- a/js/src/jit/x86/MacroAssembler-x86.h
+++ b/js/src/jit/x86/MacroAssembler-x86.h
@@ -65,22 +65,16 @@ class MacroAssemblerX86 : public MacroAs
     void setupABICall(uint32_t args);
 
   public:
     using MacroAssemblerX86Shared::Push;
     using MacroAssemblerX86Shared::Pop;
     using MacroAssemblerX86Shared::callWithExitFrame;
     using MacroAssemblerX86Shared::branch32;
 
-    enum Result {
-        GENERAL,
-        DOUBLE,
-        FLOAT
-    };
-
     MacroAssemblerX86()
       : inCall_(false),
         enoughMemory_(true)
     {
     }
 
     // The buffer is about to be linked, make sure any constant pools or excess
     // bookkeeping has been flushed to the instruction stream.
@@ -1038,29 +1032,29 @@ class MacroAssemblerX86 : public MacroAs
     void setupUnalignedABICall(uint32_t args, const Register &scratch);
 
     // Arguments must be assigned to a C/C++ call in order. They are moved
     // in parallel immediately before performing the call. This process may
     // temporarily use more stack, in which case esp-relative addresses will be
     // automatically adjusted. It is extremely important that esp-relative
     // addresses are computed *after* setupABICall(). Furthermore, no
     // operations should be emitted while setting arguments.
-    void passABIArg(const MoveOperand &from);
+    void passABIArg(const MoveOperand &from, MoveOp::Kind kind);
     void passABIArg(const Register &reg);
-    void passABIArg(const FloatRegister &reg);
+    void passABIArg(const FloatRegister &reg, MoveOp::Kind kind);
 
   private:
     void callWithABIPre(uint32_t *stackAdjust);
-    void callWithABIPost(uint32_t stackAdjust, Result result);
+    void callWithABIPost(uint32_t stackAdjust, MoveOp::Kind result);
 
   public:
     // Emits a call to a C/C++ function, resolving all argument moves.
-    void callWithABI(void *fun, Result result = GENERAL);
-    void callWithABI(AsmJSImmPtr fun, Result result = GENERAL);
-    void callWithABI(const Address &fun, Result result = GENERAL);
+    void callWithABI(void *fun, MoveOp::Kind result = MoveOp::GENERAL);
+    void callWithABI(AsmJSImmPtr fun, MoveOp::Kind result = MoveOp::GENERAL);
+    void callWithABI(const Address &fun, MoveOp::Kind result = MoveOp::GENERAL);
 
     // Used from within an Exit frame to handle a pending exception.
     void handleFailureWithHandler(void *handler);
     void handleFailureWithHandlerTail();
 
     void makeFrameDescriptor(Register frameSizeReg, FrameType type) {
         shll(Imm32(FRAMESIZE_SHIFT), frameSizeReg);
         orl(Imm32(type), frameSizeReg);
--- a/js/src/jit/x86/Trampoline-x86.cpp
+++ b/js/src/jit/x86/Trampoline-x86.cpp
@@ -609,41 +609,41 @@ JitRuntime::generateVMWrapper(JSContext 
     }
 
     masm.setupUnalignedABICall(f.argc(), regs.getAny());
     masm.passABIArg(cxreg);
 
     size_t argDisp = 0;
 
     // Copy arguments.
-    if (f.explicitArgs) {
-        for (uint32_t explicitArg = 0; explicitArg < f.explicitArgs; explicitArg++) {
-            MoveOperand from;
-            switch (f.argProperties(explicitArg)) {
-              case VMFunction::WordByValue:
-                masm.passABIArg(MoveOperand(argsBase, argDisp));
-                argDisp += sizeof(void *);
-                break;
-              case VMFunction::DoubleByValue:
-                // We don't pass doubles in float registers on x86, so no need
-                // to check for argPassedInFloatReg.
-                masm.passABIArg(MoveOperand(argsBase, argDisp));
-                argDisp += sizeof(void *);
-                masm.passABIArg(MoveOperand(argsBase, argDisp));
-                argDisp += sizeof(void *);
-                break;
-              case VMFunction::WordByRef:
-                masm.passABIArg(MoveOperand(argsBase, argDisp, MoveOperand::EFFECTIVE));
-                argDisp += sizeof(void *);
-                break;
-              case VMFunction::DoubleByRef:
-                masm.passABIArg(MoveOperand(argsBase, argDisp, MoveOperand::EFFECTIVE));
-                argDisp += 2 * sizeof(void *);
-                break;
-            }
+    for (uint32_t explicitArg = 0; explicitArg < f.explicitArgs; explicitArg++) {
+        MoveOperand from;
+        switch (f.argProperties(explicitArg)) {
+          case VMFunction::WordByValue:
+            masm.passABIArg(MoveOperand(argsBase, argDisp), MoveOp::GENERAL);
+            argDisp += sizeof(void *);
+            break;
+          case VMFunction::DoubleByValue:
+            // We don't pass doubles in float registers on x86, so no need
+            // to check for argPassedInFloatReg.
+            masm.passABIArg(MoveOperand(argsBase, argDisp), MoveOp::GENERAL);
+            argDisp += sizeof(void *);
+            masm.passABIArg(MoveOperand(argsBase, argDisp), MoveOp::GENERAL);
+            argDisp += sizeof(void *);
+            break;
+          case VMFunction::WordByRef:
+            masm.passABIArg(MoveOperand(argsBase, argDisp, MoveOperand::EFFECTIVE_ADDRESS),
+                            MoveOp::GENERAL);
+            argDisp += sizeof(void *);
+            break;
+          case VMFunction::DoubleByRef:
+            masm.passABIArg(MoveOperand(argsBase, argDisp, MoveOperand::EFFECTIVE_ADDRESS),
+                            MoveOp::GENERAL);
+            argDisp += 2 * sizeof(void *);
+            break;
         }
     }
 
     // Copy the implicit outparam, if any.
     if (outReg != InvalidReg)
         masm.passABIArg(outReg);
 
     masm.callWithABI(f.wrapped);