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 
22 namespace panda::ecmascript {
23 #define CHECK_SOBJECT_NOT_NULL()                                                        \
24     if (object != 0) {                                                                  \
25         return object;                                                                  \
26     }
27 
28 class SharedHeap;
29 class SharedLocalSpace;
30 
31 class SharedSparseSpace : public Space {
32 public:
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 
IncreaseLiveObjectSize(size_t size)78     void IncreaseLiveObjectSize(size_t size)
79     {
80         liveObjectSize_ += size;
81     }
82 
DecreaseLiveObjectSize(size_t size)83     void DecreaseLiveObjectSize(size_t size)
84     {
85         liveObjectSize_ -= size;
86     }
87 
CommittedSizeExceed()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 
101 protected:
102     bool Expand(JSThread *thread);
103     FreeListAllocator<FreeObject> *allocator_;
104     SweepState sweepState_ = SweepState::NO_SWEEP;
105     SharedHeap *sHeap_ {nullptr};
106 
107 private:
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 
124 class SharedAppSpawnSpace : public SharedSparseSpace {
125 public:
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 
134 class SharedNonMovableSpace : public SharedSparseSpace {
135 public:
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 
142 class SharedOldSpace : public SharedSparseSpace {
143 public:
144     SharedOldSpace(SharedHeap *heap, size_t initialCapacity, size_t maximumCapacity);
145     ~SharedOldSpace() override = default;
GetMergeSize() const146     size_t GetMergeSize() const
147     {
148         return mergeSize_;
149     }
150 
IncreaseMergeSize(size_t size)151     void IncreaseMergeSize(size_t size)
152     {
153         mergeSize_ += size;
154     }
155 
ResetMergeSize()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 
168 class SharedLocalSpace : public SharedSparseSpace {
169 public:
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 
182 class SharedReadOnlySpace : public Space {
183 public:
184     SharedReadOnlySpace(SharedHeap *heap, size_t initialCapacity, size_t maximumCapacity);
185     ~SharedReadOnlySpace() override = default;
SetReadOnly()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 
ClearReadOnly()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 
211 private:
212     Mutex allocateLock_;
213     BumpPointerAllocator allocator_;
214 };
215 
216 class SharedHugeObjectSpace : public Space {
217 public:
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 
CommittedSizeExceed(size_t size = 0) const235     bool CommittedSizeExceed(size_t size = 0) const
236     {
237         return committedSize_ + size >= maximumCapacity_ + outOfMemoryOvershootSize_;
238     }
239 
240     void CheckAndTriggerLocalFullMark(JSThread *thread, size_t size);
241 private:
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