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