Bug 1686445 part 4 - Add structured clone support for large DataViews. r=sfink
authorJan de Mooij <jdemooij@mozilla.com>
Thu, 14 Jan 2021 21:44:28 +0000
changeset 563272 2ca9f90369624e2626e4933eaf7f96237c9b8356
parent 563271 ad251c4f6d76433404649f6bad849e257e28e434
child 563273 7f17f8fb11351c95cb9f6f6d9b66665c832bce99
push id134263
push userjdemooij@mozilla.com
push dateFri, 15 Jan 2021 12:47:17 +0000
treeherderautoland@d5154885d8d2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs1686445
milestone86.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 1686445 part 4 - Add structured clone support for large DataViews. r=sfink Differential Revision: https://phabricator.services.mozilla.com/D101737
js/src/jit-test/tests/structured-clone/array-buffers.js
js/src/vm/StructuredClone.cpp
--- a/js/src/jit-test/tests/structured-clone/array-buffers.js
+++ b/js/src/jit-test/tests/structured-clone/array-buffers.js
@@ -55,16 +55,26 @@ function testFloat64Array() {
     var ta1 = new Float64Array([NaN, 3.14, 0, 0]);
     var clonebuf = serialize(ta1, undefined, {scope: "DifferentProcessForIndexedDB"});
     var ta2 = deserialize(clonebuf);
     assertEq(ta2 instanceof Float64Array, true);
     assertEq(ta2.toString(), "NaN,3.14,0,0");
 }
 testFloat64Array();
 
+function testDataView() {
+    var ta = new Uint8Array([5, 0, 255]);
+    var dv1 = new DataView(ta.buffer);
+    var clonebuf = serialize(dv1, undefined, {scope: "DifferentProcessForIndexedDB"});
+    var dv2 = deserialize(clonebuf);
+    assertEq(dv2 instanceof DataView, true);
+    assertEq(new Uint8Array(dv2.buffer).toString(), "5,0,255");
+}
+testDataView();
+
 function testArrayBuffer() {
     var ta = new Uint8Array([33, 44, 55, 66]);
     var clonebuf = serialize(ta.buffer, undefined, {scope: "DifferentProcessForIndexedDB"});
     var ab = deserialize(clonebuf);
     assertEq(ab instanceof ArrayBuffer, true);
     assertEq(new Uint8Array(ab).toString(), "33,44,55,66");
 }
 testArrayBuffer();
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -111,34 +111,35 @@ enum StructuredDataType : uint32_t {
   SCTAG_NUMBER_OBJECT,
   SCTAG_BACK_REFERENCE_OBJECT,
   SCTAG_DO_NOT_USE_1,           // Required for backwards compatibility
   SCTAG_DO_NOT_USE_2,           // Required for backwards compatibility
   SCTAG_TYPED_ARRAY_OBJECT_V2,  // Old version, for backwards compatibility.
   SCTAG_MAP_OBJECT,
   SCTAG_SET_OBJECT,
   SCTAG_END_OF_KEYS,
-  SCTAG_DO_NOT_USE_3,  // Required for backwards compatibility
-  SCTAG_DATA_VIEW_OBJECT,
+  SCTAG_DO_NOT_USE_3,         // Required for backwards compatibility
+  SCTAG_DATA_VIEW_OBJECT_V2,  // Old version, for backwards compatibility.
   SCTAG_SAVED_FRAME_OBJECT,
 
   // No new tags before principals.
   SCTAG_JSPRINCIPALS,
   SCTAG_NULL_JSPRINCIPALS,
   SCTAG_RECONSTRUCTED_SAVED_FRAME_PRINCIPALS_IS_SYSTEM,
   SCTAG_RECONSTRUCTED_SAVED_FRAME_PRINCIPALS_IS_NOT_SYSTEM,
 
   SCTAG_SHARED_ARRAY_BUFFER_OBJECT,
   SCTAG_SHARED_WASM_MEMORY_OBJECT,
 
   SCTAG_BIGINT,
   SCTAG_BIGINT_OBJECT,
 
   SCTAG_ARRAY_BUFFER_OBJECT,
   SCTAG_TYPED_ARRAY_OBJECT,
+  SCTAG_DATA_VIEW_OBJECT,
 
   SCTAG_TYPED_ARRAY_V1_MIN = 0xFFFF0100,
   SCTAG_TYPED_ARRAY_V1_INT8 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Int8,
   SCTAG_TYPED_ARRAY_V1_UINT8 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Uint8,
   SCTAG_TYPED_ARRAY_V1_INT16 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Int16,
   SCTAG_TYPED_ARRAY_V1_UINT16 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Uint16,
   SCTAG_TYPED_ARRAY_V1_INT32 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Int32,
   SCTAG_TYPED_ARRAY_V1_UINT32 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Uint32,
@@ -425,17 +426,17 @@ struct JSStructuredCloneReader {
   template <typename CharT>
   JSString* readStringImpl(uint32_t nchars, gc::InitialHeap heap);
   JSString* readString(uint32_t data, gc::InitialHeap heap = gc::DefaultHeap);
 
   BigInt* readBigInt(uint32_t data);
 
   MOZ_MUST_USE bool readTypedArray(uint32_t arrayType, uint64_t nelems,
                                    MutableHandleValue vp, bool v1Read = false);
-  MOZ_MUST_USE bool readDataView(uint32_t byteLength, MutableHandleValue vp);
+  MOZ_MUST_USE bool readDataView(uint64_t byteLength, MutableHandleValue vp);
   MOZ_MUST_USE bool readArrayBuffer(StructuredDataType type, uint32_t data,
                                     MutableHandleValue vp);
   MOZ_MUST_USE bool readSharedArrayBuffer(MutableHandleValue vp);
   MOZ_MUST_USE bool readSharedWasmMemory(uint32_t nbytes,
                                          MutableHandleValue vp);
   MOZ_MUST_USE bool readV1ArrayBuffer(uint32_t arrayType, uint32_t nelems,
                                       MutableHandleValue vp);
   JSObject* readSavedFrame(uint32_t principalsTag);
@@ -1286,28 +1287,33 @@ bool JSStructuredCloneWriter::writeTyped
   uint64_t byteOffset = tarr->byteOffset().get();
   return out.write(byteOffset);
 }
 
 bool JSStructuredCloneWriter::writeDataView(HandleObject obj) {
   Rooted<DataViewObject*> view(context(), obj->maybeUnwrapAs<DataViewObject>());
   JSAutoRealm ar(context(), view);
 
-  if (!out.writePair(SCTAG_DATA_VIEW_OBJECT,
-                     view->byteLength().deprecatedGetUint32())) {
+  if (!out.writePair(SCTAG_DATA_VIEW_OBJECT, 0)) {
+    return false;
+  }
+
+  uint64_t byteLength = view->byteLength().get();
+  if (!out.write(byteLength)) {
     return false;
   }
 
   // Write out the ArrayBuffer tag and contents
   RootedValue val(context(), view->bufferValue());
   if (!startWrite(val)) {
     return false;
   }
 
-  return out.write(view->byteOffset().deprecatedGetUint32());
+  uint64_t byteOffset = view->byteOffset().get();
+  return out.write(byteOffset);
 }
 
 bool JSStructuredCloneWriter::writeArrayBuffer(HandleObject obj) {
   Rooted<ArrayBufferObject*> buffer(context(),
                                     obj->maybeUnwrapAs<ArrayBufferObject>());
   JSAutoRealm ar(context(), buffer);
 
   if (!out.writePair(SCTAG_ARRAY_BUFFER_OBJECT, 0)) {
@@ -2282,17 +2288,17 @@ bool JSStructuredCloneReader::readTypedA
   }
   vp.setObject(*obj);
 
   allObjs[placeholderIndex].set(vp);
 
   return true;
 }
 
-bool JSStructuredCloneReader::readDataView(uint32_t byteLength,
+bool JSStructuredCloneReader::readDataView(uint64_t byteLength,
                                            MutableHandleValue vp) {
   // Push a placeholder onto the allObjs list to stand in for the DataView.
   uint32_t placeholderIndex = allObjs.length();
   Value dummy = UndefinedValue();
   if (!allObjs.append(dummy)) {
     return false;
   }
 
@@ -2304,21 +2310,20 @@ bool JSStructuredCloneReader::readDataVi
   if (!v.isObject() || !v.toObject().is<ArrayBufferObjectMaybeShared>()) {
     JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr,
                               JSMSG_SC_BAD_SERIALIZED_DATA,
                               "DataView must be backed by an ArrayBuffer");
     return false;
   }
 
   // Read byteOffset.
-  uint64_t n;
-  if (!in.read(&n)) {
+  uint64_t byteOffset;
+  if (!in.read(&byteOffset)) {
     return false;
   }
-  uint32_t byteOffset = n;
 
   RootedObject buffer(context(), &v.toObject());
   RootedObject obj(context(),
                    JS_NewDataView(context(), buffer, byteOffset, byteLength));
   if (!obj) {
     return false;
   }
   vp.setObject(*obj);
@@ -2730,19 +2735,29 @@ bool JSStructuredCloneReader::startRead(
       uint32_t arrayType = data;
       uint64_t nelems;
       if (!in.read(&nelems)) {
         return false;
       }
       return readTypedArray(arrayType, nelems, vp);
     }
 
+    case SCTAG_DATA_VIEW_OBJECT_V2: {
+      // readDataView adds the array to allObjs.
+      uint64_t byteLength = data;
+      return readDataView(byteLength, vp);
+    }
+
     case SCTAG_DATA_VIEW_OBJECT: {
       // readDataView adds the array to allObjs.
-      return readDataView(data, vp);
+      uint64_t byteLength;
+      if (!in.read(&byteLength)) {
+        return false;
+      }
+      return readDataView(byteLength, vp);
     }
 
     case SCTAG_MAP_OBJECT: {
       JSObject* obj = MapObject::create(context());
       if (!obj || !objs.append(ObjectValue(*obj))) {
         return false;
       }
       vp.setObject(*obj);