Quelle ReadableByteStreamController.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/. */
private: // An ArrayBuffer, which will be a transferred version of the one originally // supplied by the underlying byte source.
JS::Heap<JSObject*> mBuffer;
// A nonnegative integer number giving the byte offset derived from the view // originally supplied by the underlying byte source
size_t mByteOffset = 0;
// A nonnegative integer number giving the byte length derived from the view // originally supplied by the underlying byte source
size_t mByteLength = 0;
// Step 4. if (!aController->PendingPullIntos().isEmpty()) { // Step 4.1. Let firstPendingPullInto be controller.[[pendingPullIntos]][0].
PullIntoDescriptor* firstPendingPullInto =
aController->PendingPullIntos().getFirst();
// Step 4.2. If the remainder after dividing firstPendingPullInto’s bytes // filled by firstPendingPullInto’s element size is not 0, if ((firstPendingPullInto->BytesFilled() %
firstPendingPullInto->ElementSize()) != 0) { // Step 4.2.1
ErrorResult rv;
rv.ThrowTypeError("Leftover Bytes");
// Step 2. If cloneResult is an abrupt completion, if (!cloneResult) {
JS::Rooted<JS::Value> exception(aCx); if (!JS_GetPendingException(aCx, &exception)) { // Uncatchable exception; we should mark aRv and return.
aRv.StealExceptionFromJSContext(aCx); return;
}
JS_ClearPendingException(aCx);
// Step 2. Let reader be stream.[[reader]].
ReadableStreamBYOBReader* reader = aStream->GetReader()->AsBYOB();
// Step 3. Assert: reader.[[readIntoRequests]] is not empty.
MOZ_ASSERT(!reader->ReadIntoRequests().isEmpty());
// Step 4. Let readIntoRequest be reader.[[readIntoRequests]][0]. // Step 5. Remove readIntoRequest from reader.[[readIntoRequests]].
RefPtr<ReadIntoRequest> readIntoRequest =
reader->ReadIntoRequests().popFirst();
// Step 6. If done is true, perform readIntoRequest’s close steps, given // chunk. if (done) {
readIntoRequest->CloseSteps(aCx, aChunk, aRv); return;
}
// Step 2. Assert: pullIntoDescriptor.reader type is not "none".
MOZ_ASSERT(pullIntoDescriptor->GetReaderType() != ReaderType::None);
// Step 3. Let done be false. bool done = false;
// Step 4. If stream.[[state]] is "closed", if (aStream->State() == ReadableStream::ReaderState::Closed) { // Step 4.1. Assert: the remainder after dividing pullIntoDescriptor’s bytes // filled by pullIntoDescriptor’s element size is 0.
MOZ_ASSERT((pullIntoDescriptor->BytesFilled() %
pullIntoDescriptor->ElementSize()) == 0);
// Step 4.2. Set done to true.
done = true;
}
// Step 5. Let filledView be ! // ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor).
JS::Rooted<JSObject*> filledView(
aCx, ReadableByteStreamControllerConvertPullIntoDescriptor(
aCx, pullIntoDescriptor, aRv)); if (aRv.Failed()) { return;
}
JS::Rooted<JS::Value> filledViewValue(aCx, JS::ObjectValue(*filledView));
// Step 6. If pullIntoDescriptor’s reader type is "default", if (pullIntoDescriptor->GetReaderType() == ReaderType::Default) { // Step 6.1. Perform !ReadableStreamFulfillReadRequest(stream, filledView, // done).
ReadableStreamFulfillReadRequest(aCx, aStream, filledViewValue, done, aRv); return;
}
// Step 7.1. Assert: pullIntoDescriptor’s reader type is "byob".
MOZ_ASSERT(pullIntoDescriptor->GetReaderType() == ReaderType::BYOB);
// Step 2. Let filledPullIntos be a new empty list.
MOZ_ASSERT(aFilledPullIntos.IsEmpty());
// Step 3. While controller.[[pendingPullIntos]] is not empty, while (!aController->PendingPullIntos().isEmpty()) { // Step 3.1. If controller.[[queueTotalSize]] is 0, then break. if (aController->QueueTotalSize() == 0) { break;
}
// Step 3.2. Let pullIntoDescriptor be controller.[[pendingPullIntos]][0].
RefPtr<PullIntoDescriptor> pullIntoDescriptor =
aController->PendingPullIntos().getFirst();
// Step 3.3. If // !ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, // pullIntoDescriptor) is true, bool ready = ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(
aCx, aController, pullIntoDescriptor, aRv); if (aRv.Failed()) { return;
}
// Step 3. While reader.[[readRequests]] is not empty, while (!reader->ReadRequests().isEmpty()) { // Step 3.1. If controller.[[queueTotalSize]] is 0, return. if (aController->QueueTotalSize() == 0) { return;
}
// Step 3.2. Let readRequest be reader.[[readRequests]][0]. // Step 3.3. Remove readRequest from reader.[[readRequests]].
RefPtr<ReadRequest> readRequest = reader->ReadRequests().popFirst();
// Step 9.3.2. If controller.[[pendingPullIntos]] is not empty, if (!aController->PendingPullIntos().isEmpty()) { // Step 9.3.2.1. Assert: controller.[[pendingPullIntos]][0]'s reader // type is "default".
MOZ_ASSERT(
aController->PendingPullIntos().getFirst()->GetReaderType() ==
ReaderType::Default);
// Step 10.2. Let filledPullIntos be the result of performing ! // ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller).
nsTArray<RefPtr<PullIntoDescriptor>> filledPullIntos;
ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(
aCx, aController, filledPullIntos, aRv); if (aRv.Failed()) { return;
}
// Step 10.3. For each filledPullInto of filledPullIntos, for (auto& filledPullInto : filledPullIntos) { // Step 10.3.1. Perform ! // ReadableByteStreamControllerCommitPullIntoDescriptor(stream, // filledPullInto).
ReadableByteStreamControllerCommitPullIntoDescriptor(
aCx, stream, MOZ_KnownLive(filledPullInto), aRv); if (aRv.Failed()) { return;
}
}
// Step 4. Let autoAllocateChunkSize be this.[[autoAllocateChunkSize]].
Maybe<uint64_t> autoAllocateChunkSize = AutoAllocateChunkSize();
// Step 5. If autoAllocateChunkSize is not undefined, if (autoAllocateChunkSize) { // Step 5.1. Let buffer be Construct(%ArrayBuffer%, « autoAllocateChunkSize // »).
aRv.MightThrowJSException();
JS::Rooted<JSObject*> buffer(
aCx, JS::NewArrayBuffer(aCx, *autoAllocateChunkSize));
// Step 5.2. If buffer is an abrupt completion, if (!buffer) { // Step 5.2.1. Perform readRequest’s error steps, given buffer.[[Value]].
JS::Rooted<JS::Value> bufferError(aCx); if (!JS_GetPendingException(aCx, &bufferError)) { // Uncatchable exception; we should mark aRv and return.
aRv.StealExceptionFromJSContext(aCx); return;
}
// It's not explicitly stated, but I assume the intention here is that // we perform a normal completion here.
JS_ClearPendingException(aCx);
aReadRequest->ErrorSteps(aCx, bufferError, aRv);
// Step 5.2.2. Return. return;
}
// Step 5.3 Let pullIntoDescriptor be a new pull-into descriptor with // buffer buffer.[[Value]] // buffer byte length autoAllocateChunkSize // byte offset 0 // byte length autoAllocateChunkSize // bytes filled 0 // minimum fill 1 // element size 1 // view constructor %Uint8Array% // reader type "default"
RefPtr<PullIntoDescriptor> pullIntoDescriptor = new PullIntoDescriptor(
buffer, /* aBufferByteLength */ *autoAllocateChunkSize, /*aByteOffset */ 0, /* aByteLength */ *autoAllocateChunkSize, /* aBytesFilled */ 0, /* aMinimumFill */ 1, /* aElementSize */ 1,
PullIntoDescriptor::Constructor::Uint8, ReaderType::Default);
// Step 5.4. Append pullIntoDescriptor to this.[[pendingPullIntos]].
PendingPullIntos().insertBack(pullIntoDescriptor);
}
// https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamcontroller-releasesteps void ReadableByteStreamController::ReleaseSteps() { // Step 1. If this.[[pendingPullIntos]] is not empty, if (!PendingPullIntos().isEmpty()) { // Step 1.1. Let firstPendingPullInto be this.[[pendingPullIntos]][0].
RefPtr<PullIntoDescriptor> firstPendingPullInto =
PendingPullIntos().popFirst();
// Step 1.2. Set firstPendingPullInto’s reader type to "none".
firstPendingPullInto->SetReaderType(ReaderType::None);
// Step 1.3. Set this.[[pendingPullIntos]] to the list « // firstPendingPullInto ».
PendingPullIntos().clear();
PendingPullIntos().insertBack(firstPendingPullInto);
}
}
// https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-in-closed-state
MOZ_CAN_RUN_SCRIPT staticvoid ReadableByteStreamControllerRespondInClosedState(
JSContext* aCx, ReadableByteStreamController* aController,
RefPtr<PullIntoDescriptor>& aFirstDescriptor, ErrorResult& aRv) { // Step 1. Assert: the remainder after dividing firstDescriptor’s bytes filled // by firstDescriptor’s element size is 0.
MOZ_ASSERT(
(aFirstDescriptor->BytesFilled() % aFirstDescriptor->ElementSize()) == 0);
// Step 2. If firstDescriptor’s reader type is "none", // perform ! ReadableByteStreamControllerShiftPendingPullInto(controller). if (aFirstDescriptor->GetReaderType() == ReaderType::None) {
RefPtr<PullIntoDescriptor> discarded =
ReadableByteStreamControllerShiftPendingPullInto(aController);
(void)discarded;
}
// Step 3. Let stream be controller.[[stream]].
RefPtr<ReadableStream> stream = aController->Stream();
// Step 4. If ! ReadableStreamHasBYOBReader(stream) is true, if (ReadableStreamHasBYOBReader(stream)) { // Step 4.1. Let filledPullIntos be a new empty list.
nsTArray<RefPtr<PullIntoDescriptor>> filledPullIntos;
// Step 4.2. While |filledPullInto|'s [=list/size=] < ! // ReadableStreamGetNumReadIntoRequests(stream), while (filledPullIntos.Length() <
ReadableStreamGetNumReadIntoRequests(stream)) { // Step 4.2.1. Let pullIntoDescriptor be ! // ReadableByteStreamControllerShiftPendingPullInto(controller).
RefPtr<PullIntoDescriptor> pullIntoDescriptor =
ReadableByteStreamControllerShiftPendingPullInto(aController);
// Step 4.2.2. Append pullIntoDescriptor to filledPullIntos.
filledPullIntos.AppendElement(pullIntoDescriptor);
}
// Step 4.3. For each filledPullInto of filledPullIntos, for (auto& filledPullInto : filledPullIntos) { // Step 4.3.1. Perform ! // ReadableByteStreamControllerCommitPullIntoDescriptor(stream, // filledPullInto).
ReadableByteStreamControllerCommitPullIntoDescriptor(
aCx, stream, MOZ_KnownLive(filledPullInto), aRv); if (aRv.Failed()) { return;
}
}
}
}
// https://streams.spec.whatwg.org/#readable-byte-stream-controller-fill-head-pull-into-descriptor void ReadableByteStreamControllerFillHeadPullIntoDescriptor(
ReadableByteStreamController* aController, size_t aSize,
PullIntoDescriptor* aPullIntoDescriptor) { // Step 1. Assert: either controller.[[pendingPullIntos]] is empty, or // controller.[[pendingPullIntos]][0] is pullIntoDescriptor.
MOZ_ASSERT(aController->PendingPullIntos().isEmpty() ||
aController->PendingPullIntos().getFirst() == aPullIntoDescriptor);
// Step 2. Assert: controller.[[byobRequest]] is null.
MOZ_ASSERT(!aController->GetByobRequest());
// Step 3. Set pullIntoDescriptor’s bytes filled to bytes filled + size.
aPullIntoDescriptor->SetBytesFilled(aPullIntoDescriptor->BytesFilled() +
aSize);
}
// Step 3. If pullIntoDescriptor’s reader type is "none", if (aPullIntoDescriptor->GetReaderType() == ReaderType::None) { // Step 3.1. Perform ? // ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue(controller, // pullIntoDescriptor).
ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue(
aCx, aController, aPullIntoDescriptor, aRv); if (aRv.Failed()) { return;
}
// Step 3.2. Let filledPullIntos be the result of performing ! // ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller).
nsTArray<RefPtr<PullIntoDescriptor>> filledPullIntos;
ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(
aCx, aController, filledPullIntos, aRv); if (aRv.Failed()) { return;
}
// Step 3.3. For each filledPullInto of filledPullIntos, for (auto& filledPullInto : filledPullIntos) { // Step 3.3.1. Perform ! // ReadableByteStreamControllerCommitPullIntoDescriptor(controller.[[stream]], // filledPullInto).
ReadableByteStreamControllerCommitPullIntoDescriptor(
aCx, MOZ_KnownLive(aController->Stream()),
MOZ_KnownLive(filledPullInto), aRv); if (aRv.Failed()) { return;
}
}
// Step 3.4. Return. return;
}
// Step 4. If pullIntoDescriptor’s bytes filled < pullIntoDescriptor’s minimum // fill, return. if (aPullIntoDescriptor->BytesFilled() < aPullIntoDescriptor->MinimumFill()) { return;
}
// Step 6. Let remainderSize be the remainder after dividing // pullIntoDescriptor’s bytes filled by pullIntoDescriptor’s element size.
size_t remainderSize =
aPullIntoDescriptor->BytesFilled() % aPullIntoDescriptor->ElementSize();
// Step 7. If remainderSize > 0, if (remainderSize > 0) { // Step 7.1. Let end be pullIntoDescriptor’s byte offset + // pullIntoDescriptor’s bytes filled.
size_t end =
aPullIntoDescriptor->ByteOffset() + aPullIntoDescriptor->BytesFilled();
// Step 8. Set pullIntoDescriptor’s bytes filled to pullIntoDescriptor’s bytes // filled − remainderSize.
aPullIntoDescriptor->SetBytesFilled(aPullIntoDescriptor->BytesFilled() -
remainderSize);
// Step 9. Let filledPullIntos be the result of performing ! // ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller).
nsTArray<RefPtr<PullIntoDescriptor>> filledPullIntos;
ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(
aCx, aController, filledPullIntos, aRv); if (aRv.Failed()) { return;
}
#ifdef DEBUG // https://streams.spec.whatwg.org/#abstract-opdef-cancopydatablockbytes bool CanCopyDataBlockBytes(JS::Handle<JSObject*> aToBuffer, size_t aToIndex,
JS::Handle<JSObject*> aFromBuffer, size_t aFromIndex,
size_t aCount) { // Step 1. Assert: toBuffer is an Object. // Step 2. Assert: toBuffer has an [[ArrayBufferData]] internal slot.
MOZ_ASSERT(JS::IsArrayBufferObject(aToBuffer));
// Step 3. Assert: fromBuffer is an Object. // Step 4. Assert: fromBuffer has an [[ArrayBufferData]] internal slot.
MOZ_ASSERT(JS::IsArrayBufferObject(aFromBuffer));
// Step 5. If toBuffer is fromBuffer, return false. // Note: JS API makes it safe to just compare the pointers. if (aToBuffer == aFromBuffer) { returnfalse;
}
// Step 6. If ! IsDetachedBuffer(toBuffer) is true, return false. if (JS::IsDetachedArrayBufferObject(aToBuffer)) { returnfalse;
}
// Step 7. If ! IsDetachedBuffer(fromBuffer) is true, return false. if (JS::IsDetachedArrayBufferObject(aFromBuffer)) { returnfalse;
}
// Step 8. If toIndex + count > toBuffer.[[ArrayBufferByteLength]], return // false. if (aToIndex + aCount > JS::GetArrayBufferByteLength(aToBuffer)) { returnfalse;
} // (Not in the spec) also check overflow. if (aToIndex + aCount < aToIndex) { returnfalse;
}
// Step 9. If fromIndex + count > fromBuffer.[[ArrayBufferByteLength]], return // false. if (aFromIndex + aCount > JS::GetArrayBufferByteLength(aFromBuffer)) { returnfalse;
} // (Not in the spec) also check overflow. if (aFromIndex + aCount < aFromIndex) { returnfalse;
}
// Step 7. Let remainderBytes be the remainder after dividing maxBytesFilled // by pullIntoDescriptor’s element size.
size_t remainderBytes = maxBytesFilled % aPullIntoDescriptor->ElementSize();
// Step 8. Let maxAlignedBytes be maxBytesFilled − remainderBytes.
size_t maxAlignedBytes = maxBytesFilled - remainderBytes;
// Step 9. If maxAlignedBytes ≥ pullIntoDescriptor’s minimum fill, if (maxAlignedBytes >= aPullIntoDescriptor->MinimumFill()) { // Step 9.1. Set totalBytesToCopyRemaining to maxAlignedBytes − // pullIntoDescriptor’s bytes filled.
totalBytesToCopyRemaining =
maxAlignedBytes - aPullIntoDescriptor->BytesFilled(); // Step 9.2. Set ready to true.
ready = true;
}
// Step 10. Let queue be controller.[[queue]].
LinkedList<RefPtr<ReadableByteStreamQueueEntry>>& queue =
aController->Queue();
// Step 11. While totalBytesToCopyRemaining > 0, while (totalBytesToCopyRemaining > 0) { // Step 11.1 Let headOfQueue be queue[0].
ReadableByteStreamQueueEntry* headOfQueue = queue.getFirst();
// Step 11.2. Let bytesToCopy be min(totalBytesToCopyRemaining, // headOfQueue’s byte length).
--> --------------------
--> maximum size reached
--> --------------------
¤ Dauer der Verarbeitung: 0.8 Sekunden
(vorverarbeitet)
¤
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.