Source/bmalloc/ChangeLog

 12020-05-12 Yusuke Suzuki <ysuzuki@apple.com>
 2
 3 [bmalloc] Introduce lock-less ObjectType query
 4 https://bugs.webkit.org/show_bug.cgi?id=211809
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 This patch introduces ObjectTypeTable, which allows lock-less ObjectType query for Chunk*.
 9 It has bit-vector to store ObjectType per address. And 1bit represents 1MB VA region since
 10 Chunk*'s size is at least 1MB. Every time we extend this bit-vector to support larger VA region,
 11 we do not free the old bit-vector. Since we always allocate power-of-2 sized bit-vector, # of extension
 12 is limited and it does not waste memory so much because Chunk's size is enough large (1MB). Since each
 13 4KB page on macOS can represent a bit-vector for 32GB VA region, in practice, this extension almost never
 14 happens. I ensured that 4KB page can handle memory allocation in JetStream2 and Gmail.
 15
 16 * CMakeLists.txt:
 17 * bmalloc.xcodeproj/project.pbxproj:
 18 * bmalloc/Algorithm.h:
 19 (bmalloc::roundUpToPowerOf2):
 20 * bmalloc/Deallocator.cpp:
 21 (bmalloc::Deallocator::deallocateSlowCase):
 22 * bmalloc/Heap.cpp:
 23 (bmalloc::Heap::freeableMemory):
 24 (bmalloc::Heap::decommitLargeRange):
 25 (bmalloc::Heap::scavenge):
 26 (bmalloc::Heap::scavengeToHighWatermark):
 27 (bmalloc::Heap::allocateSmallChunk):
 28 (bmalloc::Heap::deallocateSmallChunk):
 29 (bmalloc::Heap::deallocateSmallLine):
 30 (bmalloc::Heap::splitAndAllocate):
 31 (bmalloc::Heap::isLarge): Deleted.
 32 * bmalloc/Heap.h:
 33 (bmalloc::Heap::isLarge):
 34 * bmalloc/ObjectType.cpp:
 35 (bmalloc::objectType):
 36 * bmalloc/ObjectTypeTable.cpp: Added.
 37 (bmalloc::ObjectTypeTable::set):
 38 * bmalloc/ObjectTypeTable.h: Added.
 39 (bmalloc::ObjectTypeTable::convertToIndex):
 40 (bmalloc::ObjectTypeTable::Bits::Bits):
 41 (bmalloc::ObjectTypeTable::Bits::previous const):
 42 (bmalloc::ObjectTypeTable::Bits::begin const):
 43 (bmalloc::ObjectTypeTable::Bits::end const):
 44 (bmalloc::ObjectTypeTable::Bits::words const):
 45 (bmalloc::ObjectTypeTable::Bits::words):
 46 (bmalloc::ObjectTypeTable::ObjectTypeTable):
 47 (bmalloc::ObjectTypeTable::get):
 48 (bmalloc::ObjectTypeTable::Bits::get):
 49 (bmalloc::ObjectTypeTable::Bits::set):
 50 * bmalloc/Scavenger.cpp:
 51 (bmalloc::Scavenger::scavenge):
 52 (bmalloc::Scavenger::partialScavenge):
 53 (bmalloc::Scavenger::freeableMemory):
 54
1552020-05-11 Basuke Suzuki <basuke.suzuki@sony.com>
256
357 [bmalloc][WTF] Add computing memory size implementation for FreeBSD

Source/bmalloc/CMakeLists.txt

