[bmalloc] IsoHeap should have lower tier using shared IsoPage
[WebKit-https.git] / Source / bmalloc / bmalloc / IsoHeapImpl.h
1 /*
2  * Copyright (C) 2017-2018 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 "BMalloced.h"
29 #include "IsoAllocator.h"
30 #include "IsoDirectoryPage.h"
31 #include "IsoTLSAllocatorEntry.h"
32 #include "PhysicalPageMap.h"
33
34 namespace bmalloc {
35
36 class AllIsoHeaps;
37
38 class BEXPORT IsoHeapImplBase {
39     MAKE_BMALLOCED;
40 public:
41     static constexpr unsigned maxAllocationFromShared = 8;
42     static constexpr unsigned maxAllocationFromSharedMask = maxAllocationFromShared - 1;
43     static_assert(maxAllocationFromShared <= bmalloc::alignment, "");
44     static_assert(isPowerOfTwo(maxAllocationFromShared), "");
45
46     virtual ~IsoHeapImplBase();
47     
48     virtual void scavenge(Vector<DeferredDecommit>&) = 0;
49     virtual size_t freeableMemory() = 0;
50     virtual size_t footprint() = 0;
51     
52     void scavengeNow();
53     static void finishScavenging(Vector<DeferredDecommit>&);
54
55 protected:
56     IsoHeapImplBase();
57     void addToAllIsoHeaps();
58
59     friend class IsoSharedPage;
60     friend class AllIsoHeaps;
61     
62     IsoHeapImplBase* m_next { nullptr };
63     std::chrono::steady_clock::time_point m_slowPathTimePoint;
64     std::array<void*, maxAllocationFromShared> m_sharedCells { };
65     unsigned m_numberOfAllocationsFromSharedInOneCycle { 0 };
66     unsigned m_usableBits { maxAllocationFromSharedMask };
67     AllocationMode m_allocationMode { AllocationMode::Init };
68 };
69
70 template<typename Config>
71 class IsoHeapImpl final : public IsoHeapImplBase {
72     // Pick a size that makes us most efficiently use the bitvectors.
73     static constexpr unsigned numPagesInInlineDirectory = 32;
74     
75 public:
76     IsoHeapImpl();
77     
78     EligibilityResult<Config> takeFirstEligible();
79     
80     // Callbacks from directory.
81     void didBecomeEligible(IsoDirectory<Config, numPagesInInlineDirectory>*);
82     void didBecomeEligible(IsoDirectory<Config, IsoDirectoryPage<Config>::numPages>*);
83     
84     void scavenge(Vector<DeferredDecommit>&) override;
85
86     size_t freeableMemory() override;
87
88     size_t footprint() override;
89     
90     unsigned allocatorOffset();
91     unsigned deallocatorOffset();
92
93     // White-box testing functions.
94     unsigned numLiveObjects();
95     unsigned numCommittedPages();
96     
97     template<typename Func>
98     void forEachDirectory(const Func&);
99     
100     template<typename Func>
101     void forEachCommittedPage(const Func&);
102     
103     // This is only accurate when all threads are scavenged. Otherwise it will overestimate.
104     template<typename Func>
105     void forEachLiveObject(const Func&);
106
107     void didCommit(void* ptr, size_t bytes);
108     void didDecommit(void* ptr, size_t bytes);
109
110     void isNowFreeable(void* ptr, size_t bytes);
111     void isNoLongerFreeable(void* ptr, size_t bytes);
112
113     AllocationMode updateAllocationMode();
114     void* allocateFromShared(bool abortOnFailure);
115     
116     // It's almost always the caller's responsibility to grab the lock. This lock comes from the
117     // PerProcess<IsoTLSDeallocatorEntry<Config>>::get()->lock. That's pretty weird, and we don't
118     // try to disguise the fact that it's weird. We only do that because heaps in the same size class
119     // share the same deallocator log, so it makes sense for them to also share the same lock to
120     // amortize lock acquisition costs.
121     Mutex& lock;
122
123 private:
124     IsoDirectory<Config, numPagesInInlineDirectory> m_inlineDirectory;
125     IsoDirectoryPage<Config>* m_headDirectory { nullptr };
126     IsoDirectoryPage<Config>* m_tailDirectory { nullptr };
127     size_t m_footprint { 0 };
128     size_t m_freeableMemory { 0 };
129 #if ENABLE_PHYSICAL_PAGE_MAP
130     PhysicalPageMap m_physicalPageMap;
131 #endif
132     unsigned m_nextDirectoryPageIndex { 1 }; // We start at 1 so that the high water mark being zero means we've only allocated in the inline directory since the last scavenge.
133     unsigned m_directoryHighWatermark { 0 };
134     
135     bool m_isInlineDirectoryEligible { true };
136     IsoDirectoryPage<Config>* m_firstEligibleDirectory { nullptr };
137     
138     IsoTLSAllocatorEntry<Config> m_allocator;
139 };
140
141 } // namespace bmalloc
142
143