Bug 91335 - Unify HTMLCollection and DynamicNodeList
Summary: Unify HTMLCollection and DynamicNodeList
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: DOM (show other bugs)
Version: 528+ (Nightly build)
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Ryosuke Niwa
URL:
Keywords:
Depends on: 91334 91587 91980
Blocks: 89919
  Show dependency treegraph
 
Reported: 2012-07-14 22:22 PDT by Ryosuke Niwa
Modified: 2012-07-24 05:49 PDT (History)
12 users (show)

See Also:


Attachments
Patch (50.20 KB, patch)
2012-07-14 23:15 PDT, Ryosuke Niwa
no flags Details | Formatted Diff | Diff
Archive of layout-test-results from gce-cr-linux-01 (345.04 KB, application/zip)
2012-07-15 00:21 PDT, WebKit Review Bot
no flags Details
Archive of layout-test-results from gce-cr-linux-08 (404.62 KB, application/zip)
2012-07-15 01:23 PDT, WebKit Review Bot
no flags Details
Patch (49.91 KB, patch)
2012-07-15 22:05 PDT, Ryosuke Niwa
no flags Details | Formatted Diff | Diff
Archive of layout-test-results from gce-cr-linux-07 (704.03 KB, application/zip)
2012-07-15 23:18 PDT, WebKit Review Bot
no flags Details
Patch (50.07 KB, patch)
2012-07-17 14:53 PDT, Ryosuke Niwa
no flags Details | Formatted Diff | Diff
Fixed perf. regression (51.48 KB, patch)
2012-07-18 12:58 PDT, Ryosuke Niwa
andersca: review+
Details | Formatted Diff | Diff
childNodes perf test (758 bytes, text/html)
2012-07-18 12:59 PDT, Ryosuke Niwa
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Ryosuke Niwa 2012-07-14 22:22:10 PDT
The grand unification of HTMLCollection and DynamicNodeList. In this bug, I'm going to merge item(unsigned) and length() of HTMLCollection and DynamicNodeList.
Comment 1 Ryosuke Niwa 2012-07-14 23:15:53 PDT
Created attachment 152450 [details]
Patch
Comment 2 Ryosuke Niwa 2012-07-14 23:17:41 PDT
This contains my patch for the bug 91334 as well. The patch becomes smaller once that's in.
Comment 3 WebKit Review Bot 2012-07-15 00:21:18 PDT
Comment on attachment 152450 [details]
Patch

Attachment 152450 [details] did not pass chromium-ews (chromium-xvfb):
Output: http://queues.webkit.org/results/13242627

New failing tests:
jquery/manipulation.html
Comment 4 WebKit Review Bot 2012-07-15 00:21:22 PDT
Created attachment 152453 [details]
Archive of layout-test-results from gce-cr-linux-01

The attached test failures were seen while running run-webkit-tests on the chromium-ews.
Bot: gce-cr-linux-01  Port: <class 'webkitpy.common.config.ports.ChromiumXVFBPort'>  Platform: Linux-2.6.39-gcg-201203291735-x86_64-with-Ubuntu-10.04-lucid
Comment 5 WebKit Review Bot 2012-07-15 01:23:46 PDT
Comment on attachment 152450 [details]
Patch

Attachment 152450 [details] did not pass chromium-ews (chromium-xvfb):
Output: http://queues.webkit.org/results/13243627

New failing tests:
jquery/manipulation.html
Comment 6 WebKit Review Bot 2012-07-15 01:23:50 PDT
Created attachment 152455 [details]
Archive of layout-test-results from gce-cr-linux-08

The attached test failures were seen while running run-webkit-tests on the chromium-ews.
Bot: gce-cr-linux-08  Port: <class 'webkitpy.common.config.ports.ChromiumXVFBPort'>  Platform: Linux-2.6.39-gcg-201203291735-x86_64-with-Ubuntu-10.04-lucid
Comment 7 Ojan Vafai 2012-07-15 09:50:30 PDT
Comment on attachment 152450 [details]
Patch

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

> Source/WebCore/html/HTMLCollection.cpp:302
> +    if (overridesItemAfter())
> +        return static_cast<const HTMLCollection*>(this)->virtualItemAfter(offsetInArray, toElement(previous));
> +    ASSERT(!offsetInArray);
> +    return itemBeforeOrAfter<true>(previous);

Have you seen this actually matter in benchmarks or profiles? It's a lot of complexity to add if we're not sure this matters (instead of making itemAfter always be virtual).
Comment 8 Ryosuke Niwa 2012-07-15 12:04:30 PDT
Comment on attachment 152450 [details]
Patch

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

