зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1582348 - Fill out the rest of |WritableStreamDefaultControllerAdvanceQueueIfNeeded| and implement |WritableStreamDefaultControllerProcess{Close,Write}| as required by it. r=arai
Differential Revision: https://phabricator.services.mozilla.com/D50100 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
ef6b0b0b9d
Коммит
d89c3eb925
|
@ -65,6 +65,13 @@ inline MOZ_MUST_USE bool QueueAppendValueAndSize(
|
|||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* Streams spec, 6.2.3. PeekQueueValue ( container ) nothrow
|
||||
*/
|
||||
inline JS::Value PeekQueueValue(ListObject* queue) {
|
||||
return detail::QueueFirstValue(queue);
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif // builtin_streams_QueueWithSizes_inl_h
|
||||
|
|
|
@ -49,6 +49,17 @@ extern MOZ_MUST_USE bool EnqueueValueWithSize(
|
|||
extern MOZ_MUST_USE bool ResetQueue(
|
||||
JSContext* cx, JS::Handle<StreamController*> unwrappedContainer);
|
||||
|
||||
inline bool QueueIsEmpty(ListObject* unwrappedQueue) {
|
||||
if (unwrappedQueue->isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSERT((unwrappedQueue->length() % 2) == 0,
|
||||
"queue-with-sizes must consist of (value, size) element pairs and "
|
||||
"so must have even length");
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif // builtin_streams_QueueWithSizes_h
|
||||
|
|
|
@ -15,11 +15,12 @@
|
|||
|
||||
#include "builtin/Promise.h" // js::PromiseObject
|
||||
#include "builtin/streams/MiscellaneousOperations.h" // js::CreateAlgorithmFromUnderlyingMethod, js::InvokeOrNoop
|
||||
#include "builtin/streams/QueueWithSizes.h" // js::{EnqueueValueWithSize,ResetQueue}
|
||||
#include "builtin/streams/QueueWithSizes.h" // js::{EnqueueValueWithSize,QueueIsEmpty,ResetQueue}
|
||||
#include "builtin/streams/WritableStream.h" // js::WritableStream
|
||||
#include "builtin/streams/WritableStreamDefaultController.h" // js::WritableStreamDefaultController
|
||||
#include "builtin/streams/WritableStreamOperations.h" // js::WritableStream{DealWithRejection,{Start,Finish}Erroring,UpdateBackpressure}
|
||||
#include "builtin/streams/WritableStreamOperations.h" // js::WritableStream{CloseQueuedOrInFlight,DealWithRejection,{Start,Finish}Erroring,UpdateBackpressure,Mark{Close,FirstWrite}RequestInFlight}
|
||||
#include "js/CallArgs.h" // JS::CallArgs{,FromVp}
|
||||
#include "js/Promise.h" // JS::AddPromiseReactions
|
||||
#include "js/RootingAPI.h" // JS::Handle, JS::Rooted
|
||||
#include "js/Value.h" // JS::{,Int32,Magic,Object}Value, JS::UndefinedHandleValue, JS_WRITABLESTREAM_CLOSE_RECORD
|
||||
#include "vm/Compartment.h" // JS::Compartment
|
||||
|
@ -30,6 +31,7 @@
|
|||
|
||||
#include "builtin/streams/HandlerFunction-inl.h" // js::TargetFromHandler
|
||||
#include "builtin/streams/MiscellaneousOperations-inl.h" // js::PromiseCall
|
||||
#include "builtin/streams/QueueWithSizes-inl.h" // js::PeekQueueValue
|
||||
#include "vm/Compartment-inl.h" // JS::Compartment::wrap
|
||||
#include "vm/JSContext-inl.h" // JSContext::check
|
||||
#include "vm/JSObject-inl.h" // js::NewBuiltinClassInstance, js::NewObjectWithClassProto
|
||||
|
@ -46,9 +48,16 @@ using JS::UndefinedHandleValue;
|
|||
using JS::Value;
|
||||
|
||||
using js::ListObject;
|
||||
using js::NewHandler;
|
||||
using js::PeekQueueValue;
|
||||
using js::TargetFromHandler;
|
||||
using js::WritableStream;
|
||||
using js::WritableStreamCloseQueuedOrInFlight;
|
||||
using js::WritableStreamDefaultController;
|
||||
using js::WritableStreamFinishErroring;
|
||||
using js::WritableStreamMarkCloseRequestInFlight;
|
||||
using js::WritableStreamMarkFirstWriteRequestInFlight;
|
||||
using js::WritableStreamUpdateBackpressure;
|
||||
|
||||
/*** 4.7. Writable stream default controller internal methods ***************/
|
||||
|
||||
|
@ -520,6 +529,10 @@ double js::WritableStreamDefaultControllerGetDesiredSize(
|
|||
return controller->strategyHWM() - controller->queueTotalSize();
|
||||
}
|
||||
|
||||
static MOZ_MUST_USE bool WritableStreamDefaultControllerProcessIfNeeded(
|
||||
JSContext* cx,
|
||||
Handle<WritableStreamDefaultController*> unwrappedController);
|
||||
|
||||
/**
|
||||
* Streams spec, 4.8.9.
|
||||
* WritableStreamDefaultControllerAdvanceQueueIfNeeded ( controller )
|
||||
|
@ -552,21 +565,14 @@ MOZ_MUST_USE bool WritableStreamDefaultControllerAdvanceQueueIfNeeded(
|
|||
}
|
||||
|
||||
// Step 7: If controller.[[queue]] is empty, return.
|
||||
Rooted<ListObject*> unwrappedQueue(cx, unwrappedController->queue());
|
||||
MOZ_ASSERT((unwrappedQueue->length() % 2) == 0);
|
||||
if (unwrappedQueue->isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Step 8: Let writeRecord be ! PeekQueueValue(controller).
|
||||
// Step 9: If writeRecord is "close", perform
|
||||
// ! WritableStreamDefaultControllerProcessClose(controller).
|
||||
// Step 10: Otherwise, perform
|
||||
// ! WritableStreamDefaultControllerProcessWrite(
|
||||
// controller, writeRecord.[[chunk]]).
|
||||
// XXX jwalden fill me in!
|
||||
JS_ReportErrorASCII(cx, "nope");
|
||||
return false;
|
||||
return WritableStreamDefaultControllerProcessIfNeeded(cx,
|
||||
unwrappedController);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -589,6 +595,239 @@ bool js::WritableStreamDefaultControllerErrorIfNeeded(
|
|||
return true;
|
||||
}
|
||||
|
||||
static MOZ_MUST_USE JSObject* PerformCloseAlgorithm(
|
||||
JSContext* cx,
|
||||
Handle<WritableStreamDefaultController*> unwrappedController) {
|
||||
// XXX jwalden fill me in!
|
||||
JS_ReportErrorASCII(cx, "boo");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static MOZ_MUST_USE JSObject* PerformWriteAlgorithm(
|
||||
JSContext* cx, Handle<WritableStreamDefaultController*> unwrappedController,
|
||||
Handle<Value> chunk) {
|
||||
cx->check(chunk);
|
||||
|
||||
// XXX jwalden fill me in!
|
||||
JS_ReportErrorASCII(cx, "boo");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Streams spec, 4.8.11 step 7:
|
||||
* Upon fulfillment of sinkClosePromise,
|
||||
*/
|
||||
static MOZ_MUST_USE bool WritableStreamCloseHandler(JSContext* cx,
|
||||
unsigned argc, Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
Rooted<WritableStream*> unwrappedStream(
|
||||
cx, TargetFromHandler<WritableStream>(args));
|
||||
|
||||
// Step 7.a: Perform ! WritableStreamFinishInFlightClose(stream).
|
||||
if (!WritableStreamFinishInFlightClose(cx, unwrappedStream)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Streams spec, 4.8.11 step 8:
|
||||
* Upon rejection of sinkClosePromise with reason reason,
|
||||
*/
|
||||
static MOZ_MUST_USE bool WritableStreamCloseFailedHandler(JSContext* cx,
|
||||
unsigned argc,
|
||||
Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
Rooted<WritableStream*> unwrappedStream(
|
||||
cx, TargetFromHandler<WritableStream>(args));
|
||||
|
||||
// Step 8.a: Perform
|
||||
// ! WritableStreamFinishInFlightCloseWithError(stream, reason).
|
||||
if (!WritableStreamFinishInFlightCloseWithError(cx, unwrappedStream,
|
||||
args.get(0))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Streams spec, 4.8.12 step 4:
|
||||
* Upon fulfillment of sinkWritePromise,
|
||||
*/
|
||||
static MOZ_MUST_USE bool WritableStreamWriteHandler(JSContext* cx,
|
||||
unsigned argc, Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
Rooted<WritableStream*> unwrappedStream(
|
||||
cx, TargetFromHandler<WritableStream>(args));
|
||||
|
||||
// Step 4.a: Perform ! WritableStreamFinishInFlightWrite(stream).
|
||||
if (!WritableStreamFinishInFlightWrite(cx, unwrappedStream)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 4.b: Let state be stream.[[state]].
|
||||
// Step 4.c: Assert: state is "writable" or "erroring".
|
||||
MOZ_ASSERT(unwrappedStream->writable() ^ unwrappedStream->erroring());
|
||||
|
||||
// Step 4.d: Perform ! DequeueValue(controller).
|
||||
DequeueValue(unwrappedStream->controller(), cx);
|
||||
|
||||
// Step 4.e: If ! WritableStreamCloseQueuedOrInFlight(stream) is false and
|
||||
// state is "writable",
|
||||
if (!WritableStreamCloseQueuedOrInFlight(unwrappedStream) &&
|
||||
unwrappedStream->writable()) {
|
||||
// Step 4.e.i: Let backpressure be
|
||||
// ! WritableStreamDefaultControllerGetBackpressure(
|
||||
// controller).
|
||||
bool backpressure = WritableStreamDefaultControllerGetBackpressure(
|
||||
unwrappedStream->controller());
|
||||
|
||||
// Step 4.e.ii: Perform
|
||||
// ! WritableStreamUpdateBackpressure(stream, backpressure).
|
||||
if (!WritableStreamUpdateBackpressure(cx, unwrappedStream, backpressure)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Step 4.f: Perform
|
||||
// ! WritableStreamDefaultControllerAdvanceQueueIfNeeded(
|
||||
// controller).
|
||||
Rooted<WritableStreamDefaultController*> unwrappedController(
|
||||
cx, unwrappedStream->controller());
|
||||
if (!WritableStreamDefaultControllerAdvanceQueueIfNeeded(
|
||||
cx, unwrappedController)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Streams spec, 4.8.12 step 5:
|
||||
* Upon rejection of sinkWritePromise with reason,
|
||||
*/
|
||||
static MOZ_MUST_USE bool WritableStreamWriteFailedHandler(JSContext* cx,
|
||||
unsigned argc,
|
||||
Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
Rooted<WritableStream*> unwrappedStream(
|
||||
cx, TargetFromHandler<WritableStream>(args));
|
||||
|
||||
// Step 5.a: If stream.[[state]] is "writable", perform
|
||||
// ! WritableStreamDefaultControllerClearAlgorithms(controller).
|
||||
if (unwrappedStream->writable()) {
|
||||
WritableStreamDefaultControllerClearAlgorithms(
|
||||
unwrappedStream->controller());
|
||||
}
|
||||
|
||||
// Step 5.b: Perform
|
||||
// ! WritableStreamFinishInFlightWriteWithError(stream, reason).
|
||||
if (!WritableStreamFinishInFlightWriteWithError(cx, unwrappedStream,
|
||||
args.get(0))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Streams spec, 4.8.9 (steps 7-10),
|
||||
* WritableStreamDefaultControllerAdvanceQueueIfNeeded ( controller )
|
||||
* Streams spec, 4.8.11.
|
||||
* WritableStreamDefaultControllerProcessClose ( controller )
|
||||
* Streams spec, 4.8.12.
|
||||
* WritableStreamDefaultControllerProcessWrite ( controller, chunk )
|
||||
*/
|
||||
bool WritableStreamDefaultControllerProcessIfNeeded(
|
||||
JSContext* cx,
|
||||
Handle<WritableStreamDefaultController*> unwrappedController) {
|
||||
// Step 7: If controller.[[queue]] is empty, return.
|
||||
ListObject* unwrappedQueue = unwrappedController->queue();
|
||||
if (QueueIsEmpty(unwrappedQueue)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Step 8: Let writeRecord be ! PeekQueueValue(controller).
|
||||
// Step 9: If writeRecord is "close", perform
|
||||
// ! WritableStreamDefaultControllerProcessClose(controller).
|
||||
// Step 10: Otherwise, perform
|
||||
// ! WritableStreamDefaultControllerProcessWrite(
|
||||
// controller, writeRecord.[[chunk]]).
|
||||
Rooted<JSObject*> sinkWriteOrClosePromise(cx);
|
||||
JSNative onFulfilledFunc, onRejectedFunc;
|
||||
if (PeekQueueValue(unwrappedQueue).isMagic(JS_WRITABLESTREAM_CLOSE_RECORD)) {
|
||||
MOZ_ASSERT(unwrappedQueue->length() == 2);
|
||||
|
||||
onFulfilledFunc = WritableStreamCloseHandler;
|
||||
onRejectedFunc = WritableStreamCloseFailedHandler;
|
||||
|
||||
// 4.8.11 step 1: Let stream be controller.[[controlledWritableStream]].
|
||||
// 4.8.11 step 2: Perform ! WritableStreamMarkCloseRequestInFlight(stream).
|
||||
WritableStreamMarkCloseRequestInFlight(unwrappedController->stream());
|
||||
|
||||
// 4.8.11 step 3: Perform ! DequeueValue(controller).
|
||||
DequeueValue(unwrappedController, cx);
|
||||
|
||||
// 4.8.11 step 4: Assert: controller.[[queue]] is empty.
|
||||
MOZ_ASSERT(unwrappedQueue->isEmpty());
|
||||
|
||||
// 4.8.11 step 5: Let sinkClosePromise be the result of performing
|
||||
// controller.[[closeAlgorithm]].
|
||||
sinkWriteOrClosePromise = PerformCloseAlgorithm(cx, unwrappedController);
|
||||
} else {
|
||||
onFulfilledFunc = WritableStreamWriteHandler;
|
||||
onRejectedFunc = WritableStreamWriteFailedHandler;
|
||||
|
||||
Rooted<Value> chunk(cx, PeekQueueValue(unwrappedQueue));
|
||||
if (!cx->compartment()->wrap(cx, &chunk)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4.8.12 step 1: Let stream be controller.[[controlledWritableStream]].
|
||||
// 4.8.12 step 2: Perform
|
||||
// ! WritableStreamMarkFirstWriteRequestInFlight(stream).
|
||||
WritableStreamMarkFirstWriteRequestInFlight(unwrappedController->stream());
|
||||
|
||||
// 4.8.12 step 3: Let sinkWritePromise be the result of performing
|
||||
// controller.[[writeAlgorithm]], passing in chunk.
|
||||
sinkWriteOrClosePromise =
|
||||
PerformWriteAlgorithm(cx, unwrappedController, chunk);
|
||||
}
|
||||
if (!sinkWriteOrClosePromise) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Rooted<JSObject*> stream(cx, unwrappedController->stream());
|
||||
if (!cx->compartment()->wrap(cx, &stream)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 7: Upon fulfillment of sinkClosePromise,
|
||||
// Step 4: Upon fulfillment of sinkWritePromise,
|
||||
// Step 8: Upon rejection of sinkClosePromise with reason reason,
|
||||
// Step 5: Upon rejection of sinkWritePromise with reason,
|
||||
Rooted<JSObject*> onFulfilled(cx, NewHandler(cx, onFulfilledFunc, stream));
|
||||
if (!onFulfilled) {
|
||||
return false;
|
||||
}
|
||||
Rooted<JSObject*> onRejected(cx, NewHandler(cx, onRejectedFunc, stream));
|
||||
if (!onRejected) {
|
||||
return false;
|
||||
}
|
||||
return JS::AddPromiseReactions(cx, sinkWriteOrClosePromise, onFulfilled,
|
||||
onRejected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Streams spec, 4.8.13.
|
||||
* WritableStreamDefaultControllerGetBackpressure ( controller )
|
||||
|
|
|
@ -81,6 +81,15 @@ extern MOZ_MUST_USE bool WritableStreamDefaultControllerErrorIfNeeded(
|
|||
JS::Handle<WritableStreamDefaultController*> unwrappedController,
|
||||
JS::Handle<JS::Value> error);
|
||||
|
||||
extern MOZ_MUST_USE bool WritableStreamDefaultControllerProcessClose(
|
||||
JSContext* cx,
|
||||
JS::Handle<WritableStreamDefaultController*> unwrappedController);
|
||||
|
||||
extern MOZ_MUST_USE bool WritableStreamDefaultControllerProcessWrite(
|
||||
JSContext* cx,
|
||||
JS::Handle<WritableStreamDefaultController*> unwrappedController,
|
||||
JS::Handle<JS::Value> chunk);
|
||||
|
||||
extern bool WritableStreamDefaultControllerGetBackpressure(
|
||||
const WritableStreamDefaultController* unwrappedController);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче