Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | |
|
Erik Corry
2011/02/22 12:27:19
2011
| |
| 2 // 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 #ifndef V8_INCREMENTAL_MARKING_H_ | |
| 29 #define V8_INCREMENTAL_MARKING_H_ | |
| 30 | |
| 31 | |
| 32 #include "execution.h" | |
| 33 #include "mark-compact.h" | |
| 34 #include "objects.h" | |
| 35 | |
| 36 namespace v8 { | |
| 37 namespace internal { | |
| 38 | |
| 39 | |
| 40 class IncrementalMarking : public AllStatic { | |
| 41 public: | |
| 42 enum State { | |
| 43 STOPPED, | |
| 44 MARKING, | |
| 45 COMPLETE | |
| 46 }; | |
| 47 | |
| 48 static void Start() { | |
|
Erik Corry
2011/02/22 12:27:19
I think it would be cleaner to move largish functi
Vyacheslav Egorov (Chromium)
2011/02/23 14:31:46
Done.
| |
| 49 if (FLAG_trace_incremental_marking) { | |
| 50 PrintF("[IncrementalMarking] Start\n"); | |
| 51 } | |
| 52 ASSERT(FLAG_incremental_marking); | |
| 53 ASSERT(state_ == STOPPED); | |
| 54 state_ = MARKING; | |
| 55 | |
| 56 // Initialize marking stack. | |
| 57 marking_stack_.Initialize(Heap::new_space()->FromSpaceLow(), | |
| 58 Heap::new_space()->FromSpaceHigh()); | |
| 59 | |
| 60 // Clear markbits. | |
| 61 Address new_space_top = Heap::new_space()->top(); | |
| 62 Address new_space_bottom = Heap::new_space()->bottom(); | |
| 63 | |
| 64 Marking::ClearRange(new_space_bottom, | |
| 65 static_cast<int>(new_space_top - new_space_bottom)); | |
| 66 | |
| 67 ClearMarkbits(); | |
| 68 | |
| 69 #ifdef DEBUG | |
| 70 VerifyMarkbitsAreClean(); | |
| 71 #endif | |
| 72 | |
| 73 // Mark strong roots grey. | |
| 74 RootMarkingVisitor visitor; | |
| 75 Heap::IterateStrongRoots(&visitor, VISIT_ONLY_STRONG); | |
| 76 | |
| 77 // Ready to start incremental marking. | |
| 78 if (FLAG_trace_incremental_marking) { | |
| 79 PrintF("[IncrementalMarking] Running\n"); | |
| 80 } | |
| 81 } | |
| 82 | |
| 83 static State state() { | |
| 84 ASSERT(state_ == STOPPED || FLAG_incremental_marking); | |
| 85 return state_; | |
| 86 } | |
| 87 | |
| 88 static void Stop() { | |
| 89 state_ = STOPPED; | |
|
Erik Corry
2011/02/22 12:27:19
Fits on one line.
Vyacheslav Egorov (Chromium)
2011/02/23 14:31:46
Done.
| |
| 90 } | |
| 91 | |
| 92 static void Hurry() { | |
| 93 if (state() == MARKING) { | |
| 94 if (FLAG_trace_incremental_marking) { | |
| 95 PrintF("[IncrementalMarking] Hurry\n"); | |
| 96 } | |
| 97 // TODO(gc) hurry can mark objects it encounters black as mutator | |
| 98 // was stopped. | |
| 99 while (!marking_stack_.is_empty()) { | |
| 100 HeapObject* obj = marking_stack_.Pop(); | |
| 101 obj->Iterate(&visitor_); | |
| 102 MarkBlack(obj); | |
| 103 } | |
| 104 state_ = COMPLETE; | |
| 105 if (FLAG_trace_incremental_marking) { | |
| 106 PrintF("[IncrementalMarking] Complete (hurry)\n"); | |
| 107 } | |
| 108 } | |
| 109 } | |
| 110 | |
| 111 static void Finalize() { | |
| 112 Hurry(); | |
| 113 state_ = STOPPED; | |
| 114 ASSERT(marking_stack_.is_empty()); | |
| 115 } | |
| 116 | |
| 117 | |
| 118 static void MarkingComplete() { | |
| 119 state_ = COMPLETE; | |
| 120 // We completed marking. | |
| 121 if (FLAG_trace_incremental_marking) { | |
| 122 PrintF("[IncrementalMarking] Complete (normal)\n"); | |
| 123 } | |
| 124 StackGuard::RequestGC(); | |
| 125 } | |
| 126 | |
| 127 | |
| 128 static const intptr_t kAllocatedThreshold = 1024; | |
| 129 static const intptr_t kFactor = 8; | |
|
Erik Corry
2011/02/22 12:27:19
Perhaps call this kAllocationMarkingFactor.
Vyacheslav Egorov (Chromium)
2011/02/23 14:31:46
Done.
| |
| 130 | |
| 131 static void Step(intptr_t allocated) { | |
| 132 if (state_ == MARKING) { | |
| 133 allocated_ += allocated; | |
| 134 | |
| 135 if (allocated_ >= kAllocatedThreshold) { | |
| 136 intptr_t bytes_to_process = allocated_ * kFactor; | |
| 137 int count = 0; | |
| 138 double start = 0; | |
| 139 if (FLAG_trace_incremental_marking) { | |
| 140 PrintF("[IncrementalMarking] Marking %d bytes\n", bytes_to_process); | |
| 141 start = OS::TimeCurrentMillis(); | |
| 142 } | |
| 143 while (!marking_stack_.is_empty() && bytes_to_process > 0) { | |
| 144 HeapObject* obj = marking_stack_.Pop(); | |
| 145 ASSERT(IsGrey(obj)); | |
| 146 Map* map = obj->map(); | |
| 147 int size = obj->SizeFromMap(map); | |
| 148 bytes_to_process -= size; | |
| 149 if (IsWhite(map)) WhiteToGrey(map); | |
| 150 obj->IterateBody(map->instance_type(), size, &visitor_); | |
| 151 MarkBlack(obj); | |
| 152 count++; | |
| 153 } | |
| 154 if (FLAG_trace_incremental_marking) { | |
| 155 double end = OS::TimeCurrentMillis(); | |
| 156 PrintF("[IncrementalMarking] %d objects marked, spent %d ms\n", | |
| 157 count, | |
| 158 static_cast<int>(end - start)); | |
| 159 } | |
| 160 allocated_ = 0; | |
| 161 if (marking_stack_.is_empty()) MarkingComplete(); | |
| 162 } | |
| 163 } | |
| 164 } | |
| 165 | |
| 166 static void RecordWrite(HeapObject* obj, Object* value) { | |
| 167 if (state_ != STOPPED && value->IsHeapObject()) { | |
| 168 if (IsBlack(obj) && IsWhite(HeapObject::cast(value))) { | |
| 169 BlackToGrey(obj); | |
| 170 if (state_ == COMPLETE) { | |
| 171 state_ = MARKING; | |
| 172 if (FLAG_trace_incremental_marking) { | |
| 173 PrintF("[IncrementalMarking] Restarting (new grey objects)\n"); | |
| 174 } | |
| 175 } | |
| 176 } | |
| 177 } | |
| 178 } | |
| 179 | |
| 180 static void RecordWriteOf(HeapObject* value) { | |
| 181 if (state_ != STOPPED) { | |
| 182 if (IsWhite(value)) { | |
| 183 WhiteToGrey(value); | |
| 184 if (state_ == COMPLETE) { | |
| 185 state_ = MARKING; | |
| 186 if (FLAG_trace_incremental_marking) { | |
| 187 PrintF("[IncrementalMarking] Restarting (new grey objects)\n"); | |
| 188 } | |
| 189 } | |
| 190 } | |
| 191 } | |
| 192 } | |
| 193 | |
| 194 | |
| 195 static void RecordWrites(HeapObject* obj) { | |
| 196 if (state_ != STOPPED) { | |
| 197 if (IsBlack(obj)) { | |
| 198 BlackToGrey(obj); | |
| 199 if (state_ == COMPLETE) { | |
| 200 state_ = MARKING; | |
| 201 if (FLAG_trace_incremental_marking) { | |
| 202 PrintF("[IncrementalMarking] Restarting (new grey objects)\n"); | |
| 203 } | |
| 204 } | |
| 205 } | |
| 206 } | |
| 207 } | |
| 208 | |
| 209 | |
| 210 // Black markbits: 10 | |
| 211 static inline bool IsBlack(HeapObject* obj) { | |
| 212 return Marking::IsMarked(obj->address()); | |
|
Erik Corry
2011/02/22 12:27:19
Assert that the other bit is not marked?
| |
| 213 } | |
| 214 | |
| 215 // White markbits: 00 | |
| 216 static inline bool IsWhite(HeapObject* obj) { | |
| 217 return !Marking::IsMarked(obj->address()) && | |
| 218 !Marking::IsMarked(obj->address() + kPointerSize); | |
| 219 } | |
| 220 | |
| 221 // Grey markbits: 01 | |
|
Erik Corry
2011/02/22 12:27:19
Probably should be 11 when we handle overflow.
Vyacheslav Egorov (Chromium)
2011/02/23 14:31:46
Yes. Will investigate when we start handling overf
| |
| 222 static inline bool IsGrey(HeapObject* obj) { | |
| 223 return Marking::IsMarked(obj->address() + kPointerSize); | |
|
Erik Corry
2011/02/22 12:27:19
Assert that the other bit is not marked?
| |
| 224 } | |
| 225 | |
| 226 static inline void BlackToGrey(HeapObject* obj) { | |
| 227 ASSERT(IsBlack(obj)); | |
| 228 Marking::ClearMark(obj->address()); | |
| 229 Marking::SetMark(obj->address() + kPointerSize); | |
| 230 ASSERT(IsGrey(obj)); | |
| 231 | |
| 232 marking_stack_.Push(obj); | |
| 233 ASSERT(!marking_stack_.overflowed()); | |
| 234 } | |
| 235 | |
| 236 static inline void WhiteToGrey(HeapObject* obj) { | |
| 237 ASSERT(IsWhite(obj)); | |
| 238 Marking::SetMark(obj->address() + kPointerSize); | |
| 239 ASSERT(IsGrey(obj)); | |
| 240 | |
| 241 marking_stack_.Push(obj); | |
| 242 ASSERT(!marking_stack_.overflowed()); | |
| 243 } | |
| 244 | |
| 245 static inline void MarkBlack(HeapObject* obj) { | |
| 246 Marking::SetMark(obj->address()); | |
| 247 Marking::ClearMark(obj->address() + kPointerSize); | |
| 248 ASSERT(IsBlack(obj)); | |
| 249 } | |
| 250 | |
| 251 static inline const char* ColorStr(HeapObject* obj) { | |
| 252 if (IsBlack(obj)) return "black"; | |
| 253 if (IsWhite(obj)) return "white"; | |
| 254 if (IsGrey(obj)) return "grey"; | |
| 255 return "???"; | |
|
Erik Corry
2011/02/22 12:27:19
UNREACHABLE()?
Vyacheslav Egorov (Chromium)
2011/02/23 14:31:46
Done.
| |
| 256 } | |
| 257 | |
| 258 private: | |
| 259 static intptr_t allocated_; | |
| 260 static State state_; | |
| 261 static MarkingStack marking_stack_; | |
| 262 | |
| 263 class MarkingVisitor : public ObjectVisitor { | |
| 264 public: | |
| 265 void VisitPointer(Object** p) { | |
| 266 MarkObjectByPointer(p); | |
| 267 } | |
| 268 | |
| 269 void VisitPointers(Object** start, Object** end) { | |
| 270 for (Object** p = start; p < end; p++) MarkObjectByPointer(p); | |
| 271 } | |
| 272 | |
| 273 private: | |
| 274 // Mark object pointed to by p. | |
| 275 INLINE(static void MarkObjectByPointer(Object** p)) { | |
| 276 if ((*p)->IsHeapObject()) { | |
| 277 HeapObject* object = HeapObject::cast(*p); | |
| 278 if (IsWhite(object)) WhiteToGrey(object); | |
| 279 } | |
| 280 } | |
| 281 }; | |
| 282 | |
| 283 | |
| 284 class RootMarkingVisitor : public ObjectVisitor { | |
| 285 public: | |
| 286 void VisitPointer(Object** p) { | |
| 287 MarkObjectByPointer(p); | |
| 288 } | |
| 289 | |
| 290 void VisitPointers(Object** start, Object** end) { | |
| 291 for (Object** p = start; p < end; p++) MarkObjectByPointer(p); | |
| 292 } | |
| 293 | |
| 294 private: | |
| 295 void MarkObjectByPointer(Object** p) { | |
| 296 if (!(*p)->IsHeapObject()) return; | |
| 297 | |
| 298 HeapObject* object = HeapObject::cast(*p); | |
| 299 if (!IsWhite(object)) return; | |
| 300 | |
| 301 Map* map = object->map(); | |
| 302 | |
| 303 WhiteToGrey(object); | |
|
Erik Corry
2011/02/22 12:27:19
This pushes the object onto the stack. When it is
Vyacheslav Egorov (Chromium)
2011/02/23 14:31:46
Done.
| |
| 304 | |
| 305 if (IsWhite(map)) WhiteToGrey(map); | |
|
Erik Corry
2011/02/22 12:27:19
Here we also mark the map. Aren't we doing it twi
Vyacheslav Egorov (Chromium)
2011/02/23 14:31:46
Done.
| |
| 306 } | |
| 307 }; | |
| 308 | |
| 309 | |
| 310 static void ClearMarkbits(PagedSpace* space) { | |
| 311 PageIterator it(space, PageIterator::PAGES_IN_USE); | |
| 312 | |
| 313 while (it.has_next()) { | |
| 314 Page* p = it.next(); | |
| 315 p->markbits()->Clear(); | |
| 316 } | |
| 317 } | |
| 318 | |
| 319 | |
| 320 static void ClearMarkbits() { | |
| 321 // We are sweeping code and map spaces precisely so clearing is not required . | |
|
Erik Corry
2011/02/22 12:27:19
lint?
Vyacheslav Egorov (Chromium)
2011/02/23 14:31:46
Done.
| |
| 322 ClearMarkbits(Heap::old_pointer_space()); | |
| 323 ClearMarkbits(Heap::old_data_space()); | |
| 324 ClearMarkbits(Heap::cell_space()); | |
| 325 } | |
| 326 | |
| 327 | |
| 328 #ifdef DEBUG | |
| 329 static void VerifyMarkbitsAreClean(PagedSpace* space) { | |
| 330 PageIterator it(space, PageIterator::PAGES_IN_USE); | |
| 331 | |
| 332 while (it.has_next()) { | |
| 333 Page* p = it.next(); | |
| 334 ASSERT(p->markbits()->IsClean()); | |
| 335 } | |
| 336 } | |
| 337 | |
| 338 static void VerifyMarkbitsAreClean() { | |
| 339 VerifyMarkbitsAreClean(Heap::old_pointer_space()); | |
| 340 VerifyMarkbitsAreClean(Heap::old_data_space()); | |
| 341 VerifyMarkbitsAreClean(Heap::code_space()); | |
| 342 VerifyMarkbitsAreClean(Heap::cell_space()); | |
| 343 VerifyMarkbitsAreClean(Heap::map_space()); | |
| 344 } | |
| 345 #endif | |
| 346 | |
| 347 static MarkingVisitor visitor_; | |
| 348 }; | |
| 349 | |
| 350 } } // namespace v8::internal | |
| 351 | |
| 352 #endif // V8_INCREMENTAL_MARKING_H_ | |
| OLD | NEW |