void markDOMNodesForDocument(Document* doc) { // If a node's JS wrapper holds custom properties, those properties must // persist every time the node is fetched from the DOM. So, we keep JS // wrappers like that from being garbage collected. JSWrapperCache& nodeDict = doc->wrapperCache(); JSWrapperCache::iterator nodeEnd = nodeDict.end(); for (JSWrapperCache::iterator nodeIt = nodeDict.begin(); nodeIt != nodeEnd; ++nodeIt) { JSNode* jsNode = nodeIt->second; Node* node = jsNode->impl(); if (jsNode->marked()) continue; // No need to preserve a wrapper that has no custom properties or is no // longer fetchable through the DOM. if (!jsNode->hasCustomProperties() || !node->inDocument()) { //... unless the wrapper wraps a loading image, since the "new Image" // syntax allows an orphan image wrapper to be the last reference // to a loading image, whose load event might have important side-effects. if (!node->hasTagName(imgTag) || static_cast<HTMLImageElement*>(node)->haveFiredLoadEvent()) continue; } jsNode->mark(); } }
void markDOMNodesForDocument(Document* doc) { JSWrapperCache& nodeDict = doc->wrapperCache(); JSWrapperCache::iterator nodeEnd = nodeDict.end(); for (JSWrapperCache::iterator nodeIt = nodeDict.begin(); nodeIt != nodeEnd; ++nodeIt) { JSNode* jsNode = nodeIt->second; if (!jsNode->marked() && isObservableThroughDOM(jsNode)) jsNode->mark(); } }
void JSNode::mark() { ASSERT(!marked()); Node* node = m_impl.get(); // Nodes in the document are kept alive by JSDocument::mark, // so we have no special responsibilities and can just call the base class here. if (node->inDocument()) { // But if the document isn't marked we have to mark it to ensure that // nodes reachable from this one are also marked if (Document* doc = node->ownerDocument()) if (DOMObject* docWrapper = getCachedDOMObjectWrapper(*Heap::heap(this)->globalData(), doc)) if (!docWrapper->marked()) docWrapper->mark(); DOMObject::mark(); return; } // This is a node outside the document, so find the root of the tree it is in, // and start marking from there. Node* root = node; for (Node* current = m_impl.get(); current; current = current->parentNode()) root = current; // If we're already marking this tree, then we can simply mark this wrapper // by calling the base class; our caller is iterating the tree. if (root->inSubtreeMark()) { DOMObject::mark(); return; } // Mark the whole tree; use the global set of roots to avoid reentering. root->setInSubtreeMark(true); for (Node* nodeToMark = root; nodeToMark; nodeToMark = nodeToMark->traverseNextNode()) { JSNode* wrapper = getCachedDOMNodeWrapper(m_impl->document(), nodeToMark); if (wrapper) { if (!wrapper->marked()) wrapper->mark(); } else if (nodeToMark == node) { // This is the case where the map from the document to wrappers has // been cleared out, but a wrapper is being marked. For now, we'll // let the rest of the tree of wrappers get collected, because we have // no good way of finding them. Later we should test behavior of other // browsers and see if we need to preserve other wrappers in this case. if (!marked()) mark(); } } root->setInSubtreeMark(false); // Double check that we actually ended up marked. This assert caught problems in the past. ASSERT(marked()); }