| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 118 #endif | 118 #endif |
| 119 | 119 |
| 120 #if !ENABLE(ASSERT) && CPU(64BIT) | 120 #if !ENABLE(ASSERT) && CPU(64BIT) |
| 121 #define USE_4BYTE_HEADER_PADDING 1 | 121 #define USE_4BYTE_HEADER_PADDING 1 |
| 122 #else | 122 #else |
| 123 #define USE_4BYTE_HEADER_PADDING 0 | 123 #define USE_4BYTE_HEADER_PADDING 0 |
| 124 #endif | 124 #endif |
| 125 | 125 |
| 126 class CallbackStack; | 126 class CallbackStack; |
| 127 class FreePagePool; | 127 class FreePagePool; |
| 128 class NormalPageHeap; | 128 class NormalPageArena; |
| 129 class OrphanedPagePool; | 129 class OrphanedPagePool; |
| 130 class PageMemory; | 130 class PageMemory; |
| 131 class PageMemoryRegion; | 131 class PageMemoryRegion; |
| 132 class WebMemoryAllocatorDump; | 132 class WebMemoryAllocatorDump; |
| 133 | 133 |
| 134 // HeapObjectHeader is 4 byte (32 bit) that has the following layout: | 134 // HeapObjectHeader is 4 byte (32 bit) that has the following layout: |
| 135 // | 135 // |
| 136 // | gcInfoIndex (14 bit) | DOM mark bit (1 bit) | size (14 bit) | dead bit (1 b
it) | freed bit (1 bit) | mark bit (1 bit) | | 136 // | gcInfoIndex (14 bit) | DOM mark bit (1 bit) | size (14 bit) | dead bit (1 b
it) | freed bit (1 bit) | mark bit (1 bit) | |
| 137 // | 137 // |
| 138 // - For non-large objects, 14 bit is enough for |size| because the blink | 138 // - For non-large objects, 14 bit is enough for |size| because the blink |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 345 // | 345 // |
| 346 // - LargeObjectPage is a page that contains only one object. The object size | 346 // - LargeObjectPage is a page that contains only one object. The object size |
| 347 // is arbitrary. An object whose size is larger than |blinkPageSize| is stored | 347 // is arbitrary. An object whose size is larger than |blinkPageSize| is stored |
| 348 // as a single project in LargeObjectPage. | 348 // as a single project in LargeObjectPage. |
| 349 // | 349 // |
| 350 // Note: An object whose size is between |largeObjectSizeThreshold| and | 350 // Note: An object whose size is between |largeObjectSizeThreshold| and |
| 351 // |blinkPageSize| can go to either of NormalPage or LargeObjectPage. | 351 // |blinkPageSize| can go to either of NormalPage or LargeObjectPage. |
| 352 class BasePage { | 352 class BasePage { |
| 353 DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); | 353 DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); |
| 354 public: | 354 public: |
| 355 BasePage(PageMemory*, BaseHeap*); | 355 BasePage(PageMemory*, BaseArena*); |
| 356 virtual ~BasePage() { } | 356 virtual ~BasePage() { } |
| 357 | 357 |
| 358 void link(BasePage** previousNext) | 358 void link(BasePage** previousNext) |
| 359 { | 359 { |
| 360 m_next = *previousNext; | 360 m_next = *previousNext; |
| 361 *previousNext = this; | 361 *previousNext = this; |
| 362 } | 362 } |
| 363 void unlink(BasePage** previousNext) | 363 void unlink(BasePage** previousNext) |
| 364 { | 364 { |
| 365 *previousNext = m_next; | 365 *previousNext = m_next; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 401 | 401 |
| 402 virtual void takeSnapshot(WebMemoryAllocatorDump*, ThreadState::GCSnapshotIn
fo&, HeapSnapshotInfo&) = 0; | 402 virtual void takeSnapshot(WebMemoryAllocatorDump*, ThreadState::GCSnapshotIn
fo&, HeapSnapshotInfo&) = 0; |
| 403 #if ENABLE(ASSERT) | 403 #if ENABLE(ASSERT) |
| 404 virtual bool contains(Address) = 0; | 404 virtual bool contains(Address) = 0; |
| 405 #endif | 405 #endif |
| 406 virtual size_t size() = 0; | 406 virtual size_t size() = 0; |
| 407 virtual bool isLargeObjectPage() { return false; } | 407 virtual bool isLargeObjectPage() { return false; } |
| 408 | 408 |
| 409 Address address() { return reinterpret_cast<Address>(this); } | 409 Address address() { return reinterpret_cast<Address>(this); } |
| 410 PageMemory* storage() const { return m_storage; } | 410 PageMemory* storage() const { return m_storage; } |
| 411 BaseHeap* heap() const { return m_heap; } | 411 BaseArena* arena() const { return m_arena; } |
| 412 bool orphaned() { return !m_heap; } | 412 bool orphaned() { return !m_arena; } |
| 413 bool terminating() { return m_terminating; } | 413 bool terminating() { return m_terminating; } |
| 414 void setTerminating() { m_terminating = true; } | 414 void setTerminating() { m_terminating = true; } |
| 415 | 415 |
| 416 // Returns true if this page has been swept by the ongoing lazy sweep. | 416 // Returns true if this page has been swept by the ongoing lazy sweep. |
| 417 bool hasBeenSwept() const { return m_swept; } | 417 bool hasBeenSwept() const { return m_swept; } |
| 418 | 418 |
| 419 void markAsSwept() | 419 void markAsSwept() |
| 420 { | 420 { |
| 421 ASSERT(!m_swept); | 421 ASSERT(!m_swept); |
| 422 m_swept = true; | 422 m_swept = true; |
| 423 } | 423 } |
| 424 | 424 |
| 425 void markAsUnswept() | 425 void markAsUnswept() |
| 426 { | 426 { |
| 427 ASSERT(m_swept); | 427 ASSERT(m_swept); |
| 428 m_swept = false; | 428 m_swept = false; |
| 429 } | 429 } |
| 430 | 430 |
| 431 private: | 431 private: |
| 432 PageMemory* m_storage; | 432 PageMemory* m_storage; |
| 433 BaseHeap* m_heap; | 433 BaseArena* m_arena; |
| 434 BasePage* m_next; | 434 BasePage* m_next; |
| 435 // Whether the page is part of a terminating thread or not. | 435 // Whether the page is part of a terminating thread or not. |
| 436 bool m_terminating; | 436 bool m_terminating; |
| 437 | 437 |
| 438 // Track the sweeping state of a page. Set to true once | 438 // Track the sweeping state of a page. Set to true once |
| 439 // the lazy sweep completes has processed it. | 439 // the lazy sweep completes has processed it. |
| 440 // | 440 // |
| 441 // Set to false at the start of a sweep, true upon completion | 441 // Set to false at the start of a sweep, true upon completion |
| 442 // of lazy sweeping. | 442 // of lazy sweeping. |
| 443 bool m_swept; | 443 bool m_swept; |
| 444 friend class BaseHeap; | 444 friend class BaseArena; |
| 445 }; | 445 }; |
| 446 | 446 |
| 447 class NormalPage final : public BasePage { | 447 class NormalPage final : public BasePage { |
| 448 public: | 448 public: |
| 449 NormalPage(PageMemory*, BaseHeap*); | 449 NormalPage(PageMemory*, BaseArena*); |
| 450 | 450 |
| 451 Address payload() | 451 Address payload() |
| 452 { | 452 { |
| 453 return address() + pageHeaderSize(); | 453 return address() + pageHeaderSize(); |
| 454 } | 454 } |
| 455 size_t payloadSize() | 455 size_t payloadSize() |
| 456 { | 456 { |
| 457 return (blinkPagePayloadSize() - pageHeaderSize()) & ~allocationMask; | 457 return (blinkPagePayloadSize() - pageHeaderSize()) & ~allocationMask; |
| 458 } | 458 } |
| 459 Address payloadEnd() { return payload() + payloadSize(); } | 459 Address payloadEnd() { return payload() + payloadSize(); } |
| (...skipping 25 matching lines...) Expand all Loading... |
| 485 size_t size() override { return blinkPageSize; } | 485 size_t size() override { return blinkPageSize; } |
| 486 static size_t pageHeaderSize() | 486 static size_t pageHeaderSize() |
| 487 { | 487 { |
| 488 // Compute the amount of padding we have to add to a header to make | 488 // Compute the amount of padding we have to add to a header to make |
| 489 // the size of the header plus the padding a multiple of 8 bytes. | 489 // the size of the header plus the padding a multiple of 8 bytes. |
| 490 size_t paddingSize = (sizeof(NormalPage) + allocationGranularity - (size
of(HeapObjectHeader) % allocationGranularity)) % allocationGranularity; | 490 size_t paddingSize = (sizeof(NormalPage) + allocationGranularity - (size
of(HeapObjectHeader) % allocationGranularity)) % allocationGranularity; |
| 491 return sizeof(NormalPage) + paddingSize; | 491 return sizeof(NormalPage) + paddingSize; |
| 492 } | 492 } |
| 493 | 493 |
| 494 | 494 |
| 495 NormalPageHeap* heapForNormalPage(); | 495 NormalPageArena* heapForNormalPage(); |
| 496 | 496 |
| 497 private: | 497 private: |
| 498 HeapObjectHeader* findHeaderFromAddress(Address); | 498 HeapObjectHeader* findHeaderFromAddress(Address); |
| 499 void populateObjectStartBitMap(); | 499 void populateObjectStartBitMap(); |
| 500 | 500 |
| 501 bool m_objectStartBitMapComputed; | 501 bool m_objectStartBitMapComputed; |
| 502 uint8_t m_objectStartBitMap[reservedForObjectBitMap]; | 502 uint8_t m_objectStartBitMap[reservedForObjectBitMap]; |
| 503 }; | 503 }; |
| 504 | 504 |
| 505 // Large allocations are allocated as separate objects and linked in a list. | 505 // Large allocations are allocated as separate objects and linked in a list. |
| 506 // | 506 // |
| 507 // In order to use the same memory allocation routines for everything allocated | 507 // In order to use the same memory allocation routines for everything allocated |
| 508 // in the heap, large objects are considered heap pages containing only one | 508 // in the heap, large objects are considered heap pages containing only one |
| 509 // object. | 509 // object. |
| 510 class LargeObjectPage final : public BasePage { | 510 class LargeObjectPage final : public BasePage { |
| 511 public: | 511 public: |
| 512 LargeObjectPage(PageMemory*, BaseHeap*, size_t); | 512 LargeObjectPage(PageMemory*, BaseArena*, size_t); |
| 513 | 513 |
| 514 Address payload() { return heapObjectHeader()->payload(); } | 514 Address payload() { return heapObjectHeader()->payload(); } |
| 515 size_t payloadSize() { return m_payloadSize; } | 515 size_t payloadSize() { return m_payloadSize; } |
| 516 Address payloadEnd() { return payload() + payloadSize(); } | 516 Address payloadEnd() { return payload() + payloadSize(); } |
| 517 bool containedInObjectPayload(Address address) | 517 bool containedInObjectPayload(Address address) |
| 518 { | 518 { |
| 519 return payload() <= address && address < payloadEnd(); | 519 return payload() <= address && address < payloadEnd(); |
| 520 } | 520 } |
| 521 | 521 |
| 522 size_t objectPayloadSizeForTesting() override; | 522 size_t objectPayloadSizeForTesting() override; |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 639 static void zapFreedMemory(Address, size_t); | 639 static void zapFreedMemory(Address, size_t); |
| 640 static void checkFreedMemoryIsZapped(Address, size_t); | 640 static void checkFreedMemoryIsZapped(Address, size_t); |
| 641 #endif | 641 #endif |
| 642 | 642 |
| 643 private: | 643 private: |
| 644 int m_biggestFreeListIndex; | 644 int m_biggestFreeListIndex; |
| 645 | 645 |
| 646 // All FreeListEntries in the nth list have size >= 2^n. | 646 // All FreeListEntries in the nth list have size >= 2^n. |
| 647 FreeListEntry* m_freeLists[blinkPageSizeLog2]; | 647 FreeListEntry* m_freeLists[blinkPageSizeLog2]; |
| 648 | 648 |
| 649 friend class NormalPageHeap; | 649 friend class NormalPageArena; |
| 650 }; | 650 }; |
| 651 | 651 |
| 652 // Each thread has a number of thread heaps (e.g., Generic heaps, | 652 // Each thread has a number of thread heaps (e.g., Generic heaps, |
| 653 // typed heaps for Node, heaps for collection backings etc) | 653 // typed heaps for Node, heaps for collection backings etc) |
| 654 // and BaseHeap represents each thread heap. | 654 // and BaseArena represents each thread heap. |
| 655 // | 655 // |
| 656 // BaseHeap is a parent class of NormalPageHeap and LargeObjectHeap. | 656 // BaseArena is a parent class of NormalPageArena and LargeObjectArena. |
| 657 // NormalPageHeap represents a heap that contains NormalPages | 657 // NormalPageArena represents a heap that contains NormalPages |
| 658 // and LargeObjectHeap represents a heap that contains LargeObjectPages. | 658 // and LargeObjectArena represents a heap that contains LargeObjectPages. |
| 659 class PLATFORM_EXPORT BaseHeap { | 659 class PLATFORM_EXPORT BaseArena { |
| 660 USING_FAST_MALLOC(BaseHeap); | 660 USING_FAST_MALLOC(BaseArena); |
| 661 public: | 661 public: |
| 662 BaseHeap(ThreadState*, int); | 662 BaseArena(ThreadState*, int); |
| 663 virtual ~BaseHeap(); | 663 virtual ~BaseArena(); |
| 664 void cleanupPages(); | 664 void cleanupPages(); |
| 665 | 665 |
| 666 void takeSnapshot(const String& dumpBaseName, ThreadState::GCSnapshotInfo&); | 666 void takeSnapshot(const String& dumpBaseName, ThreadState::GCSnapshotInfo&); |
| 667 #if ENABLE(ASSERT) | 667 #if ENABLE(ASSERT) |
| 668 BasePage* findPageFromAddress(Address); | 668 BasePage* findPageFromAddress(Address); |
| 669 #endif | 669 #endif |
| 670 virtual void takeFreelistSnapshot(const String& dumpBaseName) { } | 670 virtual void takeFreelistSnapshot(const String& dumpBaseName) { } |
| 671 virtual void clearFreeLists() { } | 671 virtual void clearFreeLists() { } |
| 672 void makeConsistentForGC(); | 672 void makeConsistentForGC(); |
| 673 void makeConsistentForMutator(); | 673 void makeConsistentForMutator(); |
| 674 #if ENABLE(ASSERT) | 674 #if ENABLE(ASSERT) |
| 675 virtual bool isConsistentForGC() = 0; | 675 virtual bool isConsistentForGC() = 0; |
| 676 #endif | 676 #endif |
| 677 size_t objectPayloadSizeForTesting(); | 677 size_t objectPayloadSizeForTesting(); |
| 678 void prepareHeapForTermination(); | 678 void prepareHeapForTermination(); |
| 679 void prepareForSweep(); | 679 void prepareForSweep(); |
| 680 #if defined(ADDRESS_SANITIZER) | 680 #if defined(ADDRESS_SANITIZER) |
| 681 void poisonHeap(BlinkGC::ObjectsToPoison, BlinkGC::Poisoning); | 681 void poisonHeap(BlinkGC::ObjectsToPoison, BlinkGC::Poisoning); |
| 682 #endif | 682 #endif |
| 683 Address lazySweep(size_t, size_t gcInfoIndex); | 683 Address lazySweep(size_t, size_t gcInfoIndex); |
| 684 void sweepUnsweptPage(); | 684 void sweepUnsweptPage(); |
| 685 // Returns true if we have swept all pages within the deadline. | 685 // Returns true if we have swept all pages within the deadline. |
| 686 // Returns false otherwise. | 686 // Returns false otherwise. |
| 687 bool lazySweepWithDeadline(double deadlineSeconds); | 687 bool lazySweepWithDeadline(double deadlineSeconds); |
| 688 void completeSweep(); | 688 void completeSweep(); |
| 689 | 689 |
| 690 ThreadState* threadState() { return m_threadState; } | 690 ThreadState* threadState() { return m_threadState; } |
| 691 int heapIndex() const { return m_index; } | 691 int arenaIndex() const { return m_index; } |
| 692 | 692 |
| 693 protected: | 693 protected: |
| 694 BasePage* m_firstPage; | 694 BasePage* m_firstPage; |
| 695 BasePage* m_firstUnsweptPage; | 695 BasePage* m_firstUnsweptPage; |
| 696 | 696 |
| 697 private: | 697 private: |
| 698 virtual Address lazySweepPages(size_t, size_t gcInfoIndex) = 0; | 698 virtual Address lazySweepPages(size_t, size_t gcInfoIndex) = 0; |
| 699 | 699 |
| 700 ThreadState* m_threadState; | 700 ThreadState* m_threadState; |
| 701 | 701 |
| 702 // Index into the page pools. This is used to ensure that the pages of the | 702 // Index into the page pools. This is used to ensure that the pages of the |
| 703 // same type go into the correct page pool and thus avoid type confusion. | 703 // same type go into the correct page pool and thus avoid type confusion. |
| 704 int m_index; | 704 int m_index; |
| 705 }; | 705 }; |
| 706 | 706 |
| 707 class PLATFORM_EXPORT NormalPageHeap final : public BaseHeap { | 707 class PLATFORM_EXPORT NormalPageArena final : public BaseArena { |
| 708 public: | 708 public: |
| 709 NormalPageHeap(ThreadState*, int); | 709 NormalPageArena(ThreadState*, int); |
| 710 void addToFreeList(Address address, size_t size) | 710 void addToFreeList(Address address, size_t size) |
| 711 { | 711 { |
| 712 ASSERT(findPageFromAddress(address)); | 712 ASSERT(findPageFromAddress(address)); |
| 713 ASSERT(findPageFromAddress(address + size - 1)); | 713 ASSERT(findPageFromAddress(address + size - 1)); |
| 714 m_freeList.addToFreeList(address, size); | 714 m_freeList.addToFreeList(address, size); |
| 715 } | 715 } |
| 716 void clearFreeLists() override; | 716 void clearFreeLists() override; |
| 717 #if ENABLE(ASSERT) | 717 #if ENABLE(ASSERT) |
| 718 bool isConsistentForGC() override; | 718 bool isConsistentForGC() override; |
| 719 bool pagesToBeSweptContains(Address); | 719 bool pagesToBeSweptContains(Address); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 752 | 752 |
| 753 FreeList m_freeList; | 753 FreeList m_freeList; |
| 754 Address m_currentAllocationPoint; | 754 Address m_currentAllocationPoint; |
| 755 size_t m_remainingAllocationSize; | 755 size_t m_remainingAllocationSize; |
| 756 size_t m_lastRemainingAllocationSize; | 756 size_t m_lastRemainingAllocationSize; |
| 757 | 757 |
| 758 // The size of promptly freed objects in the heap. | 758 // The size of promptly freed objects in the heap. |
| 759 size_t m_promptlyFreedSize; | 759 size_t m_promptlyFreedSize; |
| 760 }; | 760 }; |
| 761 | 761 |
| 762 class LargeObjectHeap final : public BaseHeap { | 762 class LargeObjectArena final : public BaseArena { |
| 763 public: | 763 public: |
| 764 LargeObjectHeap(ThreadState*, int); | 764 LargeObjectArena(ThreadState*, int); |
| 765 Address allocateLargeObjectPage(size_t, size_t gcInfoIndex); | 765 Address allocateLargeObjectPage(size_t, size_t gcInfoIndex); |
| 766 void freeLargeObjectPage(LargeObjectPage*); | 766 void freeLargeObjectPage(LargeObjectPage*); |
| 767 #if ENABLE(ASSERT) | 767 #if ENABLE(ASSERT) |
| 768 bool isConsistentForGC() override { return true; } | 768 bool isConsistentForGC() override { return true; } |
| 769 #endif | 769 #endif |
| 770 private: | 770 private: |
| 771 Address doAllocateLargeObjectPage(size_t, size_t gcInfoIndex); | 771 Address doAllocateLargeObjectPage(size_t, size_t gcInfoIndex); |
| 772 Address lazySweepPages(size_t, size_t gcInfoIndex) override; | 772 Address lazySweepPages(size_t, size_t gcInfoIndex) override; |
| 773 }; | 773 }; |
| 774 | 774 |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 865 } | 865 } |
| 866 | 866 |
| 867 NO_SANITIZE_ADDRESS inline | 867 NO_SANITIZE_ADDRESS inline |
| 868 void HeapObjectHeader::markDead() | 868 void HeapObjectHeader::markDead() |
| 869 { | 869 { |
| 870 ASSERT(checkHeader()); | 870 ASSERT(checkHeader()); |
| 871 ASSERT(!isMarked()); | 871 ASSERT(!isMarked()); |
| 872 m_encoded |= headerDeadBitMask; | 872 m_encoded |= headerDeadBitMask; |
| 873 } | 873 } |
| 874 | 874 |
| 875 inline Address NormalPageHeap::allocateObject(size_t allocationSize, size_t gcIn
foIndex) | 875 inline Address NormalPageArena::allocateObject(size_t allocationSize, size_t gcI
nfoIndex) |
| 876 { | 876 { |
| 877 if (LIKELY(allocationSize <= m_remainingAllocationSize)) { | 877 if (LIKELY(allocationSize <= m_remainingAllocationSize)) { |
| 878 Address headerAddress = m_currentAllocationPoint; | 878 Address headerAddress = m_currentAllocationPoint; |
| 879 m_currentAllocationPoint += allocationSize; | 879 m_currentAllocationPoint += allocationSize; |
| 880 m_remainingAllocationSize -= allocationSize; | 880 m_remainingAllocationSize -= allocationSize; |
| 881 ASSERT(gcInfoIndex > 0); | 881 ASSERT(gcInfoIndex > 0); |
| 882 new (NotNull, headerAddress) HeapObjectHeader(allocationSize, gcInfoInde
x); | 882 new (NotNull, headerAddress) HeapObjectHeader(allocationSize, gcInfoInde
x); |
| 883 Address result = headerAddress + sizeof(HeapObjectHeader); | 883 Address result = headerAddress + sizeof(HeapObjectHeader); |
| 884 ASSERT(!(reinterpret_cast<uintptr_t>(result) & allocationMask)); | 884 ASSERT(!(reinterpret_cast<uintptr_t>(result) & allocationMask)); |
| 885 | 885 |
| 886 SET_MEMORY_ACCESSIBLE(result, allocationSize - sizeof(HeapObjectHeader))
; | 886 SET_MEMORY_ACCESSIBLE(result, allocationSize - sizeof(HeapObjectHeader))
; |
| 887 ASSERT(findPageFromAddress(headerAddress + allocationSize - 1)); | 887 ASSERT(findPageFromAddress(headerAddress + allocationSize - 1)); |
| 888 return result; | 888 return result; |
| 889 } | 889 } |
| 890 return outOfLineAllocate(allocationSize, gcInfoIndex); | 890 return outOfLineAllocate(allocationSize, gcInfoIndex); |
| 891 } | 891 } |
| 892 | 892 |
| 893 } // namespace blink | 893 } // namespace blink |
| 894 | 894 |
| 895 #endif // HeapPage_h | 895 #endif // HeapPage_h |
| OLD | NEW |