diff options
Diffstat (limited to 'Source/WebCore/bindings/v8/V8GCController.cpp')
-rw-r--r-- | Source/WebCore/bindings/v8/V8GCController.cpp | 401 |
1 files changed, 202 insertions, 199 deletions
diff --git a/Source/WebCore/bindings/v8/V8GCController.cpp b/Source/WebCore/bindings/v8/V8GCController.cpp index cda9f3d..82c9ca4 100644 --- a/Source/WebCore/bindings/v8/V8GCController.cpp +++ b/Source/WebCore/bindings/v8/V8GCController.cpp @@ -34,27 +34,20 @@ #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 "RetainedDOMInfo.h" +#include "RetainedObjectInfo.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" @@ -175,19 +168,86 @@ public: } }; -class GrouperItem { +// Implements v8::RetainedObjectInfo. +class UnspecifiedGroup : public RetainedObjectInfo { public: - GrouperItem(uintptr_t groupId, v8::Persistent<v8::Object> wrapper) - : m_groupId(groupId) - , m_wrapper(wrapper) - { - } + explicit UnspecifiedGroup(void* object) + : m_object(object) + { + ASSERT(m_object); + } + + virtual void Dispose() { delete this; } + + virtual bool IsEquivalent(v8::RetainedObjectInfo* other) + { + ASSERT(other); + return other == this || static_cast<WebCore::RetainedObjectInfo*>(other)->GetEquivalenceClass() == this->GetEquivalenceClass(); + } + virtual intptr_t GetHash() + { + return reinterpret_cast<intptr_t>(m_object); + } + + virtual const char* GetLabel() + { + return "Object group"; + } + + virtual intptr_t GetEquivalenceClass() + { + return reinterpret_cast<intptr_t>(m_object); + } + +private: + void* m_object; +}; + +class GroupId { +public: + GroupId() : m_type(NullType), m_groupId(0) {} + GroupId(Node* node) : m_type(NodeType), m_node(node) {} + GroupId(void* other) : m_type(OtherType), m_other(other) {} + bool operator!() const { return m_type == NullType; } uintptr_t groupId() const { return m_groupId; } + RetainedObjectInfo* createRetainedObjectInfo() const + { + switch (m_type) { + case NullType: + return 0; + case NodeType: + return new RetainedDOMInfo(m_node); + case OtherType: + return new UnspecifiedGroup(m_other); + default: + return 0; + } + } + +private: + enum Type { + NullType, + NodeType, + OtherType + }; + Type m_type; + union { + uintptr_t m_groupId; + Node* m_node; + void* m_other; + }; +}; + +class GrouperItem { +public: + GrouperItem(GroupId groupId, v8::Persistent<v8::Object> wrapper) : m_groupId(groupId), m_wrapper(wrapper) {} + uintptr_t groupId() const { return m_groupId.groupId(); } + RetainedObjectInfo* createRetainedObjectInfo() const { return m_groupId.createRetainedObjectInfo(); } v8::Persistent<v8::Object> wrapper() const { return m_wrapper; } private: - uintptr_t m_groupId; + GroupId m_groupId; v8::Persistent<v8::Object> m_wrapper; }; @@ -198,215 +258,160 @@ 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 GroupId 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; - } - } + if (node->inDocument() || (node->hasTagName(HTMLNames::imgTag) && !static_cast<HTMLImageElement*>(node)->haveFiredLoadEvent())) + return GroupId(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 GroupId(); + } else { + while (Node* parent = root->parentNode()) + root = parent; + } - ASSERT(nextKeyIndex > i); + return GroupId(root); +} - // 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; +static GroupId calculateGroupId(StyleBase* styleBase) +{ + ASSERT(styleBase); + StyleBase* current = styleBase; + StyleSheet* styleSheet = 0; + while (true) { + // 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 (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()); } - 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 (current->isStyleSheet()) + styleSheet = static_cast<StyleSheet*>(current); - if (group.size() > 1) - v8::V8::AddObjectGroup(&group[0], group.size()); + StyleBase* parent = current->parent(); + if (!parent) + break; + current = parent; + } - ASSERT(i == nextKeyIndex); + if (styleSheet) { + if (Node* ownerNode = styleSheet->ownerNode()) + return calculateGroupId(ownerNode); + return GroupId(styleSheet); } + + return GroupId(current); } -class NodeGrouperVisitor : public DOMWrapperMap<Node>::Visitor { +class GrouperVisitor : public DOMWrapperMap<Node>::Visitor, public DOMWrapperMap<void>::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); - } + GroupId groupId = calculateGroupId(node); + if (!groupId) + return; 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()); - } - + void visitDOMWrapper(DOMDataStore* store, void* object, v8::Persistent<v8::Object> wrapper) + { WrapperTypeInfo* typeInfo = V8DOMWrapper::domWrapperType(wrapper); - if (V8HTMLLinkElement::info.equals(typeInfo)) { - HTMLLinkElement* htmlLinkElement = static_cast<HTMLLinkElement*>(node); - addDOMObjectToGroup(store, groupId, htmlLinkElement->sheet()); - } + if (typeInfo->isSubclass(&V8StyleSheetList::info)) { + StyleSheetList* styleSheetList = static_cast<StyleSheetList*>(object); + GroupId groupId(styleSheetList); + if (Document* document = styleSheetList->document()) + groupId = GroupId(document); + m_grouper.append(GrouperItem(groupId, wrapper)); - if (V8HTMLStyleElement::info.equals(typeInfo)) { - HTMLStyleElement* htmlStyleElement = static_cast<HTMLStyleElement*>(node); - addDOMObjectToGroup(store, groupId, htmlStyleElement->sheet()); - } + } else if (typeInfo->isSubclass(&V8DOMImplementation::info)) { + DOMImplementation* domImplementation = static_cast<DOMImplementation*>(object); + GroupId groupId(domImplementation); + if (Document* document = domImplementation->ownerDocument()) + groupId = GroupId(document); + m_grouper.append(GrouperItem(groupId, wrapper)); - if (V8ProcessingInstruction::info.equals(typeInfo)) { - ProcessingInstruction* processingInstruction = static_cast<ProcessingInstruction*>(node); - addDOMObjectToGroup(store, groupId, processingInstruction->sheet()); - } - } + } else if (typeInfo->isSubclass(&V8StyleSheet::info) || typeInfo->isSubclass(&V8CSSRule::info)) { + m_grouper.append(GrouperItem(calculateGroupId(static_cast<StyleBase*>(object)), wrapper)); - void applyGrouping() - { - makeV8ObjectGroups(m_grouper); - } - -private: - GrouperList m_grouper; + } else if (typeInfo->isSubclass(&V8CSSStyleDeclaration::info)) { + CSSStyleDeclaration* cssStyleDeclaration = static_cast<CSSStyleDeclaration*>(object); - void addDOMObjectToGroup(DOMDataStore* store, uintptr_t groupId, void* object) - { - if (!object) - return; - v8::Persistent<v8::Object> wrapper = store->domObjectMap().get(object); - if (!wrapper.IsEmpty()) + GroupId groupId = calculateGroupId(cssStyleDeclaration); m_grouper.append(GrouperItem(groupId, wrapper)); - } -}; -class DOMObjectGrouperVisitor : public DOMWrapperMap<void>::Visitor { -public: - DOMObjectGrouperVisitor() - { + } else if (typeInfo->isSubclass(&V8CSSRuleList::info)) { + CSSRuleList* cssRuleList = static_cast<CSSRuleList*>(object); + GroupId groupId(cssRuleList); + StyleList* styleList = cssRuleList->styleList(); + if (styleList) + groupId = calculateGroupId(styleList); + m_grouper.append(GrouperItem(groupId, wrapper)); + } } - void startMap() + void applyGrouping() { - m_grouper.shrink(0); - } + // 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; + } + } - void endMap() - { - makeV8ObjectGroups(m_grouper); - } + ASSERT(nextKeyIndex > i); - 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); - - // We put the whole tree of style elements into a single object group. - // To achieve that we group elements by the roots of their trees. - StyleBase* root = styleBase; - ASSERT(root); - while (true) { - StyleBase* parent = root->parent(); - if (!parent) - break; - root = parent; + // 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; } - // Group id is an address of the root. - uintptr_t groupId = reinterpret_cast<uintptr_t>(root); - 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)); - } - } + size_t rootIndex = i; + + 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); } - } 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); + + if (group.size() > 1) + v8::V8::AddObjectGroup(&group[0], group.size(), m_grouper[rootIndex].createRetainedObjectInfo()); + + 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. @@ -425,12 +430,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; |