Bug 1504464 - Part 5: Fix destructuring behavior in ReadableStream.prototype.getReader. r=jwalden
authorJason Orendorff <jorendorff@mozilla.com>
Mon, 14 Jan 2019 20:33:01 +0000
changeset 510919 de74494a1aa7ddfbc6a6475b8e2c3a91eba4dad9
parent 510918 d35260c2032c61c08e1e9af2f5f9fda142097de8
child 510920 7afcd486bdc615bbdca8a9afd432c61299441a4b
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwalden
bugs1504464
milestone66.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 1504464 - Part 5: Fix destructuring behavior in ReadableStream.prototype.getReader. r=jwalden The section headers in the spec that look like JS destructuring are in fact normative. The methods have to behave just like JS destructuring; see <https://streams.spec.whatwg.org/#conventions> for details. This means the getReader method <https://streams.spec.whatwg.org/#rs-get-reader> must do a full property Get for options.mode, even if that means querying %ObjectPrototype%, absurd as it sounds. Differential Revision: https://phabricator.services.mozilla.com/D14503
js/src/builtin/Stream.cpp
--- a/js/src/builtin/Stream.cpp
+++ b/js/src/builtin/Stream.cpp
@@ -672,40 +672,45 @@ static MOZ_MUST_USE bool ReadableStream_
 
 static MOZ_MUST_USE ReadableStreamDefaultReader*
 CreateReadableStreamDefaultReader(
     JSContext* cx, Handle<ReadableStream*> unwrappedStream,
     ForAuthorCodeBool forAuthorCode = ForAuthorCodeBool::No,
     HandleObject proto = nullptr);
 
 /**
- * Streams spec, 3.2.5.3. getReader()
+ * Streams spec, 3.2.5.3. getReader({ mode } = {})
  */
 static bool ReadableStream_getReader(JSContext* cx, unsigned argc, Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
 
+  // Implicit in the spec: Argument defaults and destructuring.
+  RootedValue optionsVal(cx, args.get(0));
+  if (optionsVal.isUndefined()) {
+    JSObject* emptyObj = NewBuiltinClassInstance<PlainObject>(cx);
+    if (!emptyObj) {
+      return false;
+    }
+    optionsVal.setObject(*emptyObj);
+  }
+  RootedValue modeVal(cx);
+  if (!GetProperty(cx, optionsVal, cx->names().mode, &modeVal)) {
+    return false;
+  }
+
   // Step 1: If ! IsReadableStream(this) is false, throw a TypeError exception.
   Rooted<ReadableStream*> unwrappedStream(
       cx, UnwrapAndTypeCheckThis<ReadableStream>(cx, args, "getReader"));
   if (!unwrappedStream) {
     return false;
   }
 
-  RootedObject reader(cx);
-
   // Step 2: If mode is undefined, return
   //         ? AcquireReadableStreamDefaultReader(this).
-  RootedValue modeVal(cx);
-  HandleValue optionsVal = args.get(0);
-  if (!optionsVal.isUndefined()) {
-    if (!GetProperty(cx, optionsVal, cx->names().mode, &modeVal)) {
-      return false;
-    }
-  }
-
+  RootedObject reader(cx);
   if (modeVal.isUndefined()) {
     reader = CreateReadableStreamDefaultReader(cx, unwrappedStream,
                                                ForAuthorCodeBool::Yes);
   } else {
     // Step 3: Set mode to ? ToString(mode) (implicit).
     RootedString mode(cx, ToString<CanGC>(cx, modeVal));
     if (!mode) {
       return false;