• 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 
23 namespace panda::ecmascript {
LinearSpace(Heap * heap,MemSpaceType type,size_t initialCapacity,size_t maximumCapacity)24 LinearSpace::LinearSpace(Heap *heap, MemSpaceType type, size_t initialCapacity, size_t maximumCapacity)
25     : Space(heap->GetHeapRegionAllocator(), type, initialCapacity, maximumCapacity),
26       heap_(heap),
27       waterLine_(0)
28 {
29 }
30 
Allocate(size_t size,bool isPromoted)31 uintptr_t LinearSpace::Allocate(size_t size, bool isPromoted)
32 {
33     auto object = allocator_.Allocate(size);
34     if (object != 0) {
35         return object;
36     }
37     if (Expand(isPromoted)) {
38         if (!isPromoted) {
39             heap_->TryTriggerConcurrentMarking();
40         }
41         object = allocator_.Allocate(size);
42     } else if (heap_->GetJSThread()->IsMarking()) {
43         // Temporary adjust semi space capacity
44         overShootSize_ = heap_->GetEcmaVM()->GetEcmaParamConfiguration().GetSemiSpaceOvershootSize();
45         if (Expand(isPromoted)) {
46             object = allocator_.Allocate(size);
47         }
48     }
49     return object;
50 }
51 
Expand(bool isPromoted)52 bool LinearSpace::Expand(bool isPromoted)
53 {
54     if (committedSize_ >= initialCapacity_ + overShootSize_ + outOfMemoryOvershootSize_) {
55         return false;
56     }
57 
58     uintptr_t top = allocator_.GetTop();
59     auto currentRegion = GetCurrentRegion();
60     if (currentRegion != nullptr) {
61         if (!isPromoted) {
62             if (currentRegion->HasAgeMark()) {
63                 allocateAfterLastGC_ +=
64                     currentRegion->GetAllocatedBytes(top) - currentRegion->GetAllocatedBytes(waterLine_);
65             } else {
66                 allocateAfterLastGC_ += currentRegion->GetAllocatedBytes(top);
67             }
68         } else {
69             // For GC
70             survivalObjectSize_ += currentRegion->GetAllocatedBytes(top);
71         }
72         currentRegion->SetHighWaterMark(top);
73     }
74     Region *region = heapRegionAllocator_->AllocateAlignedRegion(this, DEFAULT_REGION_SIZE, heap_->GetJSThread());
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 
ResetAllocator()88 void LinearSpace::ResetAllocator()
89 {
90     auto currentRegion = GetCurrentRegion();
91     if (currentRegion != nullptr) {
92         allocator_.Reset(currentRegion->GetBegin(), currentRegion->GetEnd(), currentRegion->GetHighWaterMark());
93     }
94 }
95 
IterateOverObjects(const std::function<void (TaggedObject * object)> & visitor) const96 void LinearSpace::IterateOverObjects(const std::function<void(TaggedObject *object)> &visitor) const
97 {
98     auto current = GetCurrentRegion();
99     EnumerateRegions([&](Region *region) {
100         auto curPtr = region->GetBegin();
101         uintptr_t endPtr = 0;
102         if (region == current) {
103             auto top = allocator_.GetTop();
104             endPtr = curPtr + region->GetAllocatedBytes(top);
105         } else {
106             endPtr = curPtr + region->GetAllocatedBytes();
107         }
108 
109         size_t objSize;
110         while (curPtr < endPtr) {
111             auto freeObject = FreeObject::Cast(curPtr);
112             // If curPtr is freeObject, It must to mark unpoison first.
113             ASAN_UNPOISON_MEMORY_REGION(freeObject, TaggedObject::TaggedObjectSize());
114             if (!freeObject->IsFreeObject()) {
115                 auto obj = reinterpret_cast<TaggedObject *>(curPtr);
116                 visitor(obj);
117                 objSize = obj->GetClass()->SizeFromJSHClass(obj);
118             } else {
119                 freeObject->AsanUnPoisonFreeObject();
120                 objSize = freeObject->Available();
121                 freeObject->AsanPoisonFreeObject();
122             }
123             curPtr += objSize;
124             CHECK_OBJECT_SIZE(objSize);
125         }
126         CHECK_REGION_END(curPtr, endPtr);
127     });
128 }
129 
SemiSpace(Heap * heap,size_t initialCapacity,size_t maximumCapacity)130 SemiSpace::SemiSpace(Heap *heap, size_t initialCapacity, size_t maximumCapacity)
131     : LinearSpace(heap, MemSpaceType::SEMI_SPACE, initialCapacity, maximumCapacity),
132       minimumCapacity_(initialCapacity), newSpaceNativeLimit_(initialCapacity) {}
133 
Initialize()134 void SemiSpace::Initialize()
135 {
136     Region *region = heapRegionAllocator_->AllocateAlignedRegion(this, DEFAULT_REGION_SIZE, heap_->GetJSThread());
137     AddRegion(region);
138     allocator_.Reset(region->GetBegin(), region->GetEnd());
139 }
140 
Restart()141 void SemiSpace::Restart()
142 {
143     overShootSize_ = 0;
144     survivalObjectSize_ = 0;
145     allocateAfterLastGC_ = 0;
146     Initialize();
147 }
148 
AllocateSync(size_t size)149 uintptr_t SemiSpace::AllocateSync(size_t size)
150 {
151     os::memory::LockHolder lock(lock_);
152     return Allocate(size, true);
153 }
154 
SwapRegion(Region * region,SemiSpace * fromSpace)155 bool SemiSpace::SwapRegion(Region *region, SemiSpace *fromSpace)
156 {
157     os::memory::LockHolder lock(lock_);
158     if (committedSize_ + region->GetCapacity() > maximumCapacity_ + overShootSize_) {
159         return false;
160     }
161     fromSpace->RemoveRegion(region);
162 
163     region->SetGCFlag(RegionGCFlags::IN_NEW_TO_NEW_SET);
164 
165     regionList_.AddNodeToFront(region);
166     IncreaseCommitted(region->GetCapacity());
167     IncreaseObjectSize(region->GetSize());
168     survivalObjectSize_ += region->GetAllocatedBytes();
169     return true;
170 }
171 
SetWaterLine()172 void SemiSpace::SetWaterLine()
173 {
174     waterLine_ = allocator_.GetTop();
175     allocateAfterLastGC_ = 0;
176     Region *last = GetCurrentRegion();
177     if (last != nullptr) {
178         last->SetGCFlag(RegionGCFlags::HAS_AGE_MARK);
179 
180         EnumerateRegions([&last](Region *current) {
181             if (current != last) {
182                 current->SetGCFlag(RegionGCFlags::BELOW_AGE_MARK);
183             }
184         });
185         survivalObjectSize_ += last->GetAllocatedBytes(waterLine_);
186     }
187 }
188 
GetHeapObjectSize() const189 size_t SemiSpace::GetHeapObjectSize() const
190 {
191     return survivalObjectSize_ + allocateAfterLastGC_;
192 }
193 
GetSurvivalObjectSize() const194 size_t SemiSpace::GetSurvivalObjectSize() const
195 {
196     return survivalObjectSize_;
197 }
198 
SetOverShootSize(size_t size)199 void SemiSpace::SetOverShootSize(size_t size)
200 {
201     overShootSize_ = size;
202 }
203 
AdjustCapacity(size_t allocatedSizeSinceGC)204 bool SemiSpace::AdjustCapacity(size_t allocatedSizeSinceGC)
205 {
206     if (allocatedSizeSinceGC <= initialCapacity_ * GROW_OBJECT_SURVIVAL_RATE / GROWING_FACTOR) {
207         return false;
208     }
209     double curObjectSurvivalRate = static_cast<double>(survivalObjectSize_) / allocatedSizeSinceGC;
210     if (curObjectSurvivalRate > GROW_OBJECT_SURVIVAL_RATE) {
211         if (initialCapacity_ >= maximumCapacity_) {
212             return false;
213         }
214         size_t newCapacity = initialCapacity_ * GROWING_FACTOR;
215         SetInitialCapacity(std::min(newCapacity, maximumCapacity_));
216         return true;
217     } else if (curObjectSurvivalRate < SHRINK_OBJECT_SURVIVAL_RATE) {
218         if (initialCapacity_ <= minimumCapacity_) {
219             return false;
220         }
221         size_t newCapacity = initialCapacity_ / GROWING_FACTOR;
222         SetInitialCapacity(std::max(newCapacity, minimumCapacity_));
223         return true;
224     }
225     return false;
226 }
227 
AdjustNativeLimit(size_t previousNativeSize)228 void SemiSpace::AdjustNativeLimit(size_t previousNativeSize)
229 {
230     if (newSpaceNativeBindingSize_ <= newSpaceNativeLimit_ * GROW_OBJECT_SURVIVAL_RATE / GROWING_FACTOR) {
231         return;
232     }
233     double curObjectSurvivalRate = static_cast<double>(previousNativeSize) / newSpaceNativeBindingSize_;
234     if (curObjectSurvivalRate > GROW_OBJECT_SURVIVAL_RATE) {
235         if (newSpaceNativeLimit_ >= maximumCapacity_) {
236             return;
237         }
238         size_t newCapacity = newSpaceNativeLimit_ * GROWING_FACTOR;
239         newSpaceNativeLimit_ = std::min(newCapacity, maximumCapacity_);
240     } else if (curObjectSurvivalRate < SHRINK_OBJECT_SURVIVAL_RATE) {
241         if (newSpaceNativeLimit_ <= minimumCapacity_) {
242             return;
243         }
244         size_t newCapacity = newSpaceNativeLimit_ / GROWING_FACTOR;
245         newSpaceNativeLimit_ = std::max(newCapacity, minimumCapacity_);
246     }
247 }
248 
GetAllocatedSizeSinceGC(uintptr_t top) const249 size_t SemiSpace::GetAllocatedSizeSinceGC(uintptr_t top) const
250 {
251     size_t currentRegionSize = 0;
252     auto currentRegion = GetCurrentRegion();
253     if (currentRegion != nullptr) {
254         currentRegionSize = currentRegion->GetAllocatedBytes(top);
255         if (currentRegion->HasAgeMark()) {
256             currentRegionSize -= currentRegion->GetAllocatedBytes(waterLine_);
257         }
258     }
259     return allocateAfterLastGC_ + currentRegionSize;
260 }
261 
SnapshotSpace(Heap * heap,size_t initialCapacity,size_t maximumCapacity)262 SnapshotSpace::SnapshotSpace(Heap *heap, size_t initialCapacity, size_t maximumCapacity)
263     : LinearSpace(heap, MemSpaceType::SNAPSHOT_SPACE, initialCapacity, maximumCapacity) {}
264 
ReadOnlySpace(Heap * heap,size_t initialCapacity,size_t maximumCapacity)265 ReadOnlySpace::ReadOnlySpace(Heap *heap, size_t initialCapacity, size_t maximumCapacity)
266     : LinearSpace(heap, MemSpaceType::READ_ONLY_SPACE, initialCapacity, maximumCapacity) {}
267 }  // namespace panda::ecmascript
268