Bug 148039

Summary: Accessing HTMLCollection.length is slow
Product: WebKit Reporter: Chris Dumez <cdumez>
Component: BindingsAssignee: Chris Dumez <cdumez>
Status: RESOLVED FIXED    
Severity: Normal CC: barraclough, ggaren, rniwa
Priority: P2    
Version: 528+ (Nightly build)   
Hardware: Unspecified   
OS: Unspecified   
See Also: https://bugs.webkit.org/show_bug.cgi?id=148092
https://bugs.webkit.org/show_bug.cgi?id=153599
Bug Depends on: 148043    
Bug Blocks: 110611, 147980    
Attachments:
Description Flags
Patch
none
Patch none

Description Chris Dumez 2015-08-14 13:49:56 PDT
Accessing HTMLCollection.length is slow. It is especially much slower than accessing NodeList.length.
Comment 1 Chris Dumez 2015-08-14 15:25:22 PDT
The issue is in our GetOwnPropertySlot. Currently, it does:
1. Check if property name is in our prototype
2. Check static properties (getStaticValueSlotEntryWithoutCaching())
3. Indexed getter
4. Named getter
5. Check own and static properties (getStaticValueSlot())

Performance-wise, the prototype check (1) is costly and is done every time we access HTMLCollection.length or HTMLCollection[i].

Based on the Web IDL specification [a][b][c] for indexed / named getters. It looks like the order ought to be:
1. Indexed Getter
2. Check own and static properties
3. Check if property name is in our prototype
4. Named getter

Besides following the specification, this has the benefit of bypassing the prototype check when accessing HTMLCollection.length or HTMLCollection[i].

On a side note, the HTMLCollection GetOwnPropertySlot is marked as impure, which means we won't cache what is returned by GetOwnPropertySlot, including accesses to the 'length' property.

[a] https://heycam.github.io/webidl/#named-properties-object-getownproperty
[b] https://heycam.github.io/webidl/#dfn-named-property-visibility
[c] https://heycam.github.io/webidl/#getownproperty-guts
Comment 2 Chris Dumez 2015-08-14 20:44:36 PDT
Created attachment 259078 [details]
Patch
Comment 3 Ryosuke Niwa 2015-08-14 22:55:23 PDT
Comment on attachment 259078 [details]
Patch

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

> Source/WebCore/ChangeLog:39
> +        Note that this patch takes the minimal approach to get the performance win
> +        while limiting the risk of breakage. Indeed, the current behavior still
> +        does not match the WebIDL specification, which seems to indicate the order
> +        should be:

Why don't we just match the spec instead assuming other browsers follow it?
I don't think named properties masking prototype properties is ever useful.

We can revert back to this behavior if we find websites that's not compatible wit the spec.
Comment 4 Chris Dumez 2015-08-15 08:19:21 PDT
(In reply to comment #3)
> Comment on attachment 259078 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=259078&action=review
> 
> > Source/WebCore/ChangeLog:39
> > +        Note that this patch takes the minimal approach to get the performance win
> > +        while limiting the risk of breakage. Indeed, the current behavior still
> > +        does not match the WebIDL specification, which seems to indicate the order
> > +        should be:
> 
> Why don't we just match the spec instead assuming other browsers follow it?
> I don't think named properties masking prototype properties is ever useful.
> 
> We can revert back to this behavior if we find websites that's not
> compatible wit the spec.

Oh, I intend to match the spec but I am doing it incrementally because it is going to be a larger change. One issue for example is that getStaticValueSlot() does more than looking for own properties. If it doesn't find any, it calls the Base class's getOwnPropertySlot(). In the case of HTMLFormControlCollection, calling getStaticValueSlot() before the named getter means the parent's named getter (HTMLCollection) takes priority over HTMLFormControlCollection's named getter. This is an issue because the named getter is supposed to return a NodeList but HTMLCollection's named getter returns a single Element.
Comment 5 Ryosuke Niwa 2015-08-15 09:12:32 PDT
Comment on attachment 259078 [details]
Patch

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

r=me.

> Source/WebCore/bindings/scripts/CodeGeneratorJS.pm:-404
> -    if (!$interface->extendedAttributes->{"CustomNamedGetter"} and InstanceAttributeCount($interface) > 0) {
> -        &$manualLookupGetterGeneration();
> -    }
> -

Oh, I see. You're changing the behavior of all classes with named properties.
I guess this is risky enough that it warrants its own patch.

Perhaps you want to mention that in the change log.
Your change log entry made it sound like it would only affect HTMLCollection.

> LayoutTests/ChangeLog:10
> +        Add new layout test covering the expected behavior of HTMLCollection's

Can we also add a test for other classes with named properties?
It can be a separate patch but given we're modifying their behaviors, it's good to test them.

> LayoutTests/fast/dom/htmlcollection-getownproperty-expected.txt:9
> +* Named properties should not mask static properties on HTMLCollection

Can we add a blank line between these test cases?
Comment 6 Chris Dumez 2015-08-17 09:41:03 PDT
Comment on attachment 259078 [details]
Patch

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

>> Source/WebCore/bindings/scripts/CodeGeneratorJS.pm:-404
>> -
> 
> Oh, I see. You're changing the behavior of all classes with named properties.
> I guess this is risky enough that it warrants its own patch.
> 
> Perhaps you want to mention that in the change log.
> Your change log entry made it sound like it would only affect HTMLCollection.

The web-exposed behavior change only impacts NamedNodeMap and HTML*Collection at the moment. This manualLookupGetterGeneration() code is merely moved after the indexed getter for performance reasons.
Comment 7 Chris Dumez 2015-08-17 09:42:58 PDT
Created attachment 259155 [details]
Patch
Comment 8 Chris Dumez 2015-08-17 09:46:45 PDT
Comment on attachment 259155 [details]
Patch

Clearing flags on attachment: 259155

Committed r188523: <http://trac.webkit.org/changeset/188523>
Comment 9 Chris Dumez 2015-08-17 09:46:52 PDT
All reviewed patches have been landed.  Closing bug.