Bug 660437: Fix conversion of non-numeric types to typed array elements, r=luke
authorDavid Mandelin <dmandelin@mozilla.com>
Tue, 06 Dec 2011 14:24:39 -0800
changeset 83762 b6ceca62f1a7e1ec2c60740483f638989a204342
parent 83761 c3678c3f162ed5ec93aa9add68e58d82ea4f6dc3
child 83763 66d577078bb11c09335f9dc284d5f9cdf2b43de7
push id519
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 00:38:35 +0000
treeherdermozilla-beta@788ea1ef610b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs660437
milestone11.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 660437: Fix conversion of non-numeric types to typed array elements, r=luke
js/src/jit-test/tests/basic/testTypedArrayUndefinedAndHoles.js
js/src/jstypedarray.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/testTypedArrayUndefinedAndHoles.js
@@ -0,0 +1,32 @@
+function holeArray(sparse) {
+    var a = [,,];
+    if (sparse)
+        a.length = 1000;
+    return a;
+}
+
+function undefinedArray(sparse) {
+    var a = [ undefined, undefined, undefined ];
+    if (sparse)
+        a.length = 1000;
+    return a;
+}
+
+var a;
+a = new Int32Array(holeArray(false));
+assertEq(a[0], 0);
+a = new Int32Array(holeArray(true));
+assertEq(a[0], 0);
+a = new Int32Array(undefinedArray(false));
+assertEq(a[0], 0);
+a = new Int32Array(undefinedArray(true));
+assertEq(a[0], 0);
+
+a = new Float64Array(holeArray(false));
+assertEq(a[0], NaN);
+a = new Float64Array(holeArray(true));
+assertEq(a[0], NaN);
+a = new Float64Array(undefinedArray(false));
+assertEq(a[0], NaN);
+a = new Float64Array(undefinedArray(true));
+assertEq(a[0], NaN);
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -1702,42 +1702,49 @@ class TypedArrayTemplate
         JS_ASSERT(UINT32_MAX - begin * sizeof(NativeType) >= getByteOffset(tarray));
         uint32 byteOffset = getByteOffset(tarray) + begin * sizeof(NativeType);
 
         return createTypedArray(cx, bufobj, byteOffset, length);
     }
 
   protected:
     static NativeType
+    nativeFromDouble(double d)
+    {
+        if (!ArrayTypeIsFloatingPoint() && JS_UNLIKELY(JSDOUBLE_IS_NaN(d)))
+            return NativeType(int32(0));
+        if (TypeIsFloatingPoint<NativeType>())
+            return NativeType(d);
+        if (TypeIsUnsigned<NativeType>())
+            return NativeType(js_DoubleToECMAUint32(d));
+        return NativeType(js_DoubleToECMAInt32(d));
+    }
+
+    static NativeType
     nativeFromValue(JSContext *cx, const Value &v)
     {
         if (v.isInt32())
             return NativeType(v.toInt32());
 
-        if (v.isDouble()) {
-            double d = v.toDouble();
-            if (!ArrayTypeIsFloatingPoint() && JS_UNLIKELY(JSDOUBLE_IS_NaN(d)))
-                return NativeType(int32(0));
-            if (TypeIsFloatingPoint<NativeType>())
-                return NativeType(d);
-            if (TypeIsUnsigned<NativeType>())
-                return NativeType(js_DoubleToECMAUint32(d));
-            return NativeType(js_DoubleToECMAInt32(d));
+        if (v.isDouble())
+            return nativeFromDouble(v.toDouble());
+
+        /*
+         * The condition guarantees that holes and undefined values
+         * are treated identically.
+         */
+        if (v.isPrimitive() && !v.isMagic() && !v.isUndefined()) {
+            jsdouble dval;
+            JS_ALWAYS_TRUE(ToNumber(cx, v, &dval));
+            return nativeFromDouble(dval);
         }
 
-        if (v.isPrimitive() && !v.isMagic()) {
-            jsdouble dval;
-            JS_ALWAYS_TRUE(ToNumber(cx, v, &dval));
-            return NativeType(dval);
-        }
-
-        if (ArrayTypeIsFloatingPoint())
-            return NativeType(js_NaN);
-
-        return NativeType(int32(0));
+        return ArrayTypeIsFloatingPoint()
+               ? NativeType(js_NaN)
+               : NativeType(int32(0));
     }
 
     static bool
     copyFromArray(JSContext *cx, JSObject *thisTypedArrayObj,
              JSObject *ar, jsuint len, jsuint offset = 0)
     {
         thisTypedArrayObj = getTypedArray(thisTypedArrayObj);
         JS_ASSERT(thisTypedArrayObj);
@@ -1746,20 +1753,23 @@ class TypedArrayTemplate
         JS_ASSERT(len <= getLength(thisTypedArrayObj) - offset);
         NativeType *dest = static_cast<NativeType*>(getDataOffset(thisTypedArrayObj)) + offset;
 
         if (ar->isDenseArray() && ar->getDenseArrayInitializedLength() >= len) {
             JS_ASSERT(ar->getArrayLength() == len);
 
             const Value *src = ar->getDenseArrayElements();
 
+            /*
+             * It is valid to skip the hole check here because nativeFromValue
+             * treats a hole as undefined.
+             */
             for (uintN i = 0; i < len; ++i)
                 *dest++ = nativeFromValue(cx, *src++);
         } else {
-            // slow path
             Value v;
 
             for (uintN i = 0; i < len; ++i) {
                 if (!ar->getElement(cx, i, &v))
                     return false;
                 *dest++ = nativeFromValue(cx, v);
             }
         }