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 |