2011-03-14 Anton Muhin <antonm@chromium.org>
authorantonm@chromium.org <antonm@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 15 Mar 2011 01:19:14 +0000 (01:19 +0000)
committerantonm@chromium.org <antonm@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 15 Mar 2011 01:19:14 +0000 (01:19 +0000)
        Reviewed by Adam Barth.

        [v8] Rework object group building.
        https://bugs.webkit.org/show_bug.cgi?id=55399

        Instead of going top-down (from owner to owned elements), go up---from objects
        to their group ids.  That fits better to v8's object grouping model and guarantees
        that each wrapper belongs to the single group.

        Alas, this cannot be implemented for one kind of objects---CSSProperties.

        Part of core GC algorithm and tested extensively by exisiting layout tests.

        * platform/chromium/test_expectations.txt: Temporary suppress text differences.
2011-03-14  Anton Muhin  <antonm@chromium.org>

        Reviewed by Adam Barth.

        [v8] Rework object group building.
        https://bugs.webkit.org/show_bug.cgi?id=55399

        Instead of going top-down (from owner to owned elements), go up---from objects
        to their group ids.  That fits better to v8's object grouping model and guarantees
        that each wrapper belongs to the single group.

        Alas, this cannot be implemented for one kind of objects---CSSProperties.

        Part of core GC algorithm and tested extensively by exisiting layout tests.

        * bindings/scripts/CodeGeneratorV8.pm:
        * bindings/scripts/test/V8/V8TestInterface.cpp:
        * bindings/scripts/test/V8/V8TestMediaQueryListListener.cpp:
        * bindings/scripts/test/V8/V8TestObj.cpp:
        * bindings/v8/V8GCController.cpp:
        (WebCore::calculateGroupId):
        (WebCore::calculateRootStyleSheet):
        (WebCore::GrouperVisitor::visitDOMWrapper):
        (WebCore::GrouperVisitor::applyGrouping):
        (WebCore::V8GCController::gcPrologue):
        * bindings/v8/WrapperTypeInfo.h:
        (WebCore::WrapperTypeInfo::isSubclass):
        * css/CSSRuleList.h:
        (WebCore::CSSRuleList::styleList):
        * css/StyleSheetList.h:
        (WebCore::StyleSheetList::document):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@81092 268f45cc-cd09-0410-ab3c-d52691b4dbfc

13 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/chromium/test_expectations.txt
Source/WebCore/ChangeLog
Source/WebCore/bindings/scripts/CodeGeneratorV8.pm
Source/WebCore/bindings/scripts/test/V8/V8TestInterface.cpp
Source/WebCore/bindings/scripts/test/V8/V8TestMediaQueryListListener.cpp
Source/WebCore/bindings/scripts/test/V8/V8TestObj.cpp
Source/WebCore/bindings/v8/V8GCController.cpp
Source/WebCore/bindings/v8/WrapperTypeInfo.h
Source/WebCore/css/CSSMutableStyleDeclaration.cpp
Source/WebCore/css/CSSMutableStyleDeclaration.h
Source/WebCore/css/CSSRuleList.h
Source/WebCore/css/StyleSheetList.h

index 11cf304..4715e40 100644 (file)
@@ -1,3 +1,20 @@
+2011-03-14  Anton Muhin  <antonm@chromium.org>
+
+        Reviewed by Adam Barth.
+
+        [v8] Rework object group building.
+        https://bugs.webkit.org/show_bug.cgi?id=55399
+
+        Instead of going top-down (from owner to owned elements), go up---from objects
+        to their group ids.  That fits better to v8's object grouping model and guarantees
+        that each wrapper belongs to the single group.
+
+        Alas, this cannot be implemented for one kind of objects---CSSProperties.
+
+        Part of core GC algorithm and tested extensively by exisiting layout tests.
+
+        * platform/chromium/test_expectations.txt: Temporary suppress text differences.
+
 2011-03-14  Ryosuke Niwa  <rniwa@webkit.org>
 
         Mac Leopard rebaselines for r81053 (Grabbed off of Chromium bots).
index f6eaa5d..bc482a3 100755 (executable)
@@ -3390,6 +3390,9 @@ BUGCR75632 LINUX : svg/W3C-SVG-1.1/text-text-03-b.svg = CRASH PASS
 BUGCR75639 WIN LINUX : fast/canvas/webgl/uninitialized-test.html = TIMEOUT
 BUGCR75639 MAC LEOPARD : fast/canvas/webgl/uninitialized-test.html = TIMEOUT
 
