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