[webkit-dev] JS bindings: Adding EventTarget to the prototype chain

2011-06-08 Thread Dominic Cooney
[If you don't care about JSC or V8 bindings you can safely ignore
this.]

TL;DR I want to change the JavaScript bindings to put EventTarget on
the prototype chain so it is easier to work with event targets from
JavaScript. What do you think?

Here is the prototype chain for a button today:

HTMLButtonElement-HTMLElement-Element-Node-Object
(add/removeEventListener and dispatchEvent are on Node.)

Here is how I think we should make it look:

HTMLButtonElement-HTMLElement-Element-Node-EventTarget-Object
(addEventListener etc. are on EventTarget.)

Here’s why I think we should do this:

- Specs are moving towards specifying EventTarget as living on the
prototype chain. DOM Core*, Notifications, Indexed DB, SVG and XHR
already do it this way. (* Editor’s draft.)

- Frameworks that want to hook add/removeEventListener will be able to
do it in one place: on EventTarget.prototype. In WebKit today they
have to hook the prototypes of window, Node, XMLHttpRequest, etc.
individually (Because WebKit implements EventTarget as a mixin
everywhere, there are 20+ different kinds of event targets to hook if
you want to be comprehensive.) If we make this change, it gets easier
to tell if a given object is an EventTarget; just do
EventTarget.prototype.isPrototypeOf(something).

- It will modestly simplify WebKit’s IDLs and bindings. Instead of
declaring addEventListener in two dozen places in IDLs, it will be in
one place; instead of calling visitJSEventListeners in dozens of
places for JSC GC, it will be called in one place; instead of assuming
that EventTarget parameters are all Node* under the covers for V8 code
generation, we can treat EventTargets uniformly; instead of
redundantly specifying EventTarget on Document and Node inheritance
will do what you want; etc.

Will doing this break the web? I don’t think so:

Anyone who calls or hooks addEventListener, etc. will continue to
work, just their foo.addEventListener might be resolved at one level
higher up the prototype chain than it is today. To really observe the
different placement of addEventListener, etc. minutely you need to
access __proto__ and hasOwnProperty. Other browsers are already differ
from WebKit in this regard, too: For example, Firefox reports
addEventListener is an own property on *every* step in the prototype
chain of DOM objects (until Object.)

Scripts that squirrel up the prototype chain themselves will see one
more link (EventTarget’s) but it is towards the top of the chain, past
most prototypes they care about (every prototype except Object.)

I tried changing half of the EventTargets in WebKit to put EventTarget
in the prototype chain, including Node and XHR (but not window) and
used it to surf the web for a few days. I didn’t notice anything break
:)

There is also the possibility that this could hurt performance,
because accessing addEventListener, etc. will have to search more
prototypes (usually just one more.) Accessing the properties of Object
on an event target via the prototype chain will have to squirrel
through one more prototype (EventTarget’s.) So I prototyped this
change in the JSC bindings and put EventTarget in the prototype chain
of a number of event targets in WebKit, including Node. Here are the
results for Dromaeo’s dom and jslib tests:



(141811 on the left is the status quo.)

I expect the Prototype and jQuery events benchmarks are of particular
interest, and the result looks particularly bad for Prototype (~3%
slowdown). So I reran  half a dozen times,
and couldn’t produce the poor result for Prototype; on average the
prototype was 1.0% slower for Prototype and 0.5% slower for jQuery. I
think Dromaeo is too noisy for measuring something as fine as this.

So I wrote three microbenchmarks:

1. Add/remove click listener on a button.

2. Add/remove progress listener on an XHR.

3. Test property presence with 'in':

if ('dispatchEvent' in target)
 n++;
// return n outside of loop

where target is an XMLHttpRequest and n is a local var n = 0.

Here are the results. A brief note on methodology: release build
running in Mac Safari, JSC, averaging 500 samples with 1,000,000
iterations of the inner loop per sample.

1. Add/remove on button
Before (ms): min=409, median=434, mean=434.4, max=472
After (ms): min=410, median=453.5, mean=452.4, max=497 (mean is 1.04x)

2. Add/remove on XHR
Before (ms): min=286, median=298, mean=298.6, max=315
After (ms): min=287, median=300.5, mean=300.7, max=320 (mean is 1.01x)

