Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  WritableStreamDefaultController.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "js/Exception.h"
#include "js/TypeDecls.h"
#include "js/Value.h"
#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/Attributes.h"
#include "mozilla/dom/AbortSignal.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/Promise-inl.h"
#include "mozilla/dom/WritableStream.h"
#include "mozilla/dom/WritableStreamDefaultController.h"
#include "mozilla/dom/WritableStreamDefaultControllerBinding.h"
#include "mozilla/dom/UnderlyingSinkBinding.h"
#include "nsCycleCollectionParticipant.h"
#include "nsDebug.h"
#include "nsISupports.h"

namespace mozilla::dom {

using namespace streams_abstract;

// Note: Using the individual macros vs NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE
// because I need to specificy a manual implementation of
// NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN.
NS_IMPL_CYCLE_COLLECTION_CLASS(WritableStreamDefaultController)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(WritableStreamDefaultController)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal, mSignal, mStrategySizeAlgorithm,
                                  mAlgorithms, mStream)
  tmp->mQueue.clear();
  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(WritableStreamDefaultController)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal, mSignal, mStrategySizeAlgorithm,
                                    mAlgorithms, mStream)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END

NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(WritableStreamDefaultController)
  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
  // Trace the associated queue.
  for (const auto& queueEntry : tmp->mQueue) {
    aCallbacks.Trace(&queueEntry->mValue, "mQueue.mValue", aClosure);
  }
NS_IMPL_CYCLE_COLLECTION_TRACE_END

NS_IMPL_CYCLE_COLLECTING_ADDREF(WritableStreamDefaultController)
NS_IMPL_CYCLE_COLLECTING_RELEASE(WritableStreamDefaultController)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WritableStreamDefaultController)
  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END

WritableStreamDefaultController::WritableStreamDefaultController(
    nsISupports* aGlobal, WritableStream& aStream)
    : mGlobal(do_QueryInterface(aGlobal)), mStream(&aStream) {
  mozilla::HoldJSObjects(this);
}

WritableStreamDefaultController::~WritableStreamDefaultController() {
  // MG:XXX: LinkedLists are required to be empty at destruction, but it seems
  //         it is possible to have a controller be destructed while still
  //         having entries in its queue.
  //
  //         This needs to be verified as not indicating some other issue.
  mQueue.clear();
  mozilla::DropJSObjects(this);
}

JSObject* WritableStreamDefaultController::WrapObject(
    JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
  return WritableStreamDefaultController_Binding::Wrap(aCx, this, aGivenProto);
}

// https://streams.spec.whatwg.org/#ws-default-controller-error
void WritableStreamDefaultController::Error(JSContext* aCx,
                                            JS::Handle<JS::Value> aError,
                                            ErrorResult& aRv) {
  // Step 1. Let state be this.[[stream]].[[state]].
  // Step 2. If state is not "writable", return.
  if (mStream->State() != WritableStream::WriterState::Writable) {
    return;
  }
  // Step 3. Perform ! WritableStreamDefaultControllerError(this, e).
  RefPtr<WritableStreamDefaultController> thisRefPtr = this;
  WritableStreamDefaultControllerError(aCx, thisRefPtr, aError, aRv);
}

// https://streams.spec.whatwg.org/#ws-default-controller-private-abort
already_AddRefed<Promise> WritableStreamDefaultController::AbortSteps(
    JSContext* aCx, JS::Handle<JS::Value> aReason, ErrorResult& aRv) {
  // Step 1. Let result be the result of performing this.[[abortAlgorithm]],
  // passing reason.
  RefPtr<UnderlyingSinkAlgorithmsBase> algorithms = mAlgorithms;
  Optional<JS::Handle<JS::Value>> optionalReason(aCx, aReason);
  RefPtr<Promise> abortPromise =
      algorithms->AbortCallback(aCx, optionalReason, aRv);
  if (aRv.Failed()) {
    return nullptr;
  }

  // Step 2. Perform ! WritableStreamDefaultControllerClearAlgorithms(this).
  ClearAlgorithms();

  // Step 3. Return result.
  return abortPromise.forget();
}

