Changeset 185197 in webkit


Ignore:
Timestamp:
Jun 4, 2015 3:19:43 AM (9 years ago)
Author:
youenn.fablet@crf.canon.fr
Message:

[Streams API] Implement ReadableStreamController enqueue
https://bugs.webkit.org/show_bug.cgi?id=145210

Reviewed by Darin Adler.

Source/WebCore:

Added possibility to enqueue any JSValue within ReadableJSStream.
They are stored in a Vector of strongified JSValue.

Added support for streams that contain data but are asked to close.
This is done through m_closeRequested boolean and splitting actual closing of the stream from changeStateToClosed().

Chunk size and backpressure mechanism is not yet implemented.
Neither is pulling once enqueued data is processed.

Covered by rebased tests.

  • Modules/streams/ReadableStream.cpp:

(WebCore::ReadableStream::changeStateToClosed): Split method with newly added close().
(WebCore::ReadableStream::close): Does the actual closing of stream once stream has no more values.
(WebCore::ReadableStream::read): Close the stream when stream is emptied and close is requested.
(WebCore::ReadableStream::resolveReadCallback): Added to enable ReadableJSStream to resolve read callbacks immediatly at enqueue time.

  • Modules/streams/ReadableStream.h:

(WebCore::ReadableStream::isErrored): Getter added for the custom binding code.
(WebCore::ReadableStream::isCloseRequested): Ditto.

  • bindings/js/JSReadableStreamControllerCustom.cpp:

(WebCore::JSReadableStreamController::enqueue): binding code for enqueue, taking care of raising exception if readable stream cannot enqueue.

  • bindings/js/ReadableJSStream.cpp:

(WebCore::ReadableJSStream::hasValue):
(WebCore::ReadableJSStream::read):
(WebCore::ReadableJSStream::enqueue):

  • bindings/js/ReadableJSStream.h:

LayoutTests:

  • streams/reference-implementation/bad-underlying-sources-expected.txt:
  • streams/reference-implementation/count-queuing-strategy-expected.txt:
  • streams/reference-implementation/count-queuing-strategy.html:
  • streams/reference-implementation/readable-stream-expected.txt:
  • streams/reference-implementation/readable-stream-reader-expected.txt:
  • streams/reference-implementation/readable-stream-reader.html:
  • streams/reference-implementation/readable-stream-templated-expected.txt:
  • streams/reference-implementation/readable-stream-templated.html:
  • streams/reference-implementation/readable-stream.html:
Location:
trunk
Files:
16 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r185192 r185197  
     12015-06-04  Xabier Rodriguez Calvar  <calvaris@igalia.com> and Youenn Fablet <youenn.fablet@crf.canon.fr>
     2
     3        [Streams API] Implement ReadableStreamController enqueue
     4        https://bugs.webkit.org/show_bug.cgi?id=145210
     5
     6        Reviewed by Darin Adler.
     7
     8        * streams/reference-implementation/bad-underlying-sources-expected.txt:
     9        * streams/reference-implementation/count-queuing-strategy-expected.txt:
     10        * streams/reference-implementation/count-queuing-strategy.html:
     11        * streams/reference-implementation/readable-stream-expected.txt:
     12        * streams/reference-implementation/readable-stream-reader-expected.txt:
     13        * streams/reference-implementation/readable-stream-reader.html:
     14        * streams/reference-implementation/readable-stream-templated-expected.txt:
     15        * streams/reference-implementation/readable-stream-templated.html:
     16        * streams/reference-implementation/readable-stream.html:
     17
    1182015-06-03  Zalan Bujtas  <zalan@apple.com>
    219
  • trunk/LayoutTests/streams/reference-implementation/bad-underlying-sources-expected.txt

    r185114 r185197  
    1919FAIL Underlying source: strategy.size returning +Infinity assert_unreached: enqueue didn't throw Reached unreachable code
    2020PASS Underlying source: calling close twice on an empty stream should throw the second time
    21 FAIL Underlying source: calling close twice on a non-empty stream should throw the second time assert_object_equals: read() should read the enqueued chunk property "done" expected object "[object Object]" got object "[object Object]"
     21PASS Underlying source: calling close twice on a non-empty stream should throw the second time
    2222FAIL Underlying source: calling close on an empty canceled stream should not throw cancel is not implemented
    2323FAIL Underlying source: calling close on a non-empty canceled stream should not throw cancel is not implemented
  • trunk/LayoutTests/streams/reference-implementation/count-queuing-strategy-expected.txt

    r185114 r185197  
    33PASS Gives a RangeError when the number is negative
    44PASS Can construct a readable stream with a valid CountQueuingStrategy
    5 TIMEOUT Correctly governs the return value of a ReadableStream's enqueue function (HWM = 0) Test timed out
    6 FAIL Correctly governs the return value of a ReadableStream's enqueue function (HWM = 1) assert_equals: After 0 reads, 1st enqueue should return true (queue now contains 1 chunk) expected true but got false
    7 FAIL Correctly governs the return value of a ReadableStream's enqueue function (HWM = 4) assert_equals: After 0 reads, 1st enqueue should return true (queue now contains 1 chunk) expected true but got false
     5FAIL Correctly governs the return value of a ReadableStream's enqueue function (HWM = 0) assert_equals: After 0 reads, 1st enqueue should return false (queue now contains 1 chunk) expected (boolean) false but got (undefined) undefined
     6FAIL Correctly governs the return value of a ReadableStream's enqueue function (HWM = 1) assert_equals: After 0 reads, 1st enqueue should return true (queue now contains 1 chunk) expected (boolean) true but got (undefined) undefined
     7FAIL Correctly governs the return value of a ReadableStream's enqueue function (HWM = 4) assert_equals: After 0 reads, 1st enqueue should return true (queue now contains 1 chunk) expected (boolean) true but got (undefined) undefined
    88
  • trunk/LayoutTests/streams/reference-implementation/count-queuing-strategy.html

    r185114 r185197  
    1818}, 'Can construct a readable stream with a valid CountQueuingStrategy');
    1919
    20 var test1 = async_test('Correctly governs the return value of a ReadableStream\'s enqueue function (HWM = 0)', { timeout: 50 });
     20var test1 = async_test('Correctly governs the return value of a ReadableStream\'s enqueue function (HWM = 0)');
    2121test1.step(function() {
    2222    var enqueue;
  • trunk/LayoutTests/streams/reference-implementation/readable-stream-expected.txt

    r185114 r185197  
    88TIMEOUT ReadableStream start should be able to return a promise Test timed out
    99TIMEOUT ReadableStream start should be able to return a promise and reject it Test timed out
    10 FAIL ReadableStream should be able to enqueue different objects. assert_object_equals: value read should be the one enqueued property "done" expected object "[object Object]" got object "[object Object]"
     10PASS ReadableStream should be able to enqueue different objects.
    1111PASS ReadableStream: if start throws an error, it should be re-thrown
    1212TIMEOUT ReadableStream: if pull rejects, it should error the stream Test timed out
    13 TIMEOUT ReadableStream: should not call pull until the previous pull call's promise fulfills Test timed out
     13FAIL ReadableStream: should not call pull until the previous pull call's promise fulfills assert_equals: pull should have been called once after start, but not yet have been called a second time expected 1 but got 0
    1414PASS ReadableStream: should not call pull after start if the stream is now closed
    1515FAIL ReadableStream: should call pull after enqueueing from inside pull (with no read requests), if strategy allows assert_equals: pull() should have been called four times expected 4 but got 0
    1616TIMEOUT ReadableStream pull should be able to close a stream. Test timed out
    17 FAIL ReadableStream: enqueue should throw when the stream is readable but draining assert_equals: the first enqueue should return true expected true but got false
    18 FAIL ReadableStream: enqueue should throw when the stream is closed assert_throws: enqueue after close should throw a TypeError function "function () { c.enqueue('a'); }" did not throw
    19 FAIL ReadableStream: enqueue should throw the stored error when the stream is errored assert_throws: enqueue after error should throw that error function "function () { c.enqueue('a'); }" did not throw
    20 TIMEOUT ReadableStream: should call underlying source methods as methods Test timed out
    21 FAIL ReadableStream strategies: the default strategy should return false for all but the first enqueue call assert_equals: first enqueue should return true expected true but got false
    22 FAIL ReadableStream strategies: the default strategy should continue returning true from enqueue if the chunks are read immediately assert_equals: first enqueue should return true expected true but got false
     17FAIL ReadableStream: enqueue should throw when the stream is readable but draining assert_equals: the first enqueue should return true expected (boolean) true but got (undefined) undefined
     18PASS ReadableStream: enqueue should throw when the stream is closed
     19PASS ReadableStream: enqueue should throw the stored error when the stream is errored
     20FAIL ReadableStream: should call underlying source methods as methods releaseLock is not implemented
     21FAIL ReadableStream strategies: the default strategy should return false for all but the first enqueue call assert_equals: first enqueue should return true expected (boolean) true but got (undefined) undefined
     22FAIL ReadableStream strategies: the default strategy should continue returning true from enqueue if the chunks are read immediately assert_equals: first enqueue should return true expected (boolean) true but got (undefined) undefined
    2323TIMEOUT ReadableStream integration test: adapting a random push source Test timed out
    2424TIMEOUT ReadableStream integration test: adapting a sync pull source Test timed out
  • trunk/LayoutTests/streams/reference-implementation/readable-stream-reader-expected.txt

    r185114 r185197  
    1010PASS Constructing a ReadableStreamReader directly should be OK if the stream is closed
    1111PASS Constructing a ReadableStreamReader directly should be OK if the stream is errored
    12 TIMEOUT Reading from a reader for an empty stream will wait until a chunk is available Test timed out
     12PASS Reading from a reader for an empty stream will wait until a chunk is available
    1313FAIL cancel() on a reader releases the reader before calling through cancel is not implemented
    1414PASS closed should be fulfilled after stream is closed (.closed access before acquiring)
  • trunk/LayoutTests/streams/reference-implementation/readable-stream-reader.html

    r185114 r185197  
    108108}, 'Constructing a ReadableStreamReader directly should be OK if the stream is errored');
    109109
    110 var test1 = async_test('Reading from a reader for an empty stream will wait until a chunk is available', { timeout: 50 });
     110var test1 = async_test('Reading from a reader for an empty stream will wait until a chunk is available');
    111111test1.step(function() {
    112112    var controller;
  • trunk/LayoutTests/streams/reference-implementation/readable-stream-templated-expected.txt

    r185114 r185197  
    3131PASS should be able to acquire multiple readers, since they are all auto-released
    3232PASS Running templatedRSTwoChunksOpenReader with ReadableStream (two chunks enqueued, still open) reader
    33 TIMEOUT calling read() twice without waiting will eventually give both chunks Test timed out
    34 TIMEOUT calling read() twice with waiting will eventually give both chunks Test timed out
     33PASS calling read() twice without waiting will eventually give both chunks
     34PASS calling read() twice with waiting will eventually give both chunks
    3535PASS read() should return distinct promises each time
    3636FAIL cancel() after a read() should still give that single read result cancel is not implemented
    3737PASS Running templatedRSTwoChunksClosedReader with ReadableStream (two chunks enqueued, then closed) reader
    38 FAIL third read(), without waiting, should give { value: undefined, done: true } assert_object_equals: first result should be correct property "done" expected object "[object Object]" got object "[object Object]"
    39 FAIL third read, with waiting, should give { value: undefined, done: true } assert_object_equals: first result should be correct property "done" expected object "[object Object]" got object "[object Object]"
     38PASS third read(), without waiting, should give { value: undefined, done: true }
     39PASS third read, with waiting, should give { value: undefined, done: true }
    4040PASS draining the stream via read() should cause the reader closed promise to fulfill
    4141FAIL releasing the lock after the stream is closed should do nothing releaseLock is not implemented
  • trunk/LayoutTests/streams/reference-implementation/readable-stream-templated.html

    r185114 r185197  
    370370    }, 'Running templatedRSTwoChunksOpenReader with ' + label);
    371371
    372     var test1 = async_test('calling read() twice without waiting will eventually give both chunks', { timeout: 50 });
     372    var test1 = async_test('calling read() twice without waiting will eventually give both chunks');
    373373    test1.step(function() {
    374374        var { reader } = factory();
  • trunk/LayoutTests/streams/reference-implementation/readable-stream.html

    r185114 r185197  
    369369// });
    370370
    371 var test11 = async_test('ReadableStream: should not call pull until the previous pull call\'s promise fulfills', { timeout: 50 });
     371var test11 = async_test('ReadableStream: should not call pull until the previous pull call\'s promise fulfills');
    372372test11.step(function() {
    373373    var resolve;
     
    566566}, 'ReadableStream: enqueue should throw the stored error when the stream is errored');
    567567
    568 var test16 = async_test('ReadableStream: should call underlying source methods as methods', { timeout: 50 });
     568var test16 = async_test('ReadableStream: should call underlying source methods as methods');
    569569test16.step(function() {
    570570    var startCalled = 0;
  • trunk/Source/WebCore/ChangeLog

    r185196 r185197  
     12015-06-04  Xabier Rodriguez Calvar  <calvaris@igalia.com> and Youenn Fablet <youenn.fablet@crf.canon.fr>
     2
     3        [Streams API] Implement ReadableStreamController enqueue
     4        https://bugs.webkit.org/show_bug.cgi?id=145210
     5
     6        Reviewed by Darin Adler.
     7
     8        Added possibility to enqueue any JSValue within ReadableJSStream.
     9        They are stored in a Vector of strongified JSValue.
     10
     11        Added support for streams that contain data but are asked to close.
     12        This is done through m_closeRequested boolean and splitting actual closing of the stream from changeStateToClosed().
     13
     14        Chunk size and backpressure mechanism is not yet implemented.
     15        Neither is pulling once enqueued data is processed.
     16
     17        Covered by rebased tests.
     18
     19        * Modules/streams/ReadableStream.cpp:
     20        (WebCore::ReadableStream::changeStateToClosed): Split method with newly added close().
     21        (WebCore::ReadableStream::close): Does the actual closing of stream once stream has no more values.
     22        (WebCore::ReadableStream::read): Close the stream when stream is emptied and close is requested.
     23        (WebCore::ReadableStream::resolveReadCallback): Added to enable ReadableJSStream to resolve read callbacks immediatly at enqueue time.
     24        * Modules/streams/ReadableStream.h:
     25        (WebCore::ReadableStream::isErrored): Getter added for the custom binding code.
     26        (WebCore::ReadableStream::isCloseRequested): Ditto.
     27        * bindings/js/JSReadableStreamControllerCustom.cpp:
     28        (WebCore::JSReadableStreamController::enqueue): binding code for enqueue, taking care of raising exception if readable stream cannot enqueue.
     29        * bindings/js/ReadableJSStream.cpp:
     30        (WebCore::ReadableJSStream::hasValue):
     31        (WebCore::ReadableJSStream::read):
     32        (WebCore::ReadableJSStream::enqueue):
     33        * bindings/js/ReadableJSStream.h:
     34
    1352015-06-04  Xabier Rodriguez Calvar  <calvaris@igalia.com> and Youenn Fablet <youenn.fablet@crf.canon.fr>
    236
  • trunk/Source/WebCore/Modules/streams/ReadableStream.cpp

    r185196 r185197  
    6868void ReadableStream::changeStateToClosed()
    6969{
    70     if (m_state != State::Readable)
     70    ASSERT(!m_closeRequested);
     71    ASSERT(m_state != State::Errored);
     72
     73    m_closeRequested = true;
     74
     75    if (m_state != State::Readable || hasValue())
    7176        return;
     77    close();
     78}
     79
     80void ReadableStream::close()
     81{
    7282    m_state = State::Closed;
    7383
     
    145155    if (hasValue()) {
    146156        successCallback(read());
     157        if (m_closeRequested && !hasValue())
     158            close();
    147159        return;
    148160    }
    149161    m_readRequests.append({ WTF::move(successCallback), WTF::move(endCallback), WTF::move(failureCallback) });
    150162    // FIXME: We should try to pull.
     163}
     164
     165bool ReadableStream::resolveReadCallback(JSC::JSValue value)
     166{
     167    if (m_readRequests.isEmpty())
     168        return false;
     169
     170    m_readRequests.first().successCallback(value);
     171    m_readRequests.remove(0);
     172    return true;
    151173}
    152174
  • trunk/Source/WebCore/Modules/streams/ReadableStream.h

    r185196 r185197  
    6767    bool isLocked() const { return !!m_reader; }
    6868
     69    bool isErrored() const { return m_state == State::Errored; }
    6970    bool isReadable() const { return m_state == State::Readable; }
     71    bool isCloseRequested() const { return m_closeRequested; }
    7072
    7173    virtual JSC::JSValue error() = 0;
     
    8789    explicit ReadableStream(ScriptExecutionContext&);
    8890
     91    bool resolveReadCallback(JSC::JSValue);
     92
    8993private:
    9094    // ActiveDOMObject API.
     
    9397
    9498    void clearCallbacks();
     99    void close();
    95100
    96101    virtual bool hasValue() const = 0;
     
    110115    Vector<ReadCallbacks> m_readRequests;
    111116
     117    bool m_closeRequested { false };
    112118    State m_state { State::Readable };
    113119};
  • trunk/Source/WebCore/bindings/js/JSReadableStreamControllerCustom.cpp

    r185039 r185197  
    3434
    3535#include "JSDOMBinding.h"
    36 #include "NotImplemented.h"
    3736#include "ReadableJSStream.h"
    3837#include <runtime/Error.h>
     
    5251}
    5352
    54 JSValue JSReadableStreamController::enqueue(ExecState*)
     53JSValue JSReadableStreamController::enqueue(ExecState* exec)
    5554{
    56     notImplemented();
    57     return jsBoolean(false);
     55    ReadableJSStream& stream = impl().stream();
     56    if (stream.isErrored())
     57        return exec->vm().throwException(exec, stream.error());
     58    if (stream.isCloseRequested())
     59        return exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Calling enqueue on a stream which is closing")));
     60    stream.enqueue(*exec);
     61    return jsUndefined();
    5862}
    5963
  • trunk/Source/WebCore/bindings/js/ReadableJSStream.cpp

    r185196 r185197  
    136136bool ReadableJSStream::hasValue() const
    137137{
    138     notImplemented();
    139     return false;
     138    return m_chunkQueue.size();
    140139}
    141140
    142141JSValue ReadableJSStream::read()
    143142{
    144     notImplemented();
    145     return jsUndefined();
     143    ASSERT(hasValue());
     144
     145    return m_chunkQueue.takeFirst().get();
     146}
     147
     148void ReadableJSStream::enqueue(ExecState& exec)
     149{
     150    ASSERT(!isCloseRequested());
     151
     152    if (!isReadable())
     153        return;
     154
     155    JSValue chunk = exec.argumentCount() ? exec.argument(0) : jsUndefined();
     156    if (resolveReadCallback(chunk))
     157        return;
     158
     159    m_chunkQueue.append(JSC::Strong<JSC::Unknown>(exec.vm(), chunk));
     160    // FIXME: Compute chunk size.
     161    // FIXME: Add pulling of data here and also when data is passed to resolve callback.
    146162}
    147163
  • trunk/Source/WebCore/bindings/js/ReadableJSStream.h

    r185196 r185197  
    3838#include <runtime/JSCJSValue.h>
    3939#include <runtime/PrivateName.h>
     40#include <wtf/Deque.h>
    4041#include <wtf/Ref.h>
    4142
     
    5455    JSC::JSValue error() { return m_error.get(); }
    5556
     57    void enqueue(JSC::ExecState&);
     58
    5659private:
    5760    ReadableJSStream(ScriptExecutionContext&, JSC::ExecState&, JSC::JSObject*);
     
    6770    JSC::Strong<JSC::Unknown> m_error;
    6871    JSC::Strong<JSC::JSObject> m_source;
     72    Deque<JSC::Strong<JSC::Unknown>> m_chunkQueue;
    6973};
    7074
Note: See TracChangeset for help on using the changeset viewer.