3. 'dispatchEvent' in XHR
Before (ms): min=85, median=88, mean=87.7, max=91
After (ms): min=89, median=91, mean=91.0, max=95 (mean is 1.04x)

So this shows that, yes, this is not free, but it is low-single
digits. Since adding and removing event listeners is a relatively
infrequent operation, I think this is OK. I want to emphasize that the
change I’m proposing has no impact on native event *dispatch*, which
is obviously a lot more performance-sensitive than adding a

Re: [webkit-dev] JS bindings: Adding EventTarget to the prototype chain

2011-06-09 Thread Sam Weinig
I don't think we should do this.  EventTarget is really just an abstract 
interface, and changing its implementation globally is of limited utility.

-Sam

On Jun 8, 2011, at 5:54 PM, Dominic Cooney wrote:

> [If you don't care about JSC or V8 bindings you can safely ignore
> this.]
> 
> TL;DR I want to change the JavaScript bindings to put EventTarget on
> the prototype chain so it is easier to work with event targets from
> JavaScript. What do you think?
> 
> Here is the prototype chain for a button today:
> 
> HTMLButtonElement-HTMLElement-Element-Node-Object
> (add/removeEventListener and dispatchEvent are on Node.)
> 
> Here is how I think we should make it look:
> 
> HTMLButtonElement-HTMLElement-Element-Node-EventTarget-Object
> (addEventListener etc. are on EventTarget.)
> 
> Here’s why I think we should do this:
> 
> - Specs are moving towards specifying EventTarget as living on the
> prototype chain. DOM Core*, Notifications, Indexed DB, SVG and XHR
> already do it this way. (* Editor’s draft.)
> 
> - Frameworks that want to hook add/removeEventListener will be able to
> do it in one place: on EventTarget.prototype. In WebKit today they
> have to hook the prototypes of window, Node, XMLHttpRequest, etc.
> individually (Because WebKit implements EventTarget as a mixin
> everywhere, there are 20+ different kinds of event targets to hook if
> you want to be comprehensive.) If we make this change, it gets easier
> to tell if a given object is an EventTarget; just do
> EventTarget.prototype.isPrototypeOf(something).
> 
> - It will modestly simplify WebKit’s IDLs and bindings. Instead of
> declaring addEventListener in two dozen places in IDLs, it will be in
> one place; instead of calling visitJSEventListeners in dozens of
> places for JSC GC, it will be called in one place; instead of assuming
> that EventTarget parameters are all Node* under the covers for V8 code
> generation, we can treat EventTargets uniformly; instead of
> redundantly specifying EventTarget on Document and Node inheritance
> will do what you want; etc.
> 
> Will doing this break the web? I don’t think so:
> 
> Anyone who calls or hooks addEventListener, etc. will continue to
> work, just their foo.addEventListener might be resolved at one level
> higher up the prototype chain than it is today. To really observe the
> different placement of addEventListener, etc. minutely you need to
> access __proto__ and hasOwnProperty. Other browsers are already differ
> from WebKit in this regard, too: For example, Firefox reports
> addEventListener is an own property on *every* step in the prototype
> chain of DOM objects (until Object.)
> 
> Scripts that squirrel up the prototype chain themselves will see one
> more link (EventTarget’s) but it is towards the top of the chain, past
> most prototypes they care about (every prototype except Object.)
> 
> I tried changing half of the EventTargets in WebKit to put EventTarget
> in the prototype chain, including Node and XHR (but not window) and
> used it to surf the web for a few days. I didn’t notice anything break
> :)
> 
> There is also the possibility that this could hurt performance,
> because accessing addEventListener, etc. will have to search more
> prototypes (usually just one more.) Accessing the properties of Object
> on an event target via the prototype chain will have to squirrel
> through one more prototype (EventTarget’s.) So I prototyped this
> change in the JSC bindings and put EventTarget in the prototype chain
> of a number of event targets in WebKit, including Node. Here are the
> results for Dromaeo’s dom and jslib tests:
> 
> 
> 
> (141811 on the left is the status quo.)
> 
> I expect the Prototype and jQuery events benchmarks are of particular
> interest, and the result looks particularly bad for Prototype (~3%
> slowdown). So I reran  half a dozen times,
> and couldn’t produce the poor result for Prototype; on average the
> prototype was 1.0% slower for Prototype and 0.5% slower for jQuery. I
> think Dromaeo is too noisy for measuring something as fine as this.
> 
> So I wrote three microbenchmarks:
> 
> 1. Add/remove click listener on a button.
> 
> 2. Add/remove progress listener on an XHR.
> 
> 3. Test property presence with 'in':
> 
> if ('dispatchEvent' in target)
>  n++;
> // return n outside of loop
> 
> where target is an XMLHttpRequest and n is a local var n = 0.
> 
> Here are the results. A brief note on methodology: release build
> running in Mac Safari, JSC, averaging 500 samples with 1,000,000
> iterations of the inner loop per sample.
> 
> 1. Add/remove on button
> Before (ms): min=409, median=434, mean=434.4, max=472
> After (ms): min=410, median=453.5, mean=452.4, max=497 (mean is 1.04x)
> 
> 2. Add/remove on XHR
> Before (ms): min=286, median=298, mean=298.6, max=315
> After (ms): min=287, median=300.5, mean=300.7, max=320 (mean is 1.01x)
> 
> 3. 'dispatchEvent' in XHR
> Before (ms): min=85,