@@set(bmalloc_SOURCES
2929 bmalloc/Logging.cpp
3030 bmalloc/Mutex.cpp
3131 bmalloc/ObjectType.cpp
 32 bmalloc/ObjectTypeTable.cpp
3233 bmalloc/PerProcess.cpp
3334 bmalloc/Scavenger.cpp
3435 bmalloc/bmalloc.cpp

@@set(bmalloc_PUBLIC_HEADERS
110111 bmalloc/Mutex.h
111112 bmalloc/Object.h
112113 bmalloc/ObjectType.h
 114 bmalloc/ObjectTypeTable.h
113115 bmalloc/Packed.h
114116 bmalloc/PerHeapKind.h
115117 bmalloc/PerProcess.h

Source/bmalloc/bmalloc.xcodeproj/project.pbxproj

139139 DE8B13B321CC5D9F00A63FCD /* BVMTags.h in Headers */ = {isa = PBXBuildFile; fileRef = DE8B13B221CC5D9F00A63FCD /* BVMTags.h */; settings = {ATTRIBUTES = (Private, ); }; };
140140 E31E74802238CA5C005D084A /* StaticPerProcess.h in Headers */ = {isa = PBXBuildFile; fileRef = E31E747F2238CA5B005D084A /* StaticPerProcess.h */; settings = {ATTRIBUTES = (Private, ); }; };
141141 E328D84D23CEB38900545B18 /* Packed.h in Headers */ = {isa = PBXBuildFile; fileRef = E328D84C23CEB38900545B18 /* Packed.h */; settings = {ATTRIBUTES = (Private, ); }; };
 142 E378A9DF246B68720029C2BB /* ObjectTypeTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E378A9DE246B686A0029C2BB /* ObjectTypeTable.cpp */; };
 143 E378A9E0246B68750029C2BB /* ObjectTypeTable.h in Headers */ = {isa = PBXBuildFile; fileRef = E378A9DD246B686A0029C2BB /* ObjectTypeTable.h */; settings = {ATTRIBUTES = (Private, ); }; };
142144 E3A413C9226061140037F470 /* IsoSharedPageInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E3A413C8226061140037F470 /* IsoSharedPageInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
143145 E3F24402225D2C0100A0E0C3 /* IsoSharedPage.h in Headers */ = {isa = PBXBuildFile; fileRef = E3F24401225D2C0100A0E0C3 /* IsoSharedPage.h */; settings = {ATTRIBUTES = (Private, ); }; };
144146 E3F24404225D2C7600A0E0C3 /* IsoSharedPage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3F24403225D2C7600A0E0C3 /* IsoSharedPage.cpp */; };

293295 DE8B13B221CC5D9F00A63FCD /* BVMTags.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = BVMTags.h; path = bmalloc/BVMTags.h; sourceTree = "<group>"; };
294296 E31E747F2238CA5B005D084A /* StaticPerProcess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StaticPerProcess.h; path = bmalloc/StaticPerProcess.h; sourceTree = "<group>"; };
295297 E328D84C23CEB38900545B18 /* Packed.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Packed.h; path = bmalloc/Packed.h; sourceTree = "<group>"; };
 298 E378A9DD246B686A0029C2BB /* ObjectTypeTable.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ObjectTypeTable.h; path = bmalloc/ObjectTypeTable.h; sourceTree = "<group>"; };
 299 E378A9DE246B686A0029C2BB /* ObjectTypeTable.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ObjectTypeTable.cpp; path = bmalloc/ObjectTypeTable.cpp; sourceTree = "<group>"; };
296300 E3A413C8226061140037F470 /* IsoSharedPageInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IsoSharedPageInlines.h; path = bmalloc/IsoSharedPageInlines.h; sourceTree = "<group>"; };
297301 E3F24401225D2C0100A0E0C3 /* IsoSharedPage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IsoSharedPage.h; path = bmalloc/IsoSharedPage.h; sourceTree = "<group>"; };
298302 E3F24403225D2C7600A0E0C3 /* IsoSharedPage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = IsoSharedPage.cpp; path = bmalloc/IsoSharedPage.cpp; sourceTree = "<group>"; };

490494 144BE11E1CA346520099C8C0 /* Object.h */,
491495 14105E8318E14374003A106E /* ObjectType.cpp */,
492496 1485656018A43DBA00ED6942 /* ObjectType.h */,
 497 E378A9DE246B686A0029C2BB /* ObjectTypeTable.cpp */,
 498 E378A9DD246B686A0029C2BB /* ObjectTypeTable.h */,
493499 795AB3C6206E0D250074FE76 /* PhysicalPageMap.h */,
494500 AD14AD27202529A600890E3B /* ProcessCheck.h */,
495501 AD14AD28202529B000890E3B /* ProcessCheck.mm */,

