| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 26 matching lines...) Expand all Loading... |
| 37 | 37 |
| 38 namespace v8 { | 38 namespace v8 { |
| 39 namespace internal { | 39 namespace internal { |
| 40 | 40 |
| 41 | 41 |
| 42 IncrementalMarking::IncrementalMarking(Heap* heap) | 42 IncrementalMarking::IncrementalMarking(Heap* heap) |
| 43 : heap_(heap), | 43 : heap_(heap), |
| 44 state_(STOPPED), | 44 state_(STOPPED), |
| 45 marking_deque_memory_(NULL), | 45 marking_deque_memory_(NULL), |
| 46 marking_deque_memory_committed_(false), | 46 marking_deque_memory_committed_(false), |
| 47 marker_(this, heap->mark_compact_collector()), |
| 47 steps_count_(0), | 48 steps_count_(0), |
| 48 steps_took_(0), | 49 steps_took_(0), |
| 49 longest_step_(0.0), | 50 longest_step_(0.0), |
| 50 old_generation_space_available_at_start_of_incremental_(0), | 51 old_generation_space_available_at_start_of_incremental_(0), |
| 51 old_generation_space_used_at_start_of_incremental_(0), | 52 old_generation_space_used_at_start_of_incremental_(0), |
| 52 steps_count_since_last_gc_(0), | 53 steps_count_since_last_gc_(0), |
| 53 steps_took_since_last_gc_(0), | 54 steps_took_since_last_gc_(0), |
| 54 should_hurry_(false), | 55 should_hurry_(false), |
| 55 marking_speed_(0), | 56 allocation_marking_factor_(0), |
| 56 allocated_(0), | 57 allocated_(0), |
| 57 no_marking_scope_depth_(0) { | 58 no_marking_scope_depth_(0) { |
| 58 } | 59 } |
| 59 | 60 |
| 60 | 61 |
| 61 void IncrementalMarking::TearDown() { | 62 void IncrementalMarking::TearDown() { |
| 62 delete marking_deque_memory_; | 63 delete marking_deque_memory_; |
| 63 } | 64 } |
| 64 | 65 |
| 65 | 66 |
| 66 void IncrementalMarking::RecordWriteSlow(HeapObject* obj, | 67 void IncrementalMarking::RecordWriteSlow(HeapObject* obj, |
| 67 Object** slot, | 68 Object** slot, |
| 68 Object* value) { | 69 Object* value) { |
| 69 if (BaseRecordWrite(obj, slot, value) && slot != NULL) { | 70 if (BaseRecordWrite(obj, slot, value) && slot != NULL) { |
| 70 MarkBit obj_bit = Marking::MarkBitFrom(obj); | 71 MarkBit obj_bit = Marking::MarkBitFrom(obj); |
| 71 if (Marking::IsBlack(obj_bit)) { | 72 if (Marking::IsBlack(obj_bit)) { |
| 72 // Object is not going to be rescanned we need to record the slot. | 73 // Object is not going to be rescanned we need to record the slot. |
| 73 heap_->mark_compact_collector()->RecordSlot( | 74 heap_->mark_compact_collector()->RecordSlot( |
| 74 HeapObject::RawField(obj, 0), slot, value); | 75 HeapObject::RawField(obj, 0), slot, value); |
| 75 } | 76 } |
| 76 } | 77 } |
| 77 } | 78 } |
| 78 | 79 |
| 79 | 80 |
| 80 void IncrementalMarking::RecordWriteFromCode(HeapObject* obj, | 81 void IncrementalMarking::RecordWriteFromCode(HeapObject* obj, |
| 81 Object* value, | 82 Object* value, |
| 82 Isolate* isolate) { | 83 Isolate* isolate) { |
| 83 ASSERT(obj->IsHeapObject()); | 84 ASSERT(obj->IsHeapObject()); |
| 85 |
| 86 // Fast cases should already be covered by RecordWriteStub. |
| 87 ASSERT(value->IsHeapObject()); |
| 88 ASSERT(!value->IsHeapNumber()); |
| 89 ASSERT(!value->IsString() || |
| 90 value->IsConsString() || |
| 91 value->IsSlicedString()); |
| 92 ASSERT(Marking::IsWhite(Marking::MarkBitFrom(HeapObject::cast(value)))); |
| 93 |
| 84 IncrementalMarking* marking = isolate->heap()->incremental_marking(); | 94 IncrementalMarking* marking = isolate->heap()->incremental_marking(); |
| 85 ASSERT(!marking->is_compacting_); | 95 ASSERT(!marking->is_compacting_); |
| 86 | |
| 87 MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address()); | |
| 88 int counter = chunk->write_barrier_counter(); | |
| 89 if (counter < (MemoryChunk::kWriteBarrierCounterGranularity / 2)) { | |
| 90 marking->write_barriers_invoked_since_last_step_ += | |
| 91 MemoryChunk::kWriteBarrierCounterGranularity - | |
| 92 chunk->write_barrier_counter(); | |
| 93 chunk->set_write_barrier_counter( | |
| 94 MemoryChunk::kWriteBarrierCounterGranularity); | |
| 95 } | |
| 96 | |
| 97 marking->RecordWrite(obj, NULL, value); | 96 marking->RecordWrite(obj, NULL, value); |
| 98 } | 97 } |
| 99 | 98 |
| 100 | 99 |
| 101 void IncrementalMarking::RecordWriteForEvacuationFromCode(HeapObject* obj, | 100 void IncrementalMarking::RecordWriteForEvacuationFromCode(HeapObject* obj, |
| 102 Object** slot, | 101 Object** slot, |
| 103 Isolate* isolate) { | 102 Isolate* isolate) { |
| 104 ASSERT(obj->IsHeapObject()); | |
| 105 IncrementalMarking* marking = isolate->heap()->incremental_marking(); | 103 IncrementalMarking* marking = isolate->heap()->incremental_marking(); |
| 106 ASSERT(marking->is_compacting_); | 104 ASSERT(marking->is_compacting_); |
| 107 | |
| 108 MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address()); | |
| 109 int counter = chunk->write_barrier_counter(); | |
| 110 if (counter < (MemoryChunk::kWriteBarrierCounterGranularity / 2)) { | |
| 111 marking->write_barriers_invoked_since_last_step_ += | |
| 112 MemoryChunk::kWriteBarrierCounterGranularity - | |
| 113 chunk->write_barrier_counter(); | |
| 114 chunk->set_write_barrier_counter( | |
| 115 MemoryChunk::kWriteBarrierCounterGranularity); | |
| 116 } | |
| 117 | |
| 118 marking->RecordWrite(obj, slot, *slot); | 105 marking->RecordWrite(obj, slot, *slot); |
| 119 } | 106 } |
| 120 | 107 |
| 121 | 108 |
| 122 void IncrementalMarking::RecordCodeTargetPatch(Code* host, | 109 void IncrementalMarking::RecordCodeTargetPatch(Code* host, |
| 123 Address pc, | 110 Address pc, |
| 124 HeapObject* value) { | 111 HeapObject* value) { |
| 125 if (IsMarking()) { | 112 if (IsMarking()) { |
| 126 RelocInfo rinfo(pc, RelocInfo::CODE_TARGET, 0, host); | 113 RelocInfo rinfo(pc, RelocInfo::CODE_TARGET, 0, host); |
| 127 RecordWriteIntoCode(host, &rinfo, value); | 114 RecordWriteIntoCode(host, &rinfo, value); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 183 | 170 |
| 184 table_.Register(kVisitSharedFunctionInfo, &VisitSharedFunctionInfo); | 171 table_.Register(kVisitSharedFunctionInfo, &VisitSharedFunctionInfo); |
| 185 | 172 |
| 186 table_.Register(kVisitJSFunction, &VisitJSFunction); | 173 table_.Register(kVisitJSFunction, &VisitJSFunction); |
| 187 | 174 |
| 188 table_.Register(kVisitJSRegExp, &VisitJSRegExp); | 175 table_.Register(kVisitJSRegExp, &VisitJSRegExp); |
| 189 } | 176 } |
| 190 | 177 |
| 191 static void VisitJSWeakMap(Map* map, HeapObject* object) { | 178 static void VisitJSWeakMap(Map* map, HeapObject* object) { |
| 192 Heap* heap = map->GetHeap(); | 179 Heap* heap = map->GetHeap(); |
| 193 Object** start_slot = | |
| 194 HeapObject::RawField(object, JSWeakMap::kPropertiesOffset); | |
| 195 VisitPointers(heap, | 180 VisitPointers(heap, |
| 196 start_slot, | 181 HeapObject::RawField(object, JSWeakMap::kPropertiesOffset), |
| 197 start_slot, | |
| 198 HeapObject::RawField(object, JSWeakMap::kSize)); | 182 HeapObject::RawField(object, JSWeakMap::kSize)); |
| 199 } | 183 } |
| 200 | 184 |
| 201 static void VisitSharedFunctionInfo(Map* map, HeapObject* object) { | 185 static void VisitSharedFunctionInfo(Map* map, HeapObject* object) { |
| 202 Heap* heap = map->GetHeap(); | 186 Heap* heap = map->GetHeap(); |
| 203 SharedFunctionInfo* shared = SharedFunctionInfo::cast(object); | 187 SharedFunctionInfo* shared = SharedFunctionInfo::cast(object); |
| 204 if (shared->ic_age() != heap->global_ic_age()) { | 188 if (shared->ic_age() != heap->global_ic_age()) { |
| 205 shared->ResetForNewContext(heap->global_ic_age()); | 189 shared->ResetForNewContext(heap->global_ic_age()); |
| 206 } | 190 } |
| 207 FixedBodyVisitor<IncrementalMarkingMarkingVisitor, | 191 FixedBodyVisitor<IncrementalMarkingMarkingVisitor, |
| 208 SharedFunctionInfo::BodyDescriptor, | 192 SharedFunctionInfo::BodyDescriptor, |
| 209 void>::Visit(map, object); | 193 void>::Visit(map, object); |
| 210 } | 194 } |
| 211 | 195 |
| 212 static const int kScanningChunk = 32 * 1024; | |
| 213 | |
| 214 static int VisitHugeArray(FixedArray* array) { | |
| 215 Heap* heap = array->GetHeap(); | |
| 216 MemoryChunk* chunk = MemoryChunk::FromAddress(array->address()); | |
| 217 Object** start_slot = array->data_start(); | |
| 218 int length = array->length(); | |
| 219 | |
| 220 if (chunk->owner()->identity() != LO_SPACE) { | |
| 221 VisitPointers(heap, start_slot, start_slot, start_slot + length); | |
| 222 return length; | |
| 223 } | |
| 224 | |
| 225 int from = | |
| 226 chunk->IsPartiallyScanned() ? chunk->PartiallyScannedProgress() : 0; | |
| 227 int to = Min(from + kScanningChunk, length); | |
| 228 | |
| 229 VisitPointers(heap, start_slot, start_slot + from, start_slot + to); | |
| 230 | |
| 231 if (to == length) { | |
| 232 // If it went from black to grey while it was waiting for the next bit to | |
| 233 // be scanned then we have to start the scan again. | |
| 234 MarkBit mark_bit = Marking::MarkBitFrom(array); | |
| 235 if (!Marking::IsBlack(mark_bit)) { | |
| 236 ASSERT(Marking::IsGrey(mark_bit)); | |
| 237 chunk->SetPartiallyScannedProgress(0); | |
| 238 } else { | |
| 239 chunk->SetCompletelyScanned(); | |
| 240 } | |
| 241 } else { | |
| 242 chunk->SetPartiallyScannedProgress(to); | |
| 243 } | |
| 244 return to - from; | |
| 245 } | |
| 246 | |
| 247 static inline void VisitJSFunction(Map* map, HeapObject* object) { | 196 static inline void VisitJSFunction(Map* map, HeapObject* object) { |
| 248 Heap* heap = map->GetHeap(); | 197 Heap* heap = map->GetHeap(); |
| 249 // Iterate over all fields in the body but take care in dealing with | 198 // Iterate over all fields in the body but take care in dealing with |
| 250 // the code entry and skip weak fields. | 199 // the code entry and skip weak fields. |
| 251 Object** start_slot = | |
| 252 HeapObject::RawField(object, JSFunction::kPropertiesOffset); | |
| 253 VisitPointers(heap, | 200 VisitPointers(heap, |
| 254 start_slot, | 201 HeapObject::RawField(object, JSFunction::kPropertiesOffset), |
| 255 start_slot, | |
| 256 HeapObject::RawField(object, JSFunction::kCodeEntryOffset)); | 202 HeapObject::RawField(object, JSFunction::kCodeEntryOffset)); |
| 257 VisitCodeEntry(heap, object->address() + JSFunction::kCodeEntryOffset); | 203 VisitCodeEntry(heap, object->address() + JSFunction::kCodeEntryOffset); |
| 258 VisitPointers(heap, | 204 VisitPointers(heap, |
| 259 start_slot, | |
| 260 HeapObject::RawField(object, | 205 HeapObject::RawField(object, |
| 261 JSFunction::kCodeEntryOffset + kPointerSize), | 206 JSFunction::kCodeEntryOffset + kPointerSize), |
| 262 HeapObject::RawField(object, | 207 HeapObject::RawField(object, |
| 263 JSFunction::kNonWeakFieldsEndOffset)); | 208 JSFunction::kNonWeakFieldsEndOffset)); |
| 264 } | 209 } |
| 265 | 210 |
| 266 INLINE(static void VisitPointer(Heap* heap, Object** p)) { | 211 INLINE(static void VisitPointer(Heap* heap, Object** p)) { |
| 267 Object* obj = *p; | 212 Object* obj = *p; |
| 268 if (obj->NonFailureIsHeapObject()) { | 213 if (obj->NonFailureIsHeapObject()) { |
| 269 heap->mark_compact_collector()->RecordSlot(p, p, obj); | 214 heap->mark_compact_collector()->RecordSlot(p, p, obj); |
| 270 MarkObject(heap, obj); | 215 MarkObject(heap, obj); |
| 271 } | 216 } |
| 272 } | 217 } |
| 273 | 218 |
| 274 INLINE(static void VisitPointers(Heap* heap, | 219 INLINE(static void VisitPointers(Heap* heap, Object** start, Object** end)) { |
| 275 Object** anchor, | |
| 276 Object** start, | |
| 277 Object** end)) { | |
| 278 for (Object** p = start; p < end; p++) { | 220 for (Object** p = start; p < end; p++) { |
| 279 Object* obj = *p; | 221 Object* obj = *p; |
| 280 if (obj->NonFailureIsHeapObject()) { | 222 if (obj->NonFailureIsHeapObject()) { |
| 281 heap->mark_compact_collector()->RecordSlot(anchor, p, obj); | 223 heap->mark_compact_collector()->RecordSlot(start, p, obj); |
| 282 MarkObject(heap, obj); | 224 MarkObject(heap, obj); |
| 283 } | 225 } |
| 284 } | 226 } |
| 285 } | 227 } |
| 286 | 228 |
| 287 // Marks the object grey and pushes it on the marking stack. | |
| 288 INLINE(static void MarkObject(Heap* heap, Object* obj)) { | 229 INLINE(static void MarkObject(Heap* heap, Object* obj)) { |
| 289 HeapObject* heap_object = HeapObject::cast(obj); | 230 HeapObject* heap_object = HeapObject::cast(obj); |
| 290 MarkBit mark_bit = Marking::MarkBitFrom(heap_object); | 231 MarkBit mark_bit = Marking::MarkBitFrom(heap_object); |
| 291 if (mark_bit.data_only()) { | 232 if (mark_bit.data_only()) { |
| 292 if (heap->incremental_marking()->MarkBlackOrKeepGrey(mark_bit)) { | 233 if (heap->incremental_marking()->MarkBlackOrKeepGrey(mark_bit)) { |
| 293 MemoryChunk::IncrementLiveBytesFromGC(heap_object->address(), | 234 MemoryChunk::IncrementLiveBytesFromGC(heap_object->address(), |
| 294 heap_object->Size()); | 235 heap_object->Size()); |
| 295 } | 236 } |
| 296 } else if (Marking::IsWhite(mark_bit)) { | 237 } else if (Marking::IsWhite(mark_bit)) { |
| 297 heap->incremental_marking()->WhiteToGreyAndPush(heap_object, mark_bit); | 238 heap->incremental_marking()->WhiteToGreyAndPush(heap_object, mark_bit); |
| 298 } | 239 } |
| 299 } | 240 } |
| 300 | |
| 301 // Marks the object black without pushing it on the marking stack. | |
| 302 // Returns true if object needed marking and false otherwise. | |
| 303 INLINE(static bool MarkObjectWithoutPush(Heap* heap, Object* obj)) { | |
| 304 HeapObject* heap_object = HeapObject::cast(obj); | |
| 305 MarkBit mark_bit = Marking::MarkBitFrom(heap_object); | |
| 306 if (Marking::IsWhite(mark_bit)) { | |
| 307 mark_bit.Set(); | |
| 308 MemoryChunk::IncrementLiveBytesFromGC(heap_object->address(), | |
| 309 heap_object->Size()); | |
| 310 return true; | |
| 311 } | |
| 312 return false; | |
| 313 } | |
| 314 }; | 241 }; |
| 315 | 242 |
| 316 | 243 |
| 317 class IncrementalMarkingRootMarkingVisitor : public ObjectVisitor { | 244 class IncrementalMarkingRootMarkingVisitor : public ObjectVisitor { |
| 318 public: | 245 public: |
| 319 IncrementalMarkingRootMarkingVisitor(Heap* heap, | 246 IncrementalMarkingRootMarkingVisitor(Heap* heap, |
| 320 IncrementalMarking* incremental_marking) | 247 IncrementalMarking* incremental_marking) |
| 321 : heap_(heap), | 248 : heap_(heap), |
| 322 incremental_marking_(incremental_marking) { | 249 incremental_marking_(incremental_marking) { |
| 323 } | 250 } |
| (...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 673 } | 600 } |
| 674 } else if (obj->map() != filler_map) { | 601 } else if (obj->map() != filler_map) { |
| 675 // Skip one word filler objects that appear on the | 602 // Skip one word filler objects that appear on the |
| 676 // stack when we perform in place array shift. | 603 // stack when we perform in place array shift. |
| 677 array[new_top] = obj; | 604 array[new_top] = obj; |
| 678 new_top = ((new_top + 1) & mask); | 605 new_top = ((new_top + 1) & mask); |
| 679 ASSERT(new_top != marking_deque_.bottom()); | 606 ASSERT(new_top != marking_deque_.bottom()); |
| 680 #ifdef DEBUG | 607 #ifdef DEBUG |
| 681 MarkBit mark_bit = Marking::MarkBitFrom(obj); | 608 MarkBit mark_bit = Marking::MarkBitFrom(obj); |
| 682 ASSERT(Marking::IsGrey(mark_bit) || | 609 ASSERT(Marking::IsGrey(mark_bit) || |
| 683 (obj->IsFiller() && Marking::IsWhite(mark_bit)) || | 610 (obj->IsFiller() && Marking::IsWhite(mark_bit))); |
| 684 MemoryChunk::FromAddress(obj->address())->IsPartiallyScanned()); | |
| 685 #endif | 611 #endif |
| 686 } | 612 } |
| 687 } | 613 } |
| 688 marking_deque_.set_top(new_top); | 614 marking_deque_.set_top(new_top); |
| 689 | 615 |
| 690 steps_took_since_last_gc_ = 0; | 616 steps_took_since_last_gc_ = 0; |
| 691 steps_count_since_last_gc_ = 0; | 617 steps_count_since_last_gc_ = 0; |
| 692 longest_step_ = 0.0; | 618 longest_step_ = 0.0; |
| 693 } | 619 } |
| 694 | 620 |
| 695 | 621 |
| 696 void IncrementalMarking::Hurry() { | 622 void IncrementalMarking::Hurry() { |
| 697 if (state() == MARKING) { | 623 if (state() == MARKING) { |
| 698 double start = 0.0; | 624 double start = 0.0; |
| 699 if (FLAG_trace_incremental_marking) { | 625 if (FLAG_trace_incremental_marking) { |
| 700 PrintF("[IncrementalMarking] Hurry\n"); | 626 PrintF("[IncrementalMarking] Hurry\n"); |
| 701 start = OS::TimeCurrentMillis(); | 627 start = OS::TimeCurrentMillis(); |
| 702 } | 628 } |
| 703 // TODO(gc) hurry can mark objects it encounters black as mutator | 629 // TODO(gc) hurry can mark objects it encounters black as mutator |
| 704 // was stopped. | 630 // was stopped. |
| 705 Map* filler_map = heap_->one_pointer_filler_map(); | 631 Map* filler_map = heap_->one_pointer_filler_map(); |
| 706 Map* native_context_map = heap_->native_context_map(); | 632 Map* native_context_map = heap_->native_context_map(); |
| 707 do { | 633 while (!marking_deque_.IsEmpty()) { |
| 708 while (!marking_deque_.IsEmpty()) { | 634 HeapObject* obj = marking_deque_.Pop(); |
| 709 HeapObject* obj = marking_deque_.Pop(); | |
| 710 | 635 |
| 711 // Explicitly skip one word fillers. Incremental markbit patterns are | 636 // Explicitly skip one word fillers. Incremental markbit patterns are |
| 712 // correct only for objects that occupy at least two words. | 637 // correct only for objects that occupy at least two words. |
| 713 Map* map = obj->map(); | 638 Map* map = obj->map(); |
| 714 if (map == filler_map) { | 639 if (map == filler_map) { |
| 715 continue; | 640 continue; |
| 716 } else if (map == native_context_map) { | 641 } else if (map == native_context_map) { |
| 717 // Native contexts have weak fields. | 642 // Native contexts have weak fields. |
| 718 IncrementalMarkingMarkingVisitor::VisitNativeContext(map, obj); | 643 IncrementalMarkingMarkingVisitor::VisitNativeContext(map, obj); |
| 719 ASSERT(!Marking::IsBlack(Marking::MarkBitFrom(obj))); | 644 } else if (map->instance_type() == MAP_TYPE) { |
| 720 MemoryChunk::IncrementLiveBytesFromGC(obj->address(), obj->Size()); | 645 Map* map = Map::cast(obj); |
| 721 } else if (map->instance_type() == FIXED_ARRAY_TYPE && | 646 heap_->ClearCacheOnMap(map); |
| 722 FixedArray::cast(obj)->length() > | 647 |
| 723 IncrementalMarkingMarkingVisitor::kScanningChunk) { | 648 // When map collection is enabled we have to mark through map's |
| 724 MarkBit map_mark_bit = Marking::MarkBitFrom(map); | 649 // transitions and back pointers in a special way to make these links |
| 725 if (Marking::IsWhite(map_mark_bit)) { | 650 // weak. Only maps for subclasses of JSReceiver can have transitions. |
| 726 WhiteToGreyAndPush(map, map_mark_bit); | 651 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); |
| 727 } | 652 if (FLAG_collect_maps && |
| 728 MarkBit mark_bit = Marking::MarkBitFrom(obj); | 653 map->instance_type() >= FIRST_JS_RECEIVER_TYPE) { |
| 729 if (!Marking::IsBlack(mark_bit)) { | 654 marker_.MarkMapContents(map); |
| 730 MemoryChunk::IncrementLiveBytesFromGC(obj->address(), obj->Size()); | 655 } else { |
| 731 } else { | 656 IncrementalMarkingMarkingVisitor::VisitPointers( |
| 732 ASSERT( | 657 heap_, |
| 733 MemoryChunk::FromAddress(obj->address())->IsPartiallyScanned()); | 658 HeapObject::RawField(map, Map::kPointerFieldsBeginOffset), |
| 734 } | 659 HeapObject::RawField(map, Map::kPointerFieldsEndOffset)); |
| 735 IncrementalMarkingMarkingVisitor::VisitHugeArray( | |
| 736 FixedArray::cast(obj)); | |
| 737 } else { | |
| 738 MarkBit map_mark_bit = Marking::MarkBitFrom(map); | |
| 739 if (Marking::IsWhite(map_mark_bit)) { | |
| 740 WhiteToGreyAndPush(map, map_mark_bit); | |
| 741 } | |
| 742 IncrementalMarkingMarkingVisitor::IterateBody(map, obj); | |
| 743 ASSERT(!Marking::IsBlack(Marking::MarkBitFrom(obj))); | |
| 744 MemoryChunk::IncrementLiveBytesFromGC(obj->address(), obj->Size()); | |
| 745 } | 660 } |
| 661 } else { |
| 662 MarkBit map_mark_bit = Marking::MarkBitFrom(map); |
| 663 if (Marking::IsWhite(map_mark_bit)) { |
| 664 WhiteToGreyAndPush(map, map_mark_bit); |
| 665 } |
| 666 IncrementalMarkingMarkingVisitor::IterateBody(map, obj); |
| 667 } |
| 746 | 668 |
| 747 MarkBit mark_bit = Marking::MarkBitFrom(obj); | 669 MarkBit mark_bit = Marking::MarkBitFrom(obj); |
| 748 Marking::MarkBlack(mark_bit); | 670 ASSERT(!Marking::IsBlack(mark_bit)); |
| 749 } | 671 Marking::MarkBlack(mark_bit); |
| 750 state_ = COMPLETE; | 672 MemoryChunk::IncrementLiveBytesFromGC(obj->address(), obj->Size()); |
| 751 if (FLAG_trace_incremental_marking) { | 673 } |
| 752 double end = OS::TimeCurrentMillis(); | 674 state_ = COMPLETE; |
| 753 PrintF("[IncrementalMarking] Complete (hurry), spent %d ms.\n", | 675 if (FLAG_trace_incremental_marking) { |
| 754 static_cast<int>(end - start)); | 676 double end = OS::TimeCurrentMillis(); |
| 755 } | 677 PrintF("[IncrementalMarking] Complete (hurry), spent %d ms.\n", |
| 756 MarkCompactCollector::ProcessLargePostponedArrays(heap_, &marking_deque_); | 678 static_cast<int>(end - start)); |
| 757 } while (!marking_deque_.IsEmpty()); | 679 } |
| 758 } | 680 } |
| 759 | 681 |
| 760 if (FLAG_cleanup_code_caches_at_gc) { | 682 if (FLAG_cleanup_code_caches_at_gc) { |
| 761 PolymorphicCodeCache* poly_cache = heap_->polymorphic_code_cache(); | 683 PolymorphicCodeCache* poly_cache = heap_->polymorphic_code_cache(); |
| 762 Marking::GreyToBlack(Marking::MarkBitFrom(poly_cache)); | 684 Marking::GreyToBlack(Marking::MarkBitFrom(poly_cache)); |
| 763 MemoryChunk::IncrementLiveBytesFromGC(poly_cache->address(), | 685 MemoryChunk::IncrementLiveBytesFromGC(poly_cache->address(), |
| 764 PolymorphicCodeCache::kSize); | 686 PolymorphicCodeCache::kSize); |
| 765 } | 687 } |
| 766 | 688 |
| 767 Object* context = heap_->native_contexts_list(); | 689 Object* context = heap_->native_contexts_list(); |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 847 CompletionAction action) { | 769 CompletionAction action) { |
| 848 if (heap_->gc_state() != Heap::NOT_IN_GC || | 770 if (heap_->gc_state() != Heap::NOT_IN_GC || |
| 849 !FLAG_incremental_marking || | 771 !FLAG_incremental_marking || |
| 850 !FLAG_incremental_marking_steps || | 772 !FLAG_incremental_marking_steps || |
| 851 (state_ != SWEEPING && state_ != MARKING)) { | 773 (state_ != SWEEPING && state_ != MARKING)) { |
| 852 return; | 774 return; |
| 853 } | 775 } |
| 854 | 776 |
| 855 allocated_ += allocated_bytes; | 777 allocated_ += allocated_bytes; |
| 856 | 778 |
| 857 if (allocated_ < kAllocatedThreshold && | 779 if (allocated_ < kAllocatedThreshold) return; |
| 858 write_barriers_invoked_since_last_step_ < | |
| 859 kWriteBarriersInvokedThreshold) { | |
| 860 return; | |
| 861 } | |
| 862 | 780 |
| 863 if (state_ == MARKING && no_marking_scope_depth_ > 0) return; | 781 if (state_ == MARKING && no_marking_scope_depth_ > 0) return; |
| 864 | 782 |
| 865 // The marking speed is driven either by the allocation rate or by the rate | 783 intptr_t bytes_to_process = allocated_ * allocation_marking_factor_; |
| 866 // at which we are having to check the color of objects in the write barrier. | |
| 867 // It is possible for a tight non-allocating loop to run a lot of write | |
| 868 // barriers before we get here and check them (marking can only take place on | |
| 869 // allocation), so to reduce the lumpiness we don't use the write barriers | |
| 870 // invoked since last step directly to determine the amount of work to do. | |
| 871 intptr_t bytes_to_process = | |
| 872 marking_speed_ * Max(allocated_, kWriteBarriersInvokedThreshold); | |
| 873 allocated_ = 0; | |
| 874 write_barriers_invoked_since_last_step_ = 0; | |
| 875 | |
| 876 bytes_scanned_ += bytes_to_process; | 784 bytes_scanned_ += bytes_to_process; |
| 877 | 785 |
| 878 double start = 0; | 786 double start = 0; |
| 879 | 787 |
| 880 if (FLAG_trace_incremental_marking || FLAG_trace_gc) { | 788 if (FLAG_trace_incremental_marking || FLAG_trace_gc) { |
| 881 start = OS::TimeCurrentMillis(); | 789 start = OS::TimeCurrentMillis(); |
| 882 } | 790 } |
| 883 | 791 |
| 884 if (state_ == SWEEPING) { | 792 if (state_ == SWEEPING) { |
| 885 if (heap_->AdvanceSweepers(static_cast<int>(bytes_to_process))) { | 793 if (heap_->AdvanceSweepers(static_cast<int>(bytes_to_process))) { |
| 886 bytes_scanned_ = 0; | 794 bytes_scanned_ = 0; |
| 887 StartMarking(PREVENT_COMPACTION); | 795 StartMarking(PREVENT_COMPACTION); |
| 888 } | 796 } |
| 889 } else if (state_ == MARKING) { | 797 } else if (state_ == MARKING) { |
| 890 Map* filler_map = heap_->one_pointer_filler_map(); | 798 Map* filler_map = heap_->one_pointer_filler_map(); |
| 891 Map* native_context_map = heap_->native_context_map(); | 799 Map* native_context_map = heap_->native_context_map(); |
| 892 while (true) { | 800 while (!marking_deque_.IsEmpty() && bytes_to_process > 0) { |
| 893 while (!marking_deque_.IsEmpty() && bytes_to_process > 0) { | 801 HeapObject* obj = marking_deque_.Pop(); |
| 894 HeapObject* obj = marking_deque_.Pop(); | |
| 895 | 802 |
| 896 // Explicitly skip one word fillers. Incremental markbit patterns are | 803 // Explicitly skip one word fillers. Incremental markbit patterns are |
| 897 // correct only for objects that occupy at least two words. | 804 // correct only for objects that occupy at least two words. |
| 898 Map* map = obj->map(); | 805 Map* map = obj->map(); |
| 899 if (map == filler_map) continue; | 806 if (map == filler_map) continue; |
| 900 | 807 |
| 901 int size = obj->SizeFromMap(map); | 808 int size = obj->SizeFromMap(map); |
| 902 MarkBit map_mark_bit = Marking::MarkBitFrom(map); | 809 bytes_to_process -= size; |
| 903 if (Marking::IsWhite(map_mark_bit)) { | 810 MarkBit map_mark_bit = Marking::MarkBitFrom(map); |
| 904 WhiteToGreyAndPush(map, map_mark_bit); | 811 if (Marking::IsWhite(map_mark_bit)) { |
| 812 WhiteToGreyAndPush(map, map_mark_bit); |
| 813 } |
| 814 |
| 815 // TODO(gc) switch to static visitor instead of normal visitor. |
| 816 if (map == native_context_map) { |
| 817 // Native contexts have weak fields. |
| 818 Context* ctx = Context::cast(obj); |
| 819 |
| 820 // We will mark cache black with a separate pass |
| 821 // when we finish marking. |
| 822 MarkObjectGreyDoNotEnqueue(ctx->normalized_map_cache()); |
| 823 |
| 824 IncrementalMarkingMarkingVisitor::VisitNativeContext(map, ctx); |
| 825 } else if (map->instance_type() == MAP_TYPE) { |
| 826 Map* map = Map::cast(obj); |
| 827 heap_->ClearCacheOnMap(map); |
| 828 |
| 829 // When map collection is enabled we have to mark through map's |
| 830 // transitions and back pointers in a special way to make these links |
| 831 // weak. Only maps for subclasses of JSReceiver can have transitions. |
| 832 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); |
| 833 if (FLAG_collect_maps && |
| 834 map->instance_type() >= FIRST_JS_RECEIVER_TYPE) { |
| 835 marker_.MarkMapContents(map); |
| 836 } else { |
| 837 IncrementalMarkingMarkingVisitor::VisitPointers( |
| 838 heap_, |
| 839 HeapObject::RawField(map, Map::kPointerFieldsBeginOffset), |
| 840 HeapObject::RawField(map, Map::kPointerFieldsEndOffset)); |
| 905 } | 841 } |
| 842 } else { |
| 843 IncrementalMarkingMarkingVisitor::IterateBody(map, obj); |
| 844 } |
| 906 | 845 |
| 907 // TODO(gc) switch to static visitor instead of normal visitor. | 846 MarkBit obj_mark_bit = Marking::MarkBitFrom(obj); |
| 908 if (map == native_context_map) { | 847 SLOW_ASSERT(Marking::IsGrey(obj_mark_bit) || |
| 909 // Native contexts have weak fields. | 848 (obj->IsFiller() && Marking::IsWhite(obj_mark_bit))); |
| 910 Context* ctx = Context::cast(obj); | 849 Marking::MarkBlack(obj_mark_bit); |
| 850 MemoryChunk::IncrementLiveBytesFromGC(obj->address(), size); |
| 851 } |
| 852 if (marking_deque_.IsEmpty()) MarkingComplete(action); |
| 853 } |
| 911 | 854 |
| 912 // We will mark cache black with a separate pass | 855 allocated_ = 0; |
| 913 // when we finish marking. | |
| 914 MarkObjectGreyDoNotEnqueue(ctx->normalized_map_cache()); | |
| 915 | |
| 916 IncrementalMarkingMarkingVisitor::VisitNativeContext(map, ctx); | |
| 917 bytes_to_process -= size; | |
| 918 SLOW_ASSERT(Marking::IsGrey(Marking::MarkBitFrom(obj))); | |
| 919 MemoryChunk::IncrementLiveBytesFromGC(obj->address(), size); | |
| 920 } else if (map->instance_type() == FIXED_ARRAY_TYPE && | |
| 921 FixedArray::cast(obj)->length() > | |
| 922 IncrementalMarkingMarkingVisitor::kScanningChunk) { | |
| 923 SLOW_ASSERT( | |
| 924 Marking::IsGrey(Marking::MarkBitFrom(obj)) || | |
| 925 MemoryChunk::FromAddress(obj->address())->IsPartiallyScanned()); | |
| 926 bytes_to_process -= | |
| 927 IncrementalMarkingMarkingVisitor::VisitHugeArray( | |
| 928 FixedArray::cast(obj)); | |
| 929 MarkBit obj_mark_bit = Marking::MarkBitFrom(obj); | |
| 930 if (!Marking::IsBlack(obj_mark_bit)) { | |
| 931 MemoryChunk::IncrementLiveBytesFromGC(obj->address(), size); | |
| 932 } | |
| 933 } else { | |
| 934 IncrementalMarkingMarkingVisitor::IterateBody(map, obj); | |
| 935 bytes_to_process -= size; | |
| 936 SLOW_ASSERT( | |
| 937 Marking::IsGrey(Marking::MarkBitFrom(obj)) || | |
| 938 (obj->IsFiller() && Marking::IsWhite(Marking::MarkBitFrom(obj)))); | |
| 939 MemoryChunk::IncrementLiveBytesFromGC(obj->address(), size); | |
| 940 } | |
| 941 | |
| 942 MarkBit obj_mark_bit = Marking::MarkBitFrom(obj); | |
| 943 Marking::MarkBlack(obj_mark_bit); | |
| 944 } | |
| 945 if (marking_deque_.IsEmpty()) { | |
| 946 MarkCompactCollector::ProcessLargePostponedArrays(heap_, | |
| 947 &marking_deque_); | |
| 948 if (marking_deque_.IsEmpty()) { | |
| 949 MarkingComplete(action); | |
| 950 break; | |
| 951 } | |
| 952 } else { | |
| 953 ASSERT(bytes_to_process <= 0); | |
| 954 break; | |
| 955 } | |
| 956 } | |
| 957 } | |
| 958 | 856 |
| 959 steps_count_++; | 857 steps_count_++; |
| 960 steps_count_since_last_gc_++; | 858 steps_count_since_last_gc_++; |
| 961 | 859 |
| 962 bool speed_up = false; | 860 bool speed_up = false; |
| 963 | 861 |
| 964 if ((steps_count_ % kMarkingSpeedAccellerationInterval) == 0) { | 862 if ((steps_count_ % kAllocationMarkingFactorSpeedupInterval) == 0) { |
| 965 if (FLAG_trace_gc) { | 863 if (FLAG_trace_gc) { |
| 966 PrintPID("Speed up marking after %d steps\n", | 864 PrintPID("Speed up marking after %d steps\n", |
| 967 static_cast<int>(kMarkingSpeedAccellerationInterval)); | 865 static_cast<int>(kAllocationMarkingFactorSpeedupInterval)); |
| 968 } | 866 } |
| 969 speed_up = true; | 867 speed_up = true; |
| 970 } | 868 } |
| 971 | 869 |
| 972 bool space_left_is_very_small = | 870 bool space_left_is_very_small = |
| 973 (old_generation_space_available_at_start_of_incremental_ < 10 * MB); | 871 (old_generation_space_available_at_start_of_incremental_ < 10 * MB); |
| 974 | 872 |
| 975 bool only_1_nth_of_space_that_was_available_still_left = | 873 bool only_1_nth_of_space_that_was_available_still_left = |
| 976 (SpaceLeftInOldSpace() * (marking_speed_ + 1) < | 874 (SpaceLeftInOldSpace() * (allocation_marking_factor_ + 1) < |
| 977 old_generation_space_available_at_start_of_incremental_); | 875 old_generation_space_available_at_start_of_incremental_); |
| 978 | 876 |
| 979 if (space_left_is_very_small || | 877 if (space_left_is_very_small || |
| 980 only_1_nth_of_space_that_was_available_still_left) { | 878 only_1_nth_of_space_that_was_available_still_left) { |
| 981 if (FLAG_trace_gc) PrintPID("Speed up marking because of low space left\n"); | 879 if (FLAG_trace_gc) PrintPID("Speed up marking because of low space left\n"); |
| 982 speed_up = true; | 880 speed_up = true; |
| 983 } | 881 } |
| 984 | 882 |
| 985 bool size_of_old_space_multiplied_by_n_during_marking = | 883 bool size_of_old_space_multiplied_by_n_during_marking = |
| 986 (heap_->PromotedTotalSize() > | 884 (heap_->PromotedTotalSize() > |
| 987 (marking_speed_ + 1) * | 885 (allocation_marking_factor_ + 1) * |
| 988 old_generation_space_used_at_start_of_incremental_); | 886 old_generation_space_used_at_start_of_incremental_); |
| 989 if (size_of_old_space_multiplied_by_n_during_marking) { | 887 if (size_of_old_space_multiplied_by_n_during_marking) { |
| 990 speed_up = true; | 888 speed_up = true; |
| 991 if (FLAG_trace_gc) { | 889 if (FLAG_trace_gc) { |
| 992 PrintPID("Speed up marking because of heap size increase\n"); | 890 PrintPID("Speed up marking because of heap size increase\n"); |
| 993 } | 891 } |
| 994 } | 892 } |
| 995 | 893 |
| 996 int64_t promoted_during_marking = heap_->PromotedTotalSize() | 894 int64_t promoted_during_marking = heap_->PromotedTotalSize() |
| 997 - old_generation_space_used_at_start_of_incremental_; | 895 - old_generation_space_used_at_start_of_incremental_; |
| 998 intptr_t delay = marking_speed_ * MB; | 896 intptr_t delay = allocation_marking_factor_ * MB; |
| 999 intptr_t scavenge_slack = heap_->MaxSemiSpaceSize(); | 897 intptr_t scavenge_slack = heap_->MaxSemiSpaceSize(); |
| 1000 | 898 |
| 1001 // We try to scan at at least twice the speed that we are allocating. | 899 // We try to scan at at least twice the speed that we are allocating. |
| 1002 if (promoted_during_marking > bytes_scanned_ / 2 + scavenge_slack + delay) { | 900 if (promoted_during_marking > bytes_scanned_ / 2 + scavenge_slack + delay) { |
| 1003 if (FLAG_trace_gc) { | 901 if (FLAG_trace_gc) { |
| 1004 PrintPID("Speed up marking because marker was not keeping up\n"); | 902 PrintPID("Speed up marking because marker was not keeping up\n"); |
| 1005 } | 903 } |
| 1006 speed_up = true; | 904 speed_up = true; |
| 1007 } | 905 } |
| 1008 | 906 |
| 1009 if (speed_up) { | 907 if (speed_up) { |
| 1010 if (state_ != MARKING) { | 908 if (state_ != MARKING) { |
| 1011 if (FLAG_trace_gc) { | 909 if (FLAG_trace_gc) { |
| 1012 PrintPID("Postponing speeding up marking until marking starts\n"); | 910 PrintPID("Postponing speeding up marking until marking starts\n"); |
| 1013 } | 911 } |
| 1014 } else { | 912 } else { |
| 1015 marking_speed_ += kMarkingSpeedAccellerationInterval; | 913 allocation_marking_factor_ += kAllocationMarkingFactorSpeedup; |
| 1016 marking_speed_ = static_cast<int>( | 914 allocation_marking_factor_ = static_cast<int>( |
| 1017 Min(kMaxMarkingSpeed, | 915 Min(kMaxAllocationMarkingFactor, |
| 1018 static_cast<intptr_t>(marking_speed_ * 1.3))); | 916 static_cast<intptr_t>(allocation_marking_factor_ * 1.3))); |
| 1019 if (FLAG_trace_gc) { | 917 if (FLAG_trace_gc) { |
| 1020 PrintPID("Marking speed increased to %d\n", marking_speed_); | 918 PrintPID("Marking speed increased to %d\n", allocation_marking_factor_); |
| 1021 } | 919 } |
| 1022 } | 920 } |
| 1023 } | 921 } |
| 1024 | 922 |
| 1025 if (FLAG_trace_incremental_marking || FLAG_trace_gc) { | 923 if (FLAG_trace_incremental_marking || FLAG_trace_gc) { |
| 1026 double end = OS::TimeCurrentMillis(); | 924 double end = OS::TimeCurrentMillis(); |
| 1027 double delta = (end - start); | 925 double delta = (end - start); |
| 1028 longest_step_ = Max(longest_step_, delta); | 926 longest_step_ = Max(longest_step_, delta); |
| 1029 steps_took_ += delta; | 927 steps_took_ += delta; |
| 1030 steps_took_since_last_gc_ += delta; | 928 steps_took_since_last_gc_ += delta; |
| 1031 } | 929 } |
| 1032 } | 930 } |
| 1033 | 931 |
| 1034 | 932 |
| 1035 void IncrementalMarking::ResetStepCounters() { | 933 void IncrementalMarking::ResetStepCounters() { |
| 1036 steps_count_ = 0; | 934 steps_count_ = 0; |
| 1037 steps_took_ = 0; | 935 steps_took_ = 0; |
| 1038 longest_step_ = 0.0; | 936 longest_step_ = 0.0; |
| 1039 old_generation_space_available_at_start_of_incremental_ = | 937 old_generation_space_available_at_start_of_incremental_ = |
| 1040 SpaceLeftInOldSpace(); | 938 SpaceLeftInOldSpace(); |
| 1041 old_generation_space_used_at_start_of_incremental_ = | 939 old_generation_space_used_at_start_of_incremental_ = |
| 1042 heap_->PromotedTotalSize(); | 940 heap_->PromotedTotalSize(); |
| 1043 steps_count_since_last_gc_ = 0; | 941 steps_count_since_last_gc_ = 0; |
| 1044 steps_took_since_last_gc_ = 0; | 942 steps_took_since_last_gc_ = 0; |
| 1045 bytes_rescanned_ = 0; | 943 bytes_rescanned_ = 0; |
| 1046 marking_speed_ = kInitialMarkingSpeed; | 944 allocation_marking_factor_ = kInitialAllocationMarkingFactor; |
| 1047 bytes_scanned_ = 0; | 945 bytes_scanned_ = 0; |
| 1048 write_barriers_invoked_since_last_step_ = 0; | |
| 1049 } | 946 } |
| 1050 | 947 |
| 1051 | 948 |
| 1052 int64_t IncrementalMarking::SpaceLeftInOldSpace() { | 949 int64_t IncrementalMarking::SpaceLeftInOldSpace() { |
| 1053 return heap_->MaxOldGenerationSize() - heap_->PromotedSpaceSizeOfObjects(); | 950 return heap_->MaxOldGenerationSize() - heap_->PromotedSpaceSizeOfObjects(); |
| 1054 } | 951 } |
| 1055 | 952 |
| 1056 } } // namespace v8::internal | 953 } } // namespace v8::internal |
| OLD | NEW |