| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 1274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1285 // TODO(haraken): We don't support reallocate() for finalizable objects. | 1285 // TODO(haraken): We don't support reallocate() for finalizable objects. |
| 1286 ASSERT(!Heap::gcInfo(previousHeader->gcInfoIndex())->hasFinalizer()); | 1286 ASSERT(!Heap::gcInfo(previousHeader->gcInfoIndex())->hasFinalizer()); |
| 1287 ASSERT(previousHeader->gcInfoIndex() == GCInfoTrait<T>::index()); | 1287 ASSERT(previousHeader->gcInfoIndex() == GCInfoTrait<T>::index()); |
| 1288 size_t copySize = previousHeader->payloadSize(); | 1288 size_t copySize = previousHeader->payloadSize(); |
| 1289 if (copySize > size) | 1289 if (copySize > size) |
| 1290 copySize = size; | 1290 copySize = size; |
| 1291 memcpy(address, previous, copySize); | 1291 memcpy(address, previous, copySize); |
| 1292 return address; | 1292 return address; |
| 1293 } | 1293 } |
| 1294 | 1294 |
| 1295 template<bool needsTracing, WTF::WeakHandlingFlag weakHandlingFlag, WTF::ShouldW
eakPointersBeMarkedStrongly strongify, typename T, typename Traits> struct Colle
ctionBackingTraceTrait; | |
| 1296 template<typename T, typename Traits = WTF::VectorTraits<T>> class HeapVectorBac
king { | 1295 template<typename T, typename Traits = WTF::VectorTraits<T>> class HeapVectorBac
king { |
| 1297 public: | 1296 public: |
| 1298 static void finalize(void* pointer); | 1297 static void finalize(void* pointer); |
| 1299 void finalizeGarbageCollectedObject() { finalize(this); } | 1298 void finalizeGarbageCollectedObject() { finalize(this); } |
| 1300 }; | 1299 }; |
| 1300 |
| 1301 template<typename T, typename Traits> |
| 1302 void HeapVectorBacking<T, Traits>::finalize(void* pointer) |
| 1303 { |
| 1304 static_assert(Traits::needsDestruction, "Only vector buffers with items requ
iring destruction should be finalized"); |
| 1305 // See the comment in HeapVectorBacking::trace. |
| 1306 static_assert(Traits::canInitializeWithMemset || WTF::IsPolymorphic<T>::valu
e, "HeapVectorBacking doesn't support objects that cannot be initialized with me
mset or don't have a vtable"); |
| 1307 |
| 1308 ASSERT(!WTF::IsTriviallyDestructible<T>::value); |
| 1309 HeapObjectHeader* header = HeapObjectHeader::fromPayload(pointer); |
| 1310 // Use the payload size as recorded by the heap to determine how many |
| 1311 // elements to finalize. |
| 1312 size_t length = header->payloadSize() / sizeof(T); |
| 1313 T* buffer = reinterpret_cast<T*>(pointer); |
| 1314 #ifdef ANNOTATE_CONTIGUOUS_CONTAINER |
| 1315 // As commented above, HeapVectorBacking calls finalizers for unused slots |
| 1316 // (which are already zeroed out). |
| 1317 ANNOTATE_CHANGE_SIZE(buffer, length, 0, length); |
| 1318 #endif |
| 1319 if (WTF::IsPolymorphic<T>::value) { |
| 1320 for (unsigned i = 0; i < length; ++i) { |
| 1321 if (blink::vTableInitialized(&buffer[i])) |
| 1322 buffer[i].~T(); |
| 1323 } |
| 1324 } else { |
| 1325 for (unsigned i = 0; i < length; ++i) { |
| 1326 buffer[i].~T(); |
| 1327 } |
| 1328 } |
| 1329 } |
| 1330 |
| 1301 template<typename Table> class HeapHashTableBacking { | 1331 template<typename Table> class HeapHashTableBacking { |
| 1302 public: | 1332 public: |
| 1303 static void finalize(void* pointer); | 1333 static void finalize(void* pointer); |
| 1304 void finalizeGarbageCollectedObject() { finalize(this); } | 1334 void finalizeGarbageCollectedObject() { finalize(this); } |
| 1305 }; | 1335 }; |
| 1306 | 1336 |
| 1337 template<typename Table> |
| 1338 void HeapHashTableBacking<Table>::finalize(void* pointer) |
| 1339 { |
| 1340 using Value = typename Table::ValueType; |
| 1341 ASSERT(!WTF::IsTriviallyDestructible<Value>::value); |
| 1342 HeapObjectHeader* header = HeapObjectHeader::fromPayload(pointer); |
| 1343 // Use the payload size as recorded by the heap to determine how many |
| 1344 // elements to finalize. |
| 1345 size_t length = header->payloadSize() / sizeof(Value); |
| 1346 Value* table = reinterpret_cast<Value*>(pointer); |
| 1347 for (unsigned i = 0; i < length; ++i) { |
| 1348 if (!Table::isEmptyOrDeletedBucket(table[i])) |
| 1349 table[i].~Value(); |
| 1350 } |
| 1351 } |
| 1352 |
| 1307 class HeapAllocatorQuantizer { | 1353 class HeapAllocatorQuantizer { |
| 1308 public: | 1354 public: |
| 1309 template<typename T> | 1355 template<typename T> |
| 1310 static size_t quantizedSize(size_t count) | 1356 static size_t quantizedSize(size_t count) |
| 1311 { | 1357 { |
| 1312 RELEASE_ASSERT(count <= kMaxUnquantizedAllocation / sizeof(T)); | 1358 RELEASE_ASSERT(count <= kMaxUnquantizedAllocation / sizeof(T)); |
| 1313 return Heap::roundedAllocationSize(count * sizeof(T)); | 1359 return Heap::roundedAllocationSize(count * sizeof(T)); |
| 1314 } | 1360 } |
| 1315 static const size_t kMaxUnquantizedAllocation = maxHeapObjectSize; | 1361 static const size_t kMaxUnquantizedAllocation = maxHeapObjectSize; |
| 1316 }; | 1362 }; |
| 1317 | 1363 |
| 1364 // CollectionBackingTraceTrait. Do nothing for things in collections that don't |
| 1365 // need tracing, or call TraceInCollectionTrait for those that do. |
| 1366 |
| 1367 template<bool needsTracing, WTF::WeakHandlingFlag weakHandlingFlag, WTF::ShouldW
eakPointersBeMarkedStrongly strongify, typename T, typename Traits> struct Colle
ctionBackingTraceTrait; |
| 1368 |
| 1369 // Specialization for things that don't need marking and have no weak pointers. |
| 1370 // We do nothing, even if WTF::WeakPointersActStrong. |
| 1371 template<WTF::ShouldWeakPointersBeMarkedStrongly strongify, typename T, typename
Traits> |
| 1372 struct CollectionBackingTraceTrait<false, WTF::NoWeakHandlingInCollections, stro
ngify, T, Traits> { |
| 1373 template<typename VisitorDispatcher> |
| 1374 static bool trace(VisitorDispatcher, T&) { return false; } |
| 1375 }; |
| 1376 |
| 1377 template<typename T> |
| 1378 static void verifyGarbageCollectedIfMember(T*) |
| 1379 { |
| 1380 } |
| 1381 |
| 1382 template<typename T> |
| 1383 static void verifyGarbageCollectedIfMember(Member<T>* t) |
| 1384 { |
| 1385 STATIC_ASSERT_IS_GARBAGE_COLLECTED(T, "non garbage collected object in membe
r"); |
| 1386 } |
| 1387 |
| 1388 // Specialization for things that either need marking or have weak pointers or |
| 1389 // both. |
| 1390 template<bool needsTracing, WTF::WeakHandlingFlag weakHandlingFlag, WTF::ShouldW
eakPointersBeMarkedStrongly strongify, typename T, typename Traits> |
| 1391 struct CollectionBackingTraceTrait { |
| 1392 template<typename VisitorDispatcher> |
| 1393 static bool trace(VisitorDispatcher visitor, T&t) |
| 1394 { |
| 1395 verifyGarbageCollectedIfMember(reinterpret_cast<T*>(0)); |
| 1396 return WTF::TraceInCollectionTrait<weakHandlingFlag, strongify, T, Trait
s>::trace(visitor, t); |
| 1397 } |
| 1398 }; |
| 1399 |
| 1400 template<typename T> struct WeakHandlingHashTraits : WTF::SimpleClassHashTraits<
T> { |
| 1401 // We want to treat the object as a weak object in the sense that it can |
| 1402 // disappear from hash sets and hash maps. |
| 1403 static const WTF::WeakHandlingFlag weakHandlingFlag = WTF::WeakHandlingInCol
lections; |
| 1404 // Normally whether or not an object needs tracing is inferred |
| 1405 // automatically from the presence of the trace method, but we don't |
| 1406 // necessarily have a trace method, and we may not need one because T |
| 1407 // can perhaps only be allocated inside collections, never as independent |
| 1408 // objects. Explicitly mark this as needing tracing and it will be traced |
| 1409 // in collections using the traceInCollection method, which it must have. |
| 1410 template<typename U = void> struct NeedsTracingLazily { |
| 1411 static const bool value = true; |
| 1412 }; |
| 1413 // The traceInCollection method traces differently depending on whether we |
| 1414 // are strongifying the trace operation. We strongify the trace operation |
| 1415 // when there are active iterators on the object. In this case all |
| 1416 // WeakMembers are marked like strong members so that elements do not |
| 1417 // suddenly disappear during iteration. Returns true if weak pointers to |
| 1418 // dead objects were found: In this case any strong pointers were not yet |
| 1419 // traced and the entry should be removed from the collection. |
| 1420 template<typename VisitorDispatcher> |
| 1421 static bool traceInCollection(VisitorDispatcher visitor, T& t, WTF::ShouldWe
akPointersBeMarkedStrongly strongify) |
| 1422 { |
| 1423 return t.traceInCollection(visitor, strongify); |
| 1424 } |
| 1425 }; |
| 1426 |
| 1318 // This is a static-only class used as a trait on collections to make them heap | 1427 // This is a static-only class used as a trait on collections to make them heap |
| 1319 // allocated. However see also HeapListHashSetAllocator. | 1428 // allocated. However see also HeapListHashSetAllocator. |
| 1320 class HeapAllocator { | 1429 class HeapAllocator { |
| 1321 public: | 1430 public: |
| 1322 using Quantizer = HeapAllocatorQuantizer; | 1431 using Quantizer = HeapAllocatorQuantizer; |
| 1323 using Visitor = blink::Visitor; | 1432 using Visitor = blink::Visitor; |
| 1324 static const bool isGarbageCollected = true; | 1433 static const bool isGarbageCollected = true; |
| 1325 | 1434 |
| 1326 template <typename T> | 1435 template <typename T> |
| 1327 static T* allocateVectorBacking(size_t size) | 1436 static T* allocateVectorBacking(size_t size) |
| (...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1673 inline void swap(HeapHashMap<T, U, V, W, X>& a, HeapHashMap<T, U, V, W, X>& b) {
a.swap(b); } | 1782 inline void swap(HeapHashMap<T, U, V, W, X>& a, HeapHashMap<T, U, V, W, X>& b) {
a.swap(b); } |
| 1674 template<typename T, size_t i, typename U> | 1783 template<typename T, size_t i, typename U> |
| 1675 inline void swap(HeapListHashSet<T, i, U>& a, HeapListHashSet<T, i, U>& b) { a.s
wap(b); } | 1784 inline void swap(HeapListHashSet<T, i, U>& a, HeapListHashSet<T, i, U>& b) { a.s
wap(b); } |
| 1676 template<typename T, typename U, typename V> | 1785 template<typename T, typename U, typename V> |
| 1677 inline void swap(HeapLinkedHashSet<T, U, V>& a, HeapLinkedHashSet<T, U, V>& b) {
a.swap(b); } | 1786 inline void swap(HeapLinkedHashSet<T, U, V>& a, HeapLinkedHashSet<T, U, V>& b) {
a.swap(b); } |
| 1678 template<typename T, typename U, typename V> | 1787 template<typename T, typename U, typename V> |
| 1679 inline void swap(HeapHashCountedSet<T, U, V>& a, HeapHashCountedSet<T, U, V>& b)
{ a.swap(b); } | 1788 inline void swap(HeapHashCountedSet<T, U, V>& a, HeapHashCountedSet<T, U, V>& b)
{ a.swap(b); } |
| 1680 | 1789 |
| 1681 } // namespace blink | 1790 } // namespace blink |
| 1682 | 1791 |
| 1683 namespace WTF { | |
| 1684 | |
| 1685 // Catch-all for types that have a way to trace that don't have special | |
| 1686 // handling for weakness in collections. This means that if this type | |
| 1687 // contains WeakMember fields, they will simply be zeroed, but the entry | |
| 1688 // will not be removed from the collection. This always happens for | |
| 1689 // things in vectors, which don't currently support special handling of | |
| 1690 // weak elements. | |
| 1691 template<ShouldWeakPointersBeMarkedStrongly strongify, typename T, typename Trai
ts> | |
| 1692 struct TraceInCollectionTrait<NoWeakHandlingInCollections, strongify, T, Traits>
{ | |
| 1693 template<typename VisitorDispatcher> | |
| 1694 static bool trace(VisitorDispatcher visitor, T& t) | |
| 1695 { | |
| 1696 blink::TraceTrait<T>::trace(visitor, &t); | |
| 1697 return false; | |
| 1698 } | |
| 1699 }; | |
| 1700 | |
| 1701 template<ShouldWeakPointersBeMarkedStrongly strongify, typename T, typename Trai
ts> | |
| 1702 struct TraceInCollectionTrait<NoWeakHandlingInCollections, strongify, blink::Mem
ber<T>, Traits> { | |
| 1703 template<typename VisitorDispatcher> | |
| 1704 static bool trace(VisitorDispatcher visitor, blink::Member<T>& t) | |
| 1705 { | |
| 1706 blink::TraceTrait<T>::mark(visitor, const_cast<typename RemoveConst<T>::
Type*>(t.get())); | |
| 1707 return false; | |
| 1708 } | |
| 1709 }; | |
| 1710 | |
| 1711 // Catch-all for things that have HashTrait support for tracing with weakness. | |
| 1712 template<ShouldWeakPointersBeMarkedStrongly strongify, typename T, typename Trai
ts> | |
| 1713 struct TraceInCollectionTrait<WeakHandlingInCollections, strongify, T, Traits> { | |
| 1714 template<typename VisitorDispatcher> | |
| 1715 static bool trace(VisitorDispatcher visitor, T& t) | |
| 1716 { | |
| 1717 return Traits::traceInCollection(visitor, t, strongify); | |
| 1718 } | |
| 1719 }; | |
| 1720 | |
| 1721 // Vector backing that needs marking. We don't support weak members in vectors. | |
| 1722 template<ShouldWeakPointersBeMarkedStrongly strongify, typename T, typename Trai
ts> | |
| 1723 struct TraceInCollectionTrait<NoWeakHandlingInCollections, strongify, blink::Hea
pVectorBacking<T, Traits>, void> { | |
| 1724 template<typename VisitorDispatcher> | |
| 1725 static bool trace(VisitorDispatcher visitor, void* self) | |
| 1726 { | |
| 1727 // HeapVectorBacking does not know the exact size of the vector | |
| 1728 // and just knows the capacity of the vector. Due to the constraint, | |
| 1729 // HeapVectorBacking can support only the following objects: | |
| 1730 // | |
| 1731 // - An object that has a vtable. In this case, HeapVectorBacking | |
| 1732 // traces only slots that are not zeroed out. This is because if | |
| 1733 // the object has a vtable, the zeroed slot means that it is | |
| 1734 // an unused slot (Remember that the unused slots are guaranteed | |
| 1735 // to be zeroed out by VectorUnusedSlotClearer). | |
| 1736 // | |
| 1737 // - An object that can be initialized with memset. In this case, | |
| 1738 // HeapVectorBacking traces all slots including unused slots. | |
| 1739 // This is fine because the fact that the object can be initialized | |
| 1740 // with memset indicates that it is safe to treat the zerod slot | |
| 1741 // as a valid object. | |
| 1742 static_assert(!ShouldBeTraced<Traits>::value || Traits::canInitializeWit
hMemset || WTF::IsPolymorphic<T>::value, "HeapVectorBacking doesn't support obje
cts that cannot be initialized with memset."); | |
| 1743 | |
| 1744 T* array = reinterpret_cast<T*>(self); | |
| 1745 blink::HeapObjectHeader* header = blink::HeapObjectHeader::fromPayload(s
elf); | |
| 1746 // Use the payload size as recorded by the heap to determine how many | |
| 1747 // elements to trace. | |
| 1748 size_t length = header->payloadSize() / sizeof(T); | |
| 1749 if (WTF::IsPolymorphic<T>::value) { | |
| 1750 for (size_t i = 0; i < length; ++i) { | |
| 1751 if (blink::vTableInitialized(&array[i])) | |
| 1752 blink::CollectionBackingTraceTrait<ShouldBeTraced<Traits>::v
alue, Traits::weakHandlingFlag, WeakPointersActStrong, T, Traits>::trace(visitor
, array[i]); | |
| 1753 } | |
| 1754 } else { | |
| 1755 #ifdef ANNOTATE_CONTIGUOUS_CONTAINER | |
| 1756 // As commented above, HeapVectorBacking can trace unused slots | |
| 1757 // (which are already zeroed out). | |
| 1758 ANNOTATE_CHANGE_SIZE(array, length, 0, length); | |
| 1759 #endif | |
| 1760 for (size_t i = 0; i < length; ++i) | |
| 1761 blink::CollectionBackingTraceTrait<ShouldBeTraced<Traits>::value
, Traits::weakHandlingFlag, WeakPointersActStrong, T, Traits>::trace(visitor, ar
ray[i]); | |
| 1762 } | |
| 1763 return false; | |
| 1764 } | |
| 1765 }; | |
| 1766 | |
| 1767 // Almost all hash table backings are visited with this specialization. | |
| 1768 template<ShouldWeakPointersBeMarkedStrongly strongify, typename Table> | |
| 1769 struct TraceInCollectionTrait<NoWeakHandlingInCollections, strongify, blink::Hea
pHashTableBacking<Table>, void> { | |
| 1770 using Value = typename Table::ValueType; | |
| 1771 using Traits = typename Table::ValueTraits; | |
| 1772 | |
| 1773 template<typename VisitorDispatcher> | |
| 1774 static bool trace(VisitorDispatcher visitor, void* self) | |
| 1775 { | |
| 1776 Value* array = reinterpret_cast<Value*>(self); | |
| 1777 blink::HeapObjectHeader* header = blink::HeapObjectHeader::fromPayload(s
elf); | |
| 1778 size_t length = header->payloadSize() / sizeof(Value); | |
| 1779 for (size_t i = 0; i < length; ++i) { | |
| 1780 if (!HashTableHelper<Value, typename Table::ExtractorType, typename
Table::KeyTraitsType>::isEmptyOrDeletedBucket(array[i])) | |
| 1781 blink::CollectionBackingTraceTrait<ShouldBeTraced<Traits>::value
, Traits::weakHandlingFlag, strongify, Value, Traits>::trace(visitor, array[i]); | |
| 1782 } | |
| 1783 return false; | |
| 1784 } | |
| 1785 }; | |
| 1786 | |
| 1787 // This specialization of TraceInCollectionTrait is for the backing of | |
| 1788 // HeapListHashSet. This is for the case that we find a reference to the | |
| 1789 // backing from the stack. That probably means we have a GC while we are in a | |
| 1790 // ListHashSet method since normal API use does not put pointers to the backing | |
| 1791 // on the stack. | |
| 1792 template<ShouldWeakPointersBeMarkedStrongly strongify, typename NodeContents, si
ze_t inlineCapacity, typename T, typename U, typename V, typename W, typename X,
typename Y> | |
| 1793 struct TraceInCollectionTrait<NoWeakHandlingInCollections, strongify, blink::Hea
pHashTableBacking<HashTable<ListHashSetNode<NodeContents, blink::HeapListHashSet
Allocator<T, inlineCapacity>>*, U, V, W, X, Y, blink::HeapAllocator>>, void> { | |
| 1794 using Node = ListHashSetNode<NodeContents, blink::HeapListHashSetAllocator<T
, inlineCapacity>>; | |
| 1795 using Table = HashTable<Node*, U, V, W, X, Y, blink::HeapAllocator>; | |
| 1796 | |
| 1797 template<typename VisitorDispatcher> | |
| 1798 static bool trace(VisitorDispatcher visitor, void* self) | |
| 1799 { | |
| 1800 Node** array = reinterpret_cast<Node**>(self); | |
| 1801 blink::HeapObjectHeader* header = blink::HeapObjectHeader::fromPayload(s
elf); | |
| 1802 size_t length = header->payloadSize() / sizeof(Node*); | |
| 1803 for (size_t i = 0; i < length; ++i) { | |
| 1804 if (!HashTableHelper<Node*, typename Table::ExtractorType, typename
Table::KeyTraitsType>::isEmptyOrDeletedBucket(array[i])) { | |
| 1805 traceListHashSetValue(visitor, array[i]->m_value); | |
| 1806 // Just mark the node without tracing because we already traced | |
| 1807 // the contents, and there is no need to trace the next and | |
| 1808 // prev fields since iterating over the hash table backing will | |
| 1809 // find the whole chain. | |
| 1810 visitor->markNoTracing(array[i]); | |
| 1811 } | |
| 1812 } | |
| 1813 return false; | |
| 1814 } | |
| 1815 }; | |
| 1816 | |
| 1817 // Key value pairs, as used in HashMap. To disambiguate template choice we have | |
| 1818 // to have two versions, first the one with no special weak handling, then the | |
| 1819 // one with weak handling. | |
| 1820 template<ShouldWeakPointersBeMarkedStrongly strongify, typename Key, typename Va
lue, typename Traits> | |
| 1821 struct TraceInCollectionTrait<NoWeakHandlingInCollections, strongify, KeyValuePa
ir<Key, Value>, Traits> { | |
| 1822 template<typename VisitorDispatcher> | |
| 1823 static bool trace(VisitorDispatcher visitor, KeyValuePair<Key, Value>& self) | |
| 1824 { | |
| 1825 ASSERT(ShouldBeTraced<Traits>::value); | |
| 1826 blink::CollectionBackingTraceTrait<ShouldBeTraced<typename Traits::KeyTr
aits>::value, NoWeakHandlingInCollections, strongify, Key, typename Traits::KeyT
raits>::trace(visitor, self.key); | |
| 1827 blink::CollectionBackingTraceTrait<ShouldBeTraced<typename Traits::Value
Traits>::value, NoWeakHandlingInCollections, strongify, Value, typename Traits::
ValueTraits>::trace(visitor, self.value); | |
| 1828 return false; | |
| 1829 } | |
| 1830 }; | |
| 1831 | |
| 1832 template<ShouldWeakPointersBeMarkedStrongly strongify, typename Key, typename Va
lue, typename Traits> | |
| 1833 struct TraceInCollectionTrait<WeakHandlingInCollections, strongify, KeyValuePair
<Key, Value>, Traits> { | |
| 1834 template<typename VisitorDispatcher> | |
| 1835 static bool trace(VisitorDispatcher visitor, KeyValuePair<Key, Value>& self) | |
| 1836 { | |
| 1837 // This is the core of the ephemeron-like functionality. If there is | |
| 1838 // weakness on the key side then we first check whether there are | |
| 1839 // dead weak pointers on that side, and if there are we don't mark the | |
| 1840 // value side (yet). Conversely if there is weakness on the value side | |
| 1841 // we check that first and don't mark the key side yet if we find dead | |
| 1842 // weak pointers. | |
| 1843 // Corner case: If there is weakness on both the key and value side, | |
| 1844 // and there are also strong pointers on the both sides then we could | |
| 1845 // unexpectedly leak. The scenario is that the weak pointer on the key | |
| 1846 // side is alive, which causes the strong pointer on the key side to be | |
| 1847 // marked. If that then results in the object pointed to by the weak | |
| 1848 // pointer on the value side being marked live, then the whole | |
| 1849 // key-value entry is leaked. To avoid unexpected leaking, we disallow | |
| 1850 // this case, but if you run into this assert, please reach out to Blink | |
| 1851 // reviewers, and we may relax it. | |
| 1852 const bool keyIsWeak = Traits::KeyTraits::weakHandlingFlag == WeakHandli
ngInCollections; | |
| 1853 const bool valueIsWeak = Traits::ValueTraits::weakHandlingFlag == WeakHa
ndlingInCollections; | |
| 1854 const bool keyHasStrongRefs = ShouldBeTraced<typename Traits::KeyTraits>
::value; | |
| 1855 const bool valueHasStrongRefs = ShouldBeTraced<typename Traits::ValueTra
its>::value; | |
| 1856 static_assert(!keyIsWeak || !valueIsWeak || !keyHasStrongRefs || !valueH
asStrongRefs, "this configuration is disallowed to avoid unexpected leaks"); | |
| 1857 if ((valueIsWeak && !keyIsWeak) || (valueIsWeak && keyIsWeak && !valueHa
sStrongRefs)) { | |
| 1858 // Check value first. | |
| 1859 bool deadWeakObjectsFoundOnValueSide = blink::CollectionBackingTrace
Trait<ShouldBeTraced<typename Traits::ValueTraits>::value, Traits::ValueTraits::
weakHandlingFlag, strongify, Value, typename Traits::ValueTraits>::trace(visitor
, self.value); | |
| 1860 if (deadWeakObjectsFoundOnValueSide) | |
| 1861 return true; | |
| 1862 return blink::CollectionBackingTraceTrait<ShouldBeTraced<typename Tr
aits::KeyTraits>::value, Traits::KeyTraits::weakHandlingFlag, strongify, Key, ty
pename Traits::KeyTraits>::trace(visitor, self.key); | |
| 1863 } | |
| 1864 // Check key first. | |
| 1865 bool deadWeakObjectsFoundOnKeySide = blink::CollectionBackingTraceTrait<
ShouldBeTraced<typename Traits::KeyTraits>::value, Traits::KeyTraits::weakHandli
ngFlag, strongify, Key, typename Traits::KeyTraits>::trace(visitor, self.key); | |
| 1866 if (deadWeakObjectsFoundOnKeySide) | |
| 1867 return true; | |
| 1868 return blink::CollectionBackingTraceTrait<ShouldBeTraced<typename Traits
::ValueTraits>::value, Traits::ValueTraits::weakHandlingFlag, strongify, Value,
typename Traits::ValueTraits>::trace(visitor, self.value); | |
| 1869 } | |
| 1870 }; | |
| 1871 | |
| 1872 // Nodes used by LinkedHashSet. Again we need two versions to disambiguate the | |
| 1873 // template. | |
| 1874 template<ShouldWeakPointersBeMarkedStrongly strongify, typename Value, typename
Allocator, typename Traits> | |
| 1875 struct TraceInCollectionTrait<NoWeakHandlingInCollections, strongify, LinkedHash
SetNode<Value, Allocator>, Traits> { | |
| 1876 template<typename VisitorDispatcher> | |
| 1877 static bool trace(VisitorDispatcher visitor, LinkedHashSetNode<Value, Alloca
tor>& self) | |
| 1878 { | |
| 1879 ASSERT(ShouldBeTraced<Traits>::value); | |
| 1880 return TraceInCollectionTrait<NoWeakHandlingInCollections, strongify, Va
lue, typename Traits::ValueTraits>::trace(visitor, self.m_value); | |
| 1881 } | |
| 1882 }; | |
| 1883 | |
| 1884 template<ShouldWeakPointersBeMarkedStrongly strongify, typename Value, typename
Allocator, typename Traits> | |
| 1885 struct TraceInCollectionTrait<WeakHandlingInCollections, strongify, LinkedHashSe
tNode<Value, Allocator>, Traits> { | |
| 1886 template<typename VisitorDispatcher> | |
| 1887 static bool trace(VisitorDispatcher visitor, LinkedHashSetNode<Value, Alloca
tor>& self) | |
| 1888 { | |
| 1889 return TraceInCollectionTrait<WeakHandlingInCollections, strongify, Valu
e, typename Traits::ValueTraits>::trace(visitor, self.m_value); | |
| 1890 } | |
| 1891 }; | |
| 1892 | |
| 1893 // ListHashSetNode pointers (a ListHashSet is implemented as a hash table of | |
| 1894 // these pointers). | |
| 1895 template<ShouldWeakPointersBeMarkedStrongly strongify, typename Value, size_t in
lineCapacity, typename Traits> | |
| 1896 struct TraceInCollectionTrait<NoWeakHandlingInCollections, strongify, ListHashSe
tNode<Value, blink::HeapListHashSetAllocator<Value, inlineCapacity>>*, Traits> { | |
| 1897 using Node = ListHashSetNode<Value, blink::HeapListHashSetAllocator<Value, i
nlineCapacity>>; | |
| 1898 | |
| 1899 template<typename VisitorDispatcher> | |
| 1900 static bool trace(VisitorDispatcher visitor, Node* node) | |
| 1901 { | |
| 1902 traceListHashSetValue(visitor, node->m_value); | |
| 1903 // Just mark the node without tracing because we already traced the | |
| 1904 // contents, and there is no need to trace the next and prev fields | |
| 1905 // since iterating over the hash table backing will find the whole | |
| 1906 // chain. | |
| 1907 visitor->markNoTracing(node); | |
| 1908 return false; | |
| 1909 } | |
| 1910 }; | |
| 1911 | |
| 1912 } // namespace WTF | |
| 1913 | |
| 1914 namespace blink { | |
| 1915 | |
| 1916 // CollectionBackingTraceTrait. Do nothing for things in collections that don't | |
| 1917 // need tracing, or call TraceInCollectionTrait for those that do. | |
| 1918 | |
| 1919 // Specialization for things that don't need marking and have no weak pointers. | |
| 1920 // We do nothing, even if WTF::WeakPointersActStrong. | |
| 1921 template<WTF::ShouldWeakPointersBeMarkedStrongly strongify, typename T, typename
Traits> | |
| 1922 struct CollectionBackingTraceTrait<false, WTF::NoWeakHandlingInCollections, stro
ngify, T, Traits> { | |
| 1923 template<typename VisitorDispatcher> | |
| 1924 static bool trace(VisitorDispatcher, T&) { return false; } | |
| 1925 }; | |
| 1926 | |
| 1927 template<typename T> | |
| 1928 static void verifyGarbageCollectedIfMember(T*) | |
| 1929 { | |
| 1930 } | |
| 1931 | |
| 1932 template<typename T> | |
| 1933 static void verifyGarbageCollectedIfMember(Member<T>* t) | |
| 1934 { | |
| 1935 STATIC_ASSERT_IS_GARBAGE_COLLECTED(T, "non garbage collected object in membe
r"); | |
| 1936 } | |
| 1937 | |
| 1938 // Specialization for things that either need marking or have weak pointers or | |
| 1939 // both. | |
| 1940 template<bool needsTracing, WTF::WeakHandlingFlag weakHandlingFlag, WTF::ShouldW
eakPointersBeMarkedStrongly strongify, typename T, typename Traits> | |
| 1941 struct CollectionBackingTraceTrait { | |
| 1942 template<typename VisitorDispatcher> | |
| 1943 static bool trace(VisitorDispatcher visitor, T&t) | |
| 1944 { | |
| 1945 verifyGarbageCollectedIfMember(reinterpret_cast<T*>(0)); | |
| 1946 return WTF::TraceInCollectionTrait<weakHandlingFlag, strongify, T, Trait
s>::trace(visitor, t); | |
| 1947 } | |
| 1948 }; | |
| 1949 | |
| 1950 template<typename T> struct WeakHandlingHashTraits : WTF::SimpleClassHashTraits<
T> { | |
| 1951 // We want to treat the object as a weak object in the sense that it can | |
| 1952 // disappear from hash sets and hash maps. | |
| 1953 static const WTF::WeakHandlingFlag weakHandlingFlag = WTF::WeakHandlingInCol
lections; | |
| 1954 // Normally whether or not an object needs tracing is inferred | |
| 1955 // automatically from the presence of the trace method, but we don't | |
| 1956 // necessarily have a trace method, and we may not need one because T | |
| 1957 // can perhaps only be allocated inside collections, never as independent | |
| 1958 // objects. Explicitly mark this as needing tracing and it will be traced | |
| 1959 // in collections using the traceInCollection method, which it must have. | |
| 1960 template<typename U = void> struct NeedsTracingLazily { | |
| 1961 static const bool value = true; | |
| 1962 }; | |
| 1963 // The traceInCollection method traces differently depending on whether we | |
| 1964 // are strongifying the trace operation. We strongify the trace operation | |
| 1965 // when there are active iterators on the object. In this case all | |
| 1966 // WeakMembers are marked like strong members so that elements do not | |
| 1967 // suddenly disappear during iteration. Returns true if weak pointers to | |
| 1968 // dead objects were found: In this case any strong pointers were not yet | |
| 1969 // traced and the entry should be removed from the collection. | |
| 1970 template<typename VisitorDispatcher> | |
| 1971 static bool traceInCollection(VisitorDispatcher visitor, T& t, WTF::ShouldWe
akPointersBeMarkedStrongly strongify) | |
| 1972 { | |
| 1973 return t.traceInCollection(visitor, strongify); | |
| 1974 } | |
| 1975 }; | |
| 1976 | |
| 1977 template<typename T, typename Traits> | |
| 1978 struct TraceTrait<HeapVectorBacking<T, Traits>> { | |
| 1979 using Backing = HeapVectorBacking<T, Traits>; | |
| 1980 | |
| 1981 template<typename VisitorDispatcher> | |
| 1982 static void trace(VisitorDispatcher visitor, void* self) | |
| 1983 { | |
| 1984 static_assert(!WTF::IsWeak<T>::value, "weakness in HeapVectors and Deque
s are not supported"); | |
| 1985 if (WTF::ShouldBeTraced<Traits>::value) | |
| 1986 WTF::TraceInCollectionTrait<WTF::NoWeakHandlingInCollections, WTF::W
eakPointersActWeak, HeapVectorBacking<T, Traits>, void>::trace(visitor, self); | |
| 1987 } | |
| 1988 | |
| 1989 template<typename VisitorDispatcher> | |
| 1990 static void mark(VisitorDispatcher visitor, const Backing* backing) | |
| 1991 { | |
| 1992 visitor->mark(backing, &trace); | |
| 1993 } | |
| 1994 static void checkGCInfo(Visitor* visitor, const Backing* backing) | |
| 1995 { | |
| 1996 #if ENABLE(ASSERT) | |
| 1997 assertObjectHasGCInfo(const_cast<Backing*>(backing), GCInfoTrait<Backing
>::index()); | |
| 1998 #endif | |
| 1999 } | |
| 2000 }; | |
| 2001 | |
| 2002 // The trace trait for the heap hashtable backing is used when we find a | |
| 2003 // direct pointer to the backing from the conservative stack scanner. This | |
| 2004 // normally indicates that there is an ongoing iteration over the table, and so | |
| 2005 // we disable weak processing of table entries. When the backing is found | |
| 2006 // through the owning hash table we mark differently, in order to do weak | |
| 2007 // processing. | |
| 2008 template<typename Table> | |
| 2009 struct TraceTrait<HeapHashTableBacking<Table>> { | |
| 2010 using Backing = HeapHashTableBacking<Table>; | |
| 2011 using Traits = typename Table::ValueTraits; | |
| 2012 | |
| 2013 template<typename VisitorDispatcher> | |
| 2014 static void trace(VisitorDispatcher visitor, void* self) | |
| 2015 { | |
| 2016 if (WTF::ShouldBeTraced<Traits>::value || Traits::weakHandlingFlag == WT
F::WeakHandlingInCollections) | |
| 2017 WTF::TraceInCollectionTrait<WTF::NoWeakHandlingInCollections, WTF::W
eakPointersActStrong, Backing, void>::trace(visitor, self); | |
| 2018 } | |
| 2019 | |
| 2020 template<typename VisitorDispatcher> | |
| 2021 static void mark(VisitorDispatcher visitor, const Backing* backing) | |
| 2022 { | |
| 2023 if (WTF::ShouldBeTraced<Traits>::value || Traits::weakHandlingFlag == WT
F::WeakHandlingInCollections) | |
| 2024 visitor->mark(backing, &trace); | |
| 2025 else | |
| 2026 visitor->markNoTracing(backing); // If we know the trace function wi
ll do nothing there is no need to call it. | |
| 2027 } | |
| 2028 static void checkGCInfo(Visitor* visitor, const Backing* backing) | |
| 2029 { | |
| 2030 #if ENABLE(ASSERT) | |
| 2031 assertObjectHasGCInfo(const_cast<Backing*>(backing), GCInfoTrait<Backing
>::index()); | |
| 2032 #endif | |
| 2033 } | |
| 2034 }; | |
| 2035 | |
| 2036 template<typename T, typename Traits> | |
| 2037 void HeapVectorBacking<T, Traits>::finalize(void* pointer) | |
| 2038 { | |
| 2039 static_assert(Traits::needsDestruction, "Only vector buffers with items requ
iring destruction should be finalized"); | |
| 2040 // See the comment in HeapVectorBacking::trace. | |
| 2041 static_assert(Traits::canInitializeWithMemset || WTF::IsPolymorphic<T>::valu
e, "HeapVectorBacking doesn't support objects that cannot be initialized with me
mset or don't have a vtable"); | |
| 2042 | |
| 2043 ASSERT(!WTF::IsTriviallyDestructible<T>::value); | |
| 2044 HeapObjectHeader* header = HeapObjectHeader::fromPayload(pointer); | |
| 2045 // Use the payload size as recorded by the heap to determine how many | |
| 2046 // elements to finalize. | |
| 2047 size_t length = header->payloadSize() / sizeof(T); | |
| 2048 T* buffer = reinterpret_cast<T*>(pointer); | |
| 2049 #ifdef ANNOTATE_CONTIGUOUS_CONTAINER | |
| 2050 // As commented above, HeapVectorBacking calls finalizers for unused slots | |
| 2051 // (which are already zeroed out). | |
| 2052 ANNOTATE_CHANGE_SIZE(buffer, length, 0, length); | |
| 2053 #endif | |
| 2054 if (WTF::IsPolymorphic<T>::value) { | |
| 2055 for (unsigned i = 0; i < length; ++i) { | |
| 2056 if (blink::vTableInitialized(&buffer[i])) | |
| 2057 buffer[i].~T(); | |
| 2058 } | |
| 2059 } else { | |
| 2060 for (unsigned i = 0; i < length; ++i) { | |
| 2061 buffer[i].~T(); | |
| 2062 } | |
| 2063 } | |
| 2064 } | |
| 2065 | |
| 2066 template<typename Table> | |
| 2067 void HeapHashTableBacking<Table>::finalize(void* pointer) | |
| 2068 { | |
| 2069 using Value = typename Table::ValueType; | |
| 2070 ASSERT(!WTF::IsTriviallyDestructible<Value>::value); | |
| 2071 HeapObjectHeader* header = HeapObjectHeader::fromPayload(pointer); | |
| 2072 // Use the payload size as recorded by the heap to determine how many | |
| 2073 // elements to finalize. | |
| 2074 size_t length = header->payloadSize() / sizeof(Value); | |
| 2075 Value* table = reinterpret_cast<Value*>(pointer); | |
| 2076 for (unsigned i = 0; i < length; ++i) { | |
| 2077 if (!Table::isEmptyOrDeletedBucket(table[i])) | |
| 2078 table[i].~Value(); | |
| 2079 } | |
| 2080 } | |
| 2081 | |
| 2082 } // namespace blink | |
| 2083 | |
| 2084 #endif // Heap_h | 1792 #endif // Heap_h |
| OLD | NEW |