Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 50 const char* Marking::kImpossibleBitPattern = "01"; | 50 const char* Marking::kImpossibleBitPattern = "01"; |
| 51 | 51 |
| 52 | 52 |
| 53 // ------------------------------------------------------------------------- | 53 // ------------------------------------------------------------------------- |
| 54 // MarkCompactCollector | 54 // MarkCompactCollector |
| 55 | 55 |
| 56 MarkCompactCollector::MarkCompactCollector() : // NOLINT | 56 MarkCompactCollector::MarkCompactCollector() : // NOLINT |
| 57 #ifdef DEBUG | 57 #ifdef DEBUG |
| 58 state_(IDLE), | 58 state_(IDLE), |
| 59 #endif | 59 #endif |
| 60 force_compaction_(false), | |
| 61 compacting_collection_(false), | |
| 62 compact_on_next_gc_(false), | |
| 63 previous_marked_count_(0), | |
| 64 tracer_(NULL), | 60 tracer_(NULL), |
| 65 #ifdef DEBUG | 61 #ifdef DEBUG |
| 66 live_young_objects_size_(0), | 62 live_young_objects_size_(0), |
| 67 live_old_pointer_objects_size_(0), | 63 live_old_pointer_objects_size_(0), |
| 68 live_old_data_objects_size_(0), | 64 live_old_data_objects_size_(0), |
| 69 live_code_objects_size_(0), | 65 live_code_objects_size_(0), |
| 70 live_map_objects_size_(0), | 66 live_map_objects_size_(0), |
| 71 live_cell_objects_size_(0), | 67 live_cell_objects_size_(0), |
| 72 live_lo_objects_size_(0), | 68 live_lo_objects_size_(0), |
| 73 live_bytes_(0), | 69 live_bytes_(0), |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 92 | 88 |
| 93 static void VerifyMarking(Address bottom, Address top) { | 89 static void VerifyMarking(Address bottom, Address top) { |
| 94 VerifyMarkingVisitor visitor; | 90 VerifyMarkingVisitor visitor; |
| 95 HeapObject* object; | 91 HeapObject* object; |
| 96 Address next_object_must_be_here_or_later = bottom; | 92 Address next_object_must_be_here_or_later = bottom; |
| 97 | 93 |
| 98 for (Address current = bottom; | 94 for (Address current = bottom; |
| 99 current < top; | 95 current < top; |
| 100 current += kPointerSize) { | 96 current += kPointerSize) { |
| 101 object = HeapObject::FromAddress(current); | 97 object = HeapObject::FromAddress(current); |
| 102 if (HEAP->mark_compact_collector()->IsMarked(object)) { | 98 if (MarkCompactCollector::IsMarked(object)) { |
| 103 ASSERT(current >= next_object_must_be_here_or_later); | 99 ASSERT(current >= next_object_must_be_here_or_later); |
| 104 object->Iterate(&visitor); | 100 object->Iterate(&visitor); |
| 105 next_object_must_be_here_or_later = current + object->Size(); | 101 next_object_must_be_here_or_later = current + object->Size(); |
| 106 } | 102 } |
| 107 } | 103 } |
| 108 } | 104 } |
| 109 | 105 |
| 110 | 106 |
| 111 static void VerifyMarking(Page* p) { | 107 static void VerifyMarking(Page* p) { |
| 112 VerifyMarking(p->ObjectAreaStart(), p->ObjectAreaEnd()); | 108 VerifyMarking(p->ObjectAreaStart(), p->ObjectAreaEnd()); |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 131 | 127 |
| 132 static void VerifyMarking(PagedSpace* space) { | 128 static void VerifyMarking(PagedSpace* space) { |
| 133 PageIterator it(space); | 129 PageIterator it(space); |
| 134 | 130 |
| 135 while (it.has_next()) { | 131 while (it.has_next()) { |
| 136 VerifyMarking(it.next()); | 132 VerifyMarking(it.next()); |
| 137 } | 133 } |
| 138 } | 134 } |
| 139 | 135 |
| 140 | 136 |
| 141 static void VerifyMarking() { | 137 static void VerifyMarking(Heap* heap) { |
| 142 // TODO(gc) ISOLATES | 138 VerifyMarking(heap->old_pointer_space()); |
| 143 VerifyMarking(HEAP->old_pointer_space()); | 139 VerifyMarking(heap->old_data_space()); |
| 144 VerifyMarking(HEAP->old_data_space()); | 140 VerifyMarking(heap->code_space()); |
| 145 VerifyMarking(HEAP->code_space()); | 141 VerifyMarking(heap->cell_space()); |
| 146 VerifyMarking(HEAP->cell_space()); | 142 VerifyMarking(heap->map_space()); |
| 147 VerifyMarking(HEAP->map_space()); | 143 VerifyMarking(heap->new_space()); |
| 148 VerifyMarking(HEAP->new_space()); | |
| 149 | 144 |
| 150 VerifyMarkingVisitor visitor; | 145 VerifyMarkingVisitor visitor; |
| 151 HEAP->IterateStrongRoots(&visitor, VISIT_ONLY_STRONG); | 146 heap->IterateStrongRoots(&visitor, VISIT_ONLY_STRONG); |
| 147 } | |
| 148 | |
| 149 | |
| 150 class VerifyEvacuationVisitor: public ObjectVisitor { | |
| 151 public: | |
| 152 void VisitPointers(Object** start, Object** end) { | |
| 153 for (Object** current = start; current < end; current++) { | |
| 154 if ((*current)->IsHeapObject()) { | |
| 155 HeapObject* object = HeapObject::cast(*current); | |
| 156 if (MarkCompactCollector::IsOnEvacuationCandidate(object)) { | |
| 157 HEAP->TracePathToObject(source_); | |
| 158 CHECK(false); | |
| 159 } | |
| 160 } | |
| 161 } | |
| 162 } | |
| 163 | |
| 164 HeapObject* source_; | |
| 165 }; | |
| 166 | |
| 167 | |
| 168 static void VerifyEvacuation(Address bottom, Address top) { | |
| 169 VerifyEvacuationVisitor visitor; | |
| 170 HeapObject* object; | |
| 171 Address next_object_must_be_here_or_later = bottom; | |
| 172 | |
| 173 for (Address current = bottom; | |
| 174 current < top; | |
| 175 current += kPointerSize) { | |
| 176 object = HeapObject::FromAddress(current); | |
| 177 if (MarkCompactCollector::IsMarked(object)) { | |
| 178 ASSERT(current >= next_object_must_be_here_or_later); | |
| 179 visitor.source_ = object; | |
| 180 object->Iterate(&visitor); | |
| 181 next_object_must_be_here_or_later = current + object->Size(); | |
| 182 } | |
| 183 } | |
| 184 } | |
| 185 | |
| 186 | |
| 187 static void VerifyEvacuation(Page* p) { | |
| 188 if (p->IsEvacuationCandidate()) return; | |
| 189 | |
| 190 VerifyEvacuation(p->ObjectAreaStart(), p->ObjectAreaEnd()); | |
| 191 } | |
| 192 | |
| 193 | |
| 194 static void VerifyEvacuation(NewSpace* space) { | |
| 195 // TODO(gc): XXX | |
|
Erik Corry
2011/06/20 20:41:26
Add text or remove XXX
Vyacheslav Egorov (Chromium)
2011/06/21 11:44:48
Done.
| |
| 196 } | |
| 197 | |
| 198 | |
| 199 static void VerifyEvacuation(PagedSpace* space) { | |
| 200 PageIterator it(space); | |
| 201 | |
| 202 while (it.has_next()) { | |
| 203 VerifyEvacuation(it.next()); | |
| 204 } | |
| 205 } | |
| 206 | |
| 207 | |
| 208 static void VerifyEvacuation(Heap* heap) { | |
| 209 VerifyEvacuation(heap->old_pointer_space()); | |
| 210 VerifyEvacuation(heap->old_data_space()); | |
| 211 VerifyEvacuation(heap->code_space()); | |
| 212 VerifyEvacuation(heap->cell_space()); | |
| 213 VerifyEvacuation(heap->map_space()); | |
| 214 VerifyEvacuation(heap->new_space()); | |
| 215 | |
| 216 VerifyEvacuationVisitor visitor; | |
| 217 heap->IterateStrongRoots(&visitor, VISIT_ALL); | |
| 152 } | 218 } |
| 153 #endif | 219 #endif |
| 154 | 220 |
| 221 | |
| 222 void MarkCompactCollector::AddEvacuationCandidate(Page* p) { | |
| 223 p->MarkEvacuationCandidate(); | |
| 224 evacuation_candidates_.Add(p); | |
| 225 } | |
| 226 | |
| 227 | |
| 155 void MarkCompactCollector::CollectGarbage() { | 228 void MarkCompactCollector::CollectGarbage() { |
| 156 // Make sure that Prepare() has been called. The individual steps below will | 229 // Make sure that Prepare() has been called. The individual steps below will |
| 157 // update the state as they proceed. | 230 // update the state as they proceed. |
| 158 ASSERT(state_ == PREPARE_GC); | 231 ASSERT(state_ == PREPARE_GC); |
| 159 | 232 |
| 160 // Prepare has selected whether to compact the old generation or not. | |
| 161 // Tell the tracer. | |
| 162 if (IsCompacting()) tracer_->set_is_compacting(); | |
| 163 | |
| 164 MarkLiveObjects(); | 233 MarkLiveObjects(); |
| 165 ASSERT(heap_->incremental_marking()->IsStopped()); | 234 ASSERT(heap_->incremental_marking()->IsStopped()); |
| 166 | 235 |
| 167 if (FLAG_collect_maps) ClearNonLiveTransitions(); | 236 if (FLAG_collect_maps) ClearNonLiveTransitions(); |
| 168 | 237 |
| 169 #ifdef DEBUG | 238 #ifdef DEBUG |
| 170 VerifyMarking(); | 239 VerifyMarking(heap_); |
| 171 #endif | 240 #endif |
| 172 | 241 |
| 173 SweepSpaces(); | 242 SweepSpaces(); |
| 174 | 243 |
| 175 heap_->isolate()->pc_to_code_cache()->Flush(); | 244 heap_->isolate()->pc_to_code_cache()->Flush(); |
| 176 | 245 |
| 177 Finish(); | 246 Finish(); |
| 178 | 247 |
| 179 // Check that swept all marked objects and | 248 // Null out the GC tracer. |
|
Erik Corry
2011/06/20 20:41:26
Comment doesnt really add much. Why are we nullin
Vyacheslav Egorov (Chromium)
2011/06/21 11:44:48
Cause it's stack allocated.
| |
| 180 // null out the GC tracer. | |
| 181 // TODO(gc) does not work with conservative sweeping. | |
| 182 // ASSERT(tracer_->marked_count() == 0); | |
| 183 tracer_ = NULL; | 249 tracer_ = NULL; |
| 184 } | 250 } |
| 185 | 251 |
| 186 | 252 |
| 187 #ifdef DEBUG | 253 #ifdef DEBUG |
| 188 static void VerifyMarkbitsAreClean(PagedSpace* space) { | 254 static void VerifyMarkbitsAreClean(PagedSpace* space) { |
| 189 PageIterator it(space); | 255 PageIterator it(space); |
| 190 | 256 |
| 191 while (it.has_next()) { | 257 while (it.has_next()) { |
| 192 Page* p = it.next(); | 258 Page* p = it.next(); |
| 193 ASSERT(p->markbits()->IsClean()); | 259 ASSERT(p->markbits()->IsClean()); |
| 194 } | 260 } |
| 195 } | 261 } |
| 196 | 262 |
| 197 static void VerifyMarkbitsAreClean(NewSpace* space) { | 263 static void VerifyMarkbitsAreClean(NewSpace* space) { |
| 198 NewSpacePageIterator it(space->ToSpaceStart(), space->ToSpaceEnd()); | 264 NewSpacePageIterator it(space->ToSpaceStart(), space->ToSpaceEnd()); |
| 199 | 265 |
| 200 while (it.has_next()) { | 266 while (it.has_next()) { |
| 201 NewSpacePage* p = it.next(); | 267 NewSpacePage* p = it.next(); |
| 202 ASSERT(p->markbits()->IsClean()); | 268 ASSERT(p->markbits()->IsClean()); |
| 203 } | 269 } |
| 204 } | 270 } |
| 205 | 271 |
| 206 static void VerifyMarkbitsAreClean() { | 272 static void VerifyMarkbitsAreClean(Heap* heap) { |
| 207 VerifyMarkbitsAreClean(HEAP->old_pointer_space()); | 273 VerifyMarkbitsAreClean(heap->old_pointer_space()); |
| 208 VerifyMarkbitsAreClean(HEAP->old_data_space()); | 274 VerifyMarkbitsAreClean(heap->old_data_space()); |
| 209 VerifyMarkbitsAreClean(HEAP->code_space()); | 275 VerifyMarkbitsAreClean(heap->code_space()); |
| 210 VerifyMarkbitsAreClean(HEAP->cell_space()); | 276 VerifyMarkbitsAreClean(heap->cell_space()); |
| 211 VerifyMarkbitsAreClean(HEAP->map_space()); | 277 VerifyMarkbitsAreClean(heap->map_space()); |
| 212 VerifyMarkbitsAreClean(HEAP->new_space()); | 278 VerifyMarkbitsAreClean(heap->new_space()); |
| 213 } | 279 } |
| 214 #endif | 280 #endif |
| 215 | 281 |
| 216 | 282 |
| 217 static void ClearMarkbits(PagedSpace* space) { | 283 static void ClearMarkbits(PagedSpace* space) { |
| 218 PageIterator it(space); | 284 PageIterator it(space); |
| 219 | 285 |
| 220 while (it.has_next()) { | 286 while (it.has_next()) { |
| 221 Page* p = it.next(); | 287 Page* p = it.next(); |
| 222 p->markbits()->Clear(); | 288 p->markbits()->Clear(); |
| 223 } | 289 } |
| 224 } | 290 } |
| 225 | 291 |
| 226 | 292 |
| 227 static void ClearMarkbits(NewSpace* space) { | 293 static void ClearMarkbits(NewSpace* space) { |
| 228 NewSpacePageIterator it(space->ToSpaceStart(), space->ToSpaceEnd()); | 294 NewSpacePageIterator it(space->ToSpaceStart(), space->ToSpaceEnd()); |
| 229 | 295 |
| 230 while (it.has_next()) { | 296 while (it.has_next()) { |
| 231 NewSpacePage* p = it.next(); | 297 NewSpacePage* p = it.next(); |
| 232 p->markbits()->Clear(); | 298 p->markbits()->Clear(); |
| 233 } | 299 } |
| 234 } | 300 } |
| 235 | 301 |
| 236 | 302 |
| 237 static void ClearMarkbits() { | 303 static void ClearMarkbits(Heap* heap) { |
| 238 // TODO(gc): Clean the mark bits while sweeping. | 304 // TODO(gc): Clean the mark bits while sweeping. |
| 239 Heap* heap = HEAP; | |
| 240 ClearMarkbits(heap->code_space()); | 305 ClearMarkbits(heap->code_space()); |
| 241 ClearMarkbits(heap->map_space()); | 306 ClearMarkbits(heap->map_space()); |
| 242 ClearMarkbits(heap->old_pointer_space()); | 307 ClearMarkbits(heap->old_pointer_space()); |
| 243 ClearMarkbits(heap->old_data_space()); | 308 ClearMarkbits(heap->old_data_space()); |
| 244 ClearMarkbits(heap->cell_space()); | 309 ClearMarkbits(heap->cell_space()); |
| 245 ClearMarkbits(heap->new_space()); | 310 ClearMarkbits(heap->new_space()); |
| 246 } | 311 } |
| 247 | 312 |
| 248 | 313 |
| 249 void Marking::TransferMark(Address old_start, Address new_start) { | 314 void Marking::TransferMark(Address old_start, Address new_start) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 281 MarkBit old_mark_bit = MarkBitFrom(old_start); | 346 MarkBit old_mark_bit = MarkBitFrom(old_start); |
| 282 if (!old_mark_bit.Get()) { | 347 if (!old_mark_bit.Get()) { |
| 283 return; | 348 return; |
| 284 } | 349 } |
| 285 } | 350 } |
| 286 new_mark_bit.Set(); | 351 new_mark_bit.Set(); |
| 287 } | 352 } |
| 288 } | 353 } |
| 289 | 354 |
| 290 | 355 |
| 356 void MarkCompactCollector::CollectEvacuationCandidates(PagedSpace* space) { | |
| 357 ASSERT(space->identity() == OLD_POINTER_SPACE || | |
| 358 space->identity() == OLD_DATA_SPACE); | |
| 359 | |
| 360 PageIterator it(space); | |
| 361 while (it.has_next()) { | |
| 362 Page* p = it.next(); | |
| 363 if (space->IsFragmented(p)) { | |
| 364 AddEvacuationCandidate(p); | |
| 365 } else { | |
| 366 p->ClearEvacuationCandidate(); | |
| 367 } | |
| 368 } | |
| 369 } | |
| 370 | |
| 371 | |
| 372 static void ClearEvacuationCandidates(PagedSpace* space) { | |
| 373 ASSERT(space->identity() == OLD_POINTER_SPACE || | |
| 374 space->identity() == OLD_DATA_SPACE); | |
| 375 | |
| 376 PageIterator it(space); | |
| 377 while (it.has_next()) { | |
| 378 Page* p = it.next(); | |
| 379 p->ClearEvacuationCandidate(); | |
| 380 } | |
| 381 } | |
| 382 | |
| 383 | |
| 291 void MarkCompactCollector::Prepare(GCTracer* tracer) { | 384 void MarkCompactCollector::Prepare(GCTracer* tracer) { |
| 385 // TODO(gc) re-enable code flushing. | |
| 292 FLAG_flush_code = false; | 386 FLAG_flush_code = false; |
| 293 FLAG_always_compact = false; | 387 FLAG_always_compact = false; |
| 294 FLAG_never_compact = true; | |
| 295 | 388 |
| 296 // Disable collection of maps if incremental marking is enabled. | 389 // Disable collection of maps if incremental marking is enabled. |
| 297 // TODO(gc) improve maps collection algorithm to work with incremental | 390 // TODO(gc) improve maps collection algorithm to work with incremental |
| 298 // marking. | 391 // marking. |
| 299 if (FLAG_incremental_marking) FLAG_collect_maps = false; | 392 if (FLAG_incremental_marking) FLAG_collect_maps = false; |
| 300 | 393 |
| 301 // Rather than passing the tracer around we stash it in a static member | 394 // Rather than passing the tracer around we stash it in a static member |
| 302 // variable. | 395 // variable. |
| 303 tracer_ = tracer; | 396 tracer_ = tracer; |
| 304 | 397 |
| 305 #ifdef DEBUG | 398 #ifdef DEBUG |
| 306 ASSERT(state_ == IDLE); | 399 ASSERT(state_ == IDLE); |
| 307 state_ = PREPARE_GC; | 400 state_ = PREPARE_GC; |
| 308 #endif | 401 #endif |
| 309 ASSERT(!FLAG_always_compact || !FLAG_never_compact); | 402 ASSERT(!FLAG_always_compact || !FLAG_never_compact); |
| 310 | 403 |
| 311 compacting_collection_ = | |
| 312 FLAG_always_compact || force_compaction_ || compact_on_next_gc_; | |
| 313 compact_on_next_gc_ = false; | |
| 314 | |
| 315 if (FLAG_never_compact) compacting_collection_ = false; | |
| 316 if (!heap()->map_space()->MapPointersEncodable()) { | |
| 317 compacting_collection_ = false; | |
| 318 } | |
| 319 if (FLAG_collect_maps) CreateBackPointers(); | 404 if (FLAG_collect_maps) CreateBackPointers(); |
| 320 #ifdef ENABLE_GDB_JIT_INTERFACE | 405 #ifdef ENABLE_GDB_JIT_INTERFACE |
| 321 if (FLAG_gdbjit) { | 406 if (FLAG_gdbjit) { |
| 322 // If GDBJIT interface is active disable compaction. | 407 // If GDBJIT interface is active disable compaction. |
| 323 compacting_collection_ = false; | 408 compacting_collection_ = false; |
| 324 } | 409 } |
| 325 #endif | 410 #endif |
| 326 | 411 |
| 412 if (!FLAG_never_compact) { | |
| 413 slots_buffer_.Clear(); | |
| 414 evacuation_candidates_.Rewind(0); | |
| 415 | |
| 416 if (!heap()->incremental_marking()->IsMarking()) { | |
| 417 CollectEvacuationCandidates(heap()->old_pointer_space()); | |
| 418 CollectEvacuationCandidates(heap()->old_data_space()); | |
| 419 } else { | |
| 420 ClearEvacuationCandidates(heap()->old_pointer_space()); | |
| 421 ClearEvacuationCandidates(heap()->old_data_space()); | |
| 422 } | |
| 423 } | |
| 424 | |
| 327 PagedSpaces spaces; | 425 PagedSpaces spaces; |
| 328 for (PagedSpace* space = spaces.next(); | 426 for (PagedSpace* space = spaces.next(); |
| 329 space != NULL; space = spaces.next()) { | 427 space != NULL; |
| 330 space->PrepareForMarkCompact(compacting_collection_); | 428 space = spaces.next()) { |
| 429 space->PrepareForMarkCompact(); | |
| 331 } | 430 } |
| 332 | 431 |
| 333 if (!heap()->incremental_marking()->IsMarking()) { | 432 if (!heap()->incremental_marking()->IsMarking()) { |
| 334 ClearMarkbits(); | 433 ClearMarkbits(heap_); |
| 335 #ifdef DEBUG | 434 #ifdef DEBUG |
| 336 VerifyMarkbitsAreClean(); | 435 VerifyMarkbitsAreClean(heap_); |
| 337 #endif | 436 #endif |
| 338 } | 437 } |
| 339 | 438 |
| 340 #ifdef DEBUG | 439 #ifdef DEBUG |
| 341 live_bytes_ = 0; | 440 live_bytes_ = 0; |
| 342 live_young_objects_size_ = 0; | 441 live_young_objects_size_ = 0; |
| 343 live_old_pointer_objects_size_ = 0; | 442 live_old_pointer_objects_size_ = 0; |
| 344 live_old_data_objects_size_ = 0; | 443 live_old_data_objects_size_ = 0; |
| 345 live_code_objects_size_ = 0; | 444 live_code_objects_size_ = 0; |
| 346 live_map_objects_size_ = 0; | 445 live_map_objects_size_ = 0; |
| 347 live_cell_objects_size_ = 0; | 446 live_cell_objects_size_ = 0; |
| 348 live_lo_objects_size_ = 0; | 447 live_lo_objects_size_ = 0; |
| 349 #endif | 448 #endif |
| 350 } | 449 } |
| 351 | 450 |
| 352 | 451 |
| 353 void MarkCompactCollector::Finish() { | 452 void MarkCompactCollector::Finish() { |
| 354 #ifdef DEBUG | 453 #ifdef DEBUG |
| 355 ASSERT(state_ == SWEEP_SPACES || state_ == RELOCATE_OBJECTS); | 454 ASSERT(state_ == SWEEP_SPACES || state_ == RELOCATE_OBJECTS); |
| 356 state_ = IDLE; | 455 state_ = IDLE; |
| 357 #endif | 456 #endif |
| 358 // The stub cache is not traversed during GC; clear the cache to | 457 // The stub cache is not traversed during GC; clear the cache to |
| 359 // force lazy re-initialization of it. This must be done after the | 458 // force lazy re-initialization of it. This must be done after the |
| 360 // GC, because it relies on the new address of certain old space | 459 // GC, because it relies on the new address of certain old space |
| 361 // objects (empty string, illegal builtin). | 460 // objects (empty string, illegal builtin). |
| 362 heap()->isolate()->stub_cache()->Clear(); | 461 heap()->isolate()->stub_cache()->Clear(); |
| 363 | 462 |
| 364 heap()->external_string_table_.CleanUp(); | 463 heap()->external_string_table_.CleanUp(); |
| 365 | |
| 366 // If we've just compacted old space there's no reason to check the | |
| 367 // fragmentation limit. Just return. | |
| 368 if (HasCompacted()) return; | |
| 369 | |
| 370 // We compact the old generation on the next GC if it has gotten too | |
| 371 // fragmented (ie, we could recover an expected amount of space by | |
| 372 // reclaiming the waste and free list blocks). | |
| 373 static const int kFragmentationLimit = 15; // Percent. | |
| 374 static const int kFragmentationAllowed = 1 * MB; // Absolute. | |
| 375 intptr_t old_gen_recoverable = 0; | |
| 376 intptr_t old_gen_used = 0; | |
| 377 | |
| 378 OldSpaces spaces; | |
| 379 for (OldSpace* space = spaces.next(); space != NULL; space = spaces.next()) { | |
| 380 old_gen_recoverable += space->Waste() + space->Available(); | |
| 381 old_gen_used += space->Size(); | |
| 382 } | |
| 383 | |
| 384 int old_gen_fragmentation = | |
| 385 static_cast<int>((old_gen_recoverable * 100.0) / old_gen_used); | |
| 386 if (old_gen_fragmentation > kFragmentationLimit && | |
| 387 old_gen_recoverable > kFragmentationAllowed) { | |
| 388 compact_on_next_gc_ = true; | |
| 389 } | |
| 390 } | 464 } |
| 391 | 465 |
| 392 | 466 |
| 393 // ------------------------------------------------------------------------- | 467 // ------------------------------------------------------------------------- |
| 394 // Phase 1: tracing and marking live objects. | 468 // Phase 1: tracing and marking live objects. |
| 395 // before: all objects are in normal state. | 469 // before: all objects are in normal state. |
| 396 // after: a live object's map pointer is marked as '00'. | 470 // after: a live object's map pointer is marked as '00'. |
| 397 | 471 |
| 398 // Marking all live objects in the heap as part of mark-sweep or mark-compact | 472 // Marking all live objects in the heap as part of mark-sweep or mark-compact |
| 399 // collection. Before marking, all objects are in their normal state. After | 473 // collection. Before marking, all objects are in their normal state. After |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 550 // (ConsString::cast(object)->second() == HEAP->empty_string()) | 624 // (ConsString::cast(object)->second() == HEAP->empty_string()) |
| 551 // except the maps for the object and its possible substrings might be | 625 // except the maps for the object and its possible substrings might be |
| 552 // marked. | 626 // marked. |
| 553 HeapObject* object = HeapObject::cast(*p); | 627 HeapObject* object = HeapObject::cast(*p); |
| 554 Map* map = object->map(); | 628 Map* map = object->map(); |
| 555 InstanceType type = map->instance_type(); | 629 InstanceType type = map->instance_type(); |
| 556 if ((type & kShortcutTypeMask) != kShortcutTypeTag) return object; | 630 if ((type & kShortcutTypeMask) != kShortcutTypeTag) return object; |
| 557 | 631 |
| 558 Object* second = reinterpret_cast<ConsString*>(object)->unchecked_second(); | 632 Object* second = reinterpret_cast<ConsString*>(object)->unchecked_second(); |
| 559 Heap* heap = map->GetHeap(); | 633 Heap* heap = map->GetHeap(); |
| 560 if (second != heap->raw_unchecked_empty_string()) { | 634 if (second != heap->empty_string()) { |
| 561 return object; | 635 return object; |
| 562 } | 636 } |
| 563 | 637 |
| 564 // Since we don't have the object's start, it is impossible to update the | 638 // Since we don't have the object's start, it is impossible to update the |
| 565 // page dirty marks. Therefore, we only replace the string with its left | 639 // page dirty marks. Therefore, we only replace the string with its left |
| 566 // substring when page dirty marks do not change. | 640 // substring when page dirty marks do not change. |
| 567 // TODO(gc): Seems like we could relax this restriction with store buffers. | 641 // TODO(gc): Seems like we could relax this restriction with store buffers. |
| 568 Object* first = reinterpret_cast<ConsString*>(object)->unchecked_first(); | 642 Object* first = reinterpret_cast<ConsString*>(object)->unchecked_first(); |
| 569 if (!heap->InNewSpace(object) && heap->InNewSpace(first)) return object; | 643 if (!heap->InNewSpace(object) && heap->InNewSpace(first)) return object; |
| 570 | 644 |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 589 &FixedBodyVisitor<StaticMarkingVisitor, | 663 &FixedBodyVisitor<StaticMarkingVisitor, |
| 590 ConsString::BodyDescriptor, | 664 ConsString::BodyDescriptor, |
| 591 void>::Visit); | 665 void>::Visit); |
| 592 | 666 |
| 593 | 667 |
| 594 table_.Register(kVisitFixedArray, | 668 table_.Register(kVisitFixedArray, |
| 595 &FlexibleBodyVisitor<StaticMarkingVisitor, | 669 &FlexibleBodyVisitor<StaticMarkingVisitor, |
| 596 FixedArray::BodyDescriptor, | 670 FixedArray::BodyDescriptor, |
| 597 void>::Visit); | 671 void>::Visit); |
| 598 | 672 |
| 599 table_.Register(kVisitGlobalContext, | 673 table_.Register(kVisitGlobalContext, &VisitGlobalContext); |
| 600 &FixedBodyVisitor<StaticMarkingVisitor, | |
| 601 Context::MarkCompactBodyDescriptor, | |
| 602 void>::Visit); | |
| 603 | 674 |
| 604 table_.Register(kVisitByteArray, &DataObjectVisitor::Visit); | 675 table_.Register(kVisitByteArray, &DataObjectVisitor::Visit); |
| 605 table_.Register(kVisitFreeSpace, &DataObjectVisitor::Visit); | 676 table_.Register(kVisitFreeSpace, &DataObjectVisitor::Visit); |
| 606 table_.Register(kVisitSeqAsciiString, &DataObjectVisitor::Visit); | 677 table_.Register(kVisitSeqAsciiString, &DataObjectVisitor::Visit); |
| 607 table_.Register(kVisitSeqTwoByteString, &DataObjectVisitor::Visit); | 678 table_.Register(kVisitSeqTwoByteString, &DataObjectVisitor::Visit); |
| 608 | 679 |
| 609 table_.Register(kVisitOddball, | 680 table_.Register(kVisitOddball, |
| 610 &FixedBodyVisitor<StaticMarkingVisitor, | 681 &FixedBodyVisitor<StaticMarkingVisitor, |
| 611 Oddball::BodyDescriptor, | 682 Oddball::BodyDescriptor, |
| 612 void>::Visit); | 683 void>::Visit); |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 635 table_.RegisterSpecializations<JSObjectVisitor, | 706 table_.RegisterSpecializations<JSObjectVisitor, |
| 636 kVisitJSObject, | 707 kVisitJSObject, |
| 637 kVisitJSObjectGeneric>(); | 708 kVisitJSObjectGeneric>(); |
| 638 | 709 |
| 639 table_.RegisterSpecializations<StructObjectVisitor, | 710 table_.RegisterSpecializations<StructObjectVisitor, |
| 640 kVisitStruct, | 711 kVisitStruct, |
| 641 kVisitStructGeneric>(); | 712 kVisitStructGeneric>(); |
| 642 } | 713 } |
| 643 | 714 |
| 644 INLINE(static void VisitPointer(Heap* heap, Object** p)) { | 715 INLINE(static void VisitPointer(Heap* heap, Object** p)) { |
| 645 MarkObjectByPointer(heap, p); | 716 MarkObjectByPointer(heap, reinterpret_cast<Address>(p), p); |
| 646 } | 717 } |
| 647 | 718 |
| 648 INLINE(static void VisitPointers(Heap* heap, Object** start, Object** end)) { | 719 INLINE(static void VisitPointers(Heap* heap, Object** start, Object** end)) { |
| 649 // Mark all objects pointed to in [start, end). | 720 // Mark all objects pointed to in [start, end). |
| 650 const int kMinRangeForMarkingRecursion = 64; | 721 const int kMinRangeForMarkingRecursion = 64; |
| 651 if (end - start >= kMinRangeForMarkingRecursion) { | 722 if (end - start >= kMinRangeForMarkingRecursion) { |
| 652 if (VisitUnmarkedObjects(heap, start, end)) return; | 723 if (VisitUnmarkedObjects(heap, start, end)) return; |
| 653 // We are close to a stack overflow, so just mark the objects. | 724 // We are close to a stack overflow, so just mark the objects. |
| 654 } | 725 } |
| 655 for (Object** p = start; p < end; p++) MarkObjectByPointer(heap, p); | 726 for (Object** p = start; p < end; p++) { |
| 727 MarkObjectByPointer(heap, reinterpret_cast<Address>(start), p); | |
|
Erik Corry
2011/06/20 20:41:26
Seems like everywhere you call this you are castin
Vyacheslav Egorov (Chromium)
2011/06/21 11:44:48
Done.
| |
| 728 } | |
| 656 } | 729 } |
| 657 | 730 |
| 658 static inline void VisitCodeTarget(Heap* heap, RelocInfo* rinfo) { | 731 static inline void VisitCodeTarget(Heap* heap, RelocInfo* rinfo) { |
| 659 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode())); | 732 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode())); |
| 660 Code* code = Code::GetCodeFromTargetAddress(rinfo->target_address()); | 733 Code* code = Code::GetCodeFromTargetAddress(rinfo->target_address()); |
| 661 if (FLAG_cleanup_code_caches_at_gc && code->is_inline_cache_stub()) { | 734 if (FLAG_cleanup_code_caches_at_gc && code->is_inline_cache_stub()) { |
| 662 IC::Clear(rinfo->pc()); | 735 IC::Clear(rinfo->pc()); |
| 663 // Please note targets for cleared inline cached do not have to be | 736 // Please note targets for cleared inline cached do not have to be |
| 664 // marked since they are contained in HEAP->non_monomorphic_cache(). | 737 // marked since they are contained in HEAP->non_monomorphic_cache(). |
| 665 } else { | 738 } else { |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 683 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) && | 756 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) && |
| 684 rinfo->IsPatchedReturnSequence()) || | 757 rinfo->IsPatchedReturnSequence()) || |
| 685 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) && | 758 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) && |
| 686 rinfo->IsPatchedDebugBreakSlotSequence())); | 759 rinfo->IsPatchedDebugBreakSlotSequence())); |
| 687 HeapObject* code = Code::GetCodeFromTargetAddress(rinfo->call_address()); | 760 HeapObject* code = Code::GetCodeFromTargetAddress(rinfo->call_address()); |
| 688 MarkBit code_mark = Marking::MarkBitFrom(code); | 761 MarkBit code_mark = Marking::MarkBitFrom(code); |
| 689 heap->mark_compact_collector()->MarkObject(code, code_mark); | 762 heap->mark_compact_collector()->MarkObject(code, code_mark); |
| 690 } | 763 } |
| 691 | 764 |
| 692 // Mark object pointed to by p. | 765 // Mark object pointed to by p. |
| 693 INLINE(static void MarkObjectByPointer(Heap* heap, Object** p)) { | 766 INLINE(static void MarkObjectByPointer(Heap* heap, |
| 767 Address anchor, | |
| 768 Object** p)) { | |
| 694 if (!(*p)->IsHeapObject()) return; | 769 if (!(*p)->IsHeapObject()) return; |
| 695 HeapObject* object = ShortCircuitConsString(p); | 770 HeapObject* object = ShortCircuitConsString(p); |
| 771 heap->mark_compact_collector()->RecordSlot(anchor, p, object); | |
| 696 MarkBit mark = Marking::MarkBitFrom(object); | 772 MarkBit mark = Marking::MarkBitFrom(object); |
| 697 heap->mark_compact_collector()->MarkObject(object, mark); | 773 heap->mark_compact_collector()->MarkObject(object, mark); |
| 698 } | 774 } |
| 699 | 775 |
| 700 | 776 |
| 701 // Visit an unmarked object. | 777 // Visit an unmarked object. |
| 702 INLINE(static void VisitUnmarkedObject(MarkCompactCollector* collector, | 778 INLINE(static void VisitUnmarkedObject(MarkCompactCollector* collector, |
| 703 HeapObject* obj)) { | 779 HeapObject* obj)) { |
| 704 #ifdef DEBUG | 780 #ifdef DEBUG |
| 705 ASSERT(Isolate::Current()->heap()->Contains(obj)); | 781 ASSERT(Isolate::Current()->heap()->Contains(obj)); |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 722 Object** end) { | 798 Object** end) { |
| 723 // Return false is we are close to the stack limit. | 799 // Return false is we are close to the stack limit. |
| 724 StackLimitCheck check(heap->isolate()); | 800 StackLimitCheck check(heap->isolate()); |
| 725 if (check.HasOverflowed()) return false; | 801 if (check.HasOverflowed()) return false; |
| 726 | 802 |
| 727 MarkCompactCollector* collector = heap->mark_compact_collector(); | 803 MarkCompactCollector* collector = heap->mark_compact_collector(); |
| 728 // Visit the unmarked objects. | 804 // Visit the unmarked objects. |
| 729 for (Object** p = start; p < end; p++) { | 805 for (Object** p = start; p < end; p++) { |
| 730 Object* o = *p; | 806 Object* o = *p; |
| 731 if (!o->IsHeapObject()) continue; | 807 if (!o->IsHeapObject()) continue; |
| 808 heap->mark_compact_collector()->RecordSlot( | |
| 809 reinterpret_cast<Address>(start), | |
| 810 p, | |
| 811 o); | |
| 732 HeapObject* obj = HeapObject::cast(o); | 812 HeapObject* obj = HeapObject::cast(o); |
| 733 MarkBit mark = Marking::MarkBitFrom(obj); | 813 MarkBit mark = Marking::MarkBitFrom(obj); |
| 734 if (mark.Get()) continue; | 814 if (mark.Get()) continue; |
| 735 VisitUnmarkedObject(collector, obj); | 815 VisitUnmarkedObject(collector, obj); |
| 736 } | 816 } |
| 737 return true; | 817 return true; |
| 738 } | 818 } |
| 739 | 819 |
| 740 static inline void VisitExternalReference(Address* p) { } | 820 static inline void VisitExternalReference(Address* p) { } |
| 741 static inline void VisitRuntimeEntry(RelocInfo* rinfo) { } | 821 static inline void VisitRuntimeEntry(RelocInfo* rinfo) { } |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 764 map->GetHeap()); | 844 map->GetHeap()); |
| 765 } | 845 } |
| 766 | 846 |
| 767 // Code flushing support. | 847 // Code flushing support. |
| 768 | 848 |
| 769 // How many collections newly compiled code object will survive before being | 849 // How many collections newly compiled code object will survive before being |
| 770 // flushed. | 850 // flushed. |
| 771 static const int kCodeAgeThreshold = 5; | 851 static const int kCodeAgeThreshold = 5; |
| 772 | 852 |
| 773 inline static bool HasSourceCode(Heap* heap, SharedFunctionInfo* info) { | 853 inline static bool HasSourceCode(Heap* heap, SharedFunctionInfo* info) { |
| 774 Object* undefined = heap->raw_unchecked_undefined_value(); | 854 Object* undefined = heap->undefined_value(); |
| 775 return (info->script() != undefined) && | 855 return (info->script() != undefined) && |
| 776 (reinterpret_cast<Script*>(info->script())->source() != undefined); | 856 (reinterpret_cast<Script*>(info->script())->source() != undefined); |
| 777 } | 857 } |
| 778 | 858 |
| 779 | 859 |
| 780 inline static bool IsCompiled(JSFunction* function) { | 860 inline static bool IsCompiled(JSFunction* function) { |
| 781 return function->unchecked_code() != | 861 return function->unchecked_code() != |
| 782 function->GetIsolate()->builtins()->builtin(Builtins::kLazyCompile); | 862 function->GetIsolate()->builtins()->builtin(Builtins::kLazyCompile); |
| 783 } | 863 } |
| 784 | 864 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 818 } | 898 } |
| 819 | 899 |
| 820 // The function must be compiled and have the source code available, | 900 // The function must be compiled and have the source code available, |
| 821 // to be able to recompile it in case we need the function again. | 901 // to be able to recompile it in case we need the function again. |
| 822 if (!(shared_info->is_compiled() && HasSourceCode(heap, shared_info))) { | 902 if (!(shared_info->is_compiled() && HasSourceCode(heap, shared_info))) { |
| 823 return false; | 903 return false; |
| 824 } | 904 } |
| 825 | 905 |
| 826 // We never flush code for Api functions. | 906 // We never flush code for Api functions. |
| 827 Object* function_data = shared_info->function_data(); | 907 Object* function_data = shared_info->function_data(); |
| 828 if (function_data->IsHeapObject() && | 908 if (function_data->IsFunctionTemplateInfo()) return false; |
| 829 (SafeMap(function_data)->instance_type() == | |
| 830 FUNCTION_TEMPLATE_INFO_TYPE)) { | |
| 831 return false; | |
| 832 } | |
| 833 | 909 |
| 834 // Only flush code for functions. | 910 // Only flush code for functions. |
| 835 if (shared_info->code()->kind() != Code::FUNCTION) return false; | 911 if (shared_info->code()->kind() != Code::FUNCTION) return false; |
| 836 | 912 |
| 837 // Function must be lazy compilable. | 913 // Function must be lazy compilable. |
| 838 if (!shared_info->allows_lazy_compilation()) return false; | 914 if (!shared_info->allows_lazy_compilation()) return false; |
| 839 | 915 |
| 840 // If this is a full script wrapped in a function we do no flush the code. | 916 // If this is a full script wrapped in a function we do no flush the code. |
| 841 if (shared_info->is_toplevel()) return false; | 917 if (shared_info->is_toplevel()) return false; |
| 842 | 918 |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 855 | 931 |
| 856 // This function's code looks flushable. But we have to postpone the | 932 // This function's code looks flushable. But we have to postpone the |
| 857 // decision until we see all functions that point to the same | 933 // decision until we see all functions that point to the same |
| 858 // SharedFunctionInfo because some of them might be optimized. | 934 // SharedFunctionInfo because some of them might be optimized. |
| 859 // That would make the nonoptimized version of the code nonflushable, | 935 // That would make the nonoptimized version of the code nonflushable, |
| 860 // because it is required for bailing out from optimized code. | 936 // because it is required for bailing out from optimized code. |
| 861 heap->mark_compact_collector()->code_flusher()->AddCandidate(function); | 937 heap->mark_compact_collector()->code_flusher()->AddCandidate(function); |
| 862 return true; | 938 return true; |
| 863 } | 939 } |
| 864 | 940 |
| 865 | 941 static inline bool IsValidNotBuiltinContext(Object* ctx) { |
| 866 static inline Map* SafeMap(Object* obj) { | 942 return ctx->IsContext() && |
| 867 return HeapObject::cast(obj)->map(); | 943 !Context::cast(ctx)->global()->IsJSBuiltinsObject(); |
| 868 } | 944 } |
| 869 | 945 |
| 870 | 946 |
| 871 static inline bool IsJSBuiltinsObject(Object* obj) { | |
| 872 return obj->IsHeapObject() && | |
| 873 (SafeMap(obj)->instance_type() == JS_BUILTINS_OBJECT_TYPE); | |
| 874 } | |
| 875 | |
| 876 | |
| 877 static inline bool IsValidNotBuiltinContext(Object* ctx) { | |
| 878 if (!ctx->IsHeapObject()) return false; | |
| 879 | |
| 880 Map* map = SafeMap(ctx); | |
| 881 Heap* heap = HeapObject::cast(ctx)->GetHeap(); | |
| 882 if (!(map == heap->raw_unchecked_context_map() || | |
| 883 map == heap->raw_unchecked_catch_context_map() || | |
| 884 map == heap->raw_unchecked_global_context_map())) { | |
| 885 return false; | |
| 886 } | |
| 887 | |
| 888 Context* context = reinterpret_cast<Context*>(ctx); | |
| 889 | |
| 890 if (IsJSBuiltinsObject(context->global())) { | |
| 891 return false; | |
| 892 } | |
| 893 | |
| 894 return true; | |
| 895 } | |
| 896 | |
| 897 | |
| 898 static void VisitSharedFunctionInfoGeneric(Map* map, HeapObject* object) { | 947 static void VisitSharedFunctionInfoGeneric(Map* map, HeapObject* object) { |
| 899 SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(object); | 948 SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(object); |
| 900 | 949 |
| 901 if (shared->IsInobjectSlackTrackingInProgress()) shared->DetachInitialMap(); | 950 if (shared->IsInobjectSlackTrackingInProgress()) shared->DetachInitialMap(); |
| 902 | 951 |
| 903 FixedBodyVisitor<StaticMarkingVisitor, | 952 FixedBodyVisitor<StaticMarkingVisitor, |
| 904 SharedFunctionInfo::BodyDescriptor, | 953 SharedFunctionInfo::BodyDescriptor, |
| 905 void>::Visit(map, object); | 954 void>::Visit(map, object); |
| 906 } | 955 } |
| 907 | 956 |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 938 static void VisitCodeEntry(Heap* heap, Address entry_address) { | 987 static void VisitCodeEntry(Heap* heap, Address entry_address) { |
| 939 Object* code = Code::GetObjectFromEntryAddress(entry_address); | 988 Object* code = Code::GetObjectFromEntryAddress(entry_address); |
| 940 Object* old_code = code; | 989 Object* old_code = code; |
| 941 VisitPointer(heap, &code); | 990 VisitPointer(heap, &code); |
| 942 if (code != old_code) { | 991 if (code != old_code) { |
| 943 Memory::Address_at(entry_address) = | 992 Memory::Address_at(entry_address) = |
| 944 reinterpret_cast<Code*>(code)->entry(); | 993 reinterpret_cast<Code*>(code)->entry(); |
| 945 } | 994 } |
| 946 } | 995 } |
| 947 | 996 |
| 997 static void VisitGlobalContext(Map* map, HeapObject* object) { | |
| 998 FixedBodyVisitor<StaticMarkingVisitor, | |
| 999 Context::MarkCompactBodyDescriptor, | |
| 1000 void>::Visit(map, object); | |
| 1001 | |
| 1002 for (int idx = Context::FIRST_WEAK_SLOT; | |
| 1003 idx < Context::GLOBAL_CONTEXT_SLOTS; | |
| 1004 ++idx) { | |
| 1005 Object** slot = | |
| 1006 HeapObject::RawField(object, FixedArray::OffsetOfElementAt(idx)); | |
| 1007 map->GetHeap()->mark_compact_collector()->RecordSlot( | |
| 1008 object->address(), slot, *slot); | |
| 1009 } | |
| 1010 } | |
| 948 | 1011 |
| 949 static void VisitJSFunctionAndFlushCode(Map* map, HeapObject* object) { | 1012 static void VisitJSFunctionAndFlushCode(Map* map, HeapObject* object) { |
| 950 Heap* heap = map->GetHeap(); | 1013 Heap* heap = map->GetHeap(); |
| 951 MarkCompactCollector* collector = heap->mark_compact_collector(); | 1014 MarkCompactCollector* collector = heap->mark_compact_collector(); |
| 952 if (!collector->is_code_flushing_enabled()) { | 1015 if (!collector->is_code_flushing_enabled()) { |
| 953 VisitJSFunction(map, object); | 1016 VisitJSFunction(map, object); |
| 954 return; | 1017 return; |
| 955 } | 1018 } |
| 956 | 1019 |
| 957 JSFunction* jsfunction = reinterpret_cast<JSFunction*>(object); | 1020 JSFunction* jsfunction = reinterpret_cast<JSFunction*>(object); |
| 958 // The function must have a valid context and not be a builtin. | 1021 // The function must have a valid context and not be a builtin. |
| 959 bool flush_code_candidate = false; | 1022 bool flush_code_candidate = false; |
| 960 if (IsValidNotBuiltinContext(jsfunction->unchecked_context())) { | 1023 if (IsValidNotBuiltinContext(jsfunction->unchecked_context())) { |
| 961 flush_code_candidate = FlushCodeForFunction(heap, jsfunction); | 1024 flush_code_candidate = FlushCodeForFunction(heap, jsfunction); |
| 962 } | 1025 } |
| 963 | 1026 |
| 964 if (!flush_code_candidate) { | 1027 if (!flush_code_candidate) { |
| 965 Code* code = jsfunction->unchecked_shared()->unchecked_code(); | 1028 Code* code = jsfunction->unchecked_shared()->unchecked_code(); |
| 966 MarkBit code_mark = Marking::MarkBitFrom(code); | 1029 MarkBit code_mark = Marking::MarkBitFrom(code); |
| 967 HEAP->mark_compact_collector()->MarkObject(code, code_mark); | 1030 heap->mark_compact_collector()->MarkObject(code, code_mark); |
| 968 | 1031 |
| 969 if (jsfunction->unchecked_code()->kind() == Code::OPTIMIZED_FUNCTION) { | 1032 if (jsfunction->unchecked_code()->kind() == Code::OPTIMIZED_FUNCTION) { |
| 970 // For optimized functions we should retain both non-optimized version | 1033 // For optimized functions we should retain both non-optimized version |
| 971 // of it's code and non-optimized version of all inlined functions. | 1034 // of it's code and non-optimized version of all inlined functions. |
| 972 // This is required to support bailing out from inlined code. | 1035 // This is required to support bailing out from inlined code. |
| 973 DeoptimizationInputData* data = | 1036 DeoptimizationInputData* data = |
| 974 reinterpret_cast<DeoptimizationInputData*>( | 1037 reinterpret_cast<DeoptimizationInputData*>( |
| 975 jsfunction->unchecked_code()->unchecked_deoptimization_data()); | 1038 jsfunction->unchecked_code()->unchecked_deoptimization_data()); |
| 976 | 1039 |
| 977 FixedArray* literals = data->UncheckedLiteralArray(); | 1040 FixedArray* literals = data->UncheckedLiteralArray(); |
| 978 | 1041 |
| 979 for (int i = 0, count = data->InlinedFunctionCount()->value(); | 1042 for (int i = 0, count = data->InlinedFunctionCount()->value(); |
| 980 i < count; | 1043 i < count; |
| 981 i++) { | 1044 i++) { |
| 982 JSFunction* inlined = reinterpret_cast<JSFunction*>(literals->get(i)); | 1045 JSFunction* inlined = reinterpret_cast<JSFunction*>(literals->get(i)); |
| 983 Code* inlined_code = inlined->unchecked_shared()->unchecked_code(); | 1046 Code* inlined_code = inlined->unchecked_shared()->unchecked_code(); |
| 984 MarkBit inlined_code_mark = | 1047 MarkBit inlined_code_mark = |
| 985 Marking::MarkBitFrom(inlined_code); | 1048 Marking::MarkBitFrom(inlined_code); |
| 986 HEAP->mark_compact_collector()->MarkObject( | 1049 heap->mark_compact_collector()->MarkObject( |
| 987 inlined_code, inlined_code_mark); | 1050 inlined_code, inlined_code_mark); |
| 988 } | 1051 } |
| 989 } | 1052 } |
| 990 } | 1053 } |
| 991 | 1054 |
| 992 VisitJSFunctionFields(map, | 1055 VisitJSFunctionFields(map, |
| 993 reinterpret_cast<JSFunction*>(object), | 1056 reinterpret_cast<JSFunction*>(object), |
| 994 flush_code_candidate); | 1057 flush_code_candidate); |
| 995 } | 1058 } |
| 996 | 1059 |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 1021 // Don't visit code object. | 1084 // Don't visit code object. |
| 1022 | 1085 |
| 1023 // Visit shared function info to avoid double checking of it's | 1086 // Visit shared function info to avoid double checking of it's |
| 1024 // flushability. | 1087 // flushability. |
| 1025 SharedFunctionInfo* shared_info = object->unchecked_shared(); | 1088 SharedFunctionInfo* shared_info = object->unchecked_shared(); |
| 1026 MarkBit shared_info_mark = Marking::MarkBitFrom(shared_info); | 1089 MarkBit shared_info_mark = Marking::MarkBitFrom(shared_info); |
| 1027 if (!shared_info_mark.Get()) { | 1090 if (!shared_info_mark.Get()) { |
| 1028 Map* shared_info_map = shared_info->map(); | 1091 Map* shared_info_map = shared_info->map(); |
| 1029 MarkBit shared_info_map_mark = | 1092 MarkBit shared_info_map_mark = |
| 1030 Marking::MarkBitFrom(shared_info_map); | 1093 Marking::MarkBitFrom(shared_info_map); |
| 1031 HEAP->mark_compact_collector()->SetMark(shared_info, shared_info_mark); | 1094 heap->mark_compact_collector()->SetMark(shared_info, shared_info_mark); |
| 1032 HEAP->mark_compact_collector()->MarkObject(shared_info_map, | 1095 heap->mark_compact_collector()->MarkObject(shared_info_map, |
| 1033 shared_info_map_mark); | 1096 shared_info_map_mark); |
| 1034 VisitSharedFunctionInfoAndFlushCodeGeneric(shared_info_map, | 1097 VisitSharedFunctionInfoAndFlushCodeGeneric(shared_info_map, |
| 1035 shared_info, | 1098 shared_info, |
| 1036 true); | 1099 true); |
| 1037 } | 1100 } |
| 1038 } | 1101 } |
| 1039 | 1102 |
| 1040 VisitPointers(heap, | 1103 VisitPointers(heap, |
| 1041 SLOT_ADDR(object, | 1104 SLOT_ADDR(object, |
| 1042 JSFunction::kCodeEntryOffset + kPointerSize), | 1105 JSFunction::kCodeEntryOffset + kPointerSize), |
| 1043 SLOT_ADDR(object, JSFunction::kNonWeakFieldsEndOffset)); | 1106 SLOT_ADDR(object, JSFunction::kNonWeakFieldsEndOffset)); |
| 1044 | 1107 |
| 1045 // Don't visit the next function list field as it is a weak reference. | 1108 // Don't visit the next function list field as it is a weak reference. |
| 1109 Object** next_function = SLOT_ADDR(object, | |
| 1110 JSFunction::kNextFunctionLinkOffset); | |
| 1111 heap->mark_compact_collector()->RecordSlot( | |
| 1112 reinterpret_cast<Address>(object), next_function, *next_function); | |
| 1046 } | 1113 } |
| 1047 | 1114 |
| 1048 | 1115 |
| 1049 static void VisitSharedFunctionInfoFields(Heap* heap, | 1116 static void VisitSharedFunctionInfoFields(Heap* heap, |
| 1050 HeapObject* object, | 1117 HeapObject* object, |
| 1051 bool flush_code_candidate) { | 1118 bool flush_code_candidate) { |
| 1052 VisitPointer(heap, SLOT_ADDR(object, SharedFunctionInfo::kNameOffset)); | 1119 VisitPointer(heap, SLOT_ADDR(object, SharedFunctionInfo::kNameOffset)); |
| 1053 | 1120 |
| 1054 if (!flush_code_candidate) { | 1121 if (!flush_code_candidate) { |
| 1055 VisitPointer(heap, SLOT_ADDR(object, SharedFunctionInfo::kCodeOffset)); | 1122 VisitPointer(heap, SLOT_ADDR(object, SharedFunctionInfo::kCodeOffset)); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1103 | 1170 |
| 1104 class CodeMarkingVisitor : public ThreadVisitor { | 1171 class CodeMarkingVisitor : public ThreadVisitor { |
| 1105 public: | 1172 public: |
| 1106 explicit CodeMarkingVisitor(MarkCompactCollector* collector) | 1173 explicit CodeMarkingVisitor(MarkCompactCollector* collector) |
| 1107 : collector_(collector) {} | 1174 : collector_(collector) {} |
| 1108 | 1175 |
| 1109 void VisitThread(Isolate* isolate, ThreadLocalTop* top) { | 1176 void VisitThread(Isolate* isolate, ThreadLocalTop* top) { |
| 1110 for (StackFrameIterator it(isolate, top); !it.done(); it.Advance()) { | 1177 for (StackFrameIterator it(isolate, top); !it.done(); it.Advance()) { |
| 1111 Code* code = it.frame()->unchecked_code(); | 1178 Code* code = it.frame()->unchecked_code(); |
| 1112 MarkBit code_bit = Marking::MarkBitFrom(code); | 1179 MarkBit code_bit = Marking::MarkBitFrom(code); |
| 1113 HEAP->mark_compact_collector()->MarkObject( | 1180 collector_->MarkObject(it.frame()->unchecked_code(), code_bit); |
| 1114 it.frame()->unchecked_code(), code_bit); | |
| 1115 } | 1181 } |
| 1116 } | 1182 } |
| 1117 | 1183 |
| 1118 private: | 1184 private: |
| 1119 MarkCompactCollector* collector_; | 1185 MarkCompactCollector* collector_; |
| 1120 }; | 1186 }; |
| 1121 | 1187 |
| 1122 | 1188 |
| 1123 class SharedFunctionInfoMarkingVisitor : public ObjectVisitor { | 1189 class SharedFunctionInfoMarkingVisitor : public ObjectVisitor { |
| 1124 public: | 1190 public: |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1157 if (heap()->isolate()->debug()->IsLoaded() || | 1223 if (heap()->isolate()->debug()->IsLoaded() || |
| 1158 heap()->isolate()->debug()->has_break_points()) { | 1224 heap()->isolate()->debug()->has_break_points()) { |
| 1159 EnableCodeFlushing(false); | 1225 EnableCodeFlushing(false); |
| 1160 return; | 1226 return; |
| 1161 } | 1227 } |
| 1162 #endif | 1228 #endif |
| 1163 EnableCodeFlushing(true); | 1229 EnableCodeFlushing(true); |
| 1164 | 1230 |
| 1165 // Ensure that empty descriptor array is marked. Method MarkDescriptorArray | 1231 // Ensure that empty descriptor array is marked. Method MarkDescriptorArray |
| 1166 // relies on it being marked before any other descriptor array. | 1232 // relies on it being marked before any other descriptor array. |
| 1167 HeapObject* descriptor_array = heap()->raw_unchecked_empty_descriptor_array(); | 1233 HeapObject* descriptor_array = heap()->empty_descriptor_array(); |
| 1168 MarkBit descriptor_array_mark = Marking::MarkBitFrom(descriptor_array); | 1234 MarkBit descriptor_array_mark = Marking::MarkBitFrom(descriptor_array); |
| 1169 MarkObject(descriptor_array, descriptor_array_mark); | 1235 MarkObject(descriptor_array, descriptor_array_mark); |
| 1170 | 1236 |
| 1171 // Make sure we are not referencing the code from the stack. | 1237 // Make sure we are not referencing the code from the stack. |
| 1172 ASSERT(this == heap()->mark_compact_collector()); | 1238 ASSERT(this == heap()->mark_compact_collector()); |
| 1173 for (StackFrameIterator it; !it.done(); it.Advance()) { | 1239 for (StackFrameIterator it; !it.done(); it.Advance()) { |
| 1174 Code* code = it.frame()->unchecked_code(); | 1240 Code* code = it.frame()->unchecked_code(); |
| 1175 MarkBit code_mark = Marking::MarkBitFrom(code); | 1241 MarkBit code_mark = Marking::MarkBitFrom(code); |
| 1176 MarkObject(code, code_mark); | 1242 MarkObject(code, code_mark); |
| 1177 } | 1243 } |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1245 !Marking::MarkBitFrom(HeapObject::cast(o)).Get()) { | 1311 !Marking::MarkBitFrom(HeapObject::cast(o)).Get()) { |
| 1246 // Check if the symbol being pruned is an external symbol. We need to | 1312 // Check if the symbol being pruned is an external symbol. We need to |
| 1247 // delete the associated external data as this symbol is going away. | 1313 // delete the associated external data as this symbol is going away. |
| 1248 | 1314 |
| 1249 // Since no objects have yet been moved we can safely access the map of | 1315 // Since no objects have yet been moved we can safely access the map of |
| 1250 // the object. | 1316 // the object. |
| 1251 if (o->IsExternalString()) { | 1317 if (o->IsExternalString()) { |
| 1252 heap_->FinalizeExternalString(String::cast(*p)); | 1318 heap_->FinalizeExternalString(String::cast(*p)); |
| 1253 } | 1319 } |
| 1254 // Set the entry to null_value (as deleted). | 1320 // Set the entry to null_value (as deleted). |
| 1255 *p = heap_->raw_unchecked_null_value(); | 1321 *p = heap_->null_value(); |
| 1256 pointers_removed_++; | 1322 pointers_removed_++; |
| 1257 } | 1323 } |
| 1258 } | 1324 } |
| 1259 } | 1325 } |
| 1260 | 1326 |
| 1261 int PointersRemoved() { | 1327 int PointersRemoved() { |
| 1262 return pointers_removed_; | 1328 return pointers_removed_; |
| 1263 } | 1329 } |
| 1264 private: | 1330 private: |
| 1265 Heap* heap_; | 1331 Heap* heap_; |
| 1266 int pointers_removed_; | 1332 int pointers_removed_; |
| 1267 }; | 1333 }; |
| 1268 | 1334 |
| 1269 | 1335 |
| 1270 // Implementation of WeakObjectRetainer for mark compact GCs. All marked objects | 1336 // Implementation of WeakObjectRetainer for mark compact GCs. All marked objects |
| 1271 // are retained. | 1337 // are retained. |
| 1272 class MarkCompactWeakObjectRetainer : public WeakObjectRetainer { | 1338 class MarkCompactWeakObjectRetainer : public WeakObjectRetainer { |
| 1273 public: | 1339 public: |
| 1274 virtual Object* RetainAs(Object* object) { | 1340 virtual Object* RetainAs(Object* object) { |
| 1275 if (Marking::MarkBitFrom(HeapObject::cast(object)).Get()) { | 1341 if (Marking::MarkBitFrom(HeapObject::cast(object)).Get()) { |
| 1276 return object; | 1342 return object; |
| 1277 } else { | 1343 } else { |
| 1278 return NULL; | 1344 return NULL; |
| 1279 } | 1345 } |
| 1280 } | 1346 } |
| 1281 }; | 1347 }; |
| 1282 | 1348 |
| 1283 | 1349 |
| 1350 /* | |
|
Erik Corry
2011/06/20 20:41:26
commented code
Vyacheslav Egorov (Chromium)
2011/06/21 11:44:48
Done.
| |
| 1351 class EvacuationWeakObjectRetainer : public WeakObjectRetainer { | |
| 1352 public: | |
| 1353 virtual Object* RetainAs(Object* object) { | |
| 1354 const Object* old_object = object; | |
| 1355 MapWord map_word = HeapObject::cast(object)->map_word(); | |
| 1356 if (map_word.IsForwardingAddress()) { | |
| 1357 object = map_word.ToForwardingAddress(); | |
| 1358 } | |
| 1359 PrintF("%p -> %p\n", (void*) old_object, (void*) object); | |
| 1360 object->Print(); | |
| 1361 return object; | |
| 1362 } | |
| 1363 }; | |
| 1364 */ | |
| 1365 | |
| 1284 void MarkCompactCollector::ProcessNewlyMarkedObject(HeapObject* object) { | 1366 void MarkCompactCollector::ProcessNewlyMarkedObject(HeapObject* object) { |
| 1285 ASSERT(IsMarked(object)); | 1367 ASSERT(IsMarked(object)); |
| 1286 ASSERT(HEAP->Contains(object)); | 1368 ASSERT(HEAP->Contains(object)); |
| 1287 if (object->IsMap()) { | 1369 if (object->IsMap()) { |
| 1288 Map* map = Map::cast(object); | 1370 Map* map = Map::cast(object); |
| 1289 if (FLAG_cleanup_code_caches_at_gc) { | 1371 if (FLAG_cleanup_code_caches_at_gc) { |
| 1290 map->ClearCodeCache(heap()); | 1372 map->ClearCodeCache(heap()); |
| 1291 } | 1373 } |
| 1292 | 1374 |
| 1293 // When map collection is enabled we have to mark through map's transitions | 1375 // When map collection is enabled we have to mark through map's transitions |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 1304 } else { | 1386 } else { |
| 1305 marking_deque_.PushBlack(object); | 1387 marking_deque_.PushBlack(object); |
| 1306 } | 1388 } |
| 1307 } | 1389 } |
| 1308 | 1390 |
| 1309 | 1391 |
| 1310 void MarkCompactCollector::MarkMapContents(Map* map) { | 1392 void MarkCompactCollector::MarkMapContents(Map* map) { |
| 1311 // Mark prototype transitions array but don't push it into marking stack. | 1393 // Mark prototype transitions array but don't push it into marking stack. |
| 1312 // This will make references from it weak. We will clean dead prototype | 1394 // This will make references from it weak. We will clean dead prototype |
| 1313 // transitions in ClearNonLiveTransitions. | 1395 // transitions in ClearNonLiveTransitions. |
| 1314 FixedArray* prototype_transitions = map->unchecked_prototype_transitions(); | 1396 FixedArray* prototype_transitions = map->prototype_transitions(); |
| 1315 MarkBit mark = Marking::MarkBitFrom(prototype_transitions); | 1397 MarkBit mark = Marking::MarkBitFrom(prototype_transitions); |
| 1316 if (!mark.Get()) mark.Set(); | 1398 if (!mark.Get()) mark.Set(); |
| 1317 | 1399 |
| 1318 Object* raw_descriptor_array = | 1400 Object** raw_descriptor_array_slot = |
| 1319 *HeapObject::RawField(map, | 1401 HeapObject::RawField(map, Map::kInstanceDescriptorsOrBitField3Offset); |
| 1320 Map::kInstanceDescriptorsOrBitField3Offset); | 1402 Object* raw_descriptor_array = *raw_descriptor_array_slot; |
| 1321 if (!raw_descriptor_array->IsSmi()) { | 1403 if (!raw_descriptor_array->IsSmi()) { |
| 1322 MarkDescriptorArray( | 1404 MarkDescriptorArray( |
| 1323 reinterpret_cast<DescriptorArray*>(raw_descriptor_array)); | 1405 reinterpret_cast<DescriptorArray*>(raw_descriptor_array)); |
| 1324 } | 1406 } |
| 1325 | 1407 |
| 1326 // Mark the Object* fields of the Map. | 1408 // Mark the Object* fields of the Map. |
| 1327 // Since the descriptor array has been marked already, it is fine | 1409 // Since the descriptor array has been marked already, it is fine |
| 1328 // that one of these fields contains a pointer to it. | 1410 // that one of these fields contains a pointer to it. |
| 1329 Object** start_slot = HeapObject::RawField(map, | 1411 Object** start_slot = HeapObject::RawField(map, |
| 1330 Map::kPointerFieldsBeginOffset); | 1412 Map::kPointerFieldsBeginOffset); |
| 1331 | 1413 |
| 1332 Object** end_slot = HeapObject::RawField(map, Map::kPointerFieldsEndOffset); | 1414 Object** end_slot = HeapObject::RawField(map, Map::kPointerFieldsEndOffset); |
| 1333 | 1415 |
| 1334 StaticMarkingVisitor::VisitPointers(map->GetHeap(), start_slot, end_slot); | 1416 StaticMarkingVisitor::VisitPointers(map->GetHeap(), start_slot, end_slot); |
| 1335 } | 1417 } |
| 1336 | 1418 |
| 1337 | 1419 |
| 1338 void MarkCompactCollector::MarkDescriptorArray( | 1420 void MarkCompactCollector::MarkDescriptorArray( |
| 1339 DescriptorArray* descriptors) { | 1421 DescriptorArray* descriptors) { |
| 1340 MarkBit descriptors_mark = Marking::MarkBitFrom(descriptors); | 1422 MarkBit descriptors_mark = Marking::MarkBitFrom(descriptors); |
| 1341 if (descriptors_mark.Get()) return; | 1423 if (descriptors_mark.Get()) return; |
| 1342 // Empty descriptor array is marked as a root before any maps are marked. | 1424 // Empty descriptor array is marked as a root before any maps are marked. |
| 1343 ASSERT(descriptors != HEAP->raw_unchecked_empty_descriptor_array()); | 1425 ASSERT(descriptors != heap()->empty_descriptor_array()); |
| 1344 SetMark(descriptors, descriptors_mark); | 1426 SetMark(descriptors, descriptors_mark); |
| 1345 | 1427 |
| 1346 FixedArray* contents = reinterpret_cast<FixedArray*>( | 1428 FixedArray* contents = reinterpret_cast<FixedArray*>( |
| 1347 descriptors->get(DescriptorArray::kContentArrayIndex)); | 1429 descriptors->get(DescriptorArray::kContentArrayIndex)); |
| 1348 ASSERT(contents->IsHeapObject()); | 1430 ASSERT(contents->IsHeapObject()); |
| 1349 ASSERT(!IsMarked(contents)); | 1431 ASSERT(!IsMarked(contents)); |
| 1350 ASSERT(contents->IsFixedArray()); | 1432 ASSERT(contents->IsFixedArray()); |
| 1351 ASSERT(contents->length() >= 2); | 1433 ASSERT(contents->length() >= 2); |
| 1352 MarkBit contents_mark = Marking::MarkBitFrom(contents); | 1434 MarkBit contents_mark = Marking::MarkBitFrom(contents); |
| 1353 SetMark(contents, contents_mark); | 1435 SetMark(contents, contents_mark); |
| 1354 // Contents contains (value, details) pairs. If the details say that the type | 1436 // Contents contains (value, details) pairs. If the details say that the type |
| 1355 // of descriptor is MAP_TRANSITION, CONSTANT_TRANSITION, | 1437 // of descriptor is MAP_TRANSITION, CONSTANT_TRANSITION, |
| 1356 // EXTERNAL_ARRAY_TRANSITION or NULL_DESCRIPTOR, we don't mark the value as | 1438 // EXTERNAL_ARRAY_TRANSITION or NULL_DESCRIPTOR, we don't mark the value as |
| 1357 // live. Only for MAP_TRANSITION, EXTERNAL_ARRAY_TRANSITION and | 1439 // live. Only for MAP_TRANSITION, EXTERNAL_ARRAY_TRANSITION and |
| 1358 // CONSTANT_TRANSITION is the value an Object* (a Map*). | 1440 // CONSTANT_TRANSITION is the value an Object* (a Map*). |
| 1359 for (int i = 0; i < contents->length(); i += 2) { | 1441 for (int i = 0; i < contents->length(); i += 2) { |
| 1360 // If the pair (value, details) at index i, i+1 is not | 1442 // If the pair (value, details) at index i, i+1 is not |
| 1361 // a transition or null descriptor, mark the value. | 1443 // a transition or null descriptor, mark the value. |
| 1362 PropertyDetails details(Smi::cast(contents->get(i + 1))); | 1444 PropertyDetails details(Smi::cast(contents->get(i + 1))); |
| 1445 | |
| 1446 Object** slot = contents->data_start() + i; | |
| 1447 Object* value = *slot; | |
| 1448 if (!value->IsHeapObject()) continue; | |
| 1449 | |
| 1450 RecordSlot(reinterpret_cast<Address>(contents), slot, *slot); | |
| 1451 | |
| 1363 if (details.type() < FIRST_PHANTOM_PROPERTY_TYPE) { | 1452 if (details.type() < FIRST_PHANTOM_PROPERTY_TYPE) { |
| 1364 HeapObject* object = reinterpret_cast<HeapObject*>(contents->get(i)); | 1453 HeapObject* object = HeapObject::cast(value); |
| 1365 if (object->IsHeapObject()) { | 1454 MarkBit mark = Marking::MarkBitFrom(HeapObject::cast(object)); |
| 1366 MarkBit mark = Marking::MarkBitFrom(HeapObject::cast(object)); | 1455 if (!mark.Get()) { |
| 1367 if (!mark.Get()) { | 1456 SetMark(HeapObject::cast(object), mark); |
| 1368 SetMark(HeapObject::cast(object), mark); | 1457 marking_deque_.PushBlack(object); |
| 1369 marking_deque_.PushBlack(object); | |
| 1370 } | |
| 1371 } | 1458 } |
| 1372 } | 1459 } |
| 1373 } | 1460 } |
| 1374 // The DescriptorArray descriptors contains a pointer to its contents array, | 1461 // The DescriptorArray descriptors contains a pointer to its contents array, |
| 1375 // but the contents array is already marked. | 1462 // but the contents array is already marked. |
| 1376 marking_deque_.PushBlack(descriptors); | 1463 marking_deque_.PushBlack(descriptors); |
| 1377 } | 1464 } |
| 1378 | 1465 |
| 1379 | 1466 |
| 1380 void MarkCompactCollector::CreateBackPointers() { | 1467 void MarkCompactCollector::CreateBackPointers() { |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1493 bool MarkCompactCollector::IsUnmarkedHeapObject(Object** p) { | 1580 bool MarkCompactCollector::IsUnmarkedHeapObject(Object** p) { |
| 1494 Object* o = *p; | 1581 Object* o = *p; |
| 1495 if (!o->IsHeapObject()) return false; | 1582 if (!o->IsHeapObject()) return false; |
| 1496 HeapObject* heap_object = HeapObject::cast(o); | 1583 HeapObject* heap_object = HeapObject::cast(o); |
| 1497 MarkBit mark = Marking::MarkBitFrom(heap_object); | 1584 MarkBit mark = Marking::MarkBitFrom(heap_object); |
| 1498 return !mark.Get(); | 1585 return !mark.Get(); |
| 1499 } | 1586 } |
| 1500 | 1587 |
| 1501 | 1588 |
| 1502 void MarkCompactCollector::MarkSymbolTable() { | 1589 void MarkCompactCollector::MarkSymbolTable() { |
| 1503 SymbolTable* symbol_table = heap()->raw_unchecked_symbol_table(); | 1590 SymbolTable* symbol_table = heap()->symbol_table(); |
| 1504 // Mark the symbol table itself. | 1591 // Mark the symbol table itself. |
| 1505 MarkBit symbol_table_mark = Marking::MarkBitFrom(symbol_table); | 1592 MarkBit symbol_table_mark = Marking::MarkBitFrom(symbol_table); |
| 1506 SetMark(symbol_table, symbol_table_mark); | 1593 SetMark(symbol_table, symbol_table_mark); |
| 1507 // Explicitly mark the prefix. | 1594 // Explicitly mark the prefix. |
| 1508 MarkingVisitor marker(heap()); | 1595 MarkingVisitor marker(heap()); |
| 1509 symbol_table->IteratePrefix(&marker); | 1596 symbol_table->IteratePrefix(&marker); |
| 1510 ProcessMarkingDeque(); | 1597 ProcessMarkingDeque(); |
| 1511 } | 1598 } |
| 1512 | 1599 |
| 1513 | 1600 |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1774 ProcessExternalMarking(); | 1861 ProcessExternalMarking(); |
| 1775 | 1862 |
| 1776 AfterMarking(); | 1863 AfterMarking(); |
| 1777 } | 1864 } |
| 1778 | 1865 |
| 1779 | 1866 |
| 1780 void MarkCompactCollector::AfterMarking() { | 1867 void MarkCompactCollector::AfterMarking() { |
| 1781 // Prune the symbol table removing all symbols only pointed to by the | 1868 // Prune the symbol table removing all symbols only pointed to by the |
| 1782 // symbol table. Cannot use symbol_table() here because the symbol | 1869 // symbol table. Cannot use symbol_table() here because the symbol |
| 1783 // table is marked. | 1870 // table is marked. |
| 1784 SymbolTable* symbol_table = heap()->raw_unchecked_symbol_table(); | 1871 SymbolTable* symbol_table = heap()->symbol_table(); |
| 1785 SymbolTableCleaner v(heap()); | 1872 SymbolTableCleaner v(heap()); |
| 1786 symbol_table->IterateElements(&v); | 1873 symbol_table->IterateElements(&v); |
| 1787 symbol_table->ElementsRemoved(v.PointersRemoved()); | 1874 symbol_table->ElementsRemoved(v.PointersRemoved()); |
| 1788 heap()->external_string_table_.Iterate(&v); | 1875 heap()->external_string_table_.Iterate(&v); |
| 1789 heap()->external_string_table_.CleanUp(); | 1876 heap()->external_string_table_.CleanUp(); |
| 1790 | 1877 |
| 1791 // Process the weak references. | 1878 // Process the weak references. |
| 1792 MarkCompactWeakObjectRetainer mark_compact_object_retainer; | 1879 MarkCompactWeakObjectRetainer mark_compact_object_retainer; |
| 1793 heap()->ProcessWeakReferences(&mark_compact_object_retainer); | 1880 heap()->ProcessWeakReferences(&mark_compact_object_retainer); |
| 1794 | 1881 |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 1825 live_code_objects_size_ += obj->Size(); | 1912 live_code_objects_size_ += obj->Size(); |
| 1826 } else if (heap()->lo_space()->Contains(obj)) { | 1913 } else if (heap()->lo_space()->Contains(obj)) { |
| 1827 live_lo_objects_size_ += obj->Size(); | 1914 live_lo_objects_size_ += obj->Size(); |
| 1828 } else { | 1915 } else { |
| 1829 UNREACHABLE(); | 1916 UNREACHABLE(); |
| 1830 } | 1917 } |
| 1831 } | 1918 } |
| 1832 #endif // DEBUG | 1919 #endif // DEBUG |
| 1833 | 1920 |
| 1834 | 1921 |
| 1835 // Safe to use during marking phase only. | |
| 1836 bool MarkCompactCollector::SafeIsMap(HeapObject* object) { | |
| 1837 return object->map()->instance_type() == MAP_TYPE; | |
| 1838 } | |
| 1839 | |
| 1840 | |
| 1841 void MarkCompactCollector::ClearNonLiveTransitions() { | 1922 void MarkCompactCollector::ClearNonLiveTransitions() { |
| 1842 HeapObjectIterator map_iterator(heap()->map_space()); | 1923 HeapObjectIterator map_iterator(heap()->map_space()); |
| 1843 // Iterate over the map space, setting map transitions that go from | 1924 // Iterate over the map space, setting map transitions that go from |
| 1844 // a marked map to an unmarked map to null transitions. At the same time, | 1925 // a marked map to an unmarked map to null transitions. At the same time, |
| 1845 // set all the prototype fields of maps back to their original value, | 1926 // set all the prototype fields of maps back to their original value, |
| 1846 // dropping the back pointers temporarily stored in the prototype field. | 1927 // dropping the back pointers temporarily stored in the prototype field. |
| 1847 // Setting the prototype field requires following the linked list of | 1928 // Setting the prototype field requires following the linked list of |
| 1848 // back pointers, reversing them all at once. This allows us to find | 1929 // back pointers, reversing them all at once. This allows us to find |
| 1849 // those maps with map transitions that need to be nulled, and only | 1930 // those maps with map transitions that need to be nulled, and only |
| 1850 // scan the descriptor arrays of those maps, not all maps. | 1931 // scan the descriptor arrays of those maps, not all maps. |
| 1851 // All of these actions are carried out only on maps of JSObjects | 1932 // All of these actions are carried out only on maps of JSObjects |
| 1852 // and related subtypes. | 1933 // and related subtypes. |
| 1853 for (HeapObject* obj = map_iterator.Next(); | 1934 for (HeapObject* obj = map_iterator.Next(); |
| 1854 obj != NULL; obj = map_iterator.Next()) { | 1935 obj != NULL; obj = map_iterator.Next()) { |
| 1855 Map* map = reinterpret_cast<Map*>(obj); | 1936 Map* map = reinterpret_cast<Map*>(obj); |
| 1856 MarkBit map_mark = Marking::MarkBitFrom(map); | 1937 MarkBit map_mark = Marking::MarkBitFrom(map); |
| 1857 if (map->IsFreeSpace()) continue; | 1938 if (map->IsFreeSpace()) continue; |
| 1858 | 1939 |
| 1859 ASSERT(SafeIsMap(map)); | 1940 ASSERT(map->IsMap()); |
| 1860 // Only JSObject and subtypes have map transitions and back pointers. | 1941 // Only JSObject and subtypes have map transitions and back pointers. |
| 1861 if (map->instance_type() < FIRST_JS_OBJECT_TYPE) continue; | 1942 if (map->instance_type() < FIRST_JS_OBJECT_TYPE) continue; |
| 1862 if (map->instance_type() > JS_FUNCTION_TYPE) continue; | 1943 if (map->instance_type() > JS_FUNCTION_TYPE) continue; |
| 1863 | 1944 |
| 1864 if (map_mark.Get() && | 1945 if (map_mark.Get() && |
| 1865 map->attached_to_shared_function_info()) { | 1946 map->attached_to_shared_function_info()) { |
| 1866 // This map is used for inobject slack tracking and has been detached | 1947 // This map is used for inobject slack tracking and has been detached |
| 1867 // from SharedFunctionInfo during the mark phase. | 1948 // from SharedFunctionInfo during the mark phase. |
| 1868 // Since it survived the GC, reattach it now. | 1949 // Since it survived the GC, reattach it now. |
| 1869 map->unchecked_constructor()->unchecked_shared()->AttachInitialMap(map); | 1950 map->unchecked_constructor()->unchecked_shared()->AttachInitialMap(map); |
| 1870 } | 1951 } |
| 1871 | 1952 |
| 1872 // Clear dead prototype transitions. | 1953 // Clear dead prototype transitions. |
| 1873 FixedArray* prototype_transitions = map->unchecked_prototype_transitions(); | 1954 FixedArray* prototype_transitions = map->prototype_transitions(); |
| 1874 if (prototype_transitions->length() > 0) { | 1955 if (prototype_transitions->length() > 0) { |
| 1875 int finger = Smi::cast(prototype_transitions->get(0))->value(); | 1956 int finger = Smi::cast(prototype_transitions->get(0))->value(); |
| 1876 int new_finger = 1; | 1957 int new_finger = 1; |
| 1877 for (int i = 1; i < finger; i += 2) { | 1958 for (int i = 1; i < finger; i += 2) { |
| 1878 HeapObject* prototype = HeapObject::cast(prototype_transitions->get(i)); | 1959 HeapObject* prototype = HeapObject::cast(prototype_transitions->get(i)); |
| 1879 Map* cached_map = Map::cast(prototype_transitions->get(i + 1)); | 1960 Map* cached_map = Map::cast(prototype_transitions->get(i + 1)); |
| 1880 MarkBit prototype_mark = Marking::MarkBitFrom(prototype); | 1961 MarkBit prototype_mark = Marking::MarkBitFrom(prototype); |
| 1881 MarkBit cached_map_mark = Marking::MarkBitFrom(cached_map); | 1962 MarkBit cached_map_mark = Marking::MarkBitFrom(cached_map); |
| 1882 if (prototype_mark.Get() && cached_map_mark.Get()) { | 1963 if (prototype_mark.Get() && cached_map_mark.Get()) { |
| 1883 if (new_finger != i) { | 1964 if (new_finger != i) { |
| 1884 prototype_transitions->set_unchecked(heap_, | 1965 prototype_transitions->set_unchecked(heap_, |
| 1885 new_finger, | 1966 new_finger, |
| 1886 prototype, | 1967 prototype, |
| 1887 UPDATE_WRITE_BARRIER); | 1968 UPDATE_WRITE_BARRIER); |
| 1888 prototype_transitions->set_unchecked(heap_, | 1969 prototype_transitions->set_unchecked(heap_, |
| 1889 new_finger + 1, | 1970 new_finger + 1, |
| 1890 cached_map, | 1971 cached_map, |
| 1891 SKIP_WRITE_BARRIER); | 1972 SKIP_WRITE_BARRIER); |
| 1892 } | 1973 } |
| 1974 | |
| 1975 Object** prototype_slot = | |
| 1976 prototype_transitions->data_start() + new_finger; | |
| 1977 RecordSlot(reinterpret_cast<Address>(prototype_transitions), | |
| 1978 prototype_slot, | |
| 1979 prototype); | |
| 1893 new_finger += 2; | 1980 new_finger += 2; |
| 1894 } | 1981 } |
| 1895 } | 1982 } |
| 1896 | 1983 |
| 1897 // Fill slots that became free with undefined value. | 1984 // Fill slots that became free with undefined value. |
| 1898 Object* undefined = heap()->raw_unchecked_undefined_value(); | 1985 Object* undefined = heap()->undefined_value(); |
| 1899 for (int i = new_finger; i < finger; i++) { | 1986 for (int i = new_finger; i < finger; i++) { |
| 1900 prototype_transitions->set_unchecked(heap_, | 1987 prototype_transitions->set_unchecked(heap_, |
| 1901 i, | 1988 i, |
| 1902 undefined, | 1989 undefined, |
| 1903 SKIP_WRITE_BARRIER); | 1990 SKIP_WRITE_BARRIER); |
| 1991 | |
| 1992 // TODO(gc) we should not evacuate first page of data space. | |
| 1993 // but we are doing it now to increase coverage. | |
| 1994 Object** undefined_slot = | |
| 1995 prototype_transitions->data_start() + i; | |
| 1996 RecordSlot(reinterpret_cast<Address>(prototype_transitions), | |
| 1997 undefined_slot, | |
| 1998 undefined); | |
| 1904 } | 1999 } |
| 1905 prototype_transitions->set_unchecked(0, Smi::FromInt(new_finger)); | 2000 prototype_transitions->set_unchecked(0, Smi::FromInt(new_finger)); |
| 1906 } | 2001 } |
| 1907 | 2002 |
| 1908 // Follow the chain of back pointers to find the prototype. | 2003 // Follow the chain of back pointers to find the prototype. |
| 1909 Map* current = map; | 2004 Map* current = map; |
| 1910 while (SafeIsMap(current)) { | 2005 while (current->IsMap()) { |
| 1911 current = reinterpret_cast<Map*>(current->prototype()); | 2006 current = reinterpret_cast<Map*>(current->prototype()); |
| 1912 ASSERT(current->IsHeapObject()); | 2007 ASSERT(current->IsHeapObject()); |
| 1913 } | 2008 } |
| 1914 Object* real_prototype = current; | 2009 Object* real_prototype = current; |
| 1915 | 2010 |
| 1916 // Follow back pointers, setting them to prototype, | 2011 // Follow back pointers, setting them to prototype, |
| 1917 // clearing map transitions when necessary. | 2012 // clearing map transitions when necessary. |
| 1918 current = map; | 2013 current = map; |
| 1919 bool on_dead_path = !map_mark.Get(); | 2014 bool on_dead_path = !map_mark.Get(); |
| 1920 Object* next; | 2015 Object* next; |
| 1921 while (SafeIsMap(current)) { | 2016 while (current->IsMap()) { |
| 1922 next = current->prototype(); | 2017 next = current->prototype(); |
| 1923 // There should never be a dead map above a live map. | 2018 // There should never be a dead map above a live map. |
| 1924 MarkBit current_mark = Marking::MarkBitFrom(current); | 2019 MarkBit current_mark = Marking::MarkBitFrom(current); |
| 1925 ASSERT(on_dead_path || current_mark.Get()); | 2020 bool is_alive = current_mark.Get(); |
| 2021 ASSERT(on_dead_path || is_alive); | |
| 1926 | 2022 |
| 1927 // A live map above a dead map indicates a dead transition. | 2023 // A live map above a dead map indicates a dead transition. |
| 1928 // This test will always be false on the first iteration. | 2024 // This test will always be false on the first iteration. |
| 1929 if (on_dead_path && current_mark.Get()) { | 2025 if (on_dead_path && is_alive) { |
| 1930 on_dead_path = false; | 2026 on_dead_path = false; |
| 1931 current->ClearNonLiveTransitions(heap(), real_prototype); | 2027 current->ClearNonLiveTransitions(heap(), real_prototype); |
| 1932 } | 2028 } |
| 1933 *HeapObject::RawField(current, Map::kPrototypeOffset) = | 2029 *HeapObject::RawField(current, Map::kPrototypeOffset) = |
| 1934 real_prototype; | 2030 real_prototype; |
| 2031 | |
| 2032 if (is_alive) { | |
| 2033 RecordSlot(current->address(), | |
| 2034 HeapObject::RawField(current, Map::kPrototypeOffset), | |
| 2035 real_prototype); | |
| 2036 } | |
| 1935 current = reinterpret_cast<Map*>(next); | 2037 current = reinterpret_cast<Map*>(next); |
| 1936 } | 2038 } |
| 1937 } | 2039 } |
| 1938 } | 2040 } |
| 1939 | 2041 |
| 1940 | 2042 |
| 1941 // We scavange new space simultaneously with sweeping. This is done in two | 2043 // We scavange new space simultaneously with sweeping. This is done in two |
| 1942 // passes. | 2044 // passes. |
| 1943 // | 2045 // |
| 1944 // The first pass migrates all alive objects from one semispace to another or | 2046 // The first pass migrates all alive objects from one semispace to another or |
| 1945 // promotes them to old space. Forwarding address is written directly into | 2047 // promotes them to old space. Forwarding address is written directly into |
| 1946 // first word of object without any encoding. If object is dead we write | 2048 // first word of object without any encoding. If object is dead we write |
| 1947 // NULL as a forwarding address. | 2049 // NULL as a forwarding address. |
| 1948 // | 2050 // |
| 1949 // The second pass updates pointers to new space in all spaces. It is possible | 2051 // The second pass updates pointers to new space in all spaces. It is possible |
| 1950 // to encounter pointers to dead new space objects during traversal of pointers | 2052 // to encounter pointers to dead new space objects during traversal of pointers |
| 1951 // to new space. We should clear them to avoid encountering them during next | 2053 // to new space. We should clear them to avoid encountering them during next |
| 1952 // pointer iteration. This is an issue if the store buffer overflows and we | 2054 // pointer iteration. This is an issue if the store buffer overflows and we |
| 1953 // have to scan the entire old space, including dead objects, looking for | 2055 // have to scan the entire old space, including dead objects, looking for |
| 1954 // pointers to new space. | 2056 // pointers to new space. |
| 1955 static void MigrateObject(Heap* heap, | 2057 void MarkCompactCollector::MigrateObject(Address dst, |
| 1956 Address dst, | 2058 Address src, |
| 1957 Address src, | 2059 int size, |
| 1958 int size, | 2060 AllocationSpace dest) { |
| 1959 bool to_old_space) { | 2061 ASSERT(dest == OLD_POINTER_SPACE || |
| 1960 if (to_old_space) { | 2062 dest == OLD_DATA_SPACE || |
| 1961 heap->CopyBlockToOldSpaceAndUpdateWriteBarrier(dst, src, size); | 2063 dest == LO_SPACE || |
| 2064 dest == NEW_SPACE); | |
| 2065 | |
| 2066 if (dest == OLD_POINTER_SPACE || dest == LO_SPACE) { | |
| 2067 Address src_slot = src; | |
| 2068 Address dst_slot = dst; | |
| 2069 ASSERT(IsAligned(size, kPointerSize)); | |
| 2070 | |
| 2071 for (int remaining = size / kPointerSize; | |
| 2072 remaining > 0; | |
| 2073 remaining--) { | |
|
Erik Corry
2011/06/20 20:41:26
Fits on one line.
Vyacheslav Egorov (Chromium)
2011/06/21 11:44:48
Done.
| |
| 2074 Object* value = Memory::Object_at(src_slot); | |
| 2075 | |
| 2076 Memory::Object_at(dst_slot) = value; | |
| 2077 | |
| 2078 if (heap_->InNewSpace(value)) { | |
| 2079 heap_->store_buffer()->Mark(dst_slot); | |
| 2080 } else if (value->IsHeapObject() && | |
| 2081 MarkCompactCollector::IsOnEvacuationCandidate(value)) { | |
| 2082 slots_buffer_.Add(reinterpret_cast<Object**>(dst_slot)); | |
| 2083 } | |
| 2084 | |
| 2085 src_slot += kPointerSize; | |
| 2086 dst_slot += kPointerSize; | |
| 2087 } | |
| 1962 } else { | 2088 } else { |
| 1963 heap->CopyBlock(dst, src, size); | 2089 heap_->CopyBlock(dst, src, size); |
| 1964 } | 2090 } |
| 1965 Memory::Address_at(src) = dst; | 2091 Memory::Address_at(src) = dst; |
| 1966 } | 2092 } |
| 1967 | 2093 |
| 1968 | 2094 |
| 1969 class StaticPointersToNewGenUpdatingVisitor : public | |
| 1970 StaticNewSpaceVisitor<StaticPointersToNewGenUpdatingVisitor> { | |
| 1971 public: | |
| 1972 static inline void VisitPointer(Heap* heap, Object** p) { | |
| 1973 if (!(*p)->IsHeapObject()) return; | |
| 1974 | |
| 1975 HeapObject* obj = HeapObject::cast(*p); | |
| 1976 Address old_addr = obj->address(); | |
| 1977 | |
| 1978 if (heap->new_space()->Contains(obj)) { | |
| 1979 ASSERT(heap->InFromSpace(*p)); | |
| 1980 *p = HeapObject::FromAddress(Memory::Address_at(old_addr)); | |
| 1981 ASSERT(!heap->InFromSpace(*p)); | |
| 1982 } | |
| 1983 } | |
| 1984 }; | |
| 1985 | |
| 1986 | |
| 1987 // Visitor for updating pointers from live objects in old spaces to new space. | 2095 // Visitor for updating pointers from live objects in old spaces to new space. |
| 1988 // It does not expect to encounter pointers to dead objects. | 2096 // It does not expect to encounter pointers to dead objects. |
| 1989 class PointersToNewGenUpdatingVisitor: public ObjectVisitor { | 2097 class PointersUpdatingVisitor: public ObjectVisitor { |
| 1990 public: | 2098 public: |
| 1991 explicit PointersToNewGenUpdatingVisitor(Heap* heap) : heap_(heap) { } | 2099 explicit PointersUpdatingVisitor(Heap* heap) : heap_(heap) { } |
| 1992 | 2100 |
| 1993 void VisitPointer(Object** p) { | 2101 void VisitPointer(Object** p) { |
| 1994 StaticPointersToNewGenUpdatingVisitor::VisitPointer(heap_, p); | 2102 UpdatePointer(p); |
| 1995 } | 2103 } |
| 1996 | 2104 |
| 1997 void VisitPointers(Object** start, Object** end) { | 2105 void VisitPointers(Object** start, Object** end) { |
| 1998 for (Object** p = start; p < end; p++) { | 2106 for (Object** p = start; p < end; p++) UpdatePointer(p); |
| 1999 StaticPointersToNewGenUpdatingVisitor::VisitPointer(heap_, p); | |
| 2000 } | |
| 2001 } | 2107 } |
| 2002 | 2108 |
| 2003 void VisitCodeTarget(RelocInfo* rinfo) { | 2109 void VisitCodeTarget(RelocInfo* rinfo) { |
| 2004 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode())); | 2110 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode())); |
| 2005 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address()); | 2111 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address()); |
| 2006 VisitPointer(&target); | 2112 VisitPointer(&target); |
| 2007 rinfo->set_target_address(Code::cast(target)->instruction_start(), NULL); | 2113 rinfo->set_target_address(Code::cast(target)->instruction_start(), NULL); |
| 2008 } | 2114 } |
| 2009 | 2115 |
| 2010 void VisitDebugTarget(RelocInfo* rinfo) { | 2116 void VisitDebugTarget(RelocInfo* rinfo) { |
| 2011 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) && | 2117 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) && |
| 2012 rinfo->IsPatchedReturnSequence()) || | 2118 rinfo->IsPatchedReturnSequence()) || |
| 2013 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) && | 2119 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) && |
| 2014 rinfo->IsPatchedDebugBreakSlotSequence())); | 2120 rinfo->IsPatchedDebugBreakSlotSequence())); |
| 2015 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address()); | 2121 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address()); |
| 2016 VisitPointer(&target); | 2122 VisitPointer(&target); |
| 2017 rinfo->set_call_address(Code::cast(target)->instruction_start()); | 2123 rinfo->set_call_address(Code::cast(target)->instruction_start()); |
| 2018 } | 2124 } |
| 2125 | |
| 2019 private: | 2126 private: |
| 2127 inline void UpdatePointer(Object** p) { | |
| 2128 if (!(*p)->IsHeapObject()) return; | |
| 2129 | |
| 2130 HeapObject* obj = HeapObject::cast(*p); | |
| 2131 | |
| 2132 if (heap_->InNewSpace(obj) || | |
| 2133 MarkCompactCollector::IsOnEvacuationCandidate(obj)) { | |
| 2134 ASSERT(obj->map_word().IsForwardingAddress()); | |
| 2135 *p = obj->map_word().ToForwardingAddress(); | |
| 2136 ASSERT(!MarkCompactCollector::IsOnEvacuationCandidate(*p)); | |
| 2137 } | |
| 2138 } | |
| 2139 | |
| 2020 Heap* heap_; | 2140 Heap* heap_; |
| 2021 }; | 2141 }; |
| 2022 | 2142 |
| 2023 | 2143 |
| 2024 static void UpdatePointerToNewGen(HeapObject** p, HeapObject* object) { | 2144 static void UpdatePointer(HeapObject** p, HeapObject* object) { |
| 2025 ASSERT(HEAP->InFromSpace(object)); | |
| 2026 ASSERT(*p == object); | 2145 ASSERT(*p == object); |
| 2027 | 2146 |
| 2028 Address old_addr = object->address(); | 2147 Address old_addr = object->address(); |
| 2029 | 2148 |
| 2030 Address new_addr = Memory::Address_at(old_addr); | 2149 Address new_addr = Memory::Address_at(old_addr); |
| 2031 | 2150 |
| 2032 // The new space sweep will overwrite the map word of dead objects | 2151 // The new space sweep will overwrite the map word of dead objects |
| 2033 // with NULL. In this case we do not need to transfer this entry to | 2152 // with NULL. In this case we do not need to transfer this entry to |
| 2034 // the store buffer which we are rebuilding. | 2153 // the store buffer which we are rebuilding. |
| 2035 if (new_addr != NULL) { | 2154 if (new_addr != NULL) { |
| 2036 *p = HeapObject::FromAddress(new_addr); | 2155 *p = HeapObject::FromAddress(new_addr); |
| 2037 } else { | 2156 } else { |
| 2038 // We have to zap this pointer, because the store buffer may overflow later, | 2157 // We have to zap this pointer, because the store buffer may overflow later, |
| 2039 // and then we have to scan the entire heap and we don't want to find | 2158 // and then we have to scan the entire heap and we don't want to find |
| 2040 // spurious newspace pointers in the old space. | 2159 // spurious newspace pointers in the old space. |
| 2041 *p = HeapObject::FromAddress(NULL); // Fake heap object not in new space. | 2160 *p = HeapObject::FromAddress(NULL); // Fake heap object not in new space. |
| 2042 } | 2161 } |
| 2043 } | 2162 } |
| 2044 | 2163 |
| 2045 | 2164 |
| 2046 static String* UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap, | 2165 static String* UpdateReferenceInExternalStringTableEntry(Heap* heap, |
| 2047 Object** p) { | 2166 Object** p) { |
| 2048 Address old_addr = HeapObject::cast(*p)->address(); | 2167 MapWord map_word = HeapObject::cast(*p)->map_word(); |
| 2049 Address new_addr = Memory::Address_at(old_addr); | 2168 |
| 2050 return String::cast(HeapObject::FromAddress(new_addr)); | 2169 if (map_word.IsForwardingAddress()) { |
| 2170 return String::cast(map_word.ToForwardingAddress()); | |
| 2171 } | |
| 2172 | |
| 2173 return String::cast(*p); | |
| 2051 } | 2174 } |
| 2052 | 2175 |
| 2053 | 2176 |
| 2054 static bool TryPromoteObject(Heap* heap, HeapObject* object, int object_size) { | 2177 bool MarkCompactCollector::TryPromoteObject(HeapObject* object, |
| 2178 int object_size) { | |
| 2055 Object* result; | 2179 Object* result; |
| 2056 | 2180 |
| 2057 if (object_size > heap->MaxObjectSizeInPagedSpace()) { | 2181 if (object_size > heap()->MaxObjectSizeInPagedSpace()) { |
| 2058 MaybeObject* maybe_result = | 2182 MaybeObject* maybe_result = |
| 2059 heap->lo_space()->AllocateRawFixedArray(object_size); | 2183 heap()->lo_space()->AllocateRawFixedArray(object_size); |
| 2060 if (maybe_result->ToObject(&result)) { | 2184 if (maybe_result->ToObject(&result)) { |
| 2061 HeapObject* target = HeapObject::cast(result); | 2185 HeapObject* target = HeapObject::cast(result); |
| 2062 MigrateObject(heap, target->address(), object->address(), object_size, | 2186 MigrateObject(target->address(), |
| 2063 true); | 2187 object->address(), |
| 2064 heap->mark_compact_collector()->tracer()-> | 2188 object_size, |
| 2189 LO_SPACE); | |
| 2190 heap()->mark_compact_collector()->tracer()-> | |
| 2065 increment_promoted_objects_size(object_size); | 2191 increment_promoted_objects_size(object_size); |
| 2066 return true; | 2192 return true; |
| 2067 } | 2193 } |
| 2068 } else { | 2194 } else { |
| 2069 OldSpace* target_space = heap->TargetSpace(object); | 2195 OldSpace* target_space = heap()->TargetSpace(object); |
| 2070 | 2196 |
| 2071 ASSERT(target_space == heap->old_pointer_space() || | 2197 ASSERT(target_space == heap()->old_pointer_space() || |
| 2072 target_space == heap->old_data_space()); | 2198 target_space == heap()->old_data_space()); |
| 2073 MaybeObject* maybe_result = target_space->AllocateRaw(object_size); | 2199 MaybeObject* maybe_result = target_space->AllocateRaw(object_size); |
| 2074 if (maybe_result->ToObject(&result)) { | 2200 if (maybe_result->ToObject(&result)) { |
| 2075 HeapObject* target = HeapObject::cast(result); | 2201 HeapObject* target = HeapObject::cast(result); |
| 2076 MigrateObject(heap, | 2202 MigrateObject(target->address(), |
| 2077 target->address(), | |
| 2078 object->address(), | 2203 object->address(), |
| 2079 object_size, | 2204 object_size, |
| 2080 target_space == heap->old_pointer_space()); | 2205 target_space->identity()); |
| 2081 heap->mark_compact_collector()->tracer()-> | 2206 heap()->mark_compact_collector()->tracer()-> |
| 2082 increment_promoted_objects_size(object_size); | 2207 increment_promoted_objects_size(object_size); |
| 2083 return true; | 2208 return true; |
| 2084 } | 2209 } |
| 2085 } | 2210 } |
| 2086 | 2211 |
| 2087 return false; | 2212 return false; |
| 2088 } | 2213 } |
| 2089 | 2214 |
| 2090 | 2215 |
| 2091 void MarkCompactCollector::SweepNewSpace(NewSpace* space) { | 2216 void MarkCompactCollector::EvacuateNewSpace() { |
| 2092 heap_->CheckNewSpaceExpansionCriteria(); | 2217 heap()->CheckNewSpaceExpansionCriteria(); |
| 2218 | |
| 2219 NewSpace* new_space = heap()->new_space(); | |
| 2093 | 2220 |
| 2094 // Store allocation range before flipping semispaces. | 2221 // Store allocation range before flipping semispaces. |
| 2095 Address from_bottom = space->bottom(); | 2222 Address from_bottom = new_space->bottom(); |
| 2096 Address from_top = space->top(); | 2223 Address from_top = new_space->top(); |
| 2097 | 2224 |
| 2098 // Flip the semispaces. After flipping, to space is empty, from space has | 2225 // Flip the semispaces. After flipping, to space is empty, from space has |
| 2099 // live objects. | 2226 // live objects. |
| 2100 space->Flip(); | 2227 new_space->Flip(); |
| 2101 space->ResetAllocationInfo(); | 2228 new_space->ResetAllocationInfo(); |
| 2102 | 2229 |
| 2103 int survivors_size = 0; | 2230 int survivors_size = 0; |
| 2104 | 2231 |
| 2105 // First pass: traverse all objects in inactive semispace, remove marks, | 2232 // First pass: traverse all objects in inactive semispace, remove marks, |
| 2106 // migrate live objects and write forwarding addresses. This stage puts | 2233 // migrate live objects and write forwarding addresses. This stage puts |
| 2107 // new entries in the store buffer and may cause some pages to be marked | 2234 // new entries in the store buffer and may cause some pages to be marked |
| 2108 // scan-on-scavenge. | 2235 // scan-on-scavenge. |
| 2109 SemiSpaceIterator from_it(from_bottom, from_top); | 2236 SemiSpaceIterator from_it(from_bottom, from_top); |
| 2110 for (HeapObject* object = from_it.Next(); | 2237 for (HeapObject* object = from_it.Next(); |
| 2111 object != NULL; | 2238 object != NULL; |
| 2112 object = from_it.Next()) { | 2239 object = from_it.Next()) { |
| 2113 MarkBit mark_bit = Marking::MarkBitFrom(object); | 2240 MarkBit mark_bit = Marking::MarkBitFrom(object); |
| 2114 if (mark_bit.Get()) { | 2241 if (mark_bit.Get()) { |
| 2115 mark_bit.Clear(); | 2242 mark_bit.Clear(); |
| 2116 heap_->mark_compact_collector()->tracer()->decrement_marked_count(); | |
| 2117 | 2243 |
| 2118 int size = object->Size(); | 2244 int size = object->Size(); |
| 2119 survivors_size += size; | 2245 survivors_size += size; |
| 2120 | 2246 |
| 2121 // Aggressively promote young survivors to the old space. | 2247 // Aggressively promote young survivors to the old space. |
| 2122 if (TryPromoteObject(heap_, object, size)) { | 2248 if (TryPromoteObject(object, size)) { |
| 2123 continue; | 2249 continue; |
| 2124 } | 2250 } |
| 2125 | 2251 |
| 2126 // Promotion failed. Just migrate object to another semispace. | 2252 // Promotion failed. Just migrate object to another semispace. |
| 2127 MaybeObject* allocation = space->AllocateRaw(size); | 2253 MaybeObject* allocation = new_space->AllocateRaw(size); |
| 2128 if (allocation->IsFailure()) { | 2254 if (allocation->IsFailure()) { |
| 2129 if (!space->AddFreshPage()) { | 2255 if (!new_space->AddFreshPage()) { |
| 2130 // Shouldn't happen. We are sweeping linearly, and to-space | 2256 // Shouldn't happen. We are sweeping linearly, and to-space |
| 2131 // has the same number of pages as from-space, so there is | 2257 // has the same number of pages as from-space, so there is |
| 2132 // always room. | 2258 // always room. |
| 2133 UNREACHABLE(); | 2259 UNREACHABLE(); |
| 2134 } | 2260 } |
| 2135 allocation = space->AllocateRaw(size); | 2261 allocation = new_space->AllocateRaw(size); |
| 2136 ASSERT(!allocation->IsFailure()); | 2262 ASSERT(!allocation->IsFailure()); |
| 2137 } | 2263 } |
| 2138 Object* target = allocation->ToObjectUnchecked(); | 2264 Object* target = allocation->ToObjectUnchecked(); |
| 2139 MigrateObject(heap_, | 2265 |
| 2140 HeapObject::cast(target)->address(), | 2266 MigrateObject(HeapObject::cast(target)->address(), |
| 2141 object->address(), | 2267 object->address(), |
| 2142 size, | 2268 size, |
| 2143 false); | 2269 NEW_SPACE); |
| 2144 } else { | 2270 } else { |
| 2145 // Process the dead object before we write a NULL into its header. | 2271 // Process the dead object before we write a NULL into its header. |
| 2146 LiveObjectList::ProcessNonLive(object); | 2272 LiveObjectList::ProcessNonLive(object); |
| 2147 | 2273 |
| 2148 // Mark dead objects in the new space with null in their map field. | 2274 // Mark dead objects in the new space with null in their map field. |
| 2149 Memory::Address_at(object->address()) = NULL; | 2275 Memory::Address_at(object->address()) = NULL; |
| 2150 } | 2276 } |
| 2151 } | 2277 } |
| 2152 | 2278 |
| 2279 heap_->IncrementYoungSurvivorsCounter(survivors_size); | |
| 2280 new_space->set_age_mark(new_space->top()); | |
| 2281 } | |
| 2282 | |
| 2283 | |
| 2284 void MarkCompactCollector::EvacuateLiveObjectsFromPage(Page* p) { | |
| 2285 AlwaysAllocateScope always_allocate; | |
| 2286 | |
| 2287 PagedSpace* space = static_cast<PagedSpace*>(p->owner()); | |
| 2288 | |
| 2289 MarkBit::CellType* cells = p->markbits()->cells(); | |
| 2290 | |
| 2291 int last_cell_index = | |
| 2292 Bitmap::IndexToCell( | |
| 2293 Bitmap::CellAlignIndex( | |
| 2294 p->AddressToMarkbitIndex(p->ObjectAreaEnd()))); | |
| 2295 | |
| 2296 int cell_index = Page::kFirstUsedCell; | |
| 2297 Address cell_base = p->ObjectAreaStart(); | |
| 2298 int offsets[16]; | |
| 2299 | |
| 2300 for (cell_index = Page::kFirstUsedCell; | |
| 2301 cell_index < last_cell_index; | |
| 2302 cell_index++, cell_base += 32 * kPointerSize) { | |
| 2303 ASSERT((unsigned)cell_index == | |
| 2304 Bitmap::IndexToCell( | |
| 2305 Bitmap::CellAlignIndex( | |
| 2306 p->AddressToMarkbitIndex(cell_base)))); | |
| 2307 if (cells[cell_index] == 0) continue; | |
| 2308 | |
| 2309 int live_objects = MarkWordToObjectStarts(cells[cell_index], offsets); | |
| 2310 for (int i = 0; i < live_objects; i++) { | |
| 2311 Address object_addr = cell_base + offsets[i] * kPointerSize; | |
| 2312 HeapObject* object = HeapObject::FromAddress(object_addr); | |
| 2313 ASSERT(Marking::IsBlack(Marking::MarkBitFrom(object))); | |
| 2314 | |
| 2315 int size = object->Size(); | |
| 2316 | |
| 2317 // This should never fail as we are in always allocate scope. | |
| 2318 Object* target = space->AllocateRaw(size)->ToObjectUnchecked(); | |
| 2319 | |
| 2320 MigrateObject(HeapObject::cast(target)->address(), | |
| 2321 object_addr, | |
| 2322 size, | |
| 2323 space->identity()); | |
| 2324 ASSERT(object->map_word().IsForwardingAddress()); | |
| 2325 } | |
| 2326 } | |
| 2327 } | |
| 2328 | |
| 2329 | |
| 2330 void MarkCompactCollector::EvacuatePages() { | |
| 2331 int npages = evacuation_candidates_.length(); | |
| 2332 for (int i = 0; i < npages; i++) { | |
| 2333 Page* p = evacuation_candidates_[i]; | |
| 2334 EvacuateLiveObjectsFromPage(p); | |
| 2335 } | |
| 2336 } | |
| 2337 | |
| 2338 | |
| 2339 void MarkCompactCollector::EvacuateNewSpaceAndCandidates() { | |
| 2340 EvacuateNewSpace(); | |
| 2341 EvacuatePages(); | |
| 2342 | |
| 2153 // Second pass: find pointers to new space and update them. | 2343 // Second pass: find pointers to new space and update them. |
| 2154 PointersToNewGenUpdatingVisitor updating_visitor(heap_); | 2344 PointersUpdatingVisitor updating_visitor(heap()); |
| 2155 | 2345 |
| 2156 // Update pointers in to space. | 2346 // Update pointers in to space. |
| 2157 SemiSpaceIterator to_it(space->bottom(), space->top()); | 2347 SemiSpaceIterator to_it(heap()->new_space()->bottom(), |
| 2348 heap()->new_space()->top()); | |
| 2158 for (HeapObject* object = to_it.Next(); | 2349 for (HeapObject* object = to_it.Next(); |
| 2159 object != NULL; | 2350 object != NULL; |
| 2160 object = to_it.Next()) { | 2351 object = to_it.Next()) { |
| 2161 StaticPointersToNewGenUpdatingVisitor::IterateBody(object->map(), | 2352 Map* map = object->map(); |
| 2162 object); | 2353 object->IterateBody(map->instance_type(), |
| 2354 object->SizeFromMap(map), | |
| 2355 &updating_visitor); | |
| 2163 } | 2356 } |
| 2164 | 2357 |
| 2165 // Update roots. | 2358 // Update roots. |
| 2166 heap_->IterateRoots(&updating_visitor, VISIT_ALL_IN_SWEEP_NEWSPACE); | 2359 heap_->IterateRoots(&updating_visitor, VISIT_ALL_IN_SWEEP_NEWSPACE); |
| 2167 LiveObjectList::IterateElements(&updating_visitor); | 2360 LiveObjectList::IterateElements(&updating_visitor); |
| 2168 | 2361 |
| 2169 { | 2362 { |
| 2170 StoreBufferRebuildScope scope(heap_, | 2363 StoreBufferRebuildScope scope(heap_, |
| 2171 heap_->store_buffer(), | 2364 heap_->store_buffer(), |
| 2172 &Heap::ScavengeStoreBufferCallback); | 2365 &Heap::ScavengeStoreBufferCallback); |
| 2173 heap_->store_buffer()->IteratePointersToNewSpace(&UpdatePointerToNewGen); | 2366 heap_->store_buffer()->IteratePointersToNewSpace( |
| 2367 &UpdatePointer, StoreBuffer::SKIP_SLOTS_IN_EVACUATION_CANDIDATES); | |
| 2174 } | 2368 } |
| 2369 slots_buffer_.Iterate(&updating_visitor); | |
| 2175 | 2370 |
| 2176 // Update pointers from cells. | 2371 // Update pointers from cells. |
| 2177 HeapObjectIterator cell_iterator(heap_->cell_space()); | 2372 HeapObjectIterator cell_iterator(heap_->cell_space()); |
| 2178 for (HeapObject* cell = cell_iterator.Next(); | 2373 for (HeapObject* cell = cell_iterator.Next(); |
| 2179 cell != NULL; | 2374 cell != NULL; |
| 2180 cell = cell_iterator.Next()) { | 2375 cell = cell_iterator.Next()) { |
| 2181 if (cell->IsJSGlobalPropertyCell()) { | 2376 if (cell->IsJSGlobalPropertyCell()) { |
| 2182 Address value_address = | 2377 Address value_address = |
| 2183 reinterpret_cast<Address>(cell) + | 2378 reinterpret_cast<Address>(cell) + |
| 2184 (JSGlobalPropertyCell::kValueOffset - kHeapObjectTag); | 2379 (JSGlobalPropertyCell::kValueOffset - kHeapObjectTag); |
| 2185 updating_visitor.VisitPointer(reinterpret_cast<Object**>(value_address)); | 2380 updating_visitor.VisitPointer(reinterpret_cast<Object**>(value_address)); |
| 2186 } | 2381 } |
| 2187 } | 2382 } |
| 2188 | 2383 |
| 2189 // Update pointer from the global contexts list. | 2384 // Update pointer from the global contexts list. |
| 2190 updating_visitor.VisitPointer(heap_->global_contexts_list_address()); | 2385 updating_visitor.VisitPointer(heap_->global_contexts_list_address()); |
| 2191 | 2386 |
| 2387 heap_->symbol_table()->Iterate(&updating_visitor); | |
| 2388 | |
| 2192 // Update pointers from external string table. | 2389 // Update pointers from external string table. |
| 2193 heap_->UpdateNewSpaceReferencesInExternalStringTable( | 2390 heap_->UpdateReferencesInExternalStringTable( |
| 2194 &UpdateNewSpaceReferenceInExternalStringTableEntry); | 2391 &UpdateReferenceInExternalStringTableEntry); |
| 2195 | |
| 2196 // All pointers were updated. Update auxiliary allocation info. | |
| 2197 heap_->IncrementYoungSurvivorsCounter(survivors_size); | |
| 2198 space->set_age_mark(space->top()); | |
| 2199 | 2392 |
| 2200 // Update JSFunction pointers from the runtime profiler. | 2393 // Update JSFunction pointers from the runtime profiler. |
| 2201 heap_->isolate()->runtime_profiler()->UpdateSamplesAfterScavenge(); | 2394 heap_->isolate()->runtime_profiler()->UpdateSamplesAfterScavenge(); |
| 2395 | |
| 2396 #ifdef DEBUG | |
| 2397 VerifyEvacuation(heap_); | |
| 2398 #endif | |
| 2399 | |
| 2400 int npages = evacuation_candidates_.length(); | |
| 2401 for (int i = 0; i < npages; i++) { | |
| 2402 Page* p = evacuation_candidates_[i]; | |
| 2403 PagedSpace* space = static_cast<PagedSpace*>(p->owner()); | |
| 2404 space->Free(p->ObjectAreaStart(), Page::kObjectAreaSize); | |
| 2405 p->set_scan_on_scavenge(false); | |
| 2406 // We are not clearing evacuation candidate flag here | |
| 2407 // because it is required to notify lazy sweeper to skip | |
| 2408 // this pages. | |
|
Erik Corry
2011/06/20 20:41:26
this -> these
| |
| 2409 } | |
| 2202 } | 2410 } |
| 2203 | 2411 |
| 2204 | 2412 |
| 2205 INLINE(static uint32_t SweepFree(PagedSpace* space, | 2413 INLINE(static uint32_t SweepFree(PagedSpace* space, |
| 2206 Page* p, | 2414 Page* p, |
| 2207 uint32_t free_start, | 2415 uint32_t free_start, |
| 2208 uint32_t region_end, | 2416 uint32_t region_end, |
| 2209 uint32_t* cells)); | 2417 uint32_t* cells)); |
| 2210 | 2418 |
| 2211 | 2419 |
| (...skipping 306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2518 | 2726 |
| 2519 | 2727 |
| 2520 // Sweeps a space conservatively. After this has been done the larger free | 2728 // Sweeps a space conservatively. After this has been done the larger free |
| 2521 // spaces have been put on the free list and the smaller ones have been | 2729 // spaces have been put on the free list and the smaller ones have been |
| 2522 // ignored and left untouched. A free space is always either ignored or put | 2730 // ignored and left untouched. A free space is always either ignored or put |
| 2523 // on the free list, never split up into two parts. This is important | 2731 // on the free list, never split up into two parts. This is important |
| 2524 // because it means that any FreeSpace maps left actually describe a region of | 2732 // because it means that any FreeSpace maps left actually describe a region of |
| 2525 // memory that can be ignored when scanning. Dead objects other than free | 2733 // memory that can be ignored when scanning. Dead objects other than free |
| 2526 // spaces will not contain the free space map. | 2734 // spaces will not contain the free space map. |
| 2527 int MarkCompactCollector::SweepConservatively(PagedSpace* space, Page* p) { | 2735 int MarkCompactCollector::SweepConservatively(PagedSpace* space, Page* p) { |
| 2736 // We might start advancing sweeper before evacuation happened. | |
| 2737 if (p->IsEvacuationCandidate()) return 0; | |
| 2738 | |
| 2528 int freed_bytes = 0; | 2739 int freed_bytes = 0; |
| 2529 | 2740 |
| 2530 MarkBit::CellType* cells = p->markbits()->cells(); | 2741 MarkBit::CellType* cells = p->markbits()->cells(); |
| 2531 | 2742 |
| 2532 p->SetFlag(MemoryChunk::WAS_SWEPT_CONSERVATIVELY); | 2743 p->SetFlag(MemoryChunk::WAS_SWEPT_CONSERVATIVELY); |
| 2533 | 2744 |
| 2534 // This is the start of the 32 word block that we are currently looking at. | 2745 // This is the start of the 32 word block that we are currently looking at. |
| 2535 Address block_address = p->ObjectAreaStart(); | 2746 Address block_address = p->ObjectAreaStart(); |
| 2536 | 2747 |
| 2537 int last_cell_index = | 2748 int last_cell_index = |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2659 space->ClearStats(); | 2870 space->ClearStats(); |
| 2660 | 2871 |
| 2661 PageIterator it(space); | 2872 PageIterator it(space); |
| 2662 | 2873 |
| 2663 int freed_bytes = 0; | 2874 int freed_bytes = 0; |
| 2664 int newspace_size = space->heap()->new_space()->Size(); | 2875 int newspace_size = space->heap()->new_space()->Size(); |
| 2665 | 2876 |
| 2666 while (it.has_next()) { | 2877 while (it.has_next()) { |
| 2667 Page* p = it.next(); | 2878 Page* p = it.next(); |
| 2668 | 2879 |
| 2880 if (p->IsEvacuationCandidate()) { | |
| 2881 ASSERT(evacuation_candidates_.length() > 0); | |
| 2882 continue; | |
| 2883 } | |
| 2884 | |
| 2669 switch (sweeper) { | 2885 switch (sweeper) { |
| 2670 case CONSERVATIVE: | 2886 case CONSERVATIVE: { |
| 2671 SweepConservatively(space, p); | 2887 SweepConservatively(space, p); |
| 2672 break; | 2888 break; |
| 2889 } | |
| 2673 case LAZY_CONSERVATIVE: | 2890 case LAZY_CONSERVATIVE: |
| 2674 freed_bytes += SweepConservatively(space, p); | 2891 freed_bytes += SweepConservatively(space, p); |
| 2675 // TODO(gc): tweak the heuristic. | 2892 // TODO(gc): tweak the heuristic. |
| 2676 if (freed_bytes >= newspace_size && p != space->LastPage()) { | 2893 if (freed_bytes >= newspace_size && p != space->LastPage()) { |
| 2677 space->SetPagesToSweep(p->next_page(), space->LastPage()); | 2894 space->SetPagesToSweep(p->next_page(), space->LastPage()); |
| 2678 return; | 2895 return; |
| 2679 } | 2896 } |
| 2680 break; | 2897 break; |
| 2681 case PRECISE: | 2898 case PRECISE: |
| 2682 SweepPrecisely(space, p); | 2899 SweepPrecisely(space, p); |
| 2683 break; | 2900 break; |
| 2684 default: | 2901 default: |
| 2685 UNREACHABLE(); | 2902 UNREACHABLE(); |
| 2686 } | 2903 } |
| 2687 } | 2904 } |
| 2688 | 2905 |
| 2689 // TODO(gc): set up allocation top and limit using the free list. | 2906 // TODO(gc): set up allocation top and limit using the free list. |
| 2690 } | 2907 } |
| 2691 | 2908 |
| 2692 | 2909 |
| 2693 void MarkCompactCollector::SweepSpaces() { | 2910 void MarkCompactCollector::SweepSpaces() { |
| 2694 GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_SWEEP); | 2911 GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_SWEEP); |
| 2695 #ifdef DEBUG | 2912 #ifdef DEBUG |
| 2696 state_ = SWEEP_SPACES; | 2913 state_ = SWEEP_SPACES; |
| 2697 #endif | 2914 #endif |
| 2698 | |
| 2699 ASSERT(!IsCompacting()); | |
| 2700 SweeperType how_to_sweep = | 2915 SweeperType how_to_sweep = |
| 2701 FLAG_lazy_sweeping ? LAZY_CONSERVATIVE : CONSERVATIVE; | 2916 FLAG_lazy_sweeping ? LAZY_CONSERVATIVE : CONSERVATIVE; |
| 2702 if (sweep_precisely_) how_to_sweep = PRECISE; | 2917 if (sweep_precisely_) how_to_sweep = PRECISE; |
| 2703 // Noncompacting collections simply sweep the spaces to clear the mark | 2918 // Noncompacting collections simply sweep the spaces to clear the mark |
| 2704 // bits and free the nonlive blocks (for old and map spaces). We sweep | 2919 // bits and free the nonlive blocks (for old and map spaces). We sweep |
| 2705 // the map space last because freeing non-live maps overwrites them and | 2920 // the map space last because freeing non-live maps overwrites them and |
| 2706 // the other spaces rely on possibly non-live maps to get the sizes for | 2921 // the other spaces rely on possibly non-live maps to get the sizes for |
| 2707 // non-live objects. | 2922 // non-live objects. |
| 2708 SweepSpace(heap()->old_pointer_space(), how_to_sweep); | 2923 SweepSpace(heap()->old_pointer_space(), how_to_sweep); |
| 2709 SweepSpace(heap()->old_data_space(), how_to_sweep); | 2924 SweepSpace(heap()->old_data_space(), how_to_sweep); |
| 2710 SweepSpace(heap()->code_space(), PRECISE); | 2925 SweepSpace(heap()->code_space(), PRECISE); |
| 2711 // TODO(gc): implement specialized sweeper for cell space. | 2926 // TODO(gc): implement specialized sweeper for cell space. |
| 2712 SweepSpace(heap()->cell_space(), PRECISE); | 2927 SweepSpace(heap()->cell_space(), PRECISE); |
| 2713 { GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_SWEEP_NEWSPACE); | 2928 { GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_SWEEP_NEWSPACE); |
| 2714 SweepNewSpace(heap_->new_space()); | 2929 EvacuateNewSpaceAndCandidates(); |
| 2715 } | 2930 } |
| 2716 // TODO(gc): ClearNonLiveTransitions depends on precise sweeping of | 2931 // TODO(gc): ClearNonLiveTransitions depends on precise sweeping of |
| 2717 // map space to detect whether unmarked map became dead in this | 2932 // map space to detect whether unmarked map became dead in this |
| 2718 // collection or in one of the previous ones. | 2933 // collection or in one of the previous ones. |
| 2719 // TODO(gc): Implement specialized sweeper for map space. | 2934 // TODO(gc): Implement specialized sweeper for map space. |
| 2720 SweepSpace(heap()->map_space(), PRECISE); | 2935 SweepSpace(heap()->map_space(), PRECISE); |
| 2721 | 2936 |
| 2722 ASSERT(live_map_objects_size_ <= heap()->map_space()->Size()); | 2937 ASSERT(live_map_objects_size_ <= heap()->map_space()->Size()); |
| 2723 | 2938 |
| 2724 // Deallocate unmarked objects and clear marked bits for marked objects. | 2939 // Deallocate unmarked objects and clear marked bits for marked objects. |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2812 #endif | 3027 #endif |
| 2813 #ifdef ENABLE_LOGGING_AND_PROFILING | 3028 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 2814 if (obj->IsCode()) { | 3029 if (obj->IsCode()) { |
| 2815 PROFILE(isolate, CodeDeleteEvent(obj->address())); | 3030 PROFILE(isolate, CodeDeleteEvent(obj->address())); |
| 2816 } | 3031 } |
| 2817 #endif | 3032 #endif |
| 2818 } | 3033 } |
| 2819 | 3034 |
| 2820 | 3035 |
| 2821 void MarkCompactCollector::Initialize() { | 3036 void MarkCompactCollector::Initialize() { |
| 2822 StaticPointersToNewGenUpdatingVisitor::Initialize(); | |
| 2823 StaticMarkingVisitor::Initialize(); | 3037 StaticMarkingVisitor::Initialize(); |
| 2824 } | 3038 } |
| 2825 | 3039 |
| 2826 | 3040 |
| 3041 SlotsBuffer::SlotsBuffer() | |
| 3042 : buffers_(0), | |
| 3043 buffer_(NULL), | |
| 3044 idx_(kBufferSize), | |
| 3045 buffer_idx_(-1) { | |
| 3046 } | |
| 3047 | |
| 3048 | |
| 3049 SlotsBuffer::~SlotsBuffer() { | |
| 3050 for (int buffer_index = 0; buffer_index < buffers_.length(); ++buffer_index) { | |
| 3051 delete buffers_[buffer_index]; | |
| 3052 } | |
| 3053 } | |
| 3054 | |
| 3055 | |
| 3056 void SlotsBuffer::Clear() { | |
| 3057 idx_ = kBufferSize; | |
| 3058 buffer_idx_ = -1; | |
| 3059 } | |
| 3060 | |
| 3061 | |
| 3062 void SlotsBuffer::Add(Object** slot) { | |
| 3063 if (idx_ == kBufferSize) { | |
| 3064 idx_ = 0; | |
| 3065 buffer_idx_++; | |
| 3066 if (buffer_idx_ == buffers_.length()) { | |
| 3067 buffers_.Add(new ObjectSlot[kBufferSize]); | |
| 3068 } | |
| 3069 buffer_ = buffers_[buffer_idx_]; | |
| 3070 } | |
| 3071 | |
| 3072 buffer_[idx_++] = slot; | |
| 3073 } | |
| 3074 | |
| 3075 | |
| 3076 void SlotsBuffer::Iterate(ObjectVisitor* visitor) { | |
| 3077 if (buffer_idx_ < 0) return; | |
| 3078 | |
| 3079 for (int buffer_index = 0; buffer_index < buffer_idx_; ++buffer_index) { | |
| 3080 ObjectSlot* buffer = buffers_[buffer_index]; | |
| 3081 for (int slot_idx = 0; slot_idx < kBufferSize; ++slot_idx) { | |
| 3082 visitor->VisitPointer(buffer[slot_idx]); | |
| 3083 } | |
| 3084 } | |
| 3085 | |
| 3086 ObjectSlot* last_buffer = buffers_[buffer_idx_]; | |
| 3087 for (int slot_idx = 0; slot_idx < idx_; ++slot_idx) { | |
| 3088 visitor->VisitPointer(last_buffer[slot_idx]); | |
| 3089 } | |
| 3090 } | |
| 3091 | |
| 3092 | |
| 3093 void SlotsBuffer::Report() { | |
| 3094 } | |
| 3095 | |
| 3096 | |
| 2827 } } // namespace v8::internal | 3097 } } // namespace v8::internal |
| OLD | NEW |