[INFER] Add inline paths for typed arrays, bug 663485. r=bhackett
authorJan de Mooij <jandemooij@gmail.com>
Mon, 11 Jul 2011 19:28:58 +0200
changeset 76033 0a10e83c2b3ac3376b20935c5fd7289712c6fa55
parent 76032 1d31362c86ce19d0f7c76a1b890b7b3a9601263b
child 76034 b67c4240345870b7f65ba403a29468ab81ec59a5
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
reviewersbhackett
bugs663485
milestone8.0a1
[INFER] Add inline paths for typed arrays, bug 663485. r=bhackett
js/src/jit-test/tests/basic/testTypedArrayClamping.js
js/src/jit-test/tests/basic/testTypedArrayOutOfBounds.js
js/src/jit-test/tests/basic/testTypedArrayUint32.js
js/src/jit-test/tests/jaeger/bug663485.js
js/src/jstypedarray.cpp
js/src/jstypedarray.h
js/src/jstypedarrayinlines.h
js/src/methodjit/BaseAssembler.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/Compiler.h
js/src/methodjit/FastOps.cpp
js/src/methodjit/MachineRegs.h
js/src/methodjit/PolyIC.cpp
js/src/methodjit/TypedArrayIC.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/testTypedArrayClamping.js
@@ -0,0 +1,41 @@
+function f() {
+    var input = [];
+    var expected = [];
+
+    var add = function(inp, exp) {
+        input.push(inp);
+        expected.push(exp);
+    };
+
+    add(-0, 0);
+    add(-0.1, 0);
+    add(-0.7, 0);
+    add(0.1, 0);
+    add(NaN, 0);
+    add(-Infinity, 0);
+    add(Infinity, 255);
+    add(0.7, 1);
+    add(1.2, 1);
+    add(3.5, 4);
+    add(4.5, 4);
+    add(254.4, 254);
+    add(254.5, 254);
+    add(254.6, 255);
+    add(254.9, 255);
+    add(255.1, 255);
+    add(255.4, 255);
+    add(255.5, 255);
+    add(255.9, 255);
+
+    var len = input.length;
+    var a = new Uint8ClampedArray(len);
+
+    for (var i=0; i<len; i++) {
+        a[i] = input[i];
+    }
+    for (var i=0; i<len; i++) {
+        assertEq(a[i], expected[i], "Failed: " + input[i]);
+    }
+}
+f();
+f();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/testTypedArrayOutOfBounds.js
@@ -0,0 +1,33 @@
+function f1() {
+    var a = new Int32Array(50);
+    for (var i=0; i<100; i++) {
+        var x = a[i];
+        assertEq(typeof x, i < a.length ? "number" : "undefined");
+    }
+
+    var b = new Float32Array(50);
+    for (var i=0; i<100; i++) {
+        var x = b[i];
+        assertEq(typeof x, i < b.length ? "number" : "undefined");
+    }
+}
+f1();
+
+function f2() {
+    Object.prototype[50] = 4.4;
+    Object.prototype[55] = Math;
+
+    var a = new Int16Array(50);
+    for (var i=0; i<100; i++) {
+        var x = a[i];
+        if (i < a.length)
+            assertEq(x, 0);
+        else if (i === 50)
+            assertEq(x, 4.4);
+        else if (i === 55)
+            assertEq(x, Math);
+        else
+            assertEq(x, undefined);
+    }
+}
+f2();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/testTypedArrayUint32.js
@@ -0,0 +1,19 @@
+function f() {
+    var input = [0, 1, 2, 0x80000000, 0xfffffff0,
+                 0xffffffff, 0xffffffff + 1, 0xffffffff + 2,
+                 101];
+
+    var arr = new Uint32Array(input.length);
+    for (var i=0; i < arr.length; i++) {
+        arr[i] = input[i];
+    }
+
+    var expected = [0, 1, 2, 0x80000000, 0xfffffff0,
+                    0xffffffff, 0, 1, 101];
+    for (var i=0; i < arr.length; i++) {
+        assertEq(arr[i], expected[i]);
+    }
+}
+for (var i=0; i<5; i++) {
+    f();
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/jaeger/bug663485.js
@@ -0,0 +1,17 @@
+function makeExpectedMatch(arr) {
+    expectedMatch = {
+        x: arr.length
+    }
+}
+var expected = makeExpectedMatch(new Int32Array);
+this.toSource();
+
+function testTypedArrayOther() {
+    var ar = new Int32Array;
+    for (; i < ar; ++i) {
+        ar[i] = i;
+    }
+    for (var i = 0; i<40; i++) {
+    }
+}
+testTypedArrayOther();
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -1753,16 +1753,18 @@ do {                                    
     proto = js_InitClass(cx, obj, NULL,                                        \
                          &TypedArray::slowClasses[TypedArray::_type],          \
                          _typedArray::class_constructor, 3,                    \
                          _typedArray::jsprops,                                 \
                          _typedArray::jsfuncs,                                 \
                          NULL, NULL);                                          \
     if (!proto)                                                                \
         return NULL;                                                           \
+    jsid lengthId = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);           \
+    AddTypePropertyId(cx, proto->getType(), lengthId, types::TYPE_INT32);      \
     AddTypePropertyId(cx, proto->getType(), JSID_VOID, types::TYPE_INT32);     \
     if (_typedArray::ArrayElementTypeMayBeDouble())                            \
         AddTypePropertyId(cx, proto->getType(), JSID_VOID, types::TYPE_DOUBLE); \
     JSObject *ctor = JS_GetConstructor(cx, proto);                             \
     if (!ctor ||                                                               \
         !JS_DefineProperty(cx, ctor, "BYTES_PER_ELEMENT",                      \
                            INT_TO_JSVAL(sizeof(_typedArray::ThisType)),        \
                            JS_PropertyStub, JS_StrictPropertyStub,             \
--- a/js/src/jstypedarray.h
+++ b/js/src/jstypedarray.h
@@ -186,32 +186,36 @@ struct JS_FRIEND_API(TypedArray) {
     uint32 byteOffset;
     uint32 byteLength;
     uint32 length;
     uint32 type;
 
     void *data;
 
     inline int slotWidth() const {
-        switch (type) {
+        return slotWidth(type);
+    }
+
+    static inline uint32 slotWidth(int atype) {
+        switch (atype) {
           case js::TypedArray::TYPE_INT8:
           case js::TypedArray::TYPE_UINT8:
           case js::TypedArray::TYPE_UINT8_CLAMPED:
             return 1;
           case js::TypedArray::TYPE_INT16:
           case js::TypedArray::TYPE_UINT16:
             return 2;
           case js::TypedArray::TYPE_INT32:
           case js::TypedArray::TYPE_UINT32:
           case js::TypedArray::TYPE_FLOAT32:
             return 4;
           case js::TypedArray::TYPE_FLOAT64:
             return 8;
           default:
-            JS_NOT_REACHED("invalid typed array");
+            JS_NOT_REACHED("invalid typed array type");
             return 0;
         }
     }
 };
 
 } // namespace js
 
 /* Friend API methods */
--- a/js/src/jstypedarrayinlines.h
+++ b/js/src/jstypedarrayinlines.h
@@ -51,10 +51,20 @@ ArrayBuffer::getByteLength(JSObject *obj
     return obj->getFixedSlot(JSSLOT_ARRAY_BYTELENGTH).toPrivateUint32();
 }
 
 inline uint8 *
 ArrayBuffer::getDataOffset(JSObject *obj)
 {
     return (uint8 *) obj->getFixedSlot(JSSLOT_ARRAY_DATA).toPrivate();
 }
+
+static inline int32
+ClampIntForUint8Array(int32 x)
+{
+    if (x < 0)
+        return 0;
+    if (x > 255)
+        return 255;
+    return x;
+}
 }
 #endif /* jstypedarrayinlines_h */
--- a/js/src/methodjit/BaseAssembler.h
+++ b/js/src/methodjit/BaseAssembler.h
@@ -859,16 +859,258 @@ static const JSC::MacroAssembler::Regist
         if (shape->isMethod())
             loadValueAsComponents(ObjectValue(shape->methodObject()), typeReg, dataReg);
         else if (obj->isFixedSlot(shape->slot))
             loadInlineSlot(objReg, shape->slot, typeReg, dataReg);
         else
             loadDynamicSlot(objReg, obj->dynamicSlotIndex(shape->slot), typeReg, dataReg);
     }
 
+    // Load a value from a typed array's packed data vector into dataReg.
+    // This function expects the following combinations of typeReg, dataReg and tempReg:
+    // 1) for all INT arrays other than UINT32:
+    //    - dataReg is a GP-register
+    //    - typeReg is optional
+    //    - tempReg is not set
+    // 2) for UINT32:
+    //    - dataReg is either a FP-register or a GP-register
+    //    - typeReg is set if dataReg is a GP-register
+    //    - tempReg is set if dataReg is a FP-register
+    // 3) for FLOAT32 and FLOAT64:
+    //    - dataReg is either a FP-register or a GP-register
+    //    - typeReg is set if dataReg is a GP-register
+    //    - tempReg is not set
+    template <typename T>
+    void loadFromTypedArray(int atype, T address, MaybeRegisterID typeReg,
+                            AnyRegisterID dataReg, MaybeRegisterID tempReg)
+    {
+        // If dataReg is an FP-register we don't use typeReg.
+        JS_ASSERT_IF(dataReg.isFPReg(), !typeReg.isSet());
+
+        // We only need tempReg for Uint32Array and only if dataReg is an FP-register.
+        JS_ASSERT_IF(atype != js::TypedArray::TYPE_UINT32 || dataReg.isReg(), !tempReg.isSet());
+
+        switch (atype) {
+          case js::TypedArray::TYPE_INT8:
+            load8SignExtend(address, dataReg.reg());
+            if (typeReg.isSet())
+                move(ImmType(JSVAL_TYPE_INT32), typeReg.reg());
+            break;
+          case js::TypedArray::TYPE_UINT8:
+          case js::TypedArray::TYPE_UINT8_CLAMPED:
+            load8ZeroExtend(address, dataReg.reg());
+            if (typeReg.isSet())
+                move(ImmType(JSVAL_TYPE_INT32), typeReg.reg());
+            break;
+          case js::TypedArray::TYPE_INT16:
+            load16SignExtend(address, dataReg.reg());
+            if (typeReg.isSet())
+                move(ImmType(JSVAL_TYPE_INT32), typeReg.reg());
+            break;
+          case js::TypedArray::TYPE_UINT16:
+            load16(address, dataReg.reg());
+            if (typeReg.isSet())
+                move(ImmType(JSVAL_TYPE_INT32), typeReg.reg());
+            break;
+          case js::TypedArray::TYPE_INT32:
+            load32(address, dataReg.reg());
+            if (typeReg.isSet())
+                move(ImmType(JSVAL_TYPE_INT32), typeReg.reg());
+            break;
+          case js::TypedArray::TYPE_UINT32:
+          {
+            // For Uint32Array the result is either int32 or double.
+            // If dataReg is a GP-register, load a double or int32 into dataReg/typeReg.
+            // If dataReg is a FP-register, load the value as double.
+            if (dataReg.isReg()) {
+                load32(address, dataReg.reg());
+                move(ImmType(JSVAL_TYPE_INT32), typeReg.reg());
+                Jump safeInt = branch32(Assembler::Below, dataReg.reg(), Imm32(0x80000000));
+                convertUInt32ToDouble(dataReg.reg(), Registers::FPConversionTemp);
+                breakDouble(Registers::FPConversionTemp, typeReg.reg(), dataReg.reg());
+                safeInt.linkTo(label(), this);
+            } else {
+                load32(address, tempReg.reg());
+                convertUInt32ToDouble(tempReg.reg(), dataReg.fpreg());
+            }
+            break;
+          }
+          case js::TypedArray::TYPE_FLOAT32:
+          case js::TypedArray::TYPE_FLOAT64:
+          {
+            FPRegisterID fpreg = dataReg.isReg()
+                               ? Registers::FPConversionTemp
+                               : dataReg.fpreg();
+            if (atype == js::TypedArray::TYPE_FLOAT32)
+                loadFloat(address, fpreg);
+            else
+                loadDouble(address, fpreg);
+            // Make sure NaN gets canonicalized. If dataReg is not an FP-register
+            // we have to use loadStaticDouble as we were probably called from an
+            // IC and we can't use slowLoadConstantDouble.
+            Jump notNaN = branchDouble(Assembler::DoubleEqual, fpreg, fpreg);
+            if (dataReg.isReg())
+                loadStaticDouble(&js_NaN, Registers::FPConversionTemp, dataReg.reg());
+            else
+                slowLoadConstantDouble(js_NaN, fpreg);
+            notNaN.linkTo(label(), this);
+            if (dataReg.isReg())
+                breakDouble(Registers::FPConversionTemp, typeReg.reg(), dataReg.reg());
+            break;
+          }
+        }
+    }
+
+    void loadFromTypedArray(int atype, RegisterID objReg, Int32Key key,
+                            MaybeRegisterID typeReg, AnyRegisterID dataReg,
+                            MaybeRegisterID tempReg)
+    {
+        int shift = TypedArray::slotWidth(atype);
+
+        if (key.isConstant()) {
+            Address addr(objReg, key.index() * shift);
+            loadFromTypedArray(atype, addr, typeReg, dataReg, tempReg);
+        } else {
+            Assembler::Scale scale = Assembler::TimesOne;
+            switch (shift) {
+              case 2:
+                scale = Assembler::TimesTwo;
+                break;
+              case 4:
+                scale = Assembler::TimesFour;
+                break;
+              case 8:
+                scale = Assembler::TimesEight;
+                break;
+            }
+            BaseIndex addr(objReg, key.reg(), scale);
+            loadFromTypedArray(atype, addr, typeReg, dataReg, tempReg);
+        }
+    }
+
+    template <typename S, typename T>
+    void storeToTypedIntArray(int atype, S src, T address)
+    {
+        switch (atype) {
+          case js::TypedArray::TYPE_INT8:
+          case js::TypedArray::TYPE_UINT8:
+          case js::TypedArray::TYPE_UINT8_CLAMPED:
+            store8(src, address);
+            break;
+          case js::TypedArray::TYPE_INT16:
+          case js::TypedArray::TYPE_UINT16:
+            store16(src, address);
+            break;
+          case js::TypedArray::TYPE_INT32:
+          case js::TypedArray::TYPE_UINT32:
+            store32(src, address);
+            break;
+          default:
+            JS_NOT_REACHED("unknown int array type");
+        }
+    }
+
+    template <typename S, typename T>
+    void storeToTypedFloatArray(int atype, S src, T address)
+    {
+        if (atype == js::TypedArray::TYPE_FLOAT32)
+            storeFloat(src, address);
+        else
+            storeDouble(src, address);
+    }
+
+    template <typename T>
+    void storeToTypedArray(int atype, ValueRemat vr, T address)
+    {
+        if (atype == js::TypedArray::TYPE_FLOAT32 || atype == js::TypedArray::TYPE_FLOAT64) {
+            if (vr.isConstant())
+                storeToTypedFloatArray(atype, ImmDouble(vr.value().toDouble()), address);
+            else
+                storeToTypedFloatArray(atype, vr.fpReg(), address);
+        } else {
+            if (vr.isConstant())
+                storeToTypedIntArray(atype, Imm32(vr.value().toInt32()), address);
+            else
+                storeToTypedIntArray(atype, vr.dataReg(), address);
+        }
+    }
+
+    void storeToTypedArray(int atype, RegisterID objReg, Int32Key key, ValueRemat vr)
+    {
+        int shift = TypedArray::slotWidth(atype);
+        if (key.isConstant()) {
+            Address addr(objReg, key.index() * shift);
+            storeToTypedArray(atype, vr, addr);
+        } else {
+            Assembler::Scale scale = Assembler::TimesOne;
+            switch (shift) {
+            case 2:
+                scale = Assembler::TimesTwo;
+                break;
+            case 4:
+                scale = Assembler::TimesFour;
+                break;
+            case 8:
+                scale = Assembler::TimesEight;
+                break;
+            }
+            BaseIndex addr(objReg, key.reg(), scale);
+            storeToTypedArray(atype, vr, addr);
+        }
+    }
+
+    void clampInt32ToUint8(RegisterID reg)
+    {
+        Jump j = branch32(Assembler::GreaterThanOrEqual, reg, Imm32(0));
+        move(Imm32(0), reg);
+        Jump done = jump();
+        j.linkTo(label(), this);
+        j = branch32(Assembler::LessThanOrEqual, reg, Imm32(255));
+        move(Imm32(255), reg);
+        j.linkTo(label(), this);
+        done.linkTo(label(), this);
+    }
+
+    // Inline version of js_TypedArray_uint8_clamp_double.
+    void clampDoubleToUint8(FPRegisterID fpReg, FPRegisterID fpTemp, RegisterID reg)
+    {
+        JS_ASSERT(fpTemp != Registers::FPConversionTemp);
+
+        // <= 0 or NaN ==> 0
+        zeroDouble(fpTemp);
+        Jump positive = branchDouble(Assembler::DoubleGreaterThan, fpReg, fpTemp);
+        move(Imm32(0), reg);
+        Jump done1 = jump();
+
+        // Add 0.5 and truncate.
+        positive.linkTo(label(), this);
+        slowLoadConstantDouble(0.5, fpTemp);
+        addDouble(fpReg, fpTemp);
+        Jump notInt = branchTruncateDoubleToInt32(fpTemp, reg);
+
+        // > 255 ==> 255
+        Jump inRange = branch32(Assembler::BelowOrEqual, reg, Imm32(255));
+        notInt.linkTo(label(), this);
+        move(Imm32(255), reg);
+        Jump done2 = jump();
+
+        // Check if we had a tie.
+        inRange.linkTo(label(), this);
+        convertInt32ToDouble(reg, Registers::FPConversionTemp);
+        Jump done3 = branchDouble(Assembler::DoubleNotEqual, fpTemp, Registers::FPConversionTemp);
+
+        // It was a tie. Mask out the ones bit to get an even value.
+        // See js_TypedArray_uint8_clamp_double for the reasoning behind this.
+        and32(Imm32(~1), reg);
+
+        done1.linkTo(label(), this);
+        done2.linkTo(label(), this);
+        done3.linkTo(label(), this);
+    }
+
     Address objPropAddress(JSObject *obj, RegisterID objReg, uint32 slot)
     {
         if (obj->isFixedSlot(slot))
             return Address(objReg, JSObject::getFixedSlotOffset(slot));
         loadPtr(Address(objReg, JSObject::offsetOfSlots()), objReg);
         return Address(objReg, obj->dynamicSlotIndex(slot) * sizeof(Value));
     }
 
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -4208,16 +4208,38 @@ mjit::Compiler::jsop_getprop(JSAtom *ato
             frame.pop();
             frame.push(Address(reg, offsetof(JSObject, privateData)), JSVAL_TYPE_INT32);
             if (!isObject)
                 stubcc.rejoin(Changes(1));
             return true;
         }
 
         /*
+         * Check if we're accessing the 'length' property of a typed array.
+         * The typed array length always fits in an int32.
+         */
+        if (!types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_TYPED_ARRAY)) {
+            bool isObject = top->isTypeKnown();
+            if (!isObject) {
+                Jump notObject = frame.testObject(Assembler::NotEqual, top);
+                stubcc.linkExit(notObject, Uses(1));
+                stubcc.leave();
+                OOL_STUBCALL(stubs::GetProp, rejoin);
+            }
+            RegisterID reg = frame.copyDataIntoReg(top);
+            masm.loadPtr(Address(reg, offsetof(JSObject, privateData)), reg);
+            frame.pop();
+            frame.push(Address(reg, TypedArray::lengthOffset()), JSVAL_TYPE_INT32);
+            frame.freeReg(reg);
+            if (!isObject)
+                stubcc.rejoin(Changes(1));
+            return true;
+        }
+
+        /*
          * Check if we are accessing the 'length' of the lazy arguments for the
          * current frame. No actual arguments object has ever been constructed
          * for the script, so we can go straight to nactual.
          */
         if (types->isLazyArguments(cx)) {
             frame.pop();
             frame.push(Address(JSFrameReg, StackFrame::offsetOfArgs()), JSVAL_TYPE_INT32);
             return true;
--- a/js/src/methodjit/Compiler.h
+++ b/js/src/methodjit/Compiler.h
@@ -700,20 +700,23 @@ class Compiler : public BaseCompiler
     bool jsop_andor(JSOp op, jsbytecode *target);
     bool jsop_arginc(JSOp op, uint32 slot);
     bool jsop_localinc(JSOp op, uint32 slot);
     bool jsop_newinit();
     void jsop_initmethod();
     void jsop_initprop();
     void jsop_initelem();
     void jsop_setelem_dense();
+    void jsop_setelem_typed(int atype);
+    void convertForTypedArray(int atype, ValueRemat *vr, bool *allocated);
     bool jsop_setelem(bool popGuaranteed);
     bool jsop_getelem(bool isCall);
     void jsop_getelem_dense(bool isPacked);
     void jsop_getelem_args();
+    void jsop_getelem_typed(int atype);
     bool isCacheableBaseAndIndex(FrameEntry *obj, FrameEntry *id);
     void jsop_stricteq(JSOp op);
     bool jsop_equality(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
     bool jsop_equality_int_string(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
     void jsop_pos();
 
     static inline Assembler::Condition
     GetCompareCondition(JSOp op, JSOp fused)
--- a/js/src/methodjit/FastOps.cpp
+++ b/js/src/methodjit/FastOps.cpp
@@ -40,16 +40,17 @@
 #include "jsbool.h"
 #include "jscntxt.h"
 #include "jsemit.h"
 #include "jslibmath.h"
 #include "jsnum.h"
 #include "jsscope.h"
 #include "jsobjinlines.h"
 #include "jsscriptinlines.h"
+#include "jstypedarrayinlines.h"
 
 #include "methodjit/MethodJIT.h"
 #include "methodjit/Compiler.h"
 #include "methodjit/StubCalls.h"
 #include "methodjit/FrameState-inl.h"
 
 #include "jsautooplen.h"
 
@@ -1188,40 +1189,260 @@ mjit::Compiler::jsop_setelem_dense()
     OOL_STUBCALL(STRICT_VARIANT(stubs::SetElem), REJOIN_FALLTHROUGH);
 
     if (!hoisted)
         frame.freeReg(slotsReg);
     frame.shimmy(2);
     stubcc.rejoin(Changes(2));
 }
 
+void
+mjit::Compiler::convertForTypedArray(int atype, ValueRemat *vr, bool *allocated)
+{
+    FrameEntry *value = frame.peek(-1);
+    bool floatArray = (atype == TypedArray::TYPE_FLOAT32 ||
+                       atype == TypedArray::TYPE_FLOAT64);
+    *allocated = false;
+
+    if (value->isConstant()) {
+        Value v = value->getValue();
+        if (floatArray) {
+            double d = v.isDouble() ? v.toDouble() : v.toInt32();
+            *vr = ValueRemat::FromConstant(DoubleValue(d));
+        } else {
+            int i32;
+            if (v.isInt32()) {
+                i32 = v.toInt32();
+                if (atype == TypedArray::TYPE_UINT8_CLAMPED)
+                    i32 = ClampIntForUint8Array(i32);
+            } else {
+                i32 = (atype == TypedArray::TYPE_UINT8_CLAMPED)
+                    ? js_TypedArray_uint8_clamp_double(v.toDouble())
+                    : js_DoubleToECMAInt32(v.toDouble());
+            }
+            *vr = ValueRemat::FromConstant(Int32Value(i32));
+        }
+    } else {
+        if (floatArray) {
+            FPRegisterID fpReg;
+            MaybeJump notNumber = loadDouble(value, &fpReg, allocated);
+            if (notNumber.isSet())
+                stubcc.linkExit(notNumber.get(), Uses(3));
+
+            if (atype == TypedArray::TYPE_FLOAT32) {
+                if (!*allocated) {
+                    frame.pinReg(fpReg);
+                    FPRegisterID newFpReg = frame.allocFPReg();
+                    masm.convertDoubleToFloat(fpReg, newFpReg);
+                    frame.unpinReg(fpReg);
+                    fpReg = newFpReg;
+                    *allocated = true;
+                } else {
+                    masm.convertDoubleToFloat(fpReg, fpReg);
+                }
+            }
+            *vr = ValueRemat::FromFPRegister(fpReg);
+        } else {
+            /*
+             * Allocate a register with the following properties:
+             * 1) For byte arrays the value must be in a byte register.
+             * 2) For Uint8ClampedArray the register must be writable.
+             * 3) If the value is definitely int32 (and the array is not
+             *    Uint8ClampedArray) we don't have to allocate a new register.
+             */
+            MaybeRegisterID reg;
+            bool needsByteReg = (atype == TypedArray::TYPE_INT8 ||
+                                 atype == TypedArray::TYPE_UINT8 ||
+                                 atype == TypedArray::TYPE_UINT8_CLAMPED);
+            if (!value->isType(JSVAL_TYPE_INT32) || atype == TypedArray::TYPE_UINT8_CLAMPED) {
+                // x86 has 4 single byte registers. Worst case we've pinned 3
+                // registers, one for each of object, key and value. This means
+                // there must be at least one single byte register available.
+                if (needsByteReg)
+                    reg = frame.allocReg(Registers::SingleByteRegs).reg();
+                else
+                    reg = frame.allocReg();
+                *allocated = true;
+            } else {
+                if (needsByteReg)
+                    reg = frame.tempRegInMaskForData(value, Registers::SingleByteRegs).reg();
+                else
+                    reg = frame.tempRegForData(value);
+            }
+
+            MaybeJump intDone;
+            if (value->mightBeType(JSVAL_TYPE_INT32)) {
+                // Check if the value is an integer.
+                MaybeJump notInt;
+                if (!value->isTypeKnown()) {
+                    JS_ASSERT(*allocated);
+                    notInt = frame.testInt32(Assembler::NotEqual, value);
+                }
+
+                if (*allocated)
+                    masm.move(frame.tempRegForData(value), reg.reg());
+
+                if (atype == TypedArray::TYPE_UINT8_CLAMPED)
+                    masm.clampInt32ToUint8(reg.reg());
+
+                if (notInt.isSet()) {
+                    intDone = masm.jump();
+                    notInt.get().linkTo(masm.label(), &masm);
+                }
+            }
+            if (value->mightBeType(JSVAL_TYPE_DOUBLE)) {
+                // Check if the value is a double.
+                if (!value->isTypeKnown()) {
+                    Jump notNumber = frame.testDouble(Assembler::NotEqual, value);
+                    stubcc.linkExit(notNumber, Uses(3));
+                }
+
+                // Load value in fpReg.
+                FPRegisterID fpReg;
+                if (value->isTypeKnown()) {
+                    fpReg = frame.tempFPRegForData(value);
+                } else {
+                    fpReg = frame.allocFPReg();
+                    frame.loadDouble(value, fpReg, masm);
+                }
+
+                // Convert double to integer.
+                if (atype == TypedArray::TYPE_UINT8_CLAMPED) {
+                    if (value->isTypeKnown())
+                        frame.pinReg(fpReg);
+                    FPRegisterID fpTemp = frame.allocFPReg();
+                    if (value->isTypeKnown())
+                        frame.unpinReg(fpReg);
+                    masm.clampDoubleToUint8(fpReg, fpTemp, reg.reg());
+                    frame.freeReg(fpTemp);
+                } else {
+                    Jump j = masm.branchTruncateDoubleToInt32(fpReg, reg.reg());
+                    stubcc.linkExit(j, Uses(3));
+                }
+                if (!value->isTypeKnown())
+                    frame.freeReg(fpReg);
+            }
+            if (intDone.isSet())
+                intDone.get().linkTo(masm.label(), &masm);
+            *vr = ValueRemat::FromKnownType(JSVAL_TYPE_INT32, reg.reg());
+        }
+    }
+}
+void
+mjit::Compiler::jsop_setelem_typed(int atype)
+{
+    FrameEntry *obj = frame.peek(-3);
+    FrameEntry *id = frame.peek(-2);
+    FrameEntry *value = frame.peek(-1);
+
+    // We might not know whether this is an object, but if it is an object we
+    // know it's a typed array.
+    if (!obj->isTypeKnown()) {
+        Jump guard = frame.testObject(Assembler::NotEqual, obj);
+        stubcc.linkExit(guard, Uses(3));
+    }
+
+    // Test for integer index.
+    if (!id->isTypeKnown()) {
+        Jump guard = frame.testInt32(Assembler::NotEqual, id);
+        stubcc.linkExit(guard, Uses(3));
+    }
+
+    // Pin value. We don't use pinEntry here because it may also
+    // pin a type register and convertForTypedArray assumes we've
+    // pinned at most 3 registers (object, key and value).
+    MaybeRegisterID dataReg;
+    if (value->mightBeType(JSVAL_TYPE_INT32) && !value->isConstant()) {
+        dataReg = frame.tempRegForData(value);
+        frame.pinReg(dataReg.reg());
+    }
+
+    // Allocate and pin object and key regs.
+    Int32Key key = id->isConstant()
+                 ? Int32Key::FromConstant(id->getValue().toInt32())
+                 : Int32Key::FromRegister(frame.tempRegForData(id));
+
+    JS_ASSERT_IF(frame.haveSameBacking(id, value), dataReg.isSet());
+    bool pinKey = !key.isConstant() && !frame.haveSameBacking(id, value);
+    if (pinKey)
+        frame.pinReg(key.reg());
+    RegisterID objReg = frame.copyDataIntoReg(obj);
+
+    // Get the internal typed array.
+    masm.loadPtr(Address(objReg, offsetof(JSObject, privateData)), objReg);
+
+    // Bounds check.
+    Jump lengthGuard = masm.guardArrayExtent(TypedArray::lengthOffset(),
+                                             objReg, key, Assembler::BelowOrEqual);
+    stubcc.linkExit(lengthGuard, Uses(3));
+
+    // Load the array's packed data vector.
+    masm.loadPtr(Address(objReg, js::TypedArray::dataOffset()), objReg);
+
+    // Convert the value.
+    bool allocated;
+    ValueRemat vr;
+    convertForTypedArray(atype, &vr, &allocated);
+    if (dataReg.isSet())
+        frame.unpinReg(dataReg.reg());
+
+    // Store the value.
+    masm.storeToTypedArray(atype, objReg, key, vr);
+    if (allocated) {
+        if (vr.isFPRegister())
+            frame.freeReg(vr.fpReg());
+        else
+            frame.freeReg(vr.dataReg());
+    }
+    if (pinKey)
+        frame.unpinReg(key.reg());
+    frame.freeReg(objReg);
+
+    stubcc.leave();
+    OOL_STUBCALL(STRICT_VARIANT(stubs::SetElem), REJOIN_FALLTHROUGH);
+
+    frame.shimmy(2);
+    stubcc.rejoin(Changes(2));
+}
+
 bool
 mjit::Compiler::jsop_setelem(bool popGuaranteed)
 {
     FrameEntry *obj = frame.peek(-3);
     FrameEntry *id = frame.peek(-2);
     FrameEntry *value = frame.peek(-1);
 
     if (!IsCacheableSetElem(obj, id, value) || monitored(PC)) {
         jsop_setelem_slow();
         return true;
     }
 
     frame.forgetMismatchedObject(obj);
 
-    if (cx->typeInferenceEnabled()) {
+    // If the object is definitely a dense array or a typed array we can generate
+    // code directly without using an inline cache.
+    if (cx->typeInferenceEnabled() && id->mightBeType(JSVAL_TYPE_INT32)) {
         types::TypeSet *types = analysis->poppedTypes(PC, 2);
-        if (id->mightBeType(JSVAL_TYPE_INT32) &&
-            !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY) &&
+
+        if (!types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY) &&
             !arrayPrototypeHasIndexedProperty()) {
-            // This is definitely a dense array, generate code directly without
-            // using an inline cache.
+            // Inline dense array path.
             jsop_setelem_dense();
             return true;
         }
+        if (!types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_TYPED_ARRAY) &&
+            (value->mightBeType(JSVAL_TYPE_INT32) || value->mightBeType(JSVAL_TYPE_DOUBLE))) {
+            // Inline typed array path. Look at the proto to determine the typed array type.
+            if (types::TypeObject *objType = types->getSingleObject()) {
+                int atype = objType->proto->getClass() - TypedArray::slowClasses;
+                JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX);
+                jsop_setelem_typed(atype);
+                return true;
+            }
+        }
     }
 
     SetElementICInfo ic = SetElementICInfo(JSOp(*PC));
 
     // One by one, check if the most important stack entries have registers,
     // and if so, pin them. This is to avoid spilling and reloading from the
     // stack as we incrementally allocate other registers.
     MaybeRegisterID pinnedValueType = frame.maybePinType(value);
@@ -1588,45 +1809,154 @@ mjit::Compiler::jsop_getelem_args()
     frame.pushRegs(typeReg, dataReg, knownPushedType(0));
     BarrierState barrier = testBarrier(typeReg, dataReg, false);
 
     stubcc.rejoin(Changes(2));
 
     finishBarrier(barrier, REJOIN_FALLTHROUGH, 0);
 }
 