645651 143CB81D19022BC900B16A45 /* Mutex.h in Headers */,
646652 144BE11F1CA346520099C8C0 /* Object.h in Headers */,
647653 14DD789318F48D0F00950702 /* ObjectType.h in Headers */,
 654 E378A9E0246B68750029C2BB /* ObjectTypeTable.h in Headers */,
648655 E328D84D23CEB38900545B18 /* Packed.h in Headers */,
649656 0F5BF1491F22A8D80029D91D /* PerHeapKind.h in Headers */,
650657 14DD78CB18F48D7500950702 /* PerProcess.h in Headers */,

777784 4426E2801C838EE0008EB042 /* Logging.cpp in Sources */,
778785 143CB81C19022BC900B16A45 /* Mutex.cpp in Sources */,
779786 14F271C818EA3990008C152F /* ObjectType.cpp in Sources */,
 787 E378A9DF246B68720029C2BB /* ObjectTypeTable.cpp in Sources */,
780788 0F26A7A5205483130090A141 /* PerProcess.cpp in Sources */,
781789 AD14AD2A202529C700890E3B /* ProcessCheck.mm in Sources */,
782790 0F5BF1521F22E1570029D91D /* Scavenger.cpp in Sources */,

Source/bmalloc/bmalloc/Algorithm.h

@@constexpr unsigned getLSBSetNonZeroConstexpr(T t)
219219 return ctzConstexpr(t);
220220}
221221
 222constexpr size_t roundUpToPowerOf2(size_t size, size_t alignment)
 223{
 224 return ((size + alignment - 1) & -alignment);
 225}
 226
222227} // namespace bmalloc
223228
224229#endif // Algorithm_h

Source/bmalloc/bmalloc/Deallocator.cpp

@@void Deallocator::deallocateSlowCase(void* object)
6868 if (!object)
6969 return;
7070
71  UniqueLockHolder lock(Heap::mutex());
72  if (m_heap.isLarge(lock, object)) {
 71 if (m_heap.isLarge(object)) {
 72 UniqueLockHolder lock(Heap::mutex());
7373 m_heap.deallocateLarge(lock, object);
7474 return;
7575 }
7676
77  if (m_objectLog.size() == m_objectLog.capacity())
 77 if (m_objectLog.size() == m_objectLog.capacity()) {
 78 UniqueLockHolder lock(Heap::mutex());
7879 processObjectLog(lock);
 80 }
7981
8082 m_objectLog.push(object);
8183}

Source/bmalloc/bmalloc/Heap.cpp

@@size_t Heap::gigacageSize()
8484 return Gigacage::size(gigacageKind(m_kind));
8585}
8686
87 size_t Heap::freeableMemory(const LockHolder&)
 87size_t Heap::freeableMemory(UniqueLockHolder&)
8888{
8989 return m_freeableMemory;
9090}

@@void Heap::markAllLargeAsEligibile(const LockHolder&)
101101 m_condition.notify_all();
102102}
103103
104 void Heap::decommitLargeRange(const LockHolder&, LargeRange& range, BulkDecommit& decommitter)
 104void Heap::decommitLargeRange(UniqueLockHolder&, LargeRange& range, BulkDecommit& decommitter)