>> Source/WebCore/html/HTMLCollection.cpp:302
>> +    return itemBeforeOrAfter<true>(previous);
> 
> Have you seen this actually matter in benchmarks or profiles? It's a lot of complexity to add if we're not sure this matters (instead of making itemAfter always be virtual).

Making itemAfter always virtual will actually add more complexity and make the code more fragile because:

1. itemAfter needs to take & return Node* now since childNodes can contain non-element nodes; however, some of subclasses that overrides itemAfter uses itemAfter themselves so we'll need to add a lot of toElement calls.

2. Before this patch, itemAfter was always virtual. However, subclasses had to tell HTMLCollection whether it supports itemBefore (only HTMLCollection itself provides one) or not. And subclasses passed in a wrong value, it still worked when HTMLCollection was traversed forwards but hit assertions when traversed backwards. After this patch, neither forwards nor backwards traversal works if it didn't give HTMLCollection the right value.
Comment 9 Ojan Vafai 2012-07-15 12:25:00 PDT
Comment on attachment 152450 [details]
Patch

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

>>> Source/WebCore/html/HTMLCollection.cpp:302
>>> +    return itemBeforeOrAfter<true>(previous);
>> 
>> Have you seen this actually matter in benchmarks or profiles? It's a lot of complexity to add if we're not sure this matters (instead of making itemAfter always be virtual).
> 
> Making itemAfter always virtual will actually add more complexity and make the code more fragile because:
> 
> 1. itemAfter needs to take & return Node* now since childNodes can contain non-element nodes; however, some of subclasses that overrides itemAfter uses itemAfter themselves so we'll need to add a lot of toElement calls.
> 
> 2. Before this patch, itemAfter was always virtual. However, subclasses had to tell HTMLCollection whether it supports itemBefore (only HTMLCollection itself provides one) or not. And subclasses passed in a wrong value, it still worked when HTMLCollection was traversed forwards but hit assertions when traversed backwards. After this patch, neither forwards nor backwards traversal works if it didn't give HTMLCollection the right value.

I see. Your ChangeLog description says that this is for performance. I think the name is confusing though. How about the following changes?
1. s/virtualItemAfter/elementAfter/
2. s/overridesItemAfter/isListOfElements/

I think that would make most of the code make more sense to me. It makes HTMLCollection::item a tad bit more confusing, but I think it's worth the clarity elsewhere in the code.

Or are there HTMLCollections that are lists of Elements and don't override itemAfter?
Comment 10 Ryosuke Niwa 2012-07-15 12:49:47 PDT
Unfortunately there are HTMLCollections that contain only elements and don't use elements array but still override itemAfter.

Maybe itemElementAfter and ProvideItemElementAfter?
Comment 11 Ryosuke Niwa 2012-07-15 22:05:06 PDT
Created attachment 152474 [details]
Patch
Comment 12 Ryosuke Niwa 2012-07-15 22:06:02 PDT
I can't reproduce jquery/manipulation.html failure on mac port or chromium mac port.
Comment 13 WebKit Review Bot 2012-07-15 23:18:11 PDT
Comment on attachment 152474 [details]
Patch

Attachment 152474 [details] did not pass chromium-ews (chromium-xvfb):
Output: http://queues.webkit.org/results/13233869

New failing tests:
jquery/manipulation.html
Comment 14 WebKit Review Bot 2012-07-15 23:18:15 PDT
Created attachment 152483 [details]
Archive of layout-test-results from gce-cr-linux-07

The attached test failures were seen while running run-webkit-tests on the chromium-ews.
Bot: gce-cr-linux-07  Port: <class 'webkitpy.common.config.ports.ChromiumXVFBPort'>  Platform: Linux-2.6.39-gcg-201203291735-x86_64-with-Ubuntu-10.04-lucid
Comment 15 Ojan Vafai 2012-07-16 18:40:20 PDT
Comment on attachment 152474 [details]
Patch

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

