1 /*
2 * Copyright (c) 2021-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_SPACE_H
17 #define ECMASCRIPT_MEM_SPACE_H
18
19 #include "ecmascript/mem/allocation_inspector.h"
20 #include "ecmascript/mem/allocator.h"
21 #include "ecmascript/mem/c_containers.h"
22 #include "ecmascript/mem/ecma_list.h"
23 #include "ecmascript/mem/heap_region_allocator.h"
24 #include "ecmascript/mem/mem.h"
25 #include "ecmascript/mem/region.h"
26
27 #include "securec.h"
28
29 namespace panda::ecmascript {
30 enum MemSpaceType {
31 OLD_SPACE = 0,
32 NON_MOVABLE,
33 MACHINE_CODE_SPACE,
34 HUGE_OBJECT_SPACE,
35 SEMI_SPACE,
36 SNAPSHOT_SPACE,
37 COMPRESS_SPACE,
38 LOCAL_SPACE,
39 READ_ONLY_SPACE,
40 APPSPAWN_SPACE,
41 HUGE_MACHINE_CODE_SPACE,
42 SHARED_OLD_SPACE,
43 SHARED_NON_MOVABLE,
44 SHARED_READ_ONLY_SPACE,
45 SHARED_HUGE_OBJECT_SPACE,
46 SHARED_LOCAL_SPACE,
47 SHARED_COMPRESS_SPACE,
48 SHARED_APPSPAWN_SPACE,
49 SPACE_TYPE_LAST, // Count of different types
50
51 SHARED_BEGIN = SHARED_OLD_SPACE,
52 SHARED_END = SHARED_HUGE_OBJECT_SPACE,
53 // Free region means memory maybe always in use and can not be evacuated
54 FREE_LIST_NUM = MACHINE_CODE_SPACE - OLD_SPACE + 1,
55 SHARED_SWEEPING_SPACE_BEGIN = SHARED_OLD_SPACE,
56 SHARED_SWEEPING_SPACE_END = SHARED_NON_MOVABLE,
57 SHARED_SWEEPING_SPACE_NUM = SHARED_SWEEPING_SPACE_END - SHARED_SWEEPING_SPACE_BEGIN + 1,
58 };
59
60 enum class MemSpaceKind {
61 LOCAL = 0,
62 SHARED = 1
63 };
64
65 enum class AllocateEventType {
66 NORMAL,
67 DESERIALIZE,
68 };
69
IsSMemSpace(MemSpaceType type)70 static inline bool IsSMemSpace(MemSpaceType type)
71 {
72 return (type >= MemSpaceType::SHARED_BEGIN) && (type <= MemSpaceType::SHARED_END);
73 }
74
ToSpaceTypeName(MemSpaceType type)75 static inline std::string ToSpaceTypeName(MemSpaceType type)
76 {
77 switch (type) {
78 case OLD_SPACE:
79 case LOCAL_SPACE:
80 return "old space";
81 case NON_MOVABLE:
82 return "non movable space";
83 case MACHINE_CODE_SPACE:
84 return "machine code space";
85 case HUGE_OBJECT_SPACE:
86 return "huge object space";
87 case SEMI_SPACE:
88 return "semi space";
89 case SNAPSHOT_SPACE:
90 return "snapshot space";
91 case COMPRESS_SPACE:
92 return "compress space";
93 case READ_ONLY_SPACE:
94 return "read only space";
95 case APPSPAWN_SPACE:
96 return "appspawn space";
97 case HUGE_MACHINE_CODE_SPACE:
98 return "huge machine code space";
99 case SHARED_NON_MOVABLE:
100 return "shared non movable space";
101 case SHARED_OLD_SPACE:
102 case SHARED_LOCAL_SPACE:
103 return "shared old space";
104 case SHARED_READ_ONLY_SPACE:
105 return "shared read only space";
106 case SHARED_HUGE_OBJECT_SPACE:
107 return "shared huge object space";
108 case SHARED_COMPRESS_SPACE:
109 return "compress space";
110 case SHARED_APPSPAWN_SPACE:
111 return "shared appspawn space";
112 default:
113 return "unknown space";
114 }
115 }
116
117 class Space {
118 public:
119 Space(BaseHeap* heap, HeapRegionAllocator *regionAllocator, MemSpaceType spaceType, size_t initialCapacity,
120 size_t maximumCapacity);
121 virtual ~Space() = default;
122 NO_COPY_SEMANTIC(Space);
123 NO_MOVE_SEMANTIC(Space);
124
GetMaximumCapacity()125 size_t GetMaximumCapacity() const
126 {
127 return maximumCapacity_;
128 }
129
SetMaximumCapacity(size_t maximumCapacity)130 void SetMaximumCapacity(size_t maximumCapacity)
131 {
132 maximumCapacity_ = maximumCapacity;
133 }
134
GetOverShootMaximumCapacity()135 size_t GetOverShootMaximumCapacity() const
136 {
137 return maximumCapacity_ + outOfMemoryOvershootSize_;
138 }
139
GetInitialCapacity()140 size_t GetInitialCapacity() const
141 {
142 return initialCapacity_;
143 }
144
SetInitialCapacity(size_t initialCapacity)145 void SetInitialCapacity(size_t initialCapacity)
146 {
147 initialCapacity_ = initialCapacity;
148 }
149
GetCommittedSize()150 size_t GetCommittedSize() const
151 {
152 return committedSize_;
153 }
154
IncreaseCommitted(size_t bytes)155 void IncreaseCommitted(size_t bytes)
156 {
157 committedSize_ += bytes;
158 }
159
DecreaseCommitted(size_t bytes)160 void DecreaseCommitted(size_t bytes)
161 {
162 committedSize_ -= bytes;
163 }
164
IncreaseObjectSize(size_t bytes)165 void IncreaseObjectSize(size_t bytes)
166 {
167 objectSize_ += bytes;
168 }
169
DecreaseObjectSize(size_t bytes)170 void DecreaseObjectSize(size_t bytes)
171 {
172 objectSize_ -= bytes;
173 }
174
GetObjectSize()175 size_t GetObjectSize()
176 {
177 return objectSize_;
178 }
179
GetOutOfMemoryOvershootSize()180 size_t GetOutOfMemoryOvershootSize() const
181 {
182 return outOfMemoryOvershootSize_;
183 }
184
IncreaseOutOfMemoryOvershootSize(size_t size)185 void IncreaseOutOfMemoryOvershootSize(size_t size)
186 {
187 outOfMemoryOvershootSize_ += size;
188 }
189
DecreaseOutOfMemoryOvershootSize(size_t size)190 void DecreaseOutOfMemoryOvershootSize(size_t size)
191 {
192 ASSERT(outOfMemoryOvershootSize_ >= size);
193 outOfMemoryOvershootSize_ -= size;
194 }
195
GetSpaceType()196 MemSpaceType GetSpaceType() const
197 {
198 return spaceType_;
199 }
200
201 inline RegionSpaceFlag GetRegionFlag() const;
202
GetAllocateAreaBegin()203 uintptr_t GetAllocateAreaBegin() const
204 {
205 return regionList_.GetLast()->GetBegin();
206 }
207
GetAllocateAreaEnd()208 uintptr_t GetAllocateAreaEnd() const
209 {
210 return regionList_.GetLast()->GetEnd();
211 }
212
GetCurrentRegion()213 Region *GetCurrentRegion() const
214 {
215 return regionList_.GetLast();
216 }
217
GetFirstRegion()218 Region *GetFirstRegion() const
219 {
220 return regionList_.GetFirst();
221 }
222
GetRegionCount()223 uint32_t GetRegionCount()
224 {
225 return regionList_.GetLength();
226 }
227
GetRegionList()228 EcmaList<Region> &GetRegionList()
229 {
230 return regionList_;
231 }
232
GetRegionList()233 const EcmaList<Region> &GetRegionList() const
234 {
235 return regionList_;
236 }
237
SetRecordRegion()238 void SetRecordRegion()
239 {
240 recordRegion_ = GetCurrentRegion();
241 }
242
IsOOMDumpSpace()243 bool IsOOMDumpSpace()
244 {
245 return spaceType_ == SEMI_SPACE || spaceType_ == OLD_SPACE || spaceType_ == NON_MOVABLE ||
246 spaceType_ == HUGE_OBJECT_SPACE;
247 }
248
249 // methods for allocation inspector
250 void AddAllocationInspector(AllocationInspector* inspector);
251 void ClearAllocationInspector();
252 void SwapAllocationCounter(Space *space);
253
254 template <class Callback>
255 inline void EnumerateRegions(const Callback &cb, Region *region = nullptr) const;
256 template <class Callback>
257 inline void EnumerateRegionsWithRecord(const Callback &cb) const;
258
259 inline void AddRegion(Region *region);
260 inline void RemoveRegion(Region *region);
261
Initialize()262 virtual void Initialize() {};
263 void Destroy();
264
265 void ReclaimRegions(size_t cachedSize = 0);
266
267 protected:
268 void ClearAndFreeRegion(Region *region, size_t cachedSize = 0);
269
270 BaseHeap *heap_ {nullptr};
271 HeapRegionAllocator *heapRegionAllocator_ {nullptr};
272 EcmaList<Region> regionList_ {};
273 MemSpaceType spaceType_ {};
274 size_t initialCapacity_ {0};
275 size_t maximumCapacity_ {0};
276 size_t committedSize_ {0};
277 size_t objectSize_ {0};
278 size_t outOfMemoryOvershootSize_ {0};
279 Region *recordRegion_ {nullptr};
280 AllocationCounter allocationCounter_;
281 };
282
283 class HugeObjectSpace : public Space {
284 public:
285 HugeObjectSpace(Heap *heap, HeapRegionAllocator *regionAllocator, size_t initialCapacity,
286 size_t maximumCapacity);
287 HugeObjectSpace(Heap *heap, HeapRegionAllocator *regionAllocator, size_t initialCapacity,
288 size_t maximumCapacity, MemSpaceType spaceType);
289 ~HugeObjectSpace() override = default;
290 NO_COPY_SEMANTIC(HugeObjectSpace);
291 NO_MOVE_SEMANTIC(HugeObjectSpace);
292 // Sometimes it is unsafe to checkSafePoint here, e.g. in deserialize, if do checkSafePoint JSThread may be
293 // suspended and then do SharedGC, which will free some regions in SharedHeap that are allocated at the beginning
294 // of deserializing for further object allocating, but no object has been allocated on at this moment.
295 uintptr_t Allocate(size_t objectSize, JSThread *thread, AllocateEventType allocType = AllocateEventType::NORMAL);
296 void Sweep();
297 size_t GetHeapObjectSize() const;
298 void IterateOverObjects(const std::function<void(TaggedObject *object)> &objectVisitor) const;
299
300 void ReclaimHugeRegion();
301
302 void InvokeAllocationInspector(Address object, size_t objectSize);
303
304 protected:
305 static constexpr size_t HUGE_OBJECT_BITSET_SIZE = 16;
306 private:
307 EcmaList<Region> hugeNeedFreeList_ {};
308 };
309
310 class HugeMachineCodeSpace : public HugeObjectSpace {
311 public:
312 HugeMachineCodeSpace(Heap *heap, HeapRegionAllocator *regionAllocator, size_t initialCapacity,
313 size_t maximumCapacity);
314 uintptr_t GetMachineCodeObject(uintptr_t pc) const;
315 uintptr_t Allocate(size_t objectSize, JSThread *thread, void *desc,
316 AllocateEventType allocType = AllocateEventType::NORMAL);
317 uintptr_t Allocate(size_t objectSize, JSThread *thread);
318 Region *PUBLIC_API AllocateFort(size_t objectSize, JSThread *thread, void *desc);
319 };
320
321 } // namespace panda::ecmascript
322 #endif // ECMASCRIPT_MEM_SPACE_H
323