| 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 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 92 void HeapObjectHeader::zapMagic() | 92 void HeapObjectHeader::zapMagic() |
| 93 { | 93 { |
| 94 ASSERT(checkHeader()); | 94 ASSERT(checkHeader()); |
| 95 m_magic = zappedMagic; | 95 m_magic = zappedMagic; |
| 96 } | 96 } |
| 97 #endif | 97 #endif |
| 98 | 98 |
| 99 void HeapObjectHeader::finalize(Address object, size_t objectSize) | 99 void HeapObjectHeader::finalize(Address object, size_t objectSize) |
| 100 { | 100 { |
| 101 HeapAllocHooks::freeHookIfEnabled(object); | 101 HeapAllocHooks::freeHookIfEnabled(object); |
| 102 const GCInfo* gcInfo = Heap::gcInfo(gcInfoIndex()); | 102 const GCInfo* gcInfo = ThreadHeap::gcInfo(gcInfoIndex()); |
| 103 if (gcInfo->hasFinalizer()) | 103 if (gcInfo->hasFinalizer()) |
| 104 gcInfo->m_finalize(object); | 104 gcInfo->m_finalize(object); |
| 105 | 105 |
| 106 ASAN_RETIRE_CONTAINER_ANNOTATION(object, objectSize); | 106 ASAN_RETIRE_CONTAINER_ANNOTATION(object, objectSize); |
| 107 } | 107 } |
| 108 | 108 |
| 109 BaseArena::BaseArena(ThreadState* state, int index) | 109 BaseArena::BaseArena(ThreadState* state, int index) |
| 110 : m_firstPage(nullptr) | 110 : m_firstPage(nullptr) |
| 111 , m_firstUnsweptPage(nullptr) | 111 , m_firstUnsweptPage(nullptr) |
| 112 , m_threadState(state) | 112 , m_threadState(state) |
| 113 , m_index(index) | 113 , m_index(index) |
| 114 { | 114 { |
| 115 } | 115 } |
| 116 | 116 |
| 117 BaseArena::~BaseArena() | 117 BaseArena::~BaseArena() |
| 118 { | 118 { |
| 119 ASSERT(!m_firstPage); | 119 ASSERT(!m_firstPage); |
| 120 ASSERT(!m_firstUnsweptPage); | 120 ASSERT(!m_firstUnsweptPage); |
| 121 } | 121 } |
| 122 | 122 |
| 123 void BaseArena::cleanupPages() | 123 void BaseArena::cleanupPages() |
| 124 { | 124 { |
| 125 clearFreeLists(); | 125 clearFreeLists(); |
| 126 | 126 |
| 127 ASSERT(!m_firstUnsweptPage); | 127 ASSERT(!m_firstUnsweptPage); |
| 128 // Add the BaseArena's pages to the orphanedPagePool. | 128 // Add the BaseArena's pages to the orphanedPagePool. |
| 129 for (BasePage* page = m_firstPage; page; page = page->next()) { | 129 for (BasePage* page = m_firstPage; page; page = page->next()) { |
| 130 Heap::decreaseAllocatedSpace(page->size()); | 130 getThreadState()->heap().heapStats().decreaseAllocatedSpace(page->size()
); |
| 131 Heap::getOrphanedPagePool()->addOrphanedPage(arenaIndex(), page); | 131 getThreadState()->heap().getOrphanedPagePool()->addOrphanedPage(arenaInd
ex(), page); |
| 132 } | 132 } |
| 133 m_firstPage = nullptr; | 133 m_firstPage = nullptr; |
| 134 } | 134 } |
| 135 | 135 |
| 136 void BaseArena::takeSnapshot(const String& dumpBaseName, ThreadState::GCSnapshot
Info& info) | 136 void BaseArena::takeSnapshot(const String& dumpBaseName, ThreadState::GCSnapshot
Info& info) |
| 137 { | 137 { |
| 138 // |dumpBaseName| at this point is "blink_gc/thread_X/heaps/HeapName" | 138 // |dumpBaseName| at this point is "blink_gc/thread_X/heaps/HeapName" |
| 139 WebMemoryAllocatorDump* allocatorDump = BlinkGCMemoryDumpProvider::instance(
)->createMemoryAllocatorDumpForCurrentGC(dumpBaseName); | 139 WebMemoryAllocatorDump* allocatorDump = BlinkGCMemoryDumpProvider::instance(
)->createMemoryAllocatorDumpForCurrentGC(dumpBaseName); |
| 140 size_t pageCount = 0; | 140 size_t pageCount = 0; |
| 141 BasePage::HeapSnapshotInfo heapInfo; | 141 BasePage::HeapSnapshotInfo heapInfo; |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 276 if (getThreadState()->sweepForbidden()) | 276 if (getThreadState()->sweepForbidden()) |
| 277 return nullptr; | 277 return nullptr; |
| 278 | 278 |
| 279 TRACE_EVENT0("blink_gc", "BaseArena::lazySweepPages"); | 279 TRACE_EVENT0("blink_gc", "BaseArena::lazySweepPages"); |
| 280 ThreadState::SweepForbiddenScope sweepForbidden(getThreadState()); | 280 ThreadState::SweepForbiddenScope sweepForbidden(getThreadState()); |
| 281 ScriptForbiddenIfMainThreadScope scriptForbidden; | 281 ScriptForbiddenIfMainThreadScope scriptForbidden; |
| 282 | 282 |
| 283 double startTime = WTF::currentTimeMS(); | 283 double startTime = WTF::currentTimeMS(); |
| 284 Address result = lazySweepPages(allocationSize, gcInfoIndex); | 284 Address result = lazySweepPages(allocationSize, gcInfoIndex); |
| 285 getThreadState()->accumulateSweepingTime(WTF::currentTimeMS() - startTime); | 285 getThreadState()->accumulateSweepingTime(WTF::currentTimeMS() - startTime); |
| 286 Heap::reportMemoryUsageForTracing(); | 286 ThreadHeap::reportMemoryUsageForTracing(); |
| 287 | 287 |
| 288 return result; | 288 return result; |
| 289 } | 289 } |
| 290 | 290 |
| 291 void BaseArena::sweepUnsweptPage() | 291 void BaseArena::sweepUnsweptPage() |
| 292 { | 292 { |
| 293 BasePage* page = m_firstUnsweptPage; | 293 BasePage* page = m_firstUnsweptPage; |
| 294 if (page->isEmpty()) { | 294 if (page->isEmpty()) { |
| 295 page->unlink(&m_firstUnsweptPage); | 295 page->unlink(&m_firstUnsweptPage); |
| 296 page->removeFromHeap(); | 296 page->removeFromHeap(); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 314 RELEASE_ASSERT(getThreadState()->isSweepingInProgress()); | 314 RELEASE_ASSERT(getThreadState()->isSweepingInProgress()); |
| 315 ASSERT(getThreadState()->sweepForbidden()); | 315 ASSERT(getThreadState()->sweepForbidden()); |
| 316 ASSERT(!getThreadState()->isMainThread() || ScriptForbiddenScope::isScriptFo
rbidden()); | 316 ASSERT(!getThreadState()->isMainThread() || ScriptForbiddenScope::isScriptFo
rbidden()); |
| 317 | 317 |
| 318 int pageCount = 1; | 318 int pageCount = 1; |
| 319 while (m_firstUnsweptPage) { | 319 while (m_firstUnsweptPage) { |
| 320 sweepUnsweptPage(); | 320 sweepUnsweptPage(); |
| 321 if (pageCount % deadlineCheckInterval == 0) { | 321 if (pageCount % deadlineCheckInterval == 0) { |
| 322 if (deadlineSeconds <= monotonicallyIncreasingTime()) { | 322 if (deadlineSeconds <= monotonicallyIncreasingTime()) { |
| 323 // Deadline has come. | 323 // Deadline has come. |
| 324 Heap::reportMemoryUsageForTracing(); | 324 ThreadHeap::reportMemoryUsageForTracing(); |
| 325 return !m_firstUnsweptPage; | 325 return !m_firstUnsweptPage; |
| 326 } | 326 } |
| 327 } | 327 } |
| 328 pageCount++; | 328 pageCount++; |
| 329 } | 329 } |
| 330 Heap::reportMemoryUsageForTracing(); | 330 ThreadHeap::reportMemoryUsageForTracing(); |
| 331 return true; | 331 return true; |
| 332 } | 332 } |
| 333 | 333 |
| 334 void BaseArena::completeSweep() | 334 void BaseArena::completeSweep() |
| 335 { | 335 { |
| 336 RELEASE_ASSERT(getThreadState()->isSweepingInProgress()); | 336 RELEASE_ASSERT(getThreadState()->isSweepingInProgress()); |
| 337 ASSERT(getThreadState()->sweepForbidden()); | 337 ASSERT(getThreadState()->sweepForbidden()); |
| 338 ASSERT(!getThreadState()->isMainThread() || ScriptForbiddenScope::isScriptFo
rbidden()); | 338 ASSERT(!getThreadState()->isMainThread() || ScriptForbiddenScope::isScriptFo
rbidden()); |
| 339 | 339 |
| 340 while (m_firstUnsweptPage) { | 340 while (m_firstUnsweptPage) { |
| 341 sweepUnsweptPage(); | 341 sweepUnsweptPage(); |
| 342 } | 342 } |
| 343 Heap::reportMemoryUsageForTracing(); | 343 ThreadHeap::reportMemoryUsageForTracing(); |
| 344 } | 344 } |
| 345 | 345 |
| 346 NormalPageArena::NormalPageArena(ThreadState* state, int index) | 346 NormalPageArena::NormalPageArena(ThreadState* state, int index) |
| 347 : BaseArena(state, index) | 347 : BaseArena(state, index) |
| 348 , m_currentAllocationPoint(nullptr) | 348 , m_currentAllocationPoint(nullptr) |
| 349 , m_remainingAllocationSize(0) | 349 , m_remainingAllocationSize(0) |
| 350 , m_lastRemainingAllocationSize(0) | 350 , m_lastRemainingAllocationSize(0) |
| 351 , m_promptlyFreedSize(0) | 351 , m_promptlyFreedSize(0) |
| 352 { | 352 { |
| 353 clearFreeLists(); | 353 clearFreeLists(); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 392 if (m_freeList.takeSnapshot(dumpName)) { | 392 if (m_freeList.takeSnapshot(dumpName)) { |
| 393 WebMemoryAllocatorDump* bucketsDump = BlinkGCMemoryDumpProvider::instanc
e()->createMemoryAllocatorDumpForCurrentGC(dumpName + "/buckets"); | 393 WebMemoryAllocatorDump* bucketsDump = BlinkGCMemoryDumpProvider::instanc
e()->createMemoryAllocatorDumpForCurrentGC(dumpName + "/buckets"); |
| 394 WebMemoryAllocatorDump* pagesDump = BlinkGCMemoryDumpProvider::instance(
)->createMemoryAllocatorDumpForCurrentGC(dumpName + "/pages"); | 394 WebMemoryAllocatorDump* pagesDump = BlinkGCMemoryDumpProvider::instance(
)->createMemoryAllocatorDumpForCurrentGC(dumpName + "/pages"); |
| 395 BlinkGCMemoryDumpProvider::instance()->currentProcessMemoryDump()->addOw
nershipEdge(pagesDump->guid(), bucketsDump->guid()); | 395 BlinkGCMemoryDumpProvider::instance()->currentProcessMemoryDump()->addOw
nershipEdge(pagesDump->guid(), bucketsDump->guid()); |
| 396 } | 396 } |
| 397 } | 397 } |
| 398 | 398 |
| 399 void NormalPageArena::allocatePage() | 399 void NormalPageArena::allocatePage() |
| 400 { | 400 { |
| 401 getThreadState()->shouldFlushHeapDoesNotContainCache(); | 401 getThreadState()->shouldFlushHeapDoesNotContainCache(); |
| 402 PageMemory* pageMemory = Heap::getFreePagePool()->takeFreePage(arenaIndex())
; | 402 PageMemory* pageMemory = getThreadState()->heap().getFreePagePool()->takeFre
ePage(arenaIndex()); |
| 403 | 403 |
| 404 if (!pageMemory) { | 404 if (!pageMemory) { |
| 405 // Allocate a memory region for blinkPagesPerRegion pages that | 405 // Allocate a memory region for blinkPagesPerRegion pages that |
| 406 // will each have the following layout. | 406 // will each have the following layout. |
| 407 // | 407 // |
| 408 // [ guard os page | ... payload ... | guard os page ] | 408 // [ guard os page | ... payload ... | guard os page ] |
| 409 // ^---{ aligned to blink page size } | 409 // ^---{ aligned to blink page size } |
| 410 PageMemoryRegion* region = PageMemoryRegion::allocateNormalPages(Heap::g
etRegionTree()); | 410 PageMemoryRegion* region = PageMemoryRegion::allocateNormalPages(getThre
adState()->heap().getRegionTree()); |
| 411 | 411 |
| 412 // Setup the PageMemory object for each of the pages in the region. | 412 // Setup the PageMemory object for each of the pages in the region. |
| 413 for (size_t i = 0; i < blinkPagesPerRegion; ++i) { | 413 for (size_t i = 0; i < blinkPagesPerRegion; ++i) { |
| 414 PageMemory* memory = PageMemory::setupPageMemoryInRegion(region, i *
blinkPageSize, blinkPagePayloadSize()); | 414 PageMemory* memory = PageMemory::setupPageMemoryInRegion(region, i *
blinkPageSize, blinkPagePayloadSize()); |
| 415 // Take the first possible page ensuring that this thread actually | 415 // Take the first possible page ensuring that this thread actually |
| 416 // gets a page and add the rest to the page pool. | 416 // gets a page and add the rest to the page pool. |
| 417 if (!pageMemory) { | 417 if (!pageMemory) { |
| 418 bool result = memory->commit(); | 418 bool result = memory->commit(); |
| 419 // If you hit the ASSERT, it will mean that you're hitting | 419 // If you hit the ASSERT, it will mean that you're hitting |
| 420 // the limit of the number of mmapped regions OS can support | 420 // the limit of the number of mmapped regions OS can support |
| 421 // (e.g., /proc/sys/vm/max_map_count in Linux). | 421 // (e.g., /proc/sys/vm/max_map_count in Linux). |
| 422 RELEASE_ASSERT(result); | 422 RELEASE_ASSERT(result); |
| 423 pageMemory = memory; | 423 pageMemory = memory; |
| 424 } else { | 424 } else { |
| 425 Heap::getFreePagePool()->addFreePage(arenaIndex(), memory); | 425 getThreadState()->heap().getFreePagePool()->addFreePage(arenaInd
ex(), memory); |
| 426 } | 426 } |
| 427 } | 427 } |
| 428 } | 428 } |
| 429 | 429 |
| 430 NormalPage* page = new (pageMemory->writableStart()) NormalPage(pageMemory,
this); | 430 NormalPage* page = new (pageMemory->writableStart()) NormalPage(pageMemory,
this); |
| 431 page->link(&m_firstPage); | 431 page->link(&m_firstPage); |
| 432 | 432 |
| 433 Heap::increaseAllocatedSpace(page->size()); | 433 getThreadState()->heap().heapStats().increaseAllocatedSpace(page->size()); |
| 434 #if ENABLE(ASSERT) || defined(LEAK_SANITIZER) || defined(ADDRESS_SANITIZER) | 434 #if ENABLE(ASSERT) || defined(LEAK_SANITIZER) || defined(ADDRESS_SANITIZER) |
| 435 // Allow the following addToFreeList() to add the newly allocated memory | 435 // Allow the following addToFreeList() to add the newly allocated memory |
| 436 // to the free list. | 436 // to the free list. |
| 437 ASAN_UNPOISON_MEMORY_REGION(page->payload(), page->payloadSize()); | 437 ASAN_UNPOISON_MEMORY_REGION(page->payload(), page->payloadSize()); |
| 438 Address address = page->payload(); | 438 Address address = page->payload(); |
| 439 for (size_t i = 0; i < page->payloadSize(); i++) | 439 for (size_t i = 0; i < page->payloadSize(); i++) |
| 440 address[i] = reuseAllowedZapValue; | 440 address[i] = reuseAllowedZapValue; |
| 441 ASAN_POISON_MEMORY_REGION(page->payload(), page->payloadSize()); | 441 ASAN_POISON_MEMORY_REGION(page->payload(), page->payloadSize()); |
| 442 #endif | 442 #endif |
| 443 addToFreeList(page->payload(), page->payloadSize()); | 443 addToFreeList(page->payload(), page->payloadSize()); |
| 444 } | 444 } |
| 445 | 445 |
| 446 void NormalPageArena::freePage(NormalPage* page) | 446 void NormalPageArena::freePage(NormalPage* page) |
| 447 { | 447 { |
| 448 Heap::decreaseAllocatedSpace(page->size()); | 448 getThreadState()->heap().heapStats().decreaseAllocatedSpace(page->size()); |
| 449 | 449 |
| 450 if (page->terminating()) { | 450 if (page->terminating()) { |
| 451 // The thread is shutting down and this page is being removed as a part | 451 // The thread is shutting down and this page is being removed as a part |
| 452 // of the thread local GC. In that case the object could be traced in | 452 // of the thread local GC. In that case the object could be traced in |
| 453 // the next global GC if there is a dangling pointer from a live thread | 453 // the next global GC if there is a dangling pointer from a live thread |
| 454 // heap to this dead thread heap. To guard against this, we put the | 454 // heap to this dead thread heap. To guard against this, we put the |
| 455 // page into the orphaned page pool and zap the page memory. This | 455 // page into the orphaned page pool and zap the page memory. This |
| 456 // ensures that tracing the dangling pointer in the next global GC just | 456 // ensures that tracing the dangling pointer in the next global GC just |
| 457 // crashes instead of causing use-after-frees. After the next global | 457 // crashes instead of causing use-after-frees. After the next global |
| 458 // GC, the orphaned pages are removed. | 458 // GC, the orphaned pages are removed. |
| 459 Heap::getOrphanedPagePool()->addOrphanedPage(arenaIndex(), page); | 459 getThreadState()->heap().getOrphanedPagePool()->addOrphanedPage(arenaInd
ex(), page); |
| 460 } else { | 460 } else { |
| 461 PageMemory* memory = page->storage(); | 461 PageMemory* memory = page->storage(); |
| 462 page->~NormalPage(); | 462 page->~NormalPage(); |
| 463 Heap::getFreePagePool()->addFreePage(arenaIndex(), memory); | 463 getThreadState()->heap().getFreePagePool()->addFreePage(arenaIndex(), me
mory); |
| 464 } | 464 } |
| 465 } | 465 } |
| 466 | 466 |
| 467 bool NormalPageArena::coalesce() | 467 bool NormalPageArena::coalesce() |
| 468 { | 468 { |
| 469 // Don't coalesce arenas if there are not enough promptly freed entries | 469 // Don't coalesce arenas if there are not enough promptly freed entries |
| 470 // to be coalesced. | 470 // to be coalesced. |
| 471 // | 471 // |
| 472 // FIXME: This threshold is determined just to optimize blink_perf | 472 // FIXME: This threshold is determined just to optimize blink_perf |
| 473 // benchmarks. Coalescing is very sensitive to the threashold and | 473 // benchmarks. Coalescing is very sensitive to the threashold and |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 559 } | 559 } |
| 560 | 560 |
| 561 bool NormalPageArena::expandObject(HeapObjectHeader* header, size_t newSize) | 561 bool NormalPageArena::expandObject(HeapObjectHeader* header, size_t newSize) |
| 562 { | 562 { |
| 563 // It's possible that Vector requests a smaller expanded size because | 563 // It's possible that Vector requests a smaller expanded size because |
| 564 // Vector::shrinkCapacity can set a capacity smaller than the actual payload | 564 // Vector::shrinkCapacity can set a capacity smaller than the actual payload |
| 565 // size. | 565 // size. |
| 566 ASSERT(header->checkHeader()); | 566 ASSERT(header->checkHeader()); |
| 567 if (header->payloadSize() >= newSize) | 567 if (header->payloadSize() >= newSize) |
| 568 return true; | 568 return true; |
| 569 size_t allocationSize = Heap::allocationSizeFromSize(newSize); | 569 size_t allocationSize = ThreadHeap::allocationSizeFromSize(newSize); |
| 570 ASSERT(allocationSize > header->size()); | 570 ASSERT(allocationSize > header->size()); |
| 571 size_t expandSize = allocationSize - header->size(); | 571 size_t expandSize = allocationSize - header->size(); |
| 572 if (isObjectAllocatedAtAllocationPoint(header) && expandSize <= m_remainingA
llocationSize) { | 572 if (isObjectAllocatedAtAllocationPoint(header) && expandSize <= m_remainingA
llocationSize) { |
| 573 m_currentAllocationPoint += expandSize; | 573 m_currentAllocationPoint += expandSize; |
| 574 ASSERT(m_remainingAllocationSize >= expandSize); | 574 ASSERT(m_remainingAllocationSize >= expandSize); |
| 575 setRemainingAllocationSize(m_remainingAllocationSize - expandSize); | 575 setRemainingAllocationSize(m_remainingAllocationSize - expandSize); |
| 576 // Unpoison the memory used for the object (payload). | 576 // Unpoison the memory used for the object (payload). |
| 577 SET_MEMORY_ACCESSIBLE(header->payloadEnd(), expandSize); | 577 SET_MEMORY_ACCESSIBLE(header->payloadEnd(), expandSize); |
| 578 header->setSize(allocationSize); | 578 header->setSize(allocationSize); |
| 579 ASSERT(findPageFromAddress(header->payloadEnd() - 1)); | 579 ASSERT(findPageFromAddress(header->payloadEnd() - 1)); |
| 580 return true; | 580 return true; |
| 581 } | 581 } |
| 582 return false; | 582 return false; |
| 583 } | 583 } |
| 584 | 584 |
| 585 bool NormalPageArena::shrinkObject(HeapObjectHeader* header, size_t newSize) | 585 bool NormalPageArena::shrinkObject(HeapObjectHeader* header, size_t newSize) |
| 586 { | 586 { |
| 587 ASSERT(header->checkHeader()); | 587 ASSERT(header->checkHeader()); |
| 588 ASSERT(header->payloadSize() > newSize); | 588 ASSERT(header->payloadSize() > newSize); |
| 589 size_t allocationSize = Heap::allocationSizeFromSize(newSize); | 589 size_t allocationSize = ThreadHeap::allocationSizeFromSize(newSize); |
| 590 ASSERT(header->size() > allocationSize); | 590 ASSERT(header->size() > allocationSize); |
| 591 size_t shrinkSize = header->size() - allocationSize; | 591 size_t shrinkSize = header->size() - allocationSize; |
| 592 if (isObjectAllocatedAtAllocationPoint(header)) { | 592 if (isObjectAllocatedAtAllocationPoint(header)) { |
| 593 m_currentAllocationPoint -= shrinkSize; | 593 m_currentAllocationPoint -= shrinkSize; |
| 594 setRemainingAllocationSize(m_remainingAllocationSize + shrinkSize); | 594 setRemainingAllocationSize(m_remainingAllocationSize + shrinkSize); |
| 595 SET_MEMORY_INACCESSIBLE(m_currentAllocationPoint, shrinkSize); | 595 SET_MEMORY_INACCESSIBLE(m_currentAllocationPoint, shrinkSize); |
| 596 header->setSize(allocationSize); | 596 header->setSize(allocationSize); |
| 597 return true; | 597 return true; |
| 598 } | 598 } |
| 599 ASSERT(shrinkSize >= sizeof(HeapObjectHeader)); | 599 ASSERT(shrinkSize >= sizeof(HeapObjectHeader)); |
| (...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 790 Address LargeObjectArena::doAllocateLargeObjectPage(size_t allocationSize, size_
t gcInfoIndex) | 790 Address LargeObjectArena::doAllocateLargeObjectPage(size_t allocationSize, size_
t gcInfoIndex) |
| 791 { | 791 { |
| 792 size_t largeObjectSize = LargeObjectPage::pageHeaderSize() + allocationSize; | 792 size_t largeObjectSize = LargeObjectPage::pageHeaderSize() + allocationSize; |
| 793 // If ASan is supported we add allocationGranularity bytes to the allocated | 793 // If ASan is supported we add allocationGranularity bytes to the allocated |
| 794 // space and poison that to detect overflows | 794 // space and poison that to detect overflows |
| 795 #if defined(ADDRESS_SANITIZER) | 795 #if defined(ADDRESS_SANITIZER) |
| 796 largeObjectSize += allocationGranularity; | 796 largeObjectSize += allocationGranularity; |
| 797 #endif | 797 #endif |
| 798 | 798 |
| 799 getThreadState()->shouldFlushHeapDoesNotContainCache(); | 799 getThreadState()->shouldFlushHeapDoesNotContainCache(); |
| 800 PageMemory* pageMemory = PageMemory::allocate(largeObjectSize, Heap::getRegi
onTree()); | 800 PageMemory* pageMemory = PageMemory::allocate(largeObjectSize, getThreadStat
e()->heap().getRegionTree()); |
| 801 Address largeObjectAddress = pageMemory->writableStart(); | 801 Address largeObjectAddress = pageMemory->writableStart(); |
| 802 Address headerAddress = largeObjectAddress + LargeObjectPage::pageHeaderSize
(); | 802 Address headerAddress = largeObjectAddress + LargeObjectPage::pageHeaderSize
(); |
| 803 #if ENABLE(ASSERT) | 803 #if ENABLE(ASSERT) |
| 804 // Verify that the allocated PageMemory is expectedly zeroed. | 804 // Verify that the allocated PageMemory is expectedly zeroed. |
| 805 for (size_t i = 0; i < largeObjectSize; ++i) | 805 for (size_t i = 0; i < largeObjectSize; ++i) |
| 806 ASSERT(!largeObjectAddress[i]); | 806 ASSERT(!largeObjectAddress[i]); |
| 807 #endif | 807 #endif |
| 808 ASSERT(gcInfoIndex > 0); | 808 ASSERT(gcInfoIndex > 0); |
| 809 HeapObjectHeader* header = new (NotNull, headerAddress) HeapObjectHeader(lar
geObjectSizeInHeader, gcInfoIndex); | 809 HeapObjectHeader* header = new (NotNull, headerAddress) HeapObjectHeader(lar
geObjectSizeInHeader, gcInfoIndex); |
| 810 Address result = headerAddress + sizeof(*header); | 810 Address result = headerAddress + sizeof(*header); |
| 811 ASSERT(!(reinterpret_cast<uintptr_t>(result) & allocationMask)); | 811 ASSERT(!(reinterpret_cast<uintptr_t>(result) & allocationMask)); |
| 812 LargeObjectPage* largeObject = new (largeObjectAddress) LargeObjectPage(page
Memory, this, allocationSize); | 812 LargeObjectPage* largeObject = new (largeObjectAddress) LargeObjectPage(page
Memory, this, allocationSize); |
| 813 ASSERT(header->checkHeader()); | 813 ASSERT(header->checkHeader()); |
| 814 | 814 |
| 815 // Poison the object header and allocationGranularity bytes after the object | 815 // Poison the object header and allocationGranularity bytes after the object |
| 816 ASAN_POISON_MEMORY_REGION(header, sizeof(*header)); | 816 ASAN_POISON_MEMORY_REGION(header, sizeof(*header)); |
| 817 ASAN_POISON_MEMORY_REGION(largeObject->getAddress() + largeObject->size(), a
llocationGranularity); | 817 ASAN_POISON_MEMORY_REGION(largeObject->getAddress() + largeObject->size(), a
llocationGranularity); |
| 818 | 818 |
| 819 largeObject->link(&m_firstPage); | 819 largeObject->link(&m_firstPage); |
| 820 | 820 |
| 821 Heap::increaseAllocatedSpace(largeObject->size()); | 821 getThreadState()->heap().heapStats().increaseAllocatedSpace(largeObject->siz
e()); |
| 822 getThreadState()->increaseAllocatedObjectSize(largeObject->size()); | 822 getThreadState()->increaseAllocatedObjectSize(largeObject->size()); |
| 823 return result; | 823 return result; |
| 824 } | 824 } |
| 825 | 825 |
| 826 void LargeObjectArena::freeLargeObjectPage(LargeObjectPage* object) | 826 void LargeObjectArena::freeLargeObjectPage(LargeObjectPage* object) |
| 827 { | 827 { |
| 828 ASAN_UNPOISON_MEMORY_REGION(object->payload(), object->payloadSize()); | 828 ASAN_UNPOISON_MEMORY_REGION(object->payload(), object->payloadSize()); |
| 829 object->heapObjectHeader()->finalize(object->payload(), object->payloadSize(
)); | 829 object->heapObjectHeader()->finalize(object->payload(), object->payloadSize(
)); |
| 830 Heap::decreaseAllocatedSpace(object->size()); | 830 getThreadState()->heap().heapStats().decreaseAllocatedSpace(object->size()); |
| 831 | 831 |
| 832 // Unpoison the object header and allocationGranularity bytes after the | 832 // Unpoison the object header and allocationGranularity bytes after the |
| 833 // object before freeing. | 833 // object before freeing. |
| 834 ASAN_UNPOISON_MEMORY_REGION(object->heapObjectHeader(), sizeof(HeapObjectHea
der)); | 834 ASAN_UNPOISON_MEMORY_REGION(object->heapObjectHeader(), sizeof(HeapObjectHea
der)); |
| 835 ASAN_UNPOISON_MEMORY_REGION(object->getAddress() + object->size(), allocatio
nGranularity); | 835 ASAN_UNPOISON_MEMORY_REGION(object->getAddress() + object->size(), allocatio
nGranularity); |
| 836 | 836 |
| 837 if (object->terminating()) { | 837 if (object->terminating()) { |
| 838 ASSERT(ThreadState::current()->isTerminating()); | 838 ASSERT(ThreadState::current()->isTerminating()); |
| 839 // The thread is shutting down and this page is being removed as a part | 839 // The thread is shutting down and this page is being removed as a part |
| 840 // of the thread local GC. In that case the object could be traced in | 840 // of the thread local GC. In that case the object could be traced in |
| 841 // the next global GC if there is a dangling pointer from a live thread | 841 // the next global GC if there is a dangling pointer from a live thread |
| 842 // heap to this dead thread heap. To guard against this, we put the | 842 // heap to this dead thread heap. To guard against this, we put the |
| 843 // page into the orphaned page pool and zap the page memory. This | 843 // page into the orphaned page pool and zap the page memory. This |
| 844 // ensures that tracing the dangling pointer in the next global GC just | 844 // ensures that tracing the dangling pointer in the next global GC just |
| 845 // crashes instead of causing use-after-frees. After the next global | 845 // crashes instead of causing use-after-frees. After the next global |
| 846 // GC, the orphaned pages are removed. | 846 // GC, the orphaned pages are removed. |
| 847 Heap::getOrphanedPagePool()->addOrphanedPage(arenaIndex(), object); | 847 getThreadState()->heap().getOrphanedPagePool()->addOrphanedPage(arenaInd
ex(), object); |
| 848 } else { | 848 } else { |
| 849 ASSERT(!ThreadState::current()->isTerminating()); | 849 ASSERT(!ThreadState::current()->isTerminating()); |
| 850 PageMemory* memory = object->storage(); | 850 PageMemory* memory = object->storage(); |
| 851 object->~LargeObjectPage(); | 851 object->~LargeObjectPage(); |
| 852 delete memory; | 852 delete memory; |
| 853 } | 853 } |
| 854 } | 854 } |
| 855 | 855 |
| 856 Address LargeObjectArena::lazySweepPages(size_t allocationSize, size_t gcInfoInd
ex) | 856 Address LargeObjectArena::lazySweepPages(size_t allocationSize, size_t gcInfoInd
ex) |
| 857 { | 857 { |
| (...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1134 // that memory on the freelist is zero filled. | 1134 // that memory on the freelist is zero filled. |
| 1135 SET_MEMORY_INACCESSIBLE(headerAddress, size); | 1135 SET_MEMORY_INACCESSIBLE(headerAddress, size); |
| 1136 headerAddress += size; | 1136 headerAddress += size; |
| 1137 continue; | 1137 continue; |
| 1138 } | 1138 } |
| 1139 if (startOfGap != headerAddress) { | 1139 if (startOfGap != headerAddress) { |
| 1140 pageArena->addToFreeList(startOfGap, headerAddress - startOfGap); | 1140 pageArena->addToFreeList(startOfGap, headerAddress - startOfGap); |
| 1141 #if !ENABLE(ASSERT) && !defined(LEAK_SANITIZER) && !defined(ADDRESS_SANITIZER) | 1141 #if !ENABLE(ASSERT) && !defined(LEAK_SANITIZER) && !defined(ADDRESS_SANITIZER) |
| 1142 // Discarding pages increases page faults and may regress performanc
e. | 1142 // Discarding pages increases page faults and may regress performanc
e. |
| 1143 // So we enable this only on low-RAM devices. | 1143 // So we enable this only on low-RAM devices. |
| 1144 if (Heap::isLowEndDevice()) | 1144 if (ProcessHeap::isLowEndDevice()) |
| 1145 discardPages(startOfGap + sizeof(FreeListEntry), headerAddress); | 1145 discardPages(startOfGap + sizeof(FreeListEntry), headerAddress); |
| 1146 #endif | 1146 #endif |
| 1147 } | 1147 } |
| 1148 header->unmark(); | 1148 header->unmark(); |
| 1149 headerAddress += size; | 1149 headerAddress += size; |
| 1150 markedObjectSize += size; | 1150 markedObjectSize += size; |
| 1151 startOfGap = headerAddress; | 1151 startOfGap = headerAddress; |
| 1152 } | 1152 } |
| 1153 if (startOfGap != payloadEnd()) { | 1153 if (startOfGap != payloadEnd()) { |
| 1154 pageArena->addToFreeList(startOfGap, payloadEnd() - startOfGap); | 1154 pageArena->addToFreeList(startOfGap, payloadEnd() - startOfGap); |
| 1155 #if !ENABLE(ASSERT) && !defined(LEAK_SANITIZER) && !defined(ADDRESS_SANITIZER) | 1155 #if !ENABLE(ASSERT) && !defined(LEAK_SANITIZER) && !defined(ADDRESS_SANITIZER) |
| 1156 if (Heap::isLowEndDevice()) | 1156 if (ProcessHeap::isLowEndDevice()) |
| 1157 discardPages(startOfGap + sizeof(FreeListEntry), payloadEnd()); | 1157 discardPages(startOfGap + sizeof(FreeListEntry), payloadEnd()); |
| 1158 #endif | 1158 #endif |
| 1159 } | 1159 } |
| 1160 | 1160 |
| 1161 if (markedObjectSize) | 1161 if (markedObjectSize) |
| 1162 pageArena->getThreadState()->increaseMarkedObjectSize(markedObjectSize); | 1162 pageArena->getThreadState()->increaseMarkedObjectSize(markedObjectSize); |
| 1163 } | 1163 } |
| 1164 | 1164 |
| 1165 void NormalPage::makeConsistentForGC() | 1165 void NormalPage::makeConsistentForGC() |
| 1166 { | 1166 { |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1312 if (objectFields[i] != 0) | 1312 if (objectFields[i] != 0) |
| 1313 return false; | 1313 return false; |
| 1314 } | 1314 } |
| 1315 return true; | 1315 return true; |
| 1316 } | 1316 } |
| 1317 #endif | 1317 #endif |
| 1318 | 1318 |
| 1319 static void markPointer(Visitor* visitor, HeapObjectHeader* header) | 1319 static void markPointer(Visitor* visitor, HeapObjectHeader* header) |
| 1320 { | 1320 { |
| 1321 ASSERT(header->checkHeader()); | 1321 ASSERT(header->checkHeader()); |
| 1322 const GCInfo* gcInfo = Heap::gcInfo(header->gcInfoIndex()); | 1322 const GCInfo* gcInfo = ThreadHeap::gcInfo(header->gcInfoIndex()); |
| 1323 if (gcInfo->hasVTable() && !vTableInitialized(header->payload())) { | 1323 if (gcInfo->hasVTable() && !vTableInitialized(header->payload())) { |
| 1324 // We hit this branch when a GC strikes before GarbageCollected<>'s | 1324 // We hit this branch when a GC strikes before GarbageCollected<>'s |
| 1325 // constructor runs. | 1325 // constructor runs. |
| 1326 // | 1326 // |
| 1327 // class A : public GarbageCollected<A> { virtual void f() = 0; }; | 1327 // class A : public GarbageCollected<A> { virtual void f() = 0; }; |
| 1328 // class B : public A { | 1328 // class B : public A { |
| 1329 // B() : A(foo()) { }; | 1329 // B() : A(foo()) { }; |
| 1330 // }; | 1330 // }; |
| 1331 // | 1331 // |
| 1332 // If foo() allocates something and triggers a GC, the vtable of A | 1332 // If foo() allocates something and triggers a GC, the vtable of A |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1562 | 1562 |
| 1563 m_hasEntries = true; | 1563 m_hasEntries = true; |
| 1564 size_t index = hash(address); | 1564 size_t index = hash(address); |
| 1565 ASSERT(!(index & 1)); | 1565 ASSERT(!(index & 1)); |
| 1566 Address cachePage = roundToBlinkPageStart(address); | 1566 Address cachePage = roundToBlinkPageStart(address); |
| 1567 m_entries[index + 1] = m_entries[index]; | 1567 m_entries[index + 1] = m_entries[index]; |
| 1568 m_entries[index] = cachePage; | 1568 m_entries[index] = cachePage; |
| 1569 } | 1569 } |
| 1570 | 1570 |
| 1571 } // namespace blink | 1571 } // namespace blink |
| OLD | NEW |