Re: [webkit-dev] JS bindings: Adding EventTarget to the prototype chain

2011-06-09 Thread Maciej Stachowiak

I don't have a personal opinion on which way is technically better myself. But 
I think the key is getting our code aligned with where standards are going, 
wether by changing he code or the standards. EventTarget in the prototype chain 
seems neither especially awesome nor especially terrible to me, it is not 
really clear to me why editor's drafts of the listed specs decided to change.

Cheers,
Maciej


On Jun 9, 2011, at 1:14 PM, Sam Weinig wrote:

> I don't think we should do this.  EventTarget is really just an abstract 
> interface, and changing its implementation globally is of limited utility.
> 
> -Sam
> 
> On Jun 8, 2011, at 5:54 PM, Dominic Cooney wrote:
> 
>> [If you don't care about JSC or V8 bindings you can safely ignore
>> this.]
>> 
>> TL;DR I want to change the JavaScript bindings to put EventTarget on
>> the prototype chain so it is easier to work with event targets from
>> JavaScript. What do you think?
>> 
>> Here is the prototype chain for a button today:
>> 
>> HTMLButtonElement-HTMLElement-Element-Node-Object
>> (add/removeEventListener and dispatchEvent are on Node.)
>> 
>> Here is how I think we should make it look:
>> 
>> HTMLButtonElement-HTMLElement-Element-Node-EventTarget-Object
>> (addEventListener etc. are on EventTarget.)
>> 
>> Here’s why I think we should do this:
>> 
>> - Specs are moving towards specifying EventTarget as living on the
>> prototype chain. DOM Core*, Notifications, Indexed DB, SVG and XHR
>> already do it this way. (* Editor’s draft.)
>> 
>> - Frameworks that want to hook add/removeEventListener will be able to
>> do it in one place: on EventTarget.prototype. In WebKit today they
>> have to hook the prototypes of window, Node, XMLHttpRequest, etc.
>> individually (Because WebKit implements EventTarget as a mixin
>> everywhere, there are 20+ different kinds of event targets to hook if
>> you want to be comprehensive.) If we make this change, it gets easier
>> to tell if a given object is an EventTarget; just do
>> EventTarget.prototype.isPrototypeOf(something).
>> 
>> - It will modestly simplify WebKit’s IDLs and bindings. Instead of
>> declaring addEventListener in two dozen places in IDLs, it will be in
>> one place; instead of calling visitJSEventListeners in dozens of
>> places for JSC GC, it will be called in one place; instead of assuming
>> that EventTarget parameters are all Node* under the covers for V8 code
>> generation, we can treat EventTargets uniformly; instead of
>> redundantly specifying EventTarget on Document and Node inheritance
>> will do what you want; etc.
>> 
>> Will doing this break the web? I don’t think so:
>> 
>> Anyone who calls or hooks addEventListener, etc. will continue to
>> work, just their foo.addEventListener might be resolved at one level
>> higher up the prototype chain than it is today. To really observe the
>> different placement of addEventListener, etc. minutely you need to
>> access __proto__ and hasOwnProperty. Other browsers are already differ
>> from WebKit in this regard, too: For example, Firefox reports
>> addEventListener is an own property on *every* step in the prototype
>> chain of DOM objects (until Object.)
>> 
>> Scripts that squirrel up the prototype chain themselves will see one
>> more link (EventTarget’s) but it is towards the top of the chain, past
>> most prototypes they care about (every prototype except Object.)
>> 
>> I tried changing half of the EventTargets in WebKit to put EventTarget
>> in the prototype chain, including Node and XHR (but not window) and
>> used it to surf the web for a few days. I didn’t notice anything break
>> :)
>> 
>> There is also the possibility that this could hurt performance,
>> because accessing addEventListener, etc. will have to search more
>> prototypes (usually just one more.) Accessing the properties of Object
>> on an event target via the prototype chain will have to squirrel
>> through one more prototype (EventTarget’s.) So I prototyped this
>> change in the JSC bindings and put EventTarget in the prototype chain
>> of a number of event targets in WebKit, including Node. Here are the
>> results for Dromaeo’s dom and jslib tests:
>> 
>> 
>> 
>> (141811 on the left is the status quo.)
>> 
>> I expect the Prototype and jQuery events benchmarks are of particular
>> interest, and the result looks particularly bad for Prototype (~3%
>> slowdown). So I reran  half a dozen times,
>> and couldn’t produce the poor result for Prototype; on average the
>> prototype was 1.0% slower for Prototype and 0.5% slower for jQuery. I
>> think Dromaeo is too noisy for measuring something as fine as this.
>> 
>> So I wrote three microbenchmarks:
>> 
>> 1. Add/remove click listener on a button.
>> 
>> 2. Add/remove progress listener on an XHR.
>> 
>> 3. Test property presence with 'in':
>> 
>> if ('dispatchEvent' in target)
>>  n++;
>> // return n outside of loop
>> 
>> where target is an XMLHttpRequest and n is 