+void
+mjit::Compiler::jsop_getelem_typed(int atype)
+{
+    FrameEntry *obj = frame.peek(-2);
+    FrameEntry *id = frame.peek(-1);
+
+    // We might not know whether this is an object, but if it's an object we
+    // know it is a typed array.
+    if (!obj->isTypeKnown()) {
+        Jump guard = frame.testObject(Assembler::NotEqual, obj);
+        stubcc.linkExit(guard, Uses(2));
+    }
+
+    // Test for integer index.
+    if (!id->isTypeKnown()) {
+        Jump guard = frame.testInt32(Assembler::NotEqual, id);
+        stubcc.linkExit(guard, Uses(2));
+    }
+
+    // Load object and key.
+    Int32Key key = id->isConstant()
+                 ? Int32Key::FromConstant(id->getValue().toInt32())
+                 : Int32Key::FromRegister(frame.tempRegForData(id));
+    if (!key.isConstant())
+        frame.pinReg(key.reg());
+    RegisterID objReg = frame.copyDataIntoReg(obj);
+
+    // We can load directly into an FP-register if the following conditions
+    // are met:
+    // 1) The array is an Uint32Array or a float array (loadFromTypedArray
+    //    can't load into an FP-register for other arrays).
+    // 2) The result is definitely a double (the result type set can include
+    //    other types after reading out-of-bound values).
+    // 3) There's no type barrier (we need separate type and data regs for
+    //    type barriers).
+    AnyRegisterID dataReg;
+    MaybeRegisterID typeReg, tempReg;
+    JSValueType type = knownPushedType(0);
+    bool maybeReadFloat = (atype == TypedArray::TYPE_FLOAT32 ||
+                           atype == TypedArray::TYPE_FLOAT64 ||
+                           atype == TypedArray::TYPE_UINT32);
+    if (maybeReadFloat && type == JSVAL_TYPE_DOUBLE && !hasTypeBarriers(PC)) {
+        dataReg = frame.allocFPReg();
+        // Need an extra reg to convert uint32 to double.
+        if (atype == TypedArray::TYPE_UINT32)
+            tempReg = frame.allocReg();
+    } else {
+        dataReg = frame.allocReg();
+        // loadFromTypedArray expects a type register for Uint32Array or
+        // float arrays. Also allocate a type register if the result may not
+        // be int32 (due to reading out-of-bound values) or if there's a
+        // type barrier.
+        if (maybeReadFloat || type != JSVAL_TYPE_INT32 || hasTypeBarriers(PC))
+            typeReg = frame.allocReg();
+    }
+
+    // Get the internal typed array.
+    masm.loadPtr(Address(objReg, offsetof(JSObject, privateData)), objReg);
+
+    // Bounds check.
+    Jump lengthGuard = masm.guardArrayExtent(TypedArray::lengthOffset(),
+                                             objReg, key, Assembler::BelowOrEqual);
+    stubcc.linkExit(lengthGuard, Uses(2));
+
+    // Load the array's packed data vector.
+    masm.loadPtr(Address(objReg, js::TypedArray::dataOffset()), objReg);
+
+    // Load value from the array.
+    masm.loadFromTypedArray(atype, objReg, key, typeReg, dataReg, tempReg);
+
+    frame.freeReg(objReg);
+    if (!key.isConstant())
+        frame.unpinReg(key.reg());
+    if (tempReg.isSet())
+        frame.freeReg(tempReg.reg());
+
+    stubcc.leave();
+    OOL_STUBCALL(stubs::GetElem, REJOIN_FALLTHROUGH);
+
+    frame.popn(2);
+
+    BarrierState barrier;
+    if (dataReg.isFPReg()) {
+        frame.pushDouble(dataReg.fpreg());
+    } else if (typeReg.isSet()) {
+        frame.pushRegs(typeReg.reg(), dataReg.reg(), knownPushedType(0));
+        if (hasTypeBarriers(PC))
+            barrier = testBarrier(typeReg.reg(), dataReg.reg(), false);
+    } else {
+        JS_ASSERT(type == JSVAL_TYPE_INT32);
+        frame.pushTypedPayload(JSVAL_TYPE_INT32, dataReg.reg());
+    }
+    stubcc.rejoin(Changes(2));
+
+    finishBarrier(barrier, REJOIN_FALLTHROUGH, 0);
+}
+
 bool
 mjit::Compiler::jsop_getelem(bool isCall)
 {
     FrameEntry *obj = frame.peek(-2);
     FrameEntry *id = frame.peek(-1);
 
     if (!IsCacheableGetElem(obj, id)) {
         if (isCall)
             jsop_callelem_slow();
         else
             jsop_getelem_slow();
         return true;
     }
 
+    // If the object is definitely an arguments object, a dense array or a typed array
+    // we can generate code directly without using an inline cache.
     if (cx->typeInferenceEnabled() && id->mightBeType(JSVAL_TYPE_INT32) && !isCall) {
         types::TypeSet *types = analysis->poppedTypes(PC, 1);
         if (types->isLazyArguments(cx) && !outerScript->analysis(cx)->modifiesArguments()) {
+            // Inline arguments path.
             jsop_getelem_args();
             return true;
         }
         if (obj->mightBeType(JSVAL_TYPE_OBJECT) &&
             !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY) &&
             !arrayPrototypeHasIndexedProperty()) {
-            // this is definitely a dense array, generate code directly without
-            // using an inline cache.
+            // Inline dense array path.
             bool packed = !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_PACKED_ARRAY);
             jsop_getelem_dense(packed);
             return true;
         }
