| 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 class PathTracer::MarkVisitor: public ObjectVisitor { |
| 5187 static Object* search_target; | 5187 public: |
| 5188 static bool found_target; | 5188 explicit MarkVisitor(PathTracer* tracer) : tracer_(tracer) {} |
| 5189 static List<Object*> object_stack(20); | 5189 void VisitPointers(Object** start, Object** end) { |
| 5190 // Scan all HeapObject pointers in [start, end) |
| 5191 for (Object** p = start; !tracer_->found() && (p < end); p++) { |
| 5192 if ((*p)->IsHeapObject()) |
| 5193 tracer_->MarkRecursively(p, this); |
| 5194 } |
| 5195 } |
| 5196 |
| 5197 private: |
| 5198 PathTracer* tracer_; |
| 5199 }; |
| 5190 | 5200 |
| 5191 | 5201 |
| 5192 // Tags 0, 1, and 3 are used. Use 2 for marking visited HeapObject. | 5202 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: | 5203 public: |
| 5204 explicit UnmarkVisitor(PathTracer* tracer) : tracer_(tracer) {} |
| 5198 void VisitPointers(Object** start, Object** end) { | 5205 void VisitPointers(Object** start, Object** end) { |
| 5199 // Copy all HeapObject pointers in [start, end) | 5206 // Scan all HeapObject pointers in [start, end) |
| 5200 for (Object** p = start; p < end; p++) { | 5207 for (Object** p = start; p < end; p++) { |
| 5201 if ((*p)->IsHeapObject()) | 5208 if ((*p)->IsHeapObject()) |
| 5202 MarkObjectRecursively(p); | 5209 tracer_->UnmarkRecursively(p, this); |
| 5203 } | 5210 } |
| 5204 } | 5211 } |
| 5212 |
| 5213 private: |
| 5214 PathTracer* tracer_; |
| 5205 }; | 5215 }; |
| 5206 | 5216 |
| 5207 static MarkObjectVisitor mark_visitor; | |
| 5208 | 5217 |
| 5209 static void MarkObjectRecursively(Object** p) { | 5218 void PathTracer::TracePathFrom(Object** root) { |
| 5219 if (search_for_any_global_) { |
| 5220 ASSERT(search_target_ == NULL); |
| 5221 } else { |
| 5222 ASSERT(search_target_->IsHeapObject()); |
| 5223 } |
| 5224 found_target_in_trace_ = false; |
| 5225 object_stack_.Clear(); |
| 5226 |
| 5227 MarkVisitor mark_visitor(this); |
| 5228 MarkRecursively(root, &mark_visitor); |
| 5229 |
| 5230 UnmarkVisitor unmark_visitor(this); |
| 5231 UnmarkRecursively(root, &unmark_visitor); |
| 5232 |
| 5233 ProcessResults(); |
| 5234 } |
| 5235 |
| 5236 |
| 5237 void PathTracer::MarkRecursively(Object** p, MarkVisitor* mark_visitor) { |
| 5210 if (!(*p)->IsHeapObject()) return; | 5238 if (!(*p)->IsHeapObject()) return; |
| 5211 | 5239 |
| 5212 HeapObject* obj = HeapObject::cast(*p); | 5240 HeapObject* obj = HeapObject::cast(*p); |
| 5213 | 5241 |
| 5214 Object* map = obj->map(); | 5242 Object* map = obj->map(); |
| 5215 | 5243 |
| 5216 if (!map->IsHeapObject()) return; // visited before | 5244 if (!map->IsHeapObject()) return; // visited before |
| 5217 | 5245 |
| 5218 if (found_target) return; // stop if target found | 5246 if (found_target_in_trace_) return; // stop if target found |
| 5219 object_stack.Add(obj); | 5247 object_stack_.Add(obj); |
| 5220 if ((search_for_any_global && obj->IsJSGlobalObject()) || | 5248 if ((search_for_any_global_ && obj->IsJSGlobalObject()) || |
| 5221 (!search_for_any_global && (obj == search_target))) { | 5249 (!search_for_any_global_ && (obj == search_target_))) { |
| 5222 found_target = true; | 5250 found_target_in_trace_ = true; |
| 5251 found_target_ = true; |
| 5223 return; | 5252 return; |
| 5224 } | 5253 } |
| 5225 | 5254 |
| 5255 bool is_global_context = obj->IsGlobalContext(); |
| 5256 |
| 5226 // not visited yet | 5257 // not visited yet |
| 5227 Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map)); | 5258 Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map)); |
| 5228 | 5259 |
| 5229 Address map_addr = map_p->address(); | 5260 Address map_addr = map_p->address(); |
| 5230 | 5261 |
| 5231 obj->set_map(reinterpret_cast<Map*>(map_addr + kMarkTag)); | 5262 obj->set_map(reinterpret_cast<Map*>(map_addr + kMarkTag)); |
| 5232 | 5263 |
| 5233 MarkObjectRecursively(&map); | 5264 // Scan the object body. |
| 5265 if (is_global_context && skip_weak_refs_) { |
| 5266 // This is specialized to scan Context's properly. |
| 5267 Object** start = reinterpret_cast<Object**>(obj->address() + |
| 5268 Context::kHeaderSize); |
| 5269 Object** end = reinterpret_cast<Object**>(obj->address() + |
| 5270 Context::kHeaderSize + Context::FIRST_WEAK_SLOT * kPointerSize); |
| 5271 mark_visitor->VisitPointers(start, end); |
| 5272 } else { |
| 5273 obj->IterateBody(map_p->instance_type(), |
| 5274 obj->SizeFromMap(map_p), |
| 5275 mark_visitor); |
| 5276 } |
| 5234 | 5277 |
| 5235 obj->IterateBody(map_p->instance_type(), obj->SizeFromMap(map_p), | 5278 // Scan the map after the body because the body is a lot more interesting |
| 5236 &mark_visitor); | 5279 // when doing leak detection. |
| 5280 MarkRecursively(&map, mark_visitor); |
| 5237 | 5281 |
| 5238 if (!found_target) // don't pop if found the target | 5282 if (!found_target_in_trace_) // don't pop if found the target |
| 5239 object_stack.RemoveLast(); | 5283 object_stack_.RemoveLast(); |
| 5240 } | 5284 } |
| 5241 | 5285 |
| 5242 | 5286 |
| 5243 static void UnmarkObjectRecursively(Object** p); | 5287 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; | 5288 if (!(*p)->IsHeapObject()) return; |
| 5259 | 5289 |
| 5260 HeapObject* obj = HeapObject::cast(*p); | 5290 HeapObject* obj = HeapObject::cast(*p); |
| 5261 | 5291 |
| 5262 Object* map = obj->map(); | 5292 Object* map = obj->map(); |
| 5263 | 5293 |
| 5264 if (map->IsHeapObject()) return; // unmarked already | 5294 if (map->IsHeapObject()) return; // unmarked already |
| 5265 | 5295 |
| 5266 Address map_addr = reinterpret_cast<Address>(map); | 5296 Address map_addr = reinterpret_cast<Address>(map); |
| 5267 | 5297 |
| 5268 map_addr -= kMarkTag; | 5298 map_addr -= kMarkTag; |
| 5269 | 5299 |
| 5270 ASSERT_TAG_ALIGNED(map_addr); | 5300 ASSERT_TAG_ALIGNED(map_addr); |
| 5271 | 5301 |
| 5272 HeapObject* map_p = HeapObject::FromAddress(map_addr); | 5302 HeapObject* map_p = HeapObject::FromAddress(map_addr); |
| 5273 | 5303 |
| 5274 obj->set_map(reinterpret_cast<Map*>(map_p)); | 5304 obj->set_map(reinterpret_cast<Map*>(map_p)); |
| 5275 | 5305 |
| 5276 UnmarkObjectRecursively(reinterpret_cast<Object**>(&map_p)); | 5306 UnmarkRecursively(reinterpret_cast<Object**>(&map_p), unmark_visitor); |
| 5277 | 5307 |
| 5278 obj->IterateBody(Map::cast(map_p)->instance_type(), | 5308 obj->IterateBody(Map::cast(map_p)->instance_type(), |
| 5279 obj->SizeFromMap(Map::cast(map_p)), | 5309 obj->SizeFromMap(Map::cast(map_p)), |
| 5280 &unmark_visitor); | 5310 unmark_visitor); |
| 5281 } | 5311 } |
| 5282 | 5312 |
| 5283 | 5313 |
| 5284 static void MarkRootObjectRecursively(Object** root) { | 5314 void PathTracer::ProcessResults() { |
| 5285 if (search_for_any_global) { | 5315 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"); | 5316 PrintF("=====================================\n"); |
| 5298 PrintF("==== Path to object ====\n"); | 5317 PrintF("==== Path to object ====\n"); |
| 5299 PrintF("=====================================\n\n"); | 5318 PrintF("=====================================\n\n"); |
| 5300 | 5319 |
| 5301 ASSERT(!object_stack.is_empty()); | 5320 ASSERT(!object_stack_.is_empty()); |
| 5302 for (int i = 0; i < object_stack.length(); i++) { | 5321 for (int i = 0; i < object_stack_.length(); i++) { |
| 5303 if (i > 0) PrintF("\n |\n |\n V\n\n"); | 5322 if (i > 0) PrintF("\n |\n |\n V\n\n"); |
| 5304 Object* obj = object_stack[i]; | 5323 Object* obj = object_stack_[i]; |
| 5305 obj->Print(); | 5324 obj->Print(); |
| 5306 } | 5325 } |
| 5307 PrintF("=====================================\n"); | 5326 PrintF("=====================================\n"); |
| 5308 } | 5327 } |
| 5309 } | 5328 } |
| 5329 #endif // DEBUG || LIVE_OBJECT_LIST |
| 5310 | 5330 |
| 5311 | 5331 |
| 5312 // Helper class for visiting HeapObjects recursively. | 5332 #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 | 5333 // Triggers a depth-first traversal of reachable objects from roots |
| 5326 // and finds a path to a specific heap object and prints it. | 5334 // and finds a path to a specific heap object and prints it. |
| 5327 void Heap::TracePathToObject(Object* target) { | 5335 void Heap::TracePathToObject(Object* target) { |
| 5328 search_target = target; | 5336 PathTracer tracer(target, false, PathTracer::FIND_ALL, false); |
| 5329 search_for_any_global = false; | 5337 IterateRoots(&tracer, VISIT_ONLY_STRONG); |
| 5330 | |
| 5331 MarkRootVisitor root_visitor; | |
| 5332 IterateRoots(&root_visitor, VISIT_ONLY_STRONG); | |
| 5333 } | 5338 } |
| 5334 | 5339 |
| 5335 | 5340 |
| 5336 // Triggers a depth-first traversal of reachable objects from roots | 5341 // Triggers a depth-first traversal of reachable objects from roots |
| 5337 // and finds a path to any global object and prints it. Useful for | 5342 // and finds a path to any global object and prints it. Useful for |
| 5338 // determining the source for leaks of global objects. | 5343 // determining the source for leaks of global objects. |
| 5339 void Heap::TracePathToGlobal() { | 5344 void Heap::TracePathToGlobal() { |
| 5340 search_target = NULL; | 5345 PathTracer tracer(NULL, true, PathTracer::FIND_ALL, false); |
| 5341 search_for_any_global = true; | 5346 IterateRoots(&tracer, VISIT_ONLY_STRONG); |
| 5342 | |
| 5343 MarkRootVisitor root_visitor; | |
| 5344 IterateRoots(&root_visitor, VISIT_ONLY_STRONG); | |
| 5345 } | 5347 } |
| 5346 #endif | 5348 #endif |
| 5347 | 5349 |
| 5348 | 5350 |
| 5349 static intptr_t CountTotalHolesSize() { | 5351 static intptr_t CountTotalHolesSize() { |
| 5350 intptr_t holes_size = 0; | 5352 intptr_t holes_size = 0; |
| 5351 OldSpaces spaces; | 5353 OldSpaces spaces; |
| 5352 for (OldSpace* space = spaces.next(); | 5354 for (OldSpace* space = spaces.next(); |
| 5353 space != NULL; | 5355 space != NULL; |
| 5354 space = spaces.next()) { | 5356 space = spaces.next()) { |
| (...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5587 void ExternalStringTable::TearDown() { | 5589 void ExternalStringTable::TearDown() { |
| 5588 new_space_strings_.Free(); | 5590 new_space_strings_.Free(); |
| 5589 old_space_strings_.Free(); | 5591 old_space_strings_.Free(); |
| 5590 } | 5592 } |
| 5591 | 5593 |
| 5592 | 5594 |
| 5593 List<Object*> ExternalStringTable::new_space_strings_; | 5595 List<Object*> ExternalStringTable::new_space_strings_; |
| 5594 List<Object*> ExternalStringTable::old_space_strings_; | 5596 List<Object*> ExternalStringTable::old_space_strings_; |
| 5595 | 5597 |
| 5596 } } // namespace v8::internal | 5598 } } // namespace v8::internal |
| OLD | NEW |