Bug 164056 - BufferSource should behave as an union
Summary: BufferSource should behave as an union
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: New Bugs (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Zan Dobersek
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-10-27 03:09 PDT by Zan Dobersek
Modified: 2016-10-27 13:39 PDT (History)
5 users (show)

See Also:


Attachments
Patch (6.56 KB, patch)
2016-10-27 03:18 PDT, Zan Dobersek
no flags Details | Formatted Diff | Diff
Patch (5.83 KB, patch)
2016-10-27 10:15 PDT, Zan Dobersek
no flags Details | Formatted Diff | Diff
Patch for landing (5.71 KB, patch)
2016-10-27 10:29 PDT, Zan Dobersek
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Zan Dobersek 2016-10-27 03:09:53 PDT
BufferSource should behave as an union
Comment 1 Zan Dobersek 2016-10-27 03:18:43 PDT
Created attachment 293006 [details]
Patch
Comment 2 Zan Dobersek 2016-10-27 03:23:56 PDT
This was 'inspired' by an equivalent typedef and the underlying code for BufferDataSource in WebGLRenderingContextBase.
Comment 3 youenn fablet 2016-10-27 04:50:35 PDT
Comment on attachment 293006 [details]
Patch

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

> Source/WebCore/bindings/js/BufferSource.h:51
> +        brigand::for_each<Sequence>([&](auto&& type) {

First time I encounter brigand for_each.
What is the advantage compared to directly using holds_alternative?

> Source/WebCore/bindings/js/BufferSource.h:81
> +    WTF::Variant<RefPtr<JSC::ArrayBufferView>, RefPtr<JSC::ArrayBuffer>> m_variant;

There is a change of behavior here: BufferSource is refing the underlying array.
This ensures the data is not collected as long as BufferSource is there.
But I guess this does some additional count churning.

Are there use-cases where this refing is useful?
Comment 4 Zan Dobersek 2016-10-27 06:11:03 PDT
Comment on attachment 293006 [details]
Patch

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

>> Source/WebCore/bindings/js/BufferSource.h:51
>> +        brigand::for_each<Sequence>([&](auto&& type) {
> 
> First time I encounter brigand for_each.
> What is the advantage compared to directly using holds_alternative?

It's used in JSConverter::convert() when converting WTF::Variant<> to JSValue. holds_alternative would probably work better here.

>> Source/WebCore/bindings/js/BufferSource.h:81
>> +    WTF::Variant<RefPtr<JSC::ArrayBufferView>, RefPtr<JSC::ArrayBuffer>> m_variant;
> 
> There is a change of behavior here: BufferSource is refing the underlying array.
> This ensures the data is not collected as long as BufferSource is there.
> But I guess this does some additional count churning.
> 
> Are there use-cases where this refing is useful?

This mirrors the behavior of BufferDataSource in WebGLRenderingContextBase, but I understand the concern.

Regarding the use-case -- I hit the limit of the previous implementation when trying to get the iterable<BufferSource, enum MediaKeyStatus> property on the EME's MediaKeyStatusMap interface to work. That would mean converting BufferSource objects (created by the implementation) from the native types to JSValues. I suppose the simplest way to support this use-case would be to simply offload the RefPtr<ArrayBuffer> object management straight into the BufferSource class.
http://w3c.github.io/encrypted-media/#mediakeystatusmap-interface
http://w3c.github.io/encrypted-media/#update-key-statuses

But in terms of current behavior, IDLUnion ends up using RefPtr<Interface> as the implementation type for interfaces that are specified as variant alternatives, so IDLInterface or IDLType would need ArrayBuffer-specific specializations to work around that and enable using Variant<RefPtr<ArrayBufferView>, ArrayBuffer*> (which at the moment doesn't compile).
Comment 5 Chris Dumez 2016-10-27 08:54:53 PDT
Comment on attachment 293006 [details]
Patch

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

> Source/WebCore/bindings/generic/IDLTypes.h:141
> +using IDLBufferSource = IDLUnion<IDLInterface<JSC::ArrayBufferView>, IDLInterface<JSC::ArrayBuffer>>;

Why do we need an IDLBufferSource type at all? If it is a union, then it would be a typedef to a union in the IDL where this is used and we should not need an IDLBufferSource type on native side.
Comment 6 Chris Dumez 2016-10-27 08:57:08 PDT
Comment on attachment 293006 [details]
Patch

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

>> Source/WebCore/bindings/generic/IDLTypes.h:141
>> +using IDLBufferSource = IDLUnion<IDLInterface<JSC::ArrayBufferView>, IDLInterface<JSC::ArrayBuffer>>;
> 
> Why do we need an IDLBufferSource type at all? If it is a union, then it would be a typedef to a union in the IDL where this is used and we should not need an IDLBufferSource type on native side.

Oh, I see now that BufferSource is actually part of the WebIDL spec:
https://heycam.github.io/webidl/#BufferSource

I guess this is acceptable then.
Comment 7 Chris Dumez 2016-10-27 08:59:04 PDT
Comment on attachment 293006 [details]
Patch

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

>>> Source/WebCore/bindings/js/BufferSource.h:51
>>> +        brigand::for_each<Sequence>([&](auto&& type) {
>> 
>> First time I encounter brigand for_each.
>> What is the advantage compared to directly using holds_alternative?
> 
> It's used in JSConverter::convert() when converting WTF::Variant<> to JSValue. holds_alternative would probably work better here.

Would something like this work?

return WTF::visit([](auto& buffer) -> const uint8_t {
    return buffer.data();
}, variant);
Comment 8 Chris Dumez 2016-10-27 08:59:57 PDT
Comment on attachment 293006 [details]
Patch

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

> Source/WebCore/bindings/js/BufferSource.h:68
> +        brigand::for_each<Sequence>([&](auto&& type) {

Ditto here:
return WTF::visit([](auto& buffer) -> const uint8_t {
    return buffer.byteLength();
}, m_variant);
Comment 9 Chris Dumez 2016-10-27 09:01:53 PDT
Comment on attachment 293006 [details]
Patch

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

> Source/WebCore/bindings/js/BufferSource.h:40
>  class BufferSource {

Personally, I think we don't need this class at all, it should just be:
using BufferSource = WTF::Variant<RefPtr<JSC::ArrayBufferView>, RefPtr<JSC::ArrayBuffer>>;

>>> Source/WebCore/bindings/js/BufferSource.h:81
>>> +    WTF::Variant<RefPtr<JSC::ArrayBufferView>, RefPtr<JSC::ArrayBuffer>> m_variant;
>> 
>> There is a change of behavior here: BufferSource is refing the underlying array.
>> This ensures the data is not collected as long as BufferSource is there.
>> But I guess this does some additional count churning.
>> 
>> Are there use-cases where this refing is useful?
> 
> This mirrors the behavior of BufferDataSource in WebGLRenderingContextBase, but I understand the concern.
> 
> Regarding the use-case -- I hit the limit of the previous implementation when trying to get the iterable<BufferSource, enum MediaKeyStatus> property on the EME's MediaKeyStatusMap interface to work. That would mean converting BufferSource objects (created by the implementation) from the native types to JSValues. I suppose the simplest way to support this use-case would be to simply offload the RefPtr<ArrayBuffer> object management straight into the BufferSource class.
> http://w3c.github.io/encrypted-media/#mediakeystatusmap-interface
> http://w3c.github.io/encrypted-media/#update-key-statuses
> 
> But in terms of current behavior, IDLUnion ends up using RefPtr<Interface> as the implementation type for interfaces that are specified as variant alternatives, so IDLInterface or IDLType would need ArrayBuffer-specific specializations to work around that and enable using Variant<RefPtr<ArrayBufferView>, ArrayBuffer*> (which at the moment doesn't compile).

Yes, we currently translate unions of wrapper types into a WTF::Variant of RefPtrs. I think this is fine.
Comment 10 youenn fablet 2016-10-27 09:13:26 PDT
> Personally, I think we don't need this class at all, it should just be:
> using BufferSource = WTF::Variant<RefPtr<JSC::ArrayBufferView>,
> RefPtr<JSC::ArrayBuffer>>;

Helper functions that hide Variant are generally more readable, I did that for FetchBody

In that particular case, we search for the same thing (a pointer and a length), so this seems useful to me.
Comment 11 Chris Dumez 2016-10-27 09:26:17 PDT
(In reply to comment #10)
> > Personally, I think we don't need this class at all, it should just be:
> > using BufferSource = WTF::Variant<RefPtr<JSC::ArrayBufferView>,
> > RefPtr<JSC::ArrayBuffer>>;
> 
> Helper functions that hide Variant are generally more readable, I did that
> for FetchBody
> 
> In that particular case, we search for the same thing (a pointer and a
> length), so this seems useful to me.

In some cases, I would agree. In this particular instance, the code the access the data and length is 3 lines using WTF::visit() and a lambda (as I commented earlier). I think it is simple enough that we don't need the extra abstraction. That said, I don't feel that strongly.
Comment 12 Zan Dobersek 2016-10-27 10:13:18 PDT
(In reply to comment #11)
> (In reply to comment #10)
> > > Personally, I think we don't need this class at all, it should just be:
> > > using BufferSource = WTF::Variant<RefPtr<JSC::ArrayBufferView>,
> > > RefPtr<JSC::ArrayBuffer>>;
> > 
> > Helper functions that hide Variant are generally more readable, I did that
> > for FetchBody
> > 
> > In that particular case, we search for the same thing (a pointer and a
> > length), so this seems useful to me.
> 
> In some cases, I would agree. In this particular instance, the code the
> access the data and length is 3 lines using WTF::visit() and a lambda (as I
> commented earlier). I think it is simple enough that we don't need the extra
> abstraction. That said, I don't feel that strongly.

I understand this reasoning, and I like to keep things simple, but these WTF::visit() calls to retrieve data pointer and size will spread as BufferSource gets used in more places, and they will likely differ in style from file to file.

I think a minimal abstraction over this specific variant that's easy for the compiler to inline wouldn't do harm. OTOH the variant object will have to be exposed through a getter when converting BufferSource to a JS value.

So overall I as well don't have strong preference here, but would personally prefer the abstraction.
Comment 13 Chris Dumez 2016-10-27 10:14:04 PDT
(In reply to comment #12)
> (In reply to comment #11)
> > (In reply to comment #10)
> > > > Personally, I think we don't need this class at all, it should just be:
> > > > using BufferSource = WTF::Variant<RefPtr<JSC::ArrayBufferView>,
> > > > RefPtr<JSC::ArrayBuffer>>;
> > > 
> > > Helper functions that hide Variant are generally more readable, I did that
> > > for FetchBody
> > > 
> > > In that particular case, we search for the same thing (a pointer and a
> > > length), so this seems useful to me.
> > 
> > In some cases, I would agree. In this particular instance, the code the
> > access the data and length is 3 lines using WTF::visit() and a lambda (as I
> > commented earlier). I think it is simple enough that we don't need the extra
> > abstraction. That said, I don't feel that strongly.
> 
> I understand this reasoning, and I like to keep things simple, but these
> WTF::visit() calls to retrieve data pointer and size will spread as
> BufferSource gets used in more places, and they will likely differ in style
> from file to file.
> 
> I think a minimal abstraction over this specific variant that's easy for the
> compiler to inline wouldn't do harm. OTOH the variant object will have to be
> exposed through a getter when converting BufferSource to a JS value.
> 
> So overall I as well don't have strong preference here, but would personally
> prefer the abstraction.

ok
Comment 14 Zan Dobersek 2016-10-27 10:15:14 PDT
Created attachment 293031 [details]
Patch

Keeps the abstraction-natured BufferSource class, uses WTF::visit().
Comment 15 Chris Dumez 2016-10-27 10:19:53 PDT
Comment on attachment 293031 [details]
Patch

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

seems fine, r=me with a few nits.

> Source/WebCore/bindings/js/BufferSource.h:30
> +#include <wtf/Brigand.h>

I don't think we need this anymore.

> Source/WebCore/bindings/js/BufferSource.h:31
> +#include <wtf/Optional.h>

Is  this really needed?

> Source/WebCore/bindings/js/BufferSource.h:36
> +class ArrayBuffer;

You include them at the top some I doubt we need those forward declarations.
Comment 16 Zan Dobersek 2016-10-27 10:23:04 PDT
Comment on attachment 293031 [details]
Patch

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

>> Source/WebCore/bindings/js/BufferSource.h:36
>> +class ArrayBuffer;
> 
> You include them at the top some I doubt we need those forward declarations.

My bad, forgot to remove these and the includes.

Thanks for the review.
Comment 17 Zan Dobersek 2016-10-27 10:29:49 PDT
Created attachment 293033 [details]
Patch for landing
Comment 18 WebKit Commit Bot 2016-10-27 13:11:44 PDT
Comment on attachment 293033 [details]
Patch for landing

Rejecting attachment 293033 [details] from commit-queue.

Failed to run "['/Volumes/Data/EWS/WebKit/Tools/Scripts/webkit-patch', '--status-host=webkit-queues.webkit.org', '--bot-id=webkit-cq-02', 'land-attachment', '--force-clean', '--non-interactive', '--parent-command=commit-queue', 293033, '--port=mac']" exit_code: 2 cwd: /Volumes/Data/EWS/WebKit

Last 500 characters of output:
    -> origin/master
Partial-rebuilding .git/svn/refs/remotes/origin/master/.rev_map.268f45cc-cd09-0410-ab3c-d52691b4dbfc ...
Currently at 207995 = e143a49787bbfc043c52fa0f6c63e1152d061637
r207998 = d04bf7db981cc8f6c353fd1d44c1a2d6ba616c18
r207999 = d444a846405f03e2808822bbf70064b677448721
Done rebuilding .git/svn/refs/remotes/origin/master/.rev_map.268f45cc-cd09-0410-ab3c-d52691b4dbfc
First, rewinding head to replay your work on top of it...
Fast-forwarded master to refs/remotes/origin/master.

Full output: http://webkit-queues.webkit.org/results/2387929
Comment 19 WebKit Commit Bot 2016-10-27 13:39:04 PDT
Comment on attachment 293033 [details]
Patch for landing

Clearing flags on attachment: 293033

Committed r208002: <http://trac.webkit.org/changeset/208002>
Comment 20 WebKit Commit Bot 2016-10-27 13:39:09 PDT
All reviewed patches have been landed.  Closing bug.