+// I (antonm) am working on proper fix for it.  Temporary suppressing text differences.
+BUGWK55399 : fast/dom/StyleSheet/gc-inline-style-cssvalues.html = TEXT
+
 // Test changed in Wk r80743, throws an exception rather than returning 'true'
 BUGCR75740 : fast/js/regexp-test-null-string.html = FAIL
 
index c05e7bc..f9a017c 100644 (file)
@@ -1,3 +1,35 @@
+2011-03-14  Anton Muhin  <antonm@chromium.org>
+
+        Reviewed by Adam Barth.
+
+        [v8] Rework object group building.
+        https://bugs.webkit.org/show_bug.cgi?id=55399
+
+        Instead of going top-down (from owner to owned elements), go up---from objects
+        to their group ids.  That fits better to v8's object grouping model and guarantees
+        that each wrapper belongs to the single group.
+
+        Alas, this cannot be implemented for one kind of objects---CSSProperties.
+
+        Part of core GC algorithm and tested extensively by exisiting layout tests.
+
+        * bindings/scripts/CodeGeneratorV8.pm:
+        * bindings/scripts/test/V8/V8TestInterface.cpp:
+        * bindings/scripts/test/V8/V8TestMediaQueryListListener.cpp:
+        * bindings/scripts/test/V8/V8TestObj.cpp:
+        * bindings/v8/V8GCController.cpp:
+        (WebCore::calculateGroupId):
+        (WebCore::calculateRootStyleSheet):
+        (WebCore::GrouperVisitor::visitDOMWrapper):
+        (WebCore::GrouperVisitor::applyGrouping):
+        (WebCore::V8GCController::gcPrologue):
+        * bindings/v8/WrapperTypeInfo.h:
+        (WebCore::WrapperTypeInfo::isSubclass):
+        * css/CSSRuleList.h:
+        (WebCore::CSSRuleList::styleList):
+        * css/StyleSheetList.h:
+        (WebCore::StyleSheetList::document):
+
 2011-03-14  Kent Tamura  <tkent@chromium.org>
 
         Reviewed by James Robinson.
index e2fe277..9d9083e 100644 (file)
@@ -1716,8 +1716,22 @@ sub GenerateImplementation
 
     my $toActive = IsActiveDomType($interfaceName) ? "${className}::toActiveDOMObject" : "0";
 
+    # Find the super descriptor.
+    my $parentClass = "";
+    my $parentClassTemplate = "";
+    foreach (@{$dataNode->parents}) {
+        my $parent = $codeGenerator->StripModule($_);
+        if ($parent eq "EventTarget") {
+            next;
+        }
+        $implIncludes{"V8${parent}.h"} = 1;
+        $parentClass = "V8" . $parent;
+        $parentClassTemplate = $parentClass . "::GetTemplate()";
+        last;
+    }
     push(@implContentDecls, "namespace WebCore {\n\n");
-    push(@implContentDecls, "WrapperTypeInfo ${className}::info = { ${className}::GetTemplate, ${className}::derefObject, ${toActive} };\n\n");   
+    my $parentClassInfo = $parentClass ? "&${parentClass}::info" : "0";
+    push(@implContentDecls, "WrapperTypeInfo ${className}::info = { ${className}::GetTemplate, ${className}::derefObject, ${toActive}, ${parentClassInfo} };\n\n");   
     push(@implContentDecls, "namespace ${interfaceName}Internal {\n\n");
     push(@implContentDecls, "template <typename T> void V8_USE(T) { }\n\n");
 
@@ -1941,15 +1955,6 @@ static v8::Persistent<v8::ObjectTemplate> ConfigureShadowObjectTemplate(v8::Pers
 END
     }
 
-    # find the super descriptor
-    my $parentClassTemplate = "";
-    foreach (@{$dataNode->parents}) {
-        my $parent = $codeGenerator->StripModule($_);
-        if ($parent eq "EventTarget") { next; }
-        $implIncludes{"V8${parent}.h"} = 1;
-        $parentClassTemplate = "V8" . $parent . "::GetTemplate()";
-        last;
-    }
     if (!$parentClassTemplate) {
         $parentClassTemplate = "v8::Persistent<v8::FunctionTemplate>()";
     }