Re: [webkit-dev] JS bindings: Adding EventTarget to the prototype chain

2011-06-09 Thread Cameron McCormack
Maciej Stachowiak:
> I don't have a personal opinion on which way is technically better
> myself. But I think the key is getting our code aligned with where
> standards are going, wether by changing he code or the standards.
> EventTarget in the prototype chain seems neither especially awesome
> nor especially terrible to me, it is not really clear to me why
> editor's drafts of the listed specs decided to change.

I remember it being discussed at the TC39 meeting in November, as part
of the general discussion we had about removing multiple inheritance
from Web IDL.  (It might not’ve been on the day that Sam was in the
room, though.)  EventTarget was brought up as the “mixin” that would
probably want to have global monkeypatching done to it the most, and a
suggestion was made to make interfaces like Node inherit from it.

We do have https://bugzilla.mozilla.org/show_bug.cgi?id=612980 to make
this change, too.

With the very-soon-to-be-rewritten Web IDL single inheritance, if we
just keep

  interface Node { ... };
  interface EventTarget { ... };
  Node implements EventTarget;

then we lose the (future) ability to do

  var ael = EventTarget.prototype.addEventListener;
  EventTarget.prototype.addEventListener = function(a, b, c) {
// do some logging
ael.call(this, a, b, c);
  };

and have it affect all EventTargets, but you would still be able to get
at Node.prototype.addEventListener (i.e., more easily than with the
currently specified mixin prototype objects).  So it’s probably not a
great loss if we didn’t go ahead with Node inheriting from EventTarget.

If there’s not a strong desire to implement this change, can someone
bring it up on www-...@w3.org?

-- 
Cameron McCormack ≝ http://mcc.id.au/
___
webkit-dev mailing list
webkit-dev@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-dev


Re: [webkit-dev] JS bindings: Adding EventTarget to the prototype chain

2011-08-05 Thread Dominic Cooney
Thread necromancy! To summarize the original post: Currently WebKit’s JS
binding implements EventTarget as a mixin—all event targets have
addEventListener, removeEventListener and dispatchEvent methods. I propose
WebKit put EventTarget on the prototype chain.

There were two basic questions in response: (1) Why? and (2) Where are the
specs going?

(1) Why? To summarize the rationale from off-list replies, spec mailing list
threads, and webapps bug threads:

Making event targets inherit from EventTarget simplifies hooking that
functionality from a single choke-point. Otherwise, the web developer has to
track down all those separate objects hook each one. Why is EventTarget
special? What about other mixins? At the TC39 meeting in November, during a
discussion about removing multiple inheritance, EventTarget was brought up
as the mixin what would probably want to have global hooking done to it the
most.

(2) Where are the specs going?

The momentum for specifying EventTarget as an interface is building. In my
original post I noted that many specs (DOM Core, Notifications, Indexed DB,
SVG, XHR) already specified EventTarget as an interface; now the specs Hixie
edits (HTML5, Web RTC, Workers, Web Sockets) and FileReader do too.

Furthermore, there’s a comment from Jonas Sicking <
http://www.w3.org/Bugs/Public/show_bug.cgi?id=12574#c3> indicating that
Firefox is going to implement EventTarget this way, and from Travis
Leithead  endorsing
implementing EventTarget this way.

Which by my rough reckoning of specs implemented by WebKit, leaves just
FileWriter and Web Audio. Both of those specs are in a funny place where
they don’t specify EventTarget at all, but are event targets in WebKit. I
will follow up with Eric Urhane and Chris Rogers about these.

As I mentioned in my original post, the performance impact of this change is
minimal. So now that the specs are lined up, are there any objections to
making this change? If not I am going to work on reworking the prototype I
used to measure performance into a proper patch.

Dominic

On Fri, Jun 10, 2011 at 7:53 AM, Maciej Stachowiak  wrote:

>
> I don't have a personal opinion on which way is technically better myself.
> But I think the key is getting our code aligned with where standards are
> going, wether by changing he code or the standards. EventTarget in the
> prototype chain seems neither especially awesome nor especially terrible to
> me, it is not really clear to me why editor's drafts of the listed specs
> decided to change.
>
> Cheers,
> Maciej
>
>
>
> On Jun 9, 2011, at 1:14 PM, Sam Weinig wrote:
>
> I don't think we should do this.  EventTarget is really just an abstract
> interface, and changing its implementation globally is of limited utility.
>
> -Sam
>
> On Jun 8, 2011, at 5:54 PM, Dominic Cooney wrote:
>
> [If you don't care about JSC or V8 bindings you can safely ignore
> this.]
>
> TL;DR I want to change the JavaScript bindings to put EventTarget on
> the prototype chain so it is easier to work with event targets from
> JavaScript. What do you think?
>
> Here is the prototype chain for a button today:
>
> HTMLButtonElement-HTMLElement-Element-Node-Object
> (add/removeEventListener and dispatchEvent are on Node.)
>
> Here is how I think we should make it look:
>
> HTMLButtonElement-HTMLElement-Element-Node-EventTarget-Object
> (addEventListener etc. are on EventTarget.)
>
> Here’s why I think we should do this:
>
> - Specs are moving towards specifying EventTarget as living on the
> prototype chain. DOM Core*, Notifications, Indexed DB, SVG and XHR
> already do it this way. (* Editor’s draft.)
>
> - Frameworks that want to hook add/removeEventListener will be able to
> do it in one place: on EventTarget.prototype. In WebKit today they
> have to hook the prototypes of window, Node, XMLHttpRequest, etc.
> individually (Because WebKit implements EventTarget as a mixin
> everywhere, there are 20+ different kinds of event targets to hook if
> you want to be comprehensive.) If we make this change, it gets easier
> to tell if a given object is an EventTarget; just do
> EventTarget.prototype.isPrototypeOf(something).
>
> - It will modestly simplify WebKit’s IDLs and bindings. Instead of
> declaring addEventListener in two dozen places in IDLs, it will be in
> one place; instead of calling visitJSEventListeners in dozens of
> places for JSC GC, it will be called in one place; instead of assuming
> that EventTarget parameters are all Node* under the covers for V8 code
> generation, we can treat EventTargets uniformly; instead of
> redundantly specifying EventTarget on Document and Node inheritance
> will do what you want; etc.
>
> Will doing this break the web? I don’t think so:
>
> Anyone who calls or hooks addEventListener, etc. will continue to
> work, just their foo.addEventListener might be resolved at one level
> higher up the prototype chain than it is today. To really observe the
> different p