| OLD | NEW |
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/heap/scavenger.h" | 5 #include "src/heap/scavenger.h" |
| 6 | 6 |
| 7 #include "src/contexts.h" | 7 #include "src/contexts.h" |
| 8 #include "src/heap/heap.h" | 8 #include "src/heap/heap.h" |
| 9 #include "src/heap/objects-visiting-inl.h" | 9 #include "src/heap/objects-visiting-inl.h" |
| 10 #include "src/heap/scavenger-inl.h" | 10 #include "src/heap/scavenger-inl.h" |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 193 heap->promotion_queue()->insert( | 193 heap->promotion_queue()->insert( |
| 194 target, object_size, | 194 target, object_size, |
| 195 Marking::IsBlack(Marking::MarkBitFrom(object))); | 195 Marking::IsBlack(Marking::MarkBitFrom(object))); |
| 196 } | 196 } |
| 197 heap->IncrementPromotedObjectsSize(object_size); | 197 heap->IncrementPromotedObjectsSize(object_size); |
| 198 return true; | 198 return true; |
| 199 } | 199 } |
| 200 return false; | 200 return false; |
| 201 } | 201 } |
| 202 | 202 |
| 203 | |
| 204 template <ObjectContents object_contents, AllocationAlignment alignment> | 203 template <ObjectContents object_contents, AllocationAlignment alignment> |
| 205 static inline void EvacuateObject(Map* map, HeapObject** slot, | 204 static inline void EvacuateObject(Map* map, HeapObject** slot, |
| 206 HeapObject* object, int object_size) { | 205 HeapObject* object, int object_size, |
| 206 bool force_promotion) { |
| 207 SLOW_DCHECK(object_size <= Page::kAllocatableMemory); | 207 SLOW_DCHECK(object_size <= Page::kAllocatableMemory); |
| 208 SLOW_DCHECK(object->Size() == object_size); | 208 SLOW_DCHECK(object->Size() == object_size); |
| 209 Heap* heap = map->GetHeap(); | 209 Heap* heap = map->GetHeap(); |
| 210 | 210 |
| 211 if (!heap->ShouldBePromoted(object->address(), object_size)) { | 211 if (!force_promotion && |
| 212 !heap->ShouldBePromoted(object->address(), object_size)) { |
| 212 // A semi-space copy may fail due to fragmentation. In that case, we | 213 // A semi-space copy may fail due to fragmentation. In that case, we |
| 213 // try to promote the object. | 214 // try to promote the object. |
| 214 if (SemiSpaceCopyObject<alignment>(map, slot, object, object_size)) { | 215 if (SemiSpaceCopyObject<alignment>(map, slot, object, object_size)) { |
| 215 return; | 216 return; |
| 216 } | 217 } |
| 217 } | 218 } |
| 218 | 219 |
| 219 if (PromoteObject<object_contents, alignment>(map, slot, object, | 220 if (PromoteObject<object_contents, alignment>(map, slot, object, |
| 220 object_size)) { | 221 object_size)) { |
| 221 return; | 222 return; |
| 222 } | 223 } |
| 223 | 224 |
| 224 // If promotion failed, we try to copy the object to the other semi-space | 225 // If promotion failed, we try to copy the object to the other semi-space |
| 225 if (SemiSpaceCopyObject<alignment>(map, slot, object, object_size)) return; | 226 if (SemiSpaceCopyObject<alignment>(map, slot, object, object_size)) return; |
| 226 | 227 |
| 227 FatalProcessOutOfMemory("Scavenger: semi-space copy\n"); | 228 FatalProcessOutOfMemory("Scavenger: semi-space copy\n"); |
| 228 } | 229 } |
| 229 | 230 |
| 230 | |
| 231 static inline void EvacuateJSFunction(Map* map, HeapObject** slot, | 231 static inline void EvacuateJSFunction(Map* map, HeapObject** slot, |
| 232 HeapObject* object) { | 232 HeapObject* object, |
| 233 ObjectEvacuationStrategy<POINTER_OBJECT>::Visit(map, slot, object); | 233 bool force_promotion) { |
| 234 ObjectEvacuationStrategy<POINTER_OBJECT>::Visit(map, slot, object, |
| 235 force_promotion); |
| 234 | 236 |
| 235 if (marks_handling == IGNORE_MARKS) return; | 237 if (marks_handling == IGNORE_MARKS) return; |
| 236 | 238 |
| 237 MapWord map_word = object->map_word(); | 239 MapWord map_word = object->map_word(); |
| 238 DCHECK(map_word.IsForwardingAddress()); | 240 DCHECK(map_word.IsForwardingAddress()); |
| 239 HeapObject* target = map_word.ToForwardingAddress(); | 241 HeapObject* target = map_word.ToForwardingAddress(); |
| 240 | 242 |
| 241 MarkBit mark_bit = Marking::MarkBitFrom(target); | 243 MarkBit mark_bit = Marking::MarkBitFrom(target); |
| 242 if (Marking::IsBlack(mark_bit)) { | 244 if (Marking::IsBlack(mark_bit)) { |
| 243 // This object is black and it might not be rescanned by marker. | 245 // This object is black and it might not be rescanned by marker. |
| 244 // We should explicitly record code entry slot for compaction because | 246 // We should explicitly record code entry slot for compaction because |
| 245 // promotion queue processing (IteratePromotedObjectPointers) will | 247 // promotion queue processing (IteratePromotedObjectPointers) will |
| 246 // miss it as it is not HeapObject-tagged. | 248 // miss it as it is not HeapObject-tagged. |
| 247 Address code_entry_slot = | 249 Address code_entry_slot = |
| 248 target->address() + JSFunction::kCodeEntryOffset; | 250 target->address() + JSFunction::kCodeEntryOffset; |
| 249 Code* code = Code::cast(Code::GetObjectFromEntryAddress(code_entry_slot)); | 251 Code* code = Code::cast(Code::GetObjectFromEntryAddress(code_entry_slot)); |
| 250 map->GetHeap()->mark_compact_collector()->RecordCodeEntrySlot( | 252 map->GetHeap()->mark_compact_collector()->RecordCodeEntrySlot( |
| 251 target, code_entry_slot, code); | 253 target, code_entry_slot, code); |
| 252 } | 254 } |
| 253 } | 255 } |
| 254 | 256 |
| 255 | |
| 256 static inline void EvacuateFixedArray(Map* map, HeapObject** slot, | 257 static inline void EvacuateFixedArray(Map* map, HeapObject** slot, |
| 257 HeapObject* object) { | 258 HeapObject* object, |
| 259 bool force_promotion) { |
| 258 int length = reinterpret_cast<FixedArray*>(object)->synchronized_length(); | 260 int length = reinterpret_cast<FixedArray*>(object)->synchronized_length(); |
| 259 int object_size = FixedArray::SizeFor(length); | 261 int object_size = FixedArray::SizeFor(length); |
| 260 EvacuateObject<POINTER_OBJECT, kWordAligned>(map, slot, object, | 262 EvacuateObject<POINTER_OBJECT, kWordAligned>(map, slot, object, object_size, |
| 261 object_size); | 263 force_promotion); |
| 262 } | 264 } |
| 263 | 265 |
| 264 | |
| 265 static inline void EvacuateFixedDoubleArray(Map* map, HeapObject** slot, | 266 static inline void EvacuateFixedDoubleArray(Map* map, HeapObject** slot, |
| 266 HeapObject* object) { | 267 HeapObject* object, |
| 268 bool force_promotion) { |
| 267 int length = reinterpret_cast<FixedDoubleArray*>(object)->length(); | 269 int length = reinterpret_cast<FixedDoubleArray*>(object)->length(); |
| 268 int object_size = FixedDoubleArray::SizeFor(length); | 270 int object_size = FixedDoubleArray::SizeFor(length); |
| 269 EvacuateObject<DATA_OBJECT, kDoubleAligned>(map, slot, object, object_size); | 271 EvacuateObject<DATA_OBJECT, kDoubleAligned>(map, slot, object, object_size, |
| 272 force_promotion); |
| 270 } | 273 } |
| 271 | 274 |
| 272 | |
| 273 static inline void EvacuateFixedTypedArray(Map* map, HeapObject** slot, | 275 static inline void EvacuateFixedTypedArray(Map* map, HeapObject** slot, |
| 274 HeapObject* object) { | 276 HeapObject* object, |
| 277 bool force_promotion) { |
| 275 int object_size = reinterpret_cast<FixedTypedArrayBase*>(object)->size(); | 278 int object_size = reinterpret_cast<FixedTypedArrayBase*>(object)->size(); |
| 276 EvacuateObject<POINTER_OBJECT, kWordAligned>(map, slot, object, | 279 EvacuateObject<POINTER_OBJECT, kWordAligned>(map, slot, object, object_size, |
| 277 object_size); | 280 force_promotion); |
| 278 } | 281 } |
| 279 | 282 |
| 280 | |
| 281 static inline void EvacuateFixedFloat64Array(Map* map, HeapObject** slot, | 283 static inline void EvacuateFixedFloat64Array(Map* map, HeapObject** slot, |
| 282 HeapObject* object) { | 284 HeapObject* object, |
| 285 bool force_promotion) { |
| 283 int object_size = reinterpret_cast<FixedFloat64Array*>(object)->size(); | 286 int object_size = reinterpret_cast<FixedFloat64Array*>(object)->size(); |
| 284 EvacuateObject<POINTER_OBJECT, kDoubleAligned>(map, slot, object, | 287 EvacuateObject<POINTER_OBJECT, kDoubleAligned>( |
| 285 object_size); | 288 map, slot, object, object_size, force_promotion); |
| 286 } | 289 } |
| 287 | 290 |
| 288 | |
| 289 static inline void EvacuateJSArrayBuffer(Map* map, HeapObject** slot, | 291 static inline void EvacuateJSArrayBuffer(Map* map, HeapObject** slot, |
| 290 HeapObject* object) { | 292 HeapObject* object, |
| 291 ObjectEvacuationStrategy<POINTER_OBJECT>::Visit(map, slot, object); | 293 bool force_promotion) { |
| 294 ObjectEvacuationStrategy<POINTER_OBJECT>::Visit(map, slot, object, |
| 295 force_promotion); |
| 292 | 296 |
| 293 Heap* heap = map->GetHeap(); | 297 Heap* heap = map->GetHeap(); |
| 294 MapWord map_word = object->map_word(); | 298 MapWord map_word = object->map_word(); |
| 295 DCHECK(map_word.IsForwardingAddress()); | 299 DCHECK(map_word.IsForwardingAddress()); |
| 296 HeapObject* target = map_word.ToForwardingAddress(); | 300 HeapObject* target = map_word.ToForwardingAddress(); |
| 297 if (!heap->InNewSpace(target)) { | 301 if (!heap->InNewSpace(target)) { |
| 298 heap->array_buffer_tracker()->Promote(JSArrayBuffer::cast(target)); | 302 heap->array_buffer_tracker()->Promote(JSArrayBuffer::cast(target)); |
| 299 } | 303 } |
| 300 } | 304 } |
| 301 | 305 |
| 302 | |
| 303 static inline void EvacuateByteArray(Map* map, HeapObject** slot, | 306 static inline void EvacuateByteArray(Map* map, HeapObject** slot, |
| 304 HeapObject* object) { | 307 HeapObject* object, |
| 308 bool force_promotion) { |
| 305 int object_size = reinterpret_cast<ByteArray*>(object)->ByteArraySize(); | 309 int object_size = reinterpret_cast<ByteArray*>(object)->ByteArraySize(); |
| 306 EvacuateObject<DATA_OBJECT, kWordAligned>(map, slot, object, object_size); | 310 EvacuateObject<DATA_OBJECT, kWordAligned>(map, slot, object, object_size, |
| 311 force_promotion); |
| 307 } | 312 } |
| 308 | 313 |
| 309 | |
| 310 static inline void EvacuateSeqOneByteString(Map* map, HeapObject** slot, | 314 static inline void EvacuateSeqOneByteString(Map* map, HeapObject** slot, |
| 311 HeapObject* object) { | 315 HeapObject* object, |
| 316 bool force_promotion) { |
| 312 int object_size = SeqOneByteString::cast(object) | 317 int object_size = SeqOneByteString::cast(object) |
| 313 ->SeqOneByteStringSize(map->instance_type()); | 318 ->SeqOneByteStringSize(map->instance_type()); |
| 314 EvacuateObject<DATA_OBJECT, kWordAligned>(map, slot, object, object_size); | 319 EvacuateObject<DATA_OBJECT, kWordAligned>(map, slot, object, object_size, |
| 320 force_promotion); |
| 315 } | 321 } |
| 316 | 322 |
| 317 | |
| 318 static inline void EvacuateSeqTwoByteString(Map* map, HeapObject** slot, | 323 static inline void EvacuateSeqTwoByteString(Map* map, HeapObject** slot, |
| 319 HeapObject* object) { | 324 HeapObject* object, |
| 325 bool force_promotion) { |
| 320 int object_size = SeqTwoByteString::cast(object) | 326 int object_size = SeqTwoByteString::cast(object) |
| 321 ->SeqTwoByteStringSize(map->instance_type()); | 327 ->SeqTwoByteStringSize(map->instance_type()); |
| 322 EvacuateObject<DATA_OBJECT, kWordAligned>(map, slot, object, object_size); | 328 EvacuateObject<DATA_OBJECT, kWordAligned>(map, slot, object, object_size, |
| 329 force_promotion); |
| 323 } | 330 } |
| 324 | 331 |
| 325 | |
| 326 static inline void EvacuateShortcutCandidate(Map* map, HeapObject** slot, | 332 static inline void EvacuateShortcutCandidate(Map* map, HeapObject** slot, |
| 327 HeapObject* object) { | 333 HeapObject* object, |
| 334 bool force_promotion) { |
| 328 DCHECK(IsShortcutCandidate(map->instance_type())); | 335 DCHECK(IsShortcutCandidate(map->instance_type())); |
| 329 | 336 |
| 330 Heap* heap = map->GetHeap(); | 337 Heap* heap = map->GetHeap(); |
| 331 | 338 |
| 332 if (marks_handling == IGNORE_MARKS && | 339 if (marks_handling == IGNORE_MARKS && |
| 333 ConsString::cast(object)->unchecked_second() == heap->empty_string()) { | 340 ConsString::cast(object)->unchecked_second() == heap->empty_string()) { |
| 334 HeapObject* first = | 341 HeapObject* first = |
| 335 HeapObject::cast(ConsString::cast(object)->unchecked_first()); | 342 HeapObject::cast(ConsString::cast(object)->unchecked_first()); |
| 336 | 343 |
| 337 *slot = first; | 344 *slot = first; |
| 338 | 345 |
| 339 if (!heap->InNewSpace(first)) { | 346 if (!heap->InNewSpace(first)) { |
| 340 object->set_map_word(MapWord::FromForwardingAddress(first)); | 347 object->set_map_word(MapWord::FromForwardingAddress(first)); |
| 341 return; | 348 return; |
| 342 } | 349 } |
| 343 | 350 |
| 344 MapWord first_word = first->map_word(); | 351 MapWord first_word = first->map_word(); |
| 345 if (first_word.IsForwardingAddress()) { | 352 if (first_word.IsForwardingAddress()) { |
| 346 HeapObject* target = first_word.ToForwardingAddress(); | 353 HeapObject* target = first_word.ToForwardingAddress(); |
| 347 | 354 |
| 348 *slot = target; | 355 *slot = target; |
| 349 object->set_map_word(MapWord::FromForwardingAddress(target)); | 356 object->set_map_word(MapWord::FromForwardingAddress(target)); |
| 350 return; | 357 return; |
| 351 } | 358 } |
| 352 | 359 |
| 353 Scavenger::ScavengeObjectSlow(slot, first); | 360 Scavenger::ScavengeObjectSlow(slot, first, force_promotion); |
| 354 object->set_map_word(MapWord::FromForwardingAddress(*slot)); | 361 object->set_map_word(MapWord::FromForwardingAddress(*slot)); |
| 355 return; | 362 return; |
| 356 } | 363 } |
| 357 | 364 |
| 358 int object_size = ConsString::kSize; | 365 int object_size = ConsString::kSize; |
| 359 EvacuateObject<POINTER_OBJECT, kWordAligned>(map, slot, object, | 366 EvacuateObject<POINTER_OBJECT, kWordAligned>(map, slot, object, object_size, |
| 360 object_size); | 367 force_promotion); |
| 361 } | 368 } |
| 362 | 369 |
| 363 template <ObjectContents object_contents> | 370 template <ObjectContents object_contents> |
| 364 class ObjectEvacuationStrategy { | 371 class ObjectEvacuationStrategy { |
| 365 public: | 372 public: |
| 366 template <int object_size> | 373 template <int object_size> |
| 367 static inline void VisitSpecialized(Map* map, HeapObject** slot, | 374 static inline void VisitSpecialized(Map* map, HeapObject** slot, |
| 368 HeapObject* object) { | 375 HeapObject* object, |
| 369 EvacuateObject<object_contents, kWordAligned>(map, slot, object, | 376 bool force_promotion) { |
| 370 object_size); | 377 EvacuateObject<object_contents, kWordAligned>( |
| 378 map, slot, object, object_size, force_promotion); |
| 371 } | 379 } |
| 372 | 380 |
| 373 static inline void Visit(Map* map, HeapObject** slot, HeapObject* object) { | 381 static inline void Visit(Map* map, HeapObject** slot, HeapObject* object, |
| 382 bool force_promotion) { |
| 374 int object_size = map->instance_size(); | 383 int object_size = map->instance_size(); |
| 375 EvacuateObject<object_contents, kWordAligned>(map, slot, object, | 384 EvacuateObject<object_contents, kWordAligned>( |
| 376 object_size); | 385 map, slot, object, object_size, force_promotion); |
| 377 } | 386 } |
| 378 }; | 387 }; |
| 379 | 388 |
| 380 static VisitorDispatchTable<ScavengingCallback> table_; | 389 static VisitorDispatchTable<ScavengingCallback> table_; |
| 381 }; | 390 }; |
| 382 | 391 |
| 383 | 392 |
| 384 template <MarksHandling marks_handling, | 393 template <MarksHandling marks_handling, |
| 385 LoggingAndProfiling logging_and_profiling_mode> | 394 LoggingAndProfiling logging_and_profiling_mode> |
| 386 VisitorDispatchTable<ScavengingCallback> | 395 VisitorDispatchTable<ScavengingCallback> |
| 387 ScavengingVisitor<marks_handling, logging_and_profiling_mode>::table_; | 396 ScavengingVisitor<marks_handling, logging_and_profiling_mode>::table_; |
| 388 | 397 |
| 389 | 398 |
| 390 // static | 399 // static |
| 391 void Scavenger::Initialize() { | 400 void Scavenger::Initialize() { |
| 392 ScavengingVisitor<TRANSFER_MARKS, | 401 ScavengingVisitor<TRANSFER_MARKS, |
| 393 LOGGING_AND_PROFILING_DISABLED>::Initialize(); | 402 LOGGING_AND_PROFILING_DISABLED>::Initialize(); |
| 394 ScavengingVisitor<IGNORE_MARKS, LOGGING_AND_PROFILING_DISABLED>::Initialize(); | 403 ScavengingVisitor<IGNORE_MARKS, LOGGING_AND_PROFILING_DISABLED>::Initialize(); |
| 395 ScavengingVisitor<TRANSFER_MARKS, | 404 ScavengingVisitor<TRANSFER_MARKS, |
| 396 LOGGING_AND_PROFILING_ENABLED>::Initialize(); | 405 LOGGING_AND_PROFILING_ENABLED>::Initialize(); |
| 397 ScavengingVisitor<IGNORE_MARKS, LOGGING_AND_PROFILING_ENABLED>::Initialize(); | 406 ScavengingVisitor<IGNORE_MARKS, LOGGING_AND_PROFILING_ENABLED>::Initialize(); |
| 398 } | 407 } |
| 399 | 408 |
| 400 | 409 |
| 401 // static | 410 // static |
| 402 void Scavenger::ScavengeObjectSlow(HeapObject** p, HeapObject* object) { | 411 void Scavenger::ScavengeObjectSlow(HeapObject** p, HeapObject* object, |
| 412 bool force_promotion) { |
| 403 SLOW_DCHECK(object->GetIsolate()->heap()->InFromSpace(object)); | 413 SLOW_DCHECK(object->GetIsolate()->heap()->InFromSpace(object)); |
| 404 MapWord first_word = object->map_word(); | 414 MapWord first_word = object->map_word(); |
| 405 SLOW_DCHECK(!first_word.IsForwardingAddress()); | 415 SLOW_DCHECK(!first_word.IsForwardingAddress()); |
| 406 Map* map = first_word.ToMap(); | 416 Map* map = first_word.ToMap(); |
| 407 Scavenger* scavenger = map->GetHeap()->scavenge_collector_; | 417 Scavenger* scavenger = map->GetHeap()->scavenge_collector_; |
| 408 scavenger->scavenging_visitors_table_.GetVisitor(map)(map, p, object); | 418 scavenger->scavenging_visitors_table_.GetVisitor(map)(map, p, object, |
| 419 force_promotion); |
| 409 } | 420 } |
| 410 | 421 |
| 411 | 422 |
| 412 void Scavenger::SelectScavengingVisitorsTable() { | 423 void Scavenger::SelectScavengingVisitorsTable() { |
| 413 bool logging_and_profiling = | 424 bool logging_and_profiling = |
| 414 FLAG_verify_predictable || isolate()->logger()->is_logging() || | 425 FLAG_verify_predictable || isolate()->logger()->is_logging() || |
| 415 isolate()->cpu_profiler()->is_profiling() || | 426 isolate()->cpu_profiler()->is_profiling() || |
| 416 (isolate()->heap_profiler() != NULL && | 427 (isolate()->heap_profiler() != NULL && |
| 417 isolate()->heap_profiler()->is_tracking_object_moves()); | 428 isolate()->heap_profiler()->is_tracking_object_moves()); |
| 418 | 429 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 465 | 476 |
| 466 void ScavengeVisitor::ScavengePointer(Object** p) { | 477 void ScavengeVisitor::ScavengePointer(Object** p) { |
| 467 Object* object = *p; | 478 Object* object = *p; |
| 468 if (!heap_->InNewSpace(object)) return; | 479 if (!heap_->InNewSpace(object)) return; |
| 469 Scavenger::ScavengeObject(reinterpret_cast<HeapObject**>(p), | 480 Scavenger::ScavengeObject(reinterpret_cast<HeapObject**>(p), |
| 470 reinterpret_cast<HeapObject*>(object)); | 481 reinterpret_cast<HeapObject*>(object)); |
| 471 } | 482 } |
| 472 | 483 |
| 473 } // namespace internal | 484 } // namespace internal |
| 474 } // namespace v8 | 485 } // namespace v8 |
| OLD | NEW |