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 44enum class SweepState : uint8_t { 45 NO_SWEEP, 46 SWEEPING, 47 SWEPT 48}; 49 50namespace panda::ecmascript { 51class LocalSpace; 52 53class SparseSpace : public Space { 54public: 55 SparseSpace(Heap *heap, MemSpaceType type, size_t initialCapacity, size_t maximumCapacity); 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 virtual void PrepareSweeping(); 72 virtual 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 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 100 void IncreaseLiveObjectSize(size_t size) 101 { 102 liveObjectSize_ += size; 103 } 104 105 void DecreaseLiveObjectSize(size_t size) 106 { 107 liveObjectSize_ -= size; 108 } 109 110 void SetOvershootSize(size_t size) 111 { 112 overshootSize_ = size; 113 } 114 115 void IncreaseOvershootSize(size_t size) 116 { 117 overshootSize_ += size; 118 } 119 120 size_t GetOvershootSize() const 121 { 122 return overshootSize_; 123 } 124 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 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 142protected: 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 149private: 150 Mutex lock_; 151 std::vector<Region *> sweepingList_; 152 std::vector<Region *> sweptList_; 153 size_t overshootSize_ {0}; 154}; 155 156class OldSpace : public SparseSpace { 157public: 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 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 177 size_t GetMergeSize() const 178 { 179 return mergeSize_; 180 } 181 182 void IncreaseMergeSize(size_t size) 183 { 184 mergeSize_ += size; 185 } 186 187 void ResetMergeSize() 188 { 189 mergeSize_ = 0; 190 } 191 192 void IncreaseCommittedOverSizeLimit(size_t size) 193 { 194 committedOverSizeLimit_ += size; 195 } 196 197 void ResetCommittedOverSizeLimit() 198 { 199 DecreaseOutOfMemoryOvershootSize(committedOverSizeLimit_); 200 committedOverSizeLimit_ = 0; 201 } 202 203 template<class Callback> 204 void EnumerateCollectRegionSet(const Callback &cb) const 205 { 206 for (Region *current : collectRegionSet_) { 207 if (current != nullptr) { 208 cb(current); 209 } 210 } 211 } 212 213 size_t GetCollectSetRegionCount() const 214 { 215 return collectRegionSet_.size(); 216 } 217 218 void Merge(LocalSpace *localSpace); 219private: 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 232class NonMovableSpace : public SparseSpace { 233public: 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 242class AppSpawnSpace : public SparseSpace { 243public: 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 252class LocalSpace : public SparseSpace { 253public: 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 266class MachineCode; 267struct MachineCodeDesc; 268class MachineCodeSpace : public SparseSpace { 269public: 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 Sweep() override; 278 void PrepareSweeping() override; 279 uintptr_t Allocate(size_t size, bool allowGC = true); 280 uintptr_t Allocate(size_t size, MachineCodeDesc *desc, bool allowGC = true); 281 uintptr_t PUBLIC_API JitFortAllocate(MachineCodeDesc *desc); 282 283 inline void MarkJitFortMemAlive(MachineCode *obj) 284 { 285 if (jitFort_) { 286 jitFort_->MarkJitFortMemAlive(obj); 287 } 288 } 289 290 inline void MarkJitFortMemInstalled(MachineCode *obj) 291 { 292 if (jitFort_) { 293 jitFort_->MarkJitFortMemInstalled(obj); 294 } 295 } 296 297 inline bool IsSweeping() 298 { 299 return sweepState_ == SweepState::SWEEPING ; 300 } 301 302 inline JitFort *GetJitFort() 303 { 304 return jitFort_; 305 } 306 307 bool InJitFortRange(uintptr_t address) const 308 { 309 if (jitFort_) { 310 return jitFort_->InRange(address); 311 } 312 return false; 313 } 314 315private: 316 JitFort *jitFort_ {nullptr}; 317 Mutex asyncSweepMutex_; 318 friend class Heap; 319 friend class ConcurrentSweeper; 320}; 321} // namespace panda::ecmascript 322#endif // ECMASCRIPT_MEM_SPARSE_SPACE_H 323