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 case LOCAL_SPACE:
81 return "old space";
82 case NON_MOVABLE:
83 return "non movable space";
84 case MACHINE_CODE_SPACE:
85 return "machine code space";
86 case HUGE_OBJECT_SPACE:
87 return "huge object space";
88 case EDEN_SPACE:
89 return "eden space";
90 case SEMI_SPACE:
91 return "semi space";
92 case SNAPSHOT_SPACE:
93 return "snapshot space";
94 case COMPRESS_SPACE:
95 return "compress space";
96 case READ_ONLY_SPACE:
97 return "read only space";
98 case APPSPAWN_SPACE:
99 return "appspawn space";
100 case HUGE_MACHINE_CODE_SPACE:
101 return "huge machine code space";
102 case SHARED_NON_MOVABLE:
103 return "shared non movable space";
104 case SHARED_OLD_SPACE:
105 case SHARED_LOCAL_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_APPSPAWN_SPACE:
114 return "shared appspawn space";
115 default:
116 return "unknown space";
117 }
118 }
119
120 class Space {
121 public:
122 Space(BaseHeap* heap, HeapRegionAllocator *regionAllocator, MemSpaceType spaceType, size_t initialCapacity,
123 size_t maximumCapacity);
124 virtual ~Space() = default;
125 NO_COPY_SEMANTIC(Space);
126 NO_MOVE_SEMANTIC(Space);
127
GetMaximumCapacity()128 size_t GetMaximumCapacity() const
129 {
130 return maximumCapacity_;
131 }
132
SetMaximumCapacity(size_t maximumCapacity)133 void SetMaximumCapacity(size_t maximumCapacity)
134 {
135 maximumCapacity_ = maximumCapacity;
136 }
137
GetOverShootMaximumCapacity()138 size_t GetOverShootMaximumCapacity() const
139 {
140 return maximumCapacity_ + outOfMemoryOvershootSize_;
141 }
142
GetInitialCapacity()143 size_t GetInitialCapacity() const
144 {
145 return initialCapacity_;
146 }
147
SetInitialCapacity(size_t initialCapacity)148 void SetInitialCapacity(size_t initialCapacity)
149 {
150 initialCapacity_ = initialCapacity;
151 }
152
GetCommittedSize()153 size_t GetCommittedSize() const
154 {
155 return committedSize_;
156 }
157
IncreaseCommitted(size_t bytes)158 void IncreaseCommitted(size_t bytes)
159 {
160 committedSize_ += bytes;
161 }
162
DecreaseCommitted(size_t bytes)163 void DecreaseCommitted(size_t bytes)
164 {
165 committedSize_ -= bytes;
166 }
167
IncreaseObjectSize(size_t bytes)168 void IncreaseObjectSize(size_t bytes)
169 {
170 objectSize_ += bytes;
171 }
172
DecreaseObjectSize(size_t bytes)173 void DecreaseObjectSize(size_t bytes)
174 {
175 objectSize_ -= bytes;
176 }
177
GetObjectSize()178 size_t GetObjectSize()
179 {
180 return objectSize_;
181 }
182
GetOutOfMemoryOvershootSize()183 size_t GetOutOfMemoryOvershootSize() const
184 {
185 return outOfMemoryOvershootSize_;
186 }
187
IncreaseOutOfMemoryOvershootSize(size_t size)188 void IncreaseOutOfMemoryOvershootSize(size_t size)
189 {
190 outOfMemoryOvershootSize_ += size;
191 }
192
DecreaseOutOfMemoryOvershootSize(size_t size)193 void DecreaseOutOfMemoryOvershootSize(size_t size)
194 {
195 ASSERT(outOfMemoryOvershootSize_ >= size);
196 outOfMemoryOvershootSize_ -= size;
197 }
198
GetSpaceType()199 MemSpaceType GetSpaceType() const
200 {
201 return spaceType_;
202 }
203
204 inline RegionSpaceFlag GetRegionFlag() const;
205
GetAllocateAreaBegin()206 uintptr_t GetAllocateAreaBegin() const
207 {
208 return regionList_.GetLast()->GetBegin();
209 }
210
GetAllocateAreaEnd()211 uintptr_t GetAllocateAreaEnd() const
212 {
213 return regionList_.GetLast()->GetEnd();
214 }
215
GetCurrentRegion()216 Region *GetCurrentRegion() const
217 {
218 return regionList_.GetLast();
219 }
220
GetFirstRegion()221 Region *GetFirstRegion() const
222 {
223 return regionList_.GetFirst();
224 }
225
GetRegionCount()226 uint32_t GetRegionCount()
227 {
228 return regionList_.GetLength();
229 }
230
GetRegionList()231 EcmaList<Region> &GetRegionList()
232 {
233 return regionList_;
234 }
235
GetRegionList()236 const EcmaList<Region> &GetRegionList() const
237 {
238 return regionList_;
239 }
240
SetRecordRegion()241 void SetRecordRegion()
242 {
243 recordRegion_ = GetCurrentRegion();
244 }
245
IsOOMDumpSpace()246 bool IsOOMDumpSpace()
247 {
248 return spaceType_ == SEMI_SPACE || spaceType_ == OLD_SPACE || spaceType_ == NON_MOVABLE ||
249 spaceType_ == HUGE_OBJECT_SPACE;
250 }
251
252 // methods for allocation inspector
253 void AddAllocationInspector(AllocationInspector* inspector);
254 void ClearAllocationInspector();
255 void SwapAllocationCounter(Space *space);
256
257 template <class Callback>
258 inline void EnumerateRegions(const Callback &cb, Region *region = nullptr) const;
259 template <class Callback>
260 inline void EnumerateRegionsWithRecord(const Callback &cb) const;
261
262 inline void AddRegion(Region *region);
263 inline void RemoveRegion(Region *region);
264
Initialize()265 virtual void Initialize() {};
266 void Destroy();
267
268 void ReclaimRegions(size_t cachedSize = 0);
269
270 protected:
271 void ClearAndFreeRegion(Region *region, size_t cachedSize = 0);
272
273 BaseHeap *heap_ {nullptr};
274 HeapRegionAllocator *heapRegionAllocator_ {nullptr};
275 EcmaList<Region> regionList_ {};
276 MemSpaceType spaceType_ {};
277 size_t initialCapacity_ {0};
278 size_t maximumCapacity_ {0};
279 size_t committedSize_ {0};
280 size_t objectSize_ {0};
281 size_t outOfMemoryOvershootSize_ {0};
282 Region *recordRegion_ {nullptr};
283 AllocationCounter allocationCounter_;
284 };
285
286 class HugeObjectSpace : public Space {
287 public:
288 HugeObjectSpace(Heap *heap, HeapRegionAllocator *regionAllocator, size_t initialCapacity,
289 size_t maximumCapacity);
290 HugeObjectSpace(Heap *heap, HeapRegionAllocator *regionAllocator, size_t initialCapacity,
291 size_t maximumCapacity, MemSpaceType spaceType);
292 ~HugeObjectSpace() override = default;
293 NO_COPY_SEMANTIC(HugeObjectSpace);
294 NO_MOVE_SEMANTIC(HugeObjectSpace);
295 // Sometimes it is unsafe to checkSafePoint here, e.g. in deserialize, if do checkSafePoint JSThread may be
296 // suspended and then do SharedGC, which will free some regions in SharedHeap that are allocated at the beginning
297 // of deserializing for further object allocating, but no object has been allocated on at this moment.
298 uintptr_t Allocate(size_t objectSize, JSThread *thread, AllocateEventType allocType = AllocateEventType::NORMAL);
299 void Sweep();
300 size_t GetHeapObjectSize() const;
301 void IterateOverObjects(const std::function<void(TaggedObject *object)> &objectVisitor) const;
302
303 void ReclaimHugeRegion();
304
305 void InvokeAllocationInspector(Address object, size_t objectSize);
306
307 protected:
308 static constexpr size_t HUGE_OBJECT_BITSET_SIZE = 16;
309 private:
310 EcmaList<Region> hugeNeedFreeList_ {};
311 };
312
313 class HugeMachineCodeSpace : public HugeObjectSpace {
314 public:
315 HugeMachineCodeSpace(Heap *heap, HeapRegionAllocator *regionAllocator, size_t initialCapacity,
316 size_t maximumCapacity);
317 uintptr_t GetMachineCodeObject(uintptr_t pc) const;
318 uintptr_t Allocate(size_t objectSize, JSThread *thread, void *desc,
319 AllocateEventType allocType = AllocateEventType::NORMAL);
320 uintptr_t Allocate(size_t objectSize, JSThread *thread);
321 Region *PUBLIC_API AllocateFort(size_t objectSize, JSThread *thread, void *desc);
322 };
323
324 } // namespace panda::ecmascript
325 #endif // ECMASCRIPT_MEM_SPACE_H
326