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
29namespace panda::ecmascript {
30enum 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
61enum class MemSpaceKind {
62    LOCAL = 0,
63    SHARED = 1
64};
65
66enum class AllocateEventType {
67    NORMAL,
68    DESERIALIZE,
69};
70
71static inline bool IsSMemSpace(MemSpaceType type)
72{
73    return (type >= MemSpaceType::SHARED_BEGIN) && (type <= MemSpaceType::SHARED_END);
74}
75
76static 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
122class Space {
123public:
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
130    size_t GetMaximumCapacity() const
131    {
132        return maximumCapacity_;
133    }
134
135    void SetMaximumCapacity(size_t maximumCapacity)
136    {
137        maximumCapacity_ = maximumCapacity;
138    }
139
140    size_t GetOverShootMaximumCapacity() const
141    {
142        return maximumCapacity_ + outOfMemoryOvershootSize_;
143    }
144
145    size_t GetInitialCapacity() const
146    {
147        return initialCapacity_;
148    }
149
150    void SetInitialCapacity(size_t initialCapacity)
151    {
152        initialCapacity_ = initialCapacity;
153    }
154
155    size_t GetCommittedSize() const
156    {
157        return committedSize_;
158    }
159
160    void IncreaseCommitted(size_t bytes)
161    {
162        committedSize_ += bytes;
163    }
164
165    void DecreaseCommitted(size_t bytes)
166    {
167        committedSize_ -= bytes;
168    }
169
170    void IncreaseObjectSize(size_t bytes)
171    {
172        objectSize_ += bytes;
173    }
174
175    void DecreaseObjectSize(size_t bytes)
176    {
177        objectSize_ -= bytes;
178    }
179
180    size_t GetObjectSize()
181    {
182        return objectSize_;
183    }
184
185    size_t GetOutOfMemoryOvershootSize() const
186    {
187        return outOfMemoryOvershootSize_;
188    }
189
190    void IncreaseOutOfMemoryOvershootSize(size_t size)
191    {
192        outOfMemoryOvershootSize_ += size;
193    }
194
195    void DecreaseOutOfMemoryOvershootSize(size_t size)
196    {
197        ASSERT(outOfMemoryOvershootSize_ >= size);
198        outOfMemoryOvershootSize_ -= size;
199    }
200
201    MemSpaceType GetSpaceType() const
202    {
203        return spaceType_;
204    }
205
206    inline RegionSpaceFlag GetRegionFlag() const;
207
208    uintptr_t GetAllocateAreaBegin() const
209    {
210        return regionList_.GetLast()->GetBegin();
211    }
212
213    uintptr_t GetAllocateAreaEnd() const
214    {
215        return regionList_.GetLast()->GetEnd();
216    }
217
218    Region *GetCurrentRegion() const
219    {
220        return regionList_.GetLast();
221    }
222
223    Region *GetFirstRegion() const
224    {
225        return regionList_.GetFirst();
226    }
227
228    uint32_t GetRegionCount()
229    {
230        return regionList_.GetLength();
231    }
232
233    EcmaList<Region> &GetRegionList()
234    {
235        return regionList_;
236    }
237
238    const EcmaList<Region> &GetRegionList() const
239    {
240        return regionList_;
241    }
242
243    void SetRecordRegion()
244    {
245        recordRegion_ = GetCurrentRegion();
246    }
247
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
267    virtual void Initialize() {};
268    void Destroy();
269
270    void ReclaimRegions(size_t cachedSize = 0);
271
272protected:
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
288class HugeObjectSpace : public Space {
289public:
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
309protected:
310    static constexpr size_t HUGE_OBJECT_BITSET_SIZE = 16;
311private:
312    EcmaList<Region> hugeNeedFreeList_ {};
313};
314
315class HugeMachineCodeSpace : public HugeObjectSpace {
316public:
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