[BMalloc] Scavenger should react to recent memory activity
[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 "IsoDirectoryPage.h"
30 #include "IsoTLSAllocatorEntry.h"
31 #include "PhysicalPageMap.h"
32
33 namespace bmalloc {
34
35 class AllIsoHeaps;
36
37 class BEXPORT IsoHeapImplBase {
38     MAKE_BMALLOCED;
39 public:
40     virtual ~IsoHeapImplBase();
41     
42     virtual void scavenge(Vector<DeferredDecommit>&) = 0;
43     virtual size_t freeableMemory() = 0;
44     virtual size_t footprint() = 0;
45     
46     void scavengeNow();
47     static void finishScavenging(Vector<DeferredDecommit>&);
48     
49 protected:
50     IsoHeapImplBase();
51     void addToAllIsoHeaps();
52
53 private:
54     friend class AllIsoHeaps;
55     
56     IsoHeapImplBase* m_next { nullptr };
57 };
58
59 template<typename Config>
60 class IsoHeapImpl final : public IsoHeapImplBase {
61     // Pick a size that makes us most efficiently use the bitvectors.
62     static constexpr unsigned numPagesInInlineDirectory = 32;
63     
64 public:
65     IsoHeapImpl();
66     
67     EligibilityResult<Config> takeFirstEligible();
68     
69     // Callbacks from directory.
70     void didBecomeEligible(IsoDirectory<Config, numPagesInInlineDirectory>*);
71     void didBecomeEligible(IsoDirectory<Config, IsoDirectoryPage<Config>::numPages>*);
72     
73     void scavenge(Vector<DeferredDecommit>&) override;
74
75     size_t freeableMemory() override;
76
77     size_t footprint() override;
78     
79     unsigned allocatorOffset();
80     unsigned deallocatorOffset();
81
82     // White-box testing functions.
83     unsigned numLiveObjects();
84     unsigned numCommittedPages();
85     
86     template<typename Func>
87     void forEachDirectory(const Func&);
88     
89     template<typename Func>
90     void forEachCommittedPage(const Func&);
91     
92     // This is only accurate when all threads are scavenged. Otherwise it will overestimate.
93     template<typename Func>
94     void forEachLiveObject(const Func&);
95
96     void didCommit(void* ptr, size_t bytes);
97     void didDecommit(void* ptr, size_t bytes);
98
99     void isNowFreeable(void* ptr, size_t bytes);
100     void isNoLongerFreeable(void* ptr, size_t bytes);
101     
102     // It's almost always the caller's responsibility to grab the lock. This lock comes from the
103     // PerProcess<IsoTLSDeallocatorEntry<Config>>::get()->lock. That's pretty weird, and we don't
104     // try to disguise the fact that it's weird. We only do that because heaps in the same size class
105     // share the same deallocator log, so it makes sense for them to also share the same lock to
106     // amortize lock acquisition costs.
107     Mutex& lock;
108
109 private:
110     IsoDirectory<Config, numPagesInInlineDirectory> m_inlineDirectory;
111     IsoDirectoryPage<Config>* m_headDirectory { nullptr };
112     IsoDirectoryPage<Config>* m_tailDirectory { nullptr };
113     size_t m_footprint { 0 };
114     size_t m_freeableMemory { 0 };
115 #if ENABLE_PHYSICAL_PAGE_MAP
116     PhysicalPageMap m_physicalPageMap;
117 #endif
118     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.
119     unsigned m_directoryHighWatermark { 0 };
120     
121     bool m_isInlineDirectoryEligible { true };
122     IsoDirectoryPage<Config>* m_firstEligibleDirectory { nullptr };
123     
124     IsoTLSAllocatorEntry<Config> m_allocator;
125 };
126
127 } // namespace bmalloc
128
129