index 4c40d98..7e59416 100644 (file)
@@ -33,7 +33,7 @@
 
 namespace WebCore {
 
-WrapperTypeInfo V8TestInterface::info = { V8TestInterface::GetTemplate, V8TestInterface::derefObject, 0 };
+WrapperTypeInfo V8TestInterface::info = { V8TestInterface::GetTemplate, V8TestInterface::derefObject, 0, 0 };
 
 namespace TestInterfaceInternal {
 
index ab9e6db..06c71c0 100644 (file)
@@ -33,7 +33,7 @@
 
 namespace WebCore {
 
-WrapperTypeInfo V8TestMediaQueryListListener::info = { V8TestMediaQueryListListener::GetTemplate, V8TestMediaQueryListListener::derefObject, 0 };
+WrapperTypeInfo V8TestMediaQueryListListener::info = { V8TestMediaQueryListListener::GetTemplate, V8TestMediaQueryListListener::derefObject, 0, 0 };
 
 namespace TestMediaQueryListListenerInternal {
 
index 4298756..49b5bbe 100644 (file)
@@ -46,7 +46,7 @@
 
 namespace WebCore {
 
-WrapperTypeInfo V8TestObj::info = { V8TestObj::GetTemplate, V8TestObj::derefObject, 0 };
+WrapperTypeInfo V8TestObj::info = { V8TestObj::GetTemplate, V8TestObj::derefObject, 0, 0 };
 
 namespace TestObjInternal {
 
index 44c0e4e..48cbf44 100644 (file)
 #include "ActiveDOMObject.h"
 #include "Attr.h"
 #include "DOMDataStore.h"
-#include "Frame.h"
+#include "DOMImplementation.h"
 #include "HTMLImageElement.h"
 #include "HTMLNames.h"
 #include "MessagePort.h"
 #include "PlatformBridge.h"
-#include "SVGElement.h"
 #include "V8Binding.h"
-#include "V8CSSCharsetRule.h"
-#include "V8CSSFontFaceRule.h"
-#include "V8CSSImportRule.h"
-#include "V8CSSMediaRule.h"
+#include "V8CSSRule.h"
 #include "V8CSSRuleList.h"
 #include "V8CSSStyleDeclaration.h"
-#include "V8CSSStyleRule.h"
-#include "V8CSSStyleSheet.h"
-#include "V8DOMMap.h"
-#include "V8HTMLLinkElement.h"
-#include "V8HTMLStyleElement.h"
+#include "V8DOMImplementation.h"
 #include "V8MessagePort.h"
-#include "V8ProcessingInstruction.h"
-#include "V8Proxy.h"
+#include "V8StyleSheet.h"
 #include "V8StyleSheetList.h"
 #include "WrapperTypeInfo.h"
 
@@ -198,136 +189,33 @@ bool operator<(const GrouperItem& a, const GrouperItem& b)
 
 typedef Vector<GrouperItem> GrouperList;
 
-void makeV8ObjectGroups(GrouperList& grouper)
+// If the node is in document, put it in the ownerDocument's object group.
+//
+// If an image element was created by JavaScript "new Image",
+// it is not in a document. However, if the load event has not
+// been fired (still onloading), it is treated as in the document.
+//
+// Otherwise, the node is put in an object group identified by the root
+// element of the tree to which it belongs.
+static uintptr_t calculateGroupId(Node* node)
 {
-    // Group by sorting by the group id.
-    std::sort(grouper.begin(), grouper.end());
-
-    // FIXME Should probably work in iterators here, but indexes were easier for my simple mind.
-    for (size_t i = 0; i < grouper.size(); ) {
-        // Seek to the next key (or the end of the list).
-        size_t nextKeyIndex = grouper.size();
-        for (size_t j = i; j < grouper.size(); ++j) {
-            if (grouper[i].groupId() != grouper[j].groupId()) {
-                nextKeyIndex = j;
-                break;
-            }
-        }
-
-        ASSERT(nextKeyIndex > i);
-
-        // We only care about a group if it has more than one object. If it only
-        // has one object, it has nothing else that needs to be kept alive.
-        if (nextKeyIndex - i <= 1) {
-            i = nextKeyIndex;
-            continue;
-        }
-
-        Vector<v8::Persistent<v8::Value> > group;
-        group.reserveCapacity(nextKeyIndex - i);
-        for (; i < nextKeyIndex; ++i) {
-            v8::Persistent<v8::Value> wrapper = grouper[i].wrapper();
-            if (!wrapper.IsEmpty())
-                group.append(wrapper);
-        }
-
-        if (group.size() > 1)
-            v8::V8::AddObjectGroup(&group[0], group.size());
-
-        ASSERT(i == nextKeyIndex);
+    if (node->inDocument() || (node->hasTagName(HTMLNames::imgTag) && !static_cast<HTMLImageElement*>(node)->haveFiredLoadEvent()))
+        return reinterpret_cast<uintptr_t>(node->document());
+
+    Node* root = node;
+    if (node->isAttributeNode()) {
+        root = static_cast<Attr*>(node)->ownerElement();
+        // If the attribute has no element, no need to put it in the group,
+        // because it'll always be a group of 1.
+        if (!root)
+            return 0;
+    } else {
+        while (Node* parent = root->parentNode())
+            root = parent;
     }
-}
-
-class NodeGrouperVisitor : public DOMWrapperMap<Node>::Visitor {
-public:
-    NodeGrouperVisitor()
-    {
-        // FIXME: grouper_.reserveCapacity(node_map.size());  ?
-    }
-
-    void visitDOMWrapper(DOMDataStore* store, Node* node, v8::Persistent<v8::Object> wrapper)
-    {
-        // If the node is in document, put it in the ownerDocument's object group.
-        //
-        // If an image element was created by JavaScript "new Image",
-        // it is not in a document. However, if the load event has not
-        // been fired (still onloading), it is treated as in the document.
-        //
-        // Otherwise, the node is put in an object group identified by the root
-        // element of the tree to which it belongs.
-        uintptr_t groupId;
-        if (node->inDocument() || (node->hasTagName(HTMLNames::imgTag) && !static_cast<HTMLImageElement*>(node)->haveFiredLoadEvent()))
-            groupId = reinterpret_cast<uintptr_t>(node->document());
-        else {
-            Node* root = node;
-            if (node->isAttributeNode()) {
-                root = static_cast<Attr*>(node)->ownerElement();
-                // If the attribute has no element, no need to put it in the group,
-                // because it'll always be a group of 1.
-                if (!root)
-                    return;
-            } else {
-                while (root->parentNode())
-                    root = root->parentNode();
-
-                // If the node is alone in its DOM tree (doesn't have a parent or any
-                // children) then the group will be filtered out later anyway.
-                if (root == node && !node->hasChildNodes() && !node->hasAttributes())
-                    return;
-            }
-            groupId = reinterpret_cast<uintptr_t>(root);
-        }
-        m_grouper.append(GrouperItem(groupId, wrapper));
 
-        // If the node is styled and there is a wrapper for the inline
-        // style declaration, we need to keep that style declaration
-        // wrapper alive as well, so we add it to the object group.
-        if (node->isStyledElement()) {
-            StyledElement* element = reinterpret_cast<StyledElement*>(node);
-            addDOMObjectToGroup(store, groupId, element->inlineStyleDecl());
-        }
-
-        if (node->isDocumentNode()) {
-            Document* document = reinterpret_cast<Document*>(node);
-            addDOMObjectToGroup(store, groupId, document->styleSheets());
-            addDOMObjectToGroup(store, groupId, document->implementation());
-        }
-
-        WrapperTypeInfo* typeInfo = V8DOMWrapper::domWrapperType(wrapper);
-
-        if (V8HTMLLinkElement::info.equals(typeInfo)) {
-            HTMLLinkElement* htmlLinkElement = static_cast<HTMLLinkElement*>(node);
-            addDOMObjectToGroup(store, groupId, htmlLinkElement->sheet());
-        }
-
-        if (V8HTMLStyleElement::info.equals(typeInfo)) {
-            HTMLStyleElement* htmlStyleElement = static_cast<HTMLStyleElement*>(node);
-            addDOMObjectToGroup(store, groupId, htmlStyleElement->sheet());
-        }
-
-        if (V8ProcessingInstruction::info.equals(typeInfo)) {
-            ProcessingInstruction* processingInstruction = static_cast<ProcessingInstruction*>(node);
-            addDOMObjectToGroup(store, groupId, processingInstruction->sheet());
-        }
-    }
-
-    void applyGrouping()
-    {
-        makeV8ObjectGroups(m_grouper);
-    }
-
-private:
-    GrouperList m_grouper;
-
-    void addDOMObjectToGroup(DOMDataStore* store, uintptr_t groupId, void* object)
-    {
-        if (!object)
-            return;
-        v8::Persistent<v8::Object> wrapper = store->domObjectMap().get(object);
-        if (!wrapper.IsEmpty())
-            m_grouper.append(GrouperItem(groupId, wrapper));
-    }
-};
+    return reinterpret_cast<uintptr_t>(root);
+}
 
 static uintptr_t calculateGroupId(StyleBase* styleBase)
 {
@@ -335,15 +223,16 @@ static uintptr_t calculateGroupId(StyleBase* styleBase)
     StyleBase* current = styleBase;
     StyleSheet* styleSheet = 0;
     while (true) {
-        // Special case: CSSStyleDeclarations should have CSSRule as a parent
-        // to proceed with parent traversal, otherwise they are coming from
-        // inlined style declaration and should be treated as a root.
+        // Special case: CSSStyleDeclarations might be either inline and in this case
+        // we need to group them with their node or regular ones.
         if (current->isMutableStyleDeclaration()) {
             CSSMutableStyleDeclaration* cssMutableStyleDeclaration = static_cast<CSSMutableStyleDeclaration*>(current);
-            if (CSSRule* parentRule = cssMutableStyleDeclaration->parentRule())
-                current = parentRule;
-            else
-                return reinterpret_cast<uintptr_t>(cssMutableStyleDeclaration);
+            if (cssMutableStyleDeclaration->isInlineStyleDeclaration()) {
+                ASSERT(cssMutableStyleDeclaration->parent()->isStyleSheet());
+                return calculateGroupId(cssMutableStyleDeclaration->node());
+            }
+            // Either we have no parent, or this parent is a CSSRule.
+            ASSERT(cssMutableStyleDeclaration->parent() == cssMutableStyleDeclaration->parentRule());
         }
 
         if (current->isStyleSheet())
@@ -355,79 +244,103 @@ static uintptr_t calculateGroupId(StyleBase* styleBase)
         current = parent;
     }
 
-    if (styleSheet)
+    if (styleSheet) {
+        if (Node* ownerNode = styleSheet->ownerNode())
+            return calculateGroupId(ownerNode);
         return reinterpret_cast<uintptr_t>(styleSheet);
+    }
 
     return reinterpret_cast<uintptr_t>(current);
 }
 
-class DOMObjectGrouperVisitor : public DOMWrapperMap<void>::Visitor {
+class GrouperVisitor : public DOMWrapperMap<Node>::Visitor, public DOMWrapperMap<void>::Visitor {
 public:
-    DOMObjectGrouperVisitor()
-    {
-    }
-
-    void startMap()
-    {
-        m_grouper.shrink(0);
-    }
-
-    void endMap()
+    void visitDOMWrapper(DOMDataStore* store, Node* node, v8::Persistent<v8::Object> wrapper)
     {
-        makeV8ObjectGroups(m_grouper);
+        uintptr_t groupId = calculateGroupId(node);
+        if (!groupId)
+            return;
+        m_grouper.append(GrouperItem(groupId, wrapper));
     }
 
     void visitDOMWrapper(DOMDataStore* store, void* object, v8::Persistent<v8::Object> wrapper)
     {
         WrapperTypeInfo* typeInfo = V8DOMWrapper::domWrapperType(wrapper);
-        // FIXME: extend WrapperTypeInfo with isStyle to simplify the check below or consider
-        // adding a virtual method to WrapperTypeInfo which would know how to group objects.
-        // FIXME: check if there are other StyleBase wrappers we should care of.
-        if (V8CSSStyleSheet::info.equals(typeInfo)
-            || V8CSSStyleDeclaration::info.equals(typeInfo)
-            || V8CSSCharsetRule::info.equals(typeInfo)
-            || V8CSSFontFaceRule::info.equals(typeInfo)
-            || V8CSSStyleRule::info.equals(typeInfo)
-            || V8CSSImportRule::info.equals(typeInfo)
-            || V8CSSMediaRule::info.equals(typeInfo)) {
-            StyleBase* styleBase = static_cast<StyleBase*>(object);
-
-            uintptr_t groupId = calculateGroupId(styleBase);
+
+        if (typeInfo->isSubclass(&V8StyleSheetList::info)) {
+            StyleSheetList* styleSheetList = static_cast<StyleSheetList*>(object);
+            uintptr_t groupId = reinterpret_cast<uintptr_t>(styleSheetList);
+            if (Document* document = styleSheetList->document())
+                groupId = reinterpret_cast<uintptr_t>(document);
+            m_grouper.append(GrouperItem(groupId, wrapper));
+
+        } else if (typeInfo->isSubclass(&V8DOMImplementation::info)) {
+            DOMImplementation* domImplementation = static_cast<DOMImplementation*>(object);
+            uintptr_t groupId = reinterpret_cast<uintptr_t>(domImplementation);
+            if (Document* document = domImplementation->ownerDocument())
+                groupId = reinterpret_cast<uintptr_t>(document);
+            m_grouper.append(GrouperItem(groupId, wrapper));
+
+        } else if (typeInfo->isSubclass(&V8StyleSheet::info) || typeInfo->isSubclass(&V8CSSRule::info)) {
+            m_grouper.append(GrouperItem(calculateGroupId(static_cast<StyleBase*>(object)), wrapper));
+
+        } else if (typeInfo->isSubclass(&V8CSSStyleDeclaration::info)) {
+            CSSStyleDeclaration* cssStyleDeclaration = static_cast<CSSStyleDeclaration*>(object);
+
+            uintptr_t groupId = calculateGroupId(cssStyleDeclaration);
+            m_grouper.append(GrouperItem(groupId, wrapper));
+
+        } else if (typeInfo->isSubclass(&V8CSSRuleList::info)) {
+            CSSRuleList* cssRuleList = static_cast<CSSRuleList*>(object);
+            uintptr_t groupId = reinterpret_cast<uintptr_t>(cssRuleList);
+            StyleList* styleList = cssRuleList->styleList();
+            if (styleList)
+                groupId = calculateGroupId(styleList);
             m_grouper.append(GrouperItem(groupId, wrapper));
+        }
+    }
 
-            if (V8CSSStyleDeclaration::info.equals(typeInfo)) {
-                CSSStyleDeclaration* cssStyleDeclaration = static_cast<CSSStyleDeclaration*>(styleBase);
-                if (cssStyleDeclaration->isMutableStyleDeclaration()) {
-                    CSSMutableStyleDeclaration* cssMutableStyleDeclaration = static_cast<CSSMutableStyleDeclaration*>(cssStyleDeclaration);
-                    CSSMutableStyleDeclaration::const_iterator end = cssMutableStyleDeclaration->end();
-                    for (CSSMutableStyleDeclaration::const_iterator it = cssMutableStyleDeclaration->begin(); it != end; ++it) {
-                        wrapper = store->domObjectMap().get(it->value());
-                        if (!wrapper.IsEmpty())
-                            m_grouper.append(GrouperItem(groupId, wrapper));
-                    }
+    void applyGrouping()
+    {
+        // Group by sorting by the group id.
+        std::sort(m_grouper.begin(), m_grouper.end());
+
+        for (size_t i = 0; i < m_grouper.size(); ) {
+            // Seek to the next key (or the end of the list).
+            size_t nextKeyIndex = m_grouper.size();
+            for (size_t j = i; j < m_grouper.size(); ++j) {
+                if (m_grouper[i].groupId() != m_grouper[j].groupId()) {
+                    nextKeyIndex = j;
+                    break;
                 }
             }
-        } else if (V8StyleSheetList::info.equals(typeInfo)) {
-            addAllItems(store, static_cast<StyleSheetList*>(object), wrapper);
-        } else if (V8CSSRuleList::info.equals(typeInfo)) {
-            addAllItems(store, static_cast<CSSRuleList*>(object), wrapper);
+
+            ASSERT(nextKeyIndex > i);
+
+            // We only care about a group if it has more than one object. If it only
+            // has one object, it has nothing else that needs to be kept alive.
+            if (nextKeyIndex - i <= 1) {
+                i = nextKeyIndex;
+                continue;
+            }
+
+            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);
+            }
+
+            if (group.size() > 1)
+                v8::V8::AddObjectGroup(&group[0], group.size());
+
+            ASSERT(i == nextKeyIndex);
         }
     }
 
 private:
     GrouperList m_grouper;
-
-    template <class C>
-    void addAllItems(DOMDataStore* store, C* collection, v8::Persistent<v8::Object> wrapper)
-    {
-        uintptr_t groupId = reinterpret_cast<uintptr_t>(collection);
-        m_grouper.append(GrouperItem(groupId, wrapper));
-        for (unsigned i = 0; i < collection->length(); i++) {
-            wrapper = store->domObjectMap().get(collection->item(i));
-            if (!wrapper.IsEmpty())
-                m_grouper.append(GrouperItem(groupId, wrapper));
-        }
-    }
 };
 
 // Create object groups for DOM tree nodes.
@@ -446,12 +359,10 @@ void V8GCController::gcPrologue()
     visitActiveDOMObjectsInCurrentThread(&prologueVisitor);
 
     // Create object groups.
-    NodeGrouperVisitor nodeGrouperVisitor;
-    visitDOMNodesInCurrentThread(&nodeGrouperVisitor);
-    nodeGrouperVisitor.applyGrouping();
-
-    DOMObjectGrouperVisitor domObjectGrouperVisitor;
-    visitDOMObjectsInCurrentThread(&domObjectGrouperVisitor);
+    GrouperVisitor grouperVisitor;
+    visitDOMNodesInCurrentThread(&grouperVisitor);
+    visitDOMObjectsInCurrentThread(&grouperVisitor);
+    grouperVisitor.applyGrouping();
 
     // Clean single element cache for string conversions.
     lastStringImpl = 0;
index 1d1cbfd..edd740f 100644 (file)
@@ -61,6 +61,16 @@ namespace WebCore {
         {
             return this == that;
         }
+
+        bool isSubclass(const WrapperTypeInfo* that) const
+        {
+            for (const WrapperTypeInfo* current = this; current; current = current->parentClass) {
+                if (current == that)
+                    return true;
+            }
+
+            return false;
+        }
         
         v8::Persistent<v8::FunctionTemplate> getTemplate() { return getTemplateFunction(); }
         
@@ -80,6 +90,7 @@ namespace WebCore {
         const GetTemplateFunction getTemplateFunction;
         const DerefObjectFunction derefObjectFunction;
         const ToActiveDOMObjectFunction toActiveDOMObjectFunction;
+        const WrapperTypeInfo* parentClass;
     };
 }
 
index 6b3207f..f3f26aa 100644 (file)
@@ -498,14 +498,18 @@ String CSSMutableStyleDeclaration::removeProperty(int propertyID, bool notifyCha
     return value;
 }
 
+bool CSSMutableStyleDeclaration::isInlineStyleDeclaration()
+{
+    // FIXME: Ideally, this should be factored better and there
+    // should be a subclass of CSSMutableStyleDeclaration just
+    // for inline style declarations that handles this
+    return m_node && m_node->isStyledElement() && static_cast<StyledElement*>(m_node)->inlineStyleDecl() == this;
+}
+
 void CSSMutableStyleDeclaration::setNeedsStyleRecalc()
 {
     if (m_node) {
-        // FIXME: Ideally, this should be factored better and there
-        // should be a subclass of CSSMutableStyleDeclaration just
-        // for inline style declarations that handles this
-        bool isInlineStyleDeclaration = m_node->isStyledElement() && this == static_cast<StyledElement*>(m_node)->inlineStyleDecl();
-        if (isInlineStyleDeclaration) {
+        if (isInlineStyleDeclaration()) {
             m_node->setNeedsStyleRecalc(InlineStyleChange);
             static_cast<StyledElement*>(m_node)->invalidateStyleAttribute();
             if (m_node->document())
index 0c3dad1..ca17f11 100644 (file)
@@ -140,6 +140,8 @@ public:
     
     bool propertiesEqual(const CSSMutableStyleDeclaration* o) const { return m_properties == o->m_properties; }
 
+    bool isInlineStyleDeclaration();
+
 protected:
     CSSMutableStyleDeclaration(CSSRule* parentRule);
 
index a355c4a..87996a9 100644 (file)
@@ -53,6 +53,11 @@ public:
     void deleteRule(unsigned index);
     void append(CSSRule*);
 
+    StyleList* styleList()
+    {
+        return m_list.get();
+    }
+
 private:
     CSSRuleList();
     CSSRuleList(StyleList*, bool omitCharsetRules);
index a486511..a019691 100644 (file)
@@ -50,6 +50,11 @@ public:
     {
         m_sheets.swap(sheets);
     }
+
+    Document* document()
+    {
+        return m_doc;
+    }
     
 private:
     StyleSheetList(Document*);