OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 #ifndef V8_HEAP_SPACES_H_ | 5 #ifndef V8_HEAP_SPACES_H_ |
6 #define V8_HEAP_SPACES_H_ | 6 #define V8_HEAP_SPACES_H_ |
7 | 7 |
8 #include "src/allocation.h" | 8 #include "src/allocation.h" |
9 #include "src/atomic-utils.h" | 9 #include "src/atomic-utils.h" |
10 #include "src/base/atomicops.h" | 10 #include "src/base/atomicops.h" |
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
261 | 261 |
262 class SkipList; | 262 class SkipList; |
263 class SlotsBuffer; | 263 class SlotsBuffer; |
264 | 264 |
265 // MemoryChunk represents a memory region owned by a specific space. | 265 // MemoryChunk represents a memory region owned by a specific space. |
266 // It is divided into the header and the body. Chunk start is always | 266 // It is divided into the header and the body. Chunk start is always |
267 // 1MB aligned. Start of the body is aligned so it can accommodate | 267 // 1MB aligned. Start of the body is aligned so it can accommodate |
268 // any heap object. | 268 // any heap object. |
269 class MemoryChunk { | 269 class MemoryChunk { |
270 public: | 270 public: |
| 271 enum MemoryChunkFlags { |
| 272 IS_EXECUTABLE, |
| 273 ABOUT_TO_BE_FREED, |
| 274 POINTERS_TO_HERE_ARE_INTERESTING, |
| 275 POINTERS_FROM_HERE_ARE_INTERESTING, |
| 276 SCAN_ON_SCAVENGE, |
| 277 IN_FROM_SPACE, // Mutually exclusive with IN_TO_SPACE. |
| 278 IN_TO_SPACE, // All pages in new space has one of these two set. |
| 279 NEW_SPACE_BELOW_AGE_MARK, |
| 280 EVACUATION_CANDIDATE, |
| 281 RESCAN_ON_EVACUATION, |
| 282 NEVER_EVACUATE, // May contain immortal immutables. |
| 283 POPULAR_PAGE, // Slots buffer of this page overflowed on the previous GC. |
| 284 |
| 285 // WAS_SWEPT indicates that marking bits have been cleared by the sweeper, |
| 286 // otherwise marking bits are still intact. |
| 287 WAS_SWEPT, |
| 288 |
| 289 // Large objects can have a progress bar in their page header. These object |
| 290 // are scanned in increments and will be kept black while being scanned. |
| 291 // Even if the mutator writes to them they will be kept black and a white |
| 292 // to grey transition is performed in the value. |
| 293 HAS_PROGRESS_BAR, |
| 294 |
| 295 // This flag is intended to be used for testing. Works only when both |
| 296 // FLAG_stress_compaction and FLAG_manual_evacuation_candidates_selection |
| 297 // are set. It forces the page to become an evacuation candidate at next |
| 298 // candidates selection cycle. |
| 299 FORCE_EVACUATION_CANDIDATE_FOR_TESTING, |
| 300 |
| 301 // The memory chunk is already logically freed, however the actual freeing |
| 302 // still has to be performed. |
| 303 PRE_FREED, |
| 304 |
| 305 // Last flag, keep at bottom. |
| 306 NUM_MEMORY_CHUNK_FLAGS |
| 307 }; |
| 308 |
271 // |kCompactionDone|: Initial compaction state of a |MemoryChunk|. | 309 // |kCompactionDone|: Initial compaction state of a |MemoryChunk|. |
272 // |kCompactingInProgress|: Parallel compaction is currently in progress. | 310 // |kCompactingInProgress|: Parallel compaction is currently in progress. |
273 // |kCompactingFinalize|: Parallel compaction is done but the chunk needs to | 311 // |kCompactingFinalize|: Parallel compaction is done but the chunk needs to |
274 // be finalized. | 312 // be finalized. |
275 // |kCompactingAborted|: Parallel compaction has been aborted, which should | 313 // |kCompactingAborted|: Parallel compaction has been aborted, which should |
276 // for now only happen in OOM scenarios. | 314 // for now only happen in OOM scenarios. |
277 enum ParallelCompactingState { | 315 enum ParallelCompactingState { |
278 kCompactingDone, | 316 kCompactingDone, |
279 kCompactingInProgress, | 317 kCompactingInProgress, |
280 kCompactingFinalize, | 318 kCompactingFinalize, |
281 kCompactingAborted, | 319 kCompactingAborted, |
282 }; | 320 }; |
283 | 321 |
284 // |kSweepingDone|: The page state when sweeping is complete or sweeping must | 322 // |kSweepingDone|: The page state when sweeping is complete or sweeping must |
285 // not be performed on that page. | 323 // not be performed on that page. |
286 // |kSweepingFinalize|: A sweeper thread is done sweeping this page and will | 324 // |kSweepingFinalize|: A sweeper thread is done sweeping this page and will |
287 // not touch the page memory anymore. | 325 // not touch the page memory anymore. |
288 // |kSweepingInProgress|: This page is currently swept by a sweeper thread. | 326 // |kSweepingInProgress|: This page is currently swept by a sweeper thread. |
289 // |kSweepingPending|: This page is ready for parallel sweeping. | 327 // |kSweepingPending|: This page is ready for parallel sweeping. |
290 enum ParallelSweepingState { | 328 enum ParallelSweepingState { |
291 kSweepingDone, | 329 kSweepingDone, |
292 kSweepingFinalize, | 330 kSweepingFinalize, |
293 kSweepingInProgress, | 331 kSweepingInProgress, |
294 kSweepingPending | 332 kSweepingPending |
295 }; | 333 }; |
296 | 334 |
| 335 // Every n write barrier invocations we go to runtime even though |
| 336 // we could have handled it in generated code. This lets us check |
| 337 // whether we have hit the limit and should do some more marking. |
| 338 static const int kWriteBarrierCounterGranularity = 500; |
| 339 |
| 340 static const int kPointersToHereAreInterestingMask = |
| 341 1 << POINTERS_TO_HERE_ARE_INTERESTING; |
| 342 |
| 343 static const int kPointersFromHereAreInterestingMask = |
| 344 1 << POINTERS_FROM_HERE_ARE_INTERESTING; |
| 345 |
| 346 static const int kEvacuationCandidateMask = 1 << EVACUATION_CANDIDATE; |
| 347 |
| 348 static const int kSkipEvacuationSlotsRecordingMask = |
| 349 (1 << EVACUATION_CANDIDATE) | (1 << RESCAN_ON_EVACUATION) | |
| 350 (1 << IN_FROM_SPACE) | (1 << IN_TO_SPACE); |
| 351 |
| 352 static const intptr_t kAlignment = |
| 353 (static_cast<uintptr_t>(1) << kPageSizeBits); |
| 354 |
| 355 static const intptr_t kAlignmentMask = kAlignment - 1; |
| 356 |
| 357 static const intptr_t kSizeOffset = 0; |
| 358 |
| 359 static const intptr_t kLiveBytesOffset = |
| 360 kSizeOffset + kPointerSize // size_t size |
| 361 + kIntptrSize // intptr_t flags_ |
| 362 + kPointerSize // Address area_start_ |
| 363 + kPointerSize // Address area_end_ |
| 364 + 2 * kPointerSize // base::VirtualMemory reservation_ |
| 365 + kPointerSize // Address owner_ |
| 366 + kPointerSize // Heap* heap_ |
| 367 + kIntSize; // int store_buffer_counter_ |
| 368 |
| 369 static const size_t kSlotsBufferOffset = |
| 370 kLiveBytesOffset + kIntSize; // int live_byte_count_ |
| 371 |
| 372 static const size_t kWriteBarrierCounterOffset = |
| 373 kSlotsBufferOffset + kPointerSize // SlotsBuffer* slots_buffer_; |
| 374 + kPointerSize; // SkipList* skip_list_; |
| 375 |
| 376 static const size_t kMinHeaderSize = |
| 377 kWriteBarrierCounterOffset + |
| 378 kIntptrSize // intptr_t write_barrier_counter_ |
| 379 + kIntSize // int progress_bar_ |
| 380 + kPointerSize // AtomicValue high_water_mark_ |
| 381 + kPointerSize // base::Mutex* mutex_ |
| 382 + kPointerSize // base::AtomicWord parallel_sweeping_ |
| 383 + kPointerSize // AtomicValue parallel_compaction_ |
| 384 + 5 * kPointerSize // AtomicNumber free-list statistics |
| 385 + kPointerSize // AtomicValue next_chunk_ |
| 386 + kPointerSize; // AtomicValue prev_chunk_ |
| 387 |
| 388 // We add some more space to the computed header size to amount for missing |
| 389 // alignment requirements in our computation. |
| 390 // Try to get kHeaderSize properly aligned on 32-bit and 64-bit machines. |
| 391 static const size_t kHeaderSize = kMinHeaderSize + kIntSize; |
| 392 |
| 393 static const int kBodyOffset = |
| 394 CODE_POINTER_ALIGN(kHeaderSize + Bitmap::kSize); |
| 395 |
| 396 // The start offset of the object area in a page. Aligned to both maps and |
| 397 // code alignment to be suitable for both. Also aligned to 32 words because |
| 398 // the marking bitmap is arranged in 32 bit chunks. |
| 399 static const int kObjectStartAlignment = 32 * kPointerSize; |
| 400 static const int kObjectStartOffset = |
| 401 kBodyOffset - 1 + |
| 402 (kObjectStartAlignment - (kBodyOffset - 1) % kObjectStartAlignment); |
| 403 |
| 404 static const int kFlagsOffset = kPointerSize; |
| 405 |
| 406 static void IncrementLiveBytesFromMutator(HeapObject* object, int by); |
| 407 |
297 // Only works if the pointer is in the first kPageSize of the MemoryChunk. | 408 // Only works if the pointer is in the first kPageSize of the MemoryChunk. |
298 static MemoryChunk* FromAddress(Address a) { | 409 static MemoryChunk* FromAddress(Address a) { |
299 return reinterpret_cast<MemoryChunk*>(OffsetFrom(a) & ~kAlignmentMask); | 410 return reinterpret_cast<MemoryChunk*>(OffsetFrom(a) & ~kAlignmentMask); |
300 } | 411 } |
| 412 |
301 static const MemoryChunk* FromAddress(const byte* a) { | 413 static const MemoryChunk* FromAddress(const byte* a) { |
302 return reinterpret_cast<const MemoryChunk*>(OffsetFrom(a) & | 414 return reinterpret_cast<const MemoryChunk*>(OffsetFrom(a) & |
303 ~kAlignmentMask); | 415 ~kAlignmentMask); |
304 } | 416 } |
305 | 417 |
| 418 static void IncrementLiveBytesFromGC(HeapObject* object, int by) { |
| 419 MemoryChunk::FromAddress(object->address())->IncrementLiveBytes(by); |
| 420 } |
| 421 |
306 // Only works for addresses in pointer spaces, not data or code spaces. | 422 // Only works for addresses in pointer spaces, not data or code spaces. |
307 static inline MemoryChunk* FromAnyPointerAddress(Heap* heap, Address addr); | 423 static inline MemoryChunk* FromAnyPointerAddress(Heap* heap, Address addr); |
308 | 424 |
| 425 static inline uint32_t FastAddressToMarkbitIndex(Address addr) { |
| 426 const intptr_t offset = reinterpret_cast<intptr_t>(addr) & kAlignmentMask; |
| 427 return static_cast<uint32_t>(offset) >> kPointerSizeLog2; |
| 428 } |
| 429 |
| 430 static inline void UpdateHighWaterMark(Address mark) { |
| 431 if (mark == nullptr) return; |
| 432 // Need to subtract one from the mark because when a chunk is full the |
| 433 // top points to the next address after the chunk, which effectively belongs |
| 434 // to another chunk. See the comment to Page::FromAllocationTop. |
| 435 MemoryChunk* chunk = MemoryChunk::FromAddress(mark - 1); |
| 436 intptr_t new_mark = static_cast<intptr_t>(mark - chunk->address()); |
| 437 intptr_t old_mark = 0; |
| 438 do { |
| 439 old_mark = chunk->high_water_mark_.Value(); |
| 440 } while ((new_mark > old_mark) && |
| 441 !chunk->high_water_mark_.TrySetValue(old_mark, new_mark)); |
| 442 } |
| 443 |
309 Address address() { return reinterpret_cast<Address>(this); } | 444 Address address() { return reinterpret_cast<Address>(this); } |
310 | 445 |
311 bool is_valid() { return address() != NULL; } | 446 bool is_valid() { return address() != NULL; } |
312 | 447 |
313 MemoryChunk* next_chunk() const { | 448 MemoryChunk* next_chunk() { return next_chunk_.Value(); } |
314 return reinterpret_cast<MemoryChunk*>(base::Acquire_Load(&next_chunk_)); | |
315 } | |
316 | 449 |
317 MemoryChunk* prev_chunk() const { | 450 MemoryChunk* prev_chunk() { return prev_chunk_.Value(); } |
318 return reinterpret_cast<MemoryChunk*>(base::Acquire_Load(&prev_chunk_)); | |
319 } | |
320 | 451 |
321 void set_next_chunk(MemoryChunk* next) { | 452 void set_next_chunk(MemoryChunk* next) { next_chunk_.SetValue(next); } |
322 base::Release_Store(&next_chunk_, reinterpret_cast<base::AtomicWord>(next)); | |
323 } | |
324 | 453 |
325 void set_prev_chunk(MemoryChunk* prev) { | 454 void set_prev_chunk(MemoryChunk* prev) { prev_chunk_.SetValue(prev); } |
326 base::Release_Store(&prev_chunk_, reinterpret_cast<base::AtomicWord>(prev)); | |
327 } | |
328 | 455 |
329 Space* owner() const { | 456 Space* owner() const { |
330 if ((reinterpret_cast<intptr_t>(owner_) & kPageHeaderTagMask) == | 457 if ((reinterpret_cast<intptr_t>(owner_) & kPageHeaderTagMask) == |
331 kPageHeaderTag) { | 458 kPageHeaderTag) { |
332 return reinterpret_cast<Space*>(reinterpret_cast<intptr_t>(owner_) - | 459 return reinterpret_cast<Space*>(reinterpret_cast<intptr_t>(owner_) - |
333 kPageHeaderTag); | 460 kPageHeaderTag); |
334 } else { | 461 } else { |
335 return NULL; | 462 return NULL; |
336 } | 463 } |
337 } | 464 } |
338 | 465 |
339 void set_owner(Space* space) { | 466 void set_owner(Space* space) { |
340 DCHECK((reinterpret_cast<intptr_t>(space) & kPageHeaderTagMask) == 0); | 467 DCHECK((reinterpret_cast<intptr_t>(space) & kPageHeaderTagMask) == 0); |
341 owner_ = reinterpret_cast<Address>(space) + kPageHeaderTag; | 468 owner_ = reinterpret_cast<Address>(space) + kPageHeaderTag; |
342 DCHECK((reinterpret_cast<intptr_t>(owner_) & kPageHeaderTagMask) == | 469 DCHECK((reinterpret_cast<intptr_t>(owner_) & kPageHeaderTagMask) == |
343 kPageHeaderTag); | 470 kPageHeaderTag); |
344 } | 471 } |
345 | 472 |
346 base::VirtualMemory* reserved_memory() { return &reservation_; } | 473 base::VirtualMemory* reserved_memory() { return &reservation_; } |
347 | 474 |
348 void InitializeReservedMemory() { reservation_.Reset(); } | |
349 | |
350 void set_reserved_memory(base::VirtualMemory* reservation) { | 475 void set_reserved_memory(base::VirtualMemory* reservation) { |
351 DCHECK_NOT_NULL(reservation); | 476 DCHECK_NOT_NULL(reservation); |
352 reservation_.TakeControl(reservation); | 477 reservation_.TakeControl(reservation); |
353 } | 478 } |
354 | 479 |
355 bool scan_on_scavenge() { return IsFlagSet(SCAN_ON_SCAVENGE); } | 480 bool scan_on_scavenge() { return IsFlagSet(SCAN_ON_SCAVENGE); } |
356 void initialize_scan_on_scavenge(bool scan) { | 481 void initialize_scan_on_scavenge(bool scan) { |
357 if (scan) { | 482 if (scan) { |
358 SetFlag(SCAN_ON_SCAVENGE); | 483 SetFlag(SCAN_ON_SCAVENGE); |
359 } else { | 484 } else { |
(...skipping 11 matching lines...) Expand all Loading... |
371 return addr >= area_start() && addr < area_end(); | 496 return addr >= area_start() && addr < area_end(); |
372 } | 497 } |
373 | 498 |
374 // Checks whether addr can be a limit of addresses in this page. | 499 // Checks whether addr can be a limit of addresses in this page. |
375 // It's a limit if it's in the page, or if it's just after the | 500 // It's a limit if it's in the page, or if it's just after the |
376 // last byte of the page. | 501 // last byte of the page. |
377 bool ContainsLimit(Address addr) { | 502 bool ContainsLimit(Address addr) { |
378 return addr >= area_start() && addr <= area_end(); | 503 return addr >= area_start() && addr <= area_end(); |
379 } | 504 } |
380 | 505 |
381 // Every n write barrier invocations we go to runtime even though | |
382 // we could have handled it in generated code. This lets us check | |
383 // whether we have hit the limit and should do some more marking. | |
384 static const int kWriteBarrierCounterGranularity = 500; | |
385 | |
386 enum MemoryChunkFlags { | |
387 IS_EXECUTABLE, | |
388 ABOUT_TO_BE_FREED, | |
389 POINTERS_TO_HERE_ARE_INTERESTING, | |
390 POINTERS_FROM_HERE_ARE_INTERESTING, | |
391 SCAN_ON_SCAVENGE, | |
392 IN_FROM_SPACE, // Mutually exclusive with IN_TO_SPACE. | |
393 IN_TO_SPACE, // All pages in new space has one of these two set. | |
394 NEW_SPACE_BELOW_AGE_MARK, | |
395 EVACUATION_CANDIDATE, | |
396 RESCAN_ON_EVACUATION, | |
397 NEVER_EVACUATE, // May contain immortal immutables. | |
398 POPULAR_PAGE, // Slots buffer of this page overflowed on the previous GC. | |
399 | |
400 // WAS_SWEPT indicates that marking bits have been cleared by the sweeper, | |
401 // otherwise marking bits are still intact. | |
402 WAS_SWEPT, | |
403 | |
404 // Large objects can have a progress bar in their page header. These object | |
405 // are scanned in increments and will be kept black while being scanned. | |
406 // Even if the mutator writes to them they will be kept black and a white | |
407 // to grey transition is performed in the value. | |
408 HAS_PROGRESS_BAR, | |
409 | |
410 // This flag is intended to be used for testing. Works only when both | |
411 // FLAG_stress_compaction and FLAG_manual_evacuation_candidates_selection | |
412 // are set. It forces the page to become an evacuation candidate at next | |
413 // candidates selection cycle. | |
414 FORCE_EVACUATION_CANDIDATE_FOR_TESTING, | |
415 | |
416 // The memory chunk is already logically freed, however the actual freeing | |
417 // still has to be performed. | |
418 PRE_FREED, | |
419 | |
420 // Last flag, keep at bottom. | |
421 NUM_MEMORY_CHUNK_FLAGS | |
422 }; | |
423 | |
424 | |
425 static const int kPointersToHereAreInterestingMask = | |
426 1 << POINTERS_TO_HERE_ARE_INTERESTING; | |
427 | |
428 static const int kPointersFromHereAreInterestingMask = | |
429 1 << POINTERS_FROM_HERE_ARE_INTERESTING; | |
430 | |
431 static const int kEvacuationCandidateMask = 1 << EVACUATION_CANDIDATE; | |
432 | |
433 static const int kSkipEvacuationSlotsRecordingMask = | |
434 (1 << EVACUATION_CANDIDATE) | (1 << RESCAN_ON_EVACUATION) | | |
435 (1 << IN_FROM_SPACE) | (1 << IN_TO_SPACE); | |
436 | |
437 | |
438 void SetFlag(int flag) { flags_ |= static_cast<uintptr_t>(1) << flag; } | 506 void SetFlag(int flag) { flags_ |= static_cast<uintptr_t>(1) << flag; } |
439 | 507 |
440 void ClearFlag(int flag) { flags_ &= ~(static_cast<uintptr_t>(1) << flag); } | 508 void ClearFlag(int flag) { flags_ &= ~(static_cast<uintptr_t>(1) << flag); } |
441 | 509 |
442 void SetFlagTo(int flag, bool value) { | 510 void SetFlagTo(int flag, bool value) { |
443 if (value) { | 511 if (value) { |
444 SetFlag(flag); | 512 SetFlag(flag); |
445 } else { | 513 } else { |
446 ClearFlag(flag); | 514 ClearFlag(flag); |
447 } | 515 } |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
534 } | 602 } |
535 } | 603 } |
536 | 604 |
537 bool IsLeftOfProgressBar(Object** slot) { | 605 bool IsLeftOfProgressBar(Object** slot) { |
538 Address slot_address = reinterpret_cast<Address>(slot); | 606 Address slot_address = reinterpret_cast<Address>(slot); |
539 DCHECK(slot_address > this->address()); | 607 DCHECK(slot_address > this->address()); |
540 return (slot_address - (this->address() + kObjectStartOffset)) < | 608 return (slot_address - (this->address() + kObjectStartOffset)) < |
541 progress_bar(); | 609 progress_bar(); |
542 } | 610 } |
543 | 611 |
544 static void IncrementLiveBytesFromGC(HeapObject* object, int by) { | |
545 MemoryChunk::FromAddress(object->address())->IncrementLiveBytes(by); | |
546 } | |
547 | |
548 static void IncrementLiveBytesFromMutator(HeapObject* object, int by); | |
549 | |
550 static const intptr_t kAlignment = | |
551 (static_cast<uintptr_t>(1) << kPageSizeBits); | |
552 | |
553 static const intptr_t kAlignmentMask = kAlignment - 1; | |
554 | |
555 static const intptr_t kSizeOffset = 0; | |
556 | |
557 static const intptr_t kLiveBytesOffset = | |
558 kSizeOffset + kPointerSize // size_t size | |
559 + kIntptrSize // intptr_t flags_ | |
560 + kPointerSize // Address area_start_ | |
561 + kPointerSize // Address area_end_ | |
562 + 2 * kPointerSize // base::VirtualMemory reservation_ | |
563 + kPointerSize // Address owner_ | |
564 + kPointerSize // Heap* heap_ | |
565 + kIntSize; // int store_buffer_counter_ | |
566 | |
567 | |
568 static const size_t kSlotsBufferOffset = | |
569 kLiveBytesOffset + kIntSize; // int live_byte_count_ | |
570 | |
571 static const size_t kWriteBarrierCounterOffset = | |
572 kSlotsBufferOffset + kPointerSize // SlotsBuffer* slots_buffer_; | |
573 + kPointerSize; // SkipList* skip_list_; | |
574 | |
575 static const size_t kMinHeaderSize = | |
576 kWriteBarrierCounterOffset + | |
577 kIntptrSize // intptr_t write_barrier_counter_ | |
578 + kIntSize // int progress_bar_ | |
579 + kPointerSize // AtomicValue high_water_mark_ | |
580 + kPointerSize // base::Mutex* mutex_ | |
581 + kPointerSize // base::AtomicWord parallel_sweeping_ | |
582 + kPointerSize // AtomicValue parallel_compaction_ | |
583 + 5 * kPointerSize // AtomicNumber free-list statistics | |
584 + kPointerSize // base::AtomicWord next_chunk_ | |
585 + kPointerSize; // base::AtomicWord prev_chunk_ | |
586 | |
587 // We add some more space to the computed header size to amount for missing | |
588 // alignment requirements in our computation. | |
589 // Try to get kHeaderSize properly aligned on 32-bit and 64-bit machines. | |
590 static const size_t kHeaderSize = kMinHeaderSize + kIntSize; | |
591 | |
592 static const int kBodyOffset = | |
593 CODE_POINTER_ALIGN(kHeaderSize + Bitmap::kSize); | |
594 | |
595 // The start offset of the object area in a page. Aligned to both maps and | |
596 // code alignment to be suitable for both. Also aligned to 32 words because | |
597 // the marking bitmap is arranged in 32 bit chunks. | |
598 static const int kObjectStartAlignment = 32 * kPointerSize; | |
599 static const int kObjectStartOffset = | |
600 kBodyOffset - 1 + | |
601 (kObjectStartAlignment - (kBodyOffset - 1) % kObjectStartAlignment); | |
602 | |
603 size_t size() const { return size_; } | 612 size_t size() const { return size_; } |
604 | 613 |
605 void set_size(size_t size) { size_ = size; } | 614 void set_size(size_t size) { size_ = size; } |
606 | 615 |
607 void SetArea(Address area_start, Address area_end) { | 616 void SetArea(Address area_start, Address area_end) { |
608 area_start_ = area_start; | 617 area_start_ = area_start; |
609 area_end_ = area_end; | 618 area_end_ = area_end; |
610 } | 619 } |
611 | 620 |
612 Executability executable() { | 621 Executability executable() { |
613 return IsFlagSet(IS_EXECUTABLE) ? EXECUTABLE : NOT_EXECUTABLE; | 622 return IsFlagSet(IS_EXECUTABLE) ? EXECUTABLE : NOT_EXECUTABLE; |
614 } | 623 } |
615 | 624 |
616 bool InNewSpace() { | 625 bool InNewSpace() { |
617 return (flags_ & ((1 << IN_FROM_SPACE) | (1 << IN_TO_SPACE))) != 0; | 626 return (flags_ & ((1 << IN_FROM_SPACE) | (1 << IN_TO_SPACE))) != 0; |
618 } | 627 } |
619 | 628 |
620 bool InToSpace() { return IsFlagSet(IN_TO_SPACE); } | 629 bool InToSpace() { return IsFlagSet(IN_TO_SPACE); } |
621 | 630 |
622 bool InFromSpace() { return IsFlagSet(IN_FROM_SPACE); } | 631 bool InFromSpace() { return IsFlagSet(IN_FROM_SPACE); } |
623 | 632 |
624 // --------------------------------------------------------------------- | |
625 // Markbits support | 633 // Markbits support |
626 | 634 |
627 inline Bitmap* markbits() { | 635 inline Bitmap* markbits() { |
628 return Bitmap::FromAddress(address() + kHeaderSize); | 636 return Bitmap::FromAddress(address() + kHeaderSize); |
629 } | 637 } |
630 | 638 |
631 void PrintMarkbits() { markbits()->Print(); } | 639 void PrintMarkbits() { markbits()->Print(); } |
632 | 640 |
633 inline uint32_t AddressToMarkbitIndex(Address addr) { | 641 inline uint32_t AddressToMarkbitIndex(Address addr) { |
634 return static_cast<uint32_t>(addr - this->address()) >> kPointerSizeLog2; | 642 return static_cast<uint32_t>(addr - this->address()) >> kPointerSizeLog2; |
635 } | 643 } |
636 | 644 |
637 inline static uint32_t FastAddressToMarkbitIndex(Address addr) { | |
638 const intptr_t offset = reinterpret_cast<intptr_t>(addr) & kAlignmentMask; | |
639 | |
640 return static_cast<uint32_t>(offset) >> kPointerSizeLog2; | |
641 } | |
642 | |
643 inline Address MarkbitIndexToAddress(uint32_t index) { | 645 inline Address MarkbitIndexToAddress(uint32_t index) { |
644 return this->address() + (index << kPointerSizeLog2); | 646 return this->address() + (index << kPointerSizeLog2); |
645 } | 647 } |
646 | 648 |
647 void InsertAfter(MemoryChunk* other); | 649 void InsertAfter(MemoryChunk* other); |
648 void Unlink(); | 650 void Unlink(); |
649 | 651 |
650 inline Heap* heap() const { return heap_; } | 652 inline Heap* heap() const { return heap_; } |
651 | 653 |
652 static const int kFlagsOffset = kPointerSize; | |
653 | |
654 bool NeverEvacuate() { return IsFlagSet(NEVER_EVACUATE); } | 654 bool NeverEvacuate() { return IsFlagSet(NEVER_EVACUATE); } |
655 | 655 |
656 void MarkNeverEvacuate() { SetFlag(NEVER_EVACUATE); } | 656 void MarkNeverEvacuate() { SetFlag(NEVER_EVACUATE); } |
657 | 657 |
658 bool IsEvacuationCandidate() { | 658 bool IsEvacuationCandidate() { |
659 DCHECK(!(IsFlagSet(NEVER_EVACUATE) && IsFlagSet(EVACUATION_CANDIDATE))); | 659 DCHECK(!(IsFlagSet(NEVER_EVACUATE) && IsFlagSet(EVACUATION_CANDIDATE))); |
660 return IsFlagSet(EVACUATION_CANDIDATE); | 660 return IsFlagSet(EVACUATION_CANDIDATE); |
661 } | 661 } |
662 | 662 |
663 bool ShouldSkipEvacuationSlotRecording() { | 663 bool ShouldSkipEvacuationSlotRecording() { |
(...skipping 23 matching lines...) Expand all Loading... |
687 Address area_end() { return area_end_; } | 687 Address area_end() { return area_end_; } |
688 int area_size() { return static_cast<int>(area_end() - area_start()); } | 688 int area_size() { return static_cast<int>(area_end() - area_start()); } |
689 bool CommitArea(size_t requested); | 689 bool CommitArea(size_t requested); |
690 | 690 |
691 // Approximate amount of physical memory committed for this chunk. | 691 // Approximate amount of physical memory committed for this chunk. |
692 size_t CommittedPhysicalMemory() { return high_water_mark_.Value(); } | 692 size_t CommittedPhysicalMemory() { return high_water_mark_.Value(); } |
693 | 693 |
694 // Should be called when memory chunk is about to be freed. | 694 // Should be called when memory chunk is about to be freed. |
695 void ReleaseAllocatedMemory(); | 695 void ReleaseAllocatedMemory(); |
696 | 696 |
697 static inline void UpdateHighWaterMark(Address mark) { | 697 protected: |
698 if (mark == nullptr) return; | 698 static MemoryChunk* Initialize(Heap* heap, Address base, size_t size, |
699 // Need to subtract one from the mark because when a chunk is full the | 699 Address area_start, Address area_end, |
700 // top points to the next address after the chunk, which effectively belongs | 700 Executability executable, Space* owner); |
701 // to another chunk. See the comment to Page::FromAllocationTop. | |
702 MemoryChunk* chunk = MemoryChunk::FromAddress(mark - 1); | |
703 intptr_t new_mark = static_cast<intptr_t>(mark - chunk->address()); | |
704 intptr_t old_mark = 0; | |
705 do { | |
706 old_mark = chunk->high_water_mark_.Value(); | |
707 } while ((new_mark > old_mark) && | |
708 !chunk->high_water_mark_.TrySetValue(old_mark, new_mark)); | |
709 } | |
710 | 701 |
711 protected: | |
712 size_t size_; | 702 size_t size_; |
713 intptr_t flags_; | 703 intptr_t flags_; |
714 | 704 |
715 // Start and end of allocatable memory on this chunk. | 705 // Start and end of allocatable memory on this chunk. |
716 Address area_start_; | 706 Address area_start_; |
717 Address area_end_; | 707 Address area_end_; |
718 | 708 |
719 // If the chunk needs to remember its memory reservation, it is stored here. | 709 // If the chunk needs to remember its memory reservation, it is stored here. |
720 base::VirtualMemory reservation_; | 710 base::VirtualMemory reservation_; |
721 // The identity of the owning space. This is tagged as a failure pointer, but | 711 // The identity of the owning space. This is tagged as a failure pointer, but |
(...skipping 21 matching lines...) Expand all Loading... |
743 AtomicValue<ParallelCompactingState> parallel_compaction_; | 733 AtomicValue<ParallelCompactingState> parallel_compaction_; |
744 | 734 |
745 // PagedSpace free-list statistics. | 735 // PagedSpace free-list statistics. |
746 AtomicNumber<intptr_t> available_in_small_free_list_; | 736 AtomicNumber<intptr_t> available_in_small_free_list_; |
747 AtomicNumber<intptr_t> available_in_medium_free_list_; | 737 AtomicNumber<intptr_t> available_in_medium_free_list_; |
748 AtomicNumber<intptr_t> available_in_large_free_list_; | 738 AtomicNumber<intptr_t> available_in_large_free_list_; |
749 AtomicNumber<intptr_t> available_in_huge_free_list_; | 739 AtomicNumber<intptr_t> available_in_huge_free_list_; |
750 AtomicNumber<intptr_t> non_available_small_blocks_; | 740 AtomicNumber<intptr_t> non_available_small_blocks_; |
751 | 741 |
752 // next_chunk_ holds a pointer of type MemoryChunk | 742 // next_chunk_ holds a pointer of type MemoryChunk |
753 base::AtomicWord next_chunk_; | 743 AtomicValue<MemoryChunk*> next_chunk_; |
754 // prev_chunk_ holds a pointer of type MemoryChunk | 744 // prev_chunk_ holds a pointer of type MemoryChunk |
755 base::AtomicWord prev_chunk_; | 745 AtomicValue<MemoryChunk*> prev_chunk_; |
756 | |
757 static MemoryChunk* Initialize(Heap* heap, Address base, size_t size, | |
758 Address area_start, Address area_end, | |
759 Executability executable, Space* owner); | |
760 | 746 |
761 private: | 747 private: |
| 748 void InitializeReservedMemory() { reservation_.Reset(); } |
| 749 |
762 friend class MemoryAllocator; | 750 friend class MemoryAllocator; |
763 friend class MemoryChunkValidator; | 751 friend class MemoryChunkValidator; |
764 }; | 752 }; |
765 | 753 |
766 | 754 |
767 // ----------------------------------------------------------------------------- | 755 // ----------------------------------------------------------------------------- |
768 // A page is a memory chunk of a size 1MB. Large object pages may be larger. | 756 // A page is a memory chunk of a size 1MB. Large object pages may be larger. |
769 // | 757 // |
770 // The only way to get a page pointer is by calling factory methods: | 758 // The only way to get a page pointer is by calling factory methods: |
771 // Page* p = Page::FromAddress(addr); or | 759 // Page* p = Page::FromAddress(addr); or |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
870 #endif // DEBUG | 858 #endif // DEBUG |
871 | 859 |
872 friend class MemoryAllocator; | 860 friend class MemoryAllocator; |
873 }; | 861 }; |
874 | 862 |
875 | 863 |
876 class LargePage : public MemoryChunk { | 864 class LargePage : public MemoryChunk { |
877 public: | 865 public: |
878 HeapObject* GetObject() { return HeapObject::FromAddress(area_start()); } | 866 HeapObject* GetObject() { return HeapObject::FromAddress(area_start()); } |
879 | 867 |
880 inline LargePage* next_page() const { | 868 inline LargePage* next_page() { |
881 return static_cast<LargePage*>(next_chunk()); | 869 return static_cast<LargePage*>(next_chunk()); |
882 } | 870 } |
883 | 871 |
884 inline void set_next_page(LargePage* page) { set_next_chunk(page); } | 872 inline void set_next_page(LargePage* page) { set_next_chunk(page); } |
885 | 873 |
886 private: | 874 private: |
887 static inline LargePage* Initialize(Heap* heap, MemoryChunk* chunk); | 875 static inline LargePage* Initialize(Heap* heap, MemoryChunk* chunk); |
888 | 876 |
889 friend class MemoryAllocator; | 877 friend class MemoryAllocator; |
890 }; | 878 }; |
(...skipping 1219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2110 public: | 2098 public: |
2111 // GC related flags copied from from-space to to-space when | 2099 // GC related flags copied from from-space to to-space when |
2112 // flipping semispaces. | 2100 // flipping semispaces. |
2113 static const intptr_t kCopyOnFlipFlagsMask = | 2101 static const intptr_t kCopyOnFlipFlagsMask = |
2114 (1 << MemoryChunk::POINTERS_TO_HERE_ARE_INTERESTING) | | 2102 (1 << MemoryChunk::POINTERS_TO_HERE_ARE_INTERESTING) | |
2115 (1 << MemoryChunk::POINTERS_FROM_HERE_ARE_INTERESTING) | | 2103 (1 << MemoryChunk::POINTERS_FROM_HERE_ARE_INTERESTING) | |
2116 (1 << MemoryChunk::SCAN_ON_SCAVENGE); | 2104 (1 << MemoryChunk::SCAN_ON_SCAVENGE); |
2117 | 2105 |
2118 static const int kAreaSize = Page::kMaxRegularHeapObjectSize; | 2106 static const int kAreaSize = Page::kMaxRegularHeapObjectSize; |
2119 | 2107 |
2120 inline NewSpacePage* next_page() const { | 2108 inline NewSpacePage* next_page() { |
2121 return static_cast<NewSpacePage*>(next_chunk()); | 2109 return static_cast<NewSpacePage*>(next_chunk()); |
2122 } | 2110 } |
2123 | 2111 |
2124 inline void set_next_page(NewSpacePage* page) { set_next_chunk(page); } | 2112 inline void set_next_page(NewSpacePage* page) { set_next_chunk(page); } |
2125 | 2113 |
2126 inline NewSpacePage* prev_page() const { | 2114 inline NewSpacePage* prev_page() { |
2127 return static_cast<NewSpacePage*>(prev_chunk()); | 2115 return static_cast<NewSpacePage*>(prev_chunk()); |
2128 } | 2116 } |
2129 | 2117 |
2130 inline void set_prev_page(NewSpacePage* page) { set_prev_chunk(page); } | 2118 inline void set_prev_page(NewSpacePage* page) { set_prev_chunk(page); } |
2131 | 2119 |
2132 SemiSpace* semi_space() { return reinterpret_cast<SemiSpace*>(owner()); } | 2120 SemiSpace* semi_space() { return reinterpret_cast<SemiSpace*>(owner()); } |
2133 | 2121 |
2134 bool is_anchor() { return !this->InNewSpace(); } | 2122 bool is_anchor() { return !this->InNewSpace(); } |
2135 | 2123 |
2136 static bool IsAtStart(Address addr) { | 2124 static bool IsAtStart(Address addr) { |
(...skipping 840 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2977 count = 0; | 2965 count = 0; |
2978 } | 2966 } |
2979 // Must be small, since an iteration is used for lookup. | 2967 // Must be small, since an iteration is used for lookup. |
2980 static const int kMaxComments = 64; | 2968 static const int kMaxComments = 64; |
2981 }; | 2969 }; |
2982 #endif | 2970 #endif |
2983 } | 2971 } |
2984 } // namespace v8::internal | 2972 } // namespace v8::internal |
2985 | 2973 |
2986 #endif // V8_HEAP_SPACES_H_ | 2974 #endif // V8_HEAP_SPACES_H_ |
OLD | NEW |