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

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

Issue 681113004: Remove Heap.h (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
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 #ifndef Heap_h
32 #define Heap_h
33
34 #include "platform/PlatformExport.h"
35 #include "platform/heap/AddressSanitizer.h"
36 #include "platform/heap/ThreadState.h"
37 #include "platform/heap/Visitor.h"
38 #include "public/platform/WebThread.h"
39 #include "wtf/Assertions.h"
40 #include "wtf/HashCountedSet.h"
41 #include "wtf/LinkedHashSet.h"
42 #include "wtf/ListHashSet.h"
43 #include "wtf/OwnPtr.h"
44 #include "wtf/PassRefPtr.h"
45 #include "wtf/ThreadSafeRefCounted.h"
46
47 #include <stdint.h>
48
49 namespace blink {
50
51 const size_t blinkPageSizeLog2 = 17;
52 const size_t blinkPageSize = 1 << blinkPageSizeLog2;
53 const size_t blinkPageOffsetMask = blinkPageSize - 1;
54 const size_t blinkPageBaseMask = ~blinkPageOffsetMask;
55
56 // We allocate pages at random addresses but in groups of
57 // blinkPagesPerRegion at a given random address. We group pages to
58 // not spread out too much over the address space which would blow
59 // away the page tables and lead to bad performance.
60 const size_t blinkPagesPerRegion = 10;
61
62 // Double precision floats are more efficient when 8 byte aligned, so we 8 byte
63 // align all allocations even on 32 bit.
64 const size_t allocationGranularity = 8;
65 const size_t allocationMask = allocationGranularity - 1;
66 const size_t objectStartBitMapSize = (blinkPageSize + ((8 * allocationGranularit y) - 1)) / (8 * allocationGranularity);
67 const size_t reservedForObjectBitMap = ((objectStartBitMapSize + allocationMask) & ~allocationMask);
68 const size_t maxHeapObjectSizeLog2 = 27;
69 const size_t maxHeapObjectSize = 1 << maxHeapObjectSizeLog2;
70
71 const size_t markBitMask = 1;
72 const size_t freeListMask = 2;
73 // The dead bit is used for objects that have gone through a GC marking, but did
74 // not get swept before a new GC started. In that case we set the dead bit on
75 // objects that were not marked in the previous GC to ensure we are not tracing
76 // them via a conservatively found pointer. Tracing dead objects could lead to
77 // tracing of already finalized objects in another thread's heap which is a
78 // use-after-free situation.
79 const size_t deadBitMask = 4;
80 // On free-list entries we reuse the dead bit to distinguish a normal free-list
81 // entry from one that has been promptly freed.
82 const size_t promptlyFreedMask = freeListMask | deadBitMask;
83 #if ENABLE(GC_PROFILE_HEAP)
84 const size_t heapObjectGenerations = 8;
85 const size_t maxHeapObjectAge = heapObjectGenerations - 1;
86 const size_t heapObjectAgeMask = ~(maxHeapObjectSize - 1);
87 const size_t sizeMask = ~heapObjectAgeMask & ~static_cast<size_t>(7);
88 #else
89 const size_t sizeMask = ~static_cast<size_t>(7);
90 #endif
91 const uint8_t freelistZapValue = 42;
92 const uint8_t finalizedZapValue = 24;
93 // The orphaned zap value must be zero in the lowest bits to allow for using
94 // the mark bit when tracing.
95 const uint8_t orphanedZapValue = 240;
96
97 const int numberOfMarkingThreads = 2;
98
99 const int numberOfPagesToConsiderForCoalescing = 100;
100
101 enum CallbackInvocationMode {
102 GlobalMarking,
103 ThreadLocalMarking,
104 PostMarking,
105 WeaknessProcessing,
106 };
107
108 class HeapStats;
109 class PageMemory;
110 template<ThreadAffinity affinity> class ThreadLocalPersistents;
111 template<typename T, typename RootsAccessor = ThreadLocalPersistents<ThreadingTr ait<T>::Affinity > > class Persistent;
112
113 #if ENABLE(GC_PROFILE_HEAP)
114 class TracedValue;
115 #endif
116
117 PLATFORM_EXPORT size_t osPageSize();
118
119 // Blink heap pages are set up with a guard page before and after the
120 // payload.
121 inline size_t blinkPagePayloadSize()
122 {
123 return blinkPageSize - 2 * osPageSize();
124 }
125
126 // Blink heap pages are aligned to the Blink heap page size.
127 // Therefore, the start of a Blink page can be obtained by
128 // rounding down to the Blink page size.
129 inline Address roundToBlinkPageStart(Address address)
130 {
131 return reinterpret_cast<Address>(reinterpret_cast<uintptr_t>(address) & blin kPageBaseMask);
132 }
133
134 inline Address roundToBlinkPageEnd(Address address)
135 {
136 return reinterpret_cast<Address>(reinterpret_cast<uintptr_t>(address - 1) & blinkPageBaseMask) + blinkPageSize;
137 }
138
139 // Compute the amount of padding we have to add to a header to make
140 // the size of the header plus the padding a multiple of 8 bytes.
141 template<typename Header>
142 inline size_t headerPadding()
143 {
144 return (allocationGranularity - (sizeof(Header) % allocationGranularity)) % allocationGranularity;
145 }
146
147 // Masks an address down to the enclosing blink page base address.
148 inline Address blinkPageAddress(Address address)
149 {
150 return reinterpret_cast<Address>(reinterpret_cast<uintptr_t>(address) & blin kPageBaseMask);
151 }
152
153 #if ENABLE(ASSERT)
154
155 // Sanity check for a page header address: the address of the page
156 // header should be OS page size away from being Blink page size
157 // aligned.
158 inline bool isPageHeaderAddress(Address address)
159 {
160 return !((reinterpret_cast<uintptr_t>(address) & blinkPageOffsetMask) - osPa geSize());
161 }
162 #endif
163
164 // Mask an address down to the enclosing oilpan heap base page.
165 // All oilpan heap pages are aligned at blinkPageBase plus an OS page size.
166 // FIXME: Remove PLATFORM_EXPORT once we get a proper public interface to our ty ped heaps.
167 // This is only exported to enable tests in HeapTest.cpp.
168 PLATFORM_EXPORT inline BaseHeapPage* pageHeaderFromObject(const void* object)
169 {
170 Address address = reinterpret_cast<Address>(const_cast<void*>(object));
171 return reinterpret_cast<BaseHeapPage*>(blinkPageAddress(address) + osPageSiz e());
172 }
173
174 // Large allocations are allocated as separate objects and linked in a
175 // list.
176 //
177 // In order to use the same memory allocation routines for everything
178 // allocated in the heap, large objects are considered heap pages
179 // containing only one object.
180 //
181 // The layout of a large heap object is as follows:
182 //
183 // | BaseHeapPage | next pointer | FinalizedHeapObjectHeader or HeapObjectHeader | payload |
184 template<typename Header>
185 class LargeHeapObject : public BaseHeapPage {
186 public:
187 LargeHeapObject(PageMemory* storage, const GCInfo* gcInfo, ThreadState* stat e) : BaseHeapPage(storage, gcInfo, state)
188 {
189 COMPILE_ASSERT(!(sizeof(LargeHeapObject<Header>) & allocationMask), larg e_heap_object_header_misaligned);
190 }
191
192 virtual void checkAndMarkPointer(Visitor*, Address) override;
193 virtual bool isLargeObject() override { return true; }
194
195 #if ENABLE(GC_PROFILE_MARKING)
196 virtual const GCInfo* findGCInfo(Address address)
197 {
198 if (!objectContains(address))
199 return 0;
200 return gcInfo();
201 }
202 #endif
203
204 #if ENABLE(GC_PROFILE_HEAP)
205 void snapshot(TracedValue*, ThreadState::SnapshotInfo*);
206 #endif
207
208 void link(LargeHeapObject<Header>** previousNext)
209 {
210 m_next = *previousNext;
211 *previousNext = this;
212 }
213
214 void unlink(LargeHeapObject<Header>** previousNext)
215 {
216 *previousNext = m_next;
217 }
218
219 // The LargeHeapObject pseudo-page contains one actual object. Determine
220 // whether the pointer is within that object.
221 bool objectContains(Address object)
222 {
223 return (payload() <= object) && (object < address() + size());
224 }
225
226 // Returns true for any address that is on one of the pages that this
227 // large object uses. That ensures that we can use a negative result to
228 // populate the negative page cache.
229 virtual bool contains(Address object) override
230 {
231 return roundToBlinkPageStart(address()) <= object && object < roundToBli nkPageEnd(address() + size());
232 }
233
234 LargeHeapObject<Header>* next()
235 {
236 return m_next;
237 }
238
239 size_t size()
240 {
241 return heapObjectHeader()->size() + sizeof(LargeHeapObject<Header>) + he aderPadding<Header>();
242 }
243
244 Address payload() { return heapObjectHeader()->payload(); }
245 size_t payloadSize() { return heapObjectHeader()->payloadSize(); }
246
247 Header* heapObjectHeader()
248 {
249 Address headerAddress = address() + sizeof(LargeHeapObject<Header>) + he aderPadding<Header>();
250 return reinterpret_cast<Header*>(headerAddress);
251 }
252
253 bool isMarked();
254 void unmark();
255 void getStats(HeapStats&);
256 void mark(Visitor*);
257 void finalize();
258 void setDeadMark();
259 virtual void markOrphaned()
260 {
261 // Zap the payload with a recognizable value to detect any incorrect
262 // cross thread pointer usage.
263 memset(payload(), orphanedZapValue, payloadSize());
264 BaseHeapPage::markOrphaned();
265 }
266
267 private:
268 friend class ThreadHeap<Header>;
269
270 LargeHeapObject<Header>* m_next;
271 };
272
273 // The BasicObjectHeader is the minimal object header. It is used when
274 // encountering heap space of size allocationGranularity to mark it as
275 // as freelist entry.
276 class PLATFORM_EXPORT BasicObjectHeader {
277 public:
278 NO_SANITIZE_ADDRESS
279 explicit BasicObjectHeader(size_t encodedSize)
280 : m_size(encodedSize) { }
281
282 static size_t freeListEncodedSize(size_t size) { return size | freeListMask; }
283
284 NO_SANITIZE_ADDRESS
285 bool isFree() { return m_size & freeListMask; }
286
287 NO_SANITIZE_ADDRESS
288 bool isPromptlyFreed() { return (m_size & promptlyFreedMask) == promptlyFree dMask; }
289
290 NO_SANITIZE_ADDRESS
291 void markPromptlyFreed() { m_size |= promptlyFreedMask; }
292
293 NO_SANITIZE_ADDRESS
294 size_t size() const { return m_size & sizeMask; }
295
296 #if ENABLE(GC_PROFILE_HEAP)
297 NO_SANITIZE_ADDRESS
298 size_t encodedSize() const { return m_size; }
299
300 NO_SANITIZE_ADDRESS
301 size_t age() const { return m_size >> maxHeapObjectSizeLog2; }
302
303 NO_SANITIZE_ADDRESS
304 void incAge()
305 {
306 size_t current = age();
307 if (current < maxHeapObjectAge)
308 m_size = ((current + 1) << maxHeapObjectSizeLog2) | (m_size & ~heapO bjectAgeMask);
309 }
310 #endif
311
312 protected:
313 volatile unsigned m_size;
314 };
315
316 // Our heap object layout is layered with the HeapObjectHeader closest
317 // to the payload, this can be wrapped in a FinalizedObjectHeader if the
318 // object is on the GeneralHeap and not on a specific TypedHeap.
319 // Finally if the object is a large object (> blinkPageSize/2) then it is
320 // wrapped with a LargeObjectHeader.
321 //
322 // Object memory layout:
323 // [ LargeObjectHeader | ] [ FinalizedObjectHeader | ] HeapObjectHeader | payloa d
324 // The [ ] notation denotes that the LargeObjectHeader and the FinalizedObjectHe ader
325 // are independently optional.
326 class PLATFORM_EXPORT HeapObjectHeader : public BasicObjectHeader {
327 public:
328 NO_SANITIZE_ADDRESS
329 explicit HeapObjectHeader(size_t encodedSize)
330 : BasicObjectHeader(encodedSize)
331 #if ENABLE(ASSERT)
332 , m_magic(magic)
333 #endif
334 { }
335
336 NO_SANITIZE_ADDRESS
337 HeapObjectHeader(size_t encodedSize, const GCInfo*)
338 : BasicObjectHeader(encodedSize)
339 #if ENABLE(ASSERT)
340 , m_magic(magic)
341 #endif
342 { }
343
344 inline void checkHeader() const;
345 inline bool isMarked() const;
346
347 inline void mark();
348 inline void unmark();
349
350 inline const GCInfo* gcInfo() { return 0; }
351
352 inline Address payload();
353 inline size_t payloadSize();
354 inline Address payloadEnd();
355
356 inline void setDeadMark();
357 inline void clearDeadMark();
358 inline bool hasDeadMark() const;
359
360 // Zap magic number with a new magic number that means there was once an
361 // object allocated here, but it was freed because nobody marked it during
362 // GC.
363 void zapMagic();
364
365 static void finalize(const GCInfo*, Address, size_t);
366 static HeapObjectHeader* fromPayload(const void*);
367
368 static const intptr_t magic = 0xc0de247;
369 static const intptr_t zappedMagic = 0xC0DEdead;
370 // The zap value for vtables should be < 4K to ensure it cannot be
371 // used for dispatch.
372 static const intptr_t zappedVTable = 0xd0d;
373
374 private:
375 #if ENABLE(ASSERT)
376 intptr_t m_magic;
377 #endif
378 };
379
380 const size_t objectHeaderSize = sizeof(HeapObjectHeader);
381
382 // Each object on the GeneralHeap needs to carry a pointer to its
383 // own GCInfo structure for tracing and potential finalization.
384 class PLATFORM_EXPORT FinalizedHeapObjectHeader : public HeapObjectHeader {
385 public:
386 NO_SANITIZE_ADDRESS
387 FinalizedHeapObjectHeader(size_t encodedSize, const GCInfo* gcInfo)
388 : HeapObjectHeader(encodedSize)
389 , m_gcInfo(gcInfo)
390 {
391 }
392
393 inline Address payload();
394 inline size_t payloadSize();
395
396 NO_SANITIZE_ADDRESS
397 const GCInfo* gcInfo() { return m_gcInfo; }
398
399 NO_SANITIZE_ADDRESS
400 TraceCallback traceCallback() { return m_gcInfo->m_trace; }
401
402 void finalize();
403
404 NO_SANITIZE_ADDRESS
405 inline bool hasFinalizer() { return m_gcInfo->hasFinalizer(); }
406
407 static FinalizedHeapObjectHeader* fromPayload(const void*);
408
409 NO_SANITIZE_ADDRESS
410 bool hasVTable() { return m_gcInfo->hasVTable(); }
411
412 private:
413 const GCInfo* m_gcInfo;
414 };
415
416 const size_t finalizedHeaderSize = sizeof(FinalizedHeapObjectHeader);
417
418 class FreeListEntry : public HeapObjectHeader {
419 public:
420 NO_SANITIZE_ADDRESS
421 explicit FreeListEntry(size_t size)
422 : HeapObjectHeader(freeListEncodedSize(size))
423 , m_next(0)
424 {
425 #if ENABLE(ASSERT) && !defined(ADDRESS_SANITIZER)
426 // Zap free area with asterisks, aka 0x2a2a2a2a.
427 // For ASan don't zap since we keep accounting in the freelist entry.
428 for (size_t i = sizeof(*this); i < size; i++)
429 reinterpret_cast<Address>(this)[i] = freelistZapValue;
430 ASSERT(size >= objectHeaderSize);
431 zapMagic();
432 #endif
433 }
434
435 Address address() { return reinterpret_cast<Address>(this); }
436
437 NO_SANITIZE_ADDRESS
438 void unlink(FreeListEntry** prevNext)
439 {
440 *prevNext = m_next;
441 m_next = 0;
442 }
443
444 NO_SANITIZE_ADDRESS
445 void link(FreeListEntry** prevNext)
446 {
447 m_next = *prevNext;
448 *prevNext = this;
449 }
450
451 NO_SANITIZE_ADDRESS
452 FreeListEntry* next() const { return m_next; }
453
454 NO_SANITIZE_ADDRESS
455 void append(FreeListEntry* next)
456 {
457 ASSERT(!m_next);
458 m_next = next;
459 }
460
461 #if defined(ADDRESS_SANITIZER)
462 NO_SANITIZE_ADDRESS
463 bool shouldAddToFreeList()
464 {
465 // Init if not already magic.
466 if ((m_asanMagic & ~asanDeferMemoryReuseMask) != asanMagic) {
467 m_asanMagic = asanMagic | asanDeferMemoryReuseCount;
468 return false;
469 }
470 // Decrement if count part of asanMagic > 0.
471 if (m_asanMagic & asanDeferMemoryReuseMask)
472 m_asanMagic--;
473 return !(m_asanMagic & asanDeferMemoryReuseMask);
474 }
475 #endif
476
477 private:
478 FreeListEntry* m_next;
479 #if defined(ADDRESS_SANITIZER)
480 unsigned m_asanMagic;
481 #endif
482 };
483
484 // Representation of Blink heap pages.
485 //
486 // Pages are specialized on the type of header on the object they
487 // contain. If a heap page only contains a certain type of object all
488 // of the objects will have the same GCInfo pointer and therefore that
489 // pointer can be stored in the HeapPage instead of in the header of
490 // each object. In that case objects have only a HeapObjectHeader and
491 // not a FinalizedHeapObjectHeader saving a word per object.
492 template<typename Header>
493 class HeapPage : public BaseHeapPage {
494 public:
495 HeapPage(PageMemory*, ThreadHeap<Header>*, const GCInfo*);
496
497 void link(HeapPage**);
498 static void unlink(ThreadHeap<Header>*, HeapPage*, HeapPage**);
499
500 bool isEmpty();
501
502 // Returns true for the whole blinkPageSize page that the page is on, even
503 // for the header, and the unmapped guard page at the start. That ensures
504 // the result can be used to populate the negative page cache.
505 virtual bool contains(Address addr) override
506 {
507 Address blinkPageStart = roundToBlinkPageStart(address());
508 ASSERT(blinkPageStart == address() - osPageSize()); // Page is at aligne d address plus guard page size.
509 return blinkPageStart <= addr && addr < blinkPageStart + blinkPageSize;
510 }
511
512 HeapPage* next() { return m_next; }
513
514 Address payload()
515 {
516 return address() + sizeof(*this) + headerPadding<Header>();
517 }
518
519 static size_t payloadSize()
520 {
521 return (blinkPagePayloadSize() - sizeof(HeapPage) - headerPadding<Header >()) & ~allocationMask;
522 }
523
524 Address end() { return payload() + payloadSize(); }
525
526 void getStats(HeapStats&);
527 void clearLiveAndMarkDead();
528 void sweep(HeapStats*, ThreadHeap<Header>*);
529 void clearObjectStartBitMap();
530 void finalize(Header*);
531 virtual void checkAndMarkPointer(Visitor*, Address) override;
532 #if ENABLE(GC_PROFILE_MARKING)
533 const GCInfo* findGCInfo(Address) override;
534 #endif
535 #if ENABLE(GC_PROFILE_HEAP)
536 virtual void snapshot(TracedValue*, ThreadState::SnapshotInfo*);
537 #endif
538
539 #if defined(ADDRESS_SANITIZER)
540 void poisonUnmarkedObjects();
541 #endif
542 NO_SANITIZE_ADDRESS
543 virtual void markOrphaned()
544 {
545 // Zap the payload with a recognizable value to detect any incorrect
546 // cross thread pointer usage.
547 #if defined(ADDRESS_SANITIZER)
548 // Don't use memset when running with ASan since this needs to zap
549 // poisoned memory as well and the NO_SANITIZE_ADDRESS annotation
550 // only works for code in this method and not for calls to memset.
551 for (Address current = payload(); current < payload() + payloadSize(); + +current)
552 *current = orphanedZapValue;
553 #else
554 memset(payload(), orphanedZapValue, payloadSize());
555 #endif
556 BaseHeapPage::markOrphaned();
557 }
558
559 protected:
560 Header* findHeaderFromAddress(Address);
561 void populateObjectStartBitMap();
562 bool isObjectStartBitMapComputed() { return m_objectStartBitMapComputed; }
563 TraceCallback traceCallback(Header*);
564 bool hasVTable(Header*);
565
566 intptr_t padding() const { return m_padding; }
567
568 HeapPage<Header>* m_next;
569 intptr_t m_padding; // Preserve 8-byte alignment on 32-bit systems.
570 bool m_objectStartBitMapComputed;
571 uint8_t m_objectStartBitMap[reservedForObjectBitMap];
572
573 friend class ThreadHeap<Header>;
574 };
575
576 class AddressEntry {
577 public:
578 AddressEntry() : m_address(0) { }
579
580 explicit AddressEntry(Address address) : m_address(address) { }
581
582 Address address() const { return m_address; }
583
584 private:
585 Address m_address;
586 };
587
588 class PositiveEntry : public AddressEntry {
589 public:
590 PositiveEntry()
591 : AddressEntry()
592 , m_containingPage(0)
593 {
594 }
595
596 PositiveEntry(Address address, BaseHeapPage* containingPage)
597 : AddressEntry(address)
598 , m_containingPage(containingPage)
599 {
600 }
601
602 BaseHeapPage* result() const { return m_containingPage; }
603
604 typedef BaseHeapPage* LookupResult;
605
606 private:
607 BaseHeapPage* m_containingPage;
608 };
609
610 class NegativeEntry : public AddressEntry {
611 public:
612 NegativeEntry() : AddressEntry() { }
613
614 NegativeEntry(Address address, bool) : AddressEntry(address) { }
615
616 bool result() const { return true; }
617
618 typedef bool LookupResult;
619 };
620
621 // A HeapExtentCache provides a fast way of taking an arbitrary
622 // pointer-sized word, and determining whether it can be interpreted
623 // as a pointer to an area that is managed by the garbage collected
624 // Blink heap. There is a cache of 'pages' that have previously been
625 // determined to be wholly inside the heap. The size of these pages must be
626 // smaller than the allocation alignment of the heap pages. We determine
627 // on-heap-ness by rounding down the pointer to the nearest page and looking up
628 // the page in the cache. If there is a miss in the cache we can ask the heap
629 // to determine the status of the pointer by iterating over all of the heap.
630 // The result is then cached in the two-way associative page cache.
631 //
632 // A HeapContainsCache is a positive cache. Therefore, it must be flushed when
633 // memory is removed from the Blink heap. The HeapDoesNotContainCache is a
634 // negative cache, so it must be flushed when memory is added to the heap.
635 template<typename Entry>
636 class HeapExtentCache {
637 public:
638 HeapExtentCache()
639 : m_entries(adoptArrayPtr(new Entry[HeapExtentCache::numberOfEntries]))
640 , m_hasEntries(false)
641 {
642 }
643
644 void flush();
645 bool contains(Address);
646 bool isEmpty() { return !m_hasEntries; }
647
648 // Perform a lookup in the cache.
649 //
650 // If lookup returns null/false the argument address was not found in
651 // the cache and it is unknown if the address is in the Blink
652 // heap.
653 //
654 // If lookup returns true/a page, the argument address was found in the
655 // cache. For the HeapContainsCache this means the address is in the heap.
656 // For the HeapDoesNotContainCache this means the address is not in the
657 // heap.
658 PLATFORM_EXPORT typename Entry::LookupResult lookup(Address);
659
660 // Add an entry to the cache.
661 PLATFORM_EXPORT void addEntry(Address, typename Entry::LookupResult);
662
663 private:
664 static const int numberOfEntriesLog2 = 12;
665 static const int numberOfEntries = 1 << numberOfEntriesLog2;
666
667 static size_t hash(Address);
668
669 WTF::OwnPtr<Entry[]> m_entries;
670 bool m_hasEntries;
671
672 friend class ThreadState;
673 };
674
675 // Normally these would be typedefs instead of subclasses, but that makes them
676 // very hard to forward declare.
677 class HeapContainsCache : public HeapExtentCache<PositiveEntry> {
678 public:
679 BaseHeapPage* lookup(Address);
680 void addEntry(Address, BaseHeapPage*);
681 };
682
683 class HeapDoesNotContainCache : public HeapExtentCache<NegativeEntry> { };
684
685 template<typename DataType>
686 class PagePool {
687 protected:
688 PagePool();
689
690 class PoolEntry {
691 public:
692 PoolEntry(DataType* data, PoolEntry* next)
693 : data(data)
694 , next(next)
695 { }
696
697 DataType* data;
698 PoolEntry* next;
699 };
700
701 PoolEntry* m_pool[NumberOfHeaps];
702 };
703
704 // Once pages have been used for one type of thread heap they will never be
705 // reused for another type of thread heap. Instead of unmapping, we add the
706 // pages to a pool of pages to be reused later by a thread heap of the same
707 // type. This is done as a security feature to avoid type confusion. The
708 // heaps are type segregated by having separate thread heaps for different
709 // types of objects. Holding on to pages ensures that the same virtual address
710 // space cannot be used for objects of another type than the type contained
711 // in this page to begin with.
712 class FreePagePool : public PagePool<PageMemory> {
713 public:
714 ~FreePagePool();
715 void addFreePage(int, PageMemory*);
716 PageMemory* takeFreePage(int);
717
718 private:
719 Mutex m_mutex[NumberOfHeaps];
720 };
721
722 class OrphanedPagePool : public PagePool<BaseHeapPage> {
723 public:
724 ~OrphanedPagePool();
725 void addOrphanedPage(int, BaseHeapPage*);
726 void decommitOrphanedPages();
727 #if ENABLE(ASSERT)
728 bool contains(void*);
729 #endif
730 private:
731 void clearMemory(PageMemory*);
732 };
733
734 // The CallbackStack contains all the visitor callbacks used to trace and mark
735 // objects. A specific CallbackStack instance contains at most bufferSize elemen ts.
736 // If more space is needed a new CallbackStack instance is created and chained
737 // together with the former instance. I.e. a logical CallbackStack can be made o f
738 // multiple chained CallbackStack object instances.
739 // There are two logical callback stacks. One containing all the marking callbac ks and
740 // one containing the weak pointer callbacks.
741 class CallbackStack {
742 public:
743 CallbackStack(CallbackStack** first)
744 : m_limit(&(m_buffer[bufferSize]))
745 , m_current(&(m_buffer[0]))
746 , m_next(*first)
747 {
748 #if ENABLE(ASSERT)
749 clearUnused();
750 #endif
751 *first = this;
752 }
753
754 ~CallbackStack();
755 void clearUnused();
756
757 bool isEmpty();
758
759 CallbackStack* takeCallbacks(CallbackStack** first);
760
761 class Item {
762 public:
763 Item() { }
764 Item(void* object, VisitorCallback callback)
765 : m_object(object)
766 , m_callback(callback)
767 {
768 }
769 void* object() { return m_object; }
770 VisitorCallback callback() { return m_callback; }
771
772 private:
773 void* m_object;
774 VisitorCallback m_callback;
775 };
776
777 static void init(CallbackStack** first);
778 static void shutdown(CallbackStack** first);
779 static void clear(CallbackStack** first)
780 {
781 if (!(*first)->isEmpty()) {
782 shutdown(first);
783 init(first);
784 }
785 }
786 template<CallbackInvocationMode Mode> bool popAndInvokeCallback(CallbackStac k** first, Visitor*);
787 static void invokeCallbacks(CallbackStack** first, Visitor*);
788
789 Item* allocateEntry(CallbackStack** first)
790 {
791 if (m_current < m_limit)
792 return m_current++;
793 return (new CallbackStack(first))->allocateEntry(first);
794 }
795
796 #if ENABLE(ASSERT)
797 bool hasCallbackForObject(const void*);
798 #endif
799
800 bool numberOfBlocksExceeds(int blocks)
801 {
802 CallbackStack* current = this;
803 for (int i = 0; i < blocks; ++i) {
804 if (!current->m_next)
805 return false;
806 current = current->m_next;
807 }
808 return true;
809 }
810
811 private:
812 void invokeOldestCallbacks(Visitor*);
813 bool currentBlockIsEmpty() { return m_current == &(m_buffer[0]); }
814
815 static const size_t bufferSize = 200;
816 Item m_buffer[bufferSize];
817 Item* m_limit;
818 Item* m_current;
819 CallbackStack* m_next;
820 };
821
822 // Non-template super class used to pass a heap around to other classes.
823 class BaseHeap {
824 public:
825 virtual ~BaseHeap() { }
826 virtual void cleanupPages() = 0;
827
828 // Find the page in this thread heap containing the given
829 // address. Returns 0 if the address is not contained in any
830 // page in this thread heap.
831 virtual BaseHeapPage* heapPageFromAddress(Address) = 0;
832
833 #if ENABLE(GC_PROFILE_MARKING)
834 virtual const GCInfo* findGCInfoOfLargeHeapObject(Address) = 0;
835 #endif
836
837 #if ENABLE(GC_PROFILE_HEAP)
838 virtual void snapshot(TracedValue*, ThreadState::SnapshotInfo*) = 0;
839 #endif
840
841 // Sweep this part of the Blink heap. This finalizes dead objects
842 // and builds freelists for all the unused memory.
843 virtual void sweep(HeapStats*) = 0;
844 virtual void postSweepProcessing() = 0;
845
846 virtual void clearFreeLists() = 0;
847 virtual void clearLiveAndMarkDead() = 0;
848
849 virtual void makeConsistentForSweeping() = 0;
850
851 #if ENABLE(ASSERT)
852 virtual bool isConsistentForSweeping() = 0;
853
854 virtual void getScannedStats(HeapStats&) = 0;
855 #endif
856
857 virtual void prepareHeapForTermination() = 0;
858
859 virtual int normalPageCount() = 0;
860
861 virtual BaseHeap* split(int normalPages) = 0;
862 virtual void merge(BaseHeap* other) = 0;
863
864 // Returns a bucket number for inserting a FreeListEntry of a
865 // given size. All FreeListEntries in the given bucket, n, have
866 // size >= 2^n.
867 static int bucketIndexForSize(size_t);
868 };
869
870 // Thread heaps represent a part of the per-thread Blink heap.
871 //
872 // Each Blink thread has a number of thread heaps: one general heap
873 // that contains any type of object and a number of heaps specialized
874 // for specific object types (such as Node).
875 //
876 // Each thread heap contains the functionality to allocate new objects
877 // (potentially adding new pages to the heap), to find and mark
878 // objects during conservative stack scanning and to sweep the set of
879 // pages after a GC.
880 template<typename Header>
881 class ThreadHeap : public BaseHeap {
882 public:
883 ThreadHeap(ThreadState*, int);
884 virtual ~ThreadHeap();
885 virtual void cleanupPages();
886
887 virtual BaseHeapPage* heapPageFromAddress(Address);
888 #if ENABLE(GC_PROFILE_MARKING)
889 virtual const GCInfo* findGCInfoOfLargeHeapObject(Address);
890 #endif
891 #if ENABLE(GC_PROFILE_HEAP)
892 virtual void snapshot(TracedValue*, ThreadState::SnapshotInfo*);
893 #endif
894
895 virtual void sweep(HeapStats*);
896 virtual void postSweepProcessing();
897
898 virtual void clearFreeLists();
899 virtual void clearLiveAndMarkDead();
900
901 virtual void makeConsistentForSweeping();
902
903 #if ENABLE(ASSERT)
904 virtual bool isConsistentForSweeping();
905
906 virtual void getScannedStats(HeapStats&);
907 #endif
908
909 ThreadState* threadState() { return m_threadState; }
910 HeapStats& stats() { return m_threadState->stats(); }
911 void flushHeapContainsCache()
912 {
913 m_threadState->heapContainsCache()->flush();
914 }
915
916 inline Address allocate(size_t, const GCInfo*);
917 void addToFreeList(Address, size_t);
918 inline static size_t roundedAllocationSize(size_t size)
919 {
920 return allocationSizeFromSize(size) - sizeof(Header);
921 }
922
923 virtual void prepareHeapForTermination();
924
925 virtual int normalPageCount() { return m_numberOfNormalPages; }
926
927 virtual BaseHeap* split(int numberOfNormalPages);
928 virtual void merge(BaseHeap* splitOffBase);
929
930 void removePageFromHeap(HeapPage<Header>*);
931
932 PLATFORM_EXPORT void promptlyFreeObject(Header*);
933
934 private:
935 void addPageToHeap(const GCInfo*);
936 PLATFORM_EXPORT Address outOfLineAllocate(size_t, const GCInfo*);
937 static size_t allocationSizeFromSize(size_t);
938 PLATFORM_EXPORT Address allocateLargeObject(size_t, const GCInfo*);
939 Address currentAllocationPoint() const { return m_currentAllocationPoint; }
940 size_t remainingAllocationSize() const { return m_remainingAllocationSize; }
941 bool ownsNonEmptyAllocationArea() const { return currentAllocationPoint() && remainingAllocationSize(); }
942 void setAllocationPoint(Address point, size_t size)
943 {
944 ASSERT(!point || heapPageFromAddress(point));
945 ASSERT(size <= HeapPage<Header>::payloadSize());
946 m_currentAllocationPoint = point;
947 m_remainingAllocationSize = size;
948 }
949 void ensureCurrentAllocation(size_t, const GCInfo*);
950 bool allocateFromFreeList(size_t);
951
952 void freeLargeObject(LargeHeapObject<Header>*, LargeHeapObject<Header>**);
953 void allocatePage(const GCInfo*);
954
955 #if ENABLE(ASSERT)
956 bool pagesToBeSweptContains(Address);
957 bool pagesAllocatedDuringSweepingContains(Address);
958 #endif
959
960 void sweepNormalPages(HeapStats*);
961 void sweepLargePages(HeapStats*);
962 bool coalesce(size_t);
963
964 Address m_currentAllocationPoint;
965 size_t m_remainingAllocationSize;
966
967 HeapPage<Header>* m_firstPage;
968 LargeHeapObject<Header>* m_firstLargeHeapObject;
969
970 HeapPage<Header>* m_firstPageAllocatedDuringSweeping;
971 HeapPage<Header>* m_lastPageAllocatedDuringSweeping;
972
973 // Merge point for parallel sweep.
974 HeapPage<Header>* m_mergePoint;
975
976 int m_biggestFreeListIndex;
977
978 ThreadState* m_threadState;
979
980 // All FreeListEntries in the nth list have size >= 2^n.
981 FreeListEntry* m_freeLists[blinkPageSizeLog2];
982 FreeListEntry* m_lastFreeListEntries[blinkPageSizeLog2];
983
984 // Index into the page pools. This is used to ensure that the pages of the
985 // same type go into the correct page pool and thus avoid type confusion.
986 int m_index;
987
988 int m_numberOfNormalPages;
989
990 // The promptly freed count contains the number of promptly freed objects
991 // since the last sweep or since it was manually reset to delay coalescing.
992 size_t m_promptlyFreedCount;
993 };
994
995 class PLATFORM_EXPORT Heap {
996 public:
997 static BaseHeapPage* contains(Address);
998 static BaseHeapPage* contains(void* pointer) { return contains(reinterpret_c ast<Address>(pointer)); }
999 static BaseHeapPage* contains(const void* pointer) { return contains(const_c ast<void*>(pointer)); }
1000 #if ENABLE(ASSERT)
1001 static bool containedInHeapOrOrphanedPage(void*);
1002 #endif
1003
1004 // Push a trace callback on the marking stack.
1005 static void pushTraceCallback(CallbackStack**, void* containerObject, TraceC allback);
1006
1007 // Push a trace callback on the post-marking callback stack. These callbacks
1008 // are called after normal marking (including ephemeron iteration).
1009 static void pushPostMarkingCallback(void*, TraceCallback);
1010
1011 // Add a weak pointer callback to the weak callback work list. General
1012 // object pointer callbacks are added to a thread local weak callback work
1013 // list and the callback is called on the thread that owns the object, with
1014 // the closure pointer as an argument. Most of the time, the closure and
1015 // the containerObject can be the same thing, but the containerObject is
1016 // constrained to be on the heap, since the heap is used to identify the
1017 // correct thread.
1018 static void pushWeakObjectPointerCallback(void* closure, void* containerObje ct, WeakPointerCallback);
1019
1020 // Similar to the more general pushWeakObjectPointerCallback, but cell
1021 // pointer callbacks are added to a static callback work list and the weak
1022 // callback is performed on the thread performing garbage collection. This
1023 // is OK because cells are just cleared and no deallocation can happen.
1024 static void pushWeakCellPointerCallback(void** cell, WeakPointerCallback);
1025
1026 // Pop the top of the marking stack and call the callback with the visitor
1027 // and the object. Returns false when there is nothing more to do.
1028 template<CallbackInvocationMode Mode> static bool popAndInvokeTraceCallback( Visitor*);
1029
1030 // Remove an item from the post-marking callback stack and call
1031 // the callback with the visitor and the object pointer. Returns
1032 // false when there is nothing more to do.
1033 static bool popAndInvokePostMarkingCallback(Visitor*);
1034
1035 // Remove an item from the weak callback work list and call the callback
1036 // with the visitor and the closure pointer. Returns false when there is
1037 // nothing more to do.
1038 static bool popAndInvokeWeakPointerCallback(Visitor*);
1039
1040 // Register an ephemeron table for fixed-point iteration.
1041 static void registerWeakTable(void* containerObject, EphemeronCallback, Ephe meronCallback);
1042 #if ENABLE(ASSERT)
1043 static bool weakTableRegistered(const void*);
1044 #endif
1045
1046 template<typename T, typename HeapTraits = HeapTypeTrait<T> > static Address allocate(size_t);
1047 template<typename T> static Address reallocate(void* previous, size_t);
1048
1049 static void collectGarbage(ThreadState::StackState);
1050 static void collectGarbageForTerminatingThread(ThreadState*);
1051 static void collectAllGarbage();
1052 static void processMarkingStackEntries(int* numberOfMarkingThreads);
1053 static void processMarkingStackOnMultipleThreads();
1054 static void processMarkingStackInParallel();
1055 template<CallbackInvocationMode Mode> static void processMarkingStack();
1056 static void postMarkingProcessing();
1057 static void globalWeakProcessing();
1058 static void setForcePreciseGCForTesting();
1059
1060 static void prepareForGC();
1061
1062 // Conservatively checks whether an address is a pointer in any of the threa d
1063 // heaps. If so marks the object pointed to as live.
1064 static Address checkAndMarkPointer(Visitor*, Address);
1065
1066 #if ENABLE(GC_PROFILE_MARKING)
1067 // Dump the path to specified object on the next GC. This method is to be in voked from GDB.
1068 static void dumpPathToObjectOnNextGC(void* p);
1069
1070 // Forcibly find GCInfo of the object at Address.
1071 // This is slow and should only be used for debug purposes.
1072 // It involves finding the heap page and scanning the heap page for an objec t header.
1073 static const GCInfo* findGCInfo(Address);
1074
1075 static String createBacktraceString();
1076 #endif
1077
1078 // Collect heap stats for all threads attached to the Blink
1079 // garbage collector. Should only be called during garbage
1080 // collection where threads are known to be at safe points.
1081 static void getStats(HeapStats*);
1082
1083 static void getHeapSpaceSize(uint64_t*, uint64_t*);
1084
1085 static void makeConsistentForSweeping();
1086
1087 #if ENABLE(ASSERT)
1088 static bool isConsistentForSweeping();
1089 #endif
1090
1091 static void flushHeapDoesNotContainCache();
1092 static bool heapDoesNotContainCacheIsEmpty() { return s_heapDoesNotContainCa che->isEmpty(); }
1093
1094 // Return true if the last GC found a pointer into a heap page
1095 // during conservative scanning.
1096 static bool lastGCWasConservative() { return s_lastGCWasConservative; }
1097
1098 static FreePagePool* freePagePool() { return s_freePagePool; }
1099 static OrphanedPagePool* orphanedPagePool() { return s_orphanedPagePool; }
1100
1101 private:
1102 static Visitor* s_markingVisitor;
1103 static Vector<OwnPtr<blink::WebThread> >* s_markingThreads;
1104 static CallbackStack* s_markingStack;
1105 static CallbackStack* s_postMarkingCallbackStack;
1106 static CallbackStack* s_weakCallbackStack;
1107 static CallbackStack* s_ephemeronStack;
1108 static HeapDoesNotContainCache* s_heapDoesNotContainCache;
1109 static bool s_shutdownCalled;
1110 static bool s_lastGCWasConservative;
1111 static FreePagePool* s_freePagePool;
1112 static OrphanedPagePool* s_orphanedPagePool;
1113 friend class ThreadState;
1114 };
1115
1116 // The NoAllocationScope class is used in debug mode to catch unwanted
1117 // allocations. E.g. allocations during GC.
1118 template<ThreadAffinity Affinity>
1119 class NoAllocationScope {
1120 public:
1121 NoAllocationScope() : m_active(true) { enter(); }
1122
1123 explicit NoAllocationScope(bool active) : m_active(active) { enter(); }
1124
1125 NoAllocationScope(const NoAllocationScope& other) : m_active(other.m_active) { enter(); }
1126
1127 NoAllocationScope& operator=(const NoAllocationScope& other)
1128 {
1129 release();
1130 m_active = other.m_active;
1131 enter();
1132 return *this;
1133 }
1134
1135 ~NoAllocationScope() { release(); }
1136
1137 void release()
1138 {
1139 if (m_active) {
1140 ThreadStateFor<Affinity>::state()->leaveNoAllocationScope();
1141 m_active = false;
1142 }
1143 }
1144
1145 private:
1146 void enter() const
1147 {
1148 if (m_active)
1149 ThreadStateFor<Affinity>::state()->enterNoAllocationScope();
1150 }
1151
1152 bool m_active;
1153 };
1154
1155 // Classes that contain heap references but aren't themselves heap
1156 // allocated, have some extra macros available which allows their use
1157 // to be restricted to cases where the garbage collector is able
1158 // to discover their heap references.
1159 //
1160 // STACK_ALLOCATED(): Use if the object is only stack allocated. Heap objects
1161 // should be in Members but you do not need the trace method as they are on
1162 // the stack. (Down the line these might turn in to raw pointers, but for
1163 // now Members indicates that we have thought about them and explicitly
1164 // taken care of them.)
1165 //
1166 // DISALLOW_ALLOCATION(): Cannot be allocated with new operators but can
1167 // be a part object. If it has Members you need a trace method and the
1168 // containing object needs to call that trace method.
1169 //
1170 // ALLOW_ONLY_INLINE_ALLOCATION(): Allows only placement new operator.
1171 // This disallows general allocation of this object but allows to put
1172 // the object as a value object in collections. If these have Members you
1173 // need to have a trace method. That trace method will be called
1174 // automatically by the Heap collections.
1175 //
1176 #define DISALLOW_ALLOCATION() \
1177 private: \
1178 void* operator new(size_t) = delete; \
1179 void* operator new(size_t, NotNullTag, void*) = delete; \
1180 void* operator new(size_t, void*) = delete;
1181
1182 #define ALLOW_ONLY_INLINE_ALLOCATION() \
1183 public: \
1184 void* operator new(size_t, NotNullTag, void* location) { return location ; } \
1185 void* operator new(size_t, void* location) { return location; } \
1186 private: \
1187 void* operator new(size_t) = delete;
1188
1189 #define STATIC_ONLY(Type) \
1190 private: \
1191 Type() = delete;
1192
1193 // These macros insert annotations that the Blink GC plugin for clang uses for
1194 // verification. STACK_ALLOCATED is used to declare that objects of this type
1195 // are always stack allocated. GC_PLUGIN_IGNORE is used to make the plugin
1196 // ignore a particular class or field when checking for proper usage. When using
1197 // GC_PLUGIN_IGNORE a bug-number should be provided as an argument where the
1198 // bug describes what needs to happen to remove the GC_PLUGIN_IGNORE again.
1199 #if COMPILER(CLANG)
1200 #define STACK_ALLOCATED() \
1201 private: \
1202 __attribute__((annotate("blink_stack_allocated"))) \
1203 void* operator new(size_t) = delete; \
1204 void* operator new(size_t, NotNullTag, void*) = delete; \
1205 void* operator new(size_t, void*) = delete;
1206
1207 #define GC_PLUGIN_IGNORE(bug) \
1208 __attribute__((annotate("blink_gc_plugin_ignore")))
1209 #else
1210 #define STACK_ALLOCATED() DISALLOW_ALLOCATION()
1211 #define GC_PLUGIN_IGNORE(bug)
1212 #endif
1213
1214 NO_SANITIZE_ADDRESS
1215 void HeapObjectHeader::checkHeader() const
1216 {
1217 #if ENABLE(ASSERT)
1218 BaseHeapPage* page = pageHeaderFromObject(this);
1219 ASSERT(page->orphaned() || m_magic == magic);
1220 #endif
1221 }
1222
1223 Address HeapObjectHeader::payload()
1224 {
1225 return reinterpret_cast<Address>(this) + objectHeaderSize;
1226 }
1227
1228 size_t HeapObjectHeader::payloadSize()
1229 {
1230 return size() - objectHeaderSize;
1231 }
1232
1233 Address HeapObjectHeader::payloadEnd()
1234 {
1235 return reinterpret_cast<Address>(this) + size();
1236 }
1237
1238 NO_SANITIZE_ADDRESS
1239 void HeapObjectHeader::mark()
1240 {
1241 checkHeader();
1242 // The use of atomic ops guarantees that the reads and writes are
1243 // atomic and that no memory operation reorderings take place.
1244 // Multiple threads can still read the old value and all store the
1245 // new value. However, the new value will be the same for all of
1246 // the threads and the end result is therefore consistent.
1247 unsigned size = acquireLoad(&m_size);
1248 releaseStore(&m_size, size | markBitMask);
1249 }
1250
1251 Address FinalizedHeapObjectHeader::payload()
1252 {
1253 return reinterpret_cast<Address>(this) + finalizedHeaderSize;
1254 }
1255
1256 size_t FinalizedHeapObjectHeader::payloadSize()
1257 {
1258 return size() - finalizedHeaderSize;
1259 }
1260
1261 template<typename Header>
1262 size_t ThreadHeap<Header>::allocationSizeFromSize(size_t size)
1263 {
1264 // Check the size before computing the actual allocation size. The
1265 // allocation size calculation can overflow for large sizes and
1266 // the check therefore has to happen before any calculation on the
1267 // size.
1268 RELEASE_ASSERT(size < maxHeapObjectSize);
1269
1270 // Add space for header.
1271 size_t allocationSize = size + sizeof(Header);
1272 // Align size with allocation granularity.
1273 allocationSize = (allocationSize + allocationMask) & ~allocationMask;
1274 return allocationSize;
1275 }
1276
1277 template<typename Header>
1278 Address ThreadHeap<Header>::allocate(size_t size, const GCInfo* gcInfo)
1279 {
1280 size_t allocationSize = allocationSizeFromSize(size);
1281 bool isLargeObject = allocationSize > blinkPageSize / 2;
1282 if (isLargeObject)
1283 return allocateLargeObject(allocationSize, gcInfo);
1284 if (m_remainingAllocationSize < allocationSize)
1285 return outOfLineAllocate(size, gcInfo);
1286 Address headerAddress = m_currentAllocationPoint;
1287 m_currentAllocationPoint += allocationSize;
1288 m_remainingAllocationSize -= allocationSize;
1289 Header* header = new (NotNull, headerAddress) Header(allocationSize, gcInfo) ;
1290 size_t payloadSize = allocationSize - sizeof(Header);
1291 stats().increaseObjectSpace(payloadSize);
1292 Address result = headerAddress + sizeof(*header);
1293 ASSERT(!(reinterpret_cast<uintptr_t>(result) & allocationMask));
1294 // Unpoison the memory used for the object (payload).
1295 ASAN_UNPOISON_MEMORY_REGION(result, payloadSize);
1296 #if ENABLE(ASSERT) || defined(LEAK_SANITIZER) || defined(ADDRESS_SANITIZER)
1297 memset(result, 0, payloadSize);
1298 #endif
1299 ASSERT(heapPageFromAddress(headerAddress + allocationSize - 1));
1300 return result;
1301 }
1302
1303 template<typename T, typename HeapTraits>
1304 Address Heap::allocate(size_t size)
1305 {
1306 ASSERT_NOT_REACHED();
1307 return 0;
1308 }
1309
1310 template<typename T>
1311 Address Heap::reallocate(void* previous, size_t size)
1312 {
1313 if (!size) {
1314 // If the new size is 0 this is equivalent to either
1315 // free(previous) or malloc(0). In both cases we do
1316 // nothing and return 0.
1317 return 0;
1318 }
1319 ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state();
1320 ASSERT(state->isAllocationAllowed());
1321 const GCInfo* gcInfo = GCInfoTrait<T>::get();
1322 int heapIndex = HeapTypeTrait<T>::index(gcInfo->hasFinalizer());
1323 // FIXME: Currently only supports raw allocation on the
1324 // GeneralHeap. Hence we assume the header is a
1325 // FinalizedHeapObjectHeader.
1326 ASSERT(heapIndex == GeneralHeap || heapIndex == GeneralHeapNonFinalized);
1327 BaseHeap* heap = state->heap(heapIndex);
1328 Address address = static_cast<typename HeapTypeTrait<T>::HeapType*>(heap)->a llocate(size, gcInfo);
1329 if (!previous) {
1330 // This is equivalent to malloc(size).
1331 return address;
1332 }
1333 FinalizedHeapObjectHeader* previousHeader = FinalizedHeapObjectHeader::fromP ayload(previous);
1334 ASSERT(!previousHeader->hasFinalizer());
1335 ASSERT(previousHeader->gcInfo() == gcInfo);
1336 size_t copySize = previousHeader->payloadSize();
1337 if (copySize > size)
1338 copySize = size;
1339 memcpy(address, previous, copySize);
1340 return address;
1341 }
1342
1343 class HeapAllocatorQuantizer {
1344 public:
1345 template<typename T>
1346 static size_t quantizedSize(size_t count)
1347 {
1348 RELEASE_ASSERT(count <= kMaxUnquantizedAllocation / sizeof(T));
1349 return HeapIndexTrait<CollectionBackingHeap>::HeapType::roundedAllocatio nSize(count * sizeof(T));
1350 }
1351 static const size_t kMaxUnquantizedAllocation = maxHeapObjectSize;
1352 };
1353
1354 // This is a static-only class used as a trait on collections to make them heap allocated.
1355 // However see also HeapListHashSetAllocator.
1356 class HeapAllocator {
1357 public:
1358 typedef HeapAllocatorQuantizer Quantizer;
1359 typedef blink::Visitor Visitor;
1360 static const bool isGarbageCollected = true;
1361
1362 template <typename Return, typename Metadata>
1363 static Return backingMalloc(size_t size)
1364 {
1365 return reinterpret_cast<Return>(Heap::allocate<Metadata, HeapIndexTrait< CollectionBackingHeap> >(size));
1366 }
1367 template <typename Return, typename Metadata>
1368 static Return zeroedBackingMalloc(size_t size)
1369 {
1370 return backingMalloc<Return, Metadata>(size);
1371 }
1372 template <typename Return, typename Metadata>
1373 static Return malloc(size_t size)
1374 {
1375 return reinterpret_cast<Return>(Heap::allocate<Metadata>(size));
1376 }
1377 PLATFORM_EXPORT static void backingFree(void* address);
1378
1379 static void free(void* address) { }
1380 template<typename T>
1381 static void* newArray(size_t bytes)
1382 {
1383 ASSERT_NOT_REACHED();
1384 return 0;
1385 }
1386
1387 static void deleteArray(void* ptr)
1388 {
1389 ASSERT_NOT_REACHED();
1390 }
1391
1392 static bool isAllocationAllowed()
1393 {
1394 ASSERT_NOT_REACHED();
1395 return false;
1396 }
1397
1398 static void markUsingGCInfo(Visitor* visitor, const void* buffer)
1399 {
1400 visitor->mark(buffer, FinalizedHeapObjectHeader::fromPayload(buffer)->tr aceCallback());
1401 }
1402
1403 static void markNoTracing(Visitor* visitor, const void* t) { visitor->markNo Tracing(t); }
1404
1405 template<typename T, typename Traits>
1406 static void trace(Visitor* visitor, T& t)
1407 {
1408 }
1409
1410 static void registerDelayedMarkNoTracing(Visitor* visitor, const void* objec t)
1411 {
1412 visitor->registerDelayedMarkNoTracing(object);
1413 }
1414
1415 static void registerWeakMembers(Visitor* visitor, const void* closure, const void* object, WeakPointerCallback callback)
1416 {
1417 visitor->registerWeakMembers(closure, object, callback);
1418 }
1419
1420 static void registerWeakTable(Visitor* visitor, const void* closure, Ephemer onCallback iterationCallback, EphemeronCallback iterationDoneCallback)
1421 {
1422 visitor->registerWeakTable(closure, iterationCallback, iterationDoneCall back);
1423 }
1424
1425 #if ENABLE(ASSERT)
1426 static bool weakTableRegistered(Visitor* visitor, const void* closure)
1427 {
1428 return visitor->weakTableRegistered(closure);
1429 }
1430 #endif
1431
1432 template<typename T>
1433 struct ResultType {
1434 typedef T* Type;
1435 };
1436
1437 template<typename T>
1438 struct OtherType {
1439 typedef T* Type;
1440 };
1441
1442 template<typename T>
1443 static T& getOther(T* other)
1444 {
1445 return *other;
1446 }
1447
1448 static void enterNoAllocationScope()
1449 {
1450 #if ENABLE(ASSERT)
1451 ThreadStateFor<AnyThread>::state()->enterNoAllocationScope();
1452 #endif
1453 }
1454
1455 static void leaveNoAllocationScope()
1456 {
1457 #if ENABLE(ASSERT)
1458 ThreadStateFor<AnyThread>::state()->leaveNoAllocationScope();
1459 #endif
1460 }
1461
1462 private:
1463 template<typename T, size_t u, typename V> friend class WTF::Vector;
1464 template<typename T, typename U, typename V, typename W> friend class WTF::H ashSet;
1465 template<typename T, typename U, typename V, typename W, typename X, typenam e Y> friend class WTF::HashMap;
1466 };
1467
1468 template<typename Value>
1469 static void traceListHashSetValue(Visitor* visitor, Value& value)
1470 {
1471 }
1472
1473 // The inline capacity is just a dummy template argument to match the off-heap
1474 // allocator.
1475 // This inherits from the static-only HeapAllocator trait class, but we do
1476 // declare pointers to instances. These pointers are always null, and no
1477 // objects are instantiated.
1478 template<typename ValueArg, size_t inlineCapacity>
1479 struct HeapListHashSetAllocator : public HeapAllocator {
1480 typedef HeapAllocator TableAllocator;
1481 typedef WTF::ListHashSetNode<ValueArg, HeapListHashSetAllocator> Node;
1482
1483 public:
1484 class AllocatorProvider {
1485 public:
1486 // For the heap allocation we don't need an actual allocator object, so we just
1487 // return null.
1488 HeapListHashSetAllocator* get() const { return 0; }
1489
1490 // No allocator object is needed.
1491 void createAllocatorIfNeeded() { }
1492
1493 // There is no allocator object in the HeapListHashSet (unlike in
1494 // the regular ListHashSet) so there is nothing to swap.
1495 void swap(AllocatorProvider& other) { }
1496 };
1497
1498 void deallocate(void* dummy) { }
1499
1500 // This is not a static method even though it could be, because it
1501 // needs to match the one that the (off-heap) ListHashSetAllocator
1502 // has. The 'this' pointer will always be null.
1503 void* allocateNode()
1504 {
1505 COMPILE_ASSERT(!WTF::IsWeak<ValueArg>::value, WeakPointersInAListHashSet WillJustResultInNullEntriesInTheSetThatsNotWhatYouWantConsiderUsingLinkedHashSet Instead);
1506 return malloc<void*, Node>(sizeof(Node));
1507 }
1508
1509 static void traceValue(Visitor* visitor, Node* node)
1510 {
1511 traceListHashSetValue(visitor, node->m_value);
1512 }
1513 };
1514
1515 // CollectionBackingTraceTrait. Do nothing for things in collections that don't
1516 // need tracing, or call TraceInCollectionTrait for those that do.
1517
1518 // Specialization for things that don't need marking and have no weak pointers. We
1519 // do nothing, even if WTF::WeakPointersActStrong.
1520 template<WTF::ShouldWeakPointersBeMarkedStrongly strongify, typename T, typename Traits>
1521 struct CollectionBackingTraceTrait<false, WTF::NoWeakHandlingInCollections, stro ngify, T, Traits> {
1522 static bool trace(Visitor*, T&) { return false; }
1523 };
1524
1525 // Specialization for things that either need marking or have weak pointers or
1526 // both.
1527 template<bool needsTracing, WTF::WeakHandlingFlag weakHandlingFlag, WTF::ShouldW eakPointersBeMarkedStrongly strongify, typename T, typename Traits>
1528 struct CollectionBackingTraceTrait {
1529 static bool trace(Visitor* visitor, T&t)
1530 {
1531 return false;
1532 }
1533 };
1534
1535 template<typename T> struct WeakHandlingHashTraits : WTF::SimpleClassHashTraits< T> {
1536 // We want to treat the object as a weak object in the sense that it can
1537 // disappear from hash sets and hash maps.
1538 static const WTF::WeakHandlingFlag weakHandlingFlag = WTF::WeakHandlingInCol lections;
1539 // Normally whether or not an object needs tracing is inferred
1540 // automatically from the presence of the trace method, but we don't
1541 // necessarily have a trace method, and we may not need one because T
1542 // can perhaps only be allocated inside collections, never as indpendent
1543 // objects. Explicitly mark this as needing tracing and it will be traced
1544 // in collections using the traceInCollection method, which it must have.
1545 template<typename U = void> struct NeedsTracingLazily {
1546 static const bool value = true;
1547 };
1548 // The traceInCollection method traces differently depending on whether we
1549 // are strongifying the trace operation. We strongify the trace operation
1550 // when there are active iterators on the object. In this case all
1551 // WeakMembers are marked like strong members so that elements do not
1552 // suddenly disappear during iteration. Returns true if weak pointers to
1553 // dead objects were found: In this case any strong pointers were not yet
1554 // traced and the entry should be removed from the collection.
1555 static bool traceInCollection(Visitor* visitor, T& t, WTF::ShouldWeakPointer sBeMarkedStrongly strongify)
1556 {
1557 return t.traceInCollection(visitor, strongify);
1558 }
1559 };
1560
1561 template<typename T, typename Traits>
1562 struct TraceTrait<HeapVectorBacking<T, Traits> > {
1563 typedef HeapVectorBacking<T, Traits> Backing;
1564 static void trace(Visitor* visitor, void* self)
1565 {
1566 }
1567 static void mark(Visitor* visitor, const Backing* backing)
1568 {
1569 }
1570 };
1571
1572 template<typename T>
1573 struct IfWeakMember;
1574
1575 template<typename T>
1576 struct IfWeakMember {
1577 template<typename U>
1578 static bool isDead(Visitor*, const U&) { return false; }
1579 };
1580
1581 template<typename T>
1582 struct IfWeakMember<WeakMember<T> > {
1583 static bool isDead(Visitor* visitor, const WeakMember<T>& t) { return !visit or->isAlive(t.get()); }
1584 };
1585
1586 }
1587
1588 #endif // Heap_h
OLDNEW
« sky/engine/core/css/MediaQueryMatcher.h ('K') | « sky/engine/platform/heap/Handle.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698