OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 5163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5174 } | 5174 } |
5175 | 5175 |
5176 | 5176 |
5177 void HeapIterator::reset() { | 5177 void HeapIterator::reset() { |
5178 // Restart the iterator. | 5178 // Restart the iterator. |
5179 Shutdown(); | 5179 Shutdown(); |
5180 Init(); | 5180 Init(); |
5181 } | 5181 } |
5182 | 5182 |
5183 | 5183 |
5184 #ifdef DEBUG | 5184 #if defined(DEBUG) || defined(LIVE_OBJECT_LIST) |
5185 | 5185 |
5186 static bool search_for_any_global; | 5186 Object* const PathTracer::kAnyGlobalObject = reinterpret_cast<Object*>(NULL); |
5187 static Object* search_target; | 5187 |
5188 static bool found_target; | 5188 class PathTracer::MarkVisitor: public ObjectVisitor { |
5189 static List<Object*> object_stack(20); | 5189 public: |
| 5190 explicit MarkVisitor(PathTracer* tracer) : tracer_(tracer) {} |
| 5191 void VisitPointers(Object** start, Object** end) { |
| 5192 // Scan all HeapObject pointers in [start, end) |
| 5193 for (Object** p = start; !tracer_->found() && (p < end); p++) { |
| 5194 if ((*p)->IsHeapObject()) |
| 5195 tracer_->MarkRecursively(p, this); |
| 5196 } |
| 5197 } |
| 5198 |
| 5199 private: |
| 5200 PathTracer* tracer_; |
| 5201 }; |
5190 | 5202 |
5191 | 5203 |
5192 // Tags 0, 1, and 3 are used. Use 2 for marking visited HeapObject. | 5204 class PathTracer::UnmarkVisitor: public ObjectVisitor { |
5193 static const int kMarkTag = 2; | |
5194 | |
5195 static void MarkObjectRecursively(Object** p); | |
5196 class MarkObjectVisitor : public ObjectVisitor { | |
5197 public: | 5205 public: |
| 5206 explicit UnmarkVisitor(PathTracer* tracer) : tracer_(tracer) {} |
5198 void VisitPointers(Object** start, Object** end) { | 5207 void VisitPointers(Object** start, Object** end) { |
5199 // Copy all HeapObject pointers in [start, end) | 5208 // Scan all HeapObject pointers in [start, end) |
5200 for (Object** p = start; p < end; p++) { | 5209 for (Object** p = start; p < end; p++) { |
5201 if ((*p)->IsHeapObject()) | 5210 if ((*p)->IsHeapObject()) |
5202 MarkObjectRecursively(p); | 5211 tracer_->UnmarkRecursively(p, this); |
5203 } | 5212 } |
5204 } | 5213 } |
| 5214 |
| 5215 private: |
| 5216 PathTracer* tracer_; |
5205 }; | 5217 }; |
5206 | 5218 |
5207 static MarkObjectVisitor mark_visitor; | |
5208 | 5219 |
5209 static void MarkObjectRecursively(Object** p) { | 5220 void PathTracer::VisitPointers(Object** start, Object** end) { |
| 5221 bool done = ((what_to_find_ == FIND_FIRST) && found_target_); |
| 5222 // Visit all HeapObject pointers in [start, end) |
| 5223 for (Object** p = start; !done && (p < end); p++) { |
| 5224 if ((*p)->IsHeapObject()) { |
| 5225 TracePathFrom(p); |
| 5226 done = ((what_to_find_ == FIND_FIRST) && found_target_); |
| 5227 } |
| 5228 } |
| 5229 } |
| 5230 |
| 5231 |
| 5232 void PathTracer::Reset() { |
| 5233 found_target_ = false; |
| 5234 object_stack_.Clear(); |
| 5235 } |
| 5236 |
| 5237 |
| 5238 void PathTracer::TracePathFrom(Object** root) { |
| 5239 ASSERT((search_target_ == kAnyGlobalObject) || |
| 5240 search_target_->IsHeapObject()); |
| 5241 found_target_in_trace_ = false; |
| 5242 object_stack_.Clear(); |
| 5243 |
| 5244 MarkVisitor mark_visitor(this); |
| 5245 MarkRecursively(root, &mark_visitor); |
| 5246 |
| 5247 UnmarkVisitor unmark_visitor(this); |
| 5248 UnmarkRecursively(root, &unmark_visitor); |
| 5249 |
| 5250 ProcessResults(); |
| 5251 } |
| 5252 |
| 5253 |
| 5254 void PathTracer::MarkRecursively(Object** p, MarkVisitor* mark_visitor) { |
5210 if (!(*p)->IsHeapObject()) return; | 5255 if (!(*p)->IsHeapObject()) return; |
5211 | 5256 |
5212 HeapObject* obj = HeapObject::cast(*p); | 5257 HeapObject* obj = HeapObject::cast(*p); |
5213 | 5258 |
5214 Object* map = obj->map(); | 5259 Object* map = obj->map(); |
5215 | 5260 |
5216 if (!map->IsHeapObject()) return; // visited before | 5261 if (!map->IsHeapObject()) return; // visited before |
5217 | 5262 |
5218 if (found_target) return; // stop if target found | 5263 if (found_target_in_trace_) return; // stop if target found |
5219 object_stack.Add(obj); | 5264 object_stack_.Add(obj); |
5220 if ((search_for_any_global && obj->IsJSGlobalObject()) || | 5265 if (((search_target_ == kAnyGlobalObject) && obj->IsJSGlobalObject()) || |
5221 (!search_for_any_global && (obj == search_target))) { | 5266 (obj == search_target_)) { |
5222 found_target = true; | 5267 found_target_in_trace_ = true; |
| 5268 found_target_ = true; |
5223 return; | 5269 return; |
5224 } | 5270 } |
5225 | 5271 |
| 5272 bool is_global_context = obj->IsGlobalContext(); |
| 5273 |
5226 // not visited yet | 5274 // not visited yet |
5227 Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map)); | 5275 Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map)); |
5228 | 5276 |
5229 Address map_addr = map_p->address(); | 5277 Address map_addr = map_p->address(); |
5230 | 5278 |
5231 obj->set_map(reinterpret_cast<Map*>(map_addr + kMarkTag)); | 5279 obj->set_map(reinterpret_cast<Map*>(map_addr + kMarkTag)); |
5232 | 5280 |
5233 MarkObjectRecursively(&map); | 5281 // Scan the object body. |
| 5282 if (is_global_context && (visit_mode_ == VISIT_ONLY_STRONG)) { |
| 5283 // This is specialized to scan Context's properly. |
| 5284 Object** start = reinterpret_cast<Object**>(obj->address() + |
| 5285 Context::kHeaderSize); |
| 5286 Object** end = reinterpret_cast<Object**>(obj->address() + |
| 5287 Context::kHeaderSize + Context::FIRST_WEAK_SLOT * kPointerSize); |
| 5288 mark_visitor->VisitPointers(start, end); |
| 5289 } else { |
| 5290 obj->IterateBody(map_p->instance_type(), |
| 5291 obj->SizeFromMap(map_p), |
| 5292 mark_visitor); |
| 5293 } |
5234 | 5294 |
5235 obj->IterateBody(map_p->instance_type(), obj->SizeFromMap(map_p), | 5295 // Scan the map after the body because the body is a lot more interesting |
5236 &mark_visitor); | 5296 // when doing leak detection. |
| 5297 MarkRecursively(&map, mark_visitor); |
5237 | 5298 |
5238 if (!found_target) // don't pop if found the target | 5299 if (!found_target_in_trace_) // don't pop if found the target |
5239 object_stack.RemoveLast(); | 5300 object_stack_.RemoveLast(); |
5240 } | 5301 } |
5241 | 5302 |
5242 | 5303 |
5243 static void UnmarkObjectRecursively(Object** p); | 5304 void PathTracer::UnmarkRecursively(Object** p, UnmarkVisitor* unmark_visitor) { |
5244 class UnmarkObjectVisitor : public ObjectVisitor { | |
5245 public: | |
5246 void VisitPointers(Object** start, Object** end) { | |
5247 // Copy all HeapObject pointers in [start, end) | |
5248 for (Object** p = start; p < end; p++) { | |
5249 if ((*p)->IsHeapObject()) | |
5250 UnmarkObjectRecursively(p); | |
5251 } | |
5252 } | |
5253 }; | |
5254 | |
5255 static UnmarkObjectVisitor unmark_visitor; | |
5256 | |
5257 static void UnmarkObjectRecursively(Object** p) { | |
5258 if (!(*p)->IsHeapObject()) return; | 5305 if (!(*p)->IsHeapObject()) return; |
5259 | 5306 |
5260 HeapObject* obj = HeapObject::cast(*p); | 5307 HeapObject* obj = HeapObject::cast(*p); |
5261 | 5308 |
5262 Object* map = obj->map(); | 5309 Object* map = obj->map(); |
5263 | 5310 |
5264 if (map->IsHeapObject()) return; // unmarked already | 5311 if (map->IsHeapObject()) return; // unmarked already |
5265 | 5312 |
5266 Address map_addr = reinterpret_cast<Address>(map); | 5313 Address map_addr = reinterpret_cast<Address>(map); |
5267 | 5314 |
5268 map_addr -= kMarkTag; | 5315 map_addr -= kMarkTag; |
5269 | 5316 |
5270 ASSERT_TAG_ALIGNED(map_addr); | 5317 ASSERT_TAG_ALIGNED(map_addr); |
5271 | 5318 |
5272 HeapObject* map_p = HeapObject::FromAddress(map_addr); | 5319 HeapObject* map_p = HeapObject::FromAddress(map_addr); |
5273 | 5320 |
5274 obj->set_map(reinterpret_cast<Map*>(map_p)); | 5321 obj->set_map(reinterpret_cast<Map*>(map_p)); |
5275 | 5322 |
5276 UnmarkObjectRecursively(reinterpret_cast<Object**>(&map_p)); | 5323 UnmarkRecursively(reinterpret_cast<Object**>(&map_p), unmark_visitor); |
5277 | 5324 |
5278 obj->IterateBody(Map::cast(map_p)->instance_type(), | 5325 obj->IterateBody(Map::cast(map_p)->instance_type(), |
5279 obj->SizeFromMap(Map::cast(map_p)), | 5326 obj->SizeFromMap(Map::cast(map_p)), |
5280 &unmark_visitor); | 5327 unmark_visitor); |
5281 } | 5328 } |
5282 | 5329 |
5283 | 5330 |
5284 static void MarkRootObjectRecursively(Object** root) { | 5331 void PathTracer::ProcessResults() { |
5285 if (search_for_any_global) { | 5332 if (found_target_) { |
5286 ASSERT(search_target == NULL); | |
5287 } else { | |
5288 ASSERT(search_target->IsHeapObject()); | |
5289 } | |
5290 found_target = false; | |
5291 object_stack.Clear(); | |
5292 | |
5293 MarkObjectRecursively(root); | |
5294 UnmarkObjectRecursively(root); | |
5295 | |
5296 if (found_target) { | |
5297 PrintF("=====================================\n"); | 5333 PrintF("=====================================\n"); |
5298 PrintF("==== Path to object ====\n"); | 5334 PrintF("==== Path to object ====\n"); |
5299 PrintF("=====================================\n\n"); | 5335 PrintF("=====================================\n\n"); |
5300 | 5336 |
5301 ASSERT(!object_stack.is_empty()); | 5337 ASSERT(!object_stack_.is_empty()); |
5302 for (int i = 0; i < object_stack.length(); i++) { | 5338 for (int i = 0; i < object_stack_.length(); i++) { |
5303 if (i > 0) PrintF("\n |\n |\n V\n\n"); | 5339 if (i > 0) PrintF("\n |\n |\n V\n\n"); |
5304 Object* obj = object_stack[i]; | 5340 Object* obj = object_stack_[i]; |
5305 obj->Print(); | 5341 obj->Print(); |
5306 } | 5342 } |
5307 PrintF("=====================================\n"); | 5343 PrintF("=====================================\n"); |
5308 } | 5344 } |
5309 } | 5345 } |
| 5346 #endif // DEBUG || LIVE_OBJECT_LIST |
5310 | 5347 |
5311 | 5348 |
5312 // Helper class for visiting HeapObjects recursively. | 5349 #ifdef DEBUG |
5313 class MarkRootVisitor: public ObjectVisitor { | |
5314 public: | |
5315 void VisitPointers(Object** start, Object** end) { | |
5316 // Visit all HeapObject pointers in [start, end) | |
5317 for (Object** p = start; p < end; p++) { | |
5318 if ((*p)->IsHeapObject()) | |
5319 MarkRootObjectRecursively(p); | |
5320 } | |
5321 } | |
5322 }; | |
5323 | |
5324 | |
5325 // Triggers a depth-first traversal of reachable objects from roots | 5350 // Triggers a depth-first traversal of reachable objects from roots |
5326 // and finds a path to a specific heap object and prints it. | 5351 // and finds a path to a specific heap object and prints it. |
5327 void Heap::TracePathToObject(Object* target) { | 5352 void Heap::TracePathToObject(Object* target) { |
5328 search_target = target; | 5353 PathTracer tracer(target, PathTracer::FIND_ALL, VISIT_ALL); |
5329 search_for_any_global = false; | 5354 IterateRoots(&tracer, VISIT_ONLY_STRONG); |
5330 | |
5331 MarkRootVisitor root_visitor; | |
5332 IterateRoots(&root_visitor, VISIT_ONLY_STRONG); | |
5333 } | 5355 } |
5334 | 5356 |
5335 | 5357 |
5336 // Triggers a depth-first traversal of reachable objects from roots | 5358 // Triggers a depth-first traversal of reachable objects from roots |
5337 // and finds a path to any global object and prints it. Useful for | 5359 // and finds a path to any global object and prints it. Useful for |
5338 // determining the source for leaks of global objects. | 5360 // determining the source for leaks of global objects. |
5339 void Heap::TracePathToGlobal() { | 5361 void Heap::TracePathToGlobal() { |
5340 search_target = NULL; | 5362 PathTracer tracer(PathTracer::kAnyGlobalObject, |
5341 search_for_any_global = true; | 5363 PathTracer::FIND_ALL, |
5342 | 5364 VISIT_ALL); |
5343 MarkRootVisitor root_visitor; | 5365 IterateRoots(&tracer, VISIT_ONLY_STRONG); |
5344 IterateRoots(&root_visitor, VISIT_ONLY_STRONG); | |
5345 } | 5366 } |
5346 #endif | 5367 #endif |
5347 | 5368 |
5348 | 5369 |
5349 static intptr_t CountTotalHolesSize() { | 5370 static intptr_t CountTotalHolesSize() { |
5350 intptr_t holes_size = 0; | 5371 intptr_t holes_size = 0; |
5351 OldSpaces spaces; | 5372 OldSpaces spaces; |
5352 for (OldSpace* space = spaces.next(); | 5373 for (OldSpace* space = spaces.next(); |
5353 space != NULL; | 5374 space != NULL; |
5354 space = spaces.next()) { | 5375 space = spaces.next()) { |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5587 void ExternalStringTable::TearDown() { | 5608 void ExternalStringTable::TearDown() { |
5588 new_space_strings_.Free(); | 5609 new_space_strings_.Free(); |
5589 old_space_strings_.Free(); | 5610 old_space_strings_.Free(); |
5590 } | 5611 } |
5591 | 5612 |
5592 | 5613 |
5593 List<Object*> ExternalStringTable::new_space_strings_; | 5614 List<Object*> ExternalStringTable::new_space_strings_; |
5594 List<Object*> ExternalStringTable::old_space_strings_; | 5615 List<Object*> ExternalStringTable::old_space_strings_; |
5595 | 5616 |
5596 } } // namespace v8::internal | 5617 } } // namespace v8::internal |
OLD | NEW |