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