RESOLVED FIXED 55399
Rework object grouping to never produce huge grouper array
https://bugs.webkit.org/show_bug.cgi?id=55399
Summary Rework object grouping to never produce huge grouper array
anton muhin
Reported 2011-02-28 12:33:17 PST
[v8] Do not put the same handle into several groups: that can easily lead to huge array of items to be grouped
Attachments
Patch (5.75 KB, patch)
2011-02-28 12:43 PST, anton muhin
no flags
Patch (24.21 KB, patch)
2011-03-04 10:19 PST, anton muhin
no flags
Patch (24.19 KB, patch)
2011-03-05 03:55 PST, anton muhin
no flags
Patch (24.13 KB, patch)
2011-03-09 05:57 PST, anton muhin
no flags
Patch (26.93 KB, patch)
2011-03-11 11:21 PST, anton muhin
no flags
Patch (27.83 KB, patch)
2011-03-11 12:02 PST, anton muhin
no flags
anton muhin
Comment 1 2011-02-28 12:35:05 PST
anton muhin
Comment 2 2011-02-28 12:43:32 PST
anton muhin
Comment 3 2011-02-28 12:44:38 PST
Guys, I would really appreciate any algorithmic advice as well. I hope that typically we shouldn't have too many group ids (~100).
anton muhin
Comment 4 2011-03-02 07:29:30 PST
Comment on attachment 84098 [details] Patch Mads and Vitaly suggested to investigate some better approaches. So I am cancelling request for review for now.
anton muhin
Comment 5 2011-03-04 10:19:27 PST
Early Warning System Bot
Comment 6 2011-03-04 12:13:33 PST
Collabora GTK+ EWS bot
Comment 7 2011-03-04 12:57:14 PST
Darin Adler
Comment 8 2011-03-04 16:12:47 PST
Comment on attachment 84775 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=84775&action=review > Source/WebCore/css/CSSRuleList.h:56 > + PassRefPtr<StyleList> styleList() A getter that is not passing ownership should return a raw pointer, not a PassRefPtr.
WebKit Review Bot
Comment 9 2011-03-04 20:26:09 PST
anton muhin
Comment 10 2011-03-05 03:55:37 PST
anton muhin
Comment 11 2011-03-05 03:56:47 PST
(In reply to comment #8) > (From update of attachment 84775 [details]) > View in context: https://bugs.webkit.org/attachment.cgi?id=84775&action=review > > > Source/WebCore/css/CSSRuleList.h:56 > > + PassRefPtr<StyleList> styleList() > > A getter that is not passing ownership should return a raw pointer, not a PassRefPtr. Thanks a lot, Darin, fixed.
Vitaly Repeshko
Comment 12 2011-03-05 09:24:44 PST
(In reply to comment #10) > Created an attachment (id=84858) [details] > Patch Looks good. It's way clearer than what we had before. >- void startMap() >- { >- m_grouper.shrink(0); >- } >+ // Alas, CSSProperty---it's a type of items behind CSSMutableStyleDeclaration---doesn't >+ // have uplink to the parent (and thus could be potentionally shared between several >+ // declarations), so we need to iterate over them. The comment is a bit hard to parse. How about "The object group for a CSSMutableStyleDeclaration must contain all its items (CSSProperties) that have wrappers. Unfortunately, a CSSProperty object can be be shared by a few declarations and doesn't have a link to them. So we have to add the items by iterating the declaration objects." Ok, it sucks too, but please make it clearer. >+ // Group by sorting by the group id. >+ std::sort(m_grouper.begin(), m_grouper.end()); >+ >+ // FIXME Should probably work in iterators here, but indexes were easier for my simple mind. >+ for (size_t i = 0; i < m_grouper.size(); ) { I don't think we should keep this comment. >+ Vector<v8::Persistent<v8::Value> > group; >+ group.reserveCapacity(nextKeyIndex - i); >+ for (; i < nextKeyIndex; ++i) { >+ v8::Persistent<v8::Value> wrapper = m_grouper[i].wrapper(); >+ if (!wrapper.IsEmpty()) >+ group.append(wrapper); How can a wrapper be empty here? If there are valid cases when this might happen, please add a comment. Otherwise, add an assert. >+ bool isSubclass(const WrapperTypeInfo* that) const >+ { >+ >+ for (const WrapperTypeInfo* current = this; current; current = current->parentClass) >+ if (current == that) >+ return true; Style nit. The loop body is now two lines and so needs {}, doesn't it? >+ StyleList* styleList() >+ { >+ return m_list.get(); >+ } Could be a one-liner. >+ Document* document() >+ { >+ return m_doc; >+ } Ditto.
anton muhin
Comment 13 2011-03-09 05:57:00 PST
anton muhin
Comment 14 2011-03-09 06:02:33 PST
(In reply to comment #12) > (In reply to comment #10) > > Created an attachment (id=84858) [details] [details] > > Patch > > Looks good. It's way clearer than what we had before. Thanks a lot, Vitaly. Just in case, Vitaly knows a lot about v8/bindings, but cannot r+ it, so I'd appreciate another look from someone with r+ privileges. > > >- void startMap() > >- { > >- m_grouper.shrink(0); > >- } > >+ // Alas, CSSProperty---it's a type of items behind CSSMutableStyleDeclaration---doesn't > >+ // have uplink to the parent (and thus could be potentionally shared between several > >+ // declarations), so we need to iterate over them. > > The comment is a bit hard to parse. How about "The object group for a CSSMutableStyleDeclaration must contain all its items (CSSProperties) that have wrappers. Unfortunately, a CSSProperty object can be be shared by a few declarations and doesn't have a link to them. So we have to add the items by iterating the declaration objects." Ok, it sucks too, but please make it clearer. Rephrased. May you have another look? > > >+ // Group by sorting by the group id. > >+ std::sort(m_grouper.begin(), m_grouper.end()); > >+ > >+ // FIXME Should probably work in iterators here, but indexes were easier for my simple mind. > >+ for (size_t i = 0; i < m_grouper.size(); ) { > > I don't think we should keep this comment. Done. > > >+ Vector<v8::Persistent<v8::Value> > group; > >+ group.reserveCapacity(nextKeyIndex - i); > >+ for (; i < nextKeyIndex; ++i) { > >+ v8::Persistent<v8::Value> wrapper = m_grouper[i].wrapper(); > >+ if (!wrapper.IsEmpty()) > >+ group.append(wrapper); > > How can a wrapper be empty here? If there are valid cases when this might happen, please add a comment. Otherwise, add an assert. Let's keep it as is now. I'll try to turn that into assert, but don't want to do it in this patch which I'd like to bring to M11. > > >+ bool isSubclass(const WrapperTypeInfo* that) const > >+ { > >+ > >+ for (const WrapperTypeInfo* current = this; current; current = current->parentClass) > >+ if (current == that) > >+ return true; > > Style nit. The loop body is now two lines and so needs {}, doesn't it? Done, but webkit style checker is fine with both versions. > > >+ StyleList* styleList() > >+ { > >+ return m_list.get(); > >+ } > > Could be a one-liner. Yep, but I am following the style in this file (see create methods above) > > >+ Document* document() > >+ { > >+ return m_doc; > >+ } > > Ditto. Ditto, right above this method there is swap method, so I am just following the style around. But if you insist on making this one-liners, definitely I'll do that.
Vitaly Repeshko
Comment 15 2011-03-09 07:22:27 PST
(In reply to comment #14) > (In reply to comment #12) > > (In reply to comment #10) > > > Created an attachment (id=84858) [details] [details] [details] > > > Patch As bug 55899 shows sharing CSSProperties is really bad. I did a small investigation and found out that these guys are not only shared but are cached (CSSPrimitiveValueCache) and so putting a property object into a set of groups is going to retain much more than we'd like. We should switch from using objects groups for them to creating hidden dependencies. Hidden dependencies are a bit nastier because they require allocation (and also require locating the right wrapper to hold them), but OTOH they don't create a two-way strong reference.
anton muhin
Comment 16 2011-03-10 07:13:32 PST
(In reply to comment #15) > (In reply to comment #14) > > (In reply to comment #12) > > > (In reply to comment #10) > > > > Created an attachment (id=84858) [details] [details] [details] [details] > > > > Patch > > As bug 55899 shows sharing CSSProperties is really bad. I did a small investigation and found out that these guys are not only shared but are cached (CSSPrimitiveValueCache) and so putting a property object into a set of groups is going to retain much more than we'd like. We should switch from using objects groups for them to creating hidden dependencies. Hidden dependencies are a bit nastier because they require allocation (and also require locating the right wrapper to hold them), but OTOH they don't create a two-way strong reference. That's indeed a problem. And correct solution is to have one way references, but I don't think hidden refs is the right approach. I can implement necessary v8 stuff though (as we discussed yesterday) and then fix it the right way. Right now I see three ways out: 1) keep this logic and reevaluate it if we meet in the wild huge retained trees due to shared CSSPrimitiveValue, 2) slightly alter the logic and ignore not dirty wrappers (that improves our chances to survive), 3) just omit this grouping---that makes one layout test fail, but it might be bearable for time being. I am personally for 1) or 3), slightly more in favour of 1) as correctness trumps performance imho. And of course we can first wait for proper v8 extension. Thoughts?
Vitaly Repeshko
Comment 17 2011-03-10 10:14:56 PST
(In reply to comment #16) > (In reply to comment #15) > > (In reply to comment #14) > > > (In reply to comment #12) > > > > (In reply to comment #10) > > > > > Created an attachment (id=84858) [details] [details] [details] [details] [details] > > > > > Patch > > > > As bug 55899 shows sharing CSSProperties is really bad. I did a small investigation and found out that these guys are not only shared but are cached (CSSPrimitiveValueCache) and so putting a property object into a set of groups is going to retain much more than we'd like. We should switch from using objects groups for them to creating hidden dependencies. Hidden dependencies are a bit nastier because they require allocation (and also require locating the right wrapper to hold them), but OTOH they don't create a two-way strong reference. > > That's indeed a problem. And correct solution is to have one way references, but I don't think hidden refs is the right approach. I can implement necessary v8 stuff though (as we discussed yesterday) and then fix it the right way. > > Right now I see three ways out: 1) keep this logic and reevaluate it if we meet in the wild huge retained trees due to shared CSSPrimitiveValue, 2) slightly alter the logic and ignore not dirty wrappers (that improves our chances to survive), 3) just omit this grouping---that makes one layout test fail, but it might be bearable for time being. > > I am personally for 1) or 3), slightly more in favour of 1) as correctness trumps performance imho. > > And of course we can first wait for proper v8 extension. > > Thoughts? 1) and even 2) are still not entirely correct in the GC sense, because they cause us to retain too much and avoiding the issue is as non-obvious for web developers as it gets. I vote for 3). The only bad consequence is that it becomes possible to detect GC by adding custom properties to primitive values like "50px". Yet because these objects are shared in unspecified (AFAIK) ways there shouldn't be anything that relies on custom properties on these objects.
Adam Barth
Comment 18 2011-03-10 12:51:47 PST
Comment on attachment 85166 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=85166&action=review I like the approach. This stuff is very subtle, so I'm not 100% sure that this change is correct, but I don't see anything wrong with it. Some very minor style nits below. > Source/WebCore/bindings/scripts/CodeGeneratorV8.pm:1715 > + # find the super descriptor This should be a complete sentence that starts with a capital letter and ends with a period. > Source/WebCore/bindings/scripts/CodeGeneratorV8.pm:1720 > + if ($parent eq "EventTarget") { next; } Each statement should be on its own line. > Source/WebCore/bindings/v8/V8GCController.cpp:237 > + if (root->isStyleSheet()) > + if (Node* ownerNode = static_cast<StyleSheet*>(root)->ownerNode()) > + return calculateGroupId(ownerNode); We need { } around the body of this if block. > Source/WebCore/bindings/v8/V8GCController.cpp:281 > + // CSSProperty (type of items in mutable style declaration) doesn't have a pointer to > + // its parent. Therefore we cannot treat them like other objects---traverse up to the > + // root when visiting a wrapper---and need to put them into the group directly. I see. We still need to walk down for these. Ok. > Source/WebCore/bindings/v8/WrapperTypeInfo.h:67 > + This blank line is empty. > Source/WebCore/css/CSSRuleList.h:59 > + StyleList* styleList() > + { > + return m_list.get(); > + } You can just put this all on one line if you like. Simple getters can be on one line to preserve vertical space. > Source/WebCore/css/StyleSheetList.h:57 > + Document* document() > + { > + return m_doc; > + } Same here.
anton muhin
Comment 19 2011-03-11 11:21:53 PST
Adam Barth
Comment 20 2011-03-11 11:24:29 PST
Comment on attachment 85499 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=85499&action=review > Source/WebCore/bindings/v8/V8GCController.cpp:293 > +#if 0 Maybe you forgot to remove this line? > Source/WebCore/css/CSSRuleList.h:59 > + StyleList* styleList() > + { > + return m_list.get(); > + } This are still multi-line...
anton muhin
Comment 21 2011-03-11 11:27:39 PST
Adam, thanks a lot for comments. Sorry for delay---it took some time to merge it with my previous change due to differences in inline style handling. I did all you asked except for one-liners. As I explained to Vitaly before, I just try to follow the style of the corresponding files (see comment 14). And again, if you think it's time to improve style of these files, I'll do that. The main question for me right now---do we want to risk retaining huge graphs due to cached CSSPrimitiveValues? I internally put offensive code into #if 0/#endif (to be removed before submit). Vitaly think we should ignore them for now even though it'll introduce a minor bug. Minor for that was a behaviour in Safari and Chromium in all the previous versions. I think we could risk, but too concerned that OOMs due to this behaviour might be difficult to trace. So now I am starting to linger on Vitaly's side. What do you think? For other options see comment 16. (In reply to comment #18) > (From update of attachment 85166 [details]) > View in context: https://bugs.webkit.org/attachment.cgi?id=85166&action=review > > I like the approach. This stuff is very subtle, so I'm not 100% sure that this change is correct, but I don't see anything wrong with it. Some very minor style nits below. > > > Source/WebCore/bindings/scripts/CodeGeneratorV8.pm:1715 > > + # find the super descriptor > > This should be a complete sentence that starts with a capital letter and ends with a period. > > > Source/WebCore/bindings/scripts/CodeGeneratorV8.pm:1720 > > + if ($parent eq "EventTarget") { next; } > > Each statement should be on its own line. > > > Source/WebCore/bindings/v8/V8GCController.cpp:237 > > + if (root->isStyleSheet()) > > + if (Node* ownerNode = static_cast<StyleSheet*>(root)->ownerNode()) > > + return calculateGroupId(ownerNode); > > We need { } around the body of this if block. > > > Source/WebCore/bindings/v8/V8GCController.cpp:281 > > + // CSSProperty (type of items in mutable style declaration) doesn't have a pointer to > > + // its parent. Therefore we cannot treat them like other objects---traverse up to the > > + // root when visiting a wrapper---and need to put them into the group directly. > > I see. We still need to walk down for these. Ok. > > > Source/WebCore/bindings/v8/WrapperTypeInfo.h:67 > > + > > This blank line is empty. > > > Source/WebCore/css/CSSRuleList.h:59 > > + StyleList* styleList() > > + { > > + return m_list.get(); > > + } > > You can just put this all on one line if you like. Simple getters can be on one line to preserve vertical space. > > > Source/WebCore/css/StyleSheetList.h:57 > > + Document* document() > > + { > > + return m_doc; > > + } > > Same here.
anton muhin
Comment 22 2011-03-11 12:02:40 PST
anton muhin
Comment 23 2011-03-11 12:03:38 PST
As discussed with Adam on IM, uploading a version that Vitaly and me prefer, so Adam can both r+ and cq+ it if he likes it. (In reply to comment #22) > Created an attachment (id=85507) [details] > Patch
Adam Barth
Comment 24 2011-03-14 14:05:28 PDT
Comment on attachment 85507 [details] Patch I'm sold. :)
WebKit Commit Bot
Comment 25 2011-03-14 18:19:35 PDT
Comment on attachment 85507 [details] Patch Clearing flags on attachment: 85507 Committed r81092: <http://trac.webkit.org/changeset/81092>
WebKit Commit Bot
Comment 26 2011-03-14 18:19:40 PDT
All reviewed patches have been landed. Closing bug.
Note You need to log in before you can comment on or make changes to this bug.