Index: third_party/WebKit/Source/core/streams/WritableStream.js |
diff --git a/third_party/WebKit/Source/core/streams/WritableStream.js b/third_party/WebKit/Source/core/streams/WritableStream.js |
index 4a4429cba4265467df633a4571b661315efbae27..7be92669bb958edce729ae73188e180043654881 100644 |
--- a/third_party/WebKit/Source/core/streams/WritableStream.js |
+++ b/third_party/WebKit/Source/core/streams/WritableStream.js |
@@ -41,14 +41,16 @@ |
const _strategySize = v8.createPrivateSymbol('[[strategySize]]'); |
const _underlyingSink = v8.createPrivateSymbol('[[underlyingSink]]'); |
- // Numeric encodings of states |
+ // Numeric encodings of stream states. Stored in the _stateAndFlags slot. |
const WRITABLE = 0; |
const CLOSED = 1; |
- const ERRORED = 2; |
+ const ERRORING = 2; |
+ const ERRORED = 3; |
- // Mask to extract or assign states to _stateAndFlags |
+ // Mask to extract or assign states to _stateAndFlags. |
const STATE_MASK = 0xF; |
+ // Also stored in _stateAndFlags. |
const BACKPRESSURE_FLAG = 0x10; |
// Javascript functions. It is important to use these copies, as the ones on |
@@ -206,48 +208,26 @@ |
if (state === ERRORED) { |
return Promise_reject(stream[_storedError]); |
} |
- TEMP_ASSERT(state === WRITABLE, |
- 'state is "writable".'); |
const error = new TypeError(errStreamAborting); |
if (stream[_pendingAbortRequest] !== undefined) { |
return Promise_reject(error); |
} |
- const controller = stream[_writableStreamController]; |
- TEMP_ASSERT(controller !== undefined, |
- 'controller is not undefined'); |
- if (!WritableStreamHasOperationMarkedInFlight(stream) && |
- controller[_started]) { |
- WritableStreamFinishAbort(stream); |
- return WritableStreamDefaultControllerAbortSteps(controller, reason); |
- } |
- const writer = stream[_writer]; |
- if (writer !== undefined) { |
- WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, error); |
+ TEMP_ASSERT(state === WRITABLE || state === ERRORING, |
+ '_state_ is `"writable"` or `"erroring"`'); |
+ |
+ const wasAlreadyErroring = state === ERRORING; |
+ if (wasAlreadyErroring) { |
+ reason = undefined; |
} |
+ |
const promise = v8.createPromise(); |
- stream[_pendingAbortRequest] = {promise, reason}; |
- return promise; |
- } |
+ stream[_pendingAbortRequest] = {promise, reason, wasAlreadyErroring}; |
- function WritableStreamError(stream, error) { |
- stream[_stateAndFlags] = (stream[_stateAndFlags] & ~STATE_MASK) | ERRORED; |
- stream[_storedError] = error; |
- WritableStreamDefaultControllerErrorSteps(stream[_writableStreamController]); |
- if (stream[_pendingAbortRequest] === undefined) { |
- const writer = stream[_writer]; |
- if (writer !== undefined) { |
- WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, error); |
- } |
- } |
- if (!WritableStreamHasOperationMarkedInFlight(stream)) { |
- WritableStreamRejectPromisesInReactionToError(stream); |
+ if (!wasAlreadyErroring) { |
+ WritableStreamStartErroring(stream, error); |
} |
- } |
- |
- function WritableStreamFinishAbort(stream) { |
- const error = new TypeError(errStreamAborted); |
- WritableStreamError(stream, error); |
+ return promise; |
} |
// Writable Stream Abstract Operations Used by Controllers |
@@ -262,23 +242,90 @@ |
return promise; |
} |
- function WritableStreamFinishInFlightWrite(stream) { |
- TEMP_ASSERT(stream[_inFlightWriteRequest] !== undefined, |
- '_stream_.[[inFlightWriteRequest]] is not *undefined*.'); |
- v8.resolvePromise(stream[_inFlightWriteRequest], undefined); |
- stream[_inFlightWriteRequest] = undefined; |
+ function WritableStreamDealWithRejection(stream, error) { |
const state = stream[_stateAndFlags] & STATE_MASK; |
- if (state === ERRORED) { |
- WritableStreamFinishInFlightWriteInErroredState(stream); |
+ if (state === WRITABLE) { |
+ WritableStreamStartErroring(stream, error); |
+ return; |
+ } |
+ |
+ TEMP_ASSERT(state === ERRORING, '_state_ is `"erroring"`'); |
+ WritableStreamFinishErroring(stream); |
+ } |
+ |
+ function WritableStreamStartErroring(stream, reason) { |
+ TEMP_ASSERT(stream[_storedError] === undefined, |
+ '_stream_.[[storedError]] is *undefined*'); |
+ TEMP_ASSERT((stream[_stateAndFlags] & STATE_MASK) === WRITABLE, |
+ '_stream_.[[state]] is `"writable"`'); |
+ |
+ const controller = stream[_writableStreamController]; |
+ TEMP_ASSERT(controller !== undefined, '_controller_ is not *undefined*'); |
+ |
+ stream[_stateAndFlags] = (stream[_stateAndFlags] & ~STATE_MASK) | ERRORING; |
+ stream[_storedError] = reason; |
+ |
+ const writer = stream[_writer]; |
+ if (writer !== undefined) { |
+ WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, reason); |
+ } |
+ |
+ if (!WritableStreamHasOperationMarkedInFlight(stream) && |
+ controller[_started]) { |
+ WritableStreamFinishErroring(stream); |
+ } |
+ } |
+ |
+ function WritableStreamFinishErroring(stream) { |
+ TEMP_ASSERT((stream[_stateAndFlags] & STATE_MASK) === ERRORING, |
+ '_stream_.[[state]] is `"erroring"`'); |
+ TEMP_ASSERT( |
+ !WritableStreamHasOperationMarkedInFlight(stream), |
+ '! WritableStreamHasOperationMarkedInFlight(_stream_) is *false*'); |
+ |
+ stream[_stateAndFlags] = (stream[_stateAndFlags] & ~STATE_MASK) | ERRORED; |
+ |
+ WritableStreamDefaultControllerErrorSteps( |
+ stream[_writableStreamController]); |
+ |
+ const storedError = stream[_storedError]; |
+ rejectPromises(stream[_writeRequests], storedError); |
+ stream[_writeRequests] = new binding.SimpleQueue(); |
+ |
+ if (stream[_pendingAbortRequest] === undefined) { |
+ WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream); |
+ return; |
+ } |
+ |
+ const abortRequest = stream[_pendingAbortRequest]; |
+ stream[_pendingAbortRequest] = undefined; |
+ |
+ if (abortRequest.wasAlreadyErroring === true) { |
+ v8.rejectPromise(abortRequest.promise, storedError); |
+ WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream); |
return; |
} |
- TEMP_ASSERT(state === WRITABLE, '_state_ is `"writable"`.'); |
- WritableStreamHandleAbortRequestIfPending(stream); |
+ |
+ const promise = WritableStreamDefaultControllerAbortSteps( |
+ stream[_writableStreamController], abortRequest.reason); |
+ |
+ thenPromise( |
+ promise, |
+ () => { |
+ v8.resolvePromise(abortRequest.promise, undefined); |
+ WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream); |
+ }, |
+ reason => { |
+ v8.rejectPromise(abortRequest.promise, reason); |
+ WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream); |
+ }); |
} |
- function WritableStreamFinishInFlightWriteInErroredState(stream) { |
- WritableStreamRejectAbortRequestIfPending(stream); |
- WritableStreamRejectPromisesInReactionToError(stream); |
+ function WritableStreamFinishInFlightWrite(stream) { |
+ TEMP_ASSERT(stream[_inFlightWriteRequest] !== undefined, |
+ '_stream_.[[inFlightWriteRequest]] is not *undefined*.'); |
+ v8.resolvePromise(stream[_inFlightWriteRequest], undefined); |
+ stream[_inFlightWriteRequest] = undefined; |
} |
function WritableStreamFinishInFlightWriteWithError(stream, error) { |
@@ -286,14 +333,12 @@ |
'_stream_.[[inFlightWriteRequest]] is not *undefined*.'); |
v8.rejectPromise(stream[_inFlightWriteRequest], error); |
stream[_inFlightWriteRequest] = undefined; |
- const state = stream[_stateAndFlags] & STATE_MASK; |
- if (state === ERRORED) { |
- WritableStreamFinishInFlightWriteInErroredState(stream); |
- return; |
- } |
- TEMP_ASSERT(state === WRITABLE, '_state_ is `"writable"`.'); |
- WritableStreamError(stream, error); |
- WritableStreamRejectAbortRequestIfPending(stream); |
+ |
+ let state = stream[_stateAndFlags] & STATE_MASK; |
+ TEMP_ASSERT(state === WRITABLE || state === ERRORING, |
+ '_stream_.[[state]] is `"writable"` or `"erroring"`'); |
+ |
+ WritableStreamDealWithRejection(stream, error); |
} |
function WritableStreamFinishInFlightClose(stream) { |
@@ -301,26 +346,29 @@ |
'_stream_.[[inFlightCloseRequest]] is not *undefined*.'); |
v8.resolvePromise(stream[_inFlightCloseRequest], undefined); |
stream[_inFlightCloseRequest] = undefined; |
+ |
const state = stream[_stateAndFlags] & STATE_MASK; |
- if (state === ERRORED) { |
- WritableStreamFinishInFlightCloseInErroredState(stream); |
- return; |
+ TEMP_ASSERT(state === WRITABLE || state === ERRORING, |
+ '_stream_.[[state]] is `"writable"` or `"erroring"`'); |
+ |
+ if (state === ERRORING) { |
+ stream[_storedError] = undefined; |
+ if (stream[_pendingAbortRequest] !== undefined) { |
+ v8.resolvePromise(stream[_pendingAbortRequest].promise, undefined); |
+ stream[_pendingAbortRequest] = undefined; |
+ } |
} |
- TEMP_ASSERT(state === WRITABLE, '_state_ is `"writable"`.'); |
+ |
stream[_stateAndFlags] = (stream[_stateAndFlags] & ~STATE_MASK) | CLOSED; |
const writer = stream[_writer]; |
if (writer !== undefined) { |
v8.resolvePromise(writer[_closedPromise], undefined); |
} |
- if (stream[_pendingAbortRequest] !== undefined) { |
- v8.resolvePromise(stream[_pendingAbortRequest].promise, undefined); |
- stream[_pendingAbortRequest] = undefined; |
- } |
- } |
- function WritableStreamFinishInFlightCloseInErroredState(stream) { |
- WritableStreamRejectAbortRequestIfPending(stream); |
- WritableStreamRejectClosedPromiseInReactionToError(stream); |
+ TEMP_ASSERT(stream[_pendingAbortRequest] === undefined, |
+ '_stream_.[[pendingAbortRequest]] is *undefined*'); |
+ TEMP_ASSERT(stream[_storedError] === undefined, |
+ '_stream_.[[storedError]] is *undefined*'); |
} |
function WritableStreamFinishInFlightCloseWithError(stream, error) { |
@@ -328,14 +376,17 @@ |
'_stream_.[[inFlightCloseRequest]] is not *undefined*.'); |
v8.rejectPromise(stream[_inFlightCloseRequest], error); |
stream[_inFlightCloseRequest] = undefined; |
+ |
const state = stream[_stateAndFlags] & STATE_MASK; |
- if (state === ERRORED) { |
- WritableStreamFinishInFlightCloseInErroredState(stream); |
- return; |
+ TEMP_ASSERT(state === WRITABLE || state === ERRORING, |
+ '_stream_.[[state]] is `"writable"` or `"erroring"`'); |
+ |
+ if (stream[_pendingAbortRequest] !== undefined) { |
+ v8.rejectPromise(stream[_pendingAbortRequest].promise, error); |
+ stream[_pendingAbortRequest] = undefined; |
} |
- TEMP_ASSERT(state === WRITABLE, '_state_ is `"writable"`.'); |
- WritableStreamError(stream, error); |
- WritableStreamRejectAbortRequestIfPending(stream); |
+ |
+ WritableStreamDealWithRejection(stream, error); |
} |
function WritableStreamCloseQueuedOrInFlight(stream) { |
@@ -343,21 +394,6 @@ |
stream[_inFlightCloseRequest] !== undefined; |
} |
- function WritableStreamHandleAbortRequestIfPending(stream) { |
- if (stream[_pendingAbortRequest] === undefined) { |
- return; |
- } |
- WritableStreamFinishAbort(stream); |
- const abortRequest = stream[_pendingAbortRequest]; |
- stream[_pendingAbortRequest] = undefined; |
- const promise = |
- WritableStreamDefaultControllerAbortSteps(stream[_writableStreamController], |
- abortRequest.reason); |
- thenPromise(promise, |
- result => v8.resolvePromise(abortRequest.promise, result), |
- reason => v8.rejectPromise(abortRequest.promise, reason)); |
- } |
- |
function WritableStreamHasOperationMarkedInFlight(stream) { |
return stream[_inFlightWriteRequest] !== undefined || |
stream[_inFlightCloseRequest] !== undefined; |
@@ -381,35 +417,22 @@ |
stream[_inFlightWriteRequest] = writeRequest; |
} |
- function WritableStreamRejectClosedPromiseInReactionToError(stream) { |
- const writer = stream[_writer]; |
- if (writer !== undefined) { |
- v8.rejectPromise(writer[_closedPromise], stream[_storedError]); |
- v8.markPromiseAsHandled(writer[_closedPromise]); |
- } |
- } |
- |
- function WritableStreamRejectAbortRequestIfPending(stream) { |
- if (stream[_pendingAbortRequest] !== undefined) { |
- v8.rejectPromise(stream[_pendingAbortRequest].promise, |
- stream[_storedError]); |
- stream[_pendingAbortRequest] = undefined; |
- } |
- } |
- |
- function WritableStreamRejectPromisesInReactionToError(stream) { |
- const storedError = stream[_storedError]; |
- rejectPromises(stream[_writeRequests], storedError); |
- stream[_writeRequests] = new binding.SimpleQueue(); |
+ function WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream) { |
+ TEMP_ASSERT((stream[_stateAndFlags] & STATE_MASK) === ERRORED, |
+ '_stream_.[[state]] is `"errored"`'); |
if (stream[_closeRequest] !== undefined) { |
TEMP_ASSERT(stream[_inFlightCloseRequest] === undefined, |
- '_stream_.[[inFlightCloseRequest]] is *undefined*.'); |
- v8.rejectPromise(stream[_closeRequest], storedError); |
+ '_stream_.[[inFlightCloseRequest]] is *undefined*'); |
+ v8.rejectPromise(stream[_closeRequest], stream[_storedError]); |
stream[_closeRequest] = undefined; |
} |
- WritableStreamRejectClosedPromiseInReactionToError(stream); |
+ const writer = stream[_writer]; |
+ if (writer !== undefined) { |
+ v8.rejectPromise(writer[_closedPromise], stream[_storedError]); |
+ v8.markPromiseAsHandled(writer[_closedPromise]); |
+ } |
} |
function WritableStreamUpdateBackpressure(stream, backpressure) { |
@@ -466,28 +489,44 @@ |
this[_ownerWritableStream] = stream; |
stream[_writer] = this; |
const state = stream[_stateAndFlags] & STATE_MASK; |
- if (state === WRITABLE) { |
- if (stream[_pendingAbortRequest] !== undefined) { |
- const error = new TypeError(errStreamAborting); |
- this[_readyPromise] = Promise_reject(error); |
+ switch (state) { |
+ case WRITABLE: |
+ { |
+ if (!WritableStreamCloseQueuedOrInFlight(stream) && |
+ stream[_stateAndFlags] & BACKPRESSURE_FLAG) { |
+ this[_readyPromise] = v8.createPromise(); |
+ } else { |
+ this[_readyPromise] = Promise_resolve(undefined); |
+ } |
+ this[_closedPromise] = v8.createPromise(); |
+ break; |
+ } |
+ |
+ case ERRORING: |
+ { |
+ this[_readyPromise] = Promise_reject(stream[_storedError]); |
v8.markPromiseAsHandled(this[_readyPromise]); |
- } else if (!WritableStreamCloseQueuedOrInFlight(stream) && |
- stream[_stateAndFlags] & BACKPRESSURE_FLAG) { |
- this[_readyPromise] = v8.createPromise(); |
- } else { |
+ this[_closedPromise] = v8.createPromise(); |
+ break; |
+ } |
+ |
+ case CLOSED: |
+ { |
this[_readyPromise] = Promise_resolve(undefined); |
+ this[_closedPromise] = Promise_resolve(undefined); |
+ break; |
+ } |
+ |
+ default: |
+ { |
+ TEMP_ASSERT(state === ERRORED, '_state_ is `"errored"`.'); |
+ const storedError = stream[_storedError]; |
+ this[_readyPromise] = Promise_reject(storedError); |
+ v8.markPromiseAsHandled(this[_readyPromise]); |
+ this[_closedPromise] = Promise_reject(storedError); |
+ v8.markPromiseAsHandled(this[_closedPromise]); |
+ break; |
} |
- this[_closedPromise] = v8.createPromise(); |
- } else if (state === CLOSED) { |
- this[_readyPromise] = Promise_resolve(undefined); |
- this[_closedPromise] = Promise_resolve(undefined); |
- } else { |
- TEMP_ASSERT(state === ERRORED, '_state_ is `"errored"`.'); |
- const storedError = stream[_storedError]; |
- this[_readyPromise] = Promise_reject(storedError); |
- v8.markPromiseAsHandled(this[_readyPromise]); |
- this[_closedPromise] = Promise_reject(storedError); |
- v8.markPromiseAsHandled(this[_closedPromise]); |
} |
} |
@@ -584,15 +623,16 @@ |
return Promise_reject( |
createCannotActionOnStateStreamError('close', state)); |
} |
- if (stream[_pendingAbortRequest] !== undefined) { |
- return Promise_reject(new TypeError(errStreamAborting)); |
- } |
- TEMP_ASSERT(state === WRITABLE, '_state_ is `"writable"`.'); |
+ |
+ TEMP_ASSERT(state === WRITABLE || state === ERRORING, |
+ '_state_ is `"writable"` or `"erroring"`.'); |
TEMP_ASSERT(!WritableStreamCloseQueuedOrInFlight(stream), |
'! WritableStreamCloseQueuedOrInFlight(_stream_) is *false*.'); |
const promise = v8.createPromise(); |
stream[_closeRequest] = promise; |
- if (stream[_stateAndFlags] & BACKPRESSURE_FLAG) { |
+ |
+ if ((stream[_stateAndFlags] & BACKPRESSURE_FLAG) && |
+ state === WRITABLE) { |
v8.resolvePromise(writer[_readyPromise], undefined); |
} |
WritableStreamDefaultControllerClose(stream[_writableStreamController]); |
@@ -609,12 +649,26 @@ |
if (state === ERRORED) { |
return Promise_reject(stream[_storedError]); |
} |
- TEMP_ASSERT(state === WRITABLE, 'state is "writable".'); |
+ |
+ TEMP_ASSERT(state === WRITABLE || state === ERRORING, |
+ '_state_ is `"writable"` or `"erroring"`.'); |
+ |
return WritableStreamDefaultWriterClose(writer); |
} |
- function WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, |
- error) { |
+ function WritableStreamDefaultWriterEnsureClosedPromiseRejected( |
+ writer, error) { |
+ if (v8.promiseState(writer[_closedPromise]) === v8.kPROMISE_PENDING) { |
+ v8.rejectPromise(writer[_closedPromise], error); |
+ } else { |
+ writer[_closedPromise] = Promise_reject(error); |
+ } |
+ v8.markPromiseAsHandled(writer[_closedPromise]); |
+ } |
+ |
+ |
+ function WritableStreamDefaultWriterEnsureReadyPromiseRejected( |
+ writer, error) { |
if (v8.promiseState(writer[_readyPromise]) === v8.kPROMISE_PENDING) { |
v8.rejectPromise(writer[_readyPromise], error); |
} else { |
@@ -626,7 +680,7 @@ |
function WritableStreamDefaultWriterGetDesiredSize(writer) { |
const stream = writer[_ownerWritableStream]; |
const state = stream[_stateAndFlags] & STATE_MASK; |
- if (state === ERRORED || stream[_pendingAbortRequest] !== undefined) { |
+ if (state === ERRORED || state === ERRORING) { |
return null; |
} |
if (state === CLOSED) { |
@@ -643,16 +697,10 @@ |
TEMP_ASSERT(stream[_writer] === writer, |
'stream.[[writer]] is writer.'); |
const releasedError = new TypeError(errReleasedWriterClosedPromise); |
- const state = stream[_stateAndFlags] & STATE_MASK; |
- WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, |
- releasedError); |
- if (state === WRITABLE || |
- WritableStreamHasOperationMarkedInFlight(stream)) { |
- v8.rejectPromise(writer[_closedPromise], releasedError); |
- } else { |
- writer[_closedPromise] = Promise_reject(releasedError); |
- } |
- v8.markPromiseAsHandled(writer[_closedPromise]); |
+ WritableStreamDefaultWriterEnsureReadyPromiseRejected( |
+ writer, releasedError); |
+ WritableStreamDefaultWriterEnsureClosedPromiseRejected( |
+ writer, releasedError); |
stream[_writer] = undefined; |
writer[_ownerWritableStream] = undefined; |
} |
@@ -678,9 +726,10 @@ |
return Promise_reject( |
createCannotActionOnStateStreamError('write to', CLOSED)); |
} |
- if (stream[_pendingAbortRequest] !== undefined) { |
- return Promise_reject(new TypeError(errStreamAborting)); |
+ if (state === ERRORING) { |
+ return Promise_reject(stream[_storedError]); |
} |
+ TEMP_ASSERT(state === WRITABLE, '_state_ is `"writable"`'); |
const promise = WritableStreamAddWriteRequest(stream); |
WritableStreamDefaultControllerWrite(controller, chunk, chunkSize); |
return promise; |
@@ -730,9 +779,10 @@ |
if (!IsWritableStreamDefaultController(this)) { |
throw new TypeError(streamErrors.illegalInvocation); |
} |
- const state = this[_controlledWritableStream][_stateAndFlags] & STATE_MASK; |
- if (state === CLOSED || state === ERRORED) { |
- throw createCannotActionOnStateStreamError('error', state); |
+ const state = |
+ this[_controlledWritableStream][_stateAndFlags] & STATE_MASK; |
+ if (state !== WRITABLE) { |
+ return; |
} |
WritableStreamDefaultControllerError(this, e); |
} |
@@ -744,9 +794,7 @@ |
// or impossible, so use static dispatch for now. This will have to be fixed |
// when adding a byte controller. |
function WritableStreamDefaultControllerAbortSteps(controller, reason) { |
- const sinkAbortPromise = |
- PromiseInvokeOrNoop(controller[_underlyingSink], 'abort', [reason]); |
- return thenPromise(sinkAbortPromise, () => undefined); |
+ return PromiseInvokeOrNoop(controller[_underlyingSink], 'abort', [reason]); |
} |
function WritableStreamDefaultControllerErrorSteps(controller) { |
@@ -761,21 +809,18 @@ |
thenPromise( |
startPromise, |
() => { |
+ const state = stream[_stateAndFlags] & STATE_MASK; |
+ TEMP_ASSERT(state === WRITABLE || state === ERRORING, |
+ '_stream_.[[state]] is `"writable"` or `"erroring"`'); |
controller[_started] = true; |
- if ((stream[_stateAndFlags] & STATE_MASK) === ERRORED) { |
- WritableStreamRejectAbortRequestIfPending(stream); |
- } else { |
- WritableStreamHandleAbortRequestIfPending(stream); |
- } |
WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller); |
}, |
r => { |
- TEMP_ASSERT( |
- (stream[_stateAndFlags] & STATE_MASK) === WRITABLE || |
- (stream[_stateAndFlags] & STATE_MASK) === ERRORED, |
- '_stream_.[[state]] is `"writable"` or `"errored"`.'); |
- WritableStreamDefaultControllerErrorIfNeeded(controller, r); |
- WritableStreamRejectAbortRequestIfPending(stream); |
+ const state = stream[_stateAndFlags] & STATE_MASK; |
+ TEMP_ASSERT(state === WRITABLE || state === ERRORING, |
+ '_stream_.[[state]] is `"writable"` or `"erroring"`'); |
+ controller[_started] = true; |
+ WritableStreamDealWithRejection(stream, r); |
}); |
} |
@@ -818,7 +863,8 @@ |
return; |
} |
const stream = controller[_controlledWritableStream]; |
- if (!WritableStreamCloseQueuedOrInFlight(stream)) { |
+ if (!WritableStreamCloseQueuedOrInFlight(stream) && |
+ (stream[_stateAndFlags] & STATE_MASK) === WRITABLE) { |
const backpressure = |
WritableStreamDefaultControllerGetBackpressure(controller); |
WritableStreamUpdateBackpressure(stream, backpressure); |
@@ -828,16 +874,20 @@ |
function WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller) { |
const stream = controller[_controlledWritableStream]; |
- const state = stream[_stateAndFlags] & STATE_MASK; |
- if (state === CLOSED || state === ERRORED) { |
- return; |
- } |
if (!controller[_started]) { |
return; |
} |
if (stream[_inFlightWriteRequest] !== undefined) { |
return; |
} |
+ const state = stream[_stateAndFlags] & STATE_MASK; |
+ if (state === CLOSED || state === ERRORED) { |
+ return; |
+ } |
+ if (state === ERRORING) { |
+ WritableStreamFinishErroring(stream); |
+ return; |
+ } |
if (controller[_queue].length === 0) { |
return; |
} |
@@ -851,7 +901,8 @@ |
} |
function WritableStreamDefaultControllerErrorIfNeeded(controller, error) { |
- const state = controller[_controlledWritableStream][_stateAndFlags] & STATE_MASK; |
+ const state = |
+ controller[_controlledWritableStream][_stateAndFlags] & STATE_MASK; |
if (state === WRITABLE) { |
WritableStreamDefaultControllerError(controller, error); |
} |
@@ -863,8 +914,8 @@ |
DequeueValue(controller); |
TEMP_ASSERT(controller[_queue].length === 0, |
'controller.[[queue]] is empty.'); |
- const sinkClosePromise = PromiseInvokeOrNoop(controller[_underlyingSink], |
- 'close', [controller]); |
+ const sinkClosePromise = PromiseInvokeOrNoop( |
+ controller[_underlyingSink], 'close', []); |
thenPromise( |
sinkClosePromise, |
() => WritableStreamFinishInFlightClose(stream), |
@@ -882,12 +933,11 @@ |
() => { |
WritableStreamFinishInFlightWrite(stream); |
const state = stream[_stateAndFlags] & STATE_MASK; |
- if (state === ERRORED) { |
- return; |
- } |
- TEMP_ASSERT(state === WRITABLE, '_state_ is `"writable"`.'); |
+ TEMP_ASSERT(state === WRITABLE || state === ERRORING, |
+ '_state_ is `"writable"` or `"erroring"`'); |
DequeueValue(controller); |
- if (!WritableStreamCloseQueuedOrInFlight(stream)) { |
+ if (!WritableStreamCloseQueuedOrInFlight(stream) && |
+ state === WRITABLE) { |
const backpressure = |
WritableStreamDefaultControllerGetBackpressure(controller); |
WritableStreamUpdateBackpressure(stream, backpressure); |
@@ -895,13 +945,7 @@ |
WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller); |
}, |
reason => { |
- const wasErrored = (stream[_stateAndFlags] & STATE_MASK) === ERRORED; |
WritableStreamFinishInFlightWriteWithError(stream, reason); |
- TEMP_ASSERT((stream[_stateAndFlags] & STATE_MASK) === ERRORED, |
- '_stream_.[[state]] is `"errored"`.'); |
- if (!wasErrored) { |
- ResetQueue(controller); |
- } |
}); |
} |
@@ -915,7 +959,7 @@ |
const stream = controller[_controlledWritableStream]; |
TEMP_ASSERT((stream[_stateAndFlags] & STATE_MASK) === WRITABLE, |
'_stream_.[[state]] is `"writable"`.'); |
- WritableStreamError(stream, error); |
+ WritableStreamStartErroring(stream, error); |
} |
// Queue-with-Sizes Operations |