| 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 , m_size(size) | 118 , m_size(size) |
| 119 { | 119 { |
| 120 ASSERT(size > 0); | 120 ASSERT(size > 0); |
| 121 } | 121 } |
| 122 | 122 |
| 123 bool contains(Address addr) const | 123 bool contains(Address addr) const |
| 124 { | 124 { |
| 125 return m_base <= addr && addr < (m_base + m_size); | 125 return m_base <= addr && addr < (m_base + m_size); |
| 126 } | 126 } |
| 127 | 127 |
| 128 |
| 128 bool contains(const MemoryRegion& other) const | 129 bool contains(const MemoryRegion& other) const |
| 129 { | 130 { |
| 130 return contains(other.m_base) && contains(other.m_base + other.m_size -
1); | 131 return contains(other.m_base) && contains(other.m_base + other.m_size -
1); |
| 131 } | 132 } |
| 132 | 133 |
| 133 void release() | 134 void release() |
| 134 { | 135 { |
| 135 #if OS(POSIX) | 136 #if OS(POSIX) |
| 136 int err = munmap(m_base, m_size); | 137 int err = munmap(m_base, m_size); |
| 137 RELEASE_ASSERT(!err); | 138 RELEASE_ASSERT(!err); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 179 // whole. The PageMemoryRegion allows us to do that by keeping track | 180 // whole. The PageMemoryRegion allows us to do that by keeping track |
| 180 // of the number of pages using it in order to be able to release all | 181 // of the number of pages using it in order to be able to release all |
| 181 // of the virtual address space when there are no more pages using it. | 182 // of the virtual address space when there are no more pages using it. |
| 182 class PageMemoryRegion : public MemoryRegion { | 183 class PageMemoryRegion : public MemoryRegion { |
| 183 public: | 184 public: |
| 184 ~PageMemoryRegion() | 185 ~PageMemoryRegion() |
| 185 { | 186 { |
| 186 release(); | 187 release(); |
| 187 } | 188 } |
| 188 | 189 |
| 189 void pageDeleted(Address page) | 190 void pageRemoved() |
| 190 { | 191 { |
| 191 markPageUnused(page); | 192 if (!--m_numPages) |
| 192 if (!--m_numPages) { | |
| 193 Heap::removePageMemoryRegion(this); | |
| 194 delete this; | 193 delete this; |
| 195 } | |
| 196 } | |
| 197 | |
| 198 void markPageUsed(Address page) | |
| 199 { | |
| 200 ASSERT(!m_inUse[index(page)]); | |
| 201 m_inUse[index(page)] = true; | |
| 202 } | |
| 203 | |
| 204 void markPageUnused(Address page) | |
| 205 { | |
| 206 m_inUse[index(page)] = false; | |
| 207 } | |
| 208 | |
| 209 static PageMemoryRegion* allocateLargePage(size_t size) | |
| 210 { | |
| 211 return allocate(size, 1); | |
| 212 } | |
| 213 | |
| 214 static PageMemoryRegion* allocateNormalPages() | |
| 215 { | |
| 216 return allocate(blinkPageSize * blinkPagesPerRegion, blinkPagesPerRegion
); | |
| 217 } | |
| 218 | |
| 219 BaseHeapPage* pageFromAddress(Address address) | |
| 220 { | |
| 221 ASSERT(contains(address)); | |
| 222 if (!m_inUse[index(address)]) | |
| 223 return 0; | |
| 224 if (m_isLargePage) | |
| 225 return pageHeaderFromObject(base()); | |
| 226 return pageHeaderFromObject(address); | |
| 227 } | |
| 228 | |
| 229 private: | |
| 230 PageMemoryRegion(Address base, size_t size, unsigned numPages) | |
| 231 : MemoryRegion(base, size) | |
| 232 , m_isLargePage(numPages == 1) | |
| 233 , m_numPages(numPages) | |
| 234 { | |
| 235 for (size_t i = 0; i < blinkPagesPerRegion; ++i) | |
| 236 m_inUse[i] = false; | |
| 237 } | |
| 238 | |
| 239 unsigned index(Address address) | |
| 240 { | |
| 241 ASSERT(contains(address)); | |
| 242 if (m_isLargePage) | |
| 243 return 0; | |
| 244 size_t offset = blinkPageAddress(address) - base(); | |
| 245 ASSERT(offset % blinkPageSize == 0); | |
| 246 return offset / blinkPageSize; | |
| 247 } | 194 } |
| 248 | 195 |
| 249 static PageMemoryRegion* allocate(size_t size, unsigned numPages) | 196 static PageMemoryRegion* allocate(size_t size, unsigned numPages) |
| 250 { | 197 { |
| 251 ASSERT(Heap::heapDoesNotContainCacheIsEmpty()); | 198 ASSERT(Heap::heapDoesNotContainCacheIsEmpty()); |
| 252 | 199 |
| 253 // Compute a random blink page aligned address for the page memory | 200 // Compute a random blink page aligned address for the page memory |
| 254 // region and attempt to get the memory there. | 201 // region and attempt to get the memory there. |
| 255 Address randomAddress = reinterpret_cast<Address>(WTF::getRandomPageBase
()); | 202 Address randomAddress = reinterpret_cast<Address>(WTF::getRandomPageBase
()); |
| 256 Address alignedRandomAddress = roundToBlinkPageBoundary(randomAddress); | 203 Address alignedRandomAddress = roundToBlinkPageBoundary(randomAddress); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 320 | 267 |
| 321 // FIXME: If base is by accident blink page size aligned | 268 // FIXME: If base is by accident blink page size aligned |
| 322 // here then we can create two pages out of reserved | 269 // here then we can create two pages out of reserved |
| 323 // space. Do this. | 270 // space. Do this. |
| 324 Address alignedBase = roundToBlinkPageBoundary(base); | 271 Address alignedBase = roundToBlinkPageBoundary(base); |
| 325 | 272 |
| 326 return new PageMemoryRegion(alignedBase, size, numPages); | 273 return new PageMemoryRegion(alignedBase, size, numPages); |
| 327 #endif | 274 #endif |
| 328 } | 275 } |
| 329 | 276 |
| 330 bool m_isLargePage; | 277 private: |
| 331 bool m_inUse[blinkPagesPerRegion]; | 278 PageMemoryRegion(Address base, size_t size, unsigned numPages) |
| 279 : MemoryRegion(base, size) |
| 280 , m_numPages(numPages) |
| 281 { |
| 282 } |
| 283 |
| 332 unsigned m_numPages; | 284 unsigned m_numPages; |
| 333 }; | 285 }; |
| 334 | 286 |
| 335 // Representation of the memory used for a Blink heap page. | 287 // Representation of the memory used for a Blink heap page. |
| 336 // | 288 // |
| 337 // The representation keeps track of two memory regions: | 289 // The representation keeps track of two memory regions: |
| 338 // | 290 // |
| 339 // 1. The virtual memory reserved from the system in order to be able | 291 // 1. The virtual memory reserved from the system in order to be able |
| 340 // to free all the virtual memory reserved. Multiple PageMemory | 292 // to free all the virtual memory reserved. Multiple PageMemory |
| 341 // instances can share the same reserved memory region and | 293 // instances can share the same reserved memory region and |
| 342 // therefore notify the reserved memory region on destruction so | 294 // therefore notify the reserved memory region on destruction so |
| 343 // that the system memory can be given back when all PageMemory | 295 // that the system memory can be given back when all PageMemory |
| 344 // instances for that memory are gone. | 296 // instances for that memory are gone. |
| 345 // | 297 // |
| 346 // 2. The writable memory (a sub-region of the reserved virtual | 298 // 2. The writable memory (a sub-region of the reserved virtual |
| 347 // memory region) that is used for the actual heap page payload. | 299 // memory region) that is used for the actual heap page payload. |
| 348 // | 300 // |
| 349 // Guard pages are created before and after the writable memory. | 301 // Guard pages are created before and after the writable memory. |
| 350 class PageMemory { | 302 class PageMemory { |
| 351 public: | 303 public: |
| 352 ~PageMemory() | 304 ~PageMemory() |
| 353 { | 305 { |
| 354 __lsan_unregister_root_region(m_writable.base(), m_writable.size()); | 306 __lsan_unregister_root_region(m_writable.base(), m_writable.size()); |
| 355 m_reserved->pageDeleted(writableStart()); | 307 m_reserved->pageRemoved(); |
| 356 } | 308 } |
| 357 | 309 |
| 358 WARN_UNUSED_RETURN bool commit() | 310 bool commit() WARN_UNUSED_RETURN { return m_writable.commit(); } |
| 359 { | 311 void decommit() { m_writable.decommit(); } |
| 360 m_reserved->markPageUsed(writableStart()); | |
| 361 return m_writable.commit(); | |
| 362 } | |
| 363 | |
| 364 void decommit() | |
| 365 { | |
| 366 m_reserved->markPageUnused(writableStart()); | |
| 367 m_writable.decommit(); | |
| 368 } | |
| 369 | |
| 370 void markUnused() { m_reserved->markPageUnused(writableStart()); } | |
| 371 | |
| 372 PageMemoryRegion* region() { return m_reserved; } | |
| 373 | 312 |
| 374 Address writableStart() { return m_writable.base(); } | 313 Address writableStart() { return m_writable.base(); } |
| 375 | 314 |
| 376 static PageMemory* setupPageMemoryInRegion(PageMemoryRegion* region, size_t
pageOffset, size_t payloadSize) | 315 static PageMemory* setupPageMemoryInRegion(PageMemoryRegion* region, size_t
pageOffset, size_t payloadSize) |
| 377 { | 316 { |
| 378 // Setup the payload one OS page into the page memory. The | 317 // Setup the payload one OS page into the page memory. The |
| 379 // first os page is the guard page. | 318 // first os page is the guard page. |
| 380 Address payloadAddress = region->base() + pageOffset + osPageSize(); | 319 Address payloadAddress = region->base() + pageOffset + osPageSize(); |
| 381 return new PageMemory(region, MemoryRegion(payloadAddress, payloadSize))
; | 320 return new PageMemory(region, MemoryRegion(payloadAddress, payloadSize))
; |
| 382 } | 321 } |
| 383 | 322 |
| 384 // Allocate a virtual address space for one blink page with the | 323 // Allocate a virtual address space for one blink page with the |
| 385 // following layout: | 324 // following layout: |
| 386 // | 325 // |
| 387 // [ guard os page | ... payload ... | guard os page ] | 326 // [ guard os page | ... payload ... | guard os page ] |
| 388 // ^---{ aligned to blink page size } | 327 // ^---{ aligned to blink page size } |
| 389 // | 328 // |
| 390 static PageMemory* allocate(size_t payloadSize) | 329 static PageMemory* allocate(size_t payloadSize) |
| 391 { | 330 { |
| 392 ASSERT(payloadSize > 0); | 331 ASSERT(payloadSize > 0); |
| 393 | 332 |
| 394 // Virtual memory allocation routines operate in OS page sizes. | 333 // Virtual memory allocation routines operate in OS page sizes. |
| 395 // Round up the requested size to nearest os page size. | 334 // Round up the requested size to nearest os page size. |
| 396 payloadSize = roundToOsPageSize(payloadSize); | 335 payloadSize = roundToOsPageSize(payloadSize); |
| 397 | 336 |
| 398 // Overallocate by 2 times OS page size to have space for a | 337 // Overallocate by 2 times OS page size to have space for a |
| 399 // guard page at the beginning and end of blink heap page. | 338 // guard page at the beginning and end of blink heap page. |
| 400 size_t allocationSize = payloadSize + 2 * osPageSize(); | 339 size_t allocationSize = payloadSize + 2 * osPageSize(); |
| 401 PageMemoryRegion* pageMemoryRegion = PageMemoryRegion::allocateLargePage
(allocationSize); | 340 PageMemoryRegion* pageMemoryRegion = PageMemoryRegion::allocate(allocati
onSize, 1); |
| 402 PageMemory* storage = setupPageMemoryInRegion(pageMemoryRegion, 0, paylo
adSize); | 341 PageMemory* storage = setupPageMemoryInRegion(pageMemoryRegion, 0, paylo
adSize); |
| 403 RELEASE_ASSERT(storage->commit()); | 342 RELEASE_ASSERT(storage->commit()); |
| 404 return storage; | 343 return storage; |
| 405 } | 344 } |
| 406 | 345 |
| 407 private: | 346 private: |
| 408 PageMemory(PageMemoryRegion* reserved, const MemoryRegion& writable) | 347 PageMemory(PageMemoryRegion* reserved, const MemoryRegion& writable) |
| 409 : m_reserved(reserved) | 348 : m_reserved(reserved) |
| 410 , m_writable(writable) | 349 , m_writable(writable) |
| 411 { | 350 { |
| (...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 663 ThreadHeap<Header>::~ThreadHeap() | 602 ThreadHeap<Header>::~ThreadHeap() |
| 664 { | 603 { |
| 665 ASSERT(!m_firstPage); | 604 ASSERT(!m_firstPage); |
| 666 ASSERT(!m_firstLargeHeapObject); | 605 ASSERT(!m_firstLargeHeapObject); |
| 667 } | 606 } |
| 668 | 607 |
| 669 template<typename Header> | 608 template<typename Header> |
| 670 void ThreadHeap<Header>::cleanupPages() | 609 void ThreadHeap<Header>::cleanupPages() |
| 671 { | 610 { |
| 672 clearFreeLists(); | 611 clearFreeLists(); |
| 612 flushHeapContainsCache(); |
| 673 | 613 |
| 674 // Add the ThreadHeap's pages to the orphanedPagePool. | 614 // Add the ThreadHeap's pages to the orphanedPagePool. |
| 675 for (HeapPage<Header>* page = m_firstPage; page; page = page->m_next) | 615 for (HeapPage<Header>* page = m_firstPage; page; page = page->m_next) |
| 676 Heap::orphanedPagePool()->addOrphanedPage(m_index, page); | 616 Heap::orphanedPagePool()->addOrphanedPage(m_index, page); |
| 677 m_firstPage = 0; | 617 m_firstPage = 0; |
| 678 | 618 |
| 679 for (LargeHeapObject<Header>* largeObject = m_firstLargeHeapObject; largeObj
ect; largeObject = largeObject->m_next) | 619 for (LargeHeapObject<Header>* largeObject = m_firstLargeHeapObject; largeObj
ect; largeObject = largeObject->m_next) |
| 680 Heap::orphanedPagePool()->addOrphanedPage(m_index, largeObject); | 620 Heap::orphanedPagePool()->addOrphanedPage(m_index, largeObject); |
| 681 m_firstLargeHeapObject = 0; | 621 m_firstLargeHeapObject = 0; |
| 682 } | 622 } |
| (...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 978 | 918 |
| 979 // If ASan is supported we add allocationGranularity bytes to the allocated
space and | 919 // If ASan is supported we add allocationGranularity bytes to the allocated
space and |
| 980 // poison that to detect overflows | 920 // poison that to detect overflows |
| 981 #if defined(ADDRESS_SANITIZER) | 921 #if defined(ADDRESS_SANITIZER) |
| 982 allocationSize += allocationGranularity; | 922 allocationSize += allocationGranularity; |
| 983 #endif | 923 #endif |
| 984 if (threadState()->shouldGC()) | 924 if (threadState()->shouldGC()) |
| 985 threadState()->setGCRequested(); | 925 threadState()->setGCRequested(); |
| 986 Heap::flushHeapDoesNotContainCache(); | 926 Heap::flushHeapDoesNotContainCache(); |
| 987 PageMemory* pageMemory = PageMemory::allocate(allocationSize); | 927 PageMemory* pageMemory = PageMemory::allocate(allocationSize); |
| 988 m_threadState->allocatedRegionsSinceLastGC().append(pageMemory->region()); | |
| 989 Address largeObjectAddress = pageMemory->writableStart(); | 928 Address largeObjectAddress = pageMemory->writableStart(); |
| 990 Address headerAddress = largeObjectAddress + sizeof(LargeHeapObject<Header>)
+ headerPadding<Header>(); | 929 Address headerAddress = largeObjectAddress + sizeof(LargeHeapObject<Header>)
+ headerPadding<Header>(); |
| 991 memset(headerAddress, 0, size); | 930 memset(headerAddress, 0, size); |
| 992 Header* header = new (NotNull, headerAddress) Header(size, gcInfo); | 931 Header* header = new (NotNull, headerAddress) Header(size, gcInfo); |
| 993 Address result = headerAddress + sizeof(*header); | 932 Address result = headerAddress + sizeof(*header); |
| 994 ASSERT(!(reinterpret_cast<uintptr_t>(result) & allocationMask)); | 933 ASSERT(!(reinterpret_cast<uintptr_t>(result) & allocationMask)); |
| 995 LargeHeapObject<Header>* largeObject = new (largeObjectAddress) LargeHeapObj
ect<Header>(pageMemory, gcInfo, threadState()); | 934 LargeHeapObject<Header>* largeObject = new (largeObjectAddress) LargeHeapObj
ect<Header>(pageMemory, gcInfo, threadState()); |
| 996 | 935 |
| 997 // Poison the object header and allocationGranularity bytes after the object | 936 // Poison the object header and allocationGranularity bytes after the object |
| 998 ASAN_POISON_MEMORY_REGION(header, sizeof(*header)); | 937 ASAN_POISON_MEMORY_REGION(header, sizeof(*header)); |
| 999 ASAN_POISON_MEMORY_REGION(largeObject->address() + largeObject->size(), allo
cationGranularity); | 938 ASAN_POISON_MEMORY_REGION(largeObject->address() + largeObject->size(), allo
cationGranularity); |
| 1000 largeObject->link(&m_firstLargeHeapObject); | 939 largeObject->link(&m_firstLargeHeapObject); |
| 1001 stats().increaseAllocatedSpace(largeObject->size()); | 940 stats().increaseAllocatedSpace(largeObject->size()); |
| 1002 stats().increaseObjectSpace(largeObject->payloadSize()); | 941 stats().increaseObjectSpace(largeObject->payloadSize()); |
| 1003 return result; | 942 return result; |
| 1004 } | 943 } |
| 1005 | 944 |
| 1006 template<typename Header> | 945 template<typename Header> |
| 1007 void ThreadHeap<Header>::freeLargeObject(LargeHeapObject<Header>* object, LargeH
eapObject<Header>** previousNext) | 946 void ThreadHeap<Header>::freeLargeObject(LargeHeapObject<Header>* object, LargeH
eapObject<Header>** previousNext) |
| 1008 { | 947 { |
| 948 flushHeapContainsCache(); |
| 1009 object->unlink(previousNext); | 949 object->unlink(previousNext); |
| 1010 object->finalize(); | 950 object->finalize(); |
| 1011 | 951 |
| 1012 // Unpoison the object header and allocationGranularity bytes after the | 952 // Unpoison the object header and allocationGranularity bytes after the |
| 1013 // object before freeing. | 953 // object before freeing. |
| 1014 ASAN_UNPOISON_MEMORY_REGION(object->heapObjectHeader(), sizeof(Header)); | 954 ASAN_UNPOISON_MEMORY_REGION(object->heapObjectHeader(), sizeof(Header)); |
| 1015 ASAN_UNPOISON_MEMORY_REGION(object->address() + object->size(), allocationGr
anularity); | 955 ASAN_UNPOISON_MEMORY_REGION(object->address() + object->size(), allocationGr
anularity); |
| 1016 | 956 |
| 1017 if (object->terminating()) { | 957 if (object->terminating()) { |
| 1018 ASSERT(ThreadState::current()->isTerminating()); | 958 ASSERT(ThreadState::current()->isTerminating()); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1078 delete entry; | 1018 delete entry; |
| 1079 if (memory->commit()) | 1019 if (memory->commit()) |
| 1080 return memory; | 1020 return memory; |
| 1081 | 1021 |
| 1082 // We got some memory, but failed to commit it, try again. | 1022 // We got some memory, but failed to commit it, try again. |
| 1083 delete memory; | 1023 delete memory; |
| 1084 } | 1024 } |
| 1085 return 0; | 1025 return 0; |
| 1086 } | 1026 } |
| 1087 | 1027 |
| 1088 BaseHeapPage::BaseHeapPage(PageMemory* storage, const GCInfo* gcInfo, ThreadStat
e* state) | |
| 1089 : m_storage(storage) | |
| 1090 , m_gcInfo(gcInfo) | |
| 1091 , m_threadState(state) | |
| 1092 , m_terminating(false) | |
| 1093 , m_tracedAfterOrphaned(false) | |
| 1094 { | |
| 1095 ASSERT(isPageHeaderAddress(reinterpret_cast<Address>(this))); | |
| 1096 } | |
| 1097 | |
| 1098 void BaseHeapPage::markOrphaned() | |
| 1099 { | |
| 1100 m_threadState = 0; | |
| 1101 m_gcInfo = 0; | |
| 1102 m_terminating = false; | |
| 1103 m_tracedAfterOrphaned = false; | |
| 1104 // Since we zap the page payload for orphaned pages we need to mark it as | |
| 1105 // unused so a conservative pointer won't interpret the object headers. | |
| 1106 storage()->markUnused(); | |
| 1107 } | |
| 1108 | |
| 1109 OrphanedPagePool::~OrphanedPagePool() | 1028 OrphanedPagePool::~OrphanedPagePool() |
| 1110 { | 1029 { |
| 1111 for (int index = 0; index < NumberOfHeaps; ++index) { | 1030 for (int index = 0; index < NumberOfHeaps; ++index) { |
| 1112 while (PoolEntry* entry = m_pool[index]) { | 1031 while (PoolEntry* entry = m_pool[index]) { |
| 1113 m_pool[index] = entry->next; | 1032 m_pool[index] = entry->next; |
| 1114 BaseHeapPage* page = entry->data; | 1033 BaseHeapPage* page = entry->data; |
| 1115 delete entry; | 1034 delete entry; |
| 1116 PageMemory* memory = page->storage(); | 1035 PageMemory* memory = page->storage(); |
| 1117 ASSERT(memory); | 1036 ASSERT(memory); |
| 1118 page->~BaseHeapPage(); | 1037 page->~BaseHeapPage(); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1223 // When adding a page to the ThreadHeap using HeapObjectHeaders store the GC
Info on the heap | 1142 // When adding a page to the ThreadHeap using HeapObjectHeaders store the GC
Info on the heap |
| 1224 // since it is the same for all objects | 1143 // since it is the same for all objects |
| 1225 ASSERT(gcInfo); | 1144 ASSERT(gcInfo); |
| 1226 allocatePage(gcInfo); | 1145 allocatePage(gcInfo); |
| 1227 } | 1146 } |
| 1228 | 1147 |
| 1229 template <typename Header> | 1148 template <typename Header> |
| 1230 void ThreadHeap<Header>::removePageFromHeap(HeapPage<Header>* page) | 1149 void ThreadHeap<Header>::removePageFromHeap(HeapPage<Header>* page) |
| 1231 { | 1150 { |
| 1232 MutexLocker locker(m_threadState->sweepMutex()); | 1151 MutexLocker locker(m_threadState->sweepMutex()); |
| 1152 flushHeapContainsCache(); |
| 1233 if (page->terminating()) { | 1153 if (page->terminating()) { |
| 1234 // The thread is shutting down so this page is being removed as part | 1154 // The thread is shutting down so this page is being removed as part |
| 1235 // of a thread local GC. In that case the page could be accessed in the | 1155 // of a thread local GC. In that case the page could be accessed in the |
| 1236 // next global GC either due to a dead object being traced via a | 1156 // next global GC either due to a dead object being traced via a |
| 1237 // conservative pointer or due to a programming error where an object | 1157 // conservative pointer or due to a programming error where an object |
| 1238 // in another thread heap keeps a dangling pointer to this object. | 1158 // in another thread heap keeps a dangling pointer to this object. |
| 1239 // To guard against this we put the page in the orphanedPagePool to | 1159 // To guard against this we put the page in the orphanedPagePool to |
| 1240 // ensure it is still reachable. After the next global GC it can be | 1160 // ensure it is still reachable. After the next global GC it can be |
| 1241 // decommitted and moved to the page pool assuming no rogue/dangling | 1161 // decommitted and moved to the page pool assuming no rogue/dangling |
| 1242 // pointers refer to it. | 1162 // pointers refer to it. |
| 1243 Heap::orphanedPagePool()->addOrphanedPage(m_index, page); | 1163 Heap::orphanedPagePool()->addOrphanedPage(m_index, page); |
| 1244 } else { | 1164 } else { |
| 1245 PageMemory* memory = page->storage(); | 1165 PageMemory* memory = page->storage(); |
| 1246 page->~HeapPage<Header>(); | 1166 page->~HeapPage<Header>(); |
| 1247 Heap::freePagePool()->addFreePage(m_index, memory); | 1167 Heap::freePagePool()->addFreePage(m_index, memory); |
| 1248 } | 1168 } |
| 1249 } | 1169 } |
| 1250 | 1170 |
| 1251 template<typename Header> | 1171 template<typename Header> |
| 1252 void ThreadHeap<Header>::allocatePage(const GCInfo* gcInfo) | 1172 void ThreadHeap<Header>::allocatePage(const GCInfo* gcInfo) |
| 1253 { | 1173 { |
| 1254 Heap::flushHeapDoesNotContainCache(); | 1174 Heap::flushHeapDoesNotContainCache(); |
| 1255 PageMemory* pageMemory = Heap::freePagePool()->takeFreePage(m_index); | 1175 PageMemory* pageMemory = Heap::freePagePool()->takeFreePage(m_index); |
| 1256 // We continue allocating page memory until we succeed in committing one. | 1176 // We continue allocating page memory until we succeed in getting one. |
| 1177 // Since the FreePagePool is global other threads could use all the |
| 1178 // newly allocated page memory before this thread calls takeFreePage. |
| 1257 while (!pageMemory) { | 1179 while (!pageMemory) { |
| 1258 // Allocate a memory region for blinkPagesPerRegion pages that | 1180 // Allocate a memory region for blinkPagesPerRegion pages that |
| 1259 // will each have the following layout. | 1181 // will each have the following layout. |
| 1260 // | 1182 // |
| 1261 // [ guard os page | ... payload ... | guard os page ] | 1183 // [ guard os page | ... payload ... | guard os page ] |
| 1262 // ^---{ aligned to blink page size } | 1184 // ^---{ aligned to blink page size } |
| 1263 PageMemoryRegion* region = PageMemoryRegion::allocateNormalPages(); | 1185 PageMemoryRegion* region = PageMemoryRegion::allocate(blinkPageSize * bl
inkPagesPerRegion, blinkPagesPerRegion); |
| 1264 m_threadState->allocatedRegionsSinceLastGC().append(region); | |
| 1265 | |
| 1266 // Setup the PageMemory object for each of the pages in the | 1186 // Setup the PageMemory object for each of the pages in the |
| 1267 // region. | 1187 // region. |
| 1268 size_t offset = 0; | 1188 size_t offset = 0; |
| 1269 for (size_t i = 0; i < blinkPagesPerRegion; i++) { | 1189 for (size_t i = 0; i < blinkPagesPerRegion; i++) { |
| 1270 PageMemory* memory = PageMemory::setupPageMemoryInRegion(region, off
set, blinkPagePayloadSize()); | 1190 Heap::freePagePool()->addFreePage(m_index, PageMemory::setupPageMemo
ryInRegion(region, offset, blinkPagePayloadSize())); |
| 1271 // Take the first possible page ensuring that this thread actually | |
| 1272 // gets a page and add the rest to the page pool. | |
| 1273 if (!pageMemory) { | |
| 1274 if (memory->commit()) | |
| 1275 pageMemory = memory; | |
| 1276 else | |
| 1277 delete memory; | |
| 1278 } else { | |
| 1279 Heap::freePagePool()->addFreePage(m_index, memory); | |
| 1280 } | |
| 1281 offset += blinkPageSize; | 1191 offset += blinkPageSize; |
| 1282 } | 1192 } |
| 1193 pageMemory = Heap::freePagePool()->takeFreePage(m_index); |
| 1283 } | 1194 } |
| 1284 HeapPage<Header>* page = new (pageMemory->writableStart()) HeapPage<Header>(
pageMemory, this, gcInfo); | 1195 HeapPage<Header>* page = new (pageMemory->writableStart()) HeapPage<Header>(
pageMemory, this, gcInfo); |
| 1285 // Use a separate list for pages allocated during sweeping to make | 1196 // Use a separate list for pages allocated during sweeping to make |
| 1286 // sure that we do not accidentally sweep objects that have been | 1197 // sure that we do not accidentally sweep objects that have been |
| 1287 // allocated during sweeping. | 1198 // allocated during sweeping. |
| 1288 if (m_threadState->isSweepInProgress()) { | 1199 if (m_threadState->isSweepInProgress()) { |
| 1289 if (!m_lastPageAllocatedDuringSweeping) | 1200 if (!m_lastPageAllocatedDuringSweeping) |
| 1290 m_lastPageAllocatedDuringSweeping = page; | 1201 m_lastPageAllocatedDuringSweeping = page; |
| 1291 page->link(&m_firstPageAllocatedDuringSweeping); | 1202 page->link(&m_firstPageAllocatedDuringSweeping); |
| 1292 } else { | 1203 } else { |
| (...skipping 538 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1831 } | 1742 } |
| 1832 | 1743 |
| 1833 if (json) { | 1744 if (json) { |
| 1834 json->setInteger("class", tag); | 1745 json->setInteger("class", tag); |
| 1835 json->setInteger("size", header->size()); | 1746 json->setInteger("size", header->size()); |
| 1836 json->setInteger("isMarked", isMarked()); | 1747 json->setInteger("isMarked", isMarked()); |
| 1837 } | 1748 } |
| 1838 } | 1749 } |
| 1839 #endif | 1750 #endif |
| 1840 | 1751 |
| 1841 void HeapDoesNotContainCache::flush() | 1752 template<typename Entry> |
| 1753 void HeapExtentCache<Entry>::flush() |
| 1842 { | 1754 { |
| 1843 if (m_hasEntries) { | 1755 if (m_hasEntries) { |
| 1844 for (int i = 0; i < numberOfEntries; i++) | 1756 for (int i = 0; i < numberOfEntries; i++) |
| 1845 m_entries[i] = 0; | 1757 m_entries[i] = Entry(); |
| 1846 m_hasEntries = false; | 1758 m_hasEntries = false; |
| 1847 } | 1759 } |
| 1848 } | 1760 } |
| 1849 | 1761 |
| 1850 size_t HeapDoesNotContainCache::hash(Address address) | 1762 template<typename Entry> |
| 1763 size_t HeapExtentCache<Entry>::hash(Address address) |
| 1851 { | 1764 { |
| 1852 size_t value = (reinterpret_cast<size_t>(address) >> blinkPageSizeLog2); | 1765 size_t value = (reinterpret_cast<size_t>(address) >> blinkPageSizeLog2); |
| 1853 value ^= value >> numberOfEntriesLog2; | 1766 value ^= value >> numberOfEntriesLog2; |
| 1854 value ^= value >> (numberOfEntriesLog2 * 2); | 1767 value ^= value >> (numberOfEntriesLog2 * 2); |
| 1855 value &= numberOfEntries - 1; | 1768 value &= numberOfEntries - 1; |
| 1856 return value & ~1; // Returns only even number. | 1769 return value & ~1; // Returns only even number. |
| 1857 } | 1770 } |
| 1858 | 1771 |
| 1859 bool HeapDoesNotContainCache::lookup(Address address) | 1772 template<typename Entry> |
| 1773 typename Entry::LookupResult HeapExtentCache<Entry>::lookup(Address address) |
| 1860 { | 1774 { |
| 1861 size_t index = hash(address); | 1775 size_t index = hash(address); |
| 1862 ASSERT(!(index & 1)); | 1776 ASSERT(!(index & 1)); |
| 1863 Address cachePage = roundToBlinkPageStart(address); | 1777 Address cachePage = roundToBlinkPageStart(address); |
| 1864 if (m_entries[index] == cachePage) | 1778 if (m_entries[index].address() == cachePage) |
| 1865 return m_entries[index]; | 1779 return m_entries[index].result(); |
| 1866 if (m_entries[index + 1] == cachePage) | 1780 if (m_entries[index + 1].address() == cachePage) |
| 1867 return m_entries[index + 1]; | 1781 return m_entries[index + 1].result(); |
| 1868 return 0; | 1782 return 0; |
| 1869 } | 1783 } |
| 1870 | 1784 |
| 1871 void HeapDoesNotContainCache::addEntry(Address address) | 1785 template<typename Entry> |
| 1786 void HeapExtentCache<Entry>::addEntry(Address address, typename Entry::LookupRes
ult entry) |
| 1872 { | 1787 { |
| 1873 m_hasEntries = true; | 1788 m_hasEntries = true; |
| 1874 size_t index = hash(address); | 1789 size_t index = hash(address); |
| 1875 ASSERT(!(index & 1)); | 1790 ASSERT(!(index & 1)); |
| 1876 Address cachePage = roundToBlinkPageStart(address); | 1791 Address cachePage = roundToBlinkPageStart(address); |
| 1877 m_entries[index + 1] = m_entries[index]; | 1792 m_entries[index + 1] = m_entries[index]; |
| 1878 m_entries[index] = cachePage; | 1793 m_entries[index] = Entry(cachePage, entry); |
| 1794 } |
| 1795 |
| 1796 // These should not be needed, but it seems impossible to persuade clang to |
| 1797 // instantiate the template functions and export them from a shared library, so |
| 1798 // we add these in the non-templated subclass, which does not have that issue. |
| 1799 void HeapContainsCache::addEntry(Address address, BaseHeapPage* page) |
| 1800 { |
| 1801 HeapExtentCache<PositiveEntry>::addEntry(address, page); |
| 1802 } |
| 1803 |
| 1804 BaseHeapPage* HeapContainsCache::lookup(Address address) |
| 1805 { |
| 1806 return HeapExtentCache<PositiveEntry>::lookup(address); |
| 1879 } | 1807 } |
| 1880 | 1808 |
| 1881 void Heap::flushHeapDoesNotContainCache() | 1809 void Heap::flushHeapDoesNotContainCache() |
| 1882 { | 1810 { |
| 1883 s_heapDoesNotContainCache->flush(); | 1811 s_heapDoesNotContainCache->flush(); |
| 1884 } | 1812 } |
| 1885 | 1813 |
| 1886 // The marking mutex is used to ensure sequential access to data | 1814 // The marking mutex is used to ensure sequential access to data |
| 1887 // structures during marking. The marking mutex needs to be acquired | 1815 // structures during marking. The marking mutex needs to be acquired |
| 1888 // during marking when elements are taken from the global marking | 1816 // during marking when elements are taken from the global marking |
| (...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2171 delete s_orphanedPagePool; | 2099 delete s_orphanedPagePool; |
| 2172 s_orphanedPagePool = 0; | 2100 s_orphanedPagePool = 0; |
| 2173 delete s_weakCallbackStack; | 2101 delete s_weakCallbackStack; |
| 2174 s_weakCallbackStack = 0; | 2102 s_weakCallbackStack = 0; |
| 2175 delete s_postMarkingCallbackStack; | 2103 delete s_postMarkingCallbackStack; |
| 2176 s_postMarkingCallbackStack = 0; | 2104 s_postMarkingCallbackStack = 0; |
| 2177 delete s_markingStack; | 2105 delete s_markingStack; |
| 2178 s_markingStack = 0; | 2106 s_markingStack = 0; |
| 2179 delete s_ephemeronStack; | 2107 delete s_ephemeronStack; |
| 2180 s_ephemeronStack = 0; | 2108 s_ephemeronStack = 0; |
| 2181 delete s_regionTree; | |
| 2182 s_regionTree = 0; | |
| 2183 ThreadState::shutdown(); | 2109 ThreadState::shutdown(); |
| 2184 } | 2110 } |
| 2185 | 2111 |
| 2186 BaseHeapPage* Heap::contains(Address address) | 2112 BaseHeapPage* Heap::contains(Address address) |
| 2187 { | 2113 { |
| 2188 ASSERT(ThreadState::isAnyThreadInGC()); | 2114 ASSERT(ThreadState::isAnyThreadInGC()); |
| 2189 ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThreads(
); | 2115 ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThreads(
); |
| 2190 for (ThreadState::AttachedThreadStateSet::iterator it = threads.begin(), end
= threads.end(); it != end; ++it) { | 2116 for (ThreadState::AttachedThreadStateSet::iterator it = threads.begin(), end
= threads.end(); it != end; ++it) { |
| 2191 BaseHeapPage* page = (*it)->contains(address); | 2117 BaseHeapPage* page = (*it)->contains(address); |
| 2192 if (page) | 2118 if (page) |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2204 | 2130 |
| 2205 Address Heap::checkAndMarkPointer(Visitor* visitor, Address address) | 2131 Address Heap::checkAndMarkPointer(Visitor* visitor, Address address) |
| 2206 { | 2132 { |
| 2207 ASSERT(ThreadState::isAnyThreadInGC()); | 2133 ASSERT(ThreadState::isAnyThreadInGC()); |
| 2208 | 2134 |
| 2209 #if !ENABLE(ASSERT) | 2135 #if !ENABLE(ASSERT) |
| 2210 if (s_heapDoesNotContainCache->lookup(address)) | 2136 if (s_heapDoesNotContainCache->lookup(address)) |
| 2211 return 0; | 2137 return 0; |
| 2212 #endif | 2138 #endif |
| 2213 | 2139 |
| 2214 if (BaseHeapPage* page = lookup(address)) { | 2140 ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThreads(
); |
| 2215 ASSERT(page->contains(address)); | 2141 for (ThreadState::AttachedThreadStateSet::iterator it = threads.begin(), end
= threads.end(); it != end; ++it) { |
| 2216 ASSERT(!s_heapDoesNotContainCache->lookup(address)); | 2142 if ((*it)->checkAndMarkPointer(visitor, address)) { |
| 2217 page->checkAndMarkPointer(visitor, address); | 2143 // Pointer was in a page of that thread. If it actually pointed |
| 2218 // FIXME: We only need to set the conservative flag if checkAndMarkPoint
er actually marked the pointer. | 2144 // into an object then that object was found and marked. |
| 2219 s_lastGCWasConservative = true; | 2145 ASSERT(!s_heapDoesNotContainCache->lookup(address)); |
| 2220 return address; | 2146 s_lastGCWasConservative = true; |
| 2147 return address; |
| 2148 } |
| 2221 } | 2149 } |
| 2222 | 2150 |
| 2223 #if !ENABLE(ASSERT) | 2151 #if !ENABLE(ASSERT) |
| 2224 s_heapDoesNotContainCache->addEntry(address); | 2152 s_heapDoesNotContainCache->addEntry(address, true); |
| 2225 #else | 2153 #else |
| 2226 if (!s_heapDoesNotContainCache->lookup(address)) | 2154 if (!s_heapDoesNotContainCache->lookup(address)) |
| 2227 s_heapDoesNotContainCache->addEntry(address); | 2155 s_heapDoesNotContainCache->addEntry(address, true); |
| 2228 #endif | 2156 #endif |
| 2229 return 0; | 2157 return 0; |
| 2230 } | 2158 } |
| 2231 | 2159 |
| 2232 #if ENABLE(GC_PROFILE_MARKING) | 2160 #if ENABLE(GC_PROFILE_MARKING) |
| 2233 const GCInfo* Heap::findGCInfo(Address address) | 2161 const GCInfo* Heap::findGCInfo(Address address) |
| 2234 { | 2162 { |
| 2235 return ThreadState::findGCInfoFromAllThreads(address); | 2163 return ThreadState::findGCInfoFromAllThreads(address); |
| 2236 } | 2164 } |
| 2237 #endif | 2165 #endif |
| (...skipping 537 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2775 | 2703 |
| 2776 HeaderType* header = HeaderType::fromPayload(address); | 2704 HeaderType* header = HeaderType::fromPayload(address); |
| 2777 header->checkHeader(); | 2705 header->checkHeader(); |
| 2778 | 2706 |
| 2779 const GCInfo* gcInfo = header->gcInfo(); | 2707 const GCInfo* gcInfo = header->gcInfo(); |
| 2780 int heapIndex = HeapTraits::index(gcInfo->hasFinalizer()); | 2708 int heapIndex = HeapTraits::index(gcInfo->hasFinalizer()); |
| 2781 HeapType* heap = static_cast<HeapType*>(state->heap(heapIndex)); | 2709 HeapType* heap = static_cast<HeapType*>(state->heap(heapIndex)); |
| 2782 heap->promptlyFreeObject(header); | 2710 heap->promptlyFreeObject(header); |
| 2783 } | 2711 } |
| 2784 | 2712 |
| 2785 BaseHeapPage* Heap::lookup(Address address) | |
| 2786 { | |
| 2787 if (!s_regionTree) | |
| 2788 return 0; | |
| 2789 if (PageMemoryRegion* region = s_regionTree->lookup(address)) | |
| 2790 return region->pageFromAddress(address); | |
| 2791 return 0; | |
| 2792 } | |
| 2793 | |
| 2794 static Mutex& regionTreeMutex() | |
| 2795 { | |
| 2796 AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex); | |
| 2797 return mutex; | |
| 2798 } | |
| 2799 | |
| 2800 void Heap::removePageMemoryRegion(PageMemoryRegion* region) | |
| 2801 { | |
| 2802 // Deletion of large objects (and thus their regions) can happen concurrentl
y | |
| 2803 // on sweeper threads. Removal can also happen during thread shutdown, but | |
| 2804 // that case is safe. Regardless, we make all removals mutually exclusive. | |
| 2805 MutexLocker locker(regionTreeMutex()); | |
| 2806 RegionTree::remove(region, &s_regionTree); | |
| 2807 } | |
| 2808 | |
| 2809 void Heap::addPageMemoryRegion(PageMemoryRegion* region) | |
| 2810 { | |
| 2811 ASSERT(ThreadState::isAnyThreadInGC()); | |
| 2812 RegionTree::add(new RegionTree(region), &s_regionTree); | |
| 2813 } | |
| 2814 | |
| 2815 PageMemoryRegion* Heap::RegionTree::lookup(Address address) | |
| 2816 { | |
| 2817 RegionTree* current = s_regionTree; | |
| 2818 while (current) { | |
| 2819 Address base = current->m_region->base(); | |
| 2820 if (address < base) { | |
| 2821 current = current->m_left; | |
| 2822 continue; | |
| 2823 } | |
| 2824 if (address >= base + current->m_region->size()) { | |
| 2825 current = current->m_right; | |
| 2826 continue; | |
| 2827 } | |
| 2828 ASSERT(current->m_region->contains(address)); | |
| 2829 return current->m_region; | |
| 2830 } | |
| 2831 return 0; | |
| 2832 } | |
| 2833 | |
| 2834 void Heap::RegionTree::add(RegionTree* newTree, RegionTree** context) | |
| 2835 { | |
| 2836 ASSERT(newTree); | |
| 2837 Address base = newTree->m_region->base(); | |
| 2838 for (RegionTree* current = *context; current; current = *context) { | |
| 2839 ASSERT(!current->m_region->contains(base)); | |
| 2840 context = (base < current->m_region->base()) ? ¤t->m_left : &curre
nt->m_right; | |
| 2841 } | |
| 2842 *context = newTree; | |
| 2843 } | |
| 2844 | |
| 2845 void Heap::RegionTree::remove(PageMemoryRegion* region, RegionTree** context) | |
| 2846 { | |
| 2847 ASSERT(region); | |
| 2848 ASSERT(context); | |
| 2849 ASSERT(*context); | |
| 2850 Address base = region->base(); | |
| 2851 RegionTree* current = *context; | |
| 2852 for ( ; region != current->m_region; current = *context) { | |
| 2853 context = (base < current->m_region->base()) ? ¤t->m_left : &curre
nt->m_right; | |
| 2854 ASSERT(*context); | |
| 2855 } | |
| 2856 *context = 0; | |
| 2857 if (current->m_left) { | |
| 2858 add(current->m_left, context); | |
| 2859 current->m_left = 0; | |
| 2860 } | |
| 2861 if (current->m_right) { | |
| 2862 add(current->m_right, context); | |
| 2863 current->m_right = 0; | |
| 2864 } | |
| 2865 delete current; | |
| 2866 } | |
| 2867 | |
| 2868 // Force template instantiations for the types that we need. | 2713 // Force template instantiations for the types that we need. |
| 2869 template class HeapPage<FinalizedHeapObjectHeader>; | 2714 template class HeapPage<FinalizedHeapObjectHeader>; |
| 2870 template class HeapPage<HeapObjectHeader>; | 2715 template class HeapPage<HeapObjectHeader>; |
| 2871 template class ThreadHeap<FinalizedHeapObjectHeader>; | 2716 template class ThreadHeap<FinalizedHeapObjectHeader>; |
| 2872 template class ThreadHeap<HeapObjectHeader>; | 2717 template class ThreadHeap<HeapObjectHeader>; |
| 2873 | 2718 |
| 2874 Visitor* Heap::s_markingVisitor; | 2719 Visitor* Heap::s_markingVisitor; |
| 2875 Vector<OwnPtr<blink::WebThread> >* Heap::s_markingThreads; | 2720 Vector<OwnPtr<blink::WebThread> >* Heap::s_markingThreads; |
| 2876 CallbackStack* Heap::s_markingStack; | 2721 CallbackStack* Heap::s_markingStack; |
| 2877 CallbackStack* Heap::s_postMarkingCallbackStack; | 2722 CallbackStack* Heap::s_postMarkingCallbackStack; |
| 2878 CallbackStack* Heap::s_weakCallbackStack; | 2723 CallbackStack* Heap::s_weakCallbackStack; |
| 2879 CallbackStack* Heap::s_ephemeronStack; | 2724 CallbackStack* Heap::s_ephemeronStack; |
| 2880 HeapDoesNotContainCache* Heap::s_heapDoesNotContainCache; | 2725 HeapDoesNotContainCache* Heap::s_heapDoesNotContainCache; |
| 2881 bool Heap::s_shutdownCalled = false; | 2726 bool Heap::s_shutdownCalled = false; |
| 2882 bool Heap::s_lastGCWasConservative = false; | 2727 bool Heap::s_lastGCWasConservative = false; |
| 2883 FreePagePool* Heap::s_freePagePool; | 2728 FreePagePool* Heap::s_freePagePool; |
| 2884 OrphanedPagePool* Heap::s_orphanedPagePool; | 2729 OrphanedPagePool* Heap::s_orphanedPagePool; |
| 2885 Heap::RegionTree* Heap::s_regionTree = 0; | |
| 2886 | |
| 2887 } | 2730 } |
| OLD | NEW |