105105{
106106 m_footprint -= range.totalPhysicalSize();
107107 m_freeableMemory -= range.totalPhysicalSize();

@@void Heap::decommitLargeRange(const LockHolder&, LargeRange& range, BulkDecommit
117117}
118118
119119#if BUSE(PARTIAL_SCAVENGE)
120 void Heap::scavenge(const LockHolder& lock, BulkDecommit& decommitter)
 120void Heap::scavenge(UniqueLockHolder& lock, BulkDecommit& decommitter)
121121#else
122 void Heap::scavenge(const LockHolder& lock, BulkDecommit& decommitter, size_t& deferredDecommits)
 122void Heap::scavenge(UniqueLockHolder& lock, BulkDecommit& decommitter, size_t& deferredDecommits)
123123#endif
124124{
125125 for (auto& list : m_freePages) {

@@void Heap::scavenge(const LockHolder& lock, BulkDecommit& decommitter, size_t& d
150150
151151 for (auto& list : m_chunkCache) {
152152 while (!list.isEmpty())
153  deallocateSmallChunk(list.pop(), &list - &m_chunkCache[0]);
 153 deallocateSmallChunk(lock, list.pop(), &list - &m_chunkCache[0]);
154154 }
155155
156156 for (LargeRange& range : m_largeFree) {

@@void Heap::scavenge(const LockHolder& lock, BulkDecommit& decommitter, size_t& d
172172}
173173
174174#if BUSE(PARTIAL_SCAVENGE)
175 void Heap::scavengeToHighWatermark(const LockHolder& lock, BulkDecommit& decommitter)
 175void Heap::scavengeToHighWatermark(UniqueLockHolder& lock, BulkDecommit& decommitter)
176176{
177177 void* newHighWaterMark = nullptr;
178178 for (LargeRange& range : m_largeFree) {

@@void Heap::allocateSmallChunk(UniqueLockHolder& lock, size_t pageClass, FailureA
213213
214214 Chunk* chunk = new (memory) Chunk(pageSize);
215215
216  m_objectTypes.set(chunk, ObjectType::Small);
 216 m_objectTypes.set(lock, chunk, ObjectType::Small);
217217
218218 size_t accountedInFreeable = 0;
219219 forEachPage(chunk, pageSize, [&](SmallPage* page) {

@@void Heap::allocateSmallChunk(UniqueLockHolder& lock, size_t pageClass, FailureA
244244 m_freePages[pageClass].push(chunk);
245245}
246246
247 void Heap::deallocateSmallChunk(Chunk* chunk, size_t pageClass)
 247void Heap::deallocateSmallChunk(UniqueLockHolder& lock, Chunk* chunk, size_t pageClass)
248248{
249  m_objectTypes.set(chunk, ObjectType::Large);
 249 m_objectTypes.set(lock, chunk, ObjectType::Large);
250250
251251 size_t size = m_largeAllocated.remove(chunk);
252252 size_t totalPhysicalSize = size;

@@void Heap::deallocateSmallLine(UniqueLockHolder& lock, Object object, LineCache&
357357 m_freePages[pageClass].remove(chunk);
358358
359359 if (!m_chunkCache[pageClass].isEmpty())
360  deallocateSmallChunk(m_chunkCache[pageClass].pop(), pageClass);
 360 deallocateSmallChunk(lock, m_chunkCache[pageClass].pop(), pageClass);
361361
362362 m_chunkCache[pageClass].push(chunk);
363363 }

@@void Heap::allocateSmallBumpRangesByObject(
495495 }
496496}
497497
498 LargeRange Heap::splitAndAllocate(UniqueLockHolder&, LargeRange& range, size_t alignment, size_t size)
 498LargeRange Heap::splitAndAllocate(UniqueLockHolder& lock, LargeRange& range, size_t alignment, size_t size)
499499{
500500 RELEASE_BASSERT(isActiveHeapKind(m_kind));
501501

@@LargeRange Heap::splitAndAllocate(UniqueLockHolder&, LargeRange& range, size_t a
537537 m_largeFree.add(next);
538538 }
539539
540  m_objectTypes.set(Chunk::get(range.begin()), ObjectType::Large);
 540 m_objectTypes.set(lock, Chunk::get(range.begin()), ObjectType::Large);
541541
542542 m_largeAllocated.set(range.begin(), range.size());
543543 return range;

@@LargeRange Heap::tryAllocateLargeChunk(size_t alignment, size_t size)
621621 return LargeRange(memory, size, 0, 0);
622622}
623623
624 bool Heap::isLarge(UniqueLockHolder&, void* object)
625 {
626  return m_objectTypes.get(Object(object).chunk()) == ObjectType::Large;
627 }
628 
629624size_t Heap::largeSize(UniqueLockHolder&, void* object)
630625{
631626 return m_largeAllocated.get(object);

Source/bmalloc/bmalloc/Heap.h

3535#include "Map.h"
3636#include "Mutex.h"
3737#include "Object.h"
 38#include "ObjectTypeTable.h"
3839#include "PerHeapKind.h"
3940#include "PerProcess.h"
4041#include "PhysicalPageMap.h"

@@class Heap {
6970 void* allocateLarge(UniqueLockHolder&, size_t alignment, size_t, FailureAction);
7071 void deallocateLarge(UniqueLockHolder&, void*);
7172
72  bool isLarge(UniqueLockHolder&, void*);
 73 bool isLarge(void*);
7374 size_t largeSize(UniqueLockHolder&, void*);
7475 void shrinkLarge(UniqueLockHolder&, const Range&, size_t);
7576
7677#if BUSE(PARTIAL_SCAVENGE)
77  void scavengeToHighWatermark(const LockHolder&, BulkDecommit&);
78  void scavenge(const LockHolder&, BulkDecommit&);
 78 void scavengeToHighWatermark(UniqueLockHolder&, BulkDecommit&);
 79 void scavenge(UniqueLockHolder&, BulkDecommit&);
7980#else
80  void scavenge(const LockHolder&, BulkDecommit&, size_t& deferredDecommits);
 81 void scavenge(UniqueLockHolder&, BulkDecommit&, size_t& deferredDecommits);
8182#endif
82  void scavenge(const LockHolder&, BulkDecommit&, size_t& freed, size_t goal);
 83 void scavenge(UniqueLockHolder&, BulkDecommit&, size_t& freed, size_t goal);
8384
84  size_t freeableMemory(const LockHolder&);
 85 size_t freeableMemory(UniqueLockHolder&);
8586 size_t footprint();
8687
8788 void externalDecommit(void* ptr, size_t);

@@class Heap {
9293 void markAllLargeAsEligibile(const LockHolder&);
9394
9495private:
95  void decommitLargeRange(const LockHolder&, LargeRange&, BulkDecommit&);
 96 void decommitLargeRange(UniqueLockHolder&, LargeRange&, BulkDecommit&);
9697
9798 struct LargeObjectHash {
9899 static unsigned hash(void* key)

@@class Heap {
117118 void deallocateSmallLine(UniqueLockHolder&, Object, LineCache&);
118119
119120 void allocateSmallChunk(UniqueLockHolder&, size_t pageClass, FailureAction);
120  void deallocateSmallChunk(Chunk*, size_t pageClass);
 121 void deallocateSmallChunk(UniqueLockHolder&, Chunk*, size_t pageClass);
121122
122123 LargeRange tryAllocateLargeChunk(size_t alignment, size_t);
123124 LargeRange splitAndAllocate(UniqueLockHolder&, LargeRange&, size_t alignment, size_t);

@@class Heap {
135136 Map<void*, size_t, LargeObjectHash> m_largeAllocated;
136137 LargeMap m_largeFree;
137138
138  Map<Chunk*, ObjectType, ChunkHash> m_objectTypes;
 139 ObjectTypeTable m_objectTypes;
139140
140141 Scavenger* m_scavenger { nullptr };
141142

@@inline void Heap::derefSmallLine(UniqueLockHolder& lock, Object object, LineCach
168169 deallocateSmallLine(lock, object, lineCache);
169170}
170171
 172inline bool Heap::isLarge(void* object)
 173{
 174 return m_objectTypes.get(Object(object).chunk()) == ObjectType::Large;
 175}
 176
171177} // namespace bmalloc
172178
173179#endif // Heap_h

Source/bmalloc/bmalloc/ObjectType.cpp

@@ObjectType objectType(Heap& heap, void* object)
3838 if (!object)
3939 return ObjectType::Small;
4040
41  UniqueLockHolder lock(Heap::mutex());
42  if (heap.isLarge(lock, object))
 41 if (heap.isLarge(object))
4342 return ObjectType::Large;
4443 }
4544

Source/bmalloc/bmalloc/ObjectTypeTable.cpp

 1/*
 2 * Copyright (C) 2020 Apple 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
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26#include "ObjectTypeTable.h"
 27
 28#include "VMAllocate.h"
 29
 30namespace bmalloc {
 31
 32ObjectTypeTable::Bits sentinelBits { nullptr, 0, 0 };
 33
 34void ObjectTypeTable::set(UniqueLockHolder&, Chunk* chunk, ObjectType objectType)
 35{
 36 unsigned index = convertToIndex(chunk);
 37 Bits* bits = m_bits;
 38 if (!(bits->begin() <= index && index < bits->end())) {
 39 unsigned newBegin = 0;
 40 unsigned newEnd = 0;
 41 if (bits == &sentinelBits) {
 42 // This is initial allocation of ObjectTypeTable. In this case, it would be possible that the first registration could be
 43 // possible that some VAs are already allocated for different purpose, and later it will be reused for bmalloc. In that case,
 44 // soon, we will see smaller index request than the initial one.
 45 // We add 128MB offset to the initial newBegin to cover such patterns without extending table too quickly.
 46 newBegin = std::min<unsigned>(index, index - ObjectTypeTable::Bits::bitCountPerWord * 4);
 47 newEnd = index + 1;
 48 } else if (index < bits->begin()) {
 49 BASSERT(bits->begin());
 50 BASSERT(bits->end());
 51 newBegin = std::min<unsigned>(index, (bits->begin() - (bits->end() - bits->begin())));
 52 newEnd = bits->end();
 53 } else {
 54 BASSERT(bits->begin());
 55 BASSERT(bits->end());
 56 newBegin = bits->begin();
 57 newEnd = std::max<unsigned>(index + 1, bits->end() + (bits->end() - bits->begin()));
 58 }
 59 BASSERT(newEnd > newBegin);
 60
 61 unsigned count = newEnd - newBegin;
 62 size_t size = vmSize(sizeof(Bits) + (roundUpToMultipleOf<size_t>(ObjectTypeTable::Bits::bitCountPerWord, count) / 8));
 63 BASSERT(isPowerOf2(size));
 64 size = roundUpToPowerOf2(size, vmPageSize());
 65 newEnd = newBegin + ((size - sizeof(Bits)) / sizeof(ObjectTypeTable::Bits::WordType)) * ObjectTypeTable::Bits::bitCountPerWord;
 66 BASSERT(newEnd > newBegin);
 67 void* allocated = vmAllocate(size);
 68 memset(allocated, 0, size);
 69 auto* newBits = new (allocated) Bits(bits, newBegin, newEnd);
 70 for (unsigned index = bits->begin(); index < bits->end(); ++index)
 71 newBits->set(index, bits->get(index));
 72 std::atomic_thread_fence(std::memory_order_seq_cst); // Ensure table gets valid when it is visible to the other threads since ObjectTypeTable::get does not take a lock.
 73 m_bits = newBits;
 74 bits = newBits;
 75 }
 76 bool value = !!static_cast<std::underlying_type_t<ObjectType>>(objectType);
 77 BASSERT(static_cast<ObjectType>(value) == objectType);
 78 bits->set(index, value);
 79}
 80
 81} // namespace bmalloc

Source/bmalloc/bmalloc/ObjectTypeTable.h

 1/*
 2 * Copyright (C) 2020 Apple 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
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26#pragma once
 27
 28#include "Mutex.h"
 29#include "ObjectType.h"
 30#include "Sizes.h"
 31
 32namespace bmalloc {
 33
 34class Chunk;
 35
 36// Querying ObjectType for Chunk without locking.
 37class ObjectTypeTable {
 38public:
 39 ObjectTypeTable();
 40
 41 static_assert(BOS_EFFECTIVE_ADDRESS_WIDTH != 64);
 42 static constexpr unsigned shiftAmount = 20;
 43 static constexpr uintptr_t addressMask = (1ULL << BOS_EFFECTIVE_ADDRESS_WIDTH) - 1;
 44 static_assert((1ULL << shiftAmount) == chunkSize);
 45 static_assert((BOS_EFFECTIVE_ADDRESS_WIDTH - shiftAmount) <= 32);
 46
 47 class Bits;
 48
 49 ObjectType get(Chunk*);
 50 void set(UniqueLockHolder&, Chunk*, ObjectType);
 51
 52private:
 53 static unsigned convertToIndex(Chunk* chunk)
 54 {
 55 uintptr_t address = reinterpret_cast<uintptr_t>(chunk);
 56 BASSERT(!(address & (~chunkMask)));
 57 return static_cast<unsigned>((address & addressMask) >> shiftAmount);
 58 }
 59
 60 Bits* m_bits;
 61};
 62
 63class ObjectTypeTable::Bits {
 64public:
 65 using WordType = unsigned;
 66 static constexpr unsigned bitCountPerWord = sizeof(WordType) * 8;
 67 static constexpr WordType one = 1;
 68 constexpr Bits(Bits* previous, unsigned begin, unsigned end)
 69 : m_previous(previous)
 70 , m_begin(begin)
 71 , m_end(end)
 72 {
 73 }
 74
 75 bool get(unsigned index);
 76 void set(unsigned index, bool);
 77
 78 Bits* previous() const { return m_previous; }
 79 unsigned begin() const { return m_begin; }
 80 unsigned end() const { return m_end; }
 81
 82private:
 83 const WordType* words() const { return const_cast<Bits*>(this)->words(); }
 84 WordType* words() { return reinterpret_cast<WordType*>(reinterpret_cast<uintptr_t>(this) + sizeof(Bits)); }
 85
 86 Bits* m_previous { nullptr }; // Keeping the previous Bits* just to suppress Leaks warnings.
 87 unsigned m_begin { 0 };
 88 unsigned m_end { 0 };
 89};
 90static_assert(!(sizeof(ObjectTypeTable::Bits) % sizeof(ObjectTypeTable::Bits::WordType)));
 91
 92extern BEXPORT ObjectTypeTable::Bits sentinelBits;
 93
 94inline ObjectTypeTable::ObjectTypeTable()
 95 : m_bits(&sentinelBits)
 96{
 97}
 98
 99inline ObjectType ObjectTypeTable::get(Chunk* chunk)
 100{
 101 Bits* bits = m_bits;
 102 unsigned index = convertToIndex(chunk);
 103 BASSERT(bits);
 104 if (bits->begin() <= index && index < bits->end())
 105 return static_cast<ObjectType>(bits->get(index));
 106 return { };
 107}
 108
 109inline bool ObjectTypeTable::Bits::get(unsigned index)
 110{
 111 unsigned n = index - begin();
 112 return words()[n / bitCountPerWord] & (one << (n % bitCountPerWord));
 113}
 114
 115inline void ObjectTypeTable::Bits::set(unsigned index, bool value)
 116{
 117 unsigned n = index - begin();
 118 if (value)
 119 words()[n / bitCountPerWord] |= (one << (n % bitCountPerWord));
 120 else
 121 words()[n / bitCountPerWord] &= ~(one << (n % bitCountPerWord));
 122}
 123
 124} // namespace bmalloc

Source/bmalloc/bmalloc/Scavenger.cpp

@@void Scavenger::scavenge()
223223#if !BUSE(PARTIAL_SCAVENGE)
224224 size_t deferredDecommits = 0;
225225#endif
226  LockHolder lock(Heap::mutex());
 226 UniqueLockHolder lock(Heap::mutex());
227227 for (unsigned i = numHeaps; i--;) {
228228 if (!isActiveHeapKind(static_cast<HeapKind>(i)))
229229 continue;

@@void Scavenger::partialScavenge()
297297 BulkDecommit decommitter;
298298 {
299299 PrintTime printTime("\npartialScavenge under lock time");
300  LockHolder lock(Heap::mutex());
 300 UniqueLockHolder lock(Heap::mutex());
301301 for (unsigned i = numHeaps; i--;) {
302302 if (!isActiveHeapKind(static_cast<HeapKind>(i)))
303303 continue;

@@size_t Scavenger::freeableMemory()
355355{
356356 size_t result = 0;
357357 {
358  LockHolder lock(Heap::mutex());
 358 UniqueLockHolder lock(Heap::mutex());
359359 for (unsigned i = numHeaps; i--;) {
360360 if (!isActiveHeapKind(static_cast<HeapKind>(i)))
361361 continue;