• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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_SPARSE_SPACE_H
17 #define ECMASCRIPT_MEM_SPARSE_SPACE_H
18 
19 #include "ecmascript/mem/space-inl.h"
20 #include "ecmascript/mem/mem_common.h"
21 #include "ecmascript/mem/jit_fort.h"
22 
23 #ifdef ECMASCRIPT_SUPPORT_HEAPSAMPLING
24 #define CHECK_OBJECT_AND_INC_OBJ_SIZE(size)                                             \
25     if (object != 0) {                                                                  \
26         IncreaseLiveObjectSize(size);                                                   \
27         if (!heap_->IsConcurrentFullMark() || heap_->IsReadyToConcurrentMark()) {       \
28             Region::ObjectAddressToRange(object)->IncreaseAliveObject(size);            \
29         }                                                                               \
30         InvokeAllocationInspector(object, size, size);                                  \
31         return object;                                                                  \
32     }
33 #else
34 #define CHECK_OBJECT_AND_INC_OBJ_SIZE(size)                                             \
35     if (object != 0) {                                                                  \
36         IncreaseLiveObjectSize(size);                                                   \
37         if (!heap_->IsConcurrentFullMark() || heap_->IsReadyToConcurrentMark()) {       \
38             Region::ObjectAddressToRange(object)->IncreaseAliveObject(size);            \
39         }                                                                               \
40         return object;                                                                  \
41     }
42 #endif
43 
44 enum class SweepState : uint8_t {
45     NO_SWEEP,
46     SWEEPING,
47     SWEPT
48 };
49 
50 namespace panda::ecmascript {
51 class LocalSpace;
52 
53 class SparseSpace : public Space {
54 public:
55     SparseSpace(Heap *heap, MemSpaceType type, size_t initialCapacity, size_t maximumCapacity);
~SparseSpace()56     ~SparseSpace() override
57     {
58         delete allocator_;
59     }
60     NO_COPY_SEMANTIC(SparseSpace);
61     NO_MOVE_SEMANTIC(SparseSpace);
62 
63     void Initialize() override;
64     void Reset();
65     void ResetTopPointer(uintptr_t top);
66 
67     uintptr_t Allocate(size_t size, bool allowGC = true);
68     bool Expand();
69 
70     // For sweeping
71     void PrepareSweeping();
72     void Sweep();
73     virtual void AsyncSweep(bool isMain);
74 
75     bool TryFillSweptRegion();
76     // Ensure All region finished sweeping
77     bool FinishFillSweptRegion();
78 
79     void AddSweepingRegion(Region *region);
80     void SortSweepingRegion();
81     Region *GetSweepingRegionSafe();
82     void AddSweptRegionSafe(Region *region);
83     Region *GetSweptRegionSafe();
84     void FreeRegionFromSpace(Region *region);
85     Region *TryToGetSuitableSweptRegion(size_t size);
86 
87     virtual void FreeRegion(Region *current, bool isMain = true);
88     void FreeLiveRange(Region *current, uintptr_t freeStart, uintptr_t freeEnd, bool isMain);
89 
90     void DetachFreeObjectSet(Region *region);
91 
92     void IterateOverObjects(const std::function<void(TaggedObject *object)> &objectVisitor) const;
93     void IterateOldToNewOverObjects(
94         const std::function<void(TaggedObject *object, JSTaggedValue value)> &visitor) const;
95 
96     size_t GetHeapObjectSize() const;
97 
98     void IncreaseAllocatedSize(size_t size);
99 
IncreaseLiveObjectSize(size_t size)100     void IncreaseLiveObjectSize(size_t size)
101     {
102         liveObjectSize_ += size;
103     }
104 
DecreaseLiveObjectSize(size_t size)105     void DecreaseLiveObjectSize(size_t size)
106     {
107         liveObjectSize_ -= size;
108     }
109 
SetOvershootSize(size_t size)110     void SetOvershootSize(size_t size)
111     {
112         overshootSize_ = size;
113     }
114 
IncreaseOvershootSize(size_t size)115     void IncreaseOvershootSize(size_t size)
116     {
117         overshootSize_ += size;
118     }
119 
GetOvershootSize()120     size_t GetOvershootSize() const
121     {
122         return overshootSize_;
123     }
124 
AdjustOvershootSize()125     void AdjustOvershootSize()
126     {
127         if (overshootSize_ > 0 && maximumCapacity_ > committedSize_) {
128             size_t size = maximumCapacity_ - committedSize_;
129             overshootSize_ = overshootSize_ > size ? overshootSize_ - size : 0;
130         }
131     }
132 
CommittedSizeExceed()133     bool CommittedSizeExceed() const
134     {
135         return committedSize_ >= maximumCapacity_ + overshootSize_ + outOfMemoryOvershootSize_;
136     }
137 
138     size_t GetTotalAllocatedSize() const;
139 
140     void InvokeAllocationInspector(Address object, size_t size, size_t alignedSize);
141 
142 protected:
143     FreeListAllocator<FreeObject> *allocator_;
144     SweepState sweepState_ = SweepState::NO_SWEEP;
145     Heap *localHeap_ {nullptr};
146     size_t liveObjectSize_ {0};
147     uintptr_t AllocateAfterSweepingCompleted(size_t size);
148 
149 private:
150     Mutex lock_;
151     std::vector<Region *> sweepingList_;
152     std::vector<Region *> sweptList_;
153     size_t overshootSize_ {0};
154 };
155 
156 class OldSpace : public SparseSpace {
157 public:
158     OldSpace(Heap *heap, size_t initialCapacity, size_t maximumCapacity);
159     ~OldSpace() override = default;
160     NO_COPY_SEMANTIC(OldSpace);
161     NO_MOVE_SEMANTIC(OldSpace);
162 
163     Region *TrySweepToGetSuitableRegion(size_t size);
164     Region *TryToGetExclusiveRegion(size_t size);
165 
166     // CSet
167     void SelectCSet();
168     void CheckRegionSize();
169     void RevertCSet();
170     void ReclaimCSet();
171 
GetSelectedRegionNumber()172     unsigned long GetSelectedRegionNumber() const
173     {
174         return std::max(committedSize_ / PARTIAL_GC_MAX_COLLECT_REGION_RATE, PARTIAL_GC_INITIAL_COLLECT_REGION_SIZE);
175     }
176 
GetMergeSize()177     size_t GetMergeSize() const
178     {
179         return mergeSize_;
180     }
181 
IncreaseMergeSize(size_t size)182     void IncreaseMergeSize(size_t size)
183     {
184         mergeSize_ += size;
185     }
186 
ResetMergeSize()187     void ResetMergeSize()
188     {
189         mergeSize_ = 0;
190     }
191 
IncreaseCommittedOverSizeLimit(size_t size)192     void IncreaseCommittedOverSizeLimit(size_t size)
193     {
194         committedOverSizeLimit_ += size;
195     }
196 
ResetCommittedOverSizeLimit()197     void ResetCommittedOverSizeLimit()
198     {
199         DecreaseOutOfMemoryOvershootSize(committedOverSizeLimit_);
200         committedOverSizeLimit_ = 0;
201     }
202 
203     template<class Callback>
EnumerateCollectRegionSet(const Callback & cb)204     void EnumerateCollectRegionSet(const Callback &cb) const
205     {
206         for (Region *current : collectRegionSet_) {
207             if (current != nullptr) {
208                 cb(current);
209             }
210         }
211     }
212 
GetCollectSetRegionCount()213     size_t GetCollectSetRegionCount() const
214     {
215         return collectRegionSet_.size();
216     }
217 
218     void Merge(LocalSpace *localSpace);
219 private:
220     static constexpr int64_t PARTIAL_GC_MAX_EVACUATION_SIZE_FOREGROUND = 2_MB;
221     static constexpr int64_t PARTIAL_GC_MAX_EVACUATION_SIZE_BACKGROUND = 6_MB;
222     static constexpr unsigned long long PARTIAL_GC_MAX_COLLECT_REGION_RATE = 2_MB;
223     static constexpr unsigned long long PARTIAL_GC_INITIAL_COLLECT_REGION_SIZE = 24;
224     static constexpr size_t PARTIAL_GC_MIN_COLLECT_REGION_SIZE = 5;
225 
226     CVector<Region *> collectRegionSet_;
227     Mutex lock_;
228     size_t mergeSize_ {0};
229     size_t committedOverSizeLimit_ {0};
230 };
231 
232 class NonMovableSpace : public SparseSpace {
233 public:
234     NonMovableSpace(Heap *heap, size_t initialCapacity, size_t maximumCapacity);
235     ~NonMovableSpace() override = default;
236     NO_COPY_SEMANTIC(NonMovableSpace);
237     NO_MOVE_SEMANTIC(NonMovableSpace);
238 
239     uintptr_t  CheckAndAllocate(size_t size);
240 };
241 
242 class AppSpawnSpace : public SparseSpace {
243 public:
244     AppSpawnSpace(Heap *heap, size_t initialCapacity);
245     ~AppSpawnSpace() override = default;
246     NO_COPY_SEMANTIC(AppSpawnSpace);
247     NO_MOVE_SEMANTIC(AppSpawnSpace);
248 
249     void IterateOverMarkedObjects(const std::function<void(TaggedObject *object)> &visitor) const;
250 };
251 
252 class LocalSpace : public SparseSpace {
253 public:
254     LocalSpace() = delete;
255     LocalSpace(Heap *heap, size_t initialCapacity, size_t maximumCapacity);
256     ~LocalSpace() override = default;
257     NO_COPY_SEMANTIC(LocalSpace);
258     NO_MOVE_SEMANTIC(LocalSpace);
259 
260     uintptr_t Allocate(size_t size, bool isExpand = true);
261     bool AddRegionToList(Region *region);
262     void FreeBumpPoint();
263     void Stop();
264 };
265 
266 class MachineCode;
267 struct MachineCodeDesc;
268 class MachineCodeSpace : public SparseSpace {
269 public:
270     MachineCodeSpace(Heap *heap, size_t initialCapacity, size_t maximumCapacity);
271     ~MachineCodeSpace() override;
272     NO_COPY_SEMANTIC(MachineCodeSpace);
273     NO_MOVE_SEMANTIC(MachineCodeSpace);  // Note: Expand() left for define
274     uintptr_t GetMachineCodeObject(uintptr_t pc);
275     size_t CheckMachineCodeObject(uintptr_t curPtr, uintptr_t &machineCode, uintptr_t pc);
276     void AsyncSweep(bool isMain) override;
277     void FreeRegion(Region *current, bool isMain = true) override;
278     uintptr_t Allocate(size_t size, bool allowGC = true);
279     uintptr_t Allocate(size_t size, MachineCodeDesc *desc, bool allowGC = true);
280     inline void RecordLiveJitCode(MachineCode *obj);
281     uintptr_t PUBLIC_API JitFortAllocate(MachineCodeDesc *desc);
282 
IsSweeping()283     inline bool IsSweeping()
284     {
285         return sweepState_ == SweepState::SWEEPING ;
286     }
287 
GetJitFort()288     inline JitFort *GetJitFort()
289     {
290         return jitFort_;
291     }
292 
InJitFortRange(uintptr_t address)293     bool InJitFortRange(uintptr_t address) const
294     {
295         if (jitFort_) {
296             return jitFort_->InRange(address);
297         }
298         return false;
299     }
300 
UpdateFortSpace()301     void UpdateFortSpace()
302     {
303         if (jitFort_) {
304             jitFort_->UpdateFreeSpace();
305         }
306     }
307 
308 private:
309     JitFort *jitFort_ {nullptr};
310     Mutex asyncSweepMutex_;
311     friend class Heap;
312     friend class ConcurrentSweeper;
313 };
314 }  // namespace panda::ecmascript
315 #endif  // ECMASCRIPT_MEM_SPARSE_SPACE_H
316