1/*
2 * Copyright (c) 2024 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_SHARED_SHARED_SPACE_H
17#define ECMASCRIPT_MEM_SHARED_SHARED_SPACE_H
18
19#include "ecmascript/mem/mem_common.h"
20#include "ecmascript/mem/sparse_space.h"
21
22namespace panda::ecmascript {
23#define CHECK_SOBJECT_NOT_NULL()                                                        \
24    if (object != 0) {                                                                  \
25        return object;                                                                  \
26    }
27
28class SharedHeap;
29class SharedLocalSpace;
30
31class SharedSparseSpace : public Space {
32public:
33    SharedSparseSpace(SharedHeap *heap, MemSpaceType type, size_t initialCapacity, size_t maximumCapacity);
34    ~SharedSparseSpace() override
35    {
36        delete allocator_;
37    }
38    NO_COPY_SEMANTIC(SharedSparseSpace);
39    NO_MOVE_SEMANTIC(SharedSparseSpace);
40
41    void Reset();
42
43    uintptr_t AllocateWithoutGC(JSThread *thread, size_t size);
44
45    uintptr_t Allocate(JSThread *thread, size_t size, bool allowGC = true);
46    uintptr_t TryAllocateAndExpand(JSThread *thread, size_t size, bool expand);
47
48    // For work deserialize
49    void ResetTopPointer(uintptr_t top);
50    uintptr_t AllocateNoGCAndExpand(JSThread *thread, size_t size);
51    Region *AllocateDeserializeRegion(JSThread *thread);
52    void MergeDeserializeAllocateRegions(const std::vector<Region *> &allocateRegions);
53
54    // For sweeping
55    void PrepareSweeping();
56    void AsyncSweep(bool isMain);
57    void Sweep();
58
59    bool TryFillSweptRegion();
60    // Ensure All region finished sweeping
61    bool FinishFillSweptRegion();
62
63    void AddSweepingRegion(Region *region);
64    void SortSweepingRegion();
65    Region *GetSweepingRegionSafe();
66    void AddSweptRegionSafe(Region *region);
67    Region *GetSweptRegionSafe();
68
69    void FreeRegion(Region *current, bool isMain = true);
70    void FreeLiveRange(uintptr_t freeStart, uintptr_t freeEnd, bool isMain);
71
72    void IterateOverObjects(const std::function<void(TaggedObject *object)> &objectVisitor) const;
73
74    size_t GetHeapObjectSize() const;
75
76    void IncreaseAllocatedSize(size_t size);
77
78    void IncreaseLiveObjectSize(size_t size)
79    {
80        liveObjectSize_ += size;
81    }
82
83    void DecreaseLiveObjectSize(size_t size)
84    {
85        liveObjectSize_ -= size;
86    }
87
88    bool CommittedSizeExceed()
89    {
90        return committedSize_ >= maximumCapacity_ + outOfMemoryOvershootSize_;
91    }
92
93    void CheckAndTriggerLocalFullMark();
94
95    size_t GetTotalAllocatedSize() const;
96
97    void InvokeAllocationInspector(Address object, size_t size, size_t alignedSize);
98
99    void DetachFreeObjectSet(Region *region);
100
101protected:
102    bool Expand(JSThread *thread);
103    FreeListAllocator<FreeObject> *allocator_;
104    SweepState sweepState_ = SweepState::NO_SWEEP;
105    SharedHeap *sHeap_ {nullptr};
106
107private:
108    static constexpr double LIVE_OBJECT_SIZE_RATIO = 0.8;
109
110    uintptr_t AllocateWithExpand(JSThread *thread, size_t size);
111    uintptr_t TryAllocate(JSThread *thread, size_t size);
112    // For sweeping
113    uintptr_t AllocateAfterSweepingCompleted(JSThread *thread, size_t size);
114    void IncAllocSObjectSize(uintptr_t object, size_t size);
115
116    Mutex lock_;
117    Mutex allocateLock_;
118    std::vector<Region *> sweepingList_;
119    std::vector<Region *> sweptList_;
120    size_t liveObjectSize_ {0};
121    size_t triggerLocalFullMarkLimit_ {0};
122};
123
124class SharedAppSpawnSpace : public SharedSparseSpace {
125public:
126    SharedAppSpawnSpace(SharedHeap *heap, size_t initialCapacity);
127    ~SharedAppSpawnSpace() override = default;
128    NO_COPY_SEMANTIC(SharedAppSpawnSpace);
129    NO_MOVE_SEMANTIC(SharedAppSpawnSpace);
130
131    void IterateOverMarkedObjects(const std::function<void(TaggedObject *object)> &visitor) const;
132};
133
134class SharedNonMovableSpace : public SharedSparseSpace {
135public:
136    SharedNonMovableSpace(SharedHeap *heap, size_t initialCapacity, size_t maximumCapacity);
137    ~SharedNonMovableSpace() override = default;
138    NO_COPY_SEMANTIC(SharedNonMovableSpace);
139    NO_MOVE_SEMANTIC(SharedNonMovableSpace);
140};
141
142class SharedOldSpace : public SharedSparseSpace {
143public:
144    SharedOldSpace(SharedHeap *heap, size_t initialCapacity, size_t maximumCapacity);
145    ~SharedOldSpace() override = default;
146    size_t GetMergeSize() const
147    {
148        return mergeSize_;
149    }
150
151    void IncreaseMergeSize(size_t size)
152    {
153        mergeSize_ += size;
154    }
155
156    void ResetMergeSize()
157    {
158        mergeSize_ = 0;
159    }
160
161    void Merge(SharedLocalSpace *localSpace);
162    NO_COPY_SEMANTIC(SharedOldSpace);
163    NO_MOVE_SEMANTIC(SharedOldSpace);
164    Mutex lock_;
165    size_t mergeSize_ {0};
166};
167
168class SharedLocalSpace : public SharedSparseSpace {
169public:
170    SharedLocalSpace() = delete;
171    SharedLocalSpace(SharedHeap *heap, size_t initialCapacity, size_t maximumCapacity);
172    ~SharedLocalSpace() override = default;
173    NO_COPY_SEMANTIC(SharedLocalSpace);
174    NO_MOVE_SEMANTIC(SharedLocalSpace);
175
176    uintptr_t Allocate(size_t size, bool isExpand = true);
177    bool AddRegionToList(Region *region);
178    void FreeBumpPoint();
179    void Stop();
180};
181
182class SharedReadOnlySpace : public Space {
183public:
184    SharedReadOnlySpace(SharedHeap *heap, size_t initialCapacity, size_t maximumCapacity);
185    ~SharedReadOnlySpace() override = default;
186    void SetReadOnly()
187    {
188        auto cb = [](Region *region) {
189            region->SetReadOnlyAndMarked();
190        };
191        EnumerateRegions(cb);
192    }
193
194    void IterateOverObjects(const std::function<void(TaggedObject *object)> &visitor) const;
195
196    void ClearReadOnly()
197    {
198        auto cb = [](Region *region) {
199            region->ClearReadOnly();
200        };
201        EnumerateRegions(cb);
202    }
203
204    bool Expand(JSThread *thread);
205
206    uintptr_t Allocate(JSThread *thread, size_t size);
207
208    NO_COPY_SEMANTIC(SharedReadOnlySpace);
209    NO_MOVE_SEMANTIC(SharedReadOnlySpace);
210
211private:
212    Mutex allocateLock_;
213    BumpPointerAllocator allocator_;
214};
215
216class SharedHugeObjectSpace : public Space {
217public:
218    SharedHugeObjectSpace(BaseHeap *heap, HeapRegionAllocator *regionAllocator, size_t initialCapacity,
219                    size_t maximumCapacity);
220    ~SharedHugeObjectSpace() override = default;
221    NO_COPY_SEMANTIC(SharedHugeObjectSpace);
222    NO_MOVE_SEMANTIC(SharedHugeObjectSpace);
223    // Sometimes it is unsafe to checkSafePoint here, e.g. in deserialize, if do checkSafePoint JSThread may be
224    // suspended and then do SharedGC, which will free some regions in SharedHeap that are allocated at the beginning
225    // of deserializing for further object allocating, but no object has been allocated on at this moment.
226    uintptr_t Allocate(JSThread *thread, size_t objectSize, AllocateEventType allocType = AllocateEventType::NORMAL);
227    void Sweep();
228    size_t GetHeapObjectSize() const;
229    void IterateOverObjects(const std::function<void(TaggedObject *object)> &objectVisitor) const;
230
231    void ReclaimHugeRegion();
232
233    void InvokeAllocationInspector(Address object, size_t objectSize);
234
235    bool CommittedSizeExceed(size_t size = 0) const
236    {
237        return committedSize_ + size >= maximumCapacity_ + outOfMemoryOvershootSize_;
238    }
239
240    void CheckAndTriggerLocalFullMark(JSThread *thread, size_t size);
241private:
242    static constexpr size_t HUGE_OBJECT_BITSET_SIZE = 16;
243    static constexpr double HUGE_OBJECT_SIZE_RATIO = 0.8;
244
245    size_t triggerLocalFullMarkLimit_ {0};
246    EcmaList<Region> hugeNeedFreeList_ {};
247    Mutex allocateLock_;
248};
249}  // namespace panda::ecmascript
250#endif  // ECMASCRIPT_MEM_SHARED_SHARED_SPACE_H
251