• 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 #include "ecmascript/mem/linear_space.h"
17 
18 #include "ecmascript/free_object.h"
19 #include "ecmascript/js_hclass-inl.h"
20 #include "ecmascript/mem/allocator-inl.h"
21 #include "ecmascript/mem/heap.h"
22 #include "ecmascript/mem/remembered_set.h"
23 
24 namespace panda::ecmascript {
LinearSpace(Heap * heap,MemSpaceType type,size_t initialCapacity,size_t maximumCapacity)25 LinearSpace::LinearSpace(Heap *heap, MemSpaceType type, size_t initialCapacity, size_t maximumCapacity)
26     : Space(heap, type, initialCapacity, maximumCapacity), waterLine_(0)
27 {
28 }
29 
Allocate(size_t size,bool isPromoted)30 uintptr_t LinearSpace::Allocate(size_t size, bool isPromoted)
31 {
32     auto object = allocator_->Allocate(size);
33     if (object != 0) {
34         return object;
35     }
36     if (Expand(isPromoted)) {
37         if (!isPromoted) {
38             heap_->TryTriggerConcurrentMarking();
39         }
40         object = allocator_->Allocate(size);
41     } else if (heap_->GetJSThread()->IsMarking()) {
42         // Temporary adjust semi space capacity
43         overShootSize_ = SEMI_SPACE_OVERSHOOT_SIZE;
44         if (Expand(isPromoted)) {
45             object = allocator_->Allocate(size);
46         }
47     }
48     return object;
49 }
50 
Expand(bool isPromoted)51 bool LinearSpace::Expand(bool isPromoted)
52 {
53     if (committedSize_ >= maximumCapacity_ + overShootSize_) {
54         return false;
55     }
56 
57     uintptr_t top = allocator_->GetTop();
58     auto currentRegion = GetCurrentRegion();
59     if (currentRegion != nullptr) {
60         if (!isPromoted) {
61             if (currentRegion->HasAgeMark()) {
62                 allocateAfterLastGC_ +=
63                     currentRegion->GetAllocatedBytes(top) - currentRegion->GetAllocatedBytes(waterLine_);
64             } else {
65                 allocateAfterLastGC_ += currentRegion->GetAllocatedBytes(top);
66             }
67         } else {
68             // For GC
69             survivalObjectSize_ += currentRegion->GetAllocatedBytes(top);
70         }
71         currentRegion->SetHighWaterMark(top);
72     }
73     Region *region = heapRegionAllocator_->AllocateAlignedRegion(this, DEFAULT_REGION_SIZE);
74     region->SetFlag(GetRegionFlag());
75     allocator_->Reset(region->GetBegin(), region->GetEnd());
76 
77     AddRegion(region);
78     return true;
79 }
80 
Stop()81 void LinearSpace::Stop()
82 {
83     if (GetCurrentRegion() != nullptr) {
84         GetCurrentRegion()->SetHighWaterMark(allocator_->GetTop());
85     }
86 }
87 
SemiSpace(Heap * heap,size_t initialCapacity,size_t maximumCapacity)88 SemiSpace::SemiSpace(Heap *heap, size_t initialCapacity, size_t maximumCapacity)
89     : LinearSpace(heap, MemSpaceType::SEMI_SPACE, initialCapacity, maximumCapacity)
90 {
91     allocator_ = new BumpPointerAllocator();
92 }
93 
Initialize()94 void SemiSpace::Initialize()
95 {
96     Region *region = heapRegionAllocator_->AllocateAlignedRegion(this, DEFAULT_REGION_SIZE);
97     region->SetFlag(GetRegionFlag());
98     AddRegion(region);
99     allocator_->Reset(region->GetBegin(), region->GetEnd());
100 }
101 
Restart()102 void SemiSpace::Restart()
103 {
104     overShootSize_ = 0;
105     survivalObjectSize_ = 0;
106     allocateAfterLastGC_ = 0;
107     Initialize();
108 }
109 
AllocateSync(size_t size)110 uintptr_t SemiSpace::AllocateSync(size_t size)
111 {
112     os::memory::LockHolder lock(lock_);
113     return Allocate(size, true);
114 }
115 
SwapRegion(Region * region,SemiSpace * fromSpace)116 bool SemiSpace::SwapRegion(Region *region, SemiSpace *fromSpace)
117 {
118     os::memory::LockHolder lock(lock_);
119     if (committedSize_ + region->GetCapacity() > maximumCapacity_ + overShootSize_) {
120         return false;
121     }
122     fromSpace->RemoveRegion(region);
123 
124     region->SetFlag(RegionFlags::IS_IN_NEW_TO_NEW_SET);
125     region->SetSpace(this);
126 
127     regionList_.AddNodeToFront(region);
128     IncrementCommitted(region->GetCapacity());
129     IncrementObjectSize(region->GetSize());
130     survivalObjectSize_ += region->GetAllocatedBytes();
131     return true;
132 }
133 
SetWaterLine()134 void SemiSpace::SetWaterLine()
135 {
136     waterLine_ = allocator_->GetTop();
137     allocateAfterLastGC_ = 0;
138     Region *last = GetCurrentRegion();
139     if (last != nullptr) {
140         last->SetFlag(RegionFlags::HAS_AGE_MARK);
141 
142         EnumerateRegions([&last](Region *current) {
143             if (current != last) {
144                 current->SetFlag(RegionFlags::BELOW_AGE_MARK);
145             }
146         });
147         survivalObjectSize_ += last->GetAllocatedBytes(waterLine_);
148     }
149 }
150 
GetHeapObjectSize() const151 size_t SemiSpace::GetHeapObjectSize() const
152 {
153     return survivalObjectSize_ + allocateAfterLastGC_;
154 }
155 
GetSurvivalObjectSize() const156 size_t SemiSpace::GetSurvivalObjectSize() const
157 {
158     return survivalObjectSize_;
159 }
160 
SetOverShootSize(size_t size)161 void SemiSpace::SetOverShootSize(size_t size)
162 {
163     overShootSize_ = size;
164 }
165 
AdjustCapacity(size_t allocatedSizeSinceGC)166 bool SemiSpace::AdjustCapacity(size_t allocatedSizeSinceGC)
167 {
168     static constexpr double growObjectSurvivalRate = 0.8;
169     static constexpr double shrinkObjectSurvivalRate = 0.2;
170     static constexpr int growingFactor = 2;
171     if (allocatedSizeSinceGC <= maximumCapacity_ * growObjectSurvivalRate / growingFactor) {
172         return false;
173     }
174     double curObjectSurvivalRate = static_cast<double>(survivalObjectSize_) / allocatedSizeSinceGC;
175     if (curObjectSurvivalRate > growObjectSurvivalRate) {
176         size_t maxCapacity = heap_->GetEcmaVM()->GetJSOptions().MaxSemiSpaceCapacity();
177         if (GetMaximumCapacity() >= maxCapacity) {
178             return false;
179         }
180         size_t newCapacity = GetMaximumCapacity() * growingFactor;
181         SetMaximumCapacity(std::min(newCapacity, maxCapacity));
182         return true;
183     } else if (curObjectSurvivalRate < shrinkObjectSurvivalRate) {
184         if (GetMaximumCapacity() <= initialCapacity_) {
185             return false;
186         }
187         size_t newCapacity = GetMaximumCapacity() / growingFactor;
188         SetMaximumCapacity(std::max(newCapacity, initialCapacity_));
189         return true;
190     }
191     return false;
192 }
193 
IterateOverObjects(const std::function<void (TaggedObject * object)> & visitor) const194 void SemiSpace::IterateOverObjects(const std::function<void(TaggedObject *object)> &visitor) const
195 {
196     auto current = GetCurrentRegion();
197     EnumerateRegions([&](Region *region) {
198         auto curPtr = region->GetBegin();
199         uintptr_t endPtr;
200         if (region == current) {
201             auto top = allocator_->GetTop();
202             endPtr = curPtr + region->GetAllocatedBytes(top);
203         } else {
204             endPtr = curPtr + region->GetAllocatedBytes();
205         }
206 
207         size_t objSize;
208         while (curPtr < endPtr) {
209             auto freeObject = FreeObject::Cast(curPtr);
210             if (!freeObject->IsFreeObject()) {
211                 auto obj = reinterpret_cast<TaggedObject *>(curPtr);
212                 visitor(obj);
213                 objSize = obj->GetClass()->SizeFromJSHClass(obj);
214             } else {
215                 objSize = freeObject->Available();
216             }
217             curPtr += objSize;
218             CHECK_OBJECT_SIZE(objSize);
219         }
220         CHECK_REGION_END(curPtr, endPtr);
221     });
222 }
223 
GetAllocatedSizeSinceGC() const224 size_t SemiSpace::GetAllocatedSizeSinceGC() const
225 {
226     size_t currentRegionSize = 0;
227     auto currentRegion = GetCurrentRegion();
228     if (currentRegion != nullptr) {
229         currentRegionSize = currentRegion->GetAllocatedBytes();
230         if (currentRegion->HasAgeMark()) {
231             currentRegionSize -= currentRegion->GetAllocatedBytes(waterLine_);
232         }
233     }
234     return allocateAfterLastGC_ + currentRegionSize;
235 }
236 
SnapShotSpace(Heap * heap,size_t initialCapacity,size_t maximumCapacity)237 SnapShotSpace::SnapShotSpace(Heap *heap, size_t initialCapacity, size_t maximumCapacity)
238     : LinearSpace(heap, MemSpaceType::SNAPSHOT_SPACE, initialCapacity, maximumCapacity)
239 {
240 }
241 }  // namespace panda::ecmascript
242