Bug 1264941 - Use byteLength of source typedArray in CloneArrayBuffer. r=lth
authorTooru Fujisawa <arai_a@mac.com>
Thu, 21 Apr 2016 08:45:40 +0900
changeset 332062 e92704fae381eb6b3363a87372663c5a6466e6fd
parent 332061 b4c514efe8c0f74ad94b33f846a3a94a37138ce4
child 332063 0b609cab107795bd79520e1674ddfdee80e46a8a
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslth
bugs1264941
milestone48.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 1264941 - Use byteLength of source typedArray in CloneArrayBuffer. r=lth
js/src/tests/ecma_6/ArrayBuffer/CloneArrayBuffer.js
js/src/tests/ecma_6/ArrayBuffer/indivisible-byteLength.js
js/src/vm/TypedArrayObject.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/ArrayBuffer/CloneArrayBuffer.js
@@ -0,0 +1,35 @@
+var BUGNUMBER = 1264941;
+var summary = 'CloneArrayBuffer should be called with byteLength of source typedArray';
+
+print(BUGNUMBER + ": " + summary);
+
+function test(ctor, byteLength) {
+  var abuf = new ctor(byteLength);
+  assertEq(abuf.byteLength, byteLength);
+
+  for (var byteOffset of [0, 16]) {
+    for (var elementLength = 0;
+         elementLength < (byteLength - byteOffset) / Float64Array.BYTES_PER_ELEMENT;
+         elementLength++) {
+      var a1 = new Float64Array(abuf, byteOffset, elementLength);
+      assertEq(a1.buffer.byteLength, byteLength);
+      assertEq(a1.byteLength, elementLength * Float64Array.BYTES_PER_ELEMENT);
+      assertEq(a1.byteOffset, byteOffset);
+
+      var a2 = new Float64Array(a1);
+      assertEq(a2.buffer.byteLength, a1.byteLength);
+      assertEq(a2.byteLength, a1.byteLength);
+      assertEq(a2.byteOffset, 0);
+    }
+  }
+}
+
+test(ArrayBuffer, 16);
+test(ArrayBuffer, 128);
+
+class MyArrayBuffer extends ArrayBuffer {}
+test(MyArrayBuffer, 16);
+test(MyArrayBuffer, 128);
+
+if (typeof reportCompare === 'function')
+  reportCompare(true, true);
deleted file mode 100644
--- a/js/src/tests/ecma_6/ArrayBuffer/indivisible-byteLength.js
+++ /dev/null
@@ -1,40 +0,0 @@
-var BUGNUMBER = 1263803;
-var summary = 'CloneArrayBuffer should allocate ArrayBuffer even with individual byteLength';
-
-print(BUGNUMBER + ": " + summary);
-
-var abuf1 = new ArrayBuffer(38);
-assertEq(abuf1.byteLength, 38);
-
-var a1 = new Float64Array(abuf1, 24, 0);
-assertEq(a1.buffer.byteLength, 38);
-assertEq(a1.byteLength, 0);
-assertEq(a1.byteOffset, 24);
-
-var a2 = new Float64Array(a1);
-// NOTE: There is a behavior difference on ArrayBuffer's byteLength, between
-//       lazily allocated case and eagerly allocated case (bug 1264941).
-//       This one is lazily allocated case, and it equals to a2.byteLength.
-assertEq(a2.buffer.byteLength, 0);
-assertEq(a2.byteLength, 0);
-assertEq(a2.byteOffset, 0);
-
-class MyArrayBuffer extends ArrayBuffer {}
-
-var abuf2 = new MyArrayBuffer(38);
-assertEq(abuf2.byteLength, 38);
-
-var a3 = new Float64Array(abuf2, 24, 0);
-assertEq(a3.buffer.byteLength, 38);
-assertEq(a3.byteLength, 0);
-assertEq(a3.byteOffset, 24);
-
-var a4 = new Float64Array(a3);
-// NOTE: This one is eagerly allocated case, and it differs from a4.byteLength.
-//       Either one should be fixed once bug 1264941 is fixed.
-assertEq(a4.buffer.byteLength, 14);
-assertEq(a4.byteLength, 0);
-assertEq(a4.byteOffset, 0);
-
-if (typeof reportCompare === 'function')
-  reportCompare(true, true);
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -676,17 +676,17 @@ class TypedArrayObjectTemplate : public 
     }
 
     static bool
     AllocateArrayBuffer(JSContext* cx, HandleValue ctor, uint32_t byteLength,
                         MutableHandle<ArrayBufferObject*> buffer);
 
     static bool
     CloneArrayBufferNoCopy(JSContext* cx, Handle<ArrayBufferObjectMaybeShared*> srcBuffer,
-                           bool isWrapped, uint32_t srcByteOffset,
+                           bool isWrapped, uint32_t srcByteOffset, uint32_t srcLength,
                            MutableHandle<ArrayBufferObject*> buffer);
 
     static JSObject*
     fromArray(JSContext* cx, HandleObject other, HandleObject newTarget = nullptr);
 
     static JSObject*
     fromTypedArray(JSContext* cx, HandleObject other, bool isWrapped, HandleObject newTarget);
 
