Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2009 Google Inc. All rights reserved. | 2 * Copyright (C) 2009 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 79 return node; | 79 return node; |
| 80 node = ownerElement; | 80 node = ownerElement; |
| 81 } | 81 } |
| 82 | 82 |
| 83 while (Node* parent = node->parentOrShadowHostNode()) | 83 while (Node* parent = node->parentOrShadowHostNode()) |
| 84 node = parent; | 84 node = parent; |
| 85 | 85 |
| 86 return node; | 86 return node; |
| 87 } | 87 } |
| 88 | 88 |
| 89 static void gcTree(v8::Isolate* isolate, Node* startNode) | |
| 90 { | |
| 91 Vector<Node*, initialNodeVectorSize> newSpaceNodes; | |
| 92 | |
| 93 // We traverse a DOM tree in the DFS order starting from startNode. | |
| 94 // The traversal order does not matter for correctness but does matter for p erformance. | |
| 95 Node* node = startNode; | |
| 96 // To make each minor GC time bounded, we might need to give up | |
| 97 // traversing at some point for a large DOM tree. That being said, | |
| 98 // I could not observe the need even in pathological test cases. | |
| 99 do { | |
| 100 ASSERT(node); | |
| 101 if (!node->wrapper().IsEmpty()) { | |
| 102 // FIXME: Remove the special handling for image elements. | |
| 103 // The same special handling is in V8GCController::opaqueRootForGC() . | |
| 104 // Maybe should image elements be active DOM nodes? | |
| 105 // See https://code.google.com/p/chromium/issues/detail?id=164882 | |
| 106 if (!node->isV8CollectableDuringMinorGC() || (node->hasTagName(HTMLN ames::imgTag) && static_cast<HTMLImageElement*>(node)->hasPendingActivity())) { | |
| 107 // This node is not in the new space of V8. This indicates that | |
| 108 // the minor GC cannot anyway judge reachability of this DOM tre e. | |
| 109 // Thus we give up traversing the DOM tree. | |
| 110 return; | |
| 111 } | |
| 112 node->setV8CollectableDuringMinorGC(false); | |
| 113 newSpaceNodes.append(node); | |
| 114 } | |
| 115 if (node->firstChild()) { | |
| 116 node = node->firstChild(); | |
| 117 continue; | |
| 118 } | |
| 119 while (!node->nextSibling()) { | |
| 120 if (!node->parentNode()) | |
| 121 break; | |
| 122 node = node->parentNode(); | |
| 123 } | |
| 124 if (node->parentNode()) | |
| 125 node = node->nextSibling(); | |
| 126 } while (node != startNode); | |
| 127 | |
| 128 // We completed the DOM tree traversal. All wrappers in the DOM tree are | |
| 129 // stored in newSpaceNodes and are expected to exist in the new space of V8. | |
| 130 // We report those wrappers to V8 as an object group. | |
| 131 Node** nodeIterator = newSpaceNodes.begin(); | |
| 132 Node** const nodeIteratorEnd = newSpaceNodes.end(); | |
| 133 if (nodeIterator == nodeIteratorEnd) | |
| 134 return; | |
| 135 v8::UniqueId id(reinterpret_cast<intptr_t>(*(*nodeIterator)->wrapper())); | |
| 136 for (; nodeIterator != nodeIteratorEnd; ++nodeIterator) { | |
| 137 v8::Persistent<v8::Object> wrapper((*nodeIterator)->wrapper()); | |
| 138 wrapper.MarkPartiallyDependent(isolate); | |
| 139 isolate->SetObjectGroupId(wrapper, id); | |
| 140 } | |
| 141 } | |
| 142 | |
| 143 // Regarding a minor GC algorithm for DOM nodes, see this document: | 89 // Regarding a minor GC algorithm for DOM nodes, see this document: |
| 144 // https://docs.google.com/a/google.com/presentation/d/1uifwVYGNYTZDoGLyCb7sXa7g 49mWNMW2gaWvMN5NLk8/edit#slide=id.p | 90 // https://docs.google.com/a/google.com/presentation/d/1uifwVYGNYTZDoGLyCb7sXa7g 49mWNMW2gaWvMN5NLk8/edit#slide=id.p |
| 145 class MinorGCWrapperVisitor : public v8::PersistentHandleVisitor { | 91 class MinorGCWrapperVisitor : public v8::PersistentHandleVisitor { |
| 146 public: | 92 public: |
| 147 explicit MinorGCWrapperVisitor(v8::Isolate* isolate) | 93 explicit MinorGCWrapperVisitor(v8::Isolate* isolate) |
| 148 : m_isolate(isolate) | 94 : m_isolate(isolate) |
| 149 { | 95 { |
| 150 UNUSED_PARAM(m_isolate); | 96 UNUSED_PARAM(m_isolate); |
| 151 } | 97 } |
| 152 | 98 |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 168 return; | 114 return; |
| 169 | 115 |
| 170 ASSERT(value->IsObject()); | 116 ASSERT(value->IsObject()); |
| 171 v8::Persistent<v8::Object> wrapper = v8::Persistent<v8::Object>::Cast(va lue); | 117 v8::Persistent<v8::Object> wrapper = v8::Persistent<v8::Object>::Cast(va lue); |
| 172 ASSERT(V8DOMWrapper::maybeDOMWrapper(value)); | 118 ASSERT(V8DOMWrapper::maybeDOMWrapper(value)); |
| 173 ASSERT(V8Node::HasInstanceInAnyWorld(wrapper, m_isolate)); | 119 ASSERT(V8Node::HasInstanceInAnyWorld(wrapper, m_isolate)); |
| 174 Node* node = V8Node::toNative(wrapper); | 120 Node* node = V8Node::toNative(wrapper); |
| 175 // A minor DOM GC can handle only node wrappers in the main world. | 121 // A minor DOM GC can handle only node wrappers in the main world. |
| 176 // Note that node->wrapper().IsEmpty() returns true for nodes that | 122 // Note that node->wrapper().IsEmpty() returns true for nodes that |
| 177 // do not have wrappers in the main world. | 123 // do not have wrappers in the main world. |
| 178 if (!node->wrapper().IsEmpty()) { | 124 if (node->containsWrapper()) { |
| 179 WrapperTypeInfo* type = toWrapperTypeInfo(wrapper); | 125 WrapperTypeInfo* type = toWrapperTypeInfo(wrapper); |
| 180 ActiveDOMObject* activeDOMObject = type->toActiveDOMObject(wrapper); | 126 ActiveDOMObject* activeDOMObject = type->toActiveDOMObject(wrapper); |
| 181 if (activeDOMObject && activeDOMObject->hasPendingActivity()) | 127 if (activeDOMObject && activeDOMObject->hasPendingActivity()) |
| 182 return; | 128 return; |
| 183 m_nodesInNewSpace.append(node); | 129 m_nodesInNewSpace.append(node); |
| 184 node->setV8CollectableDuringMinorGC(true); | 130 node->setV8CollectableDuringMinorGC(true); |
| 185 } | 131 } |
| 186 } | 132 } |
| 187 | 133 |
| 188 void notifyFinished() | 134 void notifyFinished() |
| 189 { | 135 { |
| 190 Node** nodeIterator = m_nodesInNewSpace.begin(); | 136 Node** nodeIterator = m_nodesInNewSpace.begin(); |
| 191 Node** nodeIteratorEnd = m_nodesInNewSpace.end(); | 137 Node** nodeIteratorEnd = m_nodesInNewSpace.end(); |
| 192 for (; nodeIterator < nodeIteratorEnd; ++nodeIterator) { | 138 for (; nodeIterator < nodeIteratorEnd; ++nodeIterator) { |
| 193 Node* node = *nodeIterator; | 139 Node* node = *nodeIterator; |
| 194 ASSERT(!node->wrapper().IsEmpty()); | 140 ASSERT(node->containsWrapper()); |
| 195 if (node->isV8CollectableDuringMinorGC()) // This branch is just for performance. | 141 if (node->isV8CollectableDuringMinorGC()) // This branch is just for performance. |
| 196 gcTree(m_isolate, node); | 142 gcTree(m_isolate, node); |
| 197 } | 143 } |
| 198 } | 144 } |
| 199 | 145 |
| 200 private: | 146 private: |
| 147 void gcTree(v8::Isolate* isolate, Node* startNode) | |
| 148 { | |
| 149 Vector<Node*, initialNodeVectorSize> newSpaceNodes; | |
| 150 | |
| 151 // We traverse a DOM tree in the DFS order starting from startNode. | |
| 152 // The traversal order does not matter for correctness but does matter f or performance. | |
| 153 Node* node = startNode; | |
| 154 // To make each minor GC time bounded, we might need to give up | |
| 155 // traversing at some point for a large DOM tree. That being said, | |
| 156 // I could not observe the need even in pathological test cases. | |
| 157 do { | |
| 158 ASSERT(node); | |
| 159 if (node->containsWrapper()) { | |
| 160 // FIXME: Remove the special handling for image elements. | |
| 161 // The same special handling is in V8GCController::opaqueRootFor GC(). | |
| 162 // Maybe should image elements be active DOM nodes? | |
| 163 // See https://code.google.com/p/chromium/issues/detail?id=16488 2 | |
| 164 if (!node->isV8CollectableDuringMinorGC() || (node->hasTagName(H TMLNames::imgTag) && static_cast< HTMLImageElement*>(node)->hasPendingActivit y())) { | |
| 165 // This node is not in the new space of V8. This indicates t hat | |
| 166 // the minor GC cannot anyway judge reachability of this DOM tree. | |
| 167 // Thus we give up traversing the DOM tree. | |
| 168 return; | |
| 169 } | |
| 170 node->setV8CollectableDuringMinorGC(false); | |
| 171 newSpaceNodes.append(node); | |
| 172 } | |
| 173 if (node->firstChild()) { | |
| 174 node = node->firstChild(); | |
| 175 continue; | |
| 176 } | |
| 177 while (!node->nextSibling()) { | |
| 178 if (!node->parentNode()) | |
| 179 break; | |
| 180 node = node->parentNode(); | |
| 181 } | |
| 182 if (node->parentNode()) | |
| 183 node = node->nextSibling(); | |
| 184 } while (node != startNode); | |
| 185 | |
| 186 // We completed the DOM tree traversal. All wrappers in the DOM tree are | |
| 187 // stored in newSpaceNodes and are expected to exist in the new space of V8. | |
| 188 // We report those wrappers to V8 as an object group. | |
| 189 Node** nodeIterator = newSpaceNodes.begin(); | |
| 190 Node** const nodeIteratorEnd = newSpaceNodes.end(); | |
| 191 if (nodeIterator == nodeIteratorEnd) | |
| 192 return; | |
| 193 v8::UniqueId id(reinterpret_cast<intptr_t>((*nodeIterator)->unsafePersis tent().value())); | |
| 194 for (; nodeIterator != nodeIteratorEnd; ++nodeIterator) { | |
| 195 // This is safe because we know that GC won't happen before we | |
| 196 // dispose the UnsafePersistent (we're just preparing a GC). | |
| 197 UnsafePersistent<v8::Object> unsafeWrapper = (*nodeIterator)->unsafe Persistent(); | |
| 198 v8::Persistent<v8::Object> wrapper; | |
| 199 unsafeWrapper.makePersistentHandle(&wrapper); | |
|
dcarney
2013/04/29 10:33:51
maybe make one line?
marja
2013/04/29 12:02:07
Done.
| |
| 200 wrapper.MarkPartiallyDependent(isolate); | |
|
haraken
2013/04/29 10:42:17
Would it be possible to define UnsafePersistent::o
marja
2013/04/29 12:02:07
Offline discussion -> the wrapper is still needed
| |
| 201 isolate->SetObjectGroupId(wrapper, id); | |
| 202 } | |
| 203 } | |
| 204 | |
| 201 Vector<Node*> m_nodesInNewSpace; | 205 Vector<Node*> m_nodesInNewSpace; |
| 202 v8::Isolate* m_isolate; | 206 v8::Isolate* m_isolate; |
| 203 }; | 207 }; |
| 204 | 208 |
| 205 class MajorGCWrapperVisitor : public v8::PersistentHandleVisitor { | 209 class MajorGCWrapperVisitor : public v8::PersistentHandleVisitor { |
| 206 public: | 210 public: |
| 207 explicit MajorGCWrapperVisitor(v8::Isolate* isolate, bool constructRetainedO bjectInfos) | 211 explicit MajorGCWrapperVisitor(v8::Isolate* isolate, bool constructRetainedO bjectInfos) |
| 208 : m_isolate(isolate) | 212 : m_isolate(isolate) |
| 209 , m_liveRootGroupIdSet(false) | 213 , m_liveRootGroupIdSet(false) |
| 210 , m_constructRetainedObjectInfos(constructRetainedObjectInfos) | 214 , m_constructRetainedObjectInfos(constructRetainedObjectInfos) |
| (...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 431 if (!script.IsEmpty()) { | 435 if (!script.IsEmpty()) { |
| 432 V8RecursionScope::MicrotaskSuppression scope; | 436 V8RecursionScope::MicrotaskSuppression scope; |
| 433 script->Run(); | 437 script->Run(); |
| 434 } | 438 } |
| 435 } | 439 } |
| 436 | 440 |
| 437 context.clear(); | 441 context.clear(); |
| 438 } | 442 } |
| 439 | 443 |
| 440 } // namespace WebCore | 444 } // namespace WebCore |
| OLD | NEW |