• 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 
22 #ifdef ECMASCRIPT_SUPPORT_HEAPSAMPLING
23 #define CHECK_OBJECT_AND_INC_OBJ_SIZE(size)                                             \
24     if (object != 0) {                                                                  \
25         IncreaseLiveObjectSize(size);                                                   \
26         if (!heap_->IsConcurrentFullMark() || heap_->GetJSThread()->IsReadyToMark()) {  \
27             Region::ObjectAddressToRange(object)->IncreaseAliveObject(size);            \
28         }                                                                               \
29         InvokeAllocationInspector(object, size, size);                                  \
30         return object;                                                                  \
31     }
32 #else
33 #define CHECK_OBJECT_AND_INC_OBJ_SIZE(size)                                             \
34     if (object != 0) {                                                                  \
35         IncreaseLiveObjectSize(size);                                                   \
36         if (!heap_->IsConcurrentFullMark() || heap_->GetJSThread()->IsReadyToMark()) {  \
37             Region::ObjectAddressToRange(object)->IncreaseAliveObject(size);            \
38         }                                                                               \
39         return object;                                                                  \
40     }
41 #endif
42 
43 enum class SweepState : uint8_t {
44     NO_SWEEP,
45     SWEEPING,
46     SWEPT
47 };
48 
49 namespace panda::ecmascript {
50 class LocalSpace;
51 
52 class SparseSpace : public Space {
53 public:
54     SparseSpace(Heap *heap, MemSpaceType type, size_t initialCapacity, size_t maximumCapacity);
~SparseSpace()55     ~SparseSpace() override
56     {
57         delete allocator_;
58     }
59     NO_COPY_SEMANTIC(SparseSpace);
60     NO_MOVE_SEMANTIC(SparseSpace);
61 
62     void Initialize() override;
63     void Reset();
64     void ResetTopPointer(uintptr_t top);
65 
66     uintptr_t Allocate(size_t size, bool allowGC = true);
67     bool Expand();
68 
69     // For sweeping
70     void PrepareSweeping();
71     void AsyncSweep(bool isMain);
72     void Sweep();
73 
74     bool TryFillSweptRegion();
75     // Ensure All region finished sweeping
76     bool FinishFillSweptRegion();
77 
78     void AddSweepingRegion(Region *region);
79     void SortSweepingRegion();
80     Region *GetSweepingRegionSafe();
81     void AddSweptRegionSafe(Region *region);
82     Region *GetSweptRegionSafe();
83     void FreeRegionFromSpace(Region *region);
84     Region *TryToGetSuitableSweptRegion(size_t size);
85 
86     void FreeRegion(Region *current, bool isMain = true);
87     void FreeLiveRange(Region *current, uintptr_t freeStart, uintptr_t freeEnd, bool isMain);
88 
89     void DetachFreeObjectSet(Region *region);
90 
91     void IterateOverObjects(const std::function<void(TaggedObject *object)> &objectVisitor) const;
92     void IterateOldToNewOverObjects(
93         const std::function<void(TaggedObject *object, JSTaggedValue value)> &visitor) const;
94 
95     size_t GetHeapObjectSize() const;
96 
97     void IncreaseAllocatedSize(size_t size);
98 
IncreaseLiveObjectSize(size_t size)99     void IncreaseLiveObjectSize(size_t size)
100     {
101         liveObjectSize_ += size;
102     }
103 
DecreaseLiveObjectSize(size_t size)104     void DecreaseLiveObjectSize(size_t size)
105     {
106         liveObjectSize_ -= size;
107     }
108 
SetOvershootSize(size_t size)109     void SetOvershootSize(size_t size)
110     {
111         overshootSize_ = size;
112     }
113 
GetOvershootSize()114     size_t GetOvershootSize()
115     {
116         return overshootSize_;
117     }
118 
AdjustOvershootSize()119     void AdjustOvershootSize()
120     {
121         if (overshootSize_ > 0 && maximumCapacity_ > committedSize_) {
122             size_t size = maximumCapacity_ - committedSize_;
123             overshootSize_ = overshootSize_ > size ? overshootSize_ - size : 0;
124         }
125     }
126 
CommittedSizeExceed()127     bool CommittedSizeExceed() const
128     {
129         return committedSize_ >= maximumCapacity_ + overshootSize_ + outOfMemoryOvershootSize_;
130     }
131 
132     size_t GetTotalAllocatedSize() const;
133 
134     void InvokeAllocationInspector(Address object, size_t size, size_t alignedSize);
135 
136 protected:
137     FreeListAllocator *allocator_;
138     SweepState sweepState_ = SweepState::NO_SWEEP;
139 
140 private:
141     // For sweeping
142     uintptr_t AllocateAfterSweepingCompleted(size_t size);
143 
144     Mutex lock_;
145     std::vector<Region *> sweepingList_;
146     std::vector<Region *> sweptList_;
147     size_t liveObjectSize_ {0};
148     size_t overshootSize_ {0};
149 };
150 
151 class OldSpace : public SparseSpace {
152 public:
153     OldSpace(Heap *heap, size_t initialCapacity, size_t maximumCapacity);
154     ~OldSpace() override = default;
155     NO_COPY_SEMANTIC(OldSpace);
156     NO_MOVE_SEMANTIC(OldSpace);
157 
158     Region *TrySweepToGetSuitableRegion(size_t size);
159     Region *TryToGetExclusiveRegion(size_t size);
160 
161     // CSet
162     void SelectCSet();
163     void CheckRegionSize();
164     void RevertCSet();
165     void ReclaimCSet();
166 
GetSelectedRegionNumber()167     unsigned long GetSelectedRegionNumber() const
168     {
169         return std::max(committedSize_ / PARTIAL_GC_MAX_COLLECT_REGION_RATE, PARTIAL_GC_INITIAL_COLLECT_REGION_SIZE);
170     }
171 
GetMergeSize()172     size_t GetMergeSize() const
173     {
174         return mergeSize_;
175     }
176 
IncreaseMergeSize(size_t size)177     void IncreaseMergeSize(size_t size)
178     {
179         mergeSize_ += size;
180     }
181 
ResetMergeSize()182     void ResetMergeSize()
183     {
184         mergeSize_ = 0;
185     }
186 
187     template<class Callback>
EnumerateCollectRegionSet(const Callback & cb)188     void EnumerateCollectRegionSet(const Callback &cb) const
189     {
190         for (Region *current : collectRegionSet_) {
191             if (current != nullptr) {
192                 cb(current);
193             }
194         }
195     }
196 
197     void Merge(LocalSpace *localSpace);
198 private:
199     static constexpr int64_t PARTIAL_GC_MAX_EVACUATION_SIZE_FOREGROUND = 2_MB;
200     static constexpr int64_t PARTIAL_GC_MAX_EVACUATION_SIZE_BACKGROUND = 6_MB;
201     static constexpr unsigned long long PARTIAL_GC_MAX_COLLECT_REGION_RATE = 2_MB;
202     static constexpr unsigned long long PARTIAL_GC_INITIAL_COLLECT_REGION_SIZE = 24;
203     static constexpr size_t PARTIAL_GC_MIN_COLLECT_REGION_SIZE = 5;
204 
205     CVector<Region *> collectRegionSet_;
206     Mutex lock_;
207     size_t mergeSize_ {0};
208 };
209 
210 class NonMovableSpace : public SparseSpace {
211 public:
212     NonMovableSpace(Heap *heap, size_t initialCapacity, size_t maximumCapacity);
213     ~NonMovableSpace() override = default;
214     NO_COPY_SEMANTIC(NonMovableSpace);
215     NO_MOVE_SEMANTIC(NonMovableSpace);
216 
217     uintptr_t  CheckAndAllocate(size_t size);
218 };
219 
220 class AppSpawnSpace : public SparseSpace {
221 public:
222     AppSpawnSpace(Heap *heap, size_t initialCapacity);
223     ~AppSpawnSpace() override = default;
224     NO_COPY_SEMANTIC(AppSpawnSpace);
225     NO_MOVE_SEMANTIC(AppSpawnSpace);
226 
227     void IterateOverMarkedObjects(const std::function<void(TaggedObject *object)> &visitor) const;
228 };
229 
230 class LocalSpace : public SparseSpace {
231 public:
232     LocalSpace() = delete;
233     LocalSpace(Heap *heap, size_t initialCapacity, size_t maximumCapacity);
234     ~LocalSpace() override = default;
235     NO_COPY_SEMANTIC(LocalSpace);
236     NO_MOVE_SEMANTIC(LocalSpace);
237 
238     uintptr_t Allocate(size_t size, bool isExpand = true);
239     bool AddRegionToList(Region *region);
240     void FreeBumpPoint();
241     void Stop();
242 };
243 
244 class MachineCodeSpace : public SparseSpace {
245 public:
246     MachineCodeSpace(Heap *heap, size_t initialCapacity, size_t maximumCapacity);
247     ~MachineCodeSpace() override = default;
248     NO_COPY_SEMANTIC(MachineCodeSpace);
249     NO_MOVE_SEMANTIC(MachineCodeSpace);  // Note: Expand() left for define
250 };
251 }  // namespace panda::ecmascript
252 #endif  // ECMASCRIPT_MEM_SPARSE_SPACE_H
253