@@ -814,61 +814,53 @@ GetSpeciesConstructor(JSContext* cx, Han
         RootedValue defaultCtor(cx, cx->global()->getConstructor(JSProto_ArrayBuffer));
         if (!SpeciesConstructor(cx, obj, defaultCtor, ctor))
             return false;
     }
 
     return JS_WrapValue(cx, ctor);
 }
 
-// ES 2016 draft Mar 25, 2016 24.1.1.4.
+// ES 2017 draft rev 8633ffd9394b203b8876bb23cb79aff13eb07310 24.1.1.4.
 template<typename T>
 /* static */ bool
 TypedArrayObjectTemplate<T>::CloneArrayBufferNoCopy(JSContext* cx,
                                                     Handle<ArrayBufferObjectMaybeShared*> srcBuffer,
                                                     bool isWrapped, uint32_t srcByteOffset,
+                                                    uint32_t srcLength,
                                                     MutableHandle<ArrayBufferObject*> buffer)
 {
     // Step 1 (skipped).
 
     // Step 2.a.
     RootedValue cloneCtor(cx);
     if (!GetSpeciesConstructor(cx, srcBuffer, isWrapped, &cloneCtor))
         return false;
 
     // Step 2.b.
     if (srcBuffer->isDetached()) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
         return false;
     }
 
-    // Step 3 (skipped).
-
-    // Steps 4-5.
-    uint32_t srcLength = srcBuffer->byteLength();
-    MOZ_ASSERT(srcByteOffset <= srcLength);
+    // Steps 3-4 (skipped).
+
+    // Steps 5.
+    if (!AllocateArrayBuffer(cx, cloneCtor, srcLength, buffer))
+        return false;
 
     // Step 6.
-    uint32_t cloneLength = srcLength - srcByteOffset;
-
-    // Step 7 (skipped).
-
-    // Steps 8.
-    if (!AllocateArrayBuffer(cx, cloneCtor, cloneLength, buffer))
-        return false;
-
-    // Step 9.
     if (srcBuffer->isDetached()) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
         return false;
     }
 
-    // Steps 10-11 (done in caller).
-
-    // Step 12.
+    // Steps 7-8 (done in caller).
+
+    // Step 9.
     return true;
 }
 
 template<typename T>
 /* static */ JSObject*
 TypedArrayObjectTemplate<T>::fromArray(JSContext* cx, HandleObject other,
                                        HandleObject newTarget /* = nullptr */)
 {
@@ -878,17 +870,17 @@ TypedArrayObjectTemplate<T>::fromArray(J
         return fromTypedArray(cx, other, /* wrapped= */ false, newTarget);
 
     if (other->is<WrapperObject>() && UncheckedUnwrap(other)->is<TypedArrayObject>())
         return fromTypedArray(cx, other, /* wrapped= */ true, newTarget);
 
     return fromObject(cx, other, newTarget);
 }
 
-// ES 2016 draft Mar 25, 2016 22.2.4.3.
+// ES 2017 draft rev 8633ffd9394b203b8876bb23cb79aff13eb07310 22.2.4.3.
 template<typename T>
 /* static */ JSObject*
 TypedArrayObjectTemplate<T>::fromTypedArray(JSContext* cx, HandleObject other, bool isWrapped,
                                             HandleObject newTarget)
 {
     // Step 1.
     MOZ_ASSERT_IF(!isWrapped, other->is<TypedArrayObject>());
     MOZ_ASSERT_IF(isWrapped,
@@ -944,17 +936,20 @@ TypedArrayObjectTemplate<T>::fromTypedAr
 
     // Steps 15-16.
     uint32_t byteLength = BYTES_PER_ELEMENT * elementLength;
 
     // Steps 8-9, 17.
     Rooted<ArrayBufferObject*> buffer(cx);
     if (ArrayTypeID() == srcType) {
         // Step 17.a.
-        if (!CloneArrayBufferNoCopy(cx, srcData, isWrapped, srcByteOffset, &buffer))
+        uint32_t srcLength = srcArray->byteLength();
+
+        // Step 17.b.
+        if (!CloneArrayBufferNoCopy(cx, srcData, isWrapped, srcByteOffset, srcLength, &buffer))
             return nullptr;
     } else {
         // Step 18.a.
         RootedValue bufferCtor(cx);
         if (!GetSpeciesConstructor(cx, srcData, isWrapped, &bufferCtor))
             return nullptr;
 
         // Step 18.b.