Bug 1514051 - Part 1: Drop GC edges when a stream is no longer readable. r=arai
authorJason Orendorff <jorendorff@mozilla.com>
Tue, 15 Jan 2019 20:16:05 +0000
changeset 511080 7167385d70ec11e7196a499385b263555ce778ea
parent 511079 006df494925adbd6ad79a3281b78dcb506939b8b
child 511081 bc05036b8cbbfac1857f58a8dc5b468e5076ce27
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)
reviewersarai
bugs1514051
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 1514051 - Part 1: Drop GC edges when a stream is no longer readable. r=arai I think it's a little bizarre for this to be part of the standard, but if it weren't there, I wouldn't know it was safe to do this. Differential Revision: https://phabricator.services.mozilla.com/D14511
js/src/builtin/Stream.cpp
--- a/js/src/builtin/Stream.cpp
+++ b/js/src/builtin/Stream.cpp
@@ -2630,19 +2630,22 @@ static JSObject* ReadableStreamDefaultCo
   if (unwrappedQueue && unwrappedQueue->length() != 0) {
     // Step a: Let chunk be ! DequeueValue(this).
     RootedValue chunk(cx);
     if (!DequeueValue(cx, unwrappedController, &chunk)) {
       return nullptr;
     }
 
     // Step b: If this.[[closeRequested]] is true and this.[[queue]] is empty,
-    //         perform ! ReadableStreamClose(stream).
     if (unwrappedController->closeRequested() &&
         unwrappedQueue->length() == 0) {
+      // Step i: Perform ! ReadableStreamDefaultControllerClearAlgorithms(this).
+      ReadableStreamControllerClearAlgorithms(unwrappedController);
+
+      // Step ii: Perform ! ReadableStreamClose(stream).
       if (!ReadableStreamCloseInternal(cx, unwrappedStream)) {
         return nullptr;
       }
     }
 
     // Step c: Otherwise, perform
     //         ! ReadableStreamDefaultControllerCallPullIfNeeded(this).
     else {
@@ -2970,20 +2973,24 @@ static MOZ_MUST_USE bool ReadableStreamD
   //         ! ReadableStreamDefaultControllerCanCloseOrEnqueue(controller)
   //         is true.
   MOZ_ASSERT(!unwrappedController->closeRequested());
   MOZ_ASSERT(unwrappedStream->readable());
 
   // Step 3: Set controller.[[closeRequested]] to true.
   unwrappedController->setCloseRequested();
 
-  // Step 5: If controller.[[queue]] is empty, perform
-  //         ! ReadableStreamClose(stream).
+  // Step 4: If controller.[[queue]] is empty,
   Rooted<ListObject*> unwrappedQueue(cx, unwrappedController->queue());
   if (unwrappedQueue->length() == 0) {
+    // Step a: Perform
+    //         ! ReadableStreamDefaultControllerClearAlgorithms(controller).
+    ReadableStreamControllerClearAlgorithms(unwrappedController);
+
+    // Step b: Perform ! ReadableStreamClose(stream).
     return ReadableStreamCloseInternal(cx, unwrappedStream);
   }
 
   return true;
 }
 
 static MOZ_MUST_USE bool EnqueueValueWithSize(
     JSContext* cx, Handle<ReadableStreamController*> unwrappedContainer,
@@ -3103,17 +3110,22 @@ static MOZ_MUST_USE bool ReadableStreamC
     }
   }
 
   // Step 3 (or 4): Perform ! ResetQueue(controller).
   if (!ResetQueue(cx, unwrappedController)) {
     return false;
   }
 
-  // Step 4 (or 5): Perform ! ReadableStreamError(stream, e).
+  // Step 4 (or 5):
+  //      Perform ! ReadableStreamDefaultControllerClearAlgorithms(controller)
+  //      (or ReadableByteStreamControllerClearAlgorithms(controller)).
+  ReadableStreamControllerClearAlgorithms(unwrappedController);
+
+  // Step 5 (or 6): Perform ! ReadableStreamError(stream, e).
   return ReadableStreamErrorInternal(cx, unwrappedStream, e);
 }
 
 /**
  * Streams spec, 3.9.8.
  *      ReadableStreamDefaultControllerGetDesiredSize ( controller )
  * Streams spec 3.12.14.
  *      ReadableByteStreamControllerGetDesiredSize ( controller )
@@ -3873,17 +3885,20 @@ static MOZ_MUST_USE bool ReadableByteStr
       }
 
       // Step iii: Throw e.
       cx->setPendingException(e);
       return false;
     }
   }
 
-  // Step 6: Perform ! ReadableStreamClose(stream).
+  // Step 6: Perform ! ReadableByteStreamControllerClearAlgorithms(controller).
+  ReadableStreamControllerClearAlgorithms(unwrappedController);
+
+  // Step 7: Perform ! ReadableStreamClose(stream).
   return ReadableStreamCloseInternal(cx, unwrappedStream);
 }
 
 // Streams spec, 3.12.11. ReadableByteStreamControllerError ( controller, e )
 // Unified with 3.9.7 above.
 
 // Streams spec 3.12.14.
 //      ReadableByteStreamControllerGetDesiredSize ( controller )
@@ -3902,16 +3917,20 @@ static MOZ_MUST_USE bool ReadableByteStr
   Rooted<ReadableStream*> unwrappedStream(cx, unwrappedController->stream());
   MOZ_ASSERT(unwrappedStream->readable());
 
   // Step 2: If controller.[[queueTotalSize]] is 0 and
   //         controller.[[closeRequested]] is true,
   if (unwrappedController->queueTotalSize() == 0 &&
       unwrappedController->closeRequested()) {
     // Step a: Perform
+    //         ! ReadableByteStreamControllerClearAlgorithms(controller).
+    ReadableStreamControllerClearAlgorithms(unwrappedController);
+
+    // Step b: Perform
     //         ! ReadableStreamClose(controller.[[controlledReadableStream]]).
     return ReadableStreamCloseInternal(cx, unwrappedStream);
   }
 
   // Step 3: Otherwise,
   // Step a: Perform ! ReadableByteStreamControllerCallPullIfNeeded(controller).
   return ReadableStreamControllerCallPullIfNeeded(cx, unwrappedController);
 }