+        if (obj->mightBeType(JSVAL_TYPE_OBJECT) &&
+            !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_TYPED_ARRAY)) {
+            // Inline typed array path. Look at the proto to determine the typed array type.
+            if (types::TypeObject *objType = types->getSingleObject()) {
+                int atype = objType->proto->getClass() - TypedArray::slowClasses;
+                JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX);
+                jsop_getelem_typed(atype);
+                return true;
+            }
+        }
     }
 
     frame.forgetMismatchedObject(obj);
 
     GetElementICInfo ic = GetElementICInfo(JSOp(*PC));
 
     // Pin the top of the stack to avoid spills, before allocating registers.
     MaybeRegisterID pinnedIdData = frame.maybePinData(id);
--- a/js/src/methodjit/MachineRegs.h
+++ b/js/src/methodjit/MachineRegs.h
@@ -68,18 +68,19 @@ struct AnyRegisterID {
         : reg_(JSC::MacroAssembler::TotalRegisters + (unsigned)reg)
     { pin(); }
 
     static inline AnyRegisterID fromRaw(unsigned reg);
 
     inline JSC::MacroAssembler::RegisterID reg();
     inline JSC::MacroAssembler::FPRegisterID fpreg();
 
+    bool isSet() { return reg_ != unsigned(-1); }
     bool isReg() { return reg_ < JSC::MacroAssembler::TotalRegisters; }
-    bool isSet() { return reg_ != unsigned(-1); }
+    bool isFPReg() { return isSet() && !isReg(); }
 
     inline const char * name();
 
   private:
     unsigned * pin() {
         /*
          * Workaround for apparent compiler bug in GCC 4.2. If GCC thinks that reg_
          * cannot escape then it compiles isReg() and other accesses to reg_ incorrectly.
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -2455,38 +2455,23 @@ GetElementIC::attachTypedArray(JSContext
         outOfBounds = masm.branch32(Assembler::BelowOrEqual, typedArrayLength, Imm32(v.toInt32()));
     } else {
         outOfBounds = masm.branch32(Assembler::BelowOrEqual, typedArrayLength, idRemat.dataReg());
     }
 
     // Load the array's packed data vector.
     masm.loadPtr(Address(objReg, js::TypedArray::dataOffset()), objReg);
 
+    Int32Key key = idRemat.isConstant()
+                 ? Int32Key::FromConstant(v.toInt32())
+                 : Int32Key::FromRegister(idRemat.dataReg());
+
     js::TypedArray *tarray = js::TypedArray::fromJSObject(obj);
-    int shift = tarray->slotWidth();
-    if (idRemat.isConstant()) {
-        int32 index = v.toInt32();
-        Address addr(objReg, index * shift);
-        LoadFromTypedArray(masm, tarray, addr, typeReg, objReg);
-    } else {
-        Assembler::Scale scale = Assembler::TimesOne;
-        switch (shift) {
-          case 2:
-            scale = Assembler::TimesTwo;
-            break;
-          case 4:
-            scale = Assembler::TimesFour;
-            break;
-          case 8:
-            scale = Assembler::TimesEight;
-            break;
-        }
-        BaseIndex addr(objReg, idRemat.dataReg(), scale);
-        LoadFromTypedArray(masm, tarray, addr, typeReg, objReg);
-    }
+    MaybeRegisterID tempReg;
+    masm.loadFromTypedArray(tarray->type, objReg, key, typeReg, objReg, tempReg);
 
     Jump done = masm.jump();
 
     PICLinker buffer(masm, *this);
     if (!buffer.init(cx))
         return error(cx);
 
     if (!buffer.verifyRange(cx->fp()->jit()))
--- a/js/src/methodjit/TypedArrayIC.h
+++ b/js/src/methodjit/TypedArrayIC.h
@@ -37,86 +37,31 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef js_typedarray_ic_h___
 #define js_typedarray_ic_h___
 
 #include "jscntxt.h"
 #include "jstypedarray.h"
+#include "jstypedarrayinlines.h"
 
 #include "jsnuminlines.h"
 
 namespace js {
 namespace mjit {
 
 #ifdef JS_POLYIC_TYPED_ARRAY
 
 typedef JSC::MacroAssembler::RegisterID RegisterID;
 typedef JSC::MacroAssembler::FPRegisterID FPRegisterID;
 typedef JSC::MacroAssembler::Jump Jump;
 typedef JSC::MacroAssembler::Imm32 Imm32;
 typedef JSC::MacroAssembler::ImmDouble ImmDouble;
 
-template <typename T>
-static void
-LoadFromTypedArray(Assembler &masm, js::TypedArray *tarray, T address,
-                   RegisterID typeReg, RegisterID dataReg)
-{
-    switch (tarray->type) {
-      case js::TypedArray::TYPE_INT8:
-        masm.load8SignExtend(address, dataReg);
-        masm.move(ImmType(JSVAL_TYPE_INT32), typeReg);
-        break;
-      case js::TypedArray::TYPE_UINT8:
-      case js::TypedArray::TYPE_UINT8_CLAMPED:
-        masm.load8ZeroExtend(address, dataReg);
-        masm.move(ImmType(JSVAL_TYPE_INT32), typeReg);
-        break;
-      case js::TypedArray::TYPE_INT16:
-        masm.load16SignExtend(address, dataReg);
-        masm.move(ImmType(JSVAL_TYPE_INT32), typeReg);
-        break;
-      case js::TypedArray::TYPE_UINT16:
-        masm.load16(address, dataReg);
-        masm.move(ImmType(JSVAL_TYPE_INT32), typeReg);
-        break;
-      case js::TypedArray::TYPE_INT32:
-        masm.load32(address, dataReg);
-        masm.move(ImmType(JSVAL_TYPE_INT32), typeReg);
-        break;
-      case js::TypedArray::TYPE_UINT32:
-      {
-        masm.load32(address, dataReg);
-        masm.move(ImmType(JSVAL_TYPE_INT32), typeReg);
-        Jump safeInt = masm.branch32(Assembler::Below, dataReg, Imm32(0x80000000));
-        masm.convertUInt32ToDouble(dataReg, Registers::FPConversionTemp);
-        masm.breakDouble(Registers::FPConversionTemp, typeReg, dataReg);
-        safeInt.linkTo(masm.label(), &masm);
-        break;
-      }
-      case js::TypedArray::TYPE_FLOAT32:
-      case js::TypedArray::TYPE_FLOAT64:
-      {
-        if (tarray->type == js::TypedArray::TYPE_FLOAT32)
-            masm.loadFloat(address, Registers::FPConversionTemp);
-        else
-            masm.loadDouble(address, Registers::FPConversionTemp);
-        // Make sure NaN gets canonicalized.
-        Jump notNaN = masm.branchDouble(Assembler::DoubleEqual,
-                                        Registers::FPConversionTemp,
-                                        Registers::FPConversionTemp);
-        masm.loadStaticDouble(&js_NaN, Registers::FPConversionTemp, dataReg);
-        notNaN.linkTo(masm.label(), &masm);
-        masm.breakDouble(Registers::FPConversionTemp, typeReg, dataReg);
-        break;
-      }
-    }
-}
-
 static inline bool
 ConstantFoldForFloatArray(JSContext *cx, ValueRemat *vr)
 {
     if (!vr->isTypeKnown())
         return true;
 
     // Objects and undefined coerce to NaN, which coerces to 0.
     // Null converts to 0.
@@ -147,26 +92,16 @@ ConstantFoldForFloatArray(JSContext *cx,
         d = v.toInt32();
     } else {
         JS_NOT_REACHED("unknown constant type");
     }
     *vr = ValueRemat::FromConstant(DoubleValue(d));
     return true;
 }
 
-static inline int32
-ClampIntForUint8Array(int32 x)
-{
-    if (x < 0)
-        return 0;
-    if (x > 255)
-        return 255;
-    return x;
-}
-
 static inline bool
 ConstantFoldForIntArray(JSContext *cx, js::TypedArray *tarray, ValueRemat *vr)
 {
     if (!vr->isTypeKnown())
         return true;
 
     // Objects and undefined coerce to NaN, which coerces to 0.
     // Null converts to 0.
@@ -204,49 +139,16 @@ ConstantFoldForIntArray(JSContext *cx, j
         JS_NOT_REACHED("unknown constant type");
     }
 
     *vr = ValueRemat::FromConstant(Int32Value(i32));
 
     return true;
 }
 
-template <typename S, typename T>
-static void
-StoreToIntArray(Assembler &masm, js::TypedArray *tarray, S src, T address)
-{
-    switch (tarray->type) {
-      case js::TypedArray::TYPE_INT8:
-      case js::TypedArray::TYPE_UINT8:
-      case js::TypedArray::TYPE_UINT8_CLAMPED:
-        masm.store8(src, address);
-        break;
-      case js::TypedArray::TYPE_INT16:
-      case js::TypedArray::TYPE_UINT16:
-        masm.store16(src, address);
-        break;
-      case js::TypedArray::TYPE_INT32:
-      case js::TypedArray::TYPE_UINT32:
-        masm.store32(src, address);
-        break;
-      default:
-        JS_NOT_REACHED("unknown int array type");
-    }
-}
-
-template <typename S, typename T>
-static void
-StoreToFloatArray(Assembler &masm, js::TypedArray *tarray, S src, T address)
-{
-    if (tarray->type == js::TypedArray::TYPE_FLOAT32)
-        masm.storeFloat(src, address);
-    else
-        masm.storeDouble(src, address);
-}
-
 // Generate code that will ensure a dynamically typed value, pinned in |vr|,
 // can be stored in an integer typed array. If any sort of conversion is
 // required, |dataReg| will be clobbered by a new value. |saveMask| is
 // used to ensure that |dataReg| (and volatile registers) are preserved
 // across any conversion process.
 static void
 GenConversionForIntArray(Assembler &masm, js::TypedArray *tarray, const ValueRemat &vr,
                          uint32 saveMask)
@@ -288,36 +190,18 @@ GenConversionForIntArray(Assembler &masm
         saveForCall.restore();
         masm.freeStack(vp);
 
         if (checkInt32.isSet())
             checkInt32.get().linkTo(masm.label(), &masm);
     }
 
     // Performing clamping, if needed.
-    if (tarray->type == js::TypedArray::TYPE_UINT8_CLAMPED) {
-        //     cmp dr, 0
-        //     jge _min
-        //     mov dr, 0
-        //     jump _done
-        // _min:
-        //     cmp dr, 255
-        //     jle _done
-        //     mov dr, 255
-        // _done:
-        //
-        Jump j = masm.branch32(Assembler::GreaterThanOrEqual, vr.dataReg(), Imm32(0));
-        masm.move(Imm32(0), vr.dataReg());
-        Jump done = masm.jump();
-        j.linkTo(masm.label(), &masm);
-        j = masm.branch32(Assembler::LessThanOrEqual, vr.dataReg(), Imm32(255));
-        masm.move(Imm32(255), vr.dataReg());
-        j.linkTo(masm.label(), &masm);
-        done.linkTo(masm.label(), &masm);
-    }
+    if (tarray->type == js::TypedArray::TYPE_UINT8_CLAMPED)
+        masm.clampInt32ToUint8(vr.dataReg());
 }
 
 // Generate code that will ensure a dynamically typed value, pinned in |vr|,
 // can be stored in an integer typed array.  saveMask| is used to ensure that
 // |dataReg| (and volatile registers) are preserved across any conversion
 // process.
 //
 // Constants are left untouched. Any other value is placed into destReg.
@@ -508,19 +392,19 @@ StoreToTypedArray(JSContext *cx, Assembl
 
         GenConversionForIntArray(masm, tarray, vr, saveMask);
 
         // Restore the registers in |address|. |GenConversionForIntArray| won't
         // restore them because we told it not to by fiddling with |saveMask|.
         saveLHS.restore();
 
         if (vr.isConstant())
-            StoreToIntArray(masm, tarray, Imm32(vr.value().toInt32()), address);
+            masm.storeToTypedIntArray(tarray->type, Imm32(vr.value().toInt32()), address);
         else
-            StoreToIntArray(masm, tarray, vr.dataReg(), address);
+            masm.storeToTypedIntArray(tarray->type, vr.dataReg(), address);
 
         // Note that this will finish restoring the damage from the
         // earlier register swap.
         saveRHS.restore();
         break;
       }
 
       case js::TypedArray::TYPE_FLOAT32:
@@ -531,19 +415,19 @@ StoreToTypedArray(JSContext *cx, Assembl
          */
         Registers regs(Registers::TempFPRegs);
         FPRegisterID temp = regs.takeAnyReg().fpreg();
 
         if (!ConstantFoldForFloatArray(cx, &vr))
             return false;
         GenConversionForFloatArray(masm, tarray, vr, temp, saveMask);
         if (vr.isConstant())
-            StoreToFloatArray(masm, tarray, ImmDouble(vr.value().toDouble()), address);
+            masm.storeToTypedFloatArray(tarray->type, ImmDouble(vr.value().toDouble()), address);
         else
-            StoreToFloatArray(masm, tarray, temp, address);
+            masm.storeToTypedFloatArray(tarray->type, temp, address);
         break;
       }
     }
 
     return true;
 }
 
 #endif // defined(JS_POLYIC) && (defined JS_CPU_X86 || defined JS_CPU_X64)