// https://streams.spec.whatwg.org/#ws-default-controller-private-error
void WritableStreamDefaultController::ErrorSteps() {
  // Step 1. Perform ! ResetQueue(this).
  ResetQueue(this);
}

void WritableStreamDefaultController::SetSignal(AbortSignal* aSignal) {
  MOZ_ASSERT(aSignal);
  mSignal = aSignal;
}

namespace streams_abstract {

MOZ_CAN_RUN_SCRIPT static void
WritableStreamDefaultControllerAdvanceQueueIfNeeded(
    JSContext* aCx, WritableStreamDefaultController* aController,
    ErrorResult& aRv);

// https://streams.spec.whatwg.org/#set-up-writable-stream-default-controller
void SetUpWritableStreamDefaultController(
    JSContext* aCx, WritableStream* aStream,
    WritableStreamDefaultController* aController,
    UnderlyingSinkAlgorithmsBase* aAlgorithms, double aHighWaterMark,
    QueuingStrategySize* aSizeAlgorithm, ErrorResult& aRv) {
  // Step 1. Assert: stream implements WritableStream.
  // Step 2. Assert: stream.[[controller]] is undefined.
  MOZ_ASSERT(!aStream->Controller());

  // Step 3. Set controller.[[stream]] to stream.
  // Note: Already set in
  // SetUpWritableStreamDefaultControllerFromUnderlyingSink.
  MOZ_ASSERT(aController->Stream() == aStream);

  // Step 4. Set stream.[[controller]] to controller.
  aStream->SetController(*aController);

  // Step 5. Perform ! ResetQueue(controller).
  ResetQueue(aController);

  // Step 6. Set controller.[[signal]] to a new AbortSignal.
  RefPtr<AbortSignal> signal = new AbortSignal(aController->GetParentObject(),
                                               false, JS::UndefinedHandleValue);
  aController->SetSignal(signal);

  // Step 7. Set controller.[[started]] to false.
  aController->SetStarted(false);

  // Step 8. Set controller.[[strategySizeAlgorithm]] to sizeAlgorithm.
  aController->SetStrategySizeAlgorithm(aSizeAlgorithm);

  // Step 9. Set controller.[[strategyHWM]] to highWaterMark.
  aController->SetStrategyHWM(aHighWaterMark);

  // Step 10. Set controller.[[writeAlgorithm]] to writeAlgorithm.
  // Step 11. Set controller.[[closeAlgorithm]] to closeAlgorithm.
  // Step 12. Set controller.[[abortAlgorithm]] to abortAlgorithm.
  aController->SetAlgorithms(*aAlgorithms);

  // Step 13. Let backpressure be !
  // WritableStreamDefaultControllerGetBackpressure(controller).
  bool backpressure = aController->GetBackpressure();

  // Step 14. Perform ! WritableStreamUpdateBackpressure(stream, backpressure).
  aStream->UpdateBackpressure(backpressure);

  // Step 15. Let startResult be the result of performing startAlgorithm. (This
  // may throw an exception.)
  JS::Rooted<JS::Value> startResult(aCx, JS::UndefinedValue());
  RefPtr<WritableStreamDefaultController> controller(aController);
  aAlgorithms->StartCallback(aCx, *controller, &startResult, aRv);
  if (aRv.Failed()) {
    return;
  }

  // Step 16. Let startPromise be a promise resolved with startResult.
  RefPtr<Promise> startPromise =
      Promise::CreateInfallible(aStream->GetParentObject());
  startPromise->MaybeResolve(startResult);

  // Step 17/18.
  startPromise->AddCallbacksWithCycleCollectedArgs(
      [](JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv,
         WritableStreamDefaultController* aController)
          MOZ_CAN_RUN_SCRIPT_BOUNDARY {
            // Step 17. Upon fulfillment of startPromise,
            // Step 17.1. Assert: stream.[[state]] is "writable" or "erroring".
            MOZ_ASSERT(aController->Stream()->State() ==
                           WritableStream::WriterState::Writable ||
                       aController->Stream()->State() ==
                           WritableStream::WriterState::Erroring);
            // Step 17.2. Set controller.[[started]] to true.
            aController->SetStarted(true);
            // Step 17.3 Perform
            // !WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller).
            WritableStreamDefaultControllerAdvanceQueueIfNeeded(
                aCx, MOZ_KnownLive(aController), aRv);
          },
      [](JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv,
         WritableStreamDefaultController* aController)
          MOZ_CAN_RUN_SCRIPT_BOUNDARY {
            RefPtr<WritableStream> stream = aController->Stream();
            // Step 18. Upon rejection of startPromise with reason r,
            // Step 18.1. Assert: stream.[[state]] is "writable" or "erroring".
            MOZ_ASSERT(
                stream->State() == WritableStream::WriterState::Writable ||
                stream->State() == WritableStream::WriterState::Erroring);
            // Step 18.2. Set controller.[[started]] to true.
            aController->SetStarted(true);
            // Step 18.3. Perform ! WritableStreamDealWithRejection(stream, r).
            stream->DealWithRejection(aCx, aValue, aRv);
          },
      RefPtr(aController));
}

// https://streams.spec.whatwg.org/#set-up-writable-stream-default-controller-from-underlying-sink
void SetUpWritableStreamDefaultControllerFromUnderlyingSink(
    JSContext* aCx, WritableStream* aStream,
    JS::Handle<JSObject*> aUnderlyingSink, UnderlyingSink& aUnderlyingSinkDict,
    double aHighWaterMark, QueuingStrategySize* aSizeAlgorithm,
    ErrorResult& aRv) {
  // Step 1.
  RefPtr<WritableStreamDefaultController> controller =
      new WritableStreamDefaultController(aStream->GetParentObject(), *aStream);

  // Step 2 - 9.
  auto algorithms = MakeRefPtr<UnderlyingSinkAlgorithms>(
      aStream->GetParentObject(), aUnderlyingSink, aUnderlyingSinkDict);

  // Step 10.
  SetUpWritableStreamDefaultController(aCx, aStream, controller, algorithms,
                                       aHighWaterMark, aSizeAlgorithm, aRv);
}

// https://streams.spec.whatwg.org/#writable-stream-default-controller-process-close
MOZ_CAN_RUN_SCRIPT static void WritableStreamDefaultControllerProcessClose(
    JSContext* aCx, WritableStreamDefaultController* aController,
    ErrorResult& aRv) {
  // Step 1. Let stream be controller.[[stream]].
  RefPtr<WritableStream> stream = aController->Stream();

  // Step 2. Perform ! WritableStreamMarkCloseRequestInFlight(stream).
  stream->MarkCloseRequestInFlight();

  // Step 3. Perform ! DequeueValue(controller).
  JS::Rooted<JS::Value> value(aCx);
  DequeueValue(aController, &value);

  // Step 4. Assert: controller.[[queue]] is empty.
  MOZ_ASSERT(aController->Queue().isEmpty());

  // Step 5. Let sinkClosePromise be the result of performing
  // controller.[[closeAlgorithm]].
  RefPtr<UnderlyingSinkAlgorithmsBase> algorithms =
      aController->GetAlgorithms();
  RefPtr<Promise> sinkClosePromise = algorithms->CloseCallback(aCx, aRv);
  if (aRv.Failed()) {
    return;
  }

  // Step 6. Perform !
  // WritableStreamDefaultControllerClearAlgorithms(controller).
  aController->ClearAlgorithms();

  // Step 7 + 8.
  sinkClosePromise->AddCallbacksWithCycleCollectedArgs(
      [](JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv,
         WritableStreamDefaultController* aController) {
        RefPtr<WritableStream> stream = aController->Stream();
        // Step 7. Upon fulfillment of sinkClosePromise,
        // Step 7.1. Perform ! WritableStreamFinishInFlightClose(stream).
        stream->FinishInFlightClose();
      },
      [](JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv,
         WritableStreamDefaultController* aController)
          MOZ_CAN_RUN_SCRIPT_BOUNDARY {
            RefPtr<WritableStream> stream = aController->Stream();
            // Step 8. Upon rejection of sinkClosePromise with reason reason,
            // Step 8.1. Perform
            // ! WritableStreamFinishInFlightCloseWithError(stream, reason).
            stream->FinishInFlightCloseWithError(aCx, aValue, aRv);
          },
      RefPtr(aController));
}

// https://streams.spec.whatwg.org/#writable-stream-default-controller-process-write
MOZ_CAN_RUN_SCRIPT static void WritableStreamDefaultControllerProcessWrite(
    JSContext* aCx, WritableStreamDefaultController* aController,
    JS::Handle<JS::Value> aChunk, ErrorResult& aRv) {
  // Step 1. Let stream be controller.[[stream]].
  RefPtr<WritableStream> stream = aController->Stream();

  // Step 2. Perform ! WritableStreamMarkFirstWriteRequestInFlight(stream).
  stream->MarkFirstWriteRequestInFlight();

  // Step 3. Let sinkWritePromise be the result of performing
  // controller.[[writeAlgorithm]], passing in chunk.
  RefPtr<UnderlyingSinkAlgorithmsBase> algorithms =
      aController->GetAlgorithms();
  RefPtr<Promise> sinkWritePromise =
      algorithms->WriteCallback(aCx, aChunk, *aController, aRv);
  if (aRv.Failed()) {
    return;
  }

  // Step 4 + 5:
  sinkWritePromise->AddCallbacksWithCycleCollectedArgs(
      [](JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv,
         WritableStreamDefaultController* aController)
          MOZ_CAN_RUN_SCRIPT_BOUNDARY {
            RefPtr<WritableStream> stream = aController->Stream();

            // Step 4.1. Perform ! WritableStreamFinishInFlightWrite(stream).
            stream->FinishInFlightWrite();

            // Step 4.2. Let state be stream.[[state]].
            WritableStream::WriterState state = stream->State();

            // Step 4.3. Assert: state is "writable" or "erroring".
            MOZ_ASSERT(state == WritableStream::WriterState::Writable ||
                       state == WritableStream::WriterState::Erroring);

            // Step 4.4. Perform ! DequeueValue(controller).
            JS::Rooted<JS::Value> value(aCx);
            DequeueValue(aController, &value);

            // Step 4.5. If ! WritableStreamCloseQueuedOrInFlight(stream) is
            // false and state is "writable",
            if (!stream->CloseQueuedOrInFlight() &&
                state == WritableStream::WriterState::Writable) {
              // Step 4.5.1. Let backpressure be !
              // WritableStreamDefaultControllerGetBackpressure(controller).
              bool backpressure = aController->GetBackpressure();
              // Step 4.5.2. Perform ! WritableStreamUpdateBackpressure(stream,
              // backpressure).
              stream->UpdateBackpressure(backpressure);
            }

            // Step 4.6. Perform !
            // WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller).
            WritableStreamDefaultControllerAdvanceQueueIfNeeded(
                aCx, MOZ_KnownLive(aController), aRv);
          },
      [](JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv,
         WritableStreamDefaultController* aController)
          MOZ_CAN_RUN_SCRIPT_BOUNDARY {
            RefPtr<WritableStream> stream = aController->Stream();

            // Step 5.1. If stream.[[state]] is "writable", perform !
            // WritableStreamDefaultControllerClearAlgorithms(controller).
            if (stream->State() == WritableStream::WriterState::Writable) {
              aController->ClearAlgorithms();
            }

            // Step 5.2. Perform !
            // WritableStreamFinishInFlightWriteWithError(stream, reason)
            stream->FinishInFlightWriteWithError(aCx, aValue, aRv);
          },
      RefPtr(aController));
}

// We use a JS::MagicValue to represent the close sentinel required by the spec.
// Normal JavaScript code can not generate magic values, so we can use this
// as a special value. However care has to be taken to not leak the magic value
// to other code.
constexpr JSWhyMagic CLOSE_SENTINEL = JS_GENERIC_MAGIC;

// https://streams.spec.whatwg.org/#writable-stream-default-controller-advance-queue-if-needed
static void WritableStreamDefaultControllerAdvanceQueueIfNeeded(
    JSContext* aCx, WritableStreamDefaultController* aController,
    ErrorResult& aRv) {
  // Step 1. Let stream be controller.[[stream]].
  RefPtr<WritableStream> stream = aController->Stream();

  // Step 2. If controller.[[started]] is false, return.
  if (!aController->Started()) {
    return;
  }

  // Step 3. If stream.[[inFlightWriteRequest]] is not undefined, return.
  if (stream->GetInFlightWriteRequest()) {
    return;
  }

  // Step 4. Let state be stream.[[state]].
  WritableStream::WriterState state = stream->State();

  // Step 5. Assert: state is not "closed" or "errored".
  MOZ_ASSERT(state != WritableStream::WriterState::Closed &&
             state != WritableStream::WriterState::Errored);

  // Step 6. If state is "erroring",
  if (state == WritableStream::WriterState::Erroring) {
    // Step 6.1. Perform ! WritableStreamFinishErroring(stream).
    stream->FinishErroring(aCx, aRv);

    // Step 6.2. Return.
    return;
  }

  // Step 7. If controller.[[queue]] is empty, return.
  if (aController->Queue().isEmpty()) {
    return;
  }

  // Step 8. Let value be ! PeekQueueValue(controller).
  JS::Rooted<JS::Value> value(aCx);
  PeekQueueValue(aController, &value);

  // Step 9. If value is the close sentinel, perform !
  // WritableStreamDefaultControllerProcessClose(controller).
  if (value.isMagic(CLOSE_SENTINEL)) {
    WritableStreamDefaultControllerProcessClose(aCx, aController, aRv);
    return;
  }

  // Step 10. Otherwise, perform !
  // WritableStreamDefaultControllerProcessWrite(controller, value).
  WritableStreamDefaultControllerProcessWrite(aCx, aController, value, aRv);
}

// https://streams.spec.whatwg.org/#writable-stream-default-controller-close
void WritableStreamDefaultControllerClose(
    JSContext* aCx, WritableStreamDefaultController* aController,
    ErrorResult& aRv) {
  // Step 1. Perform ! EnqueueValueWithSize(controller, close sentinel, 0).
  JS::Rooted<JS::Value> aCloseSentinel(aCx, JS::MagicValue(CLOSE_SENTINEL));
  EnqueueValueWithSize(aController, aCloseSentinel, 0, aRv);
  MOZ_ASSERT(!aRv.Failed());

  // Step 2. Perform !
  // WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller).
  WritableStreamDefaultControllerAdvanceQueueIfNeeded(aCx, aController, aRv);
}

// https://streams.spec.whatwg.org/#writable-stream-default-controller-write
void WritableStreamDefaultControllerWrite(
    JSContext* aCx, WritableStreamDefaultController* aController,
    JS::Handle<JS::Value> aChunk, double chunkSize, ErrorResult& aRv) {
  // Step 1. Let enqueueResult be EnqueueValueWithSize(controller, chunk,
  // chunkSize).
  IgnoredErrorResult rv;
  EnqueueValueWithSize(aController, aChunk, chunkSize, rv);

  // Step 2. If enqueueResult is an abrupt completion,
  if (rv.MaybeSetPendingException(aCx,
                                  "WritableStreamDefaultController.write")) {
    JS::Rooted<JS::Value> error(aCx);
    JS_GetPendingException(aCx, &error);
    JS_ClearPendingException(aCx);

    // Step 2.1. Perform !
    // WritableStreamDefaultControllerErrorIfNeeded(controller,
    // enqueueResult.[[Value]]).
    WritableStreamDefaultControllerErrorIfNeeded(aCx, aController, error, aRv);

    // Step 2.2. Return.
    return;
  }

  // Step 3. Let stream be controller.[[stream]].
  RefPtr<WritableStream> stream = aController->Stream();

  // Step 4. If ! WritableStreamCloseQueuedOrInFlight(stream) is false and
  // stream.[[state]] is "writable",
  if (!stream->CloseQueuedOrInFlight() &&
      stream->State() == WritableStream::WriterState::Writable) {
    // Step 4.1. Let backpressure be
    // !WritableStreamDefaultControllerGetBackpressure(controller).
    bool backpressure = aController->GetBackpressure();

    // Step 4.2. Perform ! WritableStreamUpdateBackpressure(stream,
    // backpressure).
    stream->UpdateBackpressure(backpressure);
  }

  // Step 5. Perform
  // ! WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller).
  WritableStreamDefaultControllerAdvanceQueueIfNeeded(aCx, aController, aRv);
}

void WritableStreamDefaultControllerError(
    JSContext* aCx, WritableStreamDefaultController* aController,
    JS::Handle<JS::Value> aError, ErrorResult& aRv) {
  // Step 1. Let stream be controller.[[stream]].
  RefPtr<WritableStream> stream = aController->Stream();

  // Step 2. Assert: stream.[[state]] is "writable".
  MOZ_ASSERT(stream->State() == WritableStream::WriterState::Writable);

  // Step 3. Perform
  // ! WritableStreamDefaultControllerClearAlgorithms(controller).
  aController->ClearAlgorithms();

  // Step 4.Perform ! WritableStreamStartErroring(stream, error).
  stream->StartErroring(aCx, aError, aRv);
}

// https://streams.spec.whatwg.org/#writable-stream-default-controller-error-if-needed
void WritableStreamDefaultControllerErrorIfNeeded(
    JSContext* aCx, WritableStreamDefaultController* aController,
    JS::Handle<JS::Value> aError, ErrorResult& aRv) {
  // Step 1. If controller.[[stream]].[[state]] is "writable", perform
  // !WritableStreamDefaultControllerError(controller, error).
  if (aController->Stream()->State() == WritableStream::WriterState::Writable) {
    WritableStreamDefaultControllerError(aCx, aController, aError, aRv);
  }
}

// https://streams.spec.whatwg.org/#writable-stream-default-controller-get-chunk-size
double WritableStreamDefaultControllerGetChunkSize(
    JSContext* aCx, WritableStreamDefaultController* aController,
    JS::Handle<JS::Value> aChunk, ErrorResult& aRv) {
  // Step 1. Let returnValue be the result of performing
  // controller.[[strategySizeAlgorithm]], passing in chunk, and interpreting
  // the result as a completion record.
  RefPtr<QueuingStrategySize> sizeAlgorithm(
      aController->StrategySizeAlgorithm());

  // If !sizeAlgorithm, we return 1, which is inlined from
  // https://streams.spec.whatwg.org/#make-size-algorithm-from-size-function
  Optional<JS::Handle<JS::Value>> optionalChunk(aCx, aChunk);

  double chunkSize =
      sizeAlgorithm
          ? sizeAlgorithm->Call(
                optionalChunk, aRv,
                "WritableStreamDefaultController.[[strategySizeAlgorithm]]",
                CallbackObject::eRethrowExceptions)
          : 1.0;

  // Step 2. If returnValue is an abrupt completion,
  if (aRv.MaybeSetPendingException(
          aCx, "WritableStreamDefaultController.[[strategySizeAlgorithm]]")) {
    JS::Rooted<JS::Value> error(aCx);
    JS_GetPendingException(aCx, &error);
    JS_ClearPendingException(aCx);

    // Step 2.1. Perform !
    // WritableStreamDefaultControllerErrorIfNeeded(controller,
    // returnValue.[[Value]]).
    WritableStreamDefaultControllerErrorIfNeeded(aCx, aController, error, aRv);

    // Step 2.2. Return 1.
    return 1.0;
  }

  // Step 3. Return returnValue.[[Value]].
  return chunkSize;
}

}  // namespace streams_abstract

}  // namespace mozilla::dom

98%


¤ Dauer der Verarbeitung: 0.32 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge