Backed out changeset eeb52543a6c6 (bug 1317383)
authorSebastian Hengst <archaeopteryx@coole-files.de>
Fri, 28 Apr 2017 16:24:24 +0200
changeset 355561 bc2539cd72c91ae71633c8aea460577e1120647c
parent 355560 4cb0cfe2b32ef6c3ad3096b2cbfca879d375e5da
child 355562 edaf81997a7bd28d3fd6c1955ef52b837b183ff5
push id89693
push userarchaeopteryx@coole-files.de
push dateFri, 28 Apr 2017 14:27:11 +0000
treeherdermozilla-inbound@edaf81997a7b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1317383
milestone55.0a1
backs outeeb52543a6c6e9bb931eaeef9734e82d5228ea92
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
Backed out changeset eeb52543a6c6 (bug 1317383)
js/src/jit-test/tests/asm.js/testBasic.js
js/src/jit-test/tests/basic/bug1292858.js
js/src/jit-test/tests/ion/bug1298354.js
js/src/jsnum.cpp
js/src/jsnum.h
js/src/tests/ecma_6/TypedArray/constructor-length-too-large.js
js/src/tests/js1_8_5/extensions/typedarray.js
js/src/tests/jstests.list
js/src/vm/TypedArrayObject-inl.h
js/src/vm/TypedArrayObject.cpp
--- a/js/src/jit-test/tests/asm.js/testBasic.js
+++ b/js/src/jit-test/tests/asm.js/testBasic.js
@@ -64,18 +64,18 @@ assertAsmTypeFail('glob', USE_ASM + 'var
 assertAsmLinkAlwaysFail(asmCompile('glob', USE_ASM + 'var im=glob.Math.imul; function f(i,j) {i=i|0;j=j|0; return im(i,j)|0} return f'), null);
 assertAsmLinkAlwaysFail(asmCompile('glob', USE_ASM + 'var im=glob.Math.imul; function f(i,j) {i=i|0;j=j|0; return im(i,j)|0} return f'), {});
 assertAsmLinkAlwaysFail(asmCompile('glob', USE_ASM + 'var im=glob.Math.imul; function f(i,j) {i=i|0;j=j|0; return im(i,j)|0} return f'), {imul:Math.imul});
 assertEq(asmLink(asmCompile('glob', USE_ASM + 'var im=glob.Math.imul; function f(i,j) {i=i|0;j=j|0; return im(i,j)|0} return f'), {Math:{imul:Math.imul}})(2,3), 6);
 assertEq(asmLink(asmCompile('glob', USE_ASM + 'var im=glob.Math.imul; function f(i,j) {i=i|0;j=j|0; return im(i,j)|0} return f'), this)(8,4), 32);
 
 var module = asmCompile('glob','i','b', USE_ASM + 'var i32=new glob.Int32Array(b); function f(){} return f');
 assertAsmLinkAlwaysFail(module, null, null);
-assertAsmLinkFail(module, this, null, null);
-assertAsmLinkFail(module, this, null, null);
+assertAsmLinkAlwaysFail(module, this, null, null);
+assertAsmLinkAlwaysFail(module, this, null, null);
 assertAsmLinkAlwaysFail(module, this, null, new ArrayBuffer(1));
 assertAsmLinkFail(module, this, null, new ArrayBuffer(4));
 assertAsmLinkFail(module, this, null, new ArrayBuffer(100));
 assertAsmLinkFail(module, this, null, new ArrayBuffer(4092));
 assertAsmLinkFail(module, this, null, new ArrayBuffer(64000));
 assertAsmLinkFail(module, this, null, new ArrayBuffer(BUF_MIN+4));
 assertAsmLinkDeprecated(module, this, null, new ArrayBuffer(4096));
 assertAsmLinkDeprecated(module, this, null, new ArrayBuffer(2*4096));
--- a/js/src/jit-test/tests/basic/bug1292858.js
+++ b/js/src/jit-test/tests/basic/bug1292858.js
@@ -1,47 +1,47 @@
 var caughtInvalidArguments = false;
 var a = -1
 try {
     var buf = new Uint8ClampedArray(a);
     throw new Error("didn't throw");
 } catch (e) {
-    assertEq(e instanceof RangeError, true,
-             "expected RangeError, instead threw: " + e);
+    assertEq(e instanceof TypeError, true,
+             "expected TypeError, instead threw: " + e);
     caughtInvalidArguments = true;
 }
 assertEq(caughtInvalidArguments, true);
 
 var caughtInvalidArguments = false;
 var i = 0;
 while (true) {
     i = (i + 1) | 0;
     var a = inIon() ? -1 : 300;
     try {
         var buf = new Uint8ClampedArray(a);
         assertEq(buf.length, 300);
     } catch (e) {
         assertEq(a, -1);
-        assertEq(e instanceof RangeError, true,
-                "expected RangeError, instead threw: " + e);
+        assertEq(e instanceof TypeError, true,
+                "expected TypeError, instead threw: " + e);
         caughtInvalidArguments = true;
         break;
     }
 }
 assertEq(caughtInvalidArguments, true);
 
 var caughtInvalidArguments = false;
 var i = 0;
 while (true) {
     i = (i + 1) | 0;
     var a = inIon() ? -1 : 0;
     try {
         var buf = new Uint8ClampedArray(a);
         assertEq(buf.length, 0);
     } catch (e) {
         assertEq(a, -1);
-        assertEq(e instanceof RangeError, true,
-                "expected RangeError, instead threw: " + e);
+        assertEq(e instanceof TypeError, true,
+                "expected TypeError, instead threw: " + e);
         caughtInvalidArguments = true;
         break;
     }
 }
 assertEq(caughtInvalidArguments, true);
--- a/js/src/jit-test/tests/ion/bug1298354.js
+++ b/js/src/jit-test/tests/ion/bug1298354.js
@@ -1,14 +1,14 @@
 // |jit-test| error: ReferenceError
 
 new Function(`
   while (true) {
     try {
-        var buf = new Uint8ClampedArray(-1);
+        var buf = new Uint8ClampedArray(a);
     } catch (e) {
         break;
     }
   }
   var caughtInvalidArguments = false;
   while (true) {
     var a = inIon() ? -true.get : 0;
     while (x > 7 & 0) {}
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -1793,17 +1793,17 @@ js::ToUint16Slow(JSContext* cx, const Ha
     if (d < 0)
         d += m;
     *out = (uint16_t) d;
     return true;
 }
 
 // ES2017 draft 7.1.17 ToIndex
 bool
-js::ToIndex(JSContext* cx, JS::HandleValue v, const unsigned errorNumber, uint64_t* index)
+js::ToIndex(JSContext* cx, JS::HandleValue v, uint64_t* index)
 {
     // Step 1.
     if (v.isUndefined()) {
         *index = 0;
         return true;
     }
 
     // Step 2.a.
@@ -1811,17 +1811,17 @@ js::ToIndex(JSContext* cx, JS::HandleVal
     if (!ToInteger(cx, v, &integerIndex))
         return false;
 
     // Inlined version of ToLength.
     // 1. Already an integer.
     // 2. Step eliminates < 0, +0 == -0 with SameValueZero.
     // 3/4. Limit to <= 2^53-1, so everything above should fail.
     if (integerIndex < 0 || integerIndex >= DOUBLE_INTEGRAL_PRECISION_LIMIT) {
-        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, errorNumber);
+        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
         return false;
     }
 
     // Step 3.
     *index = uint64_t(integerIndex);
     return true;
 }
 
--- a/js/src/jsnum.h
+++ b/js/src/jsnum.h
@@ -278,24 +278,17 @@ ToInteger(JSContext* cx, HandleValue v, 
 
 /* ES2017 draft 7.1.17 ToIndex
  *
  * Return true and set |*index| to the integer value if |v| is a valid
  * integer index value. Otherwise report a RangeError and return false.
  *
  * The returned index will always be in the range 0 <= *index <= 2^53-1.
  */
-MOZ_MUST_USE bool
-ToIndex(JSContext* cx, JS::HandleValue v, const unsigned errorNumber, uint64_t* index);
-
-static MOZ_MUST_USE inline bool
-ToIndex(JSContext* cx, JS::HandleValue v, uint64_t* index)
-{
-    return ToIndex(cx, v, JSMSG_BAD_INDEX, index);
-}
+MOZ_MUST_USE bool ToIndex(JSContext* cx, JS::HandleValue v, uint64_t* index);
 
 MOZ_MUST_USE inline bool
 SafeAdd(int32_t one, int32_t two, int32_t* res)
 {
 #if BUILTIN_CHECKED_ARITHMETIC_SUPPORTED(__builtin_sadd_overflow)
     // Using compiler's builtin function.
     return !__builtin_sadd_overflow(one, two, res);
 #else
deleted file mode 100644
--- a/js/src/tests/ecma_6/TypedArray/constructor-length-too-large.js
+++ /dev/null
@@ -1,28 +0,0 @@
-// Test that all TypedArray constructor variants throw a RangeError when
-// attempting to create a too large array.
-
-// The maximum typed array length is (currently) limited to
-// `(INT32_MAX / BYTES_PER_ELEMENT) - 1`.
-
-const INT32_MAX = 2**31 - 1;
-
-// 22.2.4.2 TypedArray ( length )
-for (let TA of typedArrayConstructors) {
-    assertThrows(() => new TA(INT32_MAX), RangeError);
-    assertThrows(() => new TA(INT32_MAX >> Math.log2(TA.BYTES_PER_ELEMENT)), RangeError);
-}
-
-// 22.2.4.3 TypedArray ( typedArray )
-const largeInt8Array = new Int8Array(2**30);
-for (let TA of typedArrayConstructors.filter(c => c.BYTES_PER_ELEMENT > 1)) {
-    assertThrows(() => new TA(largeInt8Array), RangeError);
-}
-
-// 22.2.4.4 TypedArray ( object )
-for (let TA of typedArrayConstructors) {
-    assertThrows(() => new TA({length: INT32_MAX}), RangeError);
-    assertThrows(() => new TA({length: INT32_MAX >> Math.log2(TA.BYTES_PER_ELEMENT)}), RangeError);
-}
-
-if (typeof reportCompare === "function")
-    reportCompare(true, true);
--- a/js/src/tests/js1_8_5/extensions/typedarray.js
+++ b/js/src/tests/js1_8_5/extensions/typedarray.js
@@ -431,17 +431,17 @@ function test()
     check(() =>
           a[0] == 4 && a[1] == 5 && a[2] == 6 &&
           a[3] == 4 && a[4] == 5 && a[5] == 6 &&
           a[6] == 4 && a[7] == 5 && a[8] == 6);
 
     a = new ArrayBuffer(0x10);
     checkThrows(() => new Uint32Array(buffer, 4, 0x3FFFFFFF));
 
-    check(() => new Float32Array(null).length === 0);
+    checkThrows(() => new Float32Array(null));
 
     a = new Uint8Array(0x100);
     b = Uint32Array.prototype.subarray.apply(a, [0, 0x100]);
     check(() => Object.prototype.toString.call(b) === "[object Uint8Array]");
     check(() => b.buffer === a.buffer);
     check(() => b.length === a.length);
     check(() => b.byteLength === a.byteLength);
     check(() => b.byteOffset === a.byteOffset);
@@ -491,19 +491,19 @@ function test()
     check(() => (new Int32Array(0)).BYTES_PER_ELEMENT == 4);
     check(() => Int16Array.BYTES_PER_ELEMENT == Uint16Array.BYTES_PER_ELEMENT);
 
     // test various types of args; Math.sqrt(4) is used to ensure that the
     // function gets a double, and not a demoted int
     check(() => (new Float32Array(Math.sqrt(4))).length == 2);
     check(() => (new Float32Array({ length: 10 })).length == 10);
     check(() => (new Float32Array({})).length == 0);
-    check(() => new Float32Array("3").length === 3);
-    check(() => new Float32Array(null).length === 0);
-    check(() => new Float32Array(undefined).length === 0);
+    checkThrows(() => new Float32Array("3"));
+    checkThrows(() => new Float32Array(null));
+    checkThrows(() => new Float32Array(undefined));
 
     // check that NaN conversions happen correctly with array conversions
     check(() => (new Int32Array([NaN])[0]) == 0);
     check(() => { var q = new Float32Array([NaN])[0]; return q != q; });
 
     // check that setting and reading arbitrary properties works
     // this is not something that will be done in real world
     // situations, but it should work when done just like in
--- a/js/src/tests/jstests.list
+++ b/js/src/tests/jstests.list
@@ -214,16 +214,20 @@ skip script test262/built-ins/TypedArray
 skip script test262/built-ins/TypedArrays/internals/Set/tonumber-value-throws.js
 
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1140152
 skip script test262/built-ins/TypedArray/prototype/slice/bit-precision.js
 
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1317383
 skip script test262/built-ins/TypedArrays/buffer-arg-byteoffset-is-negative-throws.js
 skip script test262/built-ins/TypedArrays/buffer-arg-defined-negative-length.js
+skip script test262/built-ins/TypedArrays/length-arg-is-infinity-throws-rangeerror.js
+skip script test262/built-ins/TypedArrays/length-arg-is-negative-integer-throws-rangeerror.js
+skip script test262/built-ins/TypedArrays/length-arg-toindex-length.js
+skip script test262/built-ins/TypedArrays/object-arg-length-excessive-throws.js
 
 # https://bugzilla.mozilla.org/show_bug.cgi?id=924058
 skip script test262/built-ins/Array/prototype/pop/S15.4.4.6_A2_T2.js
 skip script test262/built-ins/Array/prototype/pop/S15.4.4.6_A3_T1.js
 skip script test262/built-ins/Array/prototype/pop/S15.4.4.6_A3_T2.js
 skip script test262/built-ins/Array/prototype/push/S15.4.4.7_A2_T2.js
 skip script test262/built-ins/Array/prototype/push/S15.4.4.7_A4_T1.js
 skip script test262/built-ins/Array/prototype/slice/create-species-undef-invalid-len.js
--- a/js/src/vm/TypedArrayObject-inl.h
+++ b/js/src/vm/TypedArrayObject-inl.h
@@ -23,16 +23,48 @@
 
 #include "js/Conversions.h"
 #include "js/Value.h"
 
 #include "vm/NativeObject.h"
 
 namespace js {
 
+// ValueIsLength happens not to be according to ES6, which mandates
+// the use of ToLength, which in turn includes ToNumber, ToInteger,
+// and clamping.  ValueIsLength is used in the current TypedArray code
+// but will disappear when that code is made spec-compliant.
+
+inline bool
+ValueIsLength(const Value& v, uint32_t* len)
+{
+    if (v.isInt32()) {
+        int32_t i = v.toInt32();
+        if (i < 0)
+            return false;
+        *len = i;
+        return true;
+    }
+
+    if (v.isDouble()) {
+        double d = v.toDouble();
+        if (mozilla::IsNaN(d))
+            return false;
+
+        uint32_t length = uint32_t(d);
+        if (d != double(length))
+            return false;
+
+        *len = length;
+        return true;
+    }
+
+    return false;
+}
+
 template<typename To, typename From>
 inline To
 ConvertNumber(From src);
 
 template<>
 inline int8_t
 ConvertNumber<int8_t, float>(float src)
 {
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -638,17 +638,17 @@ class TypedArrayObjectTemplate : public 
             memset(data, 0, nbytes);
         }
     }
 
     static TypedArrayObject*
     makeTypedArrayWithTemplate(JSContext* cx, TypedArrayObject* templateObj, int32_t len)
     {
         if (len < 0 || uint32_t(len) >= INT32_MAX / sizeof(NativeType)) {
-            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
+            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
             return nullptr;
         }
 
         size_t nbytes;
         MOZ_ALWAYS_TRUE(js::CalculateAllocSize<NativeType>(len, &nbytes));
 
         bool fitsInline = nbytes <= INLINE_BUFFER_LIMIT;
 
@@ -709,26 +709,28 @@ class TypedArrayObjectTemplate : public 
 
   private:
     static JSObject*
     create(JSContext* cx, const CallArgs& args)
     {
         MOZ_ASSERT(args.isConstructing());
         RootedObject newTarget(cx, &args.newTarget().toObject());
 
-        /* () or (length) */
-        if (args.length() == 0 || !args[0].isObject()) {
-            uint64_t len;
-            if (!ToIndex(cx, args.get(0), JSMSG_BAD_ARRAY_LENGTH, &len))
-                return nullptr;
+        /* () or (number) */
+        uint32_t len = 0;
+        if (args.length() == 0 || ValueIsLength(args[0], &len))
+            return fromLength(cx, len, newTarget);
 
-            return fromLength(cx, len, newTarget);
+        /* (not an object) */
+        if (!args[0].isObject()) {
+            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
+            return nullptr;
         }
 
-        RootedObject dataObj(cx, &args[0].toObject());
+        RootedObject dataObj(cx, &args.get(0).toObject());
 
         /*
          * (typedArray)
          * (sharedTypedArray)
          * (type[] array)
          *
          * Otherwise create a new typed array and copy elements 0..len-1
          * properties from the object, treating it as some sort of array.
@@ -956,17 +958,18 @@ class TypedArrayObjectTemplate : public 
     }
 
     static bool
     maybeCreateArrayBuffer(JSContext* cx, uint32_t count, uint32_t unit,
                            HandleObject nonDefaultProto,
                            MutableHandle<ArrayBufferObject*> buffer)
     {
         if (count >= INT32_MAX / unit) {
-            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
+            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NEED_DIET,
+                                      "size and count");
             return false;
         }
         uint32_t byteLength = count * unit;
 
         MOZ_ASSERT(byteLength < INT32_MAX);
         static_assert(INLINE_BUFFER_LIMIT % sizeof(NativeType) == 0,
                       "ArrayBuffer inline storage shouldn't waste any space");
 
@@ -979,32 +982,27 @@ class TypedArrayObjectTemplate : public 
         if (!buf)
             return false;
 
         buffer.set(buf);
         return true;
     }
 
     static JSObject*
-    fromLength(JSContext* cx, uint64_t nelements, HandleObject newTarget = nullptr)
+    fromLength(JSContext* cx, uint32_t nelements, HandleObject newTarget = nullptr)
     {
         RootedObject proto(cx);
         if (!GetPrototypeForInstance(cx, newTarget, &proto))
             return nullptr;
 
-        if (nelements > UINT32_MAX) {
-            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
-            return nullptr;
-        }
-
         Rooted<ArrayBufferObject*> buffer(cx);
-        if (!maybeCreateArrayBuffer(cx, uint32_t(nelements), BYTES_PER_ELEMENT, nullptr, &buffer))
+        if (!maybeCreateArrayBuffer(cx, nelements, BYTES_PER_ELEMENT, nullptr, &buffer))
             return nullptr;
 
-        return makeInstance(cx, buffer, 0, uint32_t(nelements), proto);
+        return makeInstance(cx, buffer, 0, nelements, proto);
     }
 
     static bool
     AllocateArrayBuffer(JSContext* cx, HandleValue ctor,
                         uint32_t count, uint32_t unit,
                         MutableHandle<ArrayBufferObject*> buffer);
 
     static bool