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