blob: e2fca5b1a08059fea4eb213bbf65f7f1b6525581 [file] [log] [blame]
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001// Copyright 2012 the V8 project authors. All rights reserved.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "incremental-marking.h"
31
32#include "code-stubs.h"
33#include "compilation-cache.h"
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +000034#include "objects-visiting.h"
35#include "objects-visiting-inl.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000036#include "v8conversions.h"
37
38namespace v8 {
39namespace internal {
40
41
42IncrementalMarking::IncrementalMarking(Heap* heap)
43 : heap_(heap),
44 state_(STOPPED),
45 marking_deque_memory_(NULL),
danno@chromium.orgc612e022011-11-10 11:38:15 +000046 marking_deque_memory_committed_(false),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000047 steps_count_(0),
48 steps_took_(0),
49 longest_step_(0.0),
50 old_generation_space_available_at_start_of_incremental_(0),
51 old_generation_space_used_at_start_of_incremental_(0),
52 steps_count_since_last_gc_(0),
53 steps_took_since_last_gc_(0),
54 should_hurry_(false),
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000055 marking_speed_(0),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000056 allocated_(0),
57 no_marking_scope_depth_(0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000058}
59
60
61void IncrementalMarking::TearDown() {
62 delete marking_deque_memory_;
63}
64
65
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000066void IncrementalMarking::RecordWriteSlow(HeapObject* obj,
67 Object** slot,
68 Object* value) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +000069 if (BaseRecordWrite(obj, slot, value) && slot != NULL) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000070 MarkBit obj_bit = Marking::MarkBitFrom(obj);
71 if (Marking::IsBlack(obj_bit)) {
72 // Object is not going to be rescanned we need to record the slot.
73 heap_->mark_compact_collector()->RecordSlot(
74 HeapObject::RawField(obj, 0), slot, value);
75 }
76 }
77}
78
79
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000080void IncrementalMarking::RecordWriteFromCode(HeapObject* obj,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000081 Object** slot,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000082 Isolate* isolate) {
83 ASSERT(obj->IsHeapObject());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000084 IncrementalMarking* marking = isolate->heap()->incremental_marking();
85 ASSERT(!marking->is_compacting_);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000086
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
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000097 marking->RecordWrite(obj, slot, *slot);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000098}
99
100
101void IncrementalMarking::RecordWriteForEvacuationFromCode(HeapObject* obj,
102 Object** slot,
103 Isolate* isolate) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000104 ASSERT(obj->IsHeapObject());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000105 IncrementalMarking* marking = isolate->heap()->incremental_marking();
106 ASSERT(marking->is_compacting_);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000107
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
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000118 marking->RecordWrite(obj, slot, *slot);
119}
120
121
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000122void IncrementalMarking::RecordCodeTargetPatch(Code* host,
123 Address pc,
124 HeapObject* value) {
125 if (IsMarking()) {
126 RelocInfo rinfo(pc, RelocInfo::CODE_TARGET, 0, host);
127 RecordWriteIntoCode(host, &rinfo, value);
128 }
129}
130
131
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000132void IncrementalMarking::RecordCodeTargetPatch(Address pc, HeapObject* value) {
133 if (IsMarking()) {
134 Code* host = heap_->isolate()->inner_pointer_to_code_cache()->
135 GcSafeFindCodeForInnerPointer(pc);
136 RelocInfo rinfo(pc, RelocInfo::CODE_TARGET, 0, host);
137 RecordWriteIntoCode(host, &rinfo, value);
138 }
139}
140
141
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000142void IncrementalMarking::RecordWriteOfCodeEntrySlow(JSFunction* host,
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000143 Object** slot,
144 Code* value) {
145 if (BaseRecordWrite(host, slot, value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000146 ASSERT(slot != NULL);
147 heap_->mark_compact_collector()->
148 RecordCodeEntrySlot(reinterpret_cast<Address>(slot), value);
149 }
150}
151
152
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000153void IncrementalMarking::RecordWriteIntoCodeSlow(HeapObject* obj,
154 RelocInfo* rinfo,
155 Object* value) {
156 MarkBit value_bit = Marking::MarkBitFrom(HeapObject::cast(value));
157 if (Marking::IsWhite(value_bit)) {
158 MarkBit obj_bit = Marking::MarkBitFrom(obj);
159 if (Marking::IsBlack(obj_bit)) {
160 BlackToGreyAndUnshift(obj, obj_bit);
161 RestartIfNotMarking();
162 }
163 // Object is either grey or white. It will be scanned if survives.
164 return;
165 }
166
167 if (is_compacting_) {
168 MarkBit obj_bit = Marking::MarkBitFrom(obj);
169 if (Marking::IsBlack(obj_bit)) {
170 // Object is not going to be rescanned. We need to record the slot.
171 heap_->mark_compact_collector()->RecordRelocSlot(rinfo,
172 Code::cast(value));
173 }
174 }
175}
176
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000177
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000178static void MarkObjectGreyDoNotEnqueue(Object* obj) {
179 if (obj->IsHeapObject()) {
180 HeapObject* heap_obj = HeapObject::cast(obj);
181 MarkBit mark_bit = Marking::MarkBitFrom(HeapObject::cast(obj));
182 if (Marking::IsBlack(mark_bit)) {
183 MemoryChunk::IncrementLiveBytesFromGC(heap_obj->address(),
184 -heap_obj->Size());
185 }
186 Marking::AnyToGrey(mark_bit);
187 }
188}
189
190
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000191static inline void MarkBlackOrKeepGrey(HeapObject* heap_object,
192 MarkBit mark_bit,
193 int size) {
194 ASSERT(!Marking::IsImpossible(mark_bit));
195 if (mark_bit.Get()) return;
196 mark_bit.Set();
197 MemoryChunk::IncrementLiveBytesFromGC(heap_object->address(), size);
198 ASSERT(Marking::IsBlack(mark_bit));
199}
200
201
202static inline void MarkBlackOrKeepBlack(HeapObject* heap_object,
203 MarkBit mark_bit,
204 int size) {
205 ASSERT(!Marking::IsImpossible(mark_bit));
206 if (Marking::IsBlack(mark_bit)) return;
207 Marking::MarkBlack(mark_bit);
208 MemoryChunk::IncrementLiveBytesFromGC(heap_object->address(), size);
209 ASSERT(Marking::IsBlack(mark_bit));
210}
211
212
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +0000213class IncrementalMarkingMarkingVisitor
214 : public StaticMarkingVisitor<IncrementalMarkingMarkingVisitor> {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000215 public:
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +0000216 static void Initialize() {
217 StaticMarkingVisitor<IncrementalMarkingMarkingVisitor>::Initialize();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000218 table_.Register(kVisitFixedArray, &VisitFixedArrayIncremental);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000219 table_.Register(kVisitNativeContext, &VisitNativeContextIncremental);
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +0000220 table_.Register(kVisitJSRegExp, &VisitJSRegExp);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000221 }
222
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000223 static const int kProgressBarScanningChunk = 32 * 1024;
224
225 static void VisitFixedArrayIncremental(Map* map, HeapObject* object) {
226 MemoryChunk* chunk = MemoryChunk::FromAddress(object->address());
227 // TODO(mstarzinger): Move setting of the flag to the allocation site of
228 // the array. The visitor should just check the flag.
229 if (FLAG_use_marking_progress_bar &&
230 chunk->owner()->identity() == LO_SPACE) {
231 chunk->SetFlag(MemoryChunk::HAS_PROGRESS_BAR);
232 }
233 if (chunk->IsFlagSet(MemoryChunk::HAS_PROGRESS_BAR)) {
234 Heap* heap = map->GetHeap();
235 // When using a progress bar for large fixed arrays, scan only a chunk of
236 // the array and try to push it onto the marking deque again until it is
237 // fully scanned. Fall back to scanning it through to the end in case this
238 // fails because of a full deque.
239 int object_size = FixedArray::BodyDescriptor::SizeOf(map, object);
240 int start_offset = Max(FixedArray::BodyDescriptor::kStartOffset,
241 chunk->progress_bar());
242 int end_offset = Min(object_size,
243 start_offset + kProgressBarScanningChunk);
244 bool scan_until_end = false;
245 do {
246 VisitPointersWithAnchor(heap,
247 HeapObject::RawField(object, 0),
248 HeapObject::RawField(object, start_offset),
249 HeapObject::RawField(object, end_offset));
250 start_offset = end_offset;
251 end_offset = Min(object_size, end_offset + kProgressBarScanningChunk);
252 scan_until_end = heap->incremental_marking()->marking_deque()->IsFull();
253 } while (scan_until_end && start_offset < object_size);
254 chunk->set_progress_bar(start_offset);
255 if (start_offset < object_size) {
256 heap->incremental_marking()->marking_deque()->UnshiftGrey(object);
257 }
258 } else {
259 FixedArrayVisitor::Visit(map, object);
260 }
261 }
262
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000263 static void VisitNativeContextIncremental(Map* map, HeapObject* object) {
264 Context* context = Context::cast(object);
265
266 // We will mark cache black with a separate pass
267 // when we finish marking.
268 MarkObjectGreyDoNotEnqueue(context->normalized_map_cache());
269 VisitNativeContext(map, context);
270 }
271
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +0000272 static void VisitJSWeakMap(Map* map, HeapObject* object) {
273 Heap* heap = map->GetHeap();
274 VisitPointers(heap,
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +0000275 HeapObject::RawField(object, JSWeakMap::kPropertiesOffset),
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +0000276 HeapObject::RawField(object, JSWeakMap::kSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000277 }
278
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000279 static void BeforeVisitingSharedFunctionInfo(HeapObject* object) {}
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +0000280
281 INLINE(static void VisitPointer(Heap* heap, Object** p)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000282 Object* obj = *p;
283 if (obj->NonFailureIsHeapObject()) {
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +0000284 heap->mark_compact_collector()->RecordSlot(p, p, obj);
285 MarkObject(heap, obj);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000286 }
287 }
288
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +0000289 INLINE(static void VisitPointers(Heap* heap, Object** start, Object** end)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000290 for (Object** p = start; p < end; p++) {
291 Object* obj = *p;
292 if (obj->NonFailureIsHeapObject()) {
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +0000293 heap->mark_compact_collector()->RecordSlot(start, p, obj);
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +0000294 MarkObject(heap, obj);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000295 }
296 }
297 }
298
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000299 INLINE(static void VisitPointersWithAnchor(Heap* heap,
300 Object** anchor,
301 Object** start,
302 Object** end)) {
303 for (Object** p = start; p < end; p++) {
304 Object* obj = *p;
305 if (obj->NonFailureIsHeapObject()) {
306 heap->mark_compact_collector()->RecordSlot(anchor, p, obj);
307 MarkObject(heap, obj);
308 }
309 }
310 }
311
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000312 // Marks the object grey and pushes it on the marking stack.
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +0000313 INLINE(static void MarkObject(Heap* heap, Object* obj)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000314 HeapObject* heap_object = HeapObject::cast(obj);
315 MarkBit mark_bit = Marking::MarkBitFrom(heap_object);
316 if (mark_bit.data_only()) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000317 MarkBlackOrKeepGrey(heap_object, mark_bit, heap_object->Size());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000318 } else if (Marking::IsWhite(mark_bit)) {
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +0000319 heap->incremental_marking()->WhiteToGreyAndPush(heap_object, mark_bit);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000320 }
321 }
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000322
323 // Marks the object black without pushing it on the marking stack.
324 // Returns true if object needed marking and false otherwise.
325 INLINE(static bool MarkObjectWithoutPush(Heap* heap, Object* obj)) {
326 HeapObject* heap_object = HeapObject::cast(obj);
327 MarkBit mark_bit = Marking::MarkBitFrom(heap_object);
328 if (Marking::IsWhite(mark_bit)) {
329 mark_bit.Set();
330 MemoryChunk::IncrementLiveBytesFromGC(heap_object->address(),
331 heap_object->Size());
332 return true;
333 }
334 return false;
335 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000336};
337
338
339class IncrementalMarkingRootMarkingVisitor : public ObjectVisitor {
340 public:
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000341 explicit IncrementalMarkingRootMarkingVisitor(
342 IncrementalMarking* incremental_marking)
343 : incremental_marking_(incremental_marking) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000344 }
345
346 void VisitPointer(Object** p) {
347 MarkObjectByPointer(p);
348 }
349
350 void VisitPointers(Object** start, Object** end) {
351 for (Object** p = start; p < end; p++) MarkObjectByPointer(p);
352 }
353
354 private:
355 void MarkObjectByPointer(Object** p) {
356 Object* obj = *p;
357 if (!obj->IsHeapObject()) return;
358
359 HeapObject* heap_object = HeapObject::cast(obj);
360 MarkBit mark_bit = Marking::MarkBitFrom(heap_object);
361 if (mark_bit.data_only()) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000362 MarkBlackOrKeepGrey(heap_object, mark_bit, heap_object->Size());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000363 } else {
364 if (Marking::IsWhite(mark_bit)) {
365 incremental_marking_->WhiteToGreyAndPush(heap_object, mark_bit);
366 }
367 }
368 }
369
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000370 IncrementalMarking* incremental_marking_;
371};
372
373
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +0000374void IncrementalMarking::Initialize() {
375 IncrementalMarkingMarkingVisitor::Initialize();
376}
377
378
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000379void IncrementalMarking::SetOldSpacePageFlags(MemoryChunk* chunk,
380 bool is_marking,
381 bool is_compacting) {
382 if (is_marking) {
383 chunk->SetFlag(MemoryChunk::POINTERS_TO_HERE_ARE_INTERESTING);
384 chunk->SetFlag(MemoryChunk::POINTERS_FROM_HERE_ARE_INTERESTING);
385
386 // It's difficult to filter out slots recorded for large objects.
387 if (chunk->owner()->identity() == LO_SPACE &&
388 chunk->size() > static_cast<size_t>(Page::kPageSize) &&
389 is_compacting) {
390 chunk->SetFlag(MemoryChunk::RESCAN_ON_EVACUATION);
391 }
392 } else if (chunk->owner()->identity() == CELL_SPACE ||
393 chunk->scan_on_scavenge()) {
394 chunk->ClearFlag(MemoryChunk::POINTERS_TO_HERE_ARE_INTERESTING);
395 chunk->ClearFlag(MemoryChunk::POINTERS_FROM_HERE_ARE_INTERESTING);
396 } else {
397 chunk->ClearFlag(MemoryChunk::POINTERS_TO_HERE_ARE_INTERESTING);
398 chunk->SetFlag(MemoryChunk::POINTERS_FROM_HERE_ARE_INTERESTING);
399 }
400}
401
402
403void IncrementalMarking::SetNewSpacePageFlags(NewSpacePage* chunk,
404 bool is_marking) {
405 chunk->SetFlag(MemoryChunk::POINTERS_TO_HERE_ARE_INTERESTING);
406 if (is_marking) {
407 chunk->SetFlag(MemoryChunk::POINTERS_FROM_HERE_ARE_INTERESTING);
408 } else {
409 chunk->ClearFlag(MemoryChunk::POINTERS_FROM_HERE_ARE_INTERESTING);
410 }
411 chunk->SetFlag(MemoryChunk::SCAN_ON_SCAVENGE);
412}
413
414
415void IncrementalMarking::DeactivateIncrementalWriteBarrierForSpace(
416 PagedSpace* space) {
417 PageIterator it(space);
418 while (it.has_next()) {
419 Page* p = it.next();
420 SetOldSpacePageFlags(p, false, false);
421 }
422}
423
424
425void IncrementalMarking::DeactivateIncrementalWriteBarrierForSpace(
426 NewSpace* space) {
427 NewSpacePageIterator it(space);
428 while (it.has_next()) {
429 NewSpacePage* p = it.next();
430 SetNewSpacePageFlags(p, false);
431 }
432}
433
434
435void IncrementalMarking::DeactivateIncrementalWriteBarrier() {
436 DeactivateIncrementalWriteBarrierForSpace(heap_->old_pointer_space());
437 DeactivateIncrementalWriteBarrierForSpace(heap_->old_data_space());
438 DeactivateIncrementalWriteBarrierForSpace(heap_->cell_space());
439 DeactivateIncrementalWriteBarrierForSpace(heap_->map_space());
440 DeactivateIncrementalWriteBarrierForSpace(heap_->code_space());
441 DeactivateIncrementalWriteBarrierForSpace(heap_->new_space());
442
443 LargePage* lop = heap_->lo_space()->first_page();
444 while (lop->is_valid()) {
445 SetOldSpacePageFlags(lop, false, false);
446 lop = lop->next_page();
447 }
448}
449
450
451void IncrementalMarking::ActivateIncrementalWriteBarrier(PagedSpace* space) {
452 PageIterator it(space);
453 while (it.has_next()) {
454 Page* p = it.next();
455 SetOldSpacePageFlags(p, true, is_compacting_);
456 }
457}
458
459
460void IncrementalMarking::ActivateIncrementalWriteBarrier(NewSpace* space) {
461 NewSpacePageIterator it(space->ToSpaceStart(), space->ToSpaceEnd());
462 while (it.has_next()) {
463 NewSpacePage* p = it.next();
464 SetNewSpacePageFlags(p, true);
465 }
466}
467
468
469void IncrementalMarking::ActivateIncrementalWriteBarrier() {
470 ActivateIncrementalWriteBarrier(heap_->old_pointer_space());
471 ActivateIncrementalWriteBarrier(heap_->old_data_space());
472 ActivateIncrementalWriteBarrier(heap_->cell_space());
473 ActivateIncrementalWriteBarrier(heap_->map_space());
474 ActivateIncrementalWriteBarrier(heap_->code_space());
475 ActivateIncrementalWriteBarrier(heap_->new_space());
476
477 LargePage* lop = heap_->lo_space()->first_page();
478 while (lop->is_valid()) {
479 SetOldSpacePageFlags(lop, true, is_compacting_);
480 lop = lop->next_page();
481 }
482}
483
484
485bool IncrementalMarking::WorthActivating() {
486#ifndef DEBUG
487 static const intptr_t kActivationThreshold = 8 * MB;
488#else
489 // TODO(gc) consider setting this to some low level so that some
490 // debug tests run with incremental marking and some without.
491 static const intptr_t kActivationThreshold = 0;
492#endif
493
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000494 return !FLAG_expose_gc &&
495 FLAG_incremental_marking &&
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000496 !Serializer::enabled() &&
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000497 heap_->PromotedSpaceSizeOfObjects() > kActivationThreshold;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000498}
499
500
501void IncrementalMarking::ActivateGeneratedStub(Code* stub) {
502 ASSERT(RecordWriteStub::GetMode(stub) ==
503 RecordWriteStub::STORE_BUFFER_ONLY);
504
505 if (!IsMarking()) {
506 // Initially stub is generated in STORE_BUFFER_ONLY mode thus
507 // we don't need to do anything if incremental marking is
508 // not active.
509 } else if (IsCompacting()) {
510 RecordWriteStub::Patch(stub, RecordWriteStub::INCREMENTAL_COMPACTION);
511 } else {
512 RecordWriteStub::Patch(stub, RecordWriteStub::INCREMENTAL);
513 }
514}
515
516
517static void PatchIncrementalMarkingRecordWriteStubs(
518 Heap* heap, RecordWriteStub::Mode mode) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000519 UnseededNumberDictionary* stubs = heap->code_stubs();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000520
521 int capacity = stubs->Capacity();
522 for (int i = 0; i < capacity; i++) {
523 Object* k = stubs->KeyAt(i);
524 if (stubs->IsKey(k)) {
525 uint32_t key = NumberToUint32(k);
526
527 if (CodeStub::MajorKeyFromKey(key) ==
528 CodeStub::RecordWrite) {
529 Object* e = stubs->ValueAt(i);
530 if (e->IsCode()) {
531 RecordWriteStub::Patch(Code::cast(e), mode);
532 }
533 }
534 }
535 }
536}
537
538
539void IncrementalMarking::EnsureMarkingDequeIsCommitted() {
540 if (marking_deque_memory_ == NULL) {
541 marking_deque_memory_ = new VirtualMemory(4 * MB);
danno@chromium.orgc612e022011-11-10 11:38:15 +0000542 }
543 if (!marking_deque_memory_committed_) {
544 bool success = marking_deque_memory_->Commit(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000545 reinterpret_cast<Address>(marking_deque_memory_->address()),
546 marking_deque_memory_->size(),
547 false); // Not executable.
danno@chromium.orgc612e022011-11-10 11:38:15 +0000548 CHECK(success);
549 marking_deque_memory_committed_ = true;
550 }
551}
552
553void IncrementalMarking::UncommitMarkingDeque() {
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000554 if (state_ == STOPPED && marking_deque_memory_committed_) {
danno@chromium.orgc612e022011-11-10 11:38:15 +0000555 bool success = marking_deque_memory_->Uncommit(
556 reinterpret_cast<Address>(marking_deque_memory_->address()),
557 marking_deque_memory_->size());
558 CHECK(success);
559 marking_deque_memory_committed_ = false;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000560 }
561}
562
563
564void IncrementalMarking::Start() {
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +0000565 ASSERT(!heap_->mark_compact_collector()->IsConcurrentSweepingInProgress());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000566 if (FLAG_trace_incremental_marking) {
567 PrintF("[IncrementalMarking] Start\n");
568 }
569 ASSERT(FLAG_incremental_marking);
570 ASSERT(state_ == STOPPED);
571
572 ResetStepCounters();
573
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +0000574 if (heap_->IsSweepingComplete()) {
ricow@chromium.orgfa52deb2011-10-11 19:09:42 +0000575 StartMarking(ALLOW_COMPACTION);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000576 } else {
577 if (FLAG_trace_incremental_marking) {
578 PrintF("[IncrementalMarking] Start sweeping.\n");
579 }
580 state_ = SWEEPING;
581 }
582
583 heap_->new_space()->LowerInlineAllocationLimit(kAllocatedThreshold);
584}
585
586
ricow@chromium.orgfa52deb2011-10-11 19:09:42 +0000587void IncrementalMarking::StartMarking(CompactionFlag flag) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000588 if (FLAG_trace_incremental_marking) {
589 PrintF("[IncrementalMarking] Start marking\n");
590 }
591
ricow@chromium.orgfa52deb2011-10-11 19:09:42 +0000592 is_compacting_ = !FLAG_never_compact && (flag == ALLOW_COMPACTION) &&
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +0000593 heap_->mark_compact_collector()->StartCompaction(
594 MarkCompactCollector::INCREMENTAL_COMPACTION);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000595
596 state_ = MARKING;
597
598 RecordWriteStub::Mode mode = is_compacting_ ?
599 RecordWriteStub::INCREMENTAL_COMPACTION : RecordWriteStub::INCREMENTAL;
600
601 PatchIncrementalMarkingRecordWriteStubs(heap_, mode);
602
603 EnsureMarkingDequeIsCommitted();
604
605 // Initialize marking stack.
606 Address addr = static_cast<Address>(marking_deque_memory_->address());
607 size_t size = marking_deque_memory_->size();
608 if (FLAG_force_marking_deque_overflows) size = 64 * kPointerSize;
609 marking_deque_.Initialize(addr, addr + size);
610
611 ActivateIncrementalWriteBarrier();
612
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000613 // Marking bits are cleared by the sweeper.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000614#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000615 if (FLAG_verify_heap) {
616 heap_->mark_compact_collector()->VerifyMarkbitsAreClean();
617 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000618#endif
619
620 heap_->CompletelyClearInstanceofCache();
621 heap_->isolate()->compilation_cache()->MarkCompactPrologue();
622
623 if (FLAG_cleanup_code_caches_at_gc) {
624 // We will mark cache black with a separate pass
625 // when we finish marking.
626 MarkObjectGreyDoNotEnqueue(heap_->polymorphic_code_cache());
627 }
628
629 // Mark strong roots grey.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000630 IncrementalMarkingRootMarkingVisitor visitor(this);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000631 heap_->IterateStrongRoots(&visitor, VISIT_ONLY_STRONG);
632
633 // Ready to start incremental marking.
634 if (FLAG_trace_incremental_marking) {
635 PrintF("[IncrementalMarking] Running\n");
636 }
637}
638
639
640void IncrementalMarking::PrepareForScavenge() {
641 if (!IsMarking()) return;
642 NewSpacePageIterator it(heap_->new_space()->FromSpaceStart(),
643 heap_->new_space()->FromSpaceEnd());
644 while (it.has_next()) {
645 Bitmap::Clear(it.next());
646 }
647}
648
649
650void IncrementalMarking::UpdateMarkingDequeAfterScavenge() {
651 if (!IsMarking()) return;
652
653 int current = marking_deque_.bottom();
654 int mask = marking_deque_.mask();
655 int limit = marking_deque_.top();
656 HeapObject** array = marking_deque_.array();
657 int new_top = current;
658
659 Map* filler_map = heap_->one_pointer_filler_map();
660
661 while (current != limit) {
662 HeapObject* obj = array[current];
663 ASSERT(obj->IsHeapObject());
664 current = ((current + 1) & mask);
665 if (heap_->InNewSpace(obj)) {
666 MapWord map_word = obj->map_word();
667 if (map_word.IsForwardingAddress()) {
668 HeapObject* dest = map_word.ToForwardingAddress();
669 array[new_top] = dest;
670 new_top = ((new_top + 1) & mask);
671 ASSERT(new_top != marking_deque_.bottom());
ricow@chromium.orgfa52deb2011-10-11 19:09:42 +0000672#ifdef DEBUG
673 MarkBit mark_bit = Marking::MarkBitFrom(obj);
674 ASSERT(Marking::IsGrey(mark_bit) ||
675 (obj->IsFiller() && Marking::IsWhite(mark_bit)));
676#endif
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000677 }
678 } else if (obj->map() != filler_map) {
679 // Skip one word filler objects that appear on the
680 // stack when we perform in place array shift.
681 array[new_top] = obj;
682 new_top = ((new_top + 1) & mask);
683 ASSERT(new_top != marking_deque_.bottom());
ricow@chromium.orgfa52deb2011-10-11 19:09:42 +0000684#ifdef DEBUG
685 MarkBit mark_bit = Marking::MarkBitFrom(obj);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000686 MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address());
ricow@chromium.orgfa52deb2011-10-11 19:09:42 +0000687 ASSERT(Marking::IsGrey(mark_bit) ||
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000688 (obj->IsFiller() && Marking::IsWhite(mark_bit)) ||
689 (chunk->IsFlagSet(MemoryChunk::HAS_PROGRESS_BAR) &&
690 Marking::IsBlack(mark_bit)));
ricow@chromium.orgfa52deb2011-10-11 19:09:42 +0000691#endif
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000692 }
693 }
694 marking_deque_.set_top(new_top);
695
696 steps_took_since_last_gc_ = 0;
697 steps_count_since_last_gc_ = 0;
698 longest_step_ = 0.0;
699}
700
701
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000702void IncrementalMarking::VisitObject(Map* map, HeapObject* obj, int size) {
703 MarkBit map_mark_bit = Marking::MarkBitFrom(map);
704 if (Marking::IsWhite(map_mark_bit)) {
705 WhiteToGreyAndPush(map, map_mark_bit);
706 }
707
708 IncrementalMarkingMarkingVisitor::IterateBody(map, obj);
709
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000710 MarkBit mark_bit = Marking::MarkBitFrom(obj);
711#ifdef DEBUG
712 MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address());
713 SLOW_ASSERT(Marking::IsGrey(mark_bit) ||
714 (obj->IsFiller() && Marking::IsWhite(mark_bit)) ||
715 (chunk->IsFlagSet(MemoryChunk::HAS_PROGRESS_BAR) &&
716 Marking::IsBlack(mark_bit)));
717#endif
718 MarkBlackOrKeepBlack(obj, mark_bit, size);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000719}
720
721
722void IncrementalMarking::ProcessMarkingDeque(intptr_t bytes_to_process) {
723 Map* filler_map = heap_->one_pointer_filler_map();
724 while (!marking_deque_.IsEmpty() && bytes_to_process > 0) {
725 HeapObject* obj = marking_deque_.Pop();
726
727 // Explicitly skip one word fillers. Incremental markbit patterns are
728 // correct only for objects that occupy at least two words.
729 Map* map = obj->map();
730 if (map == filler_map) continue;
731
732 int size = obj->SizeFromMap(map);
733 bytes_to_process -= size;
734 VisitObject(map, obj, size);
735 }
736}
737
738
739void IncrementalMarking::ProcessMarkingDeque() {
740 Map* filler_map = heap_->one_pointer_filler_map();
741 while (!marking_deque_.IsEmpty()) {
742 HeapObject* obj = marking_deque_.Pop();
743
744 // Explicitly skip one word fillers. Incremental markbit patterns are
745 // correct only for objects that occupy at least two words.
746 Map* map = obj->map();
747 if (map == filler_map) continue;
748
749 VisitObject(map, obj, obj->SizeFromMap(map));
750 }
751}
752
753
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000754void IncrementalMarking::Hurry() {
755 if (state() == MARKING) {
756 double start = 0.0;
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000757 if (FLAG_trace_incremental_marking || FLAG_print_cumulative_gc_stat) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000758 start = OS::TimeCurrentMillis();
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000759 if (FLAG_trace_incremental_marking) {
760 PrintF("[IncrementalMarking] Hurry\n");
761 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000762 }
763 // TODO(gc) hurry can mark objects it encounters black as mutator
764 // was stopped.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000765 ProcessMarkingDeque();
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +0000766 state_ = COMPLETE;
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000767 if (FLAG_trace_incremental_marking || FLAG_print_cumulative_gc_stat) {
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +0000768 double end = OS::TimeCurrentMillis();
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000769 double delta = end - start;
770 heap_->AddMarkingTime(delta);
771 if (FLAG_trace_incremental_marking) {
772 PrintF("[IncrementalMarking] Complete (hurry), spent %d ms.\n",
773 static_cast<int>(delta));
774 }
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +0000775 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000776 }
777
778 if (FLAG_cleanup_code_caches_at_gc) {
779 PolymorphicCodeCache* poly_cache = heap_->polymorphic_code_cache();
780 Marking::GreyToBlack(Marking::MarkBitFrom(poly_cache));
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000781 MemoryChunk::IncrementLiveBytesFromGC(poly_cache->address(),
782 PolymorphicCodeCache::kSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000783 }
784
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000785 Object* context = heap_->native_contexts_list();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000786 while (!context->IsUndefined()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000787 // GC can happen when the context is not fully initialized,
788 // so the cache can be undefined.
789 HeapObject* cache = HeapObject::cast(
790 Context::cast(context)->get(Context::NORMALIZED_MAP_CACHE_INDEX));
791 if (!cache->IsUndefined()) {
792 MarkBit mark_bit = Marking::MarkBitFrom(cache);
793 if (Marking::IsGrey(mark_bit)) {
794 Marking::GreyToBlack(mark_bit);
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000795 MemoryChunk::IncrementLiveBytesFromGC(cache->address(), cache->Size());
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000796 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000797 }
798 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
799 }
800}
801
802
803void IncrementalMarking::Abort() {
804 if (IsStopped()) return;
805 if (FLAG_trace_incremental_marking) {
806 PrintF("[IncrementalMarking] Aborting.\n");
807 }
808 heap_->new_space()->LowerInlineAllocationLimit(0);
809 IncrementalMarking::set_should_hurry(false);
810 ResetStepCounters();
811 if (IsMarking()) {
812 PatchIncrementalMarkingRecordWriteStubs(heap_,
813 RecordWriteStub::STORE_BUFFER_ONLY);
814 DeactivateIncrementalWriteBarrier();
815
816 if (is_compacting_) {
817 LargeObjectIterator it(heap_->lo_space());
818 for (HeapObject* obj = it.Next(); obj != NULL; obj = it.Next()) {
819 Page* p = Page::FromAddress(obj->address());
820 if (p->IsFlagSet(Page::RESCAN_ON_EVACUATION)) {
821 p->ClearFlag(Page::RESCAN_ON_EVACUATION);
822 }
823 }
824 }
825 }
826 heap_->isolate()->stack_guard()->Continue(GC_REQUEST);
827 state_ = STOPPED;
828 is_compacting_ = false;
829}
830
831
832void IncrementalMarking::Finalize() {
833 Hurry();
834 state_ = STOPPED;
835 is_compacting_ = false;
836 heap_->new_space()->LowerInlineAllocationLimit(0);
837 IncrementalMarking::set_should_hurry(false);
838 ResetStepCounters();
839 PatchIncrementalMarkingRecordWriteStubs(heap_,
840 RecordWriteStub::STORE_BUFFER_ONLY);
841 DeactivateIncrementalWriteBarrier();
842 ASSERT(marking_deque_.IsEmpty());
843 heap_->isolate()->stack_guard()->Continue(GC_REQUEST);
844}
845
846
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000847void IncrementalMarking::MarkingComplete(CompletionAction action) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000848 state_ = COMPLETE;
849 // We will set the stack guard to request a GC now. This will mean the rest
850 // of the GC gets performed as soon as possible (we can't do a GC here in a
851 // record-write context). If a few things get allocated between now and then
852 // that shouldn't make us do a scavenge and keep being incremental, so we set
853 // the should-hurry flag to indicate that there can't be much work left to do.
854 set_should_hurry(true);
855 if (FLAG_trace_incremental_marking) {
856 PrintF("[IncrementalMarking] Complete (normal).\n");
857 }
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000858 if (action == GC_VIA_STACK_GUARD) {
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +0000859 heap_->isolate()->stack_guard()->RequestGC();
860 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000861}
862
863
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000864void IncrementalMarking::Step(intptr_t allocated_bytes,
865 CompletionAction action) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000866 if (heap_->gc_state() != Heap::NOT_IN_GC ||
867 !FLAG_incremental_marking ||
868 !FLAG_incremental_marking_steps ||
869 (state_ != SWEEPING && state_ != MARKING)) {
870 return;
871 }
872
873 allocated_ += allocated_bytes;
874
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000875 if (allocated_ < kAllocatedThreshold &&
876 write_barriers_invoked_since_last_step_ <
877 kWriteBarriersInvokedThreshold) {
878 return;
879 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000880
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000881 if (state_ == MARKING && no_marking_scope_depth_ > 0) return;
882
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000883 // The marking speed is driven either by the allocation rate or by the rate
884 // at which we are having to check the color of objects in the write barrier.
885 // It is possible for a tight non-allocating loop to run a lot of write
886 // barriers before we get here and check them (marking can only take place on
887 // allocation), so to reduce the lumpiness we don't use the write barriers
888 // invoked since last step directly to determine the amount of work to do.
889 intptr_t bytes_to_process =
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000890 marking_speed_ * Max(allocated_, write_barriers_invoked_since_last_step_);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000891 allocated_ = 0;
892 write_barriers_invoked_since_last_step_ = 0;
893
danno@chromium.orgc612e022011-11-10 11:38:15 +0000894 bytes_scanned_ += bytes_to_process;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000895
896 double start = 0;
897
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000898 if (FLAG_trace_incremental_marking || FLAG_trace_gc ||
899 FLAG_print_cumulative_gc_stat) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000900 start = OS::TimeCurrentMillis();
901 }
902
903 if (state_ == SWEEPING) {
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +0000904 if (heap_->AdvanceSweepers(static_cast<int>(bytes_to_process))) {
danno@chromium.orgc612e022011-11-10 11:38:15 +0000905 bytes_scanned_ = 0;
ricow@chromium.orgfa52deb2011-10-11 19:09:42 +0000906 StartMarking(PREVENT_COMPACTION);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000907 }
908 } else if (state_ == MARKING) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000909 ProcessMarkingDeque(bytes_to_process);
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +0000910 if (marking_deque_.IsEmpty()) MarkingComplete(action);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000911 }
912
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000913 steps_count_++;
914 steps_count_since_last_gc_++;
915
916 bool speed_up = false;
917
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000918 if ((steps_count_ % kMarkingSpeedAccellerationInterval) == 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000919 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000920 PrintPID("Speed up marking after %d steps\n",
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000921 static_cast<int>(kMarkingSpeedAccellerationInterval));
danno@chromium.orgc612e022011-11-10 11:38:15 +0000922 }
923 speed_up = true;
924 }
925
926 bool space_left_is_very_small =
927 (old_generation_space_available_at_start_of_incremental_ < 10 * MB);
928
929 bool only_1_nth_of_space_that_was_available_still_left =
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000930 (SpaceLeftInOldSpace() * (marking_speed_ + 1) <
danno@chromium.orgc612e022011-11-10 11:38:15 +0000931 old_generation_space_available_at_start_of_incremental_);
932
933 if (space_left_is_very_small ||
934 only_1_nth_of_space_that_was_available_still_left) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000935 if (FLAG_trace_gc) PrintPID("Speed up marking because of low space left\n");
danno@chromium.orgc612e022011-11-10 11:38:15 +0000936 speed_up = true;
937 }
938
939 bool size_of_old_space_multiplied_by_n_during_marking =
940 (heap_->PromotedTotalSize() >
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000941 (marking_speed_ + 1) *
danno@chromium.orgc612e022011-11-10 11:38:15 +0000942 old_generation_space_used_at_start_of_incremental_);
943 if (size_of_old_space_multiplied_by_n_during_marking) {
944 speed_up = true;
945 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000946 PrintPID("Speed up marking because of heap size increase\n");
danno@chromium.orgc612e022011-11-10 11:38:15 +0000947 }
948 }
949
950 int64_t promoted_during_marking = heap_->PromotedTotalSize()
951 - old_generation_space_used_at_start_of_incremental_;
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000952 intptr_t delay = marking_speed_ * MB;
danno@chromium.orgc612e022011-11-10 11:38:15 +0000953 intptr_t scavenge_slack = heap_->MaxSemiSpaceSize();
954
955 // We try to scan at at least twice the speed that we are allocating.
956 if (promoted_during_marking > bytes_scanned_ / 2 + scavenge_slack + delay) {
957 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000958 PrintPID("Speed up marking because marker was not keeping up\n");
danno@chromium.orgc612e022011-11-10 11:38:15 +0000959 }
960 speed_up = true;
961 }
962
963 if (speed_up) {
964 if (state_ != MARKING) {
965 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000966 PrintPID("Postponing speeding up marking until marking starts\n");
danno@chromium.orgc612e022011-11-10 11:38:15 +0000967 }
968 } else {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000969 marking_speed_ += kMarkingSpeedAccellerationInterval;
970 marking_speed_ = static_cast<int>(
971 Min(kMaxMarkingSpeed,
972 static_cast<intptr_t>(marking_speed_ * 1.3)));
danno@chromium.orgc612e022011-11-10 11:38:15 +0000973 if (FLAG_trace_gc) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000974 PrintPID("Marking speed increased to %d\n", marking_speed_);
danno@chromium.orgc612e022011-11-10 11:38:15 +0000975 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000976 }
977 }
978
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000979 if (FLAG_trace_incremental_marking || FLAG_trace_gc ||
980 FLAG_print_cumulative_gc_stat) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000981 double end = OS::TimeCurrentMillis();
982 double delta = (end - start);
983 longest_step_ = Max(longest_step_, delta);
984 steps_took_ += delta;
985 steps_took_since_last_gc_ += delta;
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000986 heap_->AddMarkingTime(delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000987 }
988}
989
990
991void IncrementalMarking::ResetStepCounters() {
992 steps_count_ = 0;
993 steps_took_ = 0;
994 longest_step_ = 0.0;
995 old_generation_space_available_at_start_of_incremental_ =
996 SpaceLeftInOldSpace();
997 old_generation_space_used_at_start_of_incremental_ =
998 heap_->PromotedTotalSize();
999 steps_count_since_last_gc_ = 0;
1000 steps_took_since_last_gc_ = 0;
1001 bytes_rescanned_ = 0;
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001002 marking_speed_ = kInitialMarkingSpeed;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001003 bytes_scanned_ = 0;
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001004 write_barriers_invoked_since_last_step_ = 0;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001005}
1006
1007
1008int64_t IncrementalMarking::SpaceLeftInOldSpace() {
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001009 return heap_->MaxOldGenerationSize() - heap_->PromotedSpaceSizeOfObjects();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001010}
1011
1012} } // namespace v8::internal