tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ReadableByteStreamController.cpp (81573B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "mozilla/dom/ReadableByteStreamController.h"
      8 
      9 #include <algorithm>  // std::min
     10 
     11 #include "ReadIntoRequest.h"
     12 #include "js/ArrayBuffer.h"
     13 #include "js/ErrorReport.h"
     14 #include "js/Exception.h"
     15 #include "js/TypeDecls.h"
     16 #include "js/Value.h"
     17 #include "js/ValueArray.h"
     18 #include "js/experimental/TypedData.h"
     19 #include "js/friend/ErrorMessages.h"
     20 #include "mozilla/AlreadyAddRefed.h"
     21 #include "mozilla/Attributes.h"
     22 #include "mozilla/ErrorResult.h"
     23 #include "mozilla/HoldDropJSObjects.h"
     24 #include "mozilla/dom/ByteStreamHelpers.h"
     25 #include "mozilla/dom/Promise-inl.h"
     26 #include "mozilla/dom/Promise.h"
     27 #include "mozilla/dom/ReadableByteStreamControllerBinding.h"
     28 #include "mozilla/dom/ReadableStream.h"
     29 #include "mozilla/dom/ReadableStreamBYOBReader.h"
     30 #include "mozilla/dom/ReadableStreamBYOBRequest.h"
     31 #include "mozilla/dom/ReadableStreamControllerBase.h"
     32 #include "mozilla/dom/ReadableStreamDefaultController.h"
     33 #include "mozilla/dom/ReadableStreamDefaultReader.h"
     34 #include "mozilla/dom/ReadableStreamGenericReader.h"
     35 #include "mozilla/dom/ScriptSettings.h"
     36 #include "mozilla/dom/ToJSValue.h"
     37 #include "mozilla/dom/UnderlyingSourceCallbackHelpers.h"
     38 #include "nsCycleCollectionParticipant.h"
     39 #include "nsIGlobalObject.h"
     40 #include "nsISupports.h"
     41 
     42 namespace mozilla::dom {
     43 
     44 using namespace streams_abstract;
     45 
     46 // https://streams.spec.whatwg.org/#readable-byte-stream-queue-entry
     47 struct ReadableByteStreamQueueEntry
     48    : LinkedListElement<RefPtr<ReadableByteStreamQueueEntry>> {
     49  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(
     50      ReadableByteStreamQueueEntry)
     51  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(
     52      ReadableByteStreamQueueEntry)
     53 
     54  ReadableByteStreamQueueEntry(JS::Handle<JSObject*> aBuffer,
     55                               size_t aByteOffset, size_t aByteLength)
     56      : mBuffer(aBuffer), mByteOffset(aByteOffset), mByteLength(aByteLength) {
     57    mozilla::HoldJSObjects(this);
     58  }
     59 
     60  JSObject* Buffer() const { return mBuffer; }
     61  void SetBuffer(JS::Handle<JSObject*> aBuffer) { mBuffer = aBuffer; }
     62 
     63  size_t ByteOffset() const { return mByteOffset; }
     64  void SetByteOffset(size_t aByteOffset) { mByteOffset = aByteOffset; }
     65 
     66  size_t ByteLength() const { return mByteLength; }
     67  void SetByteLength(size_t aByteLength) { mByteLength = aByteLength; }
     68 
     69 private:
     70  // An ArrayBuffer, which will be a transferred version of the one originally
     71  // supplied by the underlying byte source.
     72  JS::Heap<JSObject*> mBuffer;
     73 
     74  // A nonnegative integer number giving the byte offset derived from the view
     75  // originally supplied by the underlying byte source
     76  size_t mByteOffset = 0;
     77 
     78  // A nonnegative integer number giving the byte length derived from the view
     79  // originally supplied by the underlying byte source
     80  size_t mByteLength = 0;
     81 
     82  ~ReadableByteStreamQueueEntry() { mozilla::DropJSObjects(this); }
     83 };
     84 
     85 NS_IMPL_CYCLE_COLLECTION_WITH_JS_MEMBERS(ReadableByteStreamQueueEntry, (),
     86                                         (mBuffer));
     87 
     88 struct PullIntoDescriptor final
     89    : LinkedListElement<RefPtr<PullIntoDescriptor>> {
     90  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(PullIntoDescriptor)
     91  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(PullIntoDescriptor)
     92 
     93  enum Constructor {
     94    DataView,
     95 #define DEFINE_TYPED_CONSTRUCTOR_ENUM_NAMES(ExternalT, NativeT, Name) Name,
     96    JS_FOR_EACH_TYPED_ARRAY(DEFINE_TYPED_CONSTRUCTOR_ENUM_NAMES)
     97 #undef DEFINE_TYPED_CONSTRUCTOR_ENUM_NAMES
     98  };
     99 
    100  static Constructor constructorFromScalar(JS::Scalar::Type type) {
    101    switch (type) {
    102 #define REMAP_PULL_INTO_DESCRIPTOR_TYPE(ExternalT, NativeT, Name) \
    103  case JS::Scalar::Name:                                          \
    104    return Constructor::Name;
    105      JS_FOR_EACH_TYPED_ARRAY(REMAP_PULL_INTO_DESCRIPTOR_TYPE)
    106 #undef REMAP
    107 
    108      case JS::Scalar::Int64:
    109      case JS::Scalar::Simd128:
    110      case JS::Scalar::MaxTypedArrayViewType:
    111        break;
    112    }
    113    MOZ_CRASH("Unexpected Scalar::Type");
    114  }
    115 
    116  PullIntoDescriptor(JS::Handle<JSObject*> aBuffer, uint64_t aBufferByteLength,
    117                     uint64_t aByteOffset, uint64_t aByteLength,
    118                     uint64_t aBytesFilled, uint64_t aMinimumFill,
    119                     uint64_t aElementSize, Constructor aViewConstructor,
    120                     ReaderType aReaderType)
    121      : mBuffer(aBuffer),
    122        mBufferByteLength(aBufferByteLength),
    123        mByteOffset(aByteOffset),
    124        mByteLength(aByteLength),
    125        mBytesFilled(aBytesFilled),
    126        mMinimumFill(aMinimumFill),
    127        mElementSize(aElementSize),
    128        mViewConstructor(aViewConstructor),
    129        mReaderType(aReaderType) {
    130    mozilla::HoldJSObjects(this);
    131  }
    132 
    133  JSObject* Buffer() const { return mBuffer; }
    134  void SetBuffer(JS::Handle<JSObject*> aBuffer) { mBuffer = aBuffer; }
    135 
    136  uint64_t BufferByteLength() const { return mBufferByteLength; }
    137  void SetBufferByteLength(const uint64_t aBufferByteLength) {
    138    mBufferByteLength = aBufferByteLength;
    139  }
    140 
    141  uint64_t ByteOffset() const { return mByteOffset; }
    142  void SetByteOffset(const uint64_t aByteOffset) { mByteOffset = aByteOffset; }
    143 
    144  uint64_t ByteLength() const { return mByteLength; }
    145  void SetByteLength(const uint64_t aByteLength) { mByteLength = aByteLength; }
    146 
    147  uint64_t BytesFilled() const { return mBytesFilled; }
    148  void SetBytesFilled(const uint64_t aBytesFilled) {
    149    mBytesFilled = aBytesFilled;
    150  }
    151 
    152  uint64_t MinimumFill() const { return mMinimumFill; }
    153 
    154  uint64_t ElementSize() const { return mElementSize; }
    155  void SetElementSize(const uint64_t aElementSize) {
    156    mElementSize = aElementSize;
    157  }
    158 
    159  Constructor ViewConstructor() const { return mViewConstructor; }
    160 
    161  // Note: Named GetReaderType to avoid name conflict with type.
    162  ReaderType GetReaderType() const { return mReaderType; }
    163  void SetReaderType(const ReaderType aReaderType) {
    164    mReaderType = aReaderType;
    165  }
    166 
    167 private:
    168  JS::Heap<JSObject*> mBuffer;
    169  uint64_t mBufferByteLength = 0;
    170  uint64_t mByteOffset = 0;
    171  uint64_t mByteLength = 0;
    172  uint64_t mBytesFilled = 0;
    173  uint64_t mMinimumFill = 0;
    174  uint64_t mElementSize = 0;
    175  Constructor mViewConstructor;
    176  ReaderType mReaderType;
    177 
    178  ~PullIntoDescriptor() { mozilla::DropJSObjects(this); }
    179 };
    180 
    181 NS_IMPL_CYCLE_COLLECTION_WITH_JS_MEMBERS(PullIntoDescriptor, (), (mBuffer));
    182 
    183 NS_IMPL_CYCLE_COLLECTION_CLASS(ReadableByteStreamController)
    184 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ReadableByteStreamController,
    185                                                ReadableStreamControllerBase)
    186  NS_IMPL_CYCLE_COLLECTION_UNLINK(mByobRequest, mQueue, mPendingPullIntos)
    187  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
    188 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    189 
    190 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ReadableByteStreamController,
    191                                                  ReadableStreamControllerBase)
    192  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mByobRequest, mQueue, mPendingPullIntos)
    193 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    194 
    195 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(ReadableByteStreamController,
    196                                               ReadableStreamControllerBase)
    197  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
    198 NS_IMPL_CYCLE_COLLECTION_TRACE_END
    199 
    200 NS_IMPL_ADDREF_INHERITED(ReadableByteStreamController,
    201                         ReadableStreamControllerBase)
    202 NS_IMPL_RELEASE_INHERITED(ReadableByteStreamController,
    203                          ReadableStreamControllerBase)
    204 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ReadableByteStreamController)
    205  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
    206 NS_INTERFACE_MAP_END_INHERITING(ReadableStreamControllerBase)
    207 
    208 ReadableByteStreamController::ReadableByteStreamController(
    209    nsIGlobalObject* aGlobal)
    210    : ReadableStreamControllerBase(aGlobal) {}
    211 
    212 ReadableByteStreamController::~ReadableByteStreamController() = default;
    213 
    214 void ReadableByteStreamController::ClearQueue() { mQueue.clear(); }
    215 
    216 void ReadableByteStreamController::ClearPendingPullIntos() {
    217  mPendingPullIntos.clear();
    218 }
    219 
    220 namespace streams_abstract {
    221 // https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamcontrollergetbyobrequest
    222 already_AddRefed<ReadableStreamBYOBRequest>
    223 ReadableByteStreamControllerGetBYOBRequest(
    224    JSContext* aCx, ReadableByteStreamController* aController,
    225    ErrorResult& aRv) {
    226  // Step 1.
    227  if (!aController->GetByobRequest() &&
    228      !aController->PendingPullIntos().isEmpty()) {
    229    // Step 1.1:
    230    PullIntoDescriptor* firstDescriptor =
    231        aController->PendingPullIntos().getFirst();
    232 
    233    // Step 1.2:
    234    aRv.MightThrowJSException();
    235    JS::Rooted<JSObject*> buffer(aCx, firstDescriptor->Buffer());
    236    JS::Rooted<JSObject*> view(
    237        aCx, JS_NewUint8ArrayWithBuffer(
    238                 aCx, buffer,
    239                 firstDescriptor->ByteOffset() + firstDescriptor->BytesFilled(),
    240                 int64_t(firstDescriptor->ByteLength() -
    241                         firstDescriptor->BytesFilled())));
    242    if (!view) {
    243      aRv.StealExceptionFromJSContext(aCx);
    244      return nullptr;
    245    }
    246 
    247    // Step 1.3:
    248    RefPtr<ReadableStreamBYOBRequest> byobRequest =
    249        new ReadableStreamBYOBRequest(aController->GetParentObject());
    250 
    251    // Step 1.4:
    252    byobRequest->SetController(aController);
    253 
    254    // Step 1.5:
    255    byobRequest->SetView(view);
    256 
    257    // Step 1.6:
    258    aController->SetByobRequest(byobRequest);
    259  }
    260 
    261  // Step 2.
    262  RefPtr<ReadableStreamBYOBRequest> request(aController->GetByobRequest());
    263  return request.forget();
    264 }
    265 }  // namespace streams_abstract
    266 
    267 already_AddRefed<ReadableStreamBYOBRequest>
    268 ReadableByteStreamController::GetByobRequest(JSContext* aCx, ErrorResult& aRv) {
    269  return ReadableByteStreamControllerGetBYOBRequest(aCx, this, aRv);
    270 }
    271 
    272 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-get-desired-size
    273 Nullable<double> ReadableByteStreamControllerGetDesiredSize(
    274    const ReadableByteStreamController* aController) {
    275  // Step 1.
    276  ReadableStream::ReaderState state = aController->Stream()->State();
    277 
    278  // Step 2.
    279  if (state == ReadableStream::ReaderState::Errored) {
    280    return nullptr;
    281  }
    282 
    283  // Step 3.
    284  if (state == ReadableStream::ReaderState::Closed) {
    285    return 0.0;
    286  }
    287 
    288  // Step 4.
    289  return aController->StrategyHWM() - aController->QueueTotalSize();
    290 }
    291 
    292 Nullable<double> ReadableByteStreamController::GetDesiredSize() const {
    293  // Step 1.
    294  return ReadableByteStreamControllerGetDesiredSize(this);
    295 }
    296 
    297 JSObject* ReadableByteStreamController::WrapObject(
    298    JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
    299  return ReadableByteStreamController_Binding::Wrap(aCx, this, aGivenProto);
    300 }
    301 
    302 namespace streams_abstract {
    303 
    304 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-invalidate-byob-request
    305 static void ReadableByteStreamControllerInvalidateBYOBRequest(
    306    ReadableByteStreamController* aController) {
    307  // Step 1.
    308  if (!aController->GetByobRequest()) {
    309    return;
    310  }
    311 
    312  // Step 2.
    313  aController->GetByobRequest()->SetController(nullptr);
    314 
    315  // Step 3.
    316  aController->GetByobRequest()->SetView(nullptr);
    317 
    318  // Step 4.
    319  aController->SetByobRequest(nullptr);
    320 }
    321 
    322 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-clear-pending-pull-intos
    323 void ReadableByteStreamControllerClearPendingPullIntos(
    324    ReadableByteStreamController* aController) {
    325  // Step 1.
    326  ReadableByteStreamControllerInvalidateBYOBRequest(aController);
    327 
    328  // Step 2.
    329  aController->ClearPendingPullIntos();
    330 }
    331 
    332 // https://streams.spec.whatwg.org/#reset-queue
    333 void ResetQueue(ReadableByteStreamController* aContainer) {
    334  // Step 1. Implied by type.
    335  // Step 2.
    336  aContainer->ClearQueue();
    337 
    338  // Step 3.
    339  aContainer->SetQueueTotalSize(0);
    340 }
    341 
    342 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-clear-algorithms
    343 void ReadableByteStreamControllerClearAlgorithms(
    344    ReadableByteStreamController* aController) {
    345  // Step 1. Set controller.[[pullAlgorithm]] to undefined.
    346  // Step 2. Set controller.[[cancelAlgorithm]] to undefined.
    347  aController->ClearAlgorithms();
    348 }
    349 
    350 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-error
    351 void ReadableByteStreamControllerError(
    352    ReadableByteStreamController* aController, JS::Handle<JS::Value> aValue,
    353    ErrorResult& aRv) {
    354  // Step 1. Let stream be controller.[[stream]].
    355  ReadableStream* stream = aController->Stream();
    356 
    357  // Step 2. If stream.[[state]] is not "readable", return.
    358  if (stream->State() != ReadableStream::ReaderState::Readable) {
    359    return;
    360  }
    361 
    362  // Step 3. Perform
    363  // !ReadableByteStreamControllerClearPendingPullIntos(controller).
    364  ReadableByteStreamControllerClearPendingPullIntos(aController);
    365 
    366  // Step 4. Perform !ResetQueue(controller).
    367  ResetQueue(aController);
    368 
    369  // Step 5. Perform !ReadableByteStreamControllerClearAlgorithms(controller).
    370  ReadableByteStreamControllerClearAlgorithms(aController);
    371 
    372  // Step 6. Perform !ReadableStreamError(stream, e).
    373  AutoJSAPI jsapi;
    374  if (!jsapi.Init(aController->GetParentObject())) {
    375    return;
    376  }
    377  ReadableStreamError(jsapi.cx(), stream, aValue, aRv);
    378 }
    379 
    380 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-close
    381 void ReadableByteStreamControllerClose(
    382    JSContext* aCx, ReadableByteStreamController* aController,
    383    ErrorResult& aRv) {
    384  // Step 1.
    385  RefPtr<ReadableStream> stream = aController->Stream();
    386 
    387  // Step 2.
    388  if (aController->CloseRequested() ||
    389      stream->State() != ReadableStream::ReaderState::Readable) {
    390    return;
    391  }
    392 
    393  // Step 3.
    394  if (aController->QueueTotalSize() > 0) {
    395    // Step 3.1
    396    aController->SetCloseRequested(true);
    397    // Step 3.2
    398    return;
    399  }
    400 
    401  // Step 4.
    402  if (!aController->PendingPullIntos().isEmpty()) {
    403    // Step 4.1. Let firstPendingPullInto be controller.[[pendingPullIntos]][0].
    404    PullIntoDescriptor* firstPendingPullInto =
    405        aController->PendingPullIntos().getFirst();
    406 
    407    // Step 4.2. If the remainder after dividing firstPendingPullInto’s bytes
    408    // filled by firstPendingPullInto’s element size is not 0,
    409    if ((firstPendingPullInto->BytesFilled() %
    410         firstPendingPullInto->ElementSize()) != 0) {
    411      // Step 4.2.1
    412      ErrorResult rv;
    413      rv.ThrowTypeError("Leftover Bytes");
    414 
    415      JS::Rooted<JS::Value> exception(aCx);
    416      MOZ_ALWAYS_TRUE(ToJSValue(aCx, std::move(rv), &exception));
    417 
    418      // Step 4.2.2
    419      ReadableByteStreamControllerError(aController, exception, aRv);
    420      if (aRv.Failed()) {
    421        return;
    422      }
    423 
    424      aRv.MightThrowJSException();
    425      aRv.ThrowJSException(aCx, exception);
    426      return;
    427    }
    428  }
    429 
    430  // Step 5.
    431  ReadableByteStreamControllerClearAlgorithms(aController);
    432 
    433  // Step 6.
    434  ReadableStreamClose(aCx, stream, aRv);
    435 }
    436 
    437 }  // namespace streams_abstract
    438 
    439 // https://streams.spec.whatwg.org/#rbs-controller-close
    440 void ReadableByteStreamController::Close(JSContext* aCx, ErrorResult& aRv) {
    441  // Step 1.
    442  if (mCloseRequested) {
    443    aRv.ThrowTypeError("Close already requested");
    444    return;
    445  }
    446 
    447  // Step 2.
    448  if (Stream()->State() != ReadableStream::ReaderState::Readable) {
    449    aRv.ThrowTypeError("Closing un-readable stream controller");
    450    return;
    451  }
    452 
    453  // Step 3.
    454  ReadableByteStreamControllerClose(aCx, this, aRv);
    455 }
    456 
    457 namespace streams_abstract {
    458 
    459 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-enqueue-chunk-to-queue
    460 void ReadableByteStreamControllerEnqueueChunkToQueue(
    461    ReadableByteStreamController* aController,
    462    JS::Handle<JSObject*> aTransferredBuffer, size_t aByteOffset,
    463    size_t aByteLength) {
    464  // Step 1.
    465  RefPtr<ReadableByteStreamQueueEntry> queueEntry =
    466      new ReadableByteStreamQueueEntry(aTransferredBuffer, aByteOffset,
    467                                       aByteLength);
    468  aController->Queue().insertBack(queueEntry);
    469 
    470  // Step 2.
    471  aController->AddToQueueTotalSize(double(aByteLength));
    472 }
    473 
    474 // https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamcontrollerenqueueclonedchunktoqueue
    475 void ReadableByteStreamControllerEnqueueClonedChunkToQueue(
    476    JSContext* aCx, ReadableByteStreamController* aController,
    477    JS::Handle<JSObject*> aBuffer, size_t aByteOffset, size_t aByteLength,
    478    ErrorResult& aRv) {
    479  // Step 1. Let cloneResult be CloneArrayBuffer(buffer, byteOffset, byteLength,
    480  // %ArrayBuffer%).
    481  aRv.MightThrowJSException();
    482  JS::Rooted<JSObject*> cloneResult(
    483      aCx, JS::ArrayBufferClone(aCx, aBuffer, aByteOffset, aByteLength));
    484 
    485  // Step 2. If cloneResult is an abrupt completion,
    486  if (!cloneResult) {
    487    JS::Rooted<JS::Value> exception(aCx);
    488    if (!JS_GetPendingException(aCx, &exception)) {
    489      // Uncatchable exception; we should mark aRv and return.
    490      aRv.StealExceptionFromJSContext(aCx);
    491      return;
    492    }
    493    JS_ClearPendingException(aCx);
    494 
    495    // Step 2.1. Perform ! ReadableByteStreamControllerError(controller,
    496    // cloneResult.[[Value]]).
    497    ReadableByteStreamControllerError(aController, exception, aRv);
    498    if (aRv.Failed()) {
    499      return;
    500    }
    501 
    502    // Step 2.2. Return cloneResult.
    503    aRv.ThrowJSException(aCx, exception);
    504    return;
    505  }
    506 
    507  // Step 3. Perform !
    508  // ReadableByteStreamControllerEnqueueChunkToQueue(controller,
    509  // cloneResult.[[Value]], 0, byteLength).
    510  ReadableByteStreamControllerEnqueueChunkToQueue(aController, cloneResult, 0,
    511                                                  aByteLength);
    512 }
    513 
    514 already_AddRefed<PullIntoDescriptor>
    515 ReadableByteStreamControllerShiftPendingPullInto(
    516    ReadableByteStreamController* aController);
    517 
    518 // https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamcontrollerenqueuedetachedpullintotoqueue
    519 void ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue(
    520    JSContext* aCx, ReadableByteStreamController* aController,
    521    PullIntoDescriptor* aPullIntoDescriptor, ErrorResult& aRv) {
    522  // Step 1. Assert: pullIntoDescriptor’s reader type is "none".
    523  MOZ_ASSERT(aPullIntoDescriptor->GetReaderType() == ReaderType::None);
    524 
    525  // Step 2. If pullIntoDescriptor’s bytes filled > 0,
    526  // perform ? ReadableByteStreamControllerEnqueueClonedChunkToQueue(controller,
    527  // pullIntoDescriptor’s buffer, pullIntoDescriptor’s byte offset,
    528  // pullIntoDescriptor’s bytes filled).
    529  if (aPullIntoDescriptor->BytesFilled() > 0) {
    530    JS::Rooted<JSObject*> buffer(aCx, aPullIntoDescriptor->Buffer());
    531    ReadableByteStreamControllerEnqueueClonedChunkToQueue(
    532        aCx, aController, buffer, aPullIntoDescriptor->ByteOffset(),
    533        aPullIntoDescriptor->BytesFilled(), aRv);
    534    if (aRv.Failed()) {
    535      return;
    536    }
    537  }
    538 
    539  // Step 3. Perform !
    540  // ReadableByteStreamControllerShiftPendingPullInto(controller).
    541  RefPtr<PullIntoDescriptor> discarded =
    542      ReadableByteStreamControllerShiftPendingPullInto(aController);
    543  (void)discarded;
    544 }
    545 
    546 // https://streams.spec.whatwg.org/#readable-stream-get-num-read-into-requests
    547 static size_t ReadableStreamGetNumReadIntoRequests(ReadableStream* aStream) {
    548  // Step 1.
    549  MOZ_ASSERT(ReadableStreamHasBYOBReader(aStream));
    550 
    551  // Step 2.
    552  return aStream->GetReader()->AsBYOB()->ReadIntoRequests().length();
    553 }
    554 
    555 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-should-call-pull
    556 bool ReadableByteStreamControllerShouldCallPull(
    557    ReadableByteStreamController* aController) {
    558  // Step 1. Let stream be controller.[[stream]].
    559  ReadableStream* stream = aController->Stream();
    560 
    561  // Step 2. If stream.[[state]] is not "readable", return false.
    562  if (stream->State() != ReadableStream::ReaderState::Readable) {
    563    return false;
    564  }
    565 
    566  // Step 3. If controller.[[closeRequested]] is true, return false.
    567  if (aController->CloseRequested()) {
    568    return false;
    569  }
    570 
    571  // Step 4. If controller.[[started]] is false, return false.
    572  if (!aController->Started()) {
    573    return false;
    574  }
    575 
    576  // Step 5. If ! ReadableStreamHasDefaultReader(stream) is true
    577  // and ! ReadableStreamGetNumReadRequests(stream) > 0, return true.
    578  if (ReadableStreamHasDefaultReader(stream) &&
    579      ReadableStreamGetNumReadRequests(stream) > 0) {
    580    return true;
    581  }
    582 
    583  // Step 6. If ! ReadableStreamHasBYOBReader(stream) is true
    584  // and ! ReadableStreamGetNumReadIntoRequests(stream) > 0, return true.
    585  if (ReadableStreamHasBYOBReader(stream) &&
    586      ReadableStreamGetNumReadIntoRequests(stream) > 0) {
    587    return true;
    588  }
    589 
    590  // Step 7. Let desiredSize be
    591  // ! ReadableByteStreamControllerGetDesiredSize(controller).
    592  Nullable<double> desiredSize =
    593      ReadableByteStreamControllerGetDesiredSize(aController);
    594 
    595  // Step 8. Assert: desiredSize is not null.
    596  MOZ_ASSERT(!desiredSize.IsNull());
    597 
    598  // Step 9. If desiredSize > 0, return true.
    599  // Step 10. Return false.
    600  return desiredSize.Value() > 0;
    601 }
    602 
    603 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-call-pull-if-needed
    604 void ReadableByteStreamControllerCallPullIfNeeded(
    605    JSContext* aCx, ReadableByteStreamController* aController,
    606    ErrorResult& aRv) {
    607  // Step 1.
    608  bool shouldPull = ReadableByteStreamControllerShouldCallPull(aController);
    609 
    610  // Step 2.
    611  if (!shouldPull) {
    612    return;
    613  }
    614 
    615  // Step 3.
    616  if (aController->Pulling()) {
    617    aController->SetPullAgain(true);
    618    return;
    619  }
    620 
    621  // Step 4.
    622  MOZ_ASSERT(!aController->PullAgain());
    623 
    624  // Step 5.
    625  aController->SetPulling(true);
    626 
    627  // Step 6.
    628  RefPtr<ReadableStreamControllerBase> controller(aController);
    629  RefPtr<UnderlyingSourceAlgorithmsBase> algorithms =
    630      aController->GetAlgorithms();
    631  RefPtr<Promise> pullPromise = algorithms->PullCallback(aCx, *controller, aRv);
    632  if (aRv.Failed()) {
    633    return;
    634  }
    635 
    636  // Steps 7+8
    637  pullPromise->AddCallbacksWithCycleCollectedArgs(
    638      [](JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv,
    639         ReadableByteStreamController* aController)
    640          MOZ_CAN_RUN_SCRIPT_BOUNDARY {
    641            // Step 7.1
    642            aController->SetPulling(false);
    643            // Step 7.2
    644            if (aController->PullAgain()) {
    645              // Step 7.2.1
    646              aController->SetPullAgain(false);
    647 
    648              // Step 7.2.2
    649              ReadableByteStreamControllerCallPullIfNeeded(
    650                  aCx, MOZ_KnownLive(aController), aRv);
    651            }
    652          },
    653      [](JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv,
    654         ReadableByteStreamController* aController) {
    655        // Step 8.1
    656        ReadableByteStreamControllerError(aController, aValue, aRv);
    657      },
    658      RefPtr(aController));
    659 }
    660 
    661 bool ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(
    662    JSContext* aCx, ReadableByteStreamController* aController,
    663    PullIntoDescriptor* aPullIntoDescriptor, ErrorResult& aRv);
    664 
    665 JSObject* ReadableByteStreamControllerConvertPullIntoDescriptor(
    666    JSContext* aCx, PullIntoDescriptor* pullIntoDescriptor, ErrorResult& aRv);
    667 
    668 // https://streams.spec.whatwg.org/#readable-stream-fulfill-read-into-request
    669 MOZ_CAN_RUN_SCRIPT
    670 void ReadableStreamFulfillReadIntoRequest(JSContext* aCx,
    671                                          ReadableStream* aStream,
    672                                          JS::Handle<JS::Value> aChunk,
    673                                          bool done, ErrorResult& aRv) {
    674  // Step 1. Assert: !ReadableStreamHasBYOBReader(stream) is true.
    675  MOZ_ASSERT(ReadableStreamHasBYOBReader(aStream));
    676 
    677  // Step 2. Let reader be stream.[[reader]].
    678  ReadableStreamBYOBReader* reader = aStream->GetReader()->AsBYOB();
    679 
    680  // Step 3. Assert: reader.[[readIntoRequests]] is not empty.
    681  MOZ_ASSERT(!reader->ReadIntoRequests().isEmpty());
    682 
    683  // Step 4. Let readIntoRequest be reader.[[readIntoRequests]][0].
    684  // Step 5. Remove readIntoRequest from reader.[[readIntoRequests]].
    685  RefPtr<ReadIntoRequest> readIntoRequest =
    686      reader->ReadIntoRequests().popFirst();
    687 
    688  // Step 6. If done is true, perform readIntoRequest’s close steps, given
    689  // chunk.
    690  if (done) {
    691    readIntoRequest->CloseSteps(aCx, aChunk, aRv);
    692    return;
    693  }
    694 
    695  // Step 7. Otherwise, perform readIntoRequest’s chunk steps, given chunk.
    696  readIntoRequest->ChunkSteps(aCx, aChunk, aRv);
    697 }
    698 
    699 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-commit-pull-into-descriptor
    700 MOZ_CAN_RUN_SCRIPT
    701 void ReadableByteStreamControllerCommitPullIntoDescriptor(
    702    JSContext* aCx, ReadableStream* aStream,
    703    PullIntoDescriptor* pullIntoDescriptor, ErrorResult& aRv) {
    704  // Step 1. Assert: stream.[[state]] is not "errored".
    705  MOZ_ASSERT(aStream->State() != ReadableStream::ReaderState::Errored);
    706 
    707  // Step 2. Assert: pullIntoDescriptor.reader type is not "none".
    708  MOZ_ASSERT(pullIntoDescriptor->GetReaderType() != ReaderType::None);
    709 
    710  // Step 3. Let done be false.
    711  bool done = false;
    712 
    713  // Step 4. If stream.[[state]] is "closed",
    714  if (aStream->State() == ReadableStream::ReaderState::Closed) {
    715    // Step 4.1. Assert: the remainder after dividing pullIntoDescriptor’s bytes
    716    // filled by pullIntoDescriptor’s element size is 0.
    717    MOZ_ASSERT((pullIntoDescriptor->BytesFilled() %
    718                pullIntoDescriptor->ElementSize()) == 0);
    719 
    720    // Step 4.2. Set done to true.
    721    done = true;
    722  }
    723 
    724  // Step 5. Let filledView be !
    725  // ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor).
    726  JS::Rooted<JSObject*> filledView(
    727      aCx, ReadableByteStreamControllerConvertPullIntoDescriptor(
    728               aCx, pullIntoDescriptor, aRv));
    729  if (aRv.Failed()) {
    730    return;
    731  }
    732  JS::Rooted<JS::Value> filledViewValue(aCx, JS::ObjectValue(*filledView));
    733 
    734  // Step 6. If pullIntoDescriptor’s reader type is "default",
    735  if (pullIntoDescriptor->GetReaderType() == ReaderType::Default) {
    736    // Step 6.1. Perform !ReadableStreamFulfillReadRequest(stream, filledView,
    737    // done).
    738    ReadableStreamFulfillReadRequest(aCx, aStream, filledViewValue, done, aRv);
    739    return;
    740  }
    741 
    742  // Step 7.1. Assert: pullIntoDescriptor’s reader type is "byob".
    743  MOZ_ASSERT(pullIntoDescriptor->GetReaderType() == ReaderType::BYOB);
    744 
    745  // Step 7.2 Perform !ReadableStreamFulfillReadIntoRequest(stream, filledView,
    746  // done).
    747  ReadableStreamFulfillReadIntoRequest(aCx, aStream, filledViewValue, done,
    748                                       aRv);
    749 }
    750 
    751 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-process-pull-into-descriptors-using-queue
    752 MOZ_CAN_RUN_SCRIPT
    753 void ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(
    754    JSContext* aCx, ReadableByteStreamController* aController,
    755    nsTArray<RefPtr<PullIntoDescriptor>>& aFilledPullIntos, ErrorResult& aRv) {
    756  // Step 1. Assert: controller.[[closeRequested]] is false.
    757  MOZ_ASSERT(!aController->CloseRequested());
    758 
    759  // Step 2. Let filledPullIntos be a new empty list.
    760  MOZ_ASSERT(aFilledPullIntos.IsEmpty());
    761 
    762  // Step 3. While controller.[[pendingPullIntos]] is not empty,
    763  while (!aController->PendingPullIntos().isEmpty()) {
    764    // Step 3.1. If controller.[[queueTotalSize]] is 0, then break.
    765    if (aController->QueueTotalSize() == 0) {
    766      break;
    767    }
    768 
    769    // Step 3.2. Let pullIntoDescriptor be controller.[[pendingPullIntos]][0].
    770    RefPtr<PullIntoDescriptor> pullIntoDescriptor =
    771        aController->PendingPullIntos().getFirst();
    772 
    773    // Step 3.3. If
    774    // !ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller,
    775    // pullIntoDescriptor) is true,
    776    bool ready = ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(
    777        aCx, aController, pullIntoDescriptor, aRv);
    778    if (aRv.Failed()) {
    779      return;
    780    }
    781 
    782    if (ready) {
    783      //  Step 3.3.1. Perform
    784      //  !ReadableByteStreamControllerShiftPendingPullInto(controller).
    785      RefPtr<PullIntoDescriptor> discardedPullIntoDescriptor =
    786          ReadableByteStreamControllerShiftPendingPullInto(aController);
    787 
    788      // Step 3.3.2. Append pullIntoDescriptor to filledPullIntos.
    789      aFilledPullIntos.AppendElement(pullIntoDescriptor);
    790    }
    791  }
    792 
    793  // Step 4: Return filledPullIntos. (Implicit)
    794 }
    795 
    796 MOZ_CAN_RUN_SCRIPT
    797 void ReadableByteStreamControllerHandleQueueDrain(
    798    JSContext* aCx, ReadableByteStreamController* aController,
    799    ErrorResult& aRv);
    800 
    801 // https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamcontrollerfillreadrequestfromqueue
    802 MOZ_CAN_RUN_SCRIPT void ReadableByteStreamControllerFillReadRequestFromQueue(
    803    JSContext* aCx, ReadableByteStreamController* aController,
    804    ReadRequest* aReadRequest, ErrorResult& aRv) {
    805  // Step 1. Assert: controller.[[queueTotalSize]] > 0.
    806  MOZ_ASSERT(aController->QueueTotalSize() > 0);
    807  // Also assert that the queue has a non-zero length;
    808  MOZ_ASSERT(aController->Queue().length() > 0);
    809 
    810  // Step 2. Let entry be controller.[[queue]][0].
    811  // Step 3. Remove entry from controller.[[queue]].
    812  RefPtr<ReadableByteStreamQueueEntry> entry = aController->Queue().popFirst();
    813 
    814  // Assert that we actually got an entry.
    815  MOZ_ASSERT(entry);
    816 
    817  // Step 4. Set controller.[[queueTotalSize]] to controller.[[queueTotalSize]]
    818  // − entry’s byte length.
    819  aController->SetQueueTotalSize(aController->QueueTotalSize() -
    820                                 double(entry->ByteLength()));
    821 
    822  // Step 5. Perform ! ReadableByteStreamControllerHandleQueueDrain(controller).
    823  ReadableByteStreamControllerHandleQueueDrain(aCx, aController, aRv);
    824  if (aRv.Failed()) {
    825    return;
    826  }
    827 
    828  // Step 6. Let view be ! Construct(%Uint8Array%, « entry’s buffer, entry’s
    829  // byte offset, entry’s byte length »).
    830  aRv.MightThrowJSException();
    831  JS::Rooted<JSObject*> buffer(aCx, entry->Buffer());
    832  JS::Rooted<JSObject*> view(
    833      aCx, JS_NewUint8ArrayWithBuffer(aCx, buffer, entry->ByteOffset(),
    834                                      int64_t(entry->ByteLength())));
    835  if (!view) {
    836    aRv.StealExceptionFromJSContext(aCx);
    837    return;
    838  }
    839 
    840  // Step 7. Perform readRequest’s chunk steps, given view.
    841  JS::Rooted<JS::Value> viewValue(aCx, JS::ObjectValue(*view));
    842  aReadRequest->ChunkSteps(aCx, viewValue, aRv);
    843 }
    844 
    845 MOZ_CAN_RUN_SCRIPT void
    846 ReadableByteStreamControllerProcessReadRequestsUsingQueue(
    847    JSContext* aCx, ReadableByteStreamController* aController,
    848    ErrorResult& aRv) {
    849  // Step 1. Let reader be controller.[[stream]].[[reader]].
    850  // Step 2. Assert: reader implements ReadableStreamDefaultReader.
    851  RefPtr<ReadableStreamDefaultReader> reader =
    852      aController->Stream()->GetDefaultReader();
    853 
    854  // Step 3. While reader.[[readRequests]] is not empty,
    855  while (!reader->ReadRequests().isEmpty()) {
    856    // Step 3.1. If controller.[[queueTotalSize]] is 0, return.
    857    if (aController->QueueTotalSize() == 0) {
    858      return;
    859    }
    860 
    861    // Step 3.2. Let readRequest be reader.[[readRequests]][0].
    862    // Step 3.3. Remove readRequest from reader.[[readRequests]].
    863    RefPtr<ReadRequest> readRequest = reader->ReadRequests().popFirst();
    864 
    865    // Step 3.4. Perform !
    866    // ReadableByteStreamControllerFillReadRequestFromQueue(controller,
    867    // readRequest).
    868    ReadableByteStreamControllerFillReadRequestFromQueue(aCx, aController,
    869                                                         readRequest, aRv);
    870    if (aRv.Failed()) {
    871      return;
    872    }
    873  }
    874 }
    875 
    876 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-enqueue
    877 void ReadableByteStreamControllerEnqueue(
    878    JSContext* aCx, ReadableByteStreamController* aController,
    879    JS::Handle<JSObject*> aChunk, ErrorResult& aRv) {
    880  aRv.MightThrowJSException();
    881 
    882  // Step 1.
    883  RefPtr<ReadableStream> stream = aController->Stream();
    884 
    885  // Step 2.
    886  if (aController->CloseRequested() ||
    887      stream->State() != ReadableStream::ReaderState::Readable) {
    888    return;
    889  }
    890 
    891  // Step 3.
    892  bool isShared;
    893  JS::Rooted<JSObject*> buffer(
    894      aCx, JS_GetArrayBufferViewBuffer(aCx, aChunk, &isShared));
    895  if (!buffer) {
    896    aRv.StealExceptionFromJSContext(aCx);
    897    return;
    898  }
    899 
    900  // Step 4.
    901  size_t byteOffset = JS_GetArrayBufferViewByteOffset(aChunk);
    902 
    903  // Step 5.
    904  size_t byteLength = JS_GetArrayBufferViewByteLength(aChunk);
    905 
    906  // Step 6.
    907  if (JS::IsDetachedArrayBufferObject(buffer)) {
    908    aRv.ThrowTypeError("Detached Array Buffer");
    909    return;
    910  }
    911 
    912  // Step 7.
    913  JS::Rooted<JSObject*> transferredBuffer(aCx,
    914                                          TransferArrayBuffer(aCx, buffer));
    915  if (!transferredBuffer) {
    916    aRv.StealExceptionFromJSContext(aCx);
    917    return;
    918  }
    919 
    920  // Step 8.
    921  if (!aController->PendingPullIntos().isEmpty()) {
    922    // Step 8.1
    923    RefPtr<PullIntoDescriptor> firstPendingPullInto =
    924        aController->PendingPullIntos().getFirst();
    925 
    926    // Step 8.2
    927    JS::Rooted<JSObject*> pendingBuffer(aCx, firstPendingPullInto->Buffer());
    928    if (JS::IsDetachedArrayBufferObject(pendingBuffer)) {
    929      aRv.ThrowTypeError("Pending PullInto has detached buffer");
    930      return;
    931    }
    932 
    933    // Step 8.3. Perform !
    934    // ReadableByteStreamControllerInvalidateBYOBRequest(controller).
    935    ReadableByteStreamControllerInvalidateBYOBRequest(aController);
    936 
    937    // Step 8.4. Set firstPendingPullInto’s buffer to !
    938    // TransferArrayBuffer(firstPendingPullInto’s buffer).
    939    pendingBuffer = TransferArrayBuffer(aCx, pendingBuffer);
    940    if (!pendingBuffer) {
    941      aRv.StealExceptionFromJSContext(aCx);
    942      return;
    943    }
    944    firstPendingPullInto->SetBuffer(pendingBuffer);
    945 
    946    // Step 8.5. If firstPendingPullInto’s reader type is "none", perform ?
    947    // ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue(controller,
    948    // firstPendingPullInto).
    949    if (firstPendingPullInto->GetReaderType() == ReaderType::None) {
    950      ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue(
    951          aCx, aController, firstPendingPullInto, aRv);
    952      if (aRv.Failed()) {
    953        return;
    954      }
    955    }
    956  }
    957 
    958  // Step 9. If ! ReadableStreamHasDefaultReader(stream) is true,
    959  if (ReadableStreamHasDefaultReader(stream)) {
    960    // Step 9.1. Perform !
    961    // ReadableByteStreamControllerProcessReadRequestsUsingQueue(controller).
    962    ReadableByteStreamControllerProcessReadRequestsUsingQueue(aCx, aController,
    963                                                              aRv);
    964    if (aRv.Failed()) {
    965      return;
    966    }
    967 
    968    // Step 9.2. If ! ReadableStreamGetNumReadRequests(stream) is 0,
    969    if (ReadableStreamGetNumReadRequests(stream) == 0) {
    970      // Step 9.2.1 Assert: controller.[[pendingPullIntos]] is empty.
    971      MOZ_ASSERT(aController->PendingPullIntos().isEmpty());
    972 
    973      // Step 9.2.2. Perform !
    974      // ReadableByteStreamControllerEnqueueChunkToQueue(controller,
    975      // transferredBuffer, byteOffset, byteLength).
    976      ReadableByteStreamControllerEnqueueChunkToQueue(
    977          aController, transferredBuffer, byteOffset, byteLength);
    978 
    979      // Step 9.3. Otherwise,
    980    } else {
    981      // Step 9.3.1 Assert: controller.[[queue]] is empty.
    982      MOZ_ASSERT(aController->Queue().isEmpty());
    983 
    984      // Step 9.3.2. If controller.[[pendingPullIntos]] is not empty,
    985      if (!aController->PendingPullIntos().isEmpty()) {
    986        // Step 9.3.2.1. Assert: controller.[[pendingPullIntos]][0]'s reader
    987        // type is "default".
    988        MOZ_ASSERT(
    989            aController->PendingPullIntos().getFirst()->GetReaderType() ==
    990            ReaderType::Default);
    991 
    992        // Step 9.3.2.2. Perform !
    993        // ReadableByteStreamControllerShiftPendingPullInto(controller).
    994        RefPtr<PullIntoDescriptor> pullIntoDescriptor =
    995            ReadableByteStreamControllerShiftPendingPullInto(aController);
    996        (void)pullIntoDescriptor;
    997      }
    998 
    999      // Step 9.3.3. Let transferredView be ! Construct(%Uint8Array%, «
   1000      // transferredBuffer, byteOffset, byteLength »).
   1001      JS::Rooted<JSObject*> transferredView(
   1002          aCx, JS_NewUint8ArrayWithBuffer(aCx, transferredBuffer, byteOffset,
   1003                                          int64_t(byteLength)));
   1004      if (!transferredView) {
   1005        aRv.StealExceptionFromJSContext(aCx);
   1006        return;
   1007      }
   1008 
   1009      // Step 9.3.4. Perform ! ReadableStreamFulfillReadRequest(stream,
   1010      // transferredView, false).
   1011      JS::Rooted<JS::Value> transferredViewValue(
   1012          aCx, JS::ObjectValue(*transferredView));
   1013      ReadableStreamFulfillReadRequest(aCx, stream, transferredViewValue, false,
   1014                                       aRv);
   1015      if (aRv.Failed()) {
   1016        return;
   1017      }
   1018    }
   1019 
   1020    // Step 10. Otherwise, if ! ReadableStreamHasBYOBReader(stream) is true,
   1021  } else if (ReadableStreamHasBYOBReader(stream)) {
   1022    // Step 10.1. Perform !
   1023    // ReadableByteStreamControllerEnqueueChunkToQueue(controller,
   1024    // transferredBuffer, byteOffset, byteLength).
   1025    ReadableByteStreamControllerEnqueueChunkToQueue(
   1026        aController, transferredBuffer, byteOffset, byteLength);
   1027 
   1028    // Step 10.2. Let filledPullIntos be the result of performing !
   1029    // ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller).
   1030    nsTArray<RefPtr<PullIntoDescriptor>> filledPullIntos;
   1031    ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(
   1032        aCx, aController, filledPullIntos, aRv);
   1033    if (aRv.Failed()) {
   1034      return;
   1035    }
   1036 
   1037    // Step 10.3. For each filledPullInto of filledPullIntos,
   1038    for (auto& filledPullInto : filledPullIntos) {
   1039      // Step 10.3.1. Perform !
   1040      // ReadableByteStreamControllerCommitPullIntoDescriptor(stream,
   1041      // filledPullInto).
   1042      ReadableByteStreamControllerCommitPullIntoDescriptor(
   1043          aCx, stream, MOZ_KnownLive(filledPullInto), aRv);
   1044      if (aRv.Failed()) {
   1045        return;
   1046      }
   1047    }
   1048 
   1049    // Step 11. Otherwise,
   1050  } else {
   1051    // Step 11.1. Assert: ! IsReadableStreamLocked(stream) is false.
   1052    MOZ_ASSERT(!IsReadableStreamLocked(stream));
   1053 
   1054    // Step 11.2. Perform !
   1055    // ReadableByteStreamControllerEnqueueChunkToQueue(controller,
   1056    // transferredBuffer, byteOffset, byteLength).
   1057    ReadableByteStreamControllerEnqueueChunkToQueue(
   1058        aController, transferredBuffer, byteOffset, byteLength);
   1059  }
   1060 
   1061  // Step 12. Perform !
   1062  // ReadableByteStreamControllerCallPullIfNeeded(controller).
   1063  ReadableByteStreamControllerCallPullIfNeeded(aCx, aController, aRv);
   1064 }
   1065 
   1066 }  // namespace streams_abstract
   1067 
   1068 // https://streams.spec.whatwg.org/#rbs-controller-enqueue
   1069 void ReadableByteStreamController::Enqueue(JSContext* aCx,
   1070                                           const ArrayBufferView& aChunk,
   1071                                           ErrorResult& aRv) {
   1072  // Step 1.
   1073  JS::Rooted<JSObject*> chunk(aCx, aChunk.Obj());
   1074  if (JS_GetArrayBufferViewByteLength(chunk) == 0) {
   1075    aRv.ThrowTypeError("Zero Length View");
   1076    return;
   1077  }
   1078 
   1079  // Step 2.
   1080  bool isShared;
   1081  JS::Rooted<JSObject*> viewedArrayBuffer(
   1082      aCx, JS_GetArrayBufferViewBuffer(aCx, chunk, &isShared));
   1083  if (!viewedArrayBuffer) {
   1084    aRv.StealExceptionFromJSContext(aCx);
   1085    return;
   1086  }
   1087 
   1088  if (JS::GetArrayBufferByteLength(viewedArrayBuffer) == 0) {
   1089    aRv.ThrowTypeError("Zero Length Buffer");
   1090    return;
   1091  }
   1092 
   1093  // Step 3.
   1094  if (CloseRequested()) {
   1095    aRv.ThrowTypeError("close requested");
   1096    return;
   1097  }
   1098 
   1099  // Step 4.
   1100  if (Stream()->State() != ReadableStream::ReaderState::Readable) {
   1101    aRv.ThrowTypeError("Not Readable");
   1102    return;
   1103  }
   1104 
   1105  // Step 5.
   1106  ReadableByteStreamControllerEnqueue(aCx, this, chunk, aRv);
   1107 }
   1108 
   1109 // https://streams.spec.whatwg.org/#rbs-controller-error
   1110 void ReadableByteStreamController::Error(JSContext* aCx,
   1111                                         JS::Handle<JS::Value> aErrorValue,
   1112                                         ErrorResult& aRv) {
   1113  // Step 1.
   1114  ReadableByteStreamControllerError(this, aErrorValue, aRv);
   1115 }
   1116 
   1117 // https://streams.spec.whatwg.org/#rbs-controller-private-cancel
   1118 already_AddRefed<Promise> ReadableByteStreamController::CancelSteps(
   1119    JSContext* aCx, JS::Handle<JS::Value> aReason, ErrorResult& aRv) {
   1120  // Step 1.
   1121  ReadableByteStreamControllerClearPendingPullIntos(this);
   1122 
   1123  // Step 2.
   1124  ResetQueue(this);
   1125 
   1126  // Step 3.
   1127  Optional<JS::Handle<JS::Value>> reason(aCx, aReason);
   1128  RefPtr<UnderlyingSourceAlgorithmsBase> algorithms = mAlgorithms;
   1129  RefPtr<Promise> result = algorithms->CancelCallback(aCx, reason, aRv);
   1130  if (NS_WARN_IF(aRv.Failed())) {
   1131    return nullptr;
   1132  }
   1133  // Step 4.
   1134  ReadableByteStreamControllerClearAlgorithms(this);
   1135 
   1136  // Step 5.
   1137  return result.forget();
   1138 }
   1139 
   1140 namespace streams_abstract {
   1141 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-handle-queue-drain
   1142 void ReadableByteStreamControllerHandleQueueDrain(
   1143    JSContext* aCx, ReadableByteStreamController* aController,
   1144    ErrorResult& aRv) {
   1145  // Step 1.
   1146  MOZ_ASSERT(aController->Stream()->State() ==
   1147             ReadableStream::ReaderState::Readable);
   1148 
   1149  // Step 2.
   1150  if (aController->QueueTotalSize() == 0 && aController->CloseRequested()) {
   1151    // Step 2.1
   1152    ReadableByteStreamControllerClearAlgorithms(aController);
   1153 
   1154    // Step 2.2
   1155    RefPtr<ReadableStream> stream = aController->Stream();
   1156    ReadableStreamClose(aCx, stream, aRv);
   1157    return;
   1158  }
   1159 
   1160  // Step 3.1
   1161  ReadableByteStreamControllerCallPullIfNeeded(aCx, aController, aRv);
   1162 }
   1163 }  // namespace streams_abstract
   1164 
   1165 // https://streams.spec.whatwg.org/#rbs-controller-private-pull
   1166 void ReadableByteStreamController::PullSteps(JSContext* aCx,
   1167                                             ReadRequest* aReadRequest,
   1168                                             ErrorResult& aRv) {
   1169  // Step 1. Let stream be this.[[stream]].
   1170  ReadableStream* stream = Stream();
   1171 
   1172  // Step 2. Assert: ! ReadableStreamHasDefaultReader(stream) is true.
   1173  MOZ_ASSERT(ReadableStreamHasDefaultReader(stream));
   1174 
   1175  // Step 3. If this.[[queueTotalSize]] > 0,
   1176  if (QueueTotalSize() > 0) {
   1177    // Step 3.1. Assert: ! ReadableStreamGetNumReadRequests ( stream ) is 0.
   1178    MOZ_ASSERT(ReadableStreamGetNumReadRequests(stream) == 0);
   1179 
   1180    // Step 3.2. Perform !
   1181    // ReadableByteStreamControllerFillReadRequestFromQueue(this, readRequest).
   1182    ReadableByteStreamControllerFillReadRequestFromQueue(aCx, this,
   1183                                                         aReadRequest, aRv);
   1184 
   1185    // Step 3.3. Return.
   1186    return;
   1187  }
   1188 
   1189  // Step 4. Let autoAllocateChunkSize be this.[[autoAllocateChunkSize]].
   1190  Maybe<uint64_t> autoAllocateChunkSize = AutoAllocateChunkSize();
   1191 
   1192  // Step 5. If autoAllocateChunkSize is not undefined,
   1193  if (autoAllocateChunkSize) {
   1194    // Step 5.1.  Let buffer be Construct(%ArrayBuffer%, « autoAllocateChunkSize
   1195    // »).
   1196    aRv.MightThrowJSException();
   1197    JS::Rooted<JSObject*> buffer(
   1198        aCx, JS::NewArrayBuffer(aCx, *autoAllocateChunkSize));
   1199 
   1200    // Step 5.2. If buffer is an abrupt completion,
   1201    if (!buffer) {
   1202      // Step 5.2.1. Perform readRequest’s error steps, given buffer.[[Value]].
   1203      JS::Rooted<JS::Value> bufferError(aCx);
   1204      if (!JS_GetPendingException(aCx, &bufferError)) {
   1205        // Uncatchable exception; we should mark aRv and return.
   1206        aRv.StealExceptionFromJSContext(aCx);
   1207        return;
   1208      }
   1209 
   1210      // It's not explicitly stated, but I assume the intention here is that
   1211      // we perform a normal completion here.
   1212      JS_ClearPendingException(aCx);
   1213 
   1214      aReadRequest->ErrorSteps(aCx, bufferError, aRv);
   1215 
   1216      // Step 5.2.2. Return.
   1217      return;
   1218    }
   1219 
   1220    // Step 5.3 Let pullIntoDescriptor be a new pull-into descriptor with
   1221    //  buffer              buffer.[[Value]]
   1222    //  buffer byte length  autoAllocateChunkSize
   1223    //  byte offset         0
   1224    //  byte length         autoAllocateChunkSize
   1225    //  bytes filled        0
   1226    //  minimum fill        1
   1227    //  element size        1
   1228    //  view constructor    %Uint8Array%
   1229    //  reader type         "default"
   1230    RefPtr<PullIntoDescriptor> pullIntoDescriptor = new PullIntoDescriptor(
   1231        buffer, /* aBufferByteLength */ *autoAllocateChunkSize,
   1232        /*aByteOffset */ 0, /* aByteLength */ *autoAllocateChunkSize,
   1233        /* aBytesFilled */ 0, /* aMinimumFill */ 1, /* aElementSize */ 1,
   1234        PullIntoDescriptor::Constructor::Uint8, ReaderType::Default);
   1235 
   1236    //  Step 5.4. Append pullIntoDescriptor to this.[[pendingPullIntos]].
   1237    PendingPullIntos().insertBack(pullIntoDescriptor);
   1238  }
   1239 
   1240  // Step 6. Perform ! ReadableStreamAddReadRequest(stream, readRequest).
   1241  ReadableStreamAddReadRequest(stream, aReadRequest);
   1242 
   1243  // Step 7. Perform ! ReadableByteStreamControllerCallPullIfNeeded(this).
   1244  ReadableByteStreamControllerCallPullIfNeeded(aCx, this, aRv);
   1245 }
   1246 
   1247 // https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamcontroller-releasesteps
   1248 void ReadableByteStreamController::ReleaseSteps() {
   1249  // Step 1. If this.[[pendingPullIntos]] is not empty,
   1250  if (!PendingPullIntos().isEmpty()) {
   1251    // Step 1.1. Let firstPendingPullInto be this.[[pendingPullIntos]][0].
   1252    RefPtr<PullIntoDescriptor> firstPendingPullInto =
   1253        PendingPullIntos().popFirst();
   1254 
   1255    // Step 1.2. Set firstPendingPullInto’s reader type to "none".
   1256    firstPendingPullInto->SetReaderType(ReaderType::None);
   1257 
   1258    // Step 1.3. Set this.[[pendingPullIntos]] to the list «
   1259    // firstPendingPullInto ».
   1260    PendingPullIntos().clear();
   1261    PendingPullIntos().insertBack(firstPendingPullInto);
   1262  }
   1263 }
   1264 
   1265 namespace streams_abstract {
   1266 
   1267 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-shift-pending-pull-into
   1268 already_AddRefed<PullIntoDescriptor>
   1269 ReadableByteStreamControllerShiftPendingPullInto(
   1270    ReadableByteStreamController* aController) {
   1271  // Step 1.
   1272  MOZ_ASSERT(!aController->GetByobRequest());
   1273 
   1274  // Step 2 + 3
   1275  RefPtr<PullIntoDescriptor> descriptor =
   1276      aController->PendingPullIntos().popFirst();
   1277 
   1278  // Step 4.
   1279  return descriptor.forget();
   1280 }
   1281 
   1282 JSObject* ConstructFromPullIntoConstructor(
   1283    JSContext* aCx, PullIntoDescriptor::Constructor constructor,
   1284    JS::Handle<JSObject*> buffer, size_t byteOffset, size_t length) {
   1285  switch (constructor) {
   1286    case PullIntoDescriptor::Constructor::DataView:
   1287      return JS_NewDataView(aCx, buffer, byteOffset, length);
   1288      break;
   1289 
   1290 #define CONSTRUCT_TYPED_ARRAY_TYPE(ExternalT, NativeT, Name)      \
   1291  case PullIntoDescriptor::Constructor::Name:                     \
   1292    return JS_New##Name##ArrayWithBuffer(aCx, buffer, byteOffset, \
   1293                                         int64_t(length));        \
   1294    break;
   1295 
   1296      JS_FOR_EACH_TYPED_ARRAY(CONSTRUCT_TYPED_ARRAY_TYPE)
   1297 
   1298 #undef CONSTRUCT_TYPED_ARRAY_TYPE
   1299 
   1300    default:
   1301      MOZ_ASSERT_UNREACHABLE("Unknown PullIntoDescriptor::Constructor");
   1302      return nullptr;
   1303  }
   1304 }
   1305 
   1306 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-convert-pull-into-descriptor
   1307 JSObject* ReadableByteStreamControllerConvertPullIntoDescriptor(
   1308    JSContext* aCx, PullIntoDescriptor* pullIntoDescriptor, ErrorResult& aRv) {
   1309  // Step 1. Let bytesFilled be pullIntoDescriptor’s bytes filled.
   1310  uint64_t bytesFilled = pullIntoDescriptor->BytesFilled();
   1311 
   1312  // Step 2. Let elementSize be pullIntoDescriptor’s element size.
   1313  uint64_t elementSize = pullIntoDescriptor->ElementSize();
   1314 
   1315  // Step 3. Assert: bytesFilled ≤ pullIntoDescriptor’s byte length.
   1316  MOZ_ASSERT(bytesFilled <= pullIntoDescriptor->ByteLength());
   1317 
   1318  // Step 4. Assert: the remainder after dividing bytesFilled by elementSize is
   1319  // 0.
   1320  MOZ_ASSERT(bytesFilled % elementSize == 0);
   1321 
   1322  // Step 5. Let buffer be ! TransferArrayBuffer(pullIntoDescriptor’s buffer).
   1323  aRv.MightThrowJSException();
   1324  JS::Rooted<JSObject*> srcBuffer(aCx, pullIntoDescriptor->Buffer());
   1325  JS::Rooted<JSObject*> buffer(aCx, TransferArrayBuffer(aCx, srcBuffer));
   1326  if (!buffer) {
   1327    aRv.StealExceptionFromJSContext(aCx);
   1328    return nullptr;
   1329  }
   1330 
   1331  // Step 6. Return ! Construct(pullIntoDescriptor’s view constructor,
   1332  //  « buffer, pullIntoDescriptor’s byte offset, bytesFilled ÷ elementSize »).
   1333  JS::Rooted<JSObject*> res(
   1334      aCx, ConstructFromPullIntoConstructor(
   1335               aCx, pullIntoDescriptor->ViewConstructor(), buffer,
   1336               pullIntoDescriptor->ByteOffset(), bytesFilled / elementSize));
   1337  if (!res) {
   1338    aRv.StealExceptionFromJSContext(aCx);
   1339    return nullptr;
   1340  }
   1341  return res;
   1342 }
   1343 
   1344 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-in-closed-state
   1345 MOZ_CAN_RUN_SCRIPT
   1346 static void ReadableByteStreamControllerRespondInClosedState(
   1347    JSContext* aCx, ReadableByteStreamController* aController,
   1348    RefPtr<PullIntoDescriptor>& aFirstDescriptor, ErrorResult& aRv) {
   1349  // Step 1. Assert: the remainder after dividing firstDescriptor’s bytes filled
   1350  // by firstDescriptor’s element size is 0.
   1351  MOZ_ASSERT(
   1352      (aFirstDescriptor->BytesFilled() % aFirstDescriptor->ElementSize()) == 0);
   1353 
   1354  // Step 2. If firstDescriptor’s reader type is "none",
   1355  // perform ! ReadableByteStreamControllerShiftPendingPullInto(controller).
   1356  if (aFirstDescriptor->GetReaderType() == ReaderType::None) {
   1357    RefPtr<PullIntoDescriptor> discarded =
   1358        ReadableByteStreamControllerShiftPendingPullInto(aController);
   1359    (void)discarded;
   1360  }
   1361 
   1362  // Step 3. Let stream be controller.[[stream]].
   1363  RefPtr<ReadableStream> stream = aController->Stream();
   1364 
   1365  // Step 4. If ! ReadableStreamHasBYOBReader(stream) is true,
   1366  if (ReadableStreamHasBYOBReader(stream)) {
   1367    // Step 4.1. Let filledPullIntos be a new empty list.
   1368    nsTArray<RefPtr<PullIntoDescriptor>> filledPullIntos;
   1369 
   1370    // Step 4.2. While |filledPullInto|'s [=list/size=] < !
   1371    // ReadableStreamGetNumReadIntoRequests(stream),
   1372    while (filledPullIntos.Length() <
   1373           ReadableStreamGetNumReadIntoRequests(stream)) {
   1374      // Step 4.2.1. Let pullIntoDescriptor be !
   1375      // ReadableByteStreamControllerShiftPendingPullInto(controller).
   1376      RefPtr<PullIntoDescriptor> pullIntoDescriptor =
   1377          ReadableByteStreamControllerShiftPendingPullInto(aController);
   1378 
   1379      // Step 4.2.2. Append pullIntoDescriptor to filledPullIntos.
   1380      filledPullIntos.AppendElement(pullIntoDescriptor);
   1381    }
   1382 
   1383    // Step 4.3. For each filledPullInto of filledPullIntos,
   1384    for (auto& filledPullInto : filledPullIntos) {
   1385      // Step 4.3.1. Perform !
   1386      // ReadableByteStreamControllerCommitPullIntoDescriptor(stream,
   1387      // filledPullInto).
   1388      ReadableByteStreamControllerCommitPullIntoDescriptor(
   1389          aCx, stream, MOZ_KnownLive(filledPullInto), aRv);
   1390      if (aRv.Failed()) {
   1391        return;
   1392      }
   1393    }
   1394  }
   1395 }
   1396 
   1397 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-fill-head-pull-into-descriptor
   1398 void ReadableByteStreamControllerFillHeadPullIntoDescriptor(
   1399    ReadableByteStreamController* aController, size_t aSize,
   1400    PullIntoDescriptor* aPullIntoDescriptor) {
   1401  // Step 1. Assert: either controller.[[pendingPullIntos]] is empty, or
   1402  // controller.[[pendingPullIntos]][0] is pullIntoDescriptor.
   1403  MOZ_ASSERT(aController->PendingPullIntos().isEmpty() ||
   1404             aController->PendingPullIntos().getFirst() == aPullIntoDescriptor);
   1405 
   1406  // Step 2. Assert: controller.[[byobRequest]] is null.
   1407  MOZ_ASSERT(!aController->GetByobRequest());
   1408 
   1409  // Step 3. Set pullIntoDescriptor’s bytes filled to bytes filled + size.
   1410  aPullIntoDescriptor->SetBytesFilled(aPullIntoDescriptor->BytesFilled() +
   1411                                      aSize);
   1412 }
   1413 
   1414 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-in-readable-state
   1415 MOZ_CAN_RUN_SCRIPT
   1416 static void ReadableByteStreamControllerRespondInReadableState(
   1417    JSContext* aCx, ReadableByteStreamController* aController,
   1418    uint64_t aBytesWritten, PullIntoDescriptor* aPullIntoDescriptor,
   1419    ErrorResult& aRv) {
   1420  // Step 1. Assert: pullIntoDescriptor’s bytes filled + bytesWritten ≤
   1421  // pullIntoDescriptor’s byte length.
   1422  MOZ_ASSERT(aPullIntoDescriptor->BytesFilled() + aBytesWritten <=
   1423             aPullIntoDescriptor->ByteLength());
   1424 
   1425  // Step 2. Perform
   1426  // !ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller,
   1427  // bytesWritten, pullIntoDescriptor).
   1428  ReadableByteStreamControllerFillHeadPullIntoDescriptor(
   1429      aController, aBytesWritten, aPullIntoDescriptor);
   1430 
   1431  // Step 3. If pullIntoDescriptor’s reader type is "none",
   1432  if (aPullIntoDescriptor->GetReaderType() == ReaderType::None) {
   1433    // Step 3.1. Perform ?
   1434    // ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue(controller,
   1435    // pullIntoDescriptor).
   1436    ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue(
   1437        aCx, aController, aPullIntoDescriptor, aRv);
   1438    if (aRv.Failed()) {
   1439      return;
   1440    }
   1441 
   1442    // Step 3.2. Let filledPullIntos be the result of performing !
   1443    // ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller).
   1444    nsTArray<RefPtr<PullIntoDescriptor>> filledPullIntos;
   1445    ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(
   1446        aCx, aController, filledPullIntos, aRv);
   1447    if (aRv.Failed()) {
   1448      return;
   1449    }
   1450 
   1451    // Step 3.3. For each filledPullInto of filledPullIntos,
   1452    for (auto& filledPullInto : filledPullIntos) {
   1453      // Step 3.3.1. Perform !
   1454      // ReadableByteStreamControllerCommitPullIntoDescriptor(controller.[[stream]],
   1455      // filledPullInto).
   1456      ReadableByteStreamControllerCommitPullIntoDescriptor(
   1457          aCx, MOZ_KnownLive(aController->Stream()),
   1458          MOZ_KnownLive(filledPullInto), aRv);
   1459      if (aRv.Failed()) {
   1460        return;
   1461      }
   1462    }
   1463 
   1464    // Step 3.4. Return.
   1465    return;
   1466  }
   1467 
   1468  // Step 4. If pullIntoDescriptor’s bytes filled < pullIntoDescriptor’s minimum
   1469  // fill, return.
   1470  if (aPullIntoDescriptor->BytesFilled() < aPullIntoDescriptor->MinimumFill()) {
   1471    return;
   1472  }
   1473 
   1474  // Step 5. Perform
   1475  // !ReadableByteStreamControllerShiftPendingPullInto(controller).
   1476  RefPtr<PullIntoDescriptor> pullIntoDescriptor =
   1477      ReadableByteStreamControllerShiftPendingPullInto(aController);
   1478  (void)pullIntoDescriptor;
   1479 
   1480  // Step 6. Let remainderSize be the remainder after dividing
   1481  // pullIntoDescriptor’s bytes filled by pullIntoDescriptor’s element size.
   1482  size_t remainderSize =
   1483      aPullIntoDescriptor->BytesFilled() % aPullIntoDescriptor->ElementSize();
   1484 
   1485  // Step 7. If remainderSize > 0,
   1486  if (remainderSize > 0) {
   1487    // Step 7.1. Let end be pullIntoDescriptor’s byte offset +
   1488    // pullIntoDescriptor’s bytes filled.
   1489    size_t end =
   1490        aPullIntoDescriptor->ByteOffset() + aPullIntoDescriptor->BytesFilled();
   1491 
   1492    // Step 7.2. Perform ?
   1493    // ReadableByteStreamControllerEnqueueClonedChunkToQueue(controller,
   1494    // pullIntoDescriptor’s buffer, end − remainderSize, remainderSize).
   1495    JS::Rooted<JSObject*> pullIntoBuffer(aCx, aPullIntoDescriptor->Buffer());
   1496    ReadableByteStreamControllerEnqueueClonedChunkToQueue(
   1497        aCx, aController, pullIntoBuffer, end - remainderSize, remainderSize,
   1498        aRv);
   1499    if (aRv.Failed()) {
   1500      return;
   1501    }
   1502  }
   1503 
   1504  // Step 8. Set pullIntoDescriptor’s bytes filled to pullIntoDescriptor’s bytes
   1505  // filled − remainderSize.
   1506  aPullIntoDescriptor->SetBytesFilled(aPullIntoDescriptor->BytesFilled() -
   1507                                      remainderSize);
   1508 
   1509  // Step 9. Let filledPullIntos be the result of performing !
   1510  // ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller).
   1511  nsTArray<RefPtr<PullIntoDescriptor>> filledPullIntos;
   1512  ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(
   1513      aCx, aController, filledPullIntos, aRv);
   1514  if (aRv.Failed()) {
   1515    return;
   1516  }
   1517 
   1518  // Step 10. Perform
   1519  // !ReadableByteStreamControllerCommitPullIntoDescriptor(controller.[[stream]],
   1520  // pullIntoDescriptor).
   1521  RefPtr<ReadableStream> stream(aController->Stream());
   1522  ReadableByteStreamControllerCommitPullIntoDescriptor(
   1523      aCx, stream, aPullIntoDescriptor, aRv);
   1524  if (aRv.Failed()) {
   1525    return;
   1526  }
   1527 
   1528  // Step 11. For each filledPullInto of filledPullIntos,
   1529  for (auto& filledPullInto : filledPullIntos) {
   1530    // Step 11.1. Perform !
   1531    // ReadableByteStreamControllerCommitPullIntoDescriptor(controller.[[stream]],
   1532    // filledPullInto).
   1533    ReadableByteStreamControllerCommitPullIntoDescriptor(
   1534        aCx, stream, MOZ_KnownLive(filledPullInto), aRv);
   1535    if (aRv.Failed()) {
   1536      return;
   1537    }
   1538  }
   1539 }
   1540 
   1541 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-internal
   1542 void ReadableByteStreamControllerRespondInternal(
   1543    JSContext* aCx, ReadableByteStreamController* aController,
   1544    uint64_t aBytesWritten, ErrorResult& aRv) {
   1545  // Step 1.
   1546  RefPtr<PullIntoDescriptor> firstDescriptor =
   1547      aController->PendingPullIntos().getFirst();
   1548 
   1549  // Step 2.
   1550  JS::Rooted<JSObject*> buffer(aCx, firstDescriptor->Buffer());
   1551 #ifdef DEBUG
   1552  bool canTransferBuffer = CanTransferArrayBuffer(aCx, buffer, aRv);
   1553  MOZ_ASSERT(!aRv.Failed());
   1554  MOZ_ASSERT(canTransferBuffer);
   1555 #endif
   1556 
   1557  // Step 3.
   1558  ReadableByteStreamControllerInvalidateBYOBRequest(aController);
   1559 
   1560  // Step 4.
   1561  auto state = aController->Stream()->State();
   1562 
   1563  // Step 5.
   1564  if (state == ReadableStream::ReaderState::Closed) {
   1565    // Step 5.1
   1566    MOZ_ASSERT(aBytesWritten == 0);
   1567 
   1568    // Step 5.2
   1569    ReadableByteStreamControllerRespondInClosedState(aCx, aController,
   1570                                                     firstDescriptor, aRv);
   1571    if (aRv.Failed()) {
   1572      return;
   1573    }
   1574  } else {
   1575    // Step 6.1
   1576    MOZ_ASSERT(state == ReadableStream::ReaderState::Readable);
   1577 
   1578    // Step 6.2.
   1579    MOZ_ASSERT(aBytesWritten > 0);
   1580 
   1581    // Step 6.3
   1582    ReadableByteStreamControllerRespondInReadableState(
   1583        aCx, aController, aBytesWritten, firstDescriptor, aRv);
   1584    if (aRv.Failed()) {
   1585      return;
   1586    }
   1587  }
   1588  // Step 7.
   1589  ReadableByteStreamControllerCallPullIfNeeded(aCx, aController, aRv);
   1590 }
   1591 
   1592 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond
   1593 void ReadableByteStreamControllerRespond(
   1594    JSContext* aCx, ReadableByteStreamController* aController,
   1595    uint64_t aBytesWritten, ErrorResult& aRv) {
   1596  // Step 1.
   1597  MOZ_ASSERT(!aController->PendingPullIntos().isEmpty());
   1598 
   1599  // Step 2.
   1600  PullIntoDescriptor* firstDescriptor =
   1601      aController->PendingPullIntos().getFirst();
   1602 
   1603  // Step 3.
   1604  auto state = aController->Stream()->State();
   1605 
   1606  // Step 4.
   1607  if (state == ReadableStream::ReaderState::Closed) {
   1608    // Step 4.1
   1609    if (aBytesWritten != 0) {
   1610      aRv.ThrowTypeError("bytesWritten not zero on closed stream");
   1611      return;
   1612    }
   1613  } else {
   1614    // Step 5.1
   1615    MOZ_ASSERT(state == ReadableStream::ReaderState::Readable);
   1616 
   1617    // Step 5.2
   1618    if (aBytesWritten == 0) {
   1619      aRv.ThrowTypeError("bytesWritten 0");
   1620      return;
   1621    }
   1622 
   1623    // Step 5.3
   1624    if (firstDescriptor->BytesFilled() + aBytesWritten >
   1625        firstDescriptor->ByteLength()) {
   1626      aRv.ThrowRangeError("bytesFilled + bytesWritten > byteLength");
   1627      return;
   1628    }
   1629  }
   1630 
   1631  // Step 6.
   1632  aRv.MightThrowJSException();
   1633  JS::Rooted<JSObject*> buffer(aCx, firstDescriptor->Buffer());
   1634  JS::Rooted<JSObject*> transferredBuffer(aCx,
   1635                                          TransferArrayBuffer(aCx, buffer));
   1636  if (!transferredBuffer) {
   1637    aRv.StealExceptionFromJSContext(aCx);
   1638    return;
   1639  }
   1640  firstDescriptor->SetBuffer(transferredBuffer);
   1641 
   1642  // Step 7.
   1643  ReadableByteStreamControllerRespondInternal(aCx, aController, aBytesWritten,
   1644                                              aRv);
   1645 }
   1646 
   1647 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-with-new-view
   1648 void ReadableByteStreamControllerRespondWithNewView(
   1649    JSContext* aCx, ReadableByteStreamController* aController,
   1650    JS::Handle<JSObject*> aView, ErrorResult& aRv) {
   1651  aRv.MightThrowJSException();
   1652 
   1653  // Step 1.
   1654  MOZ_ASSERT(!aController->PendingPullIntos().isEmpty());
   1655 
   1656  // Step 2.
   1657  bool isSharedMemory;
   1658  JS::Rooted<JSObject*> viewedArrayBuffer(
   1659      aCx, JS_GetArrayBufferViewBuffer(aCx, aView, &isSharedMemory));
   1660  if (!viewedArrayBuffer) {
   1661    aRv.StealExceptionFromJSContext(aCx);
   1662    return;
   1663  }
   1664  MOZ_ASSERT(!JS::IsDetachedArrayBufferObject(viewedArrayBuffer));
   1665 
   1666  // Step 3.
   1667  RefPtr<PullIntoDescriptor> firstDescriptor =
   1668      aController->PendingPullIntos().getFirst();
   1669 
   1670  // Step 4.
   1671  ReadableStream::ReaderState state = aController->Stream()->State();
   1672 
   1673  // Step 5.
   1674  if (state == ReadableStream::ReaderState::Closed) {
   1675    // Step 5.1
   1676    if (JS_GetArrayBufferViewByteLength(aView) != 0) {
   1677      aRv.ThrowTypeError("View has non-zero length in closed stream");
   1678      return;
   1679    }
   1680  } else {
   1681    // Step 6.1
   1682    MOZ_ASSERT(state == ReadableStream::ReaderState::Readable);
   1683 
   1684    // Step 6.2
   1685    if (JS_GetArrayBufferViewByteLength(aView) == 0) {
   1686      aRv.ThrowTypeError("View has zero length in readable stream");
   1687      return;
   1688    }
   1689  }
   1690 
   1691  // Step 7.
   1692  if (firstDescriptor->ByteOffset() + firstDescriptor->BytesFilled() !=
   1693      JS_GetArrayBufferViewByteOffset(aView)) {
   1694    aRv.ThrowRangeError("Invalid Offset");
   1695    return;
   1696  }
   1697 
   1698  // Step 8.
   1699  if (firstDescriptor->BufferByteLength() !=
   1700      JS::GetArrayBufferByteLength(viewedArrayBuffer)) {
   1701    aRv.ThrowRangeError("Mismatched buffer byte lengths");
   1702    return;
   1703  }
   1704 
   1705  // Step 9.
   1706  if (firstDescriptor->BytesFilled() + JS_GetArrayBufferViewByteLength(aView) >
   1707      firstDescriptor->ByteLength()) {
   1708    aRv.ThrowRangeError("Too many bytes");
   1709    return;
   1710  }
   1711 
   1712  // Step 10. Let viewByteLength be view.[[ByteLength]].
   1713  size_t viewByteLength = JS_GetArrayBufferViewByteLength(aView);
   1714 
   1715  // Step 11. Set firstDescriptor’s buffer to ?
   1716  // TransferArrayBuffer(view.[[ViewedArrayBuffer]]).
   1717  JS::Rooted<JSObject*> transferedBuffer(
   1718      aCx, TransferArrayBuffer(aCx, viewedArrayBuffer));
   1719  if (!transferedBuffer) {
   1720    aRv.StealExceptionFromJSContext(aCx);
   1721    return;
   1722  }
   1723  firstDescriptor->SetBuffer(transferedBuffer);
   1724 
   1725  // Step 12. Perform ? ReadableByteStreamControllerRespondInternal(controller,
   1726  // viewByteLength).
   1727  ReadableByteStreamControllerRespondInternal(aCx, aController, viewByteLength,
   1728                                              aRv);
   1729 }
   1730 
   1731 #ifdef DEBUG
   1732 // https://streams.spec.whatwg.org/#abstract-opdef-cancopydatablockbytes
   1733 bool CanCopyDataBlockBytes(JS::Handle<JSObject*> aToBuffer, size_t aToIndex,
   1734                           JS::Handle<JSObject*> aFromBuffer, size_t aFromIndex,
   1735                           size_t aCount) {
   1736  // Step 1. Assert: toBuffer is an Object.
   1737  // Step 2. Assert: toBuffer has an [[ArrayBufferData]] internal slot.
   1738  MOZ_ASSERT(JS::IsArrayBufferObject(aToBuffer));
   1739 
   1740  // Step 3. Assert: fromBuffer is an Object.
   1741  // Step 4. Assert: fromBuffer has an [[ArrayBufferData]] internal slot.
   1742  MOZ_ASSERT(JS::IsArrayBufferObject(aFromBuffer));
   1743 
   1744  // Step 5. If toBuffer is fromBuffer, return false.
   1745  // Note: JS API makes it safe to just compare the pointers.
   1746  if (aToBuffer == aFromBuffer) {
   1747    return false;
   1748  }
   1749 
   1750  // Step 6. If ! IsDetachedBuffer(toBuffer) is true, return false.
   1751  if (JS::IsDetachedArrayBufferObject(aToBuffer)) {
   1752    return false;
   1753  }
   1754 
   1755  // Step 7. If ! IsDetachedBuffer(fromBuffer) is true, return false.
   1756  if (JS::IsDetachedArrayBufferObject(aFromBuffer)) {
   1757    return false;
   1758  }
   1759 
   1760  // Step 8. If toIndex + count > toBuffer.[[ArrayBufferByteLength]], return
   1761  // false.
   1762  if (aToIndex + aCount > JS::GetArrayBufferByteLength(aToBuffer)) {
   1763    return false;
   1764  }
   1765  // (Not in the spec) also check overflow.
   1766  if (aToIndex + aCount < aToIndex) {
   1767    return false;
   1768  }
   1769 
   1770  // Step 9. If fromIndex + count > fromBuffer.[[ArrayBufferByteLength]], return
   1771  // false.
   1772  if (aFromIndex + aCount > JS::GetArrayBufferByteLength(aFromBuffer)) {
   1773    return false;
   1774  }
   1775  // (Not in the spec) also check overflow.
   1776  if (aFromIndex + aCount < aFromIndex) {
   1777    return false;
   1778  }
   1779 
   1780  // Step 10. Return true.
   1781  return true;
   1782 }
   1783 #endif
   1784 
   1785 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-fill-pull-into-descriptor-from-queue
   1786 bool ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(
   1787    JSContext* aCx, ReadableByteStreamController* aController,
   1788    PullIntoDescriptor* aPullIntoDescriptor, ErrorResult& aRv) {
   1789  // Step 1. Let maxBytesToCopy be min(controller.[[queueTotalSize]],
   1790  // pullIntoDescriptor’s byte length − pullIntoDescriptor’s bytes filled).
   1791  size_t maxBytesToCopy =
   1792      std::min(static_cast<size_t>(aController->QueueTotalSize()),
   1793               static_cast<size_t>((aPullIntoDescriptor->ByteLength() -
   1794                                    aPullIntoDescriptor->BytesFilled())));
   1795 
   1796  // Step 2. Let maxBytesFilled be pullIntoDescriptor’s bytes filled +
   1797  // maxBytesToCopy.
   1798  size_t maxBytesFilled = aPullIntoDescriptor->BytesFilled() + maxBytesToCopy;
   1799 
   1800  // Step 3. Let totalBytesToCopyRemaining be maxBytesToCopy.
   1801  size_t totalBytesToCopyRemaining = maxBytesToCopy;
   1802 
   1803  // Step 4. Let ready be false.
   1804  bool ready = false;
   1805 
   1806  // Step 5. Assert: ! IsDetachedBuffer(pullIntoDescriptor ’s buffer) is false.
   1807  MOZ_ASSERT(!JS::IsDetachedArrayBufferObject(aPullIntoDescriptor->Buffer()));
   1808 
   1809  // Step 6. Assert: pullIntoDescriptor’s bytes filled < pullIntoDescriptor’s
   1810  // minimum fill.
   1811  MOZ_ASSERT(aPullIntoDescriptor->BytesFilled() <
   1812             aPullIntoDescriptor->MinimumFill());
   1813 
   1814  // Step 7. Let remainderBytes be the remainder after dividing maxBytesFilled
   1815  // by pullIntoDescriptor’s element size.
   1816  size_t remainderBytes = maxBytesFilled % aPullIntoDescriptor->ElementSize();
   1817 
   1818  // Step 8. Let maxAlignedBytes be maxBytesFilled − remainderBytes.
   1819  size_t maxAlignedBytes = maxBytesFilled - remainderBytes;
   1820 
   1821  // Step 9. If maxAlignedBytes ≥ pullIntoDescriptor’s minimum fill,
   1822  if (maxAlignedBytes >= aPullIntoDescriptor->MinimumFill()) {
   1823    // Step 9.1. Set totalBytesToCopyRemaining to maxAlignedBytes −
   1824    // pullIntoDescriptor’s bytes filled.
   1825    totalBytesToCopyRemaining =
   1826        maxAlignedBytes - aPullIntoDescriptor->BytesFilled();
   1827    // Step 9.2. Set ready to true.
   1828    ready = true;
   1829  }
   1830 
   1831  // Step 10. Let queue be controller.[[queue]].
   1832  LinkedList<RefPtr<ReadableByteStreamQueueEntry>>& queue =
   1833      aController->Queue();
   1834 
   1835  // Step 11. While totalBytesToCopyRemaining > 0,
   1836  while (totalBytesToCopyRemaining > 0) {
   1837    // Step 11.1  Let headOfQueue be queue[0].
   1838    ReadableByteStreamQueueEntry* headOfQueue = queue.getFirst();
   1839 
   1840    // Step 11.2. Let bytesToCopy be min(totalBytesToCopyRemaining,
   1841    // headOfQueue’s byte length).
   1842    size_t bytesToCopy =
   1843        std::min(totalBytesToCopyRemaining, headOfQueue->ByteLength());
   1844 
   1845    // Step 11.3. Let destStart be pullIntoDescriptor’s byte offset +
   1846    // pullIntoDescriptor’s bytes filled.
   1847    size_t destStart =
   1848        aPullIntoDescriptor->ByteOffset() + aPullIntoDescriptor->BytesFilled();
   1849 
   1850    // Step 11.4. Let descriptorBuffer be pullIntoDescriptor’s buffer.
   1851    JS::Rooted<JSObject*> descriptorBuffer(aCx, aPullIntoDescriptor->Buffer());
   1852 
   1853    // Step 11.5. Let queueBuffer be headOfQueue’s buffer.
   1854    JS::Rooted<JSObject*> queueBuffer(aCx, headOfQueue->Buffer());
   1855 
   1856    // Step 11.6.  Let queueByteOffset be headOfQueue’s byte offset.
   1857    size_t queueByteOffset = headOfQueue->ByteOffset();
   1858 
   1859    // Step 11.7. Assert: ! CanCopyDataBlockBytes(descriptorBuffer, destStart,
   1860    // queueBuffer, queueByteOffset, bytesToCopy) is true.
   1861    MOZ_ASSERT(CanCopyDataBlockBytes(descriptorBuffer, destStart, queueBuffer,
   1862                                     queueByteOffset, bytesToCopy));
   1863 
   1864    // Step 11.8. Perform !
   1865    // CopyDataBlockBytes(descriptorBuffer.[[ArrayBufferData]], destStart,
   1866    // queueBuffer.[[ArrayBufferData]], queueByteOffset, bytesToCopy).
   1867    if (!JS::ArrayBufferCopyData(aCx, descriptorBuffer, destStart, queueBuffer,
   1868                                 queueByteOffset, bytesToCopy)) {
   1869      aRv.StealExceptionFromJSContext(aCx);
   1870      return false;
   1871    }
   1872 
   1873    // Step 11.9. If headOfQueue’s byte length is bytesToCopy,
   1874    if (headOfQueue->ByteLength() == bytesToCopy) {
   1875      // Step 11.9.1. Remove queue[0].
   1876      queue.popFirst();
   1877    } else {
   1878      // Step 11.10.  Otherwise,
   1879 
   1880      // Step 11.10.1 Set headOfQueue’s byte offset to
   1881      // headOfQueue’s byte offset +  bytesToCopy.
   1882      headOfQueue->SetByteOffset(headOfQueue->ByteOffset() + bytesToCopy);
   1883      // Step 11.10.2  Set headOfQueue’s byte length to
   1884      // headOfQueue’s byte length − bytesToCopy.
   1885      headOfQueue->SetByteLength(headOfQueue->ByteLength() - bytesToCopy);
   1886    }
   1887 
   1888    // Step 11.11. Set controller.[[queueTotalSize]] to
   1889    // controller.[[queueTotalSize]] −  bytesToCopy.
   1890    aController->SetQueueTotalSize(aController->QueueTotalSize() -
   1891                                   (double)bytesToCopy);
   1892 
   1893    // Step 11.12, Perform
   1894    // !ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller,
   1895    //     bytesToCopy, pullIntoDescriptor).
   1896    ReadableByteStreamControllerFillHeadPullIntoDescriptor(
   1897        aController, bytesToCopy, aPullIntoDescriptor);
   1898 
   1899    // Step 11.13. Set totalBytesToCopyRemaining to totalBytesToCopyRemaining −
   1900    //     bytesToCopy.
   1901    totalBytesToCopyRemaining = totalBytesToCopyRemaining - bytesToCopy;
   1902  }
   1903 
   1904  // Step 12. If ready is false,
   1905  if (!ready) {
   1906    // Step 12.1. Assert: controller.[[queueTotalSize]] is 0.
   1907    MOZ_ASSERT(aController->QueueTotalSize() == 0);
   1908 
   1909    // Step 12.2. Assert: pullIntoDescriptor’s bytes filled > 0.
   1910    MOZ_ASSERT(aPullIntoDescriptor->BytesFilled() > 0);
   1911 
   1912    // Step 12.3. Assert: pullIntoDescriptor’s bytes filled <
   1913    // pullIntoDescriptor’s minimum fill.
   1914    MOZ_ASSERT(aPullIntoDescriptor->BytesFilled() <
   1915               aPullIntoDescriptor->MinimumFill());
   1916  }
   1917 
   1918  // Step 13. Return ready.
   1919  return ready;
   1920 }
   1921 
   1922 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-pull-into
   1923 void ReadableByteStreamControllerPullInto(
   1924    JSContext* aCx, ReadableByteStreamController* aController,
   1925    JS::Handle<JSObject*> aView, uint64_t aMin,
   1926    ReadIntoRequest* aReadIntoRequest, ErrorResult& aRv) {
   1927  aRv.MightThrowJSException();
   1928 
   1929  // Step 1. Let stream be controller.[[stream]].
   1930  ReadableStream* stream = aController->Stream();
   1931 
   1932  // Step 2. Let elementSize be 1.
   1933  size_t elementSize = 1;
   1934 
   1935  // Step 3. Let ctor be %DataView%.
   1936  PullIntoDescriptor::Constructor ctor =
   1937      PullIntoDescriptor::Constructor::DataView;
   1938 
   1939  // Step 4. If view has a [[TypedArrayName]] internal slot (i.e., it is not a
   1940  // DataView),
   1941  if (JS_IsTypedArrayObject(aView)) {
   1942    // Step 4.1. Set elementSize to the element size specified in the typed
   1943    // array constructors table for view.[[TypedArrayName]].
   1944    JS::Scalar::Type type = JS_GetArrayBufferViewType(aView);
   1945    elementSize = JS::Scalar::byteSize(type);
   1946 
   1947    // Step 4.2 Set ctor to the constructor specified in the typed array
   1948    // constructors table for view.[[TypedArrayName]].
   1949    ctor = PullIntoDescriptor::constructorFromScalar(type);
   1950  }
   1951 
   1952  // Step 5. Let minimumFill be min × elementSize.
   1953  uint64_t minimumFill = aMin * elementSize;
   1954 
   1955  // Step 6. Assert: minimumFill ≥ 0 and minimumFill ≤ view.[[ByteLength]].
   1956  MOZ_ASSERT(minimumFill <= JS_GetArrayBufferViewByteLength(aView));
   1957 
   1958  // Step 7. Assert: the remainder after dividing minimumFill by elementSize is
   1959  // 0.
   1960  MOZ_ASSERT((minimumFill % elementSize) == 0);
   1961 
   1962  // Step 8. Let byteOffset be view.[[ByteOffset]].
   1963  size_t byteOffset = JS_GetArrayBufferViewByteOffset(aView);
   1964 
   1965  // Step 9. Let byteLength be view.[[ByteLength]].
   1966  size_t byteLength = JS_GetArrayBufferViewByteLength(aView);
   1967 
   1968  // Step 10. Let bufferResult be
   1969  // TransferArrayBuffer(view.[[ViewedArrayBuffer]]).
   1970  bool isShared;
   1971  JS::Rooted<JSObject*> viewedArrayBuffer(
   1972      aCx, JS_GetArrayBufferViewBuffer(aCx, aView, &isShared));
   1973  if (!viewedArrayBuffer) {
   1974    aRv.StealExceptionFromJSContext(aCx);
   1975    return;
   1976  }
   1977  JS::Rooted<JSObject*> bufferResult(
   1978      aCx, TransferArrayBuffer(aCx, viewedArrayBuffer));
   1979 
   1980  // Step 11. If bufferResult is an abrupt completion,
   1981  if (!bufferResult) {
   1982    JS::Rooted<JS::Value> pendingException(aCx);
   1983    if (!JS_GetPendingException(aCx, &pendingException)) {
   1984      // This means an un-catchable exception. Use StealExceptionFromJSContext
   1985      // to setup aRv properly.
   1986      aRv.StealExceptionFromJSContext(aCx);
   1987      return;
   1988    }
   1989 
   1990    // It's not expliclitly stated, but I assume the intention here is that
   1991    // we perform a normal completion here; we also need to clear the
   1992    // exception state anyhow to succesfully run ErrorSteps.
   1993    JS_ClearPendingException(aCx);
   1994 
   1995    //     Step 11.1. Perform readIntoRequest’s error steps, given
   1996    //     bufferResult.[[Value]].
   1997    aReadIntoRequest->ErrorSteps(aCx, pendingException, aRv);
   1998 
   1999    //     Step 11.2. Return.
   2000    return;
   2001  }
   2002 
   2003  // Step 12. Let buffer be bufferResult.[[Value]].
   2004  JS::Rooted<JSObject*> buffer(aCx, bufferResult);
   2005 
   2006  // Step 13. Let pullIntoDescriptor be a new pull-into descriptor with
   2007  //  buffer: buffer
   2008  //  buffer byte length: buffer.[[ArrayBufferByteLength]]
   2009  //  byte offset: byteOffset
   2010  //  byte length: byteLength
   2011  //  bytes filled: 0
   2012  //  minimum fill: minimumFill
   2013  //  element size: elementSize
   2014  //  view constructor: ctor
   2015  //  reader type: "byob"
   2016  RefPtr<PullIntoDescriptor> pullIntoDescriptor = new PullIntoDescriptor(
   2017      buffer, JS::GetArrayBufferByteLength(buffer), byteOffset, byteLength, 0,
   2018      minimumFill, elementSize, ctor, ReaderType::BYOB);
   2019 
   2020  // Step 14. If controller.[[pendingPullIntos]] is not empty,
   2021  if (!aController->PendingPullIntos().isEmpty()) {
   2022    // Step 14.1. Append pullIntoDescriptor to controller.[[pendingPullIntos]].
   2023    aController->PendingPullIntos().insertBack(pullIntoDescriptor);
   2024 
   2025    // Step 14.2. Perform !ReadableStreamAddReadIntoRequest(stream,
   2026    // readIntoRequest).
   2027    ReadableStreamAddReadIntoRequest(stream, aReadIntoRequest);
   2028 
   2029    // Step 14.3. Return.
   2030    return;
   2031  }
   2032 
   2033  // Step 15. If stream.[[state]] is "closed",
   2034  if (stream->State() == ReadableStream::ReaderState::Closed) {
   2035    // Step 15.1. Let emptyView be !Construct(ctor, « pullIntoDescriptor’s
   2036    //            buffer, pullIntoDescriptor’s byte offset, 0 »).
   2037    JS::Rooted<JSObject*> pullIntoBuffer(aCx, pullIntoDescriptor->Buffer());
   2038    JS::Rooted<JSObject*> emptyView(
   2039        aCx,
   2040        ConstructFromPullIntoConstructor(aCx, ctor, pullIntoBuffer,
   2041                                         pullIntoDescriptor->ByteOffset(), 0));
   2042    if (!emptyView) {
   2043      aRv.StealExceptionFromJSContext(aCx);
   2044      return;
   2045    }
   2046 
   2047    // Step 15.2. Perform readIntoRequest’s close steps, given emptyView.
   2048    JS::Rooted<JS::Value> emptyViewValue(aCx, JS::ObjectValue(*emptyView));
   2049    aReadIntoRequest->CloseSteps(aCx, emptyViewValue, aRv);
   2050 
   2051    // Step 15.3. Return.
   2052    return;
   2053  }
   2054 
   2055  // Step 16. If controller.[[queueTotalSize]] > 0,
   2056  if (aController->QueueTotalSize() > 0) {
   2057    // Step 16.1 If
   2058    // !ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller,
   2059    //     pullIntoDescriptor) is true,
   2060    bool ready = ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(
   2061        aCx, aController, pullIntoDescriptor, aRv);
   2062    if (aRv.Failed()) {
   2063      return;
   2064    }
   2065    if (ready) {
   2066      // Step 16.1.1  Let filledView be
   2067      //         !ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor).
   2068      JS::Rooted<JSObject*> filledView(
   2069          aCx, ReadableByteStreamControllerConvertPullIntoDescriptor(
   2070                   aCx, pullIntoDescriptor, aRv));
   2071      if (aRv.Failed()) {
   2072        return;
   2073      }
   2074      //  Step 16.1.2. Perform
   2075      //         !ReadableByteStreamControllerHandleQueueDrain(controller).
   2076      ReadableByteStreamControllerHandleQueueDrain(aCx, aController, aRv);
   2077      if (aRv.Failed()) {
   2078        return;
   2079      }
   2080      // Step 16.1.3.  Perform readIntoRequest’s chunk steps, given filledView.
   2081      JS::Rooted<JS::Value> filledViewValue(aCx, JS::ObjectValue(*filledView));
   2082      aReadIntoRequest->ChunkSteps(aCx, filledViewValue, aRv);
   2083      // Step 16.1.4.   Return.
   2084      return;
   2085    }
   2086 
   2087    // Step 16.2  If controller.[[closeRequested]] is true,
   2088    if (aController->CloseRequested()) {
   2089      // Step 16.2.1.   Let e be a TypeError exception.
   2090      ErrorResult typeError;
   2091      typeError.ThrowTypeError("Close Requested True during Pull Into");
   2092 
   2093      JS::Rooted<JS::Value> e(aCx);
   2094      MOZ_RELEASE_ASSERT(ToJSValue(aCx, std::move(typeError), &e));
   2095 
   2096      // Step 16.2.2. Perform !ReadableByteStreamControllerError(controller, e).
   2097      ReadableByteStreamControllerError(aController, e, aRv);
   2098      if (aRv.Failed()) {
   2099        return;
   2100      }
   2101 
   2102      // Step 16.2.3. Perform readIntoRequest’s error steps, given e.
   2103      aReadIntoRequest->ErrorSteps(aCx, e, aRv);
   2104 
   2105      // Step 16.2.4.  Return.
   2106      return;
   2107    }
   2108  }
   2109 
   2110  // Step 17. Append pullIntoDescriptor to controller.[[pendingPullIntos]].
   2111  aController->PendingPullIntos().insertBack(pullIntoDescriptor);
   2112 
   2113  // Step 18. Perform !ReadableStreamAddReadIntoRequest(stream,
   2114  // readIntoRequest).
   2115  ReadableStreamAddReadIntoRequest(stream, aReadIntoRequest);
   2116 
   2117  // Step 19. Perform !ReadableByteStreamControllerCallPullIfNeeded(controller).
   2118  ReadableByteStreamControllerCallPullIfNeeded(aCx, aController, aRv);
   2119 }
   2120 
   2121 // https://streams.spec.whatwg.org/#set-up-readable-byte-stream-controller
   2122 void SetUpReadableByteStreamController(
   2123    JSContext* aCx, ReadableStream* aStream,
   2124    ReadableByteStreamController* aController,
   2125    UnderlyingSourceAlgorithmsBase* aAlgorithms, double aHighWaterMark,
   2126    Maybe<uint64_t> aAutoAllocateChunkSize, ErrorResult& aRv) {
   2127  // Step 1. Assert: stream.[[controller]] is undefined.
   2128  MOZ_ASSERT(!aStream->Controller());
   2129 
   2130  // Step 2. If autoAllocateChunkSize is not undefined,
   2131  // Step 2.1. Assert: ! IsInteger(autoAllocateChunkSize) is true. Implicit
   2132  // Step 2.2. Assert: autoAllocateChunkSize is positive. (Implicit by
   2133  //           type.)
   2134 
   2135  // Step 3. Set controller.[[stream]] to stream.
   2136  aController->SetStream(aStream);
   2137 
   2138  // Step 4. Set controller.[[pullAgain]] and controller.[[pulling]] to false.
   2139  aController->SetPullAgain(false);
   2140  aController->SetPulling(false);
   2141 
   2142  // Step 5. Set controller.[[byobRequest]] to null.
   2143  aController->SetByobRequest(nullptr);
   2144 
   2145  // Step 6. Perform !ResetQueue(controller).
   2146  ResetQueue(aController);
   2147 
   2148  // Step 7. Set controller.[[closeRequested]] and controller.[[started]] to
   2149  // false.
   2150  aController->SetCloseRequested(false);
   2151  aController->SetStarted(false);
   2152 
   2153  // Step 8. Set controller.[[strategyHWM]] to highWaterMark.
   2154  aController->SetStrategyHWM(aHighWaterMark);
   2155 
   2156  // Step 9. Set controller.[[pullAlgorithm]] to pullAlgorithm.
   2157  // Step 10. Set controller.[[cancelAlgorithm]] to cancelAlgorithm.
   2158  aController->SetAlgorithms(*aAlgorithms);
   2159 
   2160  // Step 11. Set controller.[[autoAllocateChunkSize]] to autoAllocateChunkSize.
   2161  aController->SetAutoAllocateChunkSize(aAutoAllocateChunkSize);
   2162 
   2163  // Step 12. Set controller.[[pendingPullIntos]] to a new empty list.
   2164  aController->PendingPullIntos().clear();
   2165 
   2166  // Step 13. Set stream.[[controller]] to controller.
   2167  aStream->SetController(*aController);
   2168 
   2169  // Step 14. Let startResult be the result of performing startAlgorithm.
   2170  JS::Rooted<JS::Value> startResult(aCx, JS::UndefinedValue());
   2171  RefPtr<ReadableStreamControllerBase> controller = aController;
   2172  aAlgorithms->StartCallback(aCx, *controller, &startResult, aRv);
   2173  if (aRv.Failed()) {
   2174    return;
   2175  }
   2176 
   2177  // Let startPromise be a promise resolved with startResult.
   2178  RefPtr<Promise> startPromise =
   2179      Promise::CreateInfallible(aStream->GetParentObject());
   2180  startPromise->MaybeResolve(startResult);
   2181 
   2182  // Step 16+17
   2183  startPromise->AddCallbacksWithCycleCollectedArgs(
   2184      [](JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv,
   2185         ReadableByteStreamController* aController)
   2186          MOZ_CAN_RUN_SCRIPT_BOUNDARY {
   2187            MOZ_ASSERT(aController);
   2188 
   2189            // Step 16.1
   2190            aController->SetStarted(true);
   2191 
   2192            // Step 16.2
   2193            aController->SetPulling(false);
   2194 
   2195            // Step 16.3
   2196            aController->SetPullAgain(false);
   2197 
   2198            // Step 16.4:
   2199            ReadableByteStreamControllerCallPullIfNeeded(
   2200                aCx, MOZ_KnownLive(aController), aRv);
   2201          },
   2202      [](JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv,
   2203         ReadableByteStreamController* aController) {
   2204        // Step 17.1
   2205        ReadableByteStreamControllerError(aController, aValue, aRv);
   2206      },
   2207      RefPtr(aController));
   2208 }
   2209 
   2210 // https://streams.spec.whatwg.org/#set-up-readable-byte-stream-controller-from-underlying-source
   2211 void SetUpReadableByteStreamControllerFromUnderlyingSource(
   2212    JSContext* aCx, ReadableStream* aStream,
   2213    JS::Handle<JSObject*> aUnderlyingSource,
   2214    UnderlyingSource& aUnderlyingSourceDict, double aHighWaterMark,
   2215    ErrorResult& aRv) {
   2216  // Step 1. Let controller be a new ReadableByteStreamController.
   2217  auto controller =
   2218      MakeRefPtr<ReadableByteStreamController>(aStream->GetParentObject());
   2219 
   2220  // Step 2 - 7
   2221  auto algorithms = MakeRefPtr<UnderlyingSourceAlgorithms>(
   2222      aStream->GetParentObject(), aUnderlyingSource, aUnderlyingSourceDict);
   2223 
   2224  // Step 8. Let autoAllocateChunkSize be
   2225  // underlyingSourceDict["autoAllocateChunkSize"], if it exists, or undefined
   2226  // otherwise.
   2227  Maybe<uint64_t> autoAllocateChunkSize = mozilla::Nothing();
   2228  if (aUnderlyingSourceDict.mAutoAllocateChunkSize.WasPassed()) {
   2229    uint64_t value = aUnderlyingSourceDict.mAutoAllocateChunkSize.Value();
   2230    // Step 9. If autoAllocateChunkSize is 0, then throw a TypeError
   2231    // exception.
   2232    if (value == 0) {
   2233      aRv.ThrowTypeError("autoAllocateChunkSize can not be zero.");
   2234      return;
   2235    }
   2236 
   2237    if constexpr (sizeof(size_t) == sizeof(uint32_t)) {
   2238      if (value > uint64_t(UINT32_MAX)) {
   2239        aRv.ThrowRangeError("autoAllocateChunkSize too large");
   2240        return;
   2241      }
   2242    }
   2243 
   2244    autoAllocateChunkSize = mozilla::Some(value);
   2245  }
   2246 
   2247  // Step 10. Perform ? SetUpReadableByteStreamController(stream, controller,
   2248  // startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark,
   2249  // autoAllocateChunkSize).
   2250  SetUpReadableByteStreamController(aCx, aStream, controller, algorithms,
   2251                                    aHighWaterMark, autoAllocateChunkSize, aRv);
   2252 }
   2253 
   2254 }  // namespace streams_abstract
   2255 
   2256 }  // namespace mozilla::dom