Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(746)

Side by Side Diff: sky/engine/platform/heap/Heap.cpp

Issue 681963002: Remove heap/*.cpp files (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sky/engine/platform/heap/Heap.h ('k') | sky/engine/platform/heap/HeapLinkedStack.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "config.h"
32 #include "platform/heap/Heap.h"
33
34 #include "platform/ScriptForbiddenScope.h"
35 #include "platform/TraceEvent.h"
36 #include "platform/heap/ThreadState.h"
37 #include "public/platform/Platform.h"
38 #include "wtf/AddressSpaceRandomization.h"
39 #include "wtf/Assertions.h"
40 #include "wtf/LeakAnnotations.h"
41 #include "wtf/PassOwnPtr.h"
42 #if ENABLE(GC_PROFILE_MARKING)
43 #include "wtf/HashMap.h"
44 #include "wtf/HashSet.h"
45 #include "wtf/text/StringBuilder.h"
46 #include "wtf/text/StringHash.h"
47 #include <stdio.h>
48 #include <utility>
49 #endif
50 #if ENABLE(GC_PROFILE_HEAP)
51 #include "platform/TracedValue.h"
52 #endif
53
54 #include <sys/mman.h>
55 #include <unistd.h>
56
57 namespace blink {
58
59 #if ENABLE(GC_PROFILE_MARKING)
60 static String classOf(const void* object)
61 {
62 const GCInfo* gcInfo = Heap::findGCInfo(reinterpret_cast<Address>(const_cast <void*>(object)));
63 if (gcInfo)
64 return gcInfo->m_className;
65
66 return "unknown";
67 }
68 #endif
69
70 static bool vTableInitialized(void* objectPointer)
71 {
72 return !!(*reinterpret_cast<Address*>(objectPointer));
73 }
74
75 static Address roundToBlinkPageBoundary(void* base)
76 {
77 return reinterpret_cast<Address>((reinterpret_cast<uintptr_t>(base) + blinkP ageOffsetMask) & blinkPageBaseMask);
78 }
79
80 static size_t roundToOsPageSize(size_t size)
81 {
82 return (size + osPageSize() - 1) & ~(osPageSize() - 1);
83 }
84
85 size_t osPageSize()
86 {
87 #if OS(POSIX)
88 static const size_t pageSize = getpagesize();
89 #else
90 static size_t pageSize = 0;
91 if (!pageSize) {
92 SYSTEM_INFO info;
93 GetSystemInfo(&info);
94 pageSize = info.dwPageSize;
95 ASSERT(IsPowerOf2(pageSize));
96 }
97 #endif
98 return pageSize;
99 }
100
101 class MemoryRegion {
102 public:
103 MemoryRegion(Address base, size_t size)
104 : m_base(base)
105 , m_size(size)
106 {
107 ASSERT(size > 0);
108 }
109
110 bool contains(Address addr) const
111 {
112 return m_base <= addr && addr < (m_base + m_size);
113 }
114
115
116 bool contains(const MemoryRegion& other) const
117 {
118 return contains(other.m_base) && contains(other.m_base + other.m_size - 1);
119 }
120
121 void release()
122 {
123 #if OS(POSIX)
124 int err = munmap(m_base, m_size);
125 RELEASE_ASSERT(!err);
126 #else
127 bool success = VirtualFree(m_base, 0, MEM_RELEASE);
128 RELEASE_ASSERT(success);
129 #endif
130 }
131
132 WARN_UNUSED_RETURN bool commit()
133 {
134 ASSERT(Heap::heapDoesNotContainCacheIsEmpty());
135 #if OS(POSIX)
136 int err = mprotect(m_base, m_size, PROT_READ | PROT_WRITE);
137 if (!err) {
138 madvise(m_base, m_size, MADV_NORMAL);
139 return true;
140 }
141 return false;
142 #else
143 void* result = VirtualAlloc(m_base, m_size, MEM_COMMIT, PAGE_READWRITE);
144 return !!result;
145 #endif
146 }
147
148 void decommit()
149 {
150 #if OS(POSIX)
151 int err = mprotect(m_base, m_size, PROT_NONE);
152 RELEASE_ASSERT(!err);
153 // FIXME: Consider using MADV_FREE on MacOS.
154 madvise(m_base, m_size, MADV_DONTNEED);
155 #else
156 bool success = VirtualFree(m_base, m_size, MEM_DECOMMIT);
157 RELEASE_ASSERT(success);
158 #endif
159 }
160
161 Address base() const { return m_base; }
162 size_t size() const { return m_size; }
163
164 private:
165 Address m_base;
166 size_t m_size;
167 };
168
169 // A PageMemoryRegion represents a chunk of reserved virtual address
170 // space containing a number of blink heap pages. On Windows, reserved
171 // virtual address space can only be given back to the system as a
172 // whole. The PageMemoryRegion allows us to do that by keeping track
173 // of the number of pages using it in order to be able to release all
174 // of the virtual address space when there are no more pages using it.
175 class PageMemoryRegion : public MemoryRegion {
176 public:
177 ~PageMemoryRegion()
178 {
179 release();
180 }
181
182 void pageRemoved()
183 {
184 if (!--m_numPages)
185 delete this;
186 }
187
188 static PageMemoryRegion* allocate(size_t size, unsigned numPages)
189 {
190 ASSERT(Heap::heapDoesNotContainCacheIsEmpty());
191
192 // Compute a random blink page aligned address for the page memory
193 // region and attempt to get the memory there.
194 Address randomAddress = reinterpret_cast<Address>(WTF::getRandomPageBase ());
195 Address alignedRandomAddress = roundToBlinkPageBoundary(randomAddress);
196
197 #if OS(POSIX)
198 Address base = static_cast<Address>(mmap(alignedRandomAddress, size, PRO T_NONE, MAP_ANON | MAP_PRIVATE, -1, 0));
199 RELEASE_ASSERT(base != MAP_FAILED);
200 if (base == roundToBlinkPageBoundary(base))
201 return new PageMemoryRegion(base, size, numPages);
202
203 // We failed to get a blink page aligned chunk of
204 // memory. Unmap the chunk that we got and fall back to
205 // overallocating and selecting an aligned sub part of what
206 // we allocate.
207 int error = munmap(base, size);
208 RELEASE_ASSERT(!error);
209 size_t allocationSize = size + blinkPageSize;
210 base = static_cast<Address>(mmap(alignedRandomAddress, allocationSize, P ROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0));
211 RELEASE_ASSERT(base != MAP_FAILED);
212
213 Address end = base + allocationSize;
214 Address alignedBase = roundToBlinkPageBoundary(base);
215 Address regionEnd = alignedBase + size;
216
217 // If the allocated memory was not blink page aligned release
218 // the memory before the aligned address.
219 if (alignedBase != base)
220 MemoryRegion(base, alignedBase - base).release();
221
222 // Free the additional memory at the end of the page if any.
223 if (regionEnd < end)
224 MemoryRegion(regionEnd, end - regionEnd).release();
225
226 return new PageMemoryRegion(alignedBase, size, numPages);
227 #else
228 Address base = static_cast<Address>(VirtualAlloc(alignedRandomAddress, s ize, MEM_RESERVE, PAGE_NOACCESS));
229 if (base) {
230 ASSERT(base == alignedRandomAddress);
231 return new PageMemoryRegion(base, size, numPages);
232 }
233
234 // We failed to get the random aligned address that we asked
235 // for. Fall back to overallocating. On Windows it is
236 // impossible to partially release a region of memory
237 // allocated by VirtualAlloc. To avoid wasting virtual address
238 // space we attempt to release a large region of memory
239 // returned as a whole and then allocate an aligned region
240 // inside this larger region.
241 size_t allocationSize = size + blinkPageSize;
242 for (int attempt = 0; attempt < 3; attempt++) {
243 base = static_cast<Address>(VirtualAlloc(0, allocationSize, MEM_RESE RVE, PAGE_NOACCESS));
244 RELEASE_ASSERT(base);
245 VirtualFree(base, 0, MEM_RELEASE);
246
247 Address alignedBase = roundToBlinkPageBoundary(base);
248 base = static_cast<Address>(VirtualAlloc(alignedBase, size, MEM_RESE RVE, PAGE_NOACCESS));
249 if (base) {
250 ASSERT(base == alignedBase);
251 return new PageMemoryRegion(alignedBase, size, numPages);
252 }
253 }
254
255 // We failed to avoid wasting virtual address space after
256 // several attempts.
257 base = static_cast<Address>(VirtualAlloc(0, allocationSize, MEM_RESERVE, PAGE_NOACCESS));
258 RELEASE_ASSERT(base);
259
260 // FIXME: If base is by accident blink page size aligned
261 // here then we can create two pages out of reserved
262 // space. Do this.
263 Address alignedBase = roundToBlinkPageBoundary(base);
264
265 return new PageMemoryRegion(alignedBase, size, numPages);
266 #endif
267 }
268
269 private:
270 PageMemoryRegion(Address base, size_t size, unsigned numPages)
271 : MemoryRegion(base, size)
272 , m_numPages(numPages)
273 {
274 }
275
276 unsigned m_numPages;
277 };
278
279 // Representation of the memory used for a Blink heap page.
280 //
281 // The representation keeps track of two memory regions:
282 //
283 // 1. The virtual memory reserved from the system in order to be able
284 // to free all the virtual memory reserved. Multiple PageMemory
285 // instances can share the same reserved memory region and
286 // therefore notify the reserved memory region on destruction so
287 // that the system memory can be given back when all PageMemory
288 // instances for that memory are gone.
289 //
290 // 2. The writable memory (a sub-region of the reserved virtual
291 // memory region) that is used for the actual heap page payload.
292 //
293 // Guard pages are created before and after the writable memory.
294 class PageMemory {
295 public:
296 ~PageMemory()
297 {
298 __lsan_unregister_root_region(m_writable.base(), m_writable.size());
299 m_reserved->pageRemoved();
300 }
301
302 bool commit() WARN_UNUSED_RETURN { return m_writable.commit(); }
303 void decommit() { m_writable.decommit(); }
304
305 Address writableStart() { return m_writable.base(); }
306
307 static PageMemory* setupPageMemoryInRegion(PageMemoryRegion* region, size_t pageOffset, size_t payloadSize)
308 {
309 // Setup the payload one OS page into the page memory. The
310 // first os page is the guard page.
311 Address payloadAddress = region->base() + pageOffset + osPageSize();
312 return new PageMemory(region, MemoryRegion(payloadAddress, payloadSize)) ;
313 }
314
315 // Allocate a virtual address space for one blink page with the
316 // following layout:
317 //
318 // [ guard os page | ... payload ... | guard os page ]
319 // ^---{ aligned to blink page size }
320 //
321 static PageMemory* allocate(size_t payloadSize)
322 {
323 ASSERT(payloadSize > 0);
324
325 // Virtual memory allocation routines operate in OS page sizes.
326 // Round up the requested size to nearest os page size.
327 payloadSize = roundToOsPageSize(payloadSize);
328
329 // Overallocate by 2 times OS page size to have space for a
330 // guard page at the beginning and end of blink heap page.
331 size_t allocationSize = payloadSize + 2 * osPageSize();
332 PageMemoryRegion* pageMemoryRegion = PageMemoryRegion::allocate(allocati onSize, 1);
333 PageMemory* storage = setupPageMemoryInRegion(pageMemoryRegion, 0, paylo adSize);
334 RELEASE_ASSERT(storage->commit());
335 return storage;
336 }
337
338 private:
339 PageMemory(PageMemoryRegion* reserved, const MemoryRegion& writable)
340 : m_reserved(reserved)
341 , m_writable(writable)
342 {
343 ASSERT(reserved->contains(writable));
344
345 // Register the writable area of the memory as part of the LSan root set .
346 // Only the writable area is mapped and can contain C++ objects. Those
347 // C++ objects can contain pointers to objects outside of the heap and
348 // should therefore be part of the LSan root set.
349 __lsan_register_root_region(m_writable.base(), m_writable.size());
350 }
351
352
353 PageMemoryRegion* m_reserved;
354 MemoryRegion m_writable;
355 };
356
357 NO_SANITIZE_ADDRESS
358 bool HeapObjectHeader::isMarked() const
359 {
360 checkHeader();
361 unsigned size = acquireLoad(&m_size);
362 return size & markBitMask;
363 }
364
365 NO_SANITIZE_ADDRESS
366 void HeapObjectHeader::unmark()
367 {
368 checkHeader();
369 m_size &= ~markBitMask;
370 }
371
372 NO_SANITIZE_ADDRESS
373 bool HeapObjectHeader::hasDeadMark() const
374 {
375 checkHeader();
376 return m_size & deadBitMask;
377 }
378
379 NO_SANITIZE_ADDRESS
380 void HeapObjectHeader::clearDeadMark()
381 {
382 checkHeader();
383 m_size &= ~deadBitMask;
384 }
385
386 NO_SANITIZE_ADDRESS
387 void HeapObjectHeader::setDeadMark()
388 {
389 ASSERT(!isMarked());
390 checkHeader();
391 m_size |= deadBitMask;
392 }
393
394 #if ENABLE(ASSERT)
395 NO_SANITIZE_ADDRESS
396 void HeapObjectHeader::zapMagic()
397 {
398 m_magic = zappedMagic;
399 }
400 #endif
401
402 HeapObjectHeader* HeapObjectHeader::fromPayload(const void* payload)
403 {
404 Address addr = reinterpret_cast<Address>(const_cast<void*>(payload));
405 HeapObjectHeader* header =
406 reinterpret_cast<HeapObjectHeader*>(addr - objectHeaderSize);
407 return header;
408 }
409
410 void HeapObjectHeader::finalize(const GCInfo* gcInfo, Address object, size_t obj ectSize)
411 {
412 ASSERT(gcInfo);
413 if (gcInfo->hasFinalizer()) {
414 gcInfo->m_finalize(object);
415 }
416
417 #if ENABLE(ASSERT) || defined(LEAK_SANITIZER) || defined(ADDRESS_SANITIZER)
418 // In Debug builds, memory is zapped when it's freed, and the zapped memory is
419 // zeroed out when the memory is reused. Memory is also zapped when using Le ak
420 // Sanitizer because the heap is used as a root region for LSan and therefor e
421 // pointers in unreachable memory could hide leaks.
422 for (size_t i = 0; i < objectSize; i++)
423 object[i] = finalizedZapValue;
424
425 // Zap the primary vTable entry (secondary vTable entries are not zapped).
426 *(reinterpret_cast<uintptr_t*>(object)) = zappedVTable;
427 #endif
428 // In Release builds, the entire object is zeroed out when it is added to th e free list.
429 // This happens right after sweeping the page and before the thread commence s execution.
430 }
431
432 NO_SANITIZE_ADDRESS
433 void FinalizedHeapObjectHeader::finalize()
434 {
435 HeapObjectHeader::finalize(m_gcInfo, payload(), payloadSize());
436 }
437
438 template<typename Header>
439 void LargeHeapObject<Header>::unmark()
440 {
441 return heapObjectHeader()->unmark();
442 }
443
444 template<typename Header>
445 bool LargeHeapObject<Header>::isMarked()
446 {
447 return heapObjectHeader()->isMarked();
448 }
449
450 template<typename Header>
451 void LargeHeapObject<Header>::setDeadMark()
452 {
453 heapObjectHeader()->setDeadMark();
454 }
455
456 template<typename Header>
457 void LargeHeapObject<Header>::checkAndMarkPointer(Visitor* visitor, Address addr ess)
458 {
459 ASSERT(contains(address));
460 if (!objectContains(address) || heapObjectHeader()->hasDeadMark())
461 return;
462 #if ENABLE(GC_PROFILE_MARKING)
463 visitor->setHostInfo(&address, "stack");
464 #endif
465 mark(visitor);
466 }
467
468 #if ENABLE(ASSERT)
469 static bool isUninitializedMemory(void* objectPointer, size_t objectSize)
470 {
471 // Scan through the object's fields and check that they are all zero.
472 Address* objectFields = reinterpret_cast<Address*>(objectPointer);
473 for (size_t i = 0; i < objectSize / sizeof(Address); ++i) {
474 if (objectFields[i] != 0)
475 return false;
476 }
477 return true;
478 }
479 #endif
480
481 template<>
482 void LargeHeapObject<FinalizedHeapObjectHeader>::mark(Visitor* visitor)
483 {
484 if (heapObjectHeader()->hasVTable() && !vTableInitialized(payload())) {
485 FinalizedHeapObjectHeader* header = heapObjectHeader();
486 visitor->markNoTracing(header);
487 ASSERT(isUninitializedMemory(header->payload(), header->payloadSize()));
488 } else {
489 visitor->mark(heapObjectHeader(), heapObjectHeader()->traceCallback());
490 }
491 }
492
493 template<>
494 void LargeHeapObject<HeapObjectHeader>::mark(Visitor* visitor)
495 {
496 ASSERT(gcInfo());
497 if (gcInfo()->hasVTable() && !vTableInitialized(payload())) {
498 HeapObjectHeader* header = heapObjectHeader();
499 visitor->markNoTracing(header);
500 ASSERT(isUninitializedMemory(header->payload(), header->payloadSize()));
501 } else {
502 visitor->mark(heapObjectHeader(), gcInfo()->m_trace);
503 }
504 }
505
506 template<>
507 void LargeHeapObject<FinalizedHeapObjectHeader>::finalize()
508 {
509 heapObjectHeader()->finalize();
510 }
511
512 template<>
513 void LargeHeapObject<HeapObjectHeader>::finalize()
514 {
515 ASSERT(gcInfo());
516 HeapObjectHeader::finalize(gcInfo(), payload(), payloadSize());
517 }
518
519 FinalizedHeapObjectHeader* FinalizedHeapObjectHeader::fromPayload(const void* pa yload)
520 {
521 Address addr = reinterpret_cast<Address>(const_cast<void*>(payload));
522 FinalizedHeapObjectHeader* header =
523 reinterpret_cast<FinalizedHeapObjectHeader*>(addr - finalizedHeaderSize) ;
524 return header;
525 }
526
527 template<typename Header>
528 ThreadHeap<Header>::ThreadHeap(ThreadState* state, int index)
529 : m_currentAllocationPoint(0)
530 , m_remainingAllocationSize(0)
531 , m_firstPage(0)
532 , m_firstLargeHeapObject(0)
533 , m_firstPageAllocatedDuringSweeping(0)
534 , m_lastPageAllocatedDuringSweeping(0)
535 , m_mergePoint(0)
536 , m_biggestFreeListIndex(0)
537 , m_threadState(state)
538 , m_index(index)
539 , m_numberOfNormalPages(0)
540 , m_promptlyFreedCount(0)
541 {
542 clearFreeLists();
543 }
544
545 template<typename Header>
546 ThreadHeap<Header>::~ThreadHeap()
547 {
548 ASSERT(!m_firstPage);
549 ASSERT(!m_firstLargeHeapObject);
550 }
551
552 template<typename Header>
553 void ThreadHeap<Header>::cleanupPages()
554 {
555 clearFreeLists();
556 flushHeapContainsCache();
557
558 // Add the ThreadHeap's pages to the orphanedPagePool.
559 for (HeapPage<Header>* page = m_firstPage; page; page = page->m_next)
560 Heap::orphanedPagePool()->addOrphanedPage(m_index, page);
561 m_firstPage = 0;
562
563 for (LargeHeapObject<Header>* largeObject = m_firstLargeHeapObject; largeObj ect; largeObject = largeObject->m_next)
564 Heap::orphanedPagePool()->addOrphanedPage(m_index, largeObject);
565 m_firstLargeHeapObject = 0;
566 }
567
568 template<typename Header>
569 Address ThreadHeap<Header>::outOfLineAllocate(size_t size, const GCInfo* gcInfo)
570 {
571 size_t allocationSize = allocationSizeFromSize(size);
572 if (threadState()->shouldGC()) {
573 if (threadState()->shouldForceConservativeGC())
574 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
575 else
576 threadState()->setGCRequested();
577 }
578 ensureCurrentAllocation(allocationSize, gcInfo);
579 return allocate(size, gcInfo);
580 }
581
582 template<typename Header>
583 bool ThreadHeap<Header>::allocateFromFreeList(size_t minSize)
584 {
585 size_t bucketSize = 1 << m_biggestFreeListIndex;
586 int i = m_biggestFreeListIndex;
587 for (; i > 0; i--, bucketSize >>= 1) {
588 if (bucketSize < minSize)
589 break;
590 FreeListEntry* entry = m_freeLists[i];
591 if (entry) {
592 m_biggestFreeListIndex = i;
593 entry->unlink(&m_freeLists[i]);
594 setAllocationPoint(entry->address(), entry->size());
595 ASSERT(currentAllocationPoint() && remainingAllocationSize() >= minS ize);
596 return true;
597 }
598 }
599 m_biggestFreeListIndex = i;
600 return false;
601 }
602
603 template<typename Header>
604 void ThreadHeap<Header>::ensureCurrentAllocation(size_t minSize, const GCInfo* g cInfo)
605 {
606 ASSERT(minSize >= allocationGranularity);
607 if (remainingAllocationSize() >= minSize)
608 return;
609
610 if (remainingAllocationSize() > 0)
611 addToFreeList(currentAllocationPoint(), remainingAllocationSize());
612 if (allocateFromFreeList(minSize))
613 return;
614 if (coalesce(minSize) && allocateFromFreeList(minSize))
615 return;
616 addPageToHeap(gcInfo);
617 bool success = allocateFromFreeList(minSize);
618 RELEASE_ASSERT(success);
619 }
620
621 template<typename Header>
622 BaseHeapPage* ThreadHeap<Header>::heapPageFromAddress(Address address)
623 {
624 for (HeapPage<Header>* page = m_firstPage; page; page = page->next()) {
625 if (page->contains(address))
626 return page;
627 }
628 for (HeapPage<Header>* page = m_firstPageAllocatedDuringSweeping; page; page = page->next()) {
629 if (page->contains(address))
630 return page;
631 }
632 for (LargeHeapObject<Header>* current = m_firstLargeHeapObject; current; cur rent = current->next()) {
633 // Check that large pages are blinkPageSize aligned (modulo the
634 // osPageSize for the guard page).
635 ASSERT(reinterpret_cast<Address>(current) - osPageSize() == roundToBlink PageStart(reinterpret_cast<Address>(current)));
636 if (current->contains(address))
637 return current;
638 }
639 return 0;
640 }
641
642 #if ENABLE(GC_PROFILE_MARKING)
643 template<typename Header>
644 const GCInfo* ThreadHeap<Header>::findGCInfoOfLargeHeapObject(Address address)
645 {
646 for (LargeHeapObject<Header>* current = m_firstLargeHeapObject; current; cur rent = current->next()) {
647 if (current->contains(address))
648 return current->gcInfo();
649 }
650 return 0;
651 }
652 #endif
653
654 #if ENABLE(GC_PROFILE_HEAP)
655 #define GC_PROFILE_HEAP_PAGE_SNAPSHOT_THRESHOLD 0
656 template<typename Header>
657 void ThreadHeap<Header>::snapshot(TracedValue* json, ThreadState::SnapshotInfo* info)
658 {
659 size_t previousPageCount = info->pageCount;
660
661 json->beginArray("pages");
662 for (HeapPage<Header>* page = m_firstPage; page; page = page->next(), ++info ->pageCount) {
663 // FIXME: To limit the size of the snapshot we only output "threshold" m any page snapshots.
664 if (info->pageCount < GC_PROFILE_HEAP_PAGE_SNAPSHOT_THRESHOLD) {
665 json->beginArray();
666 json->pushInteger(reinterpret_cast<intptr_t>(page));
667 page->snapshot(json, info);
668 json->endArray();
669 } else {
670 page->snapshot(0, info);
671 }
672 }
673 json->endArray();
674
675 json->beginArray("largeObjects");
676 for (LargeHeapObject<Header>* current = m_firstLargeHeapObject; current; cur rent = current->next()) {
677 json->beginDictionary();
678 current->snapshot(json, info);
679 json->endDictionary();
680 }
681 json->endArray();
682
683 json->setInteger("pageCount", info->pageCount - previousPageCount);
684 }
685 #endif
686
687 template<typename Header>
688 void ThreadHeap<Header>::addToFreeList(Address address, size_t size)
689 {
690 ASSERT(heapPageFromAddress(address));
691 ASSERT(heapPageFromAddress(address + size - 1));
692 ASSERT(size < blinkPagePayloadSize());
693 // The free list entries are only pointer aligned (but when we allocate
694 // from them we are 8 byte aligned due to the header size).
695 ASSERT(!((reinterpret_cast<uintptr_t>(address) + sizeof(Header)) & allocatio nMask));
696 ASSERT(!(size & allocationMask));
697 ASAN_POISON_MEMORY_REGION(address, size);
698 FreeListEntry* entry;
699 if (size < sizeof(*entry)) {
700 // Create a dummy header with only a size and freelist bit set.
701 ASSERT(size >= sizeof(BasicObjectHeader));
702 // Free list encode the size to mark the lost memory as freelist memory.
703 new (NotNull, address) BasicObjectHeader(BasicObjectHeader::freeListEnco dedSize(size));
704 // This memory gets lost. Sweeping can reclaim it.
705 return;
706 }
707 entry = new (NotNull, address) FreeListEntry(size);
708 #if defined(ADDRESS_SANITIZER)
709 // For ASan we don't add the entry to the free lists until the asanDeferMemo ryReuseCount
710 // reaches zero. However we always add entire pages to ensure that adding a new page will
711 // increase the allocation space.
712 if (HeapPage<Header>::payloadSize() != size && !entry->shouldAddToFreeList() )
713 return;
714 #endif
715 int index = bucketIndexForSize(size);
716 entry->link(&m_freeLists[index]);
717 if (!m_lastFreeListEntries[index])
718 m_lastFreeListEntries[index] = entry;
719 if (index > m_biggestFreeListIndex)
720 m_biggestFreeListIndex = index;
721 }
722
723 template<typename Header>
724 void ThreadHeap<Header>::promptlyFreeObject(Header* header)
725 {
726 ASSERT(!m_threadState->isSweepInProgress());
727 header->checkHeader();
728 Address address = reinterpret_cast<Address>(header);
729 Address payload = header->payload();
730 size_t size = header->size();
731 size_t payloadSize = header->payloadSize();
732 BaseHeapPage* page = pageHeaderFromObject(address);
733 ASSERT(size > 0);
734 ASSERT(page == heapPageFromAddress(address));
735
736 {
737 ThreadState::NoSweepScope scope(m_threadState);
738 HeapObjectHeader::finalize(header->gcInfo(), payload, payloadSize);
739 #if !ENABLE(ASSERT) && !defined(LEAK_SANITIZER) && !defined(ADDRESS_SANITIZER)
740 memset(payload, 0, payloadSize);
741 #endif
742 header->markPromptlyFreed();
743 }
744
745 page->addToPromptlyFreedSize(size);
746 m_promptlyFreedCount++;
747 }
748
749 template<typename Header>
750 bool ThreadHeap<Header>::coalesce(size_t minSize)
751 {
752 if (m_threadState->isSweepInProgress())
753 return false;
754
755 if (m_promptlyFreedCount < 256)
756 return false;
757
758 // The smallest bucket able to satisfy an allocation request for minSize is
759 // the bucket where all free-list entries are guarantied to be larger than
760 // minSize. That bucket is one larger than the bucket minSize would go into.
761 size_t neededBucketIndex = bucketIndexForSize(minSize) + 1;
762 size_t neededFreeEntrySize = 1 << neededBucketIndex;
763 size_t neededPromptlyFreedSize = neededFreeEntrySize * 3;
764 size_t foundFreeEntrySize = 0;
765
766 // Bailout early on large requests because it is unlikely we will find a fre e-list entry.
767 if (neededPromptlyFreedSize >= blinkPageSize)
768 return false;
769
770 TRACE_EVENT_BEGIN2("blink_gc", "ThreadHeap::coalesce" , "requestedSize", (un signed)minSize , "neededSize", (unsigned)neededFreeEntrySize);
771
772 // Search for a coalescing candidate.
773 ASSERT(!ownsNonEmptyAllocationArea());
774 size_t pageCount = 0;
775 HeapPage<Header>* page = m_firstPage;
776 while (page) {
777 // Only consider one of the first 'n' pages. A "younger" page is more li kely to have freed backings.
778 if (++pageCount > numberOfPagesToConsiderForCoalescing) {
779 page = 0;
780 break;
781 }
782 // Only coalesce pages with "sufficient" promptly freed space.
783 if (page->promptlyFreedSize() >= neededPromptlyFreedSize) {
784 break;
785 }
786 page = page->next();
787 }
788
789 // If we found a likely candidate, fully coalesce all its promptly-freed ent ries.
790 if (page) {
791 page->clearObjectStartBitMap();
792 page->resetPromptlyFreedSize();
793 size_t freedCount = 0;
794 Address startOfGap = page->payload();
795 for (Address headerAddress = startOfGap; headerAddress < page->end(); ) {
796 BasicObjectHeader* basicHeader = reinterpret_cast<BasicObjectHeader* >(headerAddress);
797 ASSERT(basicHeader->size() > 0);
798 ASSERT(basicHeader->size() < blinkPagePayloadSize());
799
800 if (basicHeader->isPromptlyFreed()) {
801 stats().decreaseObjectSpace(reinterpret_cast<Header*>(basicHeade r)->payloadSize());
802 size_t size = basicHeader->size();
803 ASSERT(size >= sizeof(Header));
804 #if !ENABLE(ASSERT) && !defined(LEAK_SANITIZER) && !defined(ADDRESS_SANITIZER)
805 memset(headerAddress, 0, sizeof(Header));
806 #endif
807 ++freedCount;
808 headerAddress += size;
809 continue;
810 }
811
812 if (startOfGap != headerAddress) {
813 size_t size = headerAddress - startOfGap;
814 addToFreeList(startOfGap, size);
815 if (size > foundFreeEntrySize)
816 foundFreeEntrySize = size;
817 }
818
819 headerAddress += basicHeader->size();
820 startOfGap = headerAddress;
821 }
822
823 if (startOfGap != page->end()) {
824 size_t size = page->end() - startOfGap;
825 addToFreeList(startOfGap, size);
826 if (size > foundFreeEntrySize)
827 foundFreeEntrySize = size;
828 }
829
830 // Check before subtracting because freedCount might not be balanced wit h freed entries.
831 if (freedCount < m_promptlyFreedCount)
832 m_promptlyFreedCount -= freedCount;
833 else
834 m_promptlyFreedCount = 0;
835 }
836
837 TRACE_EVENT_END1("blink_gc", "ThreadHeap::coalesce", "foundFreeEntrySize", ( unsigned)foundFreeEntrySize);
838
839 if (foundFreeEntrySize < neededFreeEntrySize) {
840 // If coalescing failed, reset the freed count to delay coalescing again .
841 m_promptlyFreedCount = 0;
842 return false;
843 }
844
845 return true;
846 }
847
848 template<typename Header>
849 Address ThreadHeap<Header>::allocateLargeObject(size_t size, const GCInfo* gcInf o)
850 {
851 // Caller already added space for object header and rounded up to allocation alignment
852 ASSERT(!(size & allocationMask));
853
854 size_t allocationSize = sizeof(LargeHeapObject<Header>) + size;
855
856 // Ensure that there is enough space for alignment. If the header
857 // is not a multiple of 8 bytes we will allocate an extra
858 // headerPadding<Header> bytes to ensure it 8 byte aligned.
859 allocationSize += headerPadding<Header>();
860
861 // If ASan is supported we add allocationGranularity bytes to the allocated space and
862 // poison that to detect overflows
863 #if defined(ADDRESS_SANITIZER)
864 allocationSize += allocationGranularity;
865 #endif
866 if (threadState()->shouldGC())
867 threadState()->setGCRequested();
868 Heap::flushHeapDoesNotContainCache();
869 PageMemory* pageMemory = PageMemory::allocate(allocationSize);
870 Address largeObjectAddress = pageMemory->writableStart();
871 Address headerAddress = largeObjectAddress + sizeof(LargeHeapObject<Header>) + headerPadding<Header>();
872 memset(headerAddress, 0, size);
873 Header* header = new (NotNull, headerAddress) Header(size, gcInfo);
874 Address result = headerAddress + sizeof(*header);
875 ASSERT(!(reinterpret_cast<uintptr_t>(result) & allocationMask));
876 LargeHeapObject<Header>* largeObject = new (largeObjectAddress) LargeHeapObj ect<Header>(pageMemory, gcInfo, threadState());
877
878 // Poison the object header and allocationGranularity bytes after the object
879 ASAN_POISON_MEMORY_REGION(header, sizeof(*header));
880 ASAN_POISON_MEMORY_REGION(largeObject->address() + largeObject->size(), allo cationGranularity);
881 largeObject->link(&m_firstLargeHeapObject);
882 stats().increaseAllocatedSpace(largeObject->size());
883 stats().increaseObjectSpace(largeObject->payloadSize());
884 return result;
885 }
886
887 template<typename Header>
888 void ThreadHeap<Header>::freeLargeObject(LargeHeapObject<Header>* object, LargeH eapObject<Header>** previousNext)
889 {
890 flushHeapContainsCache();
891 object->unlink(previousNext);
892 object->finalize();
893
894 // Unpoison the object header and allocationGranularity bytes after the
895 // object before freeing.
896 ASAN_UNPOISON_MEMORY_REGION(object->heapObjectHeader(), sizeof(Header));
897 ASAN_UNPOISON_MEMORY_REGION(object->address() + object->size(), allocationGr anularity);
898
899 if (object->terminating()) {
900 ASSERT(ThreadState::current()->isTerminating());
901 // The thread is shutting down so this object is being removed as part
902 // of a thread local GC. In that case the object could be traced in the
903 // next global GC either due to a dead object being traced via a
904 // conservative pointer or due to a programming error where an object
905 // in another thread heap keeps a dangling pointer to this object.
906 // To guard against this we put the large object memory in the
907 // orphanedPagePool to ensure it is still reachable. After the next glob al
908 // GC it can be released assuming no rogue/dangling pointers refer to
909 // it.
910 // NOTE: large objects are not moved to the free page pool as it is
911 // unlikely they can be reused due to their individual sizes.
912 Heap::orphanedPagePool()->addOrphanedPage(m_index, object);
913 } else {
914 ASSERT(!ThreadState::current()->isTerminating());
915 PageMemory* memory = object->storage();
916 object->~LargeHeapObject<Header>();
917 delete memory;
918 }
919 }
920
921 template<typename DataType>
922 PagePool<DataType>::PagePool()
923 {
924 for (int i = 0; i < NumberOfHeaps; ++i) {
925 m_pool[i] = 0;
926 }
927 }
928
929 FreePagePool::~FreePagePool()
930 {
931 for (int index = 0; index < NumberOfHeaps; ++index) {
932 while (PoolEntry* entry = m_pool[index]) {
933 m_pool[index] = entry->next;
934 PageMemory* memory = entry->data;
935 ASSERT(memory);
936 delete memory;
937 delete entry;
938 }
939 }
940 }
941
942 void FreePagePool::addFreePage(int index, PageMemory* memory)
943 {
944 // When adding a page to the pool we decommit it to ensure it is unused
945 // while in the pool. This also allows the physical memory, backing the
946 // page, to be given back to the OS.
947 memory->decommit();
948 MutexLocker locker(m_mutex[index]);
949 PoolEntry* entry = new PoolEntry(memory, m_pool[index]);
950 m_pool[index] = entry;
951 }
952
953 PageMemory* FreePagePool::takeFreePage(int index)
954 {
955 MutexLocker locker(m_mutex[index]);
956 while (PoolEntry* entry = m_pool[index]) {
957 m_pool[index] = entry->next;
958 PageMemory* memory = entry->data;
959 ASSERT(memory);
960 delete entry;
961 if (memory->commit())
962 return memory;
963
964 // We got some memory, but failed to commit it, try again.
965 delete memory;
966 }
967 return 0;
968 }
969
970 OrphanedPagePool::~OrphanedPagePool()
971 {
972 for (int index = 0; index < NumberOfHeaps; ++index) {
973 while (PoolEntry* entry = m_pool[index]) {
974 m_pool[index] = entry->next;
975 BaseHeapPage* page = entry->data;
976 delete entry;
977 PageMemory* memory = page->storage();
978 ASSERT(memory);
979 page->~BaseHeapPage();
980 delete memory;
981 }
982 }
983 }
984
985 void OrphanedPagePool::addOrphanedPage(int index, BaseHeapPage* page)
986 {
987 page->markOrphaned();
988 PoolEntry* entry = new PoolEntry(page, m_pool[index]);
989 m_pool[index] = entry;
990 }
991
992 NO_SANITIZE_ADDRESS
993 void OrphanedPagePool::decommitOrphanedPages()
994 {
995 #if ENABLE(ASSERT)
996 // No locking needed as all threads are at safepoints at this point in time.
997 ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThreads( );
998 for (ThreadState::AttachedThreadStateSet::iterator it = threads.begin(), end = threads.end(); it != end; ++it)
999 ASSERT((*it)->isAtSafePoint());
1000 #endif
1001
1002 for (int index = 0; index < NumberOfHeaps; ++index) {
1003 PoolEntry* entry = m_pool[index];
1004 PoolEntry** prevNext = &m_pool[index];
1005 while (entry) {
1006 BaseHeapPage* page = entry->data;
1007 if (page->tracedAfterOrphaned()) {
1008 // If the orphaned page was traced in the last GC it is not
1009 // decommited. We only decommit a page, ie. put it in the
1010 // memory pool, when the page has no objects pointing to it.
1011 // We remark the page as orphaned to clear the tracedAfterOrphan ed
1012 // flag and any object trace bits that were set during tracing.
1013 page->markOrphaned();
1014 prevNext = &entry->next;
1015 entry = entry->next;
1016 continue;
1017 }
1018
1019 // Page was not traced. Check if we should reuse the memory or just
1020 // free it. Large object memory is not reused, but freed, normal
1021 // blink heap pages are reused.
1022 // NOTE: We call the destructor before freeing or adding to the
1023 // free page pool.
1024 PageMemory* memory = page->storage();
1025 if (page->isLargeObject()) {
1026 page->~BaseHeapPage();
1027 delete memory;
1028 } else {
1029 page->~BaseHeapPage();
1030 // Clear out the page's memory before adding it to the free page
1031 // pool to ensure it is zero filled when being reused.
1032 clearMemory(memory);
1033 Heap::freePagePool()->addFreePage(index, memory);
1034 }
1035
1036 PoolEntry* deadEntry = entry;
1037 entry = entry->next;
1038 *prevNext = entry;
1039 delete deadEntry;
1040 }
1041 }
1042 }
1043
1044 NO_SANITIZE_ADDRESS
1045 void OrphanedPagePool::clearMemory(PageMemory* memory)
1046 {
1047 #if defined(ADDRESS_SANITIZER)
1048 // Don't use memset when running with ASan since this needs to zap
1049 // poisoned memory as well and the NO_SANITIZE_ADDRESS annotation
1050 // only works for code in this method and not for calls to memset.
1051 Address base = memory->writableStart();
1052 for (Address current = base; current < base + blinkPagePayloadSize(); ++curr ent)
1053 *current = 0;
1054 #else
1055 memset(memory->writableStart(), 0, blinkPagePayloadSize());
1056 #endif
1057 }
1058
1059 #if ENABLE(ASSERT)
1060 bool OrphanedPagePool::contains(void* object)
1061 {
1062 for (int index = 0; index < NumberOfHeaps; ++index) {
1063 for (PoolEntry* entry = m_pool[index]; entry; entry = entry->next) {
1064 BaseHeapPage* page = entry->data;
1065 if (page->contains(reinterpret_cast<Address>(object)))
1066 return true;
1067 }
1068 }
1069 return false;
1070 }
1071 #endif
1072
1073 template<>
1074 void ThreadHeap<FinalizedHeapObjectHeader>::addPageToHeap(const GCInfo* gcInfo)
1075 {
1076 // When adding a page to the ThreadHeap using FinalizedHeapObjectHeaders the GCInfo on
1077 // the heap should be unused (ie. 0).
1078 allocatePage(0);
1079 }
1080
1081 template<>
1082 void ThreadHeap<HeapObjectHeader>::addPageToHeap(const GCInfo* gcInfo)
1083 {
1084 // When adding a page to the ThreadHeap using HeapObjectHeaders store the GC Info on the heap
1085 // since it is the same for all objects
1086 ASSERT(gcInfo);
1087 allocatePage(gcInfo);
1088 }
1089
1090 template <typename Header>
1091 void ThreadHeap<Header>::removePageFromHeap(HeapPage<Header>* page)
1092 {
1093 MutexLocker locker(m_threadState->sweepMutex());
1094 flushHeapContainsCache();
1095 if (page->terminating()) {
1096 // The thread is shutting down so this page is being removed as part
1097 // of a thread local GC. In that case the page could be accessed in the
1098 // next global GC either due to a dead object being traced via a
1099 // conservative pointer or due to a programming error where an object
1100 // in another thread heap keeps a dangling pointer to this object.
1101 // To guard against this we put the page in the orphanedPagePool to
1102 // ensure it is still reachable. After the next global GC it can be
1103 // decommitted and moved to the page pool assuming no rogue/dangling
1104 // pointers refer to it.
1105 Heap::orphanedPagePool()->addOrphanedPage(m_index, page);
1106 } else {
1107 PageMemory* memory = page->storage();
1108 page->~HeapPage<Header>();
1109 Heap::freePagePool()->addFreePage(m_index, memory);
1110 }
1111 }
1112
1113 template<typename Header>
1114 void ThreadHeap<Header>::allocatePage(const GCInfo* gcInfo)
1115 {
1116 Heap::flushHeapDoesNotContainCache();
1117 PageMemory* pageMemory = Heap::freePagePool()->takeFreePage(m_index);
1118 // We continue allocating page memory until we succeed in getting one.
1119 // Since the FreePagePool is global other threads could use all the
1120 // newly allocated page memory before this thread calls takeFreePage.
1121 while (!pageMemory) {
1122 // Allocate a memory region for blinkPagesPerRegion pages that
1123 // will each have the following layout.
1124 //
1125 // [ guard os page | ... payload ... | guard os page ]
1126 // ^---{ aligned to blink page size }
1127 PageMemoryRegion* region = PageMemoryRegion::allocate(blinkPageSize * bl inkPagesPerRegion, blinkPagesPerRegion);
1128 // Setup the PageMemory object for each of the pages in the
1129 // region.
1130 size_t offset = 0;
1131 for (size_t i = 0; i < blinkPagesPerRegion; i++) {
1132 Heap::freePagePool()->addFreePage(m_index, PageMemory::setupPageMemo ryInRegion(region, offset, blinkPagePayloadSize()));
1133 offset += blinkPageSize;
1134 }
1135 pageMemory = Heap::freePagePool()->takeFreePage(m_index);
1136 }
1137 HeapPage<Header>* page = new (pageMemory->writableStart()) HeapPage<Header>( pageMemory, this, gcInfo);
1138 // Use a separate list for pages allocated during sweeping to make
1139 // sure that we do not accidentally sweep objects that have been
1140 // allocated during sweeping.
1141 if (m_threadState->isSweepInProgress()) {
1142 if (!m_lastPageAllocatedDuringSweeping)
1143 m_lastPageAllocatedDuringSweeping = page;
1144 page->link(&m_firstPageAllocatedDuringSweeping);
1145 } else {
1146 page->link(&m_firstPage);
1147 }
1148 ++m_numberOfNormalPages;
1149 addToFreeList(page->payload(), HeapPage<Header>::payloadSize());
1150 }
1151
1152 #if ENABLE(ASSERT)
1153 template<typename Header>
1154 bool ThreadHeap<Header>::pagesToBeSweptContains(Address address)
1155 {
1156 for (HeapPage<Header>* page = m_firstPage; page; page = page->next()) {
1157 if (page->contains(address))
1158 return true;
1159 }
1160 return false;
1161 }
1162
1163 template<typename Header>
1164 bool ThreadHeap<Header>::pagesAllocatedDuringSweepingContains(Address address)
1165 {
1166 for (HeapPage<Header>* page = m_firstPageAllocatedDuringSweeping; page; page = page->next()) {
1167 if (page->contains(address))
1168 return true;
1169 }
1170 return false;
1171 }
1172
1173 template<typename Header>
1174 void ThreadHeap<Header>::getScannedStats(HeapStats& scannedStats)
1175 {
1176 ASSERT(!m_firstPageAllocatedDuringSweeping);
1177 for (HeapPage<Header>* page = m_firstPage; page; page = page->next())
1178 page->getStats(scannedStats);
1179 for (LargeHeapObject<Header>* current = m_firstLargeHeapObject; current; cur rent = current->next())
1180 current->getStats(scannedStats);
1181 }
1182 #endif
1183
1184 template<typename Header>
1185 void ThreadHeap<Header>::sweepNormalPages(HeapStats* stats)
1186 {
1187 HeapPage<Header>* page = m_firstPage;
1188 HeapPage<Header>** previousNext = &m_firstPage;
1189 HeapPage<Header>* previous = 0;
1190 while (page) {
1191 page->resetPromptlyFreedSize();
1192 if (page->isEmpty()) {
1193 HeapPage<Header>* unused = page;
1194 if (unused == m_mergePoint)
1195 m_mergePoint = previous;
1196 page = page->next();
1197 HeapPage<Header>::unlink(this, unused, previousNext);
1198 --m_numberOfNormalPages;
1199 } else {
1200 page->sweep(stats, this);
1201 previousNext = &page->m_next;
1202 previous = page;
1203 page = page->next();
1204 }
1205 }
1206 }
1207
1208 template<typename Header>
1209 void ThreadHeap<Header>::sweepLargePages(HeapStats* stats)
1210 {
1211 LargeHeapObject<Header>** previousNext = &m_firstLargeHeapObject;
1212 for (LargeHeapObject<Header>* current = m_firstLargeHeapObject; current;) {
1213 if (current->isMarked()) {
1214 stats->increaseAllocatedSpace(current->size());
1215 stats->increaseObjectSpace(current->payloadSize());
1216 current->unmark();
1217 previousNext = &current->m_next;
1218 current = current->next();
1219 } else {
1220 LargeHeapObject<Header>* next = current->next();
1221 freeLargeObject(current, previousNext);
1222 current = next;
1223 }
1224 }
1225 }
1226
1227
1228 // STRICT_ASAN_finalIZATION_CHECKING turns on poisoning of all objects during
1229 // sweeping to catch cases where dead objects touch each other. This is not
1230 // turned on by default because it also triggers for cases that are safe.
1231 // Examples of such safe cases are context life cycle observers and timers
1232 // embedded in garbage collected objects.
1233 #define STRICT_ASAN_finalIZATION_CHECKING 0
1234
1235 template<typename Header>
1236 void ThreadHeap<Header>::sweep(HeapStats* stats)
1237 {
1238 ASSERT(isConsistentForSweeping());
1239 #if defined(ADDRESS_SANITIZER) && STRICT_ASAN_finalIZATION_CHECKING
1240 // When using ASan do a pre-sweep where all unmarked objects are
1241 // poisoned before calling their finalizer methods. This can catch
1242 // the case where the finalizer of an object tries to modify
1243 // another object as part of finalization.
1244 for (HeapPage<Header>* page = m_firstPage; page; page = page->next())
1245 page->poisonUnmarkedObjects();
1246 #endif
1247 sweepNormalPages(stats);
1248 sweepLargePages(stats);
1249 }
1250
1251 template<typename Header>
1252 void ThreadHeap<Header>::postSweepProcessing()
1253 {
1254 // If pages have been allocated during sweeping, link them into
1255 // the list of pages.
1256 if (m_firstPageAllocatedDuringSweeping) {
1257 m_lastPageAllocatedDuringSweeping->m_next = m_firstPage;
1258 m_firstPage = m_firstPageAllocatedDuringSweeping;
1259 m_lastPageAllocatedDuringSweeping = 0;
1260 m_firstPageAllocatedDuringSweeping = 0;
1261 }
1262 }
1263
1264 #if ENABLE(ASSERT)
1265 template<typename Header>
1266 bool ThreadHeap<Header>::isConsistentForSweeping()
1267 {
1268 // A thread heap is consistent for sweeping if none of the pages to
1269 // be swept contain a freelist block or the current allocation
1270 // point.
1271 for (size_t i = 0; i < blinkPageSizeLog2; i++) {
1272 for (FreeListEntry* freeListEntry = m_freeLists[i]; freeListEntry; freeL istEntry = freeListEntry->next()) {
1273 if (pagesToBeSweptContains(freeListEntry->address())) {
1274 return false;
1275 }
1276 ASSERT(pagesAllocatedDuringSweepingContains(freeListEntry->address() ));
1277 }
1278 }
1279 if (ownsNonEmptyAllocationArea()) {
1280 ASSERT(pagesToBeSweptContains(currentAllocationPoint())
1281 || pagesAllocatedDuringSweepingContains(currentAllocationPoint()));
1282 return !pagesToBeSweptContains(currentAllocationPoint());
1283 }
1284 return true;
1285 }
1286 #endif
1287
1288 template<typename Header>
1289 void ThreadHeap<Header>::makeConsistentForSweeping()
1290 {
1291 if (ownsNonEmptyAllocationArea())
1292 addToFreeList(currentAllocationPoint(), remainingAllocationSize());
1293 setAllocationPoint(0, 0);
1294 clearFreeLists();
1295 }
1296
1297 template<typename Header>
1298 void ThreadHeap<Header>::clearLiveAndMarkDead()
1299 {
1300 ASSERT(isConsistentForSweeping());
1301 for (HeapPage<Header>* page = m_firstPage; page; page = page->next())
1302 page->clearLiveAndMarkDead();
1303 for (LargeHeapObject<Header>* current = m_firstLargeHeapObject; current; cur rent = current->next()) {
1304 if (current->isMarked())
1305 current->unmark();
1306 else
1307 current->setDeadMark();
1308 }
1309 }
1310
1311 template<typename Header>
1312 void ThreadHeap<Header>::clearFreeLists()
1313 {
1314 m_promptlyFreedCount = 0;
1315 for (size_t i = 0; i < blinkPageSizeLog2; i++) {
1316 m_freeLists[i] = 0;
1317 m_lastFreeListEntries[i] = 0;
1318 }
1319 }
1320
1321 int BaseHeap::bucketIndexForSize(size_t size)
1322 {
1323 ASSERT(size > 0);
1324 int index = -1;
1325 while (size) {
1326 size >>= 1;
1327 index++;
1328 }
1329 return index;
1330 }
1331
1332 template<typename Header>
1333 HeapPage<Header>::HeapPage(PageMemory* storage, ThreadHeap<Header>* heap, const GCInfo* gcInfo)
1334 : BaseHeapPage(storage, gcInfo, heap->threadState())
1335 , m_next(0)
1336 {
1337 COMPILE_ASSERT(!(sizeof(HeapPage<Header>) & allocationMask), page_header_inc orrectly_aligned);
1338 m_objectStartBitMapComputed = false;
1339 ASSERT(isPageHeaderAddress(reinterpret_cast<Address>(this)));
1340 heap->stats().increaseAllocatedSpace(blinkPageSize);
1341 }
1342
1343 template<typename Header>
1344 void HeapPage<Header>::link(HeapPage** prevNext)
1345 {
1346 m_next = *prevNext;
1347 *prevNext = this;
1348 }
1349
1350 template<typename Header>
1351 void HeapPage<Header>::unlink(ThreadHeap<Header>* heap, HeapPage* unused, HeapPa ge** prevNext)
1352 {
1353 *prevNext = unused->m_next;
1354 heap->removePageFromHeap(unused);
1355 }
1356
1357 template<typename Header>
1358 void HeapPage<Header>::getStats(HeapStats& stats)
1359 {
1360 stats.increaseAllocatedSpace(blinkPageSize);
1361 Address headerAddress = payload();
1362 ASSERT(headerAddress != end());
1363 do {
1364 Header* header = reinterpret_cast<Header*>(headerAddress);
1365 if (!header->isFree())
1366 stats.increaseObjectSpace(header->payloadSize());
1367 ASSERT(header->size() < blinkPagePayloadSize());
1368 headerAddress += header->size();
1369 ASSERT(headerAddress <= end());
1370 } while (headerAddress < end());
1371 }
1372
1373 template<typename Header>
1374 bool HeapPage<Header>::isEmpty()
1375 {
1376 BasicObjectHeader* header = reinterpret_cast<BasicObjectHeader*>(payload());
1377 return header->isFree() && (header->size() == payloadSize());
1378 }
1379
1380 template<typename Header>
1381 void HeapPage<Header>::sweep(HeapStats* stats, ThreadHeap<Header>* heap)
1382 {
1383 clearObjectStartBitMap();
1384 stats->increaseAllocatedSpace(blinkPageSize);
1385 Address startOfGap = payload();
1386 for (Address headerAddress = startOfGap; headerAddress < end(); ) {
1387 BasicObjectHeader* basicHeader = reinterpret_cast<BasicObjectHeader*>(he aderAddress);
1388 ASSERT(basicHeader->size() > 0);
1389 ASSERT(basicHeader->size() < blinkPagePayloadSize());
1390
1391 if (basicHeader->isFree()) {
1392 size_t size = basicHeader->size();
1393 #if !ENABLE(ASSERT) && !defined(LEAK_SANITIZER) && !defined(ADDRESS_SANITIZER)
1394 // Zero the memory in the free list header to maintain the
1395 // invariant that memory on the free list is zero filled.
1396 // The rest of the memory is already on the free list and is
1397 // therefore already zero filled.
1398 if (size < sizeof(FreeListEntry))
1399 memset(headerAddress, 0, size);
1400 else
1401 memset(headerAddress, 0, sizeof(FreeListEntry));
1402 #endif
1403 headerAddress += size;
1404 continue;
1405 }
1406 // At this point we know this is a valid object of type Header
1407 Header* header = static_cast<Header*>(basicHeader);
1408
1409 if (!header->isMarked()) {
1410 // For ASan we unpoison the specific object when calling the finaliz er and
1411 // poison it again when done to allow the object's own finalizer to operate
1412 // on the object, but not have other finalizers be allowed to access it.
1413 ASAN_UNPOISON_MEMORY_REGION(header->payload(), header->payloadSize() );
1414 finalize(header);
1415 size_t size = header->size();
1416 #if !ENABLE(ASSERT) && !defined(LEAK_SANITIZER) && !defined(ADDRESS_SANITIZER)
1417 // This memory will be added to the freelist. Maintain the invariant
1418 // that memory on the freelist is zero filled.
1419 memset(headerAddress, 0, size);
1420 #endif
1421 ASAN_POISON_MEMORY_REGION(header->payload(), header->payloadSize());
1422 headerAddress += size;
1423 continue;
1424 }
1425
1426 if (startOfGap != headerAddress)
1427 heap->addToFreeList(startOfGap, headerAddress - startOfGap);
1428 header->unmark();
1429 headerAddress += header->size();
1430 stats->increaseObjectSpace(header->payloadSize());
1431 startOfGap = headerAddress;
1432 }
1433 if (startOfGap != end())
1434 heap->addToFreeList(startOfGap, end() - startOfGap);
1435 }
1436
1437 template<typename Header>
1438 void HeapPage<Header>::clearLiveAndMarkDead()
1439 {
1440 for (Address headerAddress = payload(); headerAddress < end();) {
1441 Header* header = reinterpret_cast<Header*>(headerAddress);
1442 ASSERT(header->size() < blinkPagePayloadSize());
1443 // Check if a free list entry first since we cannot call
1444 // isMarked on a free list entry.
1445 if (header->isFree()) {
1446 headerAddress += header->size();
1447 continue;
1448 }
1449 if (header->isMarked())
1450 header->unmark();
1451 else
1452 header->setDeadMark();
1453 headerAddress += header->size();
1454 }
1455 }
1456
1457 template<typename Header>
1458 void HeapPage<Header>::populateObjectStartBitMap()
1459 {
1460 memset(&m_objectStartBitMap, 0, objectStartBitMapSize);
1461 Address start = payload();
1462 for (Address headerAddress = start; headerAddress < end();) {
1463 Header* header = reinterpret_cast<Header*>(headerAddress);
1464 size_t objectOffset = headerAddress - start;
1465 ASSERT(!(objectOffset & allocationMask));
1466 size_t objectStartNumber = objectOffset / allocationGranularity;
1467 size_t mapIndex = objectStartNumber / 8;
1468 ASSERT(mapIndex < objectStartBitMapSize);
1469 m_objectStartBitMap[mapIndex] |= (1 << (objectStartNumber & 7));
1470 headerAddress += header->size();
1471 ASSERT(headerAddress <= end());
1472 }
1473 m_objectStartBitMapComputed = true;
1474 }
1475
1476 template<typename Header>
1477 void HeapPage<Header>::clearObjectStartBitMap()
1478 {
1479 m_objectStartBitMapComputed = false;
1480 }
1481
1482 static int numberOfLeadingZeroes(uint8_t byte)
1483 {
1484 if (!byte)
1485 return 8;
1486 int result = 0;
1487 if (byte <= 0x0F) {
1488 result += 4;
1489 byte = byte << 4;
1490 }
1491 if (byte <= 0x3F) {
1492 result += 2;
1493 byte = byte << 2;
1494 }
1495 if (byte <= 0x7F)
1496 result++;
1497 return result;
1498 }
1499
1500 template<typename Header>
1501 Header* HeapPage<Header>::findHeaderFromAddress(Address address)
1502 {
1503 if (address < payload())
1504 return 0;
1505 if (!isObjectStartBitMapComputed())
1506 populateObjectStartBitMap();
1507 size_t objectOffset = address - payload();
1508 size_t objectStartNumber = objectOffset / allocationGranularity;
1509 size_t mapIndex = objectStartNumber / 8;
1510 ASSERT(mapIndex < objectStartBitMapSize);
1511 size_t bit = objectStartNumber & 7;
1512 uint8_t byte = m_objectStartBitMap[mapIndex] & ((1 << (bit + 1)) - 1);
1513 while (!byte) {
1514 ASSERT(mapIndex > 0);
1515 byte = m_objectStartBitMap[--mapIndex];
1516 }
1517 int leadingZeroes = numberOfLeadingZeroes(byte);
1518 objectStartNumber = (mapIndex * 8) + 7 - leadingZeroes;
1519 objectOffset = objectStartNumber * allocationGranularity;
1520 Address objectAddress = objectOffset + payload();
1521 Header* header = reinterpret_cast<Header*>(objectAddress);
1522 if (header->isFree())
1523 return 0;
1524 return header;
1525 }
1526
1527 template<typename Header>
1528 void HeapPage<Header>::checkAndMarkPointer(Visitor* visitor, Address address)
1529 {
1530 ASSERT(contains(address));
1531 Header* header = findHeaderFromAddress(address);
1532 if (!header || header->hasDeadMark())
1533 return;
1534
1535 #if ENABLE(GC_PROFILE_MARKING)
1536 visitor->setHostInfo(&address, "stack");
1537 #endif
1538 if (hasVTable(header) && !vTableInitialized(header->payload())) {
1539 visitor->markNoTracing(header);
1540 ASSERT(isUninitializedMemory(header->payload(), header->payloadSize()));
1541 } else {
1542 visitor->mark(header, traceCallback(header));
1543 }
1544 }
1545
1546 #if ENABLE(GC_PROFILE_MARKING)
1547 template<typename Header>
1548 const GCInfo* HeapPage<Header>::findGCInfo(Address address)
1549 {
1550 if (address < payload())
1551 return 0;
1552
1553 if (gcInfo()) // for non FinalizedObjectHeader
1554 return gcInfo();
1555
1556 Header* header = findHeaderFromAddress(address);
1557 if (!header)
1558 return 0;
1559
1560 return header->gcInfo();
1561 }
1562 #endif
1563
1564 #if ENABLE(GC_PROFILE_HEAP)
1565 template<typename Header>
1566 void HeapPage<Header>::snapshot(TracedValue* json, ThreadState::SnapshotInfo* in fo)
1567 {
1568 Header* header = 0;
1569 for (Address addr = payload(); addr < end(); addr += header->size()) {
1570 header = reinterpret_cast<Header*>(addr);
1571 if (json)
1572 json->pushInteger(header->encodedSize());
1573 if (header->isFree()) {
1574 info->freeSize += header->size();
1575 continue;
1576 }
1577
1578 const GCInfo* gcinfo = header->gcInfo() ? header->gcInfo() : gcInfo();
1579 size_t tag = info->getClassTag(gcinfo);
1580 size_t age = header->age();
1581 if (json)
1582 json->pushInteger(tag);
1583 if (header->isMarked()) {
1584 info->liveCount[tag] += 1;
1585 info->liveSize[tag] += header->size();
1586 // Count objects that are live when promoted to the final generation .
1587 if (age == maxHeapObjectAge - 1)
1588 info->generations[tag][maxHeapObjectAge] += 1;
1589 header->incAge();
1590 } else {
1591 info->deadCount[tag] += 1;
1592 info->deadSize[tag] += header->size();
1593 // Count objects that are dead before the final generation.
1594 if (age < maxHeapObjectAge)
1595 info->generations[tag][age] += 1;
1596 }
1597 }
1598 }
1599 #endif
1600
1601 #if defined(ADDRESS_SANITIZER)
1602 template<typename Header>
1603 void HeapPage<Header>::poisonUnmarkedObjects()
1604 {
1605 for (Address headerAddress = payload(); headerAddress < end(); ) {
1606 Header* header = reinterpret_cast<Header*>(headerAddress);
1607 ASSERT(header->size() < blinkPagePayloadSize());
1608
1609 if (!header->isFree() && !header->isMarked())
1610 ASAN_POISON_MEMORY_REGION(header->payload(), header->payloadSize());
1611 headerAddress += header->size();
1612 }
1613 }
1614 #endif
1615
1616 template<>
1617 inline void HeapPage<FinalizedHeapObjectHeader>::finalize(FinalizedHeapObjectHea der* header)
1618 {
1619 header->finalize();
1620 }
1621
1622 template<>
1623 inline void HeapPage<HeapObjectHeader>::finalize(HeapObjectHeader* header)
1624 {
1625 ASSERT(gcInfo());
1626 HeapObjectHeader::finalize(gcInfo(), header->payload(), header->payloadSize( ));
1627 }
1628
1629 template<>
1630 inline TraceCallback HeapPage<HeapObjectHeader>::traceCallback(HeapObjectHeader* header)
1631 {
1632 ASSERT(gcInfo());
1633 return gcInfo()->m_trace;
1634 }
1635
1636 template<>
1637 inline TraceCallback HeapPage<FinalizedHeapObjectHeader>::traceCallback(Finalize dHeapObjectHeader* header)
1638 {
1639 return header->traceCallback();
1640 }
1641
1642 template<>
1643 inline bool HeapPage<HeapObjectHeader>::hasVTable(HeapObjectHeader* header)
1644 {
1645 ASSERT(gcInfo());
1646 return gcInfo()->hasVTable();
1647 }
1648
1649 template<>
1650 inline bool HeapPage<FinalizedHeapObjectHeader>::hasVTable(FinalizedHeapObjectHe ader* header)
1651 {
1652 return header->hasVTable();
1653 }
1654
1655 template<typename Header>
1656 void LargeHeapObject<Header>::getStats(HeapStats& stats)
1657 {
1658 stats.increaseAllocatedSpace(size());
1659 stats.increaseObjectSpace(payloadSize());
1660 }
1661
1662 #if ENABLE(GC_PROFILE_HEAP)
1663 template<typename Header>
1664 void LargeHeapObject<Header>::snapshot(TracedValue* json, ThreadState::SnapshotI nfo* info)
1665 {
1666 Header* header = heapObjectHeader();
1667 size_t tag = info->getClassTag(header->gcInfo());
1668 size_t age = header->age();
1669 if (isMarked()) {
1670 info->liveCount[tag] += 1;
1671 info->liveSize[tag] += header->size();
1672 // Count objects that are live when promoted to the final generation.
1673 if (age == maxHeapObjectAge - 1)
1674 info->generations[tag][maxHeapObjectAge] += 1;
1675 header->incAge();
1676 } else {
1677 info->deadCount[tag] += 1;
1678 info->deadSize[tag] += header->size();
1679 // Count objects that are dead before the final generation.
1680 if (age < maxHeapObjectAge)
1681 info->generations[tag][age] += 1;
1682 }
1683
1684 if (json) {
1685 json->setInteger("class", tag);
1686 json->setInteger("size", header->size());
1687 json->setInteger("isMarked", isMarked());
1688 }
1689 }
1690 #endif
1691
1692 template<typename Entry>
1693 void HeapExtentCache<Entry>::flush()
1694 {
1695 if (m_hasEntries) {
1696 for (int i = 0; i < numberOfEntries; i++)
1697 m_entries[i] = Entry();
1698 m_hasEntries = false;
1699 }
1700 }
1701
1702 template<typename Entry>
1703 size_t HeapExtentCache<Entry>::hash(Address address)
1704 {
1705 size_t value = (reinterpret_cast<size_t>(address) >> blinkPageSizeLog2);
1706 value ^= value >> numberOfEntriesLog2;
1707 value ^= value >> (numberOfEntriesLog2 * 2);
1708 value &= numberOfEntries - 1;
1709 return value & ~1; // Returns only even number.
1710 }
1711
1712 template<typename Entry>
1713 typename Entry::LookupResult HeapExtentCache<Entry>::lookup(Address address)
1714 {
1715 size_t index = hash(address);
1716 ASSERT(!(index & 1));
1717 Address cachePage = roundToBlinkPageStart(address);
1718 if (m_entries[index].address() == cachePage)
1719 return m_entries[index].result();
1720 if (m_entries[index + 1].address() == cachePage)
1721 return m_entries[index + 1].result();
1722 return 0;
1723 }
1724
1725 template<typename Entry>
1726 void HeapExtentCache<Entry>::addEntry(Address address, typename Entry::LookupRes ult entry)
1727 {
1728 m_hasEntries = true;
1729 size_t index = hash(address);
1730 ASSERT(!(index & 1));
1731 Address cachePage = roundToBlinkPageStart(address);
1732 m_entries[index + 1] = m_entries[index];
1733 m_entries[index] = Entry(cachePage, entry);
1734 }
1735
1736 // These should not be needed, but it seems impossible to persuade clang to
1737 // instantiate the template functions and export them from a shared library, so
1738 // we add these in the non-templated subclass, which does not have that issue.
1739 void HeapContainsCache::addEntry(Address address, BaseHeapPage* page)
1740 {
1741 HeapExtentCache<PositiveEntry>::addEntry(address, page);
1742 }
1743
1744 BaseHeapPage* HeapContainsCache::lookup(Address address)
1745 {
1746 return HeapExtentCache<PositiveEntry>::lookup(address);
1747 }
1748
1749 void Heap::flushHeapDoesNotContainCache()
1750 {
1751 s_heapDoesNotContainCache->flush();
1752 }
1753
1754 void CallbackStack::init(CallbackStack** first)
1755 {
1756 // The stacks are chained, so we start by setting this to null as terminator .
1757 *first = 0;
1758 *first = new CallbackStack(first);
1759 }
1760
1761 void CallbackStack::shutdown(CallbackStack** first)
1762 {
1763 CallbackStack* next;
1764 for (CallbackStack* current = *first; current; current = next) {
1765 next = current->m_next;
1766 delete current;
1767 }
1768 *first = 0;
1769 }
1770
1771 CallbackStack::~CallbackStack()
1772 {
1773 #if ENABLE(ASSERT)
1774 clearUnused();
1775 #endif
1776 }
1777
1778 void CallbackStack::clearUnused()
1779 {
1780 for (size_t i = 0; i < bufferSize; i++)
1781 m_buffer[i] = Item(0, 0);
1782 }
1783
1784 bool CallbackStack::isEmpty()
1785 {
1786 return currentBlockIsEmpty() && !m_next;
1787 }
1788
1789 CallbackStack* CallbackStack::takeCallbacks(CallbackStack** first)
1790 {
1791 // If there is a full next block unlink and return it.
1792 if (m_next) {
1793 CallbackStack* result = m_next;
1794 m_next = result->m_next;
1795 result->m_next = 0;
1796 return result;
1797 }
1798 // Only the current block is in the stack. If the current block is
1799 // empty return 0.
1800 if (currentBlockIsEmpty())
1801 return 0;
1802 // The current block is not empty. Return this block and insert a
1803 // new empty block as the marking stack.
1804 *first = 0;
1805 *first = new CallbackStack(first);
1806 return this;
1807 }
1808
1809 template<CallbackInvocationMode Mode>
1810 bool CallbackStack::popAndInvokeCallback(CallbackStack** first, Visitor* visitor )
1811 {
1812 if (currentBlockIsEmpty()) {
1813 if (!m_next) {
1814 #if ENABLE(ASSERT)
1815 clearUnused();
1816 #endif
1817 return false;
1818 }
1819 CallbackStack* nextStack = m_next;
1820 *first = nextStack;
1821 delete this;
1822 return nextStack->popAndInvokeCallback<Mode>(first, visitor);
1823 }
1824 Item* item = --m_current;
1825
1826 // If the object being traced is located on a page which is dead don't
1827 // trace it. This can happen when a conservative GC kept a dead object
1828 // alive which pointed to a (now gone) object on the cleaned up page.
1829 // Also if doing a thread local GC don't trace objects that are located
1830 // on other thread's heaps, ie. pages where the terminating flag is not
1831 // set.
1832 BaseHeapPage* heapPage = pageHeaderFromObject(item->object());
1833 if (Mode == GlobalMarking && heapPage->orphaned()) {
1834 // When doing a global GC we should only get a trace callback to an orph aned
1835 // page if the GC is conservative. If it is not conservative there is
1836 // a bug in the code where we have a dangling pointer to a page
1837 // on the dead thread.
1838 RELEASE_ASSERT(Heap::lastGCWasConservative());
1839 heapPage->setTracedAfterOrphaned();
1840 return true;
1841 }
1842 if (Mode == ThreadLocalMarking && (heapPage->orphaned() || !heapPage->termin ating()))
1843 return true;
1844 // For WeaknessProcessing we should never reach orphaned pages since
1845 // they should never be registered as objects on orphaned pages are not
1846 // traced. We cannot assert this here since we might have an off-heap
1847 // collection. However we assert it in Heap::pushWeakObjectPointerCallback.
1848
1849 VisitorCallback callback = item->callback();
1850 #if ENABLE(GC_PROFILE_MARKING)
1851 if (ThreadState::isAnyThreadInGC()) // weak-processing will also use popAndI nvokeCallback
1852 visitor->setHostInfo(item->object(), classOf(item->object()));
1853 #endif
1854 callback(visitor, item->object());
1855
1856 return true;
1857 }
1858
1859 void CallbackStack::invokeCallbacks(CallbackStack** first, Visitor* visitor)
1860 {
1861 CallbackStack* stack = 0;
1862 // The first block is the only one where new ephemerons are added, so we
1863 // call the callbacks on that last, to catch any new ephemerons discovered
1864 // in the callbacks.
1865 // However, if enough ephemerons were added, we may have a new block that
1866 // has been prepended to the chain. This will be very rare, but we can
1867 // handle the situation by starting again and calling all the callbacks
1868 // a second time.
1869 while (stack != *first) {
1870 stack = *first;
1871 stack->invokeOldestCallbacks(visitor);
1872 }
1873 }
1874
1875 void CallbackStack::invokeOldestCallbacks(Visitor* visitor)
1876 {
1877 // Recurse first (bufferSize at a time) so we get to the newly added entries
1878 // last.
1879 if (m_next)
1880 m_next->invokeOldestCallbacks(visitor);
1881
1882 // This loop can tolerate entries being added by the callbacks after
1883 // iteration starts.
1884 for (unsigned i = 0; m_buffer + i < m_current; i++) {
1885 Item& item = m_buffer[i];
1886
1887 // We don't need to check for orphaned pages when popping an ephemeron
1888 // callback since the callback is only pushed after the object containin g
1889 // it has been traced. There are basically three cases to consider:
1890 // 1. Member<EphemeronCollection>
1891 // 2. EphemeronCollection is part of a containing object
1892 // 3. EphemeronCollection is a value object in a collection
1893 //
1894 // Ad. 1. In this case we push the start of the ephemeron on the
1895 // marking stack and do the orphaned page check when popping it off
1896 // the marking stack.
1897 // Ad. 2. The containing object cannot be on an orphaned page since
1898 // in that case we wouldn't have traced its parts. This also means
1899 // the ephemeron collection is not on the orphaned page.
1900 // Ad. 3. Is the same as 2. The collection containing the ephemeron
1901 // collection as a value object cannot be on an orphaned page since
1902 // it would not have traced its values in that case.
1903 item.callback()(visitor, item.object());
1904 }
1905 }
1906
1907 #if ENABLE(ASSERT)
1908 bool CallbackStack::hasCallbackForObject(const void* object)
1909 {
1910 for (unsigned i = 0; m_buffer + i < m_current; i++) {
1911 Item* item = &m_buffer[i];
1912 if (item->object() == object) {
1913 return true;
1914 }
1915 }
1916 if (m_next)
1917 return m_next->hasCallbackForObject(object);
1918
1919 return false;
1920 }
1921 #endif
1922
1923 // The marking mutex is used to ensure sequential access to data
1924 // structures during marking. The marking mutex needs to be acquired
1925 // during marking when elements are taken from the global marking
1926 // stack or when elements are added to the global ephemeron,
1927 // post-marking, and weak processing stacks. In debug mode the mutex
1928 // also needs to be acquired when asserts use the heap contains
1929 // caches.
1930 static Mutex& markingMutex()
1931 {
1932 AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex);
1933 return mutex;
1934 }
1935
1936 static ThreadCondition& markingCondition()
1937 {
1938 AtomicallyInitializedStatic(ThreadCondition&, condition = *new ThreadConditi on);
1939 return condition;
1940 }
1941
1942 static void markNoTracingCallback(Visitor* visitor, void* object)
1943 {
1944 visitor->markNoTracing(object);
1945 }
1946
1947 class MarkingVisitor : public Visitor {
1948 public:
1949 #if ENABLE(GC_PROFILE_MARKING)
1950 typedef HashSet<uintptr_t> LiveObjectSet;
1951 typedef HashMap<String, LiveObjectSet> LiveObjectMap;
1952 typedef HashMap<uintptr_t, std::pair<uintptr_t, String> > ObjectGraph;
1953 #endif
1954
1955 MarkingVisitor(CallbackStack** markingStack) : m_markingStack(markingStack)
1956 {
1957 }
1958
1959 inline void visitHeader(HeapObjectHeader* header, const void* objectPointer, TraceCallback callback)
1960 {
1961 ASSERT(header);
1962 #if ENABLE(ASSERT)
1963 {
1964 // Check that we are not marking objects that are outside
1965 // the heap by calling Heap::contains. However we cannot
1966 // call Heap::contains when outside a GC and we call mark
1967 // when doing weakness for ephemerons. Hence we only check
1968 // when called within.
1969 MutexLocker locker(markingMutex());
1970 ASSERT(!ThreadState::isAnyThreadInGC() || Heap::containedInHeapOrOrp hanedPage(header));
1971 }
1972 #endif
1973 ASSERT(objectPointer);
1974 if (header->isMarked())
1975 return;
1976 header->mark();
1977 #if ENABLE(GC_PROFILE_MARKING)
1978 MutexLocker locker(objectGraphMutex());
1979 String className(classOf(objectPointer));
1980 {
1981 LiveObjectMap::AddResult result = currentlyLive().add(className, Liv eObjectSet());
1982 result.storedValue->value.add(reinterpret_cast<uintptr_t>(objectPoin ter));
1983 }
1984 ObjectGraph::AddResult result = objectGraph().add(reinterpret_cast<uintp tr_t>(objectPointer), std::make_pair(reinterpret_cast<uintptr_t>(m_hostObject), m_hostName));
1985 ASSERT(result.isNewEntry);
1986 // fprintf(stderr, "%s[%p] -> %s[%p]\n", m_hostName.ascii().data(), m_ho stObject, className.ascii().data(), objectPointer);
1987 #endif
1988 if (callback)
1989 Heap::pushTraceCallback(m_markingStack, const_cast<void*>(objectPoin ter), callback);
1990 }
1991
1992 virtual void mark(HeapObjectHeader* header, TraceCallback callback) override
1993 {
1994 // We need both the HeapObjectHeader and FinalizedHeapObjectHeader
1995 // version to correctly find the payload.
1996 visitHeader(header, header->payload(), callback);
1997 }
1998
1999 virtual void mark(FinalizedHeapObjectHeader* header, TraceCallback callback) override
2000 {
2001 // We need both the HeapObjectHeader and FinalizedHeapObjectHeader
2002 // version to correctly find the payload.
2003 visitHeader(header, header->payload(), callback);
2004 }
2005
2006 virtual void mark(const void* objectPointer, TraceCallback callback) overrid e
2007 {
2008 if (!objectPointer)
2009 return;
2010 FinalizedHeapObjectHeader* header = FinalizedHeapObjectHeader::fromPaylo ad(objectPointer);
2011 visitHeader(header, header->payload(), callback);
2012 }
2013
2014 virtual void registerDelayedMarkNoTracing(const void* object) override
2015 {
2016 Heap::pushPostMarkingCallback(const_cast<void*>(object), markNoTracingCa llback);
2017 }
2018
2019 virtual void registerWeakMembers(const void* closure, const void* containing Object, WeakPointerCallback callback) override
2020 {
2021 Heap::pushWeakObjectPointerCallback(const_cast<void*>(closure), const_ca st<void*>(containingObject), callback);
2022 }
2023
2024 virtual void registerWeakTable(const void* closure, EphemeronCallback iterat ionCallback, EphemeronCallback iterationDoneCallback)
2025 {
2026 Heap::registerWeakTable(const_cast<void*>(closure), iterationCallback, i terationDoneCallback);
2027 }
2028
2029 #if ENABLE(ASSERT)
2030 virtual bool weakTableRegistered(const void* closure)
2031 {
2032 return Heap::weakTableRegistered(closure);
2033 }
2034 #endif
2035
2036 virtual bool isMarked(const void* objectPointer) override
2037 {
2038 return FinalizedHeapObjectHeader::fromPayload(objectPointer)->isMarked() ;
2039 }
2040
2041 // This macro defines the necessary visitor methods for typed heaps
2042 #define DEFINE_VISITOR_METHODS(Type) \
2043 virtual void mark(const Type* objectPointer, TraceCallback callback) overrid e \
2044 { \
2045 if (!objectPointer) \
2046 return; \
2047 HeapObjectHeader* header = \
2048 HeapObjectHeader::fromPayload(objectPointer); \
2049 visitHeader(header, header->payload(), callback); \
2050 } \
2051 virtual bool isMarked(const Type* objectPointer) override \
2052 { \
2053 return HeapObjectHeader::fromPayload(objectPointer)->isMarked(); \
2054 }
2055
2056 FOR_EACH_TYPED_HEAP(DEFINE_VISITOR_METHODS)
2057 #undef DEFINE_VISITOR_METHODS
2058
2059 #if ENABLE(GC_PROFILE_MARKING)
2060 void reportStats()
2061 {
2062 fprintf(stderr, "\n---------- AFTER MARKING -------------------\n");
2063 for (LiveObjectMap::iterator it = currentlyLive().begin(), end = current lyLive().end(); it != end; ++it) {
2064 fprintf(stderr, "%s %u", it->key.ascii().data(), it->value.size());
2065
2066 if (it->key == "blink::Document")
2067 reportStillAlive(it->value, previouslyLive().get(it->key));
2068
2069 fprintf(stderr, "\n");
2070 }
2071
2072 previouslyLive().swap(currentlyLive());
2073 currentlyLive().clear();
2074
2075 for (HashSet<uintptr_t>::iterator it = objectsToFindPath().begin(), end = objectsToFindPath().end(); it != end; ++it) {
2076 dumpPathToObjectFromObjectGraph(objectGraph(), *it);
2077 }
2078 }
2079
2080 static void reportStillAlive(LiveObjectSet current, LiveObjectSet previous)
2081 {
2082 int count = 0;
2083
2084 fprintf(stderr, " [previously %u]", previous.size());
2085 for (LiveObjectSet::iterator it = current.begin(), end = current.end(); it != end; ++it) {
2086 if (previous.find(*it) == previous.end())
2087 continue;
2088 count++;
2089 }
2090
2091 if (!count)
2092 return;
2093
2094 fprintf(stderr, " {survived 2GCs %d: ", count);
2095 for (LiveObjectSet::iterator it = current.begin(), end = current.end(); it != end; ++it) {
2096 if (previous.find(*it) == previous.end())
2097 continue;
2098 fprintf(stderr, "%ld", *it);
2099 if (--count)
2100 fprintf(stderr, ", ");
2101 }
2102 ASSERT(!count);
2103 fprintf(stderr, "}");
2104 }
2105
2106 static void dumpPathToObjectFromObjectGraph(const ObjectGraph& graph, uintpt r_t target)
2107 {
2108 ObjectGraph::const_iterator it = graph.find(target);
2109 if (it == graph.end())
2110 return;
2111 fprintf(stderr, "Path to %lx of %s\n", target, classOf(reinterpret_cast< const void*>(target)).ascii().data());
2112 while (it != graph.end()) {
2113 fprintf(stderr, "<- %lx of %s\n", it->value.first, it->value.second. utf8().data());
2114 it = graph.find(it->value.first);
2115 }
2116 fprintf(stderr, "\n");
2117 }
2118
2119 static void dumpPathToObjectOnNextGC(void* p)
2120 {
2121 objectsToFindPath().add(reinterpret_cast<uintptr_t>(p));
2122 }
2123
2124 static Mutex& objectGraphMutex()
2125 {
2126 AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex);
2127 return mutex;
2128 }
2129
2130 static LiveObjectMap& previouslyLive()
2131 {
2132 DEFINE_STATIC_LOCAL(LiveObjectMap, map, ());
2133 return map;
2134 }
2135
2136 static LiveObjectMap& currentlyLive()
2137 {
2138 DEFINE_STATIC_LOCAL(LiveObjectMap, map, ());
2139 return map;
2140 }
2141
2142 static ObjectGraph& objectGraph()
2143 {
2144 DEFINE_STATIC_LOCAL(ObjectGraph, graph, ());
2145 return graph;
2146 }
2147
2148 static HashSet<uintptr_t>& objectsToFindPath()
2149 {
2150 DEFINE_STATIC_LOCAL(HashSet<uintptr_t>, set, ());
2151 return set;
2152 }
2153 #endif
2154
2155 protected:
2156 virtual void registerWeakCell(void** cell, WeakPointerCallback callback) ove rride
2157 {
2158 Heap::pushWeakCellPointerCallback(cell, callback);
2159 }
2160
2161 private:
2162 CallbackStack** m_markingStack;
2163 };
2164
2165 BaseHeapPage* Heap::contains(Address address)
2166 {
2167 ASSERT(ThreadState::isAnyThreadInGC());
2168 ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThreads( );
2169 for (ThreadState::AttachedThreadStateSet::iterator it = threads.begin(), end = threads.end(); it != end; ++it) {
2170 BaseHeapPage* page = (*it)->contains(address);
2171 if (page)
2172 return page;
2173 }
2174 return 0;
2175 }
2176
2177 #if ENABLE(ASSERT)
2178 bool Heap::containedInHeapOrOrphanedPage(void* object)
2179 {
2180 return contains(object) || orphanedPagePool()->contains(object);
2181 }
2182 #endif
2183
2184 Address Heap::checkAndMarkPointer(Visitor* visitor, Address address)
2185 {
2186 ASSERT(ThreadState::isAnyThreadInGC());
2187
2188 #if !ENABLE(ASSERT)
2189 if (s_heapDoesNotContainCache->lookup(address))
2190 return 0;
2191 #endif
2192
2193 ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThreads( );
2194 for (ThreadState::AttachedThreadStateSet::iterator it = threads.begin(), end = threads.end(); it != end; ++it) {
2195 if ((*it)->checkAndMarkPointer(visitor, address)) {
2196 // Pointer was in a page of that thread. If it actually pointed
2197 // into an object then that object was found and marked.
2198 ASSERT(!s_heapDoesNotContainCache->lookup(address));
2199 s_lastGCWasConservative = true;
2200 return address;
2201 }
2202 }
2203
2204 #if !ENABLE(ASSERT)
2205 s_heapDoesNotContainCache->addEntry(address, true);
2206 #else
2207 if (!s_heapDoesNotContainCache->lookup(address))
2208 s_heapDoesNotContainCache->addEntry(address, true);
2209 #endif
2210 return 0;
2211 }
2212
2213 #if ENABLE(GC_PROFILE_MARKING)
2214 const GCInfo* Heap::findGCInfo(Address address)
2215 {
2216 return ThreadState::findGCInfoFromAllThreads(address);
2217 }
2218 #endif
2219
2220 #if ENABLE(GC_PROFILE_MARKING)
2221 void Heap::dumpPathToObjectOnNextGC(void* p)
2222 {
2223 static_cast<MarkingVisitor*>(s_markingVisitor)->dumpPathToObjectOnNextGC(p);
2224 }
2225
2226 String Heap::createBacktraceString()
2227 {
2228 int framesToShow = 3;
2229 int stackFrameSize = 16;
2230 ASSERT(stackFrameSize >= framesToShow);
2231 typedef void* FramePointer;
2232 FramePointer* stackFrame = static_cast<FramePointer*>(alloca(sizeof(FramePoi nter) * stackFrameSize));
2233 WTFGetBacktrace(stackFrame, &stackFrameSize);
2234
2235 StringBuilder builder;
2236 builder.append("Persistent");
2237 bool didAppendFirstName = false;
2238 // Skip frames before/including "blink::Persistent".
2239 bool didSeePersistent = false;
2240 for (int i = 0; i < stackFrameSize && framesToShow > 0; ++i) {
2241 FrameToNameScope frameToName(stackFrame[i]);
2242 if (!frameToName.nullableName())
2243 continue;
2244 if (strstr(frameToName.nullableName(), "blink::Persistent")) {
2245 didSeePersistent = true;
2246 continue;
2247 }
2248 if (!didSeePersistent)
2249 continue;
2250 if (!didAppendFirstName) {
2251 didAppendFirstName = true;
2252 builder.append(" ... Backtrace:");
2253 }
2254 builder.append("\n\t");
2255 builder.append(frameToName.nullableName());
2256 --framesToShow;
2257 }
2258 return builder.toString().replace("blink::", "");
2259 }
2260 #endif
2261
2262 void Heap::pushTraceCallback(CallbackStack** stack, void* object, TraceCallback callback)
2263 {
2264 #if ENABLE(ASSERT)
2265 {
2266 MutexLocker locker(markingMutex());
2267 ASSERT(Heap::containedInHeapOrOrphanedPage(object));
2268 }
2269 #endif
2270 CallbackStack::Item* slot = (*stack)->allocateEntry(stack);
2271 *slot = CallbackStack::Item(object, callback);
2272 }
2273
2274 template<CallbackInvocationMode Mode>
2275 bool Heap::popAndInvokeTraceCallback(Visitor* visitor)
2276 {
2277 return s_markingStack->popAndInvokeCallback<Mode>(&s_markingStack, visitor);
2278 }
2279
2280 void Heap::pushPostMarkingCallback(void* object, TraceCallback callback)
2281 {
2282 MutexLocker locker(markingMutex());
2283 ASSERT(!Heap::orphanedPagePool()->contains(object));
2284 CallbackStack::Item* slot = s_postMarkingCallbackStack->allocateEntry(&s_pos tMarkingCallbackStack);
2285 *slot = CallbackStack::Item(object, callback);
2286 }
2287
2288 bool Heap::popAndInvokePostMarkingCallback(Visitor* visitor)
2289 {
2290 return s_postMarkingCallbackStack->popAndInvokeCallback<PostMarking>(&s_post MarkingCallbackStack, visitor);
2291 }
2292
2293 void Heap::pushWeakCellPointerCallback(void** cell, WeakPointerCallback callback )
2294 {
2295 MutexLocker locker(markingMutex());
2296 ASSERT(!Heap::orphanedPagePool()->contains(cell));
2297 CallbackStack::Item* slot = s_weakCallbackStack->allocateEntry(&s_weakCallba ckStack);
2298 *slot = CallbackStack::Item(cell, callback);
2299 }
2300
2301 void Heap::pushWeakObjectPointerCallback(void* closure, void* object, WeakPointe rCallback callback)
2302 {
2303 MutexLocker locker(markingMutex());
2304 ASSERT(Heap::contains(object));
2305 BaseHeapPage* heapPageForObject = pageHeaderFromObject(object);
2306 ASSERT(!heapPageForObject->orphaned());
2307 ASSERT(Heap::contains(object) == heapPageForObject);
2308 ThreadState* state = heapPageForObject->threadState();
2309 state->pushWeakObjectPointerCallback(closure, callback);
2310 }
2311
2312 bool Heap::popAndInvokeWeakPointerCallback(Visitor* visitor)
2313 {
2314 return s_weakCallbackStack->popAndInvokeCallback<WeaknessProcessing>(&s_weak CallbackStack, visitor);
2315 }
2316
2317 void Heap::registerWeakTable(void* table, EphemeronCallback iterationCallback, E phemeronCallback iterationDoneCallback)
2318 {
2319 {
2320 MutexLocker locker(markingMutex());
2321 // Check that the ephemeron table being pushed onto the stack is not on an
2322 // orphaned page.
2323 ASSERT(!Heap::orphanedPagePool()->contains(table));
2324 CallbackStack::Item* slot = s_ephemeronStack->allocateEntry(&s_ephemeron Stack);
2325 *slot = CallbackStack::Item(table, iterationCallback);
2326 }
2327
2328 // Register a post-marking callback to tell the tables that
2329 // ephemeron iteration is complete.
2330 pushPostMarkingCallback(table, iterationDoneCallback);
2331 }
2332
2333 #if ENABLE(ASSERT)
2334 bool Heap::weakTableRegistered(const void* table)
2335 {
2336 MutexLocker locker(markingMutex());
2337 ASSERT(s_ephemeronStack);
2338 return s_ephemeronStack->hasCallbackForObject(table);
2339 }
2340 #endif
2341
2342 void Heap::prepareForGC()
2343 {
2344 ASSERT(ThreadState::isAnyThreadInGC());
2345 ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThreads( );
2346 for (ThreadState::AttachedThreadStateSet::iterator it = threads.begin(), end = threads.end(); it != end; ++it)
2347 (*it)->prepareForGC();
2348 }
2349
2350 void Heap::collectGarbage(ThreadState::StackState stackState)
2351 {
2352 }
2353
2354 void Heap::collectGarbageForTerminatingThread(ThreadState* state)
2355 {
2356 }
2357
2358 void Heap::processMarkingStackEntries(int* runningMarkingThreads)
2359 {
2360 CallbackStack* stack = 0;
2361 MarkingVisitor visitor(&stack);
2362 {
2363 MutexLocker locker(markingMutex());
2364 stack = s_markingStack->takeCallbacks(&s_markingStack);
2365 }
2366 while (stack) {
2367 while (stack->popAndInvokeCallback<GlobalMarking>(&stack, &visitor)) { }
2368 delete stack;
2369 {
2370 MutexLocker locker(markingMutex());
2371 stack = s_markingStack->takeCallbacks(&s_markingStack);
2372 }
2373 }
2374 {
2375 MutexLocker locker(markingMutex());
2376 if (!--(*runningMarkingThreads))
2377 markingCondition().signal();
2378 }
2379 }
2380
2381 void Heap::processMarkingStackOnMultipleThreads()
2382 {
2383 }
2384
2385 void Heap::processMarkingStackInParallel()
2386 {
2387 static const int numberOfBlocksForParallelMarking = 2;
2388 // Ephemeron fixed point loop run on the garbage collecting thread.
2389 do {
2390 // Iteratively mark all objects that are reachable from the objects
2391 // currently pushed onto the marking stack. Do so in parallel if there
2392 // are multiple blocks on the global marking stack.
2393 if (s_markingStack->numberOfBlocksExceeds(numberOfBlocksForParallelMarki ng)) {
2394 processMarkingStackOnMultipleThreads();
2395 } else {
2396 while (popAndInvokeTraceCallback<GlobalMarking>(s_markingVisitor)) { }
2397 }
2398
2399 // Mark any strong pointers that have now become reachable in ephemeron
2400 // maps.
2401 CallbackStack::invokeCallbacks(&s_ephemeronStack, s_markingVisitor);
2402
2403 // Rerun loop if ephemeron processing queued more objects for tracing.
2404 } while (!s_markingStack->isEmpty());
2405 }
2406
2407 template<CallbackInvocationMode Mode>
2408 void Heap::processMarkingStack()
2409 {
2410 // Ephemeron fixed point loop.
2411 do {
2412 // Iteratively mark all objects that are reachable from the objects
2413 // currently pushed onto the marking stack. If Mode is ThreadLocalMarkin g
2414 // don't continue tracing if the trace hits an object on another thread' s
2415 // heap.
2416 while (popAndInvokeTraceCallback<Mode>(s_markingVisitor)) { }
2417
2418 // Mark any strong pointers that have now become reachable in ephemeron
2419 // maps.
2420 CallbackStack::invokeCallbacks(&s_ephemeronStack, s_markingVisitor);
2421
2422 // Rerun loop if ephemeron processing queued more objects for tracing.
2423 } while (!s_markingStack->isEmpty());
2424 }
2425
2426 void Heap::postMarkingProcessing()
2427 {
2428 // Call post-marking callbacks including:
2429 // 1. the ephemeronIterationDone callbacks on weak tables to do cleanup
2430 // (specifically to clear the queued bits for weak hash tables), and
2431 // 2. the markNoTracing callbacks on collection backings to mark them
2432 // if they are only reachable from their front objects.
2433 while (popAndInvokePostMarkingCallback(s_markingVisitor)) { }
2434
2435 CallbackStack::clear(&s_ephemeronStack);
2436
2437 // Post-marking callbacks should not trace any objects and
2438 // therefore the marking stack should be empty after the
2439 // post-marking callbacks.
2440 ASSERT(s_markingStack->isEmpty());
2441 }
2442
2443 void Heap::globalWeakProcessing()
2444 {
2445 // Call weak callbacks on objects that may now be pointing to dead
2446 // objects.
2447 while (popAndInvokeWeakPointerCallback(s_markingVisitor)) { }
2448
2449 // It is not permitted to trace pointers of live objects in the weak
2450 // callback phase, so the marking stack should still be empty here.
2451 ASSERT(s_markingStack->isEmpty());
2452 }
2453
2454 void Heap::collectAllGarbage()
2455 {
2456 // FIXME: oilpan: we should perform a single GC and everything
2457 // should die. Unfortunately it is not the case for all objects
2458 // because the hierarchy was not completely moved to the heap and
2459 // some heap allocated objects own objects that contain persistents
2460 // pointing to other heap allocated objects.
2461 for (int i = 0; i < 5; i++)
2462 collectGarbage(ThreadState::NoHeapPointersOnStack);
2463 }
2464
2465 void Heap::setForcePreciseGCForTesting()
2466 {
2467 ThreadState::current()->setForcePreciseGCForTesting(true);
2468 }
2469
2470 template<typename Header>
2471 void ThreadHeap<Header>::prepareHeapForTermination()
2472 {
2473 for (HeapPage<Header>* page = m_firstPage; page; page = page->next()) {
2474 page->setTerminating();
2475 }
2476 for (LargeHeapObject<Header>* current = m_firstLargeHeapObject; current; cur rent = current->next()) {
2477 current->setTerminating();
2478 }
2479 }
2480
2481 template<typename Header>
2482 BaseHeap* ThreadHeap<Header>::split(int numberOfNormalPages)
2483 {
2484 // Create a new split off thread heap containing
2485 // |numberOfNormalPages| of the pages of this ThreadHeap for
2486 // parallel sweeping. The split off thread heap will be merged
2487 // with this heap at the end of sweeping and the temporary
2488 // ThreadHeap object will be deallocated after the merge.
2489 ASSERT(numberOfNormalPages > 0);
2490 ThreadHeap<Header>* splitOff = new ThreadHeap(m_threadState, m_index);
2491 HeapPage<Header>* splitPoint = m_firstPage;
2492 for (int i = 1; i < numberOfNormalPages; i++)
2493 splitPoint = splitPoint->next();
2494 splitOff->m_firstPage = m_firstPage;
2495 m_firstPage = splitPoint->m_next;
2496 splitOff->m_mergePoint = splitPoint;
2497 splitOff->m_numberOfNormalPages = numberOfNormalPages;
2498 m_numberOfNormalPages -= numberOfNormalPages;
2499 splitPoint->m_next = 0;
2500 return splitOff;
2501 }
2502
2503 template<typename Header>
2504 void ThreadHeap<Header>::merge(BaseHeap* splitOffBase)
2505 {
2506 ThreadHeap<Header>* splitOff = static_cast<ThreadHeap<Header>*>(splitOffBase );
2507 // If the mergePoint is zero all split off pages became empty in
2508 // this round and we don't have to merge. There are no pages and
2509 // nothing on the freelists.
2510 ASSERT(splitOff->m_mergePoint || splitOff->m_numberOfNormalPages == 0);
2511 if (splitOff->m_mergePoint) {
2512 // Link the split off pages into the beginning of the list again.
2513 splitOff->m_mergePoint->m_next = m_firstPage;
2514 m_firstPage = splitOff->m_firstPage;
2515 m_numberOfNormalPages += splitOff->m_numberOfNormalPages;
2516 splitOff->m_firstPage = 0;
2517 // Merge free lists.
2518 for (size_t i = 0; i < blinkPageSizeLog2; i++) {
2519 if (!m_freeLists[i]) {
2520 m_freeLists[i] = splitOff->m_freeLists[i];
2521 } else if (splitOff->m_freeLists[i]) {
2522 m_lastFreeListEntries[i]->append(splitOff->m_freeLists[i]);
2523 m_lastFreeListEntries[i] = splitOff->m_lastFreeListEntries[i];
2524 }
2525 }
2526 }
2527 delete splitOffBase;
2528 }
2529
2530 void Heap::getHeapSpaceSize(uint64_t* objectSpaceSize, uint64_t* allocatedSpaceS ize)
2531 {
2532 *objectSpaceSize = 0;
2533 *allocatedSpaceSize = 0;
2534 ASSERT(ThreadState::isAnyThreadInGC());
2535 ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThreads( );
2536 typedef ThreadState::AttachedThreadStateSet::iterator ThreadStateIterator;
2537 for (ThreadStateIterator it = threads.begin(), end = threads.end(); it != en d; ++it) {
2538 *objectSpaceSize += (*it)->stats().totalObjectSpace();
2539 *allocatedSpaceSize += (*it)->stats().totalAllocatedSpace();
2540 }
2541 }
2542
2543 void Heap::getStats(HeapStats* stats)
2544 {
2545 stats->clear();
2546 ASSERT(ThreadState::isAnyThreadInGC());
2547 ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThreads( );
2548 typedef ThreadState::AttachedThreadStateSet::iterator ThreadStateIterator;
2549 for (ThreadStateIterator it = threads.begin(), end = threads.end(); it != en d; ++it) {
2550 HeapStats temp;
2551 (*it)->getStats(temp);
2552 stats->add(&temp);
2553 }
2554 }
2555
2556 #if ENABLE(ASSERT)
2557 bool Heap::isConsistentForSweeping()
2558 {
2559 ASSERT(ThreadState::isAnyThreadInGC());
2560 ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThreads( );
2561 for (ThreadState::AttachedThreadStateSet::iterator it = threads.begin(), end = threads.end(); it != end; ++it) {
2562 if (!(*it)->isConsistentForSweeping())
2563 return false;
2564 }
2565 return true;
2566 }
2567 #endif
2568
2569 void Heap::makeConsistentForSweeping()
2570 {
2571 ASSERT(ThreadState::isAnyThreadInGC());
2572 ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThreads( );
2573 for (ThreadState::AttachedThreadStateSet::iterator it = threads.begin(), end = threads.end(); it != end; ++it)
2574 (*it)->makeConsistentForSweeping();
2575 }
2576
2577 void HeapAllocator::backingFree(void* address)
2578 {
2579 if (!address || ThreadState::isAnyThreadInGC())
2580 return;
2581
2582 ThreadState* state = ThreadState::current();
2583 if (state->isSweepInProgress())
2584 return;
2585
2586 // Don't promptly free large objects because their page is never reused
2587 // and don't free backings allocated on other threads.
2588 BaseHeapPage* page = pageHeaderFromObject(address);
2589 if (page->isLargeObject() || page->threadState() != state)
2590 return;
2591
2592 typedef HeapIndexTrait<CollectionBackingHeap> HeapTraits;
2593 typedef HeapTraits::HeapType HeapType;
2594 typedef HeapTraits::HeaderType HeaderType;
2595
2596 HeaderType* header = HeaderType::fromPayload(address);
2597 header->checkHeader();
2598
2599 const GCInfo* gcInfo = header->gcInfo();
2600 int heapIndex = HeapTraits::index(gcInfo->hasFinalizer());
2601 HeapType* heap = static_cast<HeapType*>(state->heap(heapIndex));
2602 heap->promptlyFreeObject(header);
2603 }
2604
2605 // Force template instantiations for the types that we need.
2606 template class HeapPage<FinalizedHeapObjectHeader>;
2607 template class HeapPage<HeapObjectHeader>;
2608 template class ThreadHeap<FinalizedHeapObjectHeader>;
2609 template class ThreadHeap<HeapObjectHeader>;
2610 template bool CallbackStack::popAndInvokeCallback<GlobalMarking>(CallbackStack** , Visitor*);
2611 template bool CallbackStack::popAndInvokeCallback<ThreadLocalMarking>(CallbackSt ack**, Visitor*);
2612 template bool CallbackStack::popAndInvokeCallback<WeaknessProcessing>(CallbackSt ack**, Visitor*);
2613
2614 Visitor* Heap::s_markingVisitor;
2615 Vector<OwnPtr<blink::WebThread> >* Heap::s_markingThreads;
2616 CallbackStack* Heap::s_markingStack;
2617 CallbackStack* Heap::s_postMarkingCallbackStack;
2618 CallbackStack* Heap::s_weakCallbackStack;
2619 CallbackStack* Heap::s_ephemeronStack;
2620 HeapDoesNotContainCache* Heap::s_heapDoesNotContainCache;
2621 bool Heap::s_shutdownCalled = false;
2622 bool Heap::s_lastGCWasConservative = false;
2623 FreePagePool* Heap::s_freePagePool;
2624 OrphanedPagePool* Heap::s_orphanedPagePool;
2625 }
OLDNEW
« no previous file with comments | « sky/engine/platform/heap/Heap.h ('k') | sky/engine/platform/heap/HeapLinkedStack.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698