Bug 215557 - Optimise resolution of promises with values in ReadableStream implementation
Summary: Optimise resolution of promises with values in ReadableStream implementation
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebCore Misc. (show other bugs)
Version: WebKit Local Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: youenn fablet
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2020-08-17 00:53 PDT by youenn fablet
Modified: 2020-08-19 08:02 PDT (History)
8 users (show)

See Also:


Attachments
Patch (10.06 KB, patch)
2020-08-17 01:00 PDT, youenn fablet
no flags Details | Formatted Diff | Diff
Patch (14.79 KB, patch)
2020-08-17 02:16 PDT, youenn fablet
no flags Details | Formatted Diff | Diff
Patch (16.78 KB, patch)
2020-08-18 02:04 PDT, youenn fablet
no flags Details | Formatted Diff | Diff
Patch for landing (17.10 KB, patch)
2020-08-19 02:20 PDT, youenn fablet
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description youenn fablet 2020-08-17 00:53:25 PDT
Optimise resolution of promises with values in ReadableStream implementation
Comment 1 youenn fablet 2020-08-17 00:53:54 PDT
<rdar://problem/66828616>
Comment 2 youenn fablet 2020-08-17 01:00:32 PDT
Created attachment 406701 [details]
Patch
Comment 3 youenn fablet 2020-08-17 02:16:36 PDT
Created attachment 406706 [details]
Patch
Comment 4 Yusuke Suzuki 2020-08-17 16:06:34 PDT
Comment on attachment 406706 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=406706&action=review

> Source/WebCore/Modules/streams/ReadableByteStreamInternals.js:577
> +    @fulfillPromise(readIntoRequest.@promise, { value: chunk, done: done });

@fulfillPromise is raw implementation detail, and it is not designed to be called directly from the non-JSC code.
If we want to use it, we need to be extra careful.
For example, even if you call it, you can still call `requests[index].@resolve` and it causes broken promise behavior.
And you cannot call @fulfillPromise multiple times on the same promise (which should cause assertion crash).
Can you use @newPromise instead of @newPromiseCapability(@Promise) and consistently use @fulfillPromise, @resolvePromise, and @rejectPromise?

> Source/WebCore/Modules/streams/ReadableStreamInternals.js:449
> +            @fulfillPromise(requests[index].@promise, { value: @undefined, done: true });

Ditto.

> Source/WebCore/Modules/streams/ReadableStreamInternals.js:460
> +    const readRequest = @getByIdDirectPrivate(@getByIdDirectPrivate(stream, "reader"), "readRequests").@shift();
> +    @fulfillPromise(readRequest.@promise, { value: chunk, done: done });

Ditto.

> Source/WebCore/Modules/streams/StreamInternals.js:196
> +function createFulfilledPromise(value)
> +{
> +    const promise = @newPromise();
> +    @fulfillPromise(promise, value);
> +    return promise;
> +}

I think this is OK since we do not create a @resolve / @reject handlers for this promise since we are creating promise via @newPromise.
Comment 5 youenn fablet 2020-08-18 02:04:45 PDT
Created attachment 406773 [details]
Patch
Comment 6 Yusuke Suzuki 2020-08-18 11:58:27 PDT
Comment on attachment 406773 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=406773&action=review

r=me

> Source/WebCore/Modules/streams/ReadableStreamInternals.js:305
>          const requests = @getByIdDirectPrivate(reader, "readRequests");
>          for (let index = 0, length = requests.length; index < length; ++index)
> -            requests[index].@reject.@call(@undefined, error);
> +            @rejectPromise(requests[index], error);
>          @putByIdDirectPrivate(reader, "readRequests", []);

I recommend doing,

const requests = @getByIdDirectPrivate(reader, "readRequests");
@putByIdDirectPrivate(reader, "readRequests", []);
for (let index = 0, length = requests.length; index < length; ++index)
    @rejectPromise(requests[index], error);

To ensure there is no reference to these promises from ReadableStream while calling @rejectPromise.

> Source/WebCore/Modules/streams/ReadableStreamInternals.js:311
>          const requests = @getByIdDirectPrivate(reader, "readIntoRequests");
>          for (let index = 0, length = requests.length; index < length; ++index)
> -            requests[index].@reject.@call(@undefined, error);
> +            @rejectPromise(requests[index], error);
>          @putByIdDirectPrivate(reader, "readIntoRequests", []);

Ditto.

> Source/WebCore/Modules/streams/ReadableStreamInternals.js:450
>          for (let index = 0, length = requests.length; index < length; ++index)
> -            requests[index].@resolve.@call(@undefined, {value:@undefined, done: true});
> +            @fulfillPromise(requests[index], { value: @undefined, done: true });
>          @putByIdDirectPrivate(reader, "readRequests", []);

Ditto.
Comment 7 youenn fablet 2020-08-19 02:20:14 PDT
Created attachment 406831 [details]
Patch for landing
Comment 8 EWS 2020-08-19 08:02:55 PDT
Committed r265854: <https://trac.webkit.org/changeset/265854>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 406831 [details].