Changeset 185537 in webkit


Ignore:
Timestamp:
Jun 13, 2015 2:09:53 AM (9 years ago)
Author:
youenn.fablet@crf.canon.fr
Message:

[Streams API] ReadableJSStream should handle promises returned by JS source start callback
https://bugs.webkit.org/show_bug.cgi?id=145792

Source/JavaScriptCore:

Reviewed by Darin Adler.

Added support for JSFunction implemented by std::function.

  • runtime/JSFunction.cpp:

(JSC::getNativeExecutable): Refactored code to share it with the two JSFunction::create
(JSC::JSFunction::create):
(JSC::runStdFunction):

  • runtime/JSFunction.h: Added std::function based JSFunction::create prototype.
  • runtime.JSPromise.h:

Source/WebCore:

Reviewed by Darin Adler.

Covered by rebased tests.

When calling start callback, the returned value is checked.
If it is not a promise, we do as if it is a resolved promise.
If it is a promise, we call its then() method with two resolve/reject JS functions.

  • Modules/streams/ReadableStream.cpp:
  • bindings/js/ReadableJSStream.cpp:

(WebCore::ReadableJSStream::invoke): Returns a JSPromise* if any is returned by the JS source callback.
(WebCore::thenPromise): Utility method to call the promise.
(WebCore::createStartResultFulfilledFunction): The promise resolve callback.
(WebCore::ReadableJSStream::doStart): Calls thenPromise if a JSPromise* is returned by invoke.
(WebCore::ReadableJSStream::ReadableJSStream):

  • bindings/js/ReadableJSStream.h:

LayoutTests:

Reviewed by Darin Adler.

Rebasing expectations, and removing timeouts for tests that no longer timeout.

  • streams/reference-implementation/readable-stream-expected.txt:
  • streams/reference-implementation/readable-stream.html:
Location:
trunk
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r185536 r185537  
     12015-06-13  Xabier Rodriguez Calvar  <calvaris@igalia.com> and Youenn Fablet <youenn.fablet@crf.canon.fr>
     2
     3        [Streams API] ReadableJSStream should handle promises returned by JS source start callback
     4        https://bugs.webkit.org/show_bug.cgi?id=145792
     5
     6        Reviewed by Darin Adler.
     7
     8        Rebasing expectations, and removing timeouts for tests that no longer timeout.
     9
     10        * streams/reference-implementation/readable-stream-expected.txt:
     11        * streams/reference-implementation/readable-stream.html:
     12
    1132015-06-13  Andres Gonzalez  <agonzalez334@nc.rr.com>
    214
  • trunk/LayoutTests/streams/reference-implementation/readable-stream-expected.txt

    r185467 r185537  
    66PASS ReadableStream constructor can get initial garbage as pull argument
    77PASS ReadableStream constructor can get initial garbage as strategy argument
    8 TIMEOUT ReadableStream start should be able to return a promise Test timed out
    9 TIMEOUT ReadableStream start should be able to return a promise and reject it Test timed out
     8PASS ReadableStream start should be able to return a promise
     9PASS ReadableStream start should be able to return a promise and reject it
    1010PASS ReadableStream should be able to enqueue different objects.
    1111PASS ReadableStream: if start throws an error, it should be re-thrown
     
    2121FAIL 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
    2222FAIL 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
    23 TIMEOUT ReadableStream integration test: adapting a random push source Test timed out
     23PASS ReadableStream integration test: adapting a random push source
    2424PASS ReadableStream integration test: adapting a sync pull source
    2525
  • trunk/LayoutTests/streams/reference-implementation/readable-stream.html

    r185467 r185537  
    5454}, 'ReadableStream constructor can get initial garbage as strategy argument');
    5555
    56 var test1 = async_test('ReadableStream start should be able to return a promise', { timeout: 50 });
     56var test1 = async_test('ReadableStream start should be able to return a promise');
    5757test1.step(function()
    5858{
     
    8383});
    8484
    85 var test2 = async_test('ReadableStream start should be able to return a promise and reject it', { timeout: 100 });
     85var test2 = async_test('ReadableStream start should be able to return a promise and reject it');
    8686test2.step(function()
    8787{
     
    659659});
    660660
    661 var test18 = async_test('ReadableStream integration test: adapting a random push source', { timeout: 50 });
     661var test18 = async_test('ReadableStream integration test: adapting a random push source');
    662662test18.step(function() {
    663663    var pullChecked = false;
  • trunk/Source/JavaScriptCore/ChangeLog

    r185532 r185537  
     12015-06-13  Youenn Fablet  <youenn.fablet@crf.canon.fr>
     2
     3        [Streams API] ReadableJSStream should handle promises returned by JS source start callback
     4        https://bugs.webkit.org/show_bug.cgi?id=145792
     5
     6        Reviewed by Darin Adler.
     7
     8        Added support for JSFunction implemented by std::function.
     9
     10        * runtime/JSFunction.cpp:
     11        (JSC::getNativeExecutable): Refactored code to share it with the two JSFunction::create
     12        (JSC::JSFunction::create):
     13        (JSC::runStdFunction):
     14        * runtime/JSFunction.h: Added std::function based JSFunction::create prototype.
     15        * runtime.JSPromise.h:
     16
    1172015-06-12  Gyuyoung Kim  <gyuyoung.kim@webkit.org>
    218
  • trunk/Source/JavaScriptCore/runtime/JSFunction.cpp

    r185467 r185537  
    55 *  Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
    66 *  Copyright (C) 2007 Maks Orlovich
     7 *  Copyright (C) 2015 Canon Inc. All rights reserved.
    78 *
    89 *  This library is free software; you can redistribute it and/or
     
    6768}
    6869
    69 JSFunction* JSFunction::create(VM& vm, JSGlobalObject* globalObject, int length, const String& name, NativeFunction nativeFunction, Intrinsic intrinsic, NativeFunction nativeConstructor)
    70 {
    71     NativeExecutable* executable;
     70static inline NativeExecutable* getNativeExecutable(VM& vm, NativeFunction nativeFunction, Intrinsic intrinsic, NativeFunction nativeConstructor)
     71{
    7272#if !ENABLE(JIT)
    7373    UNUSED_PARAM(intrinsic);
     
    7575    if (intrinsic != NoIntrinsic && vm.canUseJIT()) {
    7676        ASSERT(nativeConstructor == callHostFunctionAsConstructor);
    77         executable = vm.getHostFunction(nativeFunction, intrinsic);
    78     } else
     77        return vm.getHostFunction(nativeFunction, intrinsic);
     78    }
    7979#endif
    80         executable = vm.getHostFunction(nativeFunction, nativeConstructor);
    81 
     80    return vm.getHostFunction(nativeFunction, nativeConstructor);
     81}
     82
     83JSFunction* JSFunction::create(VM& vm, JSGlobalObject* globalObject, int length, const String& name, NativeFunction nativeFunction, Intrinsic intrinsic, NativeFunction nativeConstructor)
     84{
     85    NativeExecutable* executable = getNativeExecutable(vm, nativeFunction, intrinsic, nativeConstructor);
    8286    JSFunction* function = new (NotNull, allocateCell<JSFunction>(vm.heap)) JSFunction(vm, globalObject, globalObject->functionStructure());
     87    // Can't do this during initialization because getHostFunction might do a GC allocation.
     88    function->finishCreation(vm, executable, length, name);
     89    return function;
     90}
     91
     92class JSStdFunction : public JSFunction {
     93public:
     94    JSStdFunction(VM& vm, JSGlobalObject* object, Structure* structure, NativeStdFunction&& function)
     95        : JSFunction(vm, object, structure)
     96        , stdFunction(WTF::move(function)) { }
     97
     98    NativeStdFunction stdFunction;
     99};
     100
     101static EncodedJSValue JSC_HOST_CALL runStdFunction(ExecState* state)
     102{
     103    JSStdFunction* jsFunction = jsCast<JSStdFunction*>(state->callee());
     104    ASSERT(jsFunction);
     105    return jsFunction->stdFunction(state);
     106}
     107
     108JSFunction* JSFunction::create(VM& vm, JSGlobalObject* globalObject, int length, const String& name, NativeStdFunction&& nativeStdFunction, Intrinsic intrinsic, NativeFunction nativeConstructor)
     109{
     110    NativeExecutable* executable = getNativeExecutable(vm, runStdFunction, intrinsic, nativeConstructor);
     111    JSStdFunction* function = new (NotNull, allocateCell<JSStdFunction>(vm.heap)) JSStdFunction(vm, globalObject, globalObject->functionStructure(), WTF::move(nativeStdFunction));
    83112    // Can't do this during initialization because getHostFunction might do a GC allocation.
    84113    function->finishCreation(vm, executable, length, name);
  • trunk/Source/JavaScriptCore/runtime/JSFunction.h

    r185467 r185537  
    4646}
    4747
     48typedef std::function<EncodedJSValue (ExecState*)> NativeStdFunction;
     49
    4850JS_EXPORT_PRIVATE EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState*);
    4951
     
    6971   
    7072    static JSFunction* createWithInvalidatedReallocationWatchpoint(VM&, FunctionExecutable*, JSScope*);
     73    JS_EXPORT_PRIVATE static JSFunction* create(VM&, JSGlobalObject*, int length, const String& name, NativeStdFunction&&, Intrinsic = NoIntrinsic, NativeFunction nativeConstructor = callHostFunctionAsConstructor);
    7174
    7275    static JSFunction* create(VM&, FunctionExecutable*, JSScope*);
  • trunk/Source/JavaScriptCore/runtime/JSPromise.h

    r185467 r185537  
    4343    static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
    4444
    45     DECLARE_INFO;
     45    DECLARE_EXPORT_INFO;
    4646
    4747    enum class Status {
  • trunk/Source/WebCore/ChangeLog

    r185536 r185537  
     12015-06-13  Xabier Rodriguez Calvar  <calvaris@igalia.com> and Youenn Fablet <youenn.fablet@crf.canon.fr>
     2
     3        [Streams API] ReadableJSStream should handle promises returned by JS source start callback
     4        https://bugs.webkit.org/show_bug.cgi?id=145792
     5
     6        Reviewed by Darin Adler.
     7
     8        Covered by rebased tests.
     9
     10        When calling start callback, the returned value is checked.
     11        If it is not a promise, we do as if it is a resolved promise.
     12        If it is a promise, we call its then() method with two resolve/reject JS functions.
     13
     14        * Modules/streams/ReadableStream.cpp:
     15        * bindings/js/ReadableJSStream.cpp:
     16        (WebCore::ReadableJSStream::invoke): Returns a JSPromise* if any is returned by the JS source callback.
     17        (WebCore::thenPromise): Utility method to call the promise.
     18        (WebCore::createStartResultFulfilledFunction): The promise resolve callback.
     19        (WebCore::ReadableJSStream::doStart): Calls thenPromise if a JSPromise* is returned by invoke.
     20        (WebCore::ReadableJSStream::ReadableJSStream):
     21        * bindings/js/ReadableJSStream.h:
     22
    1232015-06-13  Andres Gonzalez  <agonzalez334@nc.rr.com>
    224
  • trunk/Source/WebCore/Modules/streams/ReadableStream.cpp

    r185467 r185537  
    3333#if ENABLE(STREAMS_API)
    3434
    35 #include "NotImplemented.h"
    3635#include "ReadableStreamReader.h"
    3736#include <runtime/JSCJSValueInlines.h>
  • trunk/Source/WebCore/bindings/js/ReadableJSStream.cpp

    r185467 r185537  
    3737#include "JSReadableStream.h"
    3838#include "JSReadableStreamController.h"
    39 #include "NotImplemented.h"
    4039#include "ScriptExecutionContext.h"
    4140#include <runtime/Error.h>
    4241#include <runtime/Exception.h>
    4342#include <runtime/JSCJSValueInlines.h>
     43#include <runtime/JSPromise.h>
    4444#include <runtime/JSString.h>
    4545#include <runtime/StructureInlines.h>
     
    6161}
    6262
    63 JSValue ReadableJSStream::invoke(ExecState& exec, const char* propertyName)
    64 {
    65     JSValue function = getPropertyFromObject(exec, m_source.get(), propertyName);
    66     if (exec.hadException())
    67         return jsUndefined();
     63JSPromise* ReadableJSStream::invoke(ExecState& state, const char* propertyName)
     64{
     65    JSValue function = getPropertyFromObject(state, m_source.get(), propertyName);
     66    if (state.hadException())
     67        return nullptr;
    6868
    6969    if (!function.isFunction()) {
    7070        if (!function.isUndefined())
    71             throwVMError(&exec, createTypeError(&exec, ASCIILiteral("ReadableStream trying to call a property that is not callable")));
    72         return jsUndefined();
     71            throwVMError(&state, createTypeError(&state, ASCIILiteral("ReadableStream trying to call a property that is not callable")));
     72        return nullptr;
    7373    }
    7474
    7575    MarkedArgumentBuffer arguments;
    76     arguments.append(jsController(exec, globalObject()));
    77     return callFunction(exec, function, m_source.get(), arguments);
     76    arguments.append(jsController(state, globalObject()));
     77
     78    JSPromise* promise = jsDynamicCast<JSPromise*>(callFunction(state, function, m_source.get(), arguments));
     79
     80    ASSERT(!(promise && state.hadException()));
     81    return promise;
     82}
     83
     84static void thenPromise(ExecState& state, JSPromise* deferredPromise, JSValue fullfilFunction, JSValue rejectFunction)
     85{
     86    JSValue thenValue = deferredPromise->get(&state, state.vm().propertyNames->then);
     87    if (state.hadException())
     88        return;
     89
     90    MarkedArgumentBuffer arguments;
     91    arguments.append(fullfilFunction);
     92    arguments.append(rejectFunction);
     93
     94    callFunction(state, thenValue, deferredPromise, arguments);
    7895}
    7996
     
    83100}
    84101
    85 static void startReadableStreamAsync(ReadableStream& readableStream)
     102static inline JSFunction* createStartResultFulfilledFunction(ExecState& state, ReadableStream& readableStream)
     103{
     104    RefPtr<ReadableStream> stream = &readableStream;
     105    return JSFunction::create(state.vm(), state.callee()->globalObject(), 1, String(), [stream](ExecState*) {
     106        stream->start();
     107        return JSValue::encode(jsUndefined());
     108    });
     109}
     110
     111static inline void startReadableStreamAsync(ReadableStream& readableStream)
    86112{
    87113    RefPtr<ReadableStream> stream = &readableStream;
     
    95121    JSLockHolder lock(&exec);
    96122
    97     invoke(exec, "start");
     123    JSPromise* promise = invoke(exec, "start");
    98124
    99125    if (exec.hadException())
    100126        return;
    101127
    102     // FIXME: Implement handling promise as result of calling start function.
    103     startReadableStreamAsync(*this);
     128    if (!promise) {
     129        startReadableStreamAsync(*this);
     130        return;
     131    }
     132
     133    thenPromise(exec, promise, createStartResultFulfilledFunction(exec, *this), m_errorFunction.get());
    104134}
    105135
     
    140170}
    141171
    142 ReadableJSStream::ReadableJSStream(ScriptExecutionContext& scriptExecutionContext, ExecState& exec, JSObject* source)
     172ReadableJSStream::ReadableJSStream(ScriptExecutionContext& scriptExecutionContext, ExecState& state, JSObject* source)
    143173    : ReadableStream(scriptExecutionContext)
    144174{
    145     m_source.set(exec.vm(), source);
     175    m_source.set(state.vm(), source);
     176    // We do not take a Ref to the stream as this would cause a Ref cycle.
     177    // The resolution callback used jointly with m_errorFunction as promise callbacks should protect the stream instead.
     178    m_errorFunction.set(state.vm(), JSFunction::create(state.vm(), state.callee()->globalObject(), 1, String(), [this](ExecState* state) {
     179        storeError(*state);
     180        return JSValue::encode(jsUndefined());
     181    }));
    146182}
    147183
  • trunk/Source/WebCore/bindings/js/ReadableJSStream.h

    r185518 r185537  
    4141#include <wtf/Ref.h>
    4242
     43namespace JSC {
     44class JSFunction;
     45class JSPromise;
     46}
     47   
    4348namespace WebCore {
    4449
     
    6267    void doStart(JSC::ExecState&);
    6368
    64     JSC::JSValue invoke(JSC::ExecState&, const char*);
     69    JSC::JSPromise* invoke(JSC::ExecState&, const char*);
    6570    void storeException(JSC::ExecState&);
    6671    void storeError(JSC::ExecState&, JSC::JSValue);
     
    7479    std::unique_ptr<ReadableStreamController> m_controller;
    7580    JSC::Strong<JSC::Unknown> m_error;
     81    JSC::Strong<JSC::JSFunction> m_errorFunction;
    7682    JSC::Strong<JSC::JSObject> m_source;
    7783    Deque<JSC::Strong<JSC::Unknown>> m_chunkQueue;
Note: See TracChangeset for help on using the changeset viewer.