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