blob: 80dc8eaca090df6e574048b32504ded8a6bedca1 [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),
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +000057 no_marking_scope_depth_(0),
58 unscanned_bytes_of_large_object_(0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000059}
60
61
62void IncrementalMarking::TearDown() {
63 delete marking_deque_memory_;
64}
65
66
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000067void IncrementalMarking::RecordWriteSlow(HeapObject* obj,
68 Object** slot,
69 Object* value) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +000070 if (BaseRecordWrite(obj, slot, value) && slot != NULL) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000071 MarkBit obj_bit = Marking::MarkBitFrom(obj);
72 if (Marking::IsBlack(obj_bit)) {
73 // Object is not going to be rescanned we need to record the slot.
74 heap_->mark_compact_collector()->RecordSlot(
75 HeapObject::RawField(obj, 0), slot, value);
76 }
77 }
78}
79
80
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000081void IncrementalMarking::RecordWriteFromCode(HeapObject* obj,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000082 Object** slot,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000083 Isolate* isolate) {
84 ASSERT(obj->IsHeapObject());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000085 IncrementalMarking* marking = isolate->heap()->incremental_marking();
86 ASSERT(!marking->is_compacting_);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000087
88 MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address());
89 int counter = chunk->write_barrier_counter();
90 if (counter < (MemoryChunk::kWriteBarrierCounterGranularity / 2)) {
91 marking->write_barriers_invoked_since_last_step_ +=
92 MemoryChunk::kWriteBarrierCounterGranularity -
93 chunk->write_barrier_counter();
94 chunk->set_write_barrier_counter(
95 MemoryChunk::kWriteBarrierCounterGranularity);
96 }
97
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000098 marking->RecordWrite(obj, slot, *slot);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000099}
100
101
102void IncrementalMarking::RecordWriteForEvacuationFromCode(HeapObject* obj,
103 Object** slot,
104 Isolate* isolate) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000105 ASSERT(obj->IsHeapObject());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000106 IncrementalMarking* marking = isolate->heap()->incremental_marking();
107 ASSERT(marking->is_compacting_);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000108
109 MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address());
110 int counter = chunk->write_barrier_counter();
111 if (counter < (MemoryChunk::kWriteBarrierCounterGranularity / 2)) {
112 marking->write_barriers_invoked_since_last_step_ +=
113 MemoryChunk::kWriteBarrierCounterGranularity -
114 chunk->write_barrier_counter();
115 chunk->set_write_barrier_counter(
116 MemoryChunk::kWriteBarrierCounterGranularity);
117 }
118
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000119 marking->RecordWrite(obj, slot, *slot);
120}
121
122
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000123void IncrementalMarking::RecordCodeTargetPatch(Code* host,
124 Address pc,
125 HeapObject* value) {
126 if (IsMarking()) {
127 RelocInfo rinfo(pc, RelocInfo::CODE_TARGET, 0, host);
128 RecordWriteIntoCode(host, &rinfo, value);
129 }
130}
131
132
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000133void IncrementalMarking::RecordCodeTargetPatch(Address pc, HeapObject* value) {
134 if (IsMarking()) {
135 Code* host = heap_->isolate()->inner_pointer_to_code_cache()->
136 GcSafeFindCodeForInnerPointer(pc);
137 RelocInfo rinfo(pc, RelocInfo::CODE_TARGET, 0, host);
138 RecordWriteIntoCode(host, &rinfo, value);
139 }
140}
141
142
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000143void IncrementalMarking::RecordWriteOfCodeEntrySlow(JSFunction* host,
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000144 Object** slot,
145 Code* value) {
146 if (BaseRecordWrite(host, slot, value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000147 ASSERT(slot != NULL);
148 heap_->mark_compact_collector()->
149 RecordCodeEntrySlot(reinterpret_cast<Address>(slot), value);
150 }
151}
152
153
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000154void IncrementalMarking::RecordWriteIntoCodeSlow(HeapObject* obj,
155 RelocInfo* rinfo,
156 Object* value) {
157 MarkBit value_bit = Marking::MarkBitFrom(HeapObject::cast(value));
158 if (Marking::IsWhite(value_bit)) {
159 MarkBit obj_bit = Marking::MarkBitFrom(obj);
160 if (Marking::IsBlack(obj_bit)) {
161 BlackToGreyAndUnshift(obj, obj_bit);
162 RestartIfNotMarking();
163 }
164 // Object is either grey or white. It will be scanned if survives.
165 return;
166 }
167
168 if (is_compacting_) {
169 MarkBit obj_bit = Marking::MarkBitFrom(obj);
170 if (Marking::IsBlack(obj_bit)) {
171 // Object is not going to be rescanned. We need to record the slot.
172 heap_->mark_compact_collector()->RecordRelocSlot(rinfo,
173 Code::cast(value));
174 }
175 }
176}
177
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000178
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000179static void MarkObjectGreyDoNotEnqueue(Object* obj) {
180 if (obj->IsHeapObject()) {
181 HeapObject* heap_obj = HeapObject::cast(obj);
182 MarkBit mark_bit = Marking::MarkBitFrom(HeapObject::cast(obj));
183 if (Marking::IsBlack(mark_bit)) {
184 MemoryChunk::IncrementLiveBytesFromGC(heap_obj->address(),
185 -heap_obj->Size());
186 }
187 Marking::AnyToGrey(mark_bit);
188 }
189}
190
191
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000192static inline void MarkBlackOrKeepGrey(HeapObject* heap_object,
193 MarkBit mark_bit,
194 int size) {
195 ASSERT(!Marking::IsImpossible(mark_bit));
196 if (mark_bit.Get()) return;
197 mark_bit.Set();
198 MemoryChunk::IncrementLiveBytesFromGC(heap_object->address(), size);
199 ASSERT(Marking::IsBlack(mark_bit));
200}
201
202
203static inline void MarkBlackOrKeepBlack(HeapObject* heap_object,
204 MarkBit mark_bit,
205 int size) {
206 ASSERT(!Marking::IsImpossible(mark_bit));
207 if (Marking::IsBlack(mark_bit)) return;
208 Marking::MarkBlack(mark_bit);
209 MemoryChunk::IncrementLiveBytesFromGC(heap_object->address(), size);
210 ASSERT(Marking::IsBlack(mark_bit));
211}
212
213
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +0000214class IncrementalMarkingMarkingVisitor
215 : public StaticMarkingVisitor<IncrementalMarkingMarkingVisitor> {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000216 public:
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +0000217 static void Initialize() {
218 StaticMarkingVisitor<IncrementalMarkingMarkingVisitor>::Initialize();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000219 table_.Register(kVisitFixedArray, &VisitFixedArrayIncremental);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000220 table_.Register(kVisitNativeContext, &VisitNativeContextIncremental);
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +0000221 table_.Register(kVisitJSRegExp, &VisitJSRegExp);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000222 }
223
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000224 static const int kProgressBarScanningChunk = 32 * 1024;
225
226 static void VisitFixedArrayIncremental(Map* map, HeapObject* object) {
227 MemoryChunk* chunk = MemoryChunk::FromAddress(object->address());
228 // TODO(mstarzinger): Move setting of the flag to the allocation site of
229 // the array. The visitor should just check the flag.
230 if (FLAG_use_marking_progress_bar &&
231 chunk->owner()->identity() == LO_SPACE) {
232 chunk->SetFlag(MemoryChunk::HAS_PROGRESS_BAR);
233 }
234 if (chunk->IsFlagSet(MemoryChunk::HAS_PROGRESS_BAR)) {
235 Heap* heap = map->GetHeap();
236 // When using a progress bar for large fixed arrays, scan only a chunk of
237 // the array and try to push it onto the marking deque again until it is
238 // fully scanned. Fall back to scanning it through to the end in case this
239 // fails because of a full deque.
240 int object_size = FixedArray::BodyDescriptor::SizeOf(map, object);
241 int start_offset = Max(FixedArray::BodyDescriptor::kStartOffset,
242 chunk->progress_bar());
243 int end_offset = Min(object_size,
244 start_offset + kProgressBarScanningChunk);
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000245 int already_scanned_offset = start_offset;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000246 bool scan_until_end = false;
247 do {
248 VisitPointersWithAnchor(heap,
249 HeapObject::RawField(object, 0),
250 HeapObject::RawField(object, start_offset),
251 HeapObject::RawField(object, end_offset));
252 start_offset = end_offset;
253 end_offset = Min(object_size, end_offset + kProgressBarScanningChunk);
254 scan_until_end = heap->incremental_marking()->marking_deque()->IsFull();
255 } while (scan_until_end && start_offset < object_size);
256 chunk->set_progress_bar(start_offset);
257 if (start_offset < object_size) {
258 heap->incremental_marking()->marking_deque()->UnshiftGrey(object);
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000259 heap->incremental_marking()->NotifyIncompleteScanOfObject(
260 object_size - (start_offset - already_scanned_offset));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000261 }
262 } else {
263 FixedArrayVisitor::Visit(map, object);
264 }
265 }
266
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000267 static void VisitNativeContextIncremental(Map* map, HeapObject* object) {
268 Context* context = Context::cast(object);
269
270 // We will mark cache black with a separate pass
271 // when we finish marking.
272 MarkObjectGreyDoNotEnqueue(context->normalized_map_cache());
273 VisitNativeContext(map, context);
274 }
275
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +0000276 static void VisitJSWeakMap(Map* map, HeapObject* object) {
277 Heap* heap = map->GetHeap();
278 VisitPointers(heap,
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +0000279 HeapObject::RawField(object, JSWeakMap::kPropertiesOffset),
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +0000280 HeapObject::RawField(object, JSWeakMap::kSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000281 }
282
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000283 static void BeforeVisitingSharedFunctionInfo(HeapObject* object) {}
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +0000284
285 INLINE(static void VisitPointer(Heap* heap, Object** p)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000286 Object* obj = *p;
287 if (obj->NonFailureIsHeapObject()) {
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +0000288 heap->mark_compact_collector()->RecordSlot(p, p, obj);
289 MarkObject(heap, obj);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000290 }
291 }
292
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +0000293 INLINE(static void VisitPointers(Heap* heap, Object** start, Object** end)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000294 for (Object** p = start; p < end; p++) {
295 Object* obj = *p;
296 if (obj->NonFailureIsHeapObject()) {
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +0000297 heap->mark_compact_collector()->RecordSlot(start, p, obj);
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +0000298 MarkObject(heap, obj);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000299 }
300 }
301 }
302
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000303 INLINE(static void VisitPointersWithAnchor(Heap* heap,
304 Object** anchor,
305 Object** start,
306 Object** end)) {
307 for (Object** p = start; p < end; p++) {
308 Object* obj = *p;
309 if (obj->NonFailureIsHeapObject()) {
310 heap->mark_compact_collector()->RecordSlot(anchor, p, obj);
311 MarkObject(heap, obj);
312 }
313 }
314 }
315
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000316 // Marks the object grey and pushes it on the marking stack.
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +0000317 INLINE(static void MarkObject(Heap* heap, Object* obj)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000318 HeapObject* heap_object = HeapObject::cast(obj);
319 MarkBit mark_bit = Marking::MarkBitFrom(heap_object);
320 if (mark_bit.data_only()) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000321 MarkBlackOrKeepGrey(heap_object, mark_bit, heap_object->Size());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000322 } else if (Marking::IsWhite(mark_bit)) {
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +0000323 heap->incremental_marking()->WhiteToGreyAndPush(heap_object, mark_bit);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000324 }
325 }
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000326
327 // Marks the object black without pushing it on the marking stack.
328 // Returns true if object needed marking and false otherwise.
329 INLINE(static bool MarkObjectWithoutPush(Heap* heap, Object* obj)) {
330 HeapObject* heap_object = HeapObject::cast(obj);
331 MarkBit mark_bit = Marking::MarkBitFrom(heap_object);
332 if (Marking::IsWhite(mark_bit)) {
333 mark_bit.Set();
334 MemoryChunk::IncrementLiveBytesFromGC(heap_object->address(),
335 heap_object->Size());
336 return true;
337 }
338 return false;
339 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000340};
341
342
343class IncrementalMarkingRootMarkingVisitor : public ObjectVisitor {
344 public:
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000345 explicit IncrementalMarkingRootMarkingVisitor(
346 IncrementalMarking* incremental_marking)
347 : incremental_marking_(incremental_marking) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000348 }
349
350 void VisitPointer(Object** p) {
351 MarkObjectByPointer(p);
352 }
353
354 void VisitPointers(Object** start, Object** end) {
355 for (Object** p = start; p < end; p++) MarkObjectByPointer(p);
356 }
357
358 private:
359 void MarkObjectByPointer(Object** p) {
360 Object* obj = *p;
361 if (!obj->IsHeapObject()) return;
362
363 HeapObject* heap_object = HeapObject::cast(obj);
364 MarkBit mark_bit = Marking::MarkBitFrom(heap_object);
365 if (mark_bit.data_only()) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000366 MarkBlackOrKeepGrey(heap_object, mark_bit, heap_object->Size());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000367 } else {
368 if (Marking::IsWhite(mark_bit)) {
369 incremental_marking_->WhiteToGreyAndPush(heap_object, mark_bit);
370 }
371 }
372 }
373
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000374 IncrementalMarking* incremental_marking_;
375};
376
377
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +0000378void IncrementalMarking::Initialize() {
379 IncrementalMarkingMarkingVisitor::Initialize();
380}
381
382
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000383void IncrementalMarking::SetOldSpacePageFlags(MemoryChunk* chunk,
384 bool is_marking,
385 bool is_compacting) {
386 if (is_marking) {
387 chunk->SetFlag(MemoryChunk::POINTERS_TO_HERE_ARE_INTERESTING);
388 chunk->SetFlag(MemoryChunk::POINTERS_FROM_HERE_ARE_INTERESTING);
389
390 // It's difficult to filter out slots recorded for large objects.
391 if (chunk->owner()->identity() == LO_SPACE &&
392 chunk->size() > static_cast<size_t>(Page::kPageSize) &&
393 is_compacting) {
394 chunk->SetFlag(MemoryChunk::RESCAN_ON_EVACUATION);
395 }
396 } else if (chunk->owner()->identity() == CELL_SPACE ||
danno@chromium.org41728482013-06-12 22:31:22 +0000397 chunk->owner()->identity() == PROPERTY_CELL_SPACE ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000398 chunk->scan_on_scavenge()) {
399 chunk->ClearFlag(MemoryChunk::POINTERS_TO_HERE_ARE_INTERESTING);
400 chunk->ClearFlag(MemoryChunk::POINTERS_FROM_HERE_ARE_INTERESTING);
401 } else {
402 chunk->ClearFlag(MemoryChunk::POINTERS_TO_HERE_ARE_INTERESTING);
403 chunk->SetFlag(MemoryChunk::POINTERS_FROM_HERE_ARE_INTERESTING);
404 }
405}
406
407
408void IncrementalMarking::SetNewSpacePageFlags(NewSpacePage* chunk,
409 bool is_marking) {
410 chunk->SetFlag(MemoryChunk::POINTERS_TO_HERE_ARE_INTERESTING);
411 if (is_marking) {
412 chunk->SetFlag(MemoryChunk::POINTERS_FROM_HERE_ARE_INTERESTING);
413 } else {
414 chunk->ClearFlag(MemoryChunk::POINTERS_FROM_HERE_ARE_INTERESTING);
415 }
416 chunk->SetFlag(MemoryChunk::SCAN_ON_SCAVENGE);
417}
418
419
420void IncrementalMarking::DeactivateIncrementalWriteBarrierForSpace(
421 PagedSpace* space) {
422 PageIterator it(space);
423 while (it.has_next()) {
424 Page* p = it.next();
425 SetOldSpacePageFlags(p, false, false);
426 }
427}
428
429
430void IncrementalMarking::DeactivateIncrementalWriteBarrierForSpace(
431 NewSpace* space) {
432 NewSpacePageIterator it(space);
433 while (it.has_next()) {
434 NewSpacePage* p = it.next();
435 SetNewSpacePageFlags(p, false);
436 }
437}
438
439
440void IncrementalMarking::DeactivateIncrementalWriteBarrier() {
441 DeactivateIncrementalWriteBarrierForSpace(heap_->old_pointer_space());
442 DeactivateIncrementalWriteBarrierForSpace(heap_->old_data_space());
443 DeactivateIncrementalWriteBarrierForSpace(heap_->cell_space());
danno@chromium.org41728482013-06-12 22:31:22 +0000444 DeactivateIncrementalWriteBarrierForSpace(heap_->property_cell_space());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000445 DeactivateIncrementalWriteBarrierForSpace(heap_->map_space());
446 DeactivateIncrementalWriteBarrierForSpace(heap_->code_space());
447 DeactivateIncrementalWriteBarrierForSpace(heap_->new_space());
448
449 LargePage* lop = heap_->lo_space()->first_page();
450 while (lop->is_valid()) {
451 SetOldSpacePageFlags(lop, false, false);
452 lop = lop->next_page();
453 }
454}
455
456
457void IncrementalMarking::ActivateIncrementalWriteBarrier(PagedSpace* space) {
458 PageIterator it(space);
459 while (it.has_next()) {
460 Page* p = it.next();
461 SetOldSpacePageFlags(p, true, is_compacting_);
462 }
463}
464
465
466void IncrementalMarking::ActivateIncrementalWriteBarrier(NewSpace* space) {
467 NewSpacePageIterator it(space->ToSpaceStart(), space->ToSpaceEnd());
468 while (it.has_next()) {
469 NewSpacePage* p = it.next();
470 SetNewSpacePageFlags(p, true);
471 }
472}
473
474
475void IncrementalMarking::ActivateIncrementalWriteBarrier() {
476 ActivateIncrementalWriteBarrier(heap_->old_pointer_space());
477 ActivateIncrementalWriteBarrier(heap_->old_data_space());
478 ActivateIncrementalWriteBarrier(heap_->cell_space());
danno@chromium.org41728482013-06-12 22:31:22 +0000479 ActivateIncrementalWriteBarrier(heap_->property_cell_space());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000480 ActivateIncrementalWriteBarrier(heap_->map_space());
481 ActivateIncrementalWriteBarrier(heap_->code_space());
482 ActivateIncrementalWriteBarrier(heap_->new_space());
483
484 LargePage* lop = heap_->lo_space()->first_page();
485 while (lop->is_valid()) {
486 SetOldSpacePageFlags(lop, true, is_compacting_);
487 lop = lop->next_page();
488 }
489}
490
491
492bool IncrementalMarking::WorthActivating() {
493#ifndef DEBUG
494 static const intptr_t kActivationThreshold = 8 * MB;
495#else
496 // TODO(gc) consider setting this to some low level so that some
497 // debug tests run with incremental marking and some without.
498 static const intptr_t kActivationThreshold = 0;
499#endif
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000500 // Only start incremental marking in a safe state: 1) when expose GC is
501 // deactivated, 2) when incremental marking is turned on, 3) when we are
502 // currently not in a GC, and 4) when we are currently not serializing
503 // or deserializing the heap.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000504 return !FLAG_expose_gc &&
505 FLAG_incremental_marking &&
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000506 FLAG_incremental_marking_steps &&
507 heap_->gc_state() == Heap::NOT_IN_GC &&
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000508 !Serializer::enabled() &&
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000509 heap_->isolate()->IsInitialized() &&
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000510 heap_->PromotedSpaceSizeOfObjects() > kActivationThreshold;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000511}
512
513
514void IncrementalMarking::ActivateGeneratedStub(Code* stub) {
515 ASSERT(RecordWriteStub::GetMode(stub) ==
516 RecordWriteStub::STORE_BUFFER_ONLY);
517
518 if (!IsMarking()) {
519 // Initially stub is generated in STORE_BUFFER_ONLY mode thus
520 // we don't need to do anything if incremental marking is
521 // not active.
522 } else if (IsCompacting()) {
523 RecordWriteStub::Patch(stub, RecordWriteStub::INCREMENTAL_COMPACTION);
524 } else {
525 RecordWriteStub::Patch(stub, RecordWriteStub::INCREMENTAL);
526 }
527}
528
529
530static void PatchIncrementalMarkingRecordWriteStubs(
531 Heap* heap, RecordWriteStub::Mode mode) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000532 UnseededNumberDictionary* stubs = heap->code_stubs();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000533
534 int capacity = stubs->Capacity();
535 for (int i = 0; i < capacity; i++) {
536 Object* k = stubs->KeyAt(i);
537 if (stubs->IsKey(k)) {
538 uint32_t key = NumberToUint32(k);
539
540 if (CodeStub::MajorKeyFromKey(key) ==
541 CodeStub::RecordWrite) {
542 Object* e = stubs->ValueAt(i);
543 if (e->IsCode()) {
544 RecordWriteStub::Patch(Code::cast(e), mode);
545 }
546 }
547 }
548 }
549}
550
551
552void IncrementalMarking::EnsureMarkingDequeIsCommitted() {
553 if (marking_deque_memory_ == NULL) {
554 marking_deque_memory_ = new VirtualMemory(4 * MB);
danno@chromium.orgc612e022011-11-10 11:38:15 +0000555 }
556 if (!marking_deque_memory_committed_) {
557 bool success = marking_deque_memory_->Commit(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000558 reinterpret_cast<Address>(marking_deque_memory_->address()),
559 marking_deque_memory_->size(),
560 false); // Not executable.
danno@chromium.orgc612e022011-11-10 11:38:15 +0000561 CHECK(success);
562 marking_deque_memory_committed_ = true;
563 }
564}
565
566void IncrementalMarking::UncommitMarkingDeque() {
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000567 if (state_ == STOPPED && marking_deque_memory_committed_) {
danno@chromium.orgc612e022011-11-10 11:38:15 +0000568 bool success = marking_deque_memory_->Uncommit(
569 reinterpret_cast<Address>(marking_deque_memory_->address()),
570 marking_deque_memory_->size());
571 CHECK(success);
572 marking_deque_memory_committed_ = false;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000573 }
574}
575
576
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000577void IncrementalMarking::Start(CompactionFlag flag) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000578 if (FLAG_trace_incremental_marking) {
579 PrintF("[IncrementalMarking] Start\n");
580 }
581 ASSERT(FLAG_incremental_marking);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000582 ASSERT(FLAG_incremental_marking_steps);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000583 ASSERT(state_ == STOPPED);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000584 ASSERT(heap_->gc_state() == Heap::NOT_IN_GC);
585 ASSERT(!Serializer::enabled());
586 ASSERT(heap_->isolate()->IsInitialized());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000587
588 ResetStepCounters();
589
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +0000590 if (heap_->IsSweepingComplete()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000591 StartMarking(flag);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000592 } else {
593 if (FLAG_trace_incremental_marking) {
594 PrintF("[IncrementalMarking] Start sweeping.\n");
595 }
596 state_ = SWEEPING;
597 }
598
599 heap_->new_space()->LowerInlineAllocationLimit(kAllocatedThreshold);
600}
601
602
ricow@chromium.orgfa52deb2011-10-11 19:09:42 +0000603void IncrementalMarking::StartMarking(CompactionFlag flag) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000604 if (FLAG_trace_incremental_marking) {
605 PrintF("[IncrementalMarking] Start marking\n");
606 }
607
ricow@chromium.orgfa52deb2011-10-11 19:09:42 +0000608 is_compacting_ = !FLAG_never_compact && (flag == ALLOW_COMPACTION) &&
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +0000609 heap_->mark_compact_collector()->StartCompaction(
610 MarkCompactCollector::INCREMENTAL_COMPACTION);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000611
612 state_ = MARKING;
613
614 RecordWriteStub::Mode mode = is_compacting_ ?
615 RecordWriteStub::INCREMENTAL_COMPACTION : RecordWriteStub::INCREMENTAL;
616
617 PatchIncrementalMarkingRecordWriteStubs(heap_, mode);
618
619 EnsureMarkingDequeIsCommitted();
620
621 // Initialize marking stack.
622 Address addr = static_cast<Address>(marking_deque_memory_->address());
623 size_t size = marking_deque_memory_->size();
624 if (FLAG_force_marking_deque_overflows) size = 64 * kPointerSize;
625 marking_deque_.Initialize(addr, addr + size);
626
627 ActivateIncrementalWriteBarrier();
628
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000629 // Marking bits are cleared by the sweeper.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000630#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000631 if (FLAG_verify_heap) {
632 heap_->mark_compact_collector()->VerifyMarkbitsAreClean();
633 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000634#endif
635
636 heap_->CompletelyClearInstanceofCache();
637 heap_->isolate()->compilation_cache()->MarkCompactPrologue();
638
639 if (FLAG_cleanup_code_caches_at_gc) {
640 // We will mark cache black with a separate pass
641 // when we finish marking.
642 MarkObjectGreyDoNotEnqueue(heap_->polymorphic_code_cache());
643 }
644
645 // Mark strong roots grey.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000646 IncrementalMarkingRootMarkingVisitor visitor(this);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000647 heap_->IterateStrongRoots(&visitor, VISIT_ONLY_STRONG);
648
649 // Ready to start incremental marking.
650 if (FLAG_trace_incremental_marking) {
651 PrintF("[IncrementalMarking] Running\n");
652 }
653}
654
655
656void IncrementalMarking::PrepareForScavenge() {
657 if (!IsMarking()) return;
658 NewSpacePageIterator it(heap_->new_space()->FromSpaceStart(),
659 heap_->new_space()->FromSpaceEnd());
660 while (it.has_next()) {
661 Bitmap::Clear(it.next());
662 }
663}
664
665
666void IncrementalMarking::UpdateMarkingDequeAfterScavenge() {
667 if (!IsMarking()) return;
668
669 int current = marking_deque_.bottom();
670 int mask = marking_deque_.mask();
671 int limit = marking_deque_.top();
672 HeapObject** array = marking_deque_.array();
673 int new_top = current;
674
675 Map* filler_map = heap_->one_pointer_filler_map();
676
677 while (current != limit) {
678 HeapObject* obj = array[current];
679 ASSERT(obj->IsHeapObject());
680 current = ((current + 1) & mask);
681 if (heap_->InNewSpace(obj)) {
682 MapWord map_word = obj->map_word();
683 if (map_word.IsForwardingAddress()) {
684 HeapObject* dest = map_word.ToForwardingAddress();
685 array[new_top] = dest;
686 new_top = ((new_top + 1) & mask);
687 ASSERT(new_top != marking_deque_.bottom());
ricow@chromium.orgfa52deb2011-10-11 19:09:42 +0000688#ifdef DEBUG
689 MarkBit mark_bit = Marking::MarkBitFrom(obj);
690 ASSERT(Marking::IsGrey(mark_bit) ||
691 (obj->IsFiller() && Marking::IsWhite(mark_bit)));
692#endif
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000693 }
694 } else if (obj->map() != filler_map) {
695 // Skip one word filler objects that appear on the
696 // stack when we perform in place array shift.
697 array[new_top] = obj;
698 new_top = ((new_top + 1) & mask);
699 ASSERT(new_top != marking_deque_.bottom());
ricow@chromium.orgfa52deb2011-10-11 19:09:42 +0000700#ifdef DEBUG
701 MarkBit mark_bit = Marking::MarkBitFrom(obj);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000702 MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address());
ricow@chromium.orgfa52deb2011-10-11 19:09:42 +0000703 ASSERT(Marking::IsGrey(mark_bit) ||
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000704 (obj->IsFiller() && Marking::IsWhite(mark_bit)) ||
705 (chunk->IsFlagSet(MemoryChunk::HAS_PROGRESS_BAR) &&
706 Marking::IsBlack(mark_bit)));
ricow@chromium.orgfa52deb2011-10-11 19:09:42 +0000707#endif
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000708 }
709 }
710 marking_deque_.set_top(new_top);
711
712 steps_took_since_last_gc_ = 0;
713 steps_count_since_last_gc_ = 0;
714 longest_step_ = 0.0;
715}
716
717
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000718void IncrementalMarking::VisitObject(Map* map, HeapObject* obj, int size) {
719 MarkBit map_mark_bit = Marking::MarkBitFrom(map);
720 if (Marking::IsWhite(map_mark_bit)) {
721 WhiteToGreyAndPush(map, map_mark_bit);
722 }
723
724 IncrementalMarkingMarkingVisitor::IterateBody(map, obj);
725
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000726 MarkBit mark_bit = Marking::MarkBitFrom(obj);
727#ifdef DEBUG
728 MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address());
729 SLOW_ASSERT(Marking::IsGrey(mark_bit) ||
730 (obj->IsFiller() && Marking::IsWhite(mark_bit)) ||
731 (chunk->IsFlagSet(MemoryChunk::HAS_PROGRESS_BAR) &&
732 Marking::IsBlack(mark_bit)));
733#endif
734 MarkBlackOrKeepBlack(obj, mark_bit, size);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000735}
736
737
738void IncrementalMarking::ProcessMarkingDeque(intptr_t bytes_to_process) {
739 Map* filler_map = heap_->one_pointer_filler_map();
740 while (!marking_deque_.IsEmpty() && bytes_to_process > 0) {
741 HeapObject* obj = marking_deque_.Pop();
742
743 // Explicitly skip one word fillers. Incremental markbit patterns are
744 // correct only for objects that occupy at least two words.
745 Map* map = obj->map();
746 if (map == filler_map) continue;
747
748 int size = obj->SizeFromMap(map);
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000749 unscanned_bytes_of_large_object_ = 0;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000750 VisitObject(map, obj, size);
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000751 bytes_to_process -= (size - unscanned_bytes_of_large_object_);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000752 }
753}
754
755
756void IncrementalMarking::ProcessMarkingDeque() {
757 Map* filler_map = heap_->one_pointer_filler_map();
758 while (!marking_deque_.IsEmpty()) {
759 HeapObject* obj = marking_deque_.Pop();
760
761 // Explicitly skip one word fillers. Incremental markbit patterns are
762 // correct only for objects that occupy at least two words.
763 Map* map = obj->map();
764 if (map == filler_map) continue;
765
766 VisitObject(map, obj, obj->SizeFromMap(map));
767 }
768}
769
770
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000771void IncrementalMarking::Hurry() {
772 if (state() == MARKING) {
773 double start = 0.0;
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000774 if (FLAG_trace_incremental_marking || FLAG_print_cumulative_gc_stat) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000775 start = OS::TimeCurrentMillis();
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000776 if (FLAG_trace_incremental_marking) {
777 PrintF("[IncrementalMarking] Hurry\n");
778 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000779 }
780 // TODO(gc) hurry can mark objects it encounters black as mutator
781 // was stopped.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000782 ProcessMarkingDeque();
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +0000783 state_ = COMPLETE;
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000784 if (FLAG_trace_incremental_marking || FLAG_print_cumulative_gc_stat) {
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +0000785 double end = OS::TimeCurrentMillis();
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000786 double delta = end - start;
787 heap_->AddMarkingTime(delta);
788 if (FLAG_trace_incremental_marking) {
789 PrintF("[IncrementalMarking] Complete (hurry), spent %d ms.\n",
790 static_cast<int>(delta));
791 }
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +0000792 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000793 }
794
795 if (FLAG_cleanup_code_caches_at_gc) {
796 PolymorphicCodeCache* poly_cache = heap_->polymorphic_code_cache();
797 Marking::GreyToBlack(Marking::MarkBitFrom(poly_cache));
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000798 MemoryChunk::IncrementLiveBytesFromGC(poly_cache->address(),
799 PolymorphicCodeCache::kSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000800 }
801
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000802 Object* context = heap_->native_contexts_list();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000803 while (!context->IsUndefined()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000804 // GC can happen when the context is not fully initialized,
805 // so the cache can be undefined.
806 HeapObject* cache = HeapObject::cast(
807 Context::cast(context)->get(Context::NORMALIZED_MAP_CACHE_INDEX));
808 if (!cache->IsUndefined()) {
809 MarkBit mark_bit = Marking::MarkBitFrom(cache);
810 if (Marking::IsGrey(mark_bit)) {
811 Marking::GreyToBlack(mark_bit);
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000812 MemoryChunk::IncrementLiveBytesFromGC(cache->address(), cache->Size());
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000813 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000814 }
815 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
816 }
817}
818
819
820void IncrementalMarking::Abort() {
821 if (IsStopped()) return;
822 if (FLAG_trace_incremental_marking) {
823 PrintF("[IncrementalMarking] Aborting.\n");
824 }
825 heap_->new_space()->LowerInlineAllocationLimit(0);
826 IncrementalMarking::set_should_hurry(false);
827 ResetStepCounters();
828 if (IsMarking()) {
829 PatchIncrementalMarkingRecordWriteStubs(heap_,
830 RecordWriteStub::STORE_BUFFER_ONLY);
831 DeactivateIncrementalWriteBarrier();
832
833 if (is_compacting_) {
834 LargeObjectIterator it(heap_->lo_space());
835 for (HeapObject* obj = it.Next(); obj != NULL; obj = it.Next()) {
836 Page* p = Page::FromAddress(obj->address());
837 if (p->IsFlagSet(Page::RESCAN_ON_EVACUATION)) {
838 p->ClearFlag(Page::RESCAN_ON_EVACUATION);
839 }
840 }
841 }
842 }
843 heap_->isolate()->stack_guard()->Continue(GC_REQUEST);
844 state_ = STOPPED;
845 is_compacting_ = false;
846}
847
848
849void IncrementalMarking::Finalize() {
850 Hurry();
851 state_ = STOPPED;
852 is_compacting_ = false;
853 heap_->new_space()->LowerInlineAllocationLimit(0);
854 IncrementalMarking::set_should_hurry(false);
855 ResetStepCounters();
856 PatchIncrementalMarkingRecordWriteStubs(heap_,
857 RecordWriteStub::STORE_BUFFER_ONLY);
858 DeactivateIncrementalWriteBarrier();
859 ASSERT(marking_deque_.IsEmpty());
860 heap_->isolate()->stack_guard()->Continue(GC_REQUEST);
861}
862
863
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000864void IncrementalMarking::MarkingComplete(CompletionAction action) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000865 state_ = COMPLETE;
866 // We will set the stack guard to request a GC now. This will mean the rest
867 // of the GC gets performed as soon as possible (we can't do a GC here in a
868 // record-write context). If a few things get allocated between now and then
869 // that shouldn't make us do a scavenge and keep being incremental, so we set
870 // the should-hurry flag to indicate that there can't be much work left to do.
871 set_should_hurry(true);
872 if (FLAG_trace_incremental_marking) {
873 PrintF("[IncrementalMarking] Complete (normal).\n");
874 }
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000875 if (action == GC_VIA_STACK_GUARD) {
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +0000876 heap_->isolate()->stack_guard()->RequestGC();
877 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000878}
879
880
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000881void IncrementalMarking::OldSpaceStep(intptr_t allocated) {
882 if (IsStopped() && WorthActivating() && heap_->NextGCIsLikelyToBeFull()) {
883 // TODO(hpayer): Let's play safe for now, but compaction should be
884 // in principle possible.
885 Start(PREVENT_COMPACTION);
886 } else {
887 Step(allocated * kFastMarking / kInitialMarkingSpeed, GC_VIA_STACK_GUARD);
888 }
889}
890
891
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000892void IncrementalMarking::Step(intptr_t allocated_bytes,
893 CompletionAction action) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000894 if (heap_->gc_state() != Heap::NOT_IN_GC ||
895 !FLAG_incremental_marking ||
896 !FLAG_incremental_marking_steps ||
897 (state_ != SWEEPING && state_ != MARKING)) {
898 return;
899 }
900
901 allocated_ += allocated_bytes;
902
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000903 if (allocated_ < kAllocatedThreshold &&
904 write_barriers_invoked_since_last_step_ <
905 kWriteBarriersInvokedThreshold) {
906 return;
907 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000908
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000909 if (state_ == MARKING && no_marking_scope_depth_ > 0) return;
910
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000911 // The marking speed is driven either by the allocation rate or by the rate
912 // at which we are having to check the color of objects in the write barrier.
913 // It is possible for a tight non-allocating loop to run a lot of write
914 // barriers before we get here and check them (marking can only take place on
915 // allocation), so to reduce the lumpiness we don't use the write barriers
916 // invoked since last step directly to determine the amount of work to do.
917 intptr_t bytes_to_process =
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000918 marking_speed_ * Max(allocated_, write_barriers_invoked_since_last_step_);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000919 allocated_ = 0;
920 write_barriers_invoked_since_last_step_ = 0;
921
danno@chromium.orgc612e022011-11-10 11:38:15 +0000922 bytes_scanned_ += bytes_to_process;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000923
924 double start = 0;
925
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000926 if (FLAG_trace_incremental_marking || FLAG_trace_gc ||
927 FLAG_print_cumulative_gc_stat) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000928 start = OS::TimeCurrentMillis();
929 }
930
931 if (state_ == SWEEPING) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000932 if (heap_->EnsureSweepersProgressed(static_cast<int>(bytes_to_process))) {
danno@chromium.orgc612e022011-11-10 11:38:15 +0000933 bytes_scanned_ = 0;
ricow@chromium.orgfa52deb2011-10-11 19:09:42 +0000934 StartMarking(PREVENT_COMPACTION);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000935 }
936 } else if (state_ == MARKING) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000937 ProcessMarkingDeque(bytes_to_process);
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +0000938 if (marking_deque_.IsEmpty()) MarkingComplete(action);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000939 }
940
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000941 steps_count_++;
942 steps_count_since_last_gc_++;
943
944 bool speed_up = false;
945
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000946 if ((steps_count_ % kMarkingSpeedAccellerationInterval) == 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000947 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000948 PrintPID("Speed up marking after %d steps\n",
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000949 static_cast<int>(kMarkingSpeedAccellerationInterval));
danno@chromium.orgc612e022011-11-10 11:38:15 +0000950 }
951 speed_up = true;
952 }
953
954 bool space_left_is_very_small =
955 (old_generation_space_available_at_start_of_incremental_ < 10 * MB);
956
957 bool only_1_nth_of_space_that_was_available_still_left =
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000958 (SpaceLeftInOldSpace() * (marking_speed_ + 1) <
danno@chromium.orgc612e022011-11-10 11:38:15 +0000959 old_generation_space_available_at_start_of_incremental_);
960
961 if (space_left_is_very_small ||
962 only_1_nth_of_space_that_was_available_still_left) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000963 if (FLAG_trace_gc) PrintPID("Speed up marking because of low space left\n");
danno@chromium.orgc612e022011-11-10 11:38:15 +0000964 speed_up = true;
965 }
966
967 bool size_of_old_space_multiplied_by_n_during_marking =
968 (heap_->PromotedTotalSize() >
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000969 (marking_speed_ + 1) *
danno@chromium.orgc612e022011-11-10 11:38:15 +0000970 old_generation_space_used_at_start_of_incremental_);
971 if (size_of_old_space_multiplied_by_n_during_marking) {
972 speed_up = true;
973 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000974 PrintPID("Speed up marking because of heap size increase\n");
danno@chromium.orgc612e022011-11-10 11:38:15 +0000975 }
976 }
977
978 int64_t promoted_during_marking = heap_->PromotedTotalSize()
979 - old_generation_space_used_at_start_of_incremental_;
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000980 intptr_t delay = marking_speed_ * MB;
danno@chromium.orgc612e022011-11-10 11:38:15 +0000981 intptr_t scavenge_slack = heap_->MaxSemiSpaceSize();
982
983 // We try to scan at at least twice the speed that we are allocating.
984 if (promoted_during_marking > bytes_scanned_ / 2 + scavenge_slack + delay) {
985 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000986 PrintPID("Speed up marking because marker was not keeping up\n");
danno@chromium.orgc612e022011-11-10 11:38:15 +0000987 }
988 speed_up = true;
989 }
990
991 if (speed_up) {
992 if (state_ != MARKING) {
993 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000994 PrintPID("Postponing speeding up marking until marking starts\n");
danno@chromium.orgc612e022011-11-10 11:38:15 +0000995 }
996 } else {
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000997 marking_speed_ += kMarkingSpeedAccelleration;
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000998 marking_speed_ = static_cast<int>(
999 Min(kMaxMarkingSpeed,
1000 static_cast<intptr_t>(marking_speed_ * 1.3)));
danno@chromium.orgc612e022011-11-10 11:38:15 +00001001 if (FLAG_trace_gc) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001002 PrintPID("Marking speed increased to %d\n", marking_speed_);
danno@chromium.orgc612e022011-11-10 11:38:15 +00001003 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001004 }
1005 }
1006
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00001007 if (FLAG_trace_incremental_marking || FLAG_trace_gc ||
1008 FLAG_print_cumulative_gc_stat) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001009 double end = OS::TimeCurrentMillis();
1010 double delta = (end - start);
1011 longest_step_ = Max(longest_step_, delta);
1012 steps_took_ += delta;
1013 steps_took_since_last_gc_ += delta;
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00001014 heap_->AddMarkingTime(delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001015 }
1016}
1017
1018
1019void IncrementalMarking::ResetStepCounters() {
1020 steps_count_ = 0;
1021 steps_took_ = 0;
1022 longest_step_ = 0.0;
1023 old_generation_space_available_at_start_of_incremental_ =
1024 SpaceLeftInOldSpace();
1025 old_generation_space_used_at_start_of_incremental_ =
1026 heap_->PromotedTotalSize();
1027 steps_count_since_last_gc_ = 0;
1028 steps_took_since_last_gc_ = 0;
1029 bytes_rescanned_ = 0;
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001030 marking_speed_ = kInitialMarkingSpeed;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001031 bytes_scanned_ = 0;
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001032 write_barriers_invoked_since_last_step_ = 0;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001033}
1034
1035
1036int64_t IncrementalMarking::SpaceLeftInOldSpace() {
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001037 return heap_->MaxOldGenerationSize() - heap_->PromotedSpaceSizeOfObjects();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001038}
1039
1040} } // namespace v8::internal