> Source/WebCore/html/HTMLCollection.cpp:370
> +    if (isLengthCacheValid() && !overridesItemAfter() && isLastItemCloserThanLastOrCachedItem(offset)) {

Is the plan for the rest of the collections to implement itemBefore? If so, I think that would make this code make a lot more sense to me. As it is, overridesItemAfter is serving multiple purposes and it makes the code very convoluted.
Comment 16 Ojan Vafai 2012-07-16 18:45:02 PDT
(In reply to comment #10)
> Unfortunately there are HTMLCollections that contain only elements and don't use elements array but still override itemAfter.
> 
> Maybe itemElementAfter and ProvideItemElementAfter?

I'd prefer elementAfter and ProvidesElementAfter.

Can you put elementAfter as a virtual on DynamicNodeListCacheBase and have DynamicNodeListCacheBase::itemAfter be something like:
if (Element* element = elementAfter(...))
    return element;
ASSERT(!offsetInArray);
return itemBeforeOrAfter<true>(previous);

Then you don't need ProvidesElementAfter. I understand it's adding a virtual function call, but I think we should try it and see if the performance is a problem.

I think this patch as is makes the code very confusing.
Comment 17 Ryosuke Niwa 2012-07-16 19:41:11 PDT
(In reply to comment #16)
> (In reply to comment #10)
> > Unfortunately there are HTMLCollections that contain only elements and don't use elements array but still override itemAfter.
> > 
> > Maybe itemElementAfter and ProvideItemElementAfter?
> 
> I'd prefer elementAfter and ProvidesElementAfter.

That's very cumbersome because HTMLPropertiesCollection can contain multiple items inside each element in the elementsArray.

> Can you put elementAfter as a virtual on DynamicNodeListCacheBase and have DynamicNodeListCacheBase::itemAfter be something like:
> if (Element* element = elementAfter(...))
>     return element;
> ASSERT(!offsetInArray);
> return itemBeforeOrAfter<true>(previous);
> 
> Then you don't need ProvidesElementAfter. I understand it's adding a virtual function call, but I think we should try it and see if the performance is a problem.

No, we can't afford to do that. Furthermore, that'll add one more vtable pointer because DynamicNodeList inherits from both NodeList and DynamicNodeListCacheBase. And no, DynamicNodeListCacheBase can't inherit from NodeList because HTMLCollection is not a NodeList.
Comment 18 Ryosuke Niwa 2012-07-16 19:47:31 PDT
(In reply to comment #16)
>
> Can you put elementAfter as a virtual on DynamicNodeListCacheBase and have DynamicNodeListCacheBase::itemAfter be something like:
> if (Element* element = elementAfter(...))
>     return element;
> ASSERT(!offsetInArray);
> return itemBeforeOrAfter<true>(previous);

Also, this is semantically wrong. This change would force HTMLCollections that provide elementAfter to call both elementAfter and itemBeforeOrAfter<true>(previous) when there are items left. We'll then have to either iterate DOM twice or add a special branching at the beginning of itemBeforeOrAfter, which is added complexity and unnecessary runtime cost.
Comment 19 Ryosuke Niwa 2012-07-16 20:47:24 PDT
I have the exact same patch on https://bugs.webkit.org/show_bug.cgi?id=91413 with a slight modification to jquery/manipulation.html to diagnose the issue. The cr-linux EWS passed. I have no idea what the heck is going on there. I'm just going to ignore cr-linux EWS for now.

Adam & Eric, it seems like EWS cr-linux has been very unreliable on this particular patch.
Comment 20 Ryosuke Niwa 2012-07-17 14:53:06 PDT
Created attachment 152838 [details]
Patch
Comment 21 Ryosuke Niwa 2012-07-18 12:58:28 PDT
Created attachment 153071 [details]
Fixed perf. regression
Comment 22 Ryosuke Niwa 2012-07-18 12:59:41 PDT
Created attachment 153072 [details]
childNodes perf test

Fixed the perf. regression I saw on this test. In old versions of this patch, the performance regressed as much as 100%.
Comment 23 WebKit Review Bot 2012-07-18 13:01:11 PDT
Attachment 153071 [details] did not pass style-queue:

Failed to run "['Tools/Scripts/check-webkit-style', '--diff-files', u'Source/WebCore/ChangeLog', u'Source/WebCor..." exit_code: 1
Source/WebCore/html/HTMLCollection.cpp:258:  An else statement can be removed when the prior "if" concludes with a return, break, continue or goto statement.  [readability/control_flow] [4]
Total errors found: 1 in 24 files


If any of these errors are false positives, please file a bug against check-webkit-style.
Comment 24 Ryosuke Niwa 2012-07-20 18:03:26 PDT
Committed r123281: <http://trac.webkit.org/changeset/123281>
Comment 25 Csaba Osztrogonác 2012-07-23 04:00:27 PDT
(In reply to comment #24)
> Committed r123281: <http://trac.webkit.org/changeset/123281>

It made 2 tests timeout on the perf bots. I filed a new bug report to
fix this regression: https://bugs.webkit.org/show_bug.cgi?id=91980

Could you check what happened?
Comment 26 Vsevolod Vlasov 2012-07-24 05:49:55 PDT
(In reply to comment #24)
> Committed r123281: <http://trac.webkit.org/changeset/123281>

This caused a regression: https://bugs.webkit.org/show_bug.cgi?id=92104

TL;DR 
table.childNodes[table.childNodes.length - 1] returns incorrect value.