• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef ECMASCRIPT_MEM_MEM_MAP_ALLOCATOR_H
17 #define ECMASCRIPT_MEM_MEM_MAP_ALLOCATOR_H
18 
19 #include <deque>
20 #include <map>
21 
22 #include "ecmascript/platform/map.h"
23 #include "ecmascript/mem/mem.h"
24 #include "ecmascript/mem/mem_common.h"
25 #include "ecmascript/log_wrapper.h"
26 #include "libpandabase/os/mutex.h"
27 
28 namespace panda::ecmascript {
29 // Regular region with length of DEFAULT_REGION_SIZE(256kb)
30 class MemMapPool {
31 public:
32     explicit MemMapPool() = default;
33     ~MemMapPool() = default;
34 
Finalize()35     void Finalize()
36     {
37         os::memory::LockHolder lock(lock_);
38         for (auto &it : memMapVector_) {
39             PageUnmap(it);
40         }
41         memMapVector_.clear();
42         memMapCache_.clear();
43     }
44 
45     NO_COPY_SEMANTIC(MemMapPool);
46     NO_MOVE_SEMANTIC(MemMapPool);
47 
GetMemFromCache(size_t size)48     MemMap GetMemFromCache([[maybe_unused]]size_t size)
49     {
50         ASSERT(size == REGULAR_MMAP_SIZE);
51         os::memory::LockHolder lock(lock_);
52         if (!memMapCache_.empty()) {
53             MemMap mem = memMapCache_.front();
54             memMapCache_.pop_front();
55             return mem;
56         }
57         return MemMap();
58     }
59 
AddMemToCache(void * mem,size_t size)60     void AddMemToCache(void *mem, size_t size)
61     {
62         ASSERT(size == REGULAR_MMAP_SIZE);
63         os::memory::LockHolder lock(lock_);
64         memMapCache_.emplace_back(mem, size);
65     }
66 
SplitMemFromCache(MemMap memMap)67     MemMap SplitMemFromCache(MemMap memMap)
68     {
69         os::memory::LockHolder lock(lock_);
70         auto remainderMem = reinterpret_cast<uintptr_t>(memMap.GetMem()) + REGULAR_MMAP_SIZE;
71         size_t remainderSize = AlignDown(memMap.GetSize() - REGULAR_MMAP_SIZE, REGULAR_MMAP_SIZE);
72         size_t count = remainderSize / REGULAR_MMAP_SIZE;
73         while (count-- > 0) {
74             memMapCache_.emplace_back(reinterpret_cast<void *>(remainderMem), REGULAR_MMAP_SIZE);
75             remainderMem = remainderMem + REGULAR_MMAP_SIZE;
76         }
77         return MemMap(memMap.GetMem(), REGULAR_MMAP_SIZE);
78     }
79 
InsertMemMap(MemMap memMap)80     void InsertMemMap(MemMap memMap)
81     {
82         os::memory::LockHolder lock(lock_);
83         memMapVector_.emplace_back(memMap);
84     }
85 
86 private:
87     static constexpr size_t REGULAR_MMAP_SIZE = 256_KB;
88     os::memory::Mutex lock_;
89     std::deque<MemMap> memMapCache_;
90     std::vector<MemMap> memMapVector_;
91 };
92 
93 // Non regular region with length of DEFAULT_REGION_SIZE(256kb) multiple
94 class MemMapFreeList {
95 public:
96     MemMapFreeList() = default;
97     ~MemMapFreeList() = default;
98 
Initialize(MemMap memMap)99     void Initialize(MemMap memMap)
100     {
101         memMap_ = memMap;
102         freeList_.emplace(memMap.GetSize(), memMap);
103         capacity_ = memMap.GetSize();
104     }
105 
Finalize()106     void Finalize()
107     {
108         PageUnmap(memMap_);
109         freeList_.clear();
110     }
111 
112     NO_COPY_SEMANTIC(MemMapFreeList);
113     NO_MOVE_SEMANTIC(MemMapFreeList);
114 
GetMemFromList(size_t size)115     MemMap GetMemFromList(size_t size)
116     {
117         if (freeListPoolSize_ + size > capacity_) {
118             LOG_GC(ERROR) << "Freelist pool oom: overflow(" << freeListPoolSize_ << ")";
119             return MemMap();
120         }
121         os::memory::LockHolder lock(lock_);
122         auto iterate = freeList_.lower_bound(size);
123         if (iterate == freeList_.end()) {
124             LOG_GC(ERROR) << "Freelist pool oom: memory fragment(" << freeListPoolSize_ << ")";
125             return MemMap();
126         }
127         MemMap memMap = iterate->second;
128         size_t remainderSize = memMap.GetSize() - size;
129         freeList_.erase(iterate);
130         if (remainderSize >= DEFAULT_REGION_SIZE) {
131             auto next = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(memMap.GetMem()) + size);
132             freeList_.emplace(remainderSize, MemMap(next, remainderSize));
133         }
134         freeListPoolSize_ += size;
135         return MemMap(memMap.GetMem(), size);
136     }
137 
AddMemToList(MemMap memMap)138     void AddMemToList(MemMap memMap)
139     {
140         os::memory::LockHolder lock(lock_);
141         freeListPoolSize_ -= memMap.GetSize();
142         freeList_.emplace(memMap.GetSize(), memMap);
143     }
144 
145 private:
146     os::memory::Mutex lock_;
147     MemMap memMap_;
148     std::multimap<size_t, MemMap> freeList_;
149     std::atomic_size_t freeListPoolSize_ {0};
150     size_t capacity_ {0};
151 };
152 
153 class MemMapAllocator {
154 public:
155     MemMapAllocator() = default;
156     ~MemMapAllocator() = default;
157 
158     NO_COPY_SEMANTIC(MemMapAllocator);
159     NO_MOVE_SEMANTIC(MemMapAllocator);
160 
Initialize(size_t alignment)161     void Initialize(size_t alignment)
162     {
163         AdapterSuitablePoolCapacity();
164         memMapTotalSize_ = 0;
165         size_t hugeObjectCapacity = std::min(capacity_ / 2, MAX_HUGE_OBJECT_CAPACITY);
166         MemMap memMap = PageMap(hugeObjectCapacity, PAGE_PROT_NONE, alignment);
167         PageRelease(memMap.GetMem(), memMap.GetSize());
168         memMapFreeList_.Initialize(memMap);
169     }
170 
Finalize()171     void Finalize()
172     {
173         memMapTotalSize_ = 0;
174         capacity_ = 0;
175         memMapFreeList_.Finalize();
176         memMapPool_.Finalize();
177     }
178 
GetCapacity()179     size_t GetCapacity()
180     {
181         return capacity_;
182     }
183 
IncreaseAndCheckReserved(size_t size)184     void IncreaseAndCheckReserved(size_t size)
185     {
186         if (reserved_ + size > capacity_) {
187             LOG_GC(ERROR) << "pool is empty, reserved = " << reserved_ << ", capacity_ = "
188                                 << capacity_ << ", size = " << size;
189         }
190         reserved_ += size;
191         LOG_GC(DEBUG) << "Ark IncreaseAndCheckReserved reserved = " << reserved_ << ", capacity_ = " << capacity_;
192     }
193 
DecreaseReserved(size_t size)194     void DecreaseReserved(size_t size)
195     {
196         reserved_ -= size;
197         LOG_GC(DEBUG) << "Ark DecreaseReserved reserved = " << reserved_ << ", capacity_ = " << capacity_;
198     }
199 
200     static MemMapAllocator *GetInstance();
201 
202     MemMap Allocate(size_t size, size_t alignment, bool regular, int prot);
203 
204     void Free(void *mem, size_t size, bool isRegular);
205 
206 private:
207     static constexpr size_t REGULAR_REGION_MMAP_SIZE = 4_MB;
208 
209     void AdapterSuitablePoolCapacity();
210 
211     MemMapPool memMapPool_;
212     MemMapFreeList memMapFreeList_;
213     std::atomic_size_t memMapTotalSize_ {0};
214     size_t capacity_ {0};
215     size_t reserved_ {0};
216 };
217 }  // namespace panda::ecmascript
218 #endif  // ECMASCRIPT_MEM_MEM_MAP_ALLOCATOR_H
219