• 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/concurrent_marker.h"
22 #include "ecmascript/mem/heap.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->GetHeapRegionAllocator(), type, initialCapacity, maximumCapacity),
27       heap_(heap),
28       waterLine_(0),
29       newSpaceNativeLimit_(initialCapacity)
30 {
31 }
32 
Allocate(size_t size,bool isPromoted)33 uintptr_t LinearSpace::Allocate(size_t size, bool isPromoted)
34 {
35     auto object = allocator_.Allocate(size);
36     if (object != 0) {
37 #ifdef ECMASCRIPT_SUPPORT_HEAPSAMPLING
38         // can not heap sampling in gc.
39         if (!isPromoted) {
40             InvokeAllocationInspector(object, size, size);
41         }
42 #endif
43         return object;
44     }
45     if (!isPromoted && heap_->GetConcurrentMarker()->IsConfigDisabled() && NativeBindingSizeLargerThanLimit()) {
46         // Native binding size is larger than limit. Trigger gc.
47         return object;
48     }
49     if (Expand(isPromoted)) {
50         if (!isPromoted) {
51             heap_->TryTriggerIncrementalMarking();
52             heap_->TryTriggerIdleCollection();
53             heap_->TryTriggerConcurrentMarking();
54         }
55         object = allocator_.Allocate(size);
56     } else if (heap_->GetJSThread()->IsMarking()) {
57         // Temporary adjust semi space capacity
58         overShootSize_ = heap_->GetEcmaVM()->GetEcmaParamConfiguration().GetSemiSpaceOvershootSize();
59         if (Expand(isPromoted)) {
60             object = allocator_.Allocate(size);
61         }
62     }
63 #ifdef ECMASCRIPT_SUPPORT_HEAPSAMPLING
64     if (object != 0 && !isPromoted) {
65         InvokeAllocationInspector(object, size, size);
66     }
67 #endif
68     return object;
69 }
70 
Expand(bool isPromoted)71 bool LinearSpace::Expand(bool isPromoted)
72 {
73     if (committedSize_ >= initialCapacity_ + overShootSize_ + outOfMemoryOvershootSize_) {
74         return false;
75     }
76 
77     uintptr_t top = allocator_.GetTop();
78     auto currentRegion = GetCurrentRegion();
79     if (currentRegion != nullptr) {
80         if (!isPromoted) {
81             if (currentRegion->HasAgeMark()) {
82                 allocateAfterLastGC_ +=
83                     currentRegion->GetAllocatedBytes(top) - currentRegion->GetAllocatedBytes(waterLine_);
84             } else {
85                 allocateAfterLastGC_ += currentRegion->GetAllocatedBytes(top);
86             }
87         } else {
88             // For GC
89             survivalObjectSize_ += currentRegion->GetAllocatedBytes(top);
90         }
91         currentRegion->SetHighWaterMark(top);
92     }
93     Region *region = heapRegionAllocator_->AllocateAlignedRegion(this, DEFAULT_REGION_SIZE, heap_->GetJSThread());
94     allocator_.Reset(region->GetBegin(), region->GetEnd());
95 
96     AddRegion(region);
97     return true;
98 }
99 
Stop()100 void LinearSpace::Stop()
101 {
102     if (GetCurrentRegion() != nullptr) {
103         GetCurrentRegion()->SetHighWaterMark(allocator_.GetTop());
104     }
105 }
106 
ResetAllocator()107 void LinearSpace::ResetAllocator()
108 {
109     auto currentRegion = GetCurrentRegion();
110     if (currentRegion != nullptr) {
111         allocator_.Reset(currentRegion->GetBegin(), currentRegion->GetEnd(), currentRegion->GetHighWaterMark());
112     }
113 }
114 
IterateOverObjects(const std::function<void (TaggedObject * object)> & visitor) const115 void LinearSpace::IterateOverObjects(const std::function<void(TaggedObject *object)> &visitor) const
116 {
117     auto current = GetCurrentRegion();
118     EnumerateRegions([&](Region *region) {
119         auto curPtr = region->GetBegin();
120         uintptr_t endPtr = 0;
121         if (region == current) {
122             auto top = allocator_.GetTop();
123             endPtr = curPtr + region->GetAllocatedBytes(top);
124         } else {
125             endPtr = curPtr + region->GetAllocatedBytes();
126         }
127 
128         size_t objSize;
129         while (curPtr < endPtr) {
130             auto freeObject = FreeObject::Cast(curPtr);
131             // If curPtr is freeObject, It must to mark unpoison first.
132             ASAN_UNPOISON_MEMORY_REGION(freeObject, TaggedObject::TaggedObjectSize());
133             if (!freeObject->IsFreeObject()) {
134                 auto obj = reinterpret_cast<TaggedObject *>(curPtr);
135                 visitor(obj);
136                 objSize = obj->GetClass()->SizeFromJSHClass(obj);
137             } else {
138                 freeObject->AsanUnPoisonFreeObject();
139                 objSize = freeObject->Available();
140                 freeObject->AsanPoisonFreeObject();
141             }
142             curPtr += objSize;
143             CHECK_OBJECT_SIZE(objSize);
144         }
145         CHECK_REGION_END(curPtr, endPtr);
146     });
147 }
148 
InvokeAllocationInspector(Address object,size_t size,size_t alignedSize)149 void LinearSpace::InvokeAllocationInspector(Address object, size_t size, size_t alignedSize)
150 {
151     ASSERT(size <= alignedSize);
152     if (LIKELY(!allocationCounter_.IsActive())) {
153         return;
154     }
155     if (alignedSize >= allocationCounter_.NextBytes()) {
156         allocationCounter_.InvokeAllocationInspector(object, size, alignedSize);
157     }
158     allocationCounter_.AdvanceAllocationInspector(alignedSize);
159 }
160 
SemiSpace(Heap * heap,size_t initialCapacity,size_t maximumCapacity)161 SemiSpace::SemiSpace(Heap *heap, size_t initialCapacity, size_t maximumCapacity)
162     : LinearSpace(heap, MemSpaceType::SEMI_SPACE, initialCapacity, maximumCapacity),
163       minimumCapacity_(initialCapacity) {}
164 
Initialize()165 void SemiSpace::Initialize()
166 {
167     Region *region = heapRegionAllocator_->AllocateAlignedRegion(this, DEFAULT_REGION_SIZE, heap_->GetJSThread());
168     AddRegion(region);
169     allocator_.Reset(region->GetBegin(), region->GetEnd());
170 }
171 
Restart()172 void SemiSpace::Restart()
173 {
174     overShootSize_ = 0;
175     survivalObjectSize_ = 0;
176     allocateAfterLastGC_ = 0;
177     Initialize();
178 }
179 
AllocateSync(size_t size)180 uintptr_t SemiSpace::AllocateSync(size_t size)
181 {
182     os::memory::LockHolder lock(lock_);
183     return Allocate(size, true);
184 }
185 
SwapRegion(Region * region,SemiSpace * fromSpace)186 bool SemiSpace::SwapRegion(Region *region, SemiSpace *fromSpace)
187 {
188     os::memory::LockHolder lock(lock_);
189     if (committedSize_ + region->GetCapacity() > maximumCapacity_ + overShootSize_) {
190         return false;
191     }
192     fromSpace->RemoveRegion(region);
193 
194     region->SetGCFlag(RegionGCFlags::IN_NEW_TO_NEW_SET);
195 
196     regionList_.AddNodeToFront(region);
197     IncreaseCommitted(region->GetCapacity());
198     IncreaseObjectSize(region->GetSize());
199     survivalObjectSize_ += region->GetAllocatedBytes();
200     return true;
201 }
202 
SetWaterLine()203 void SemiSpace::SetWaterLine()
204 {
205     waterLine_ = allocator_.GetTop();
206     allocateAfterLastGC_ = 0;
207     Region *last = GetCurrentRegion();
208     if (last != nullptr) {
209         last->SetGCFlag(RegionGCFlags::HAS_AGE_MARK);
210 
211         EnumerateRegions([&last](Region *current) {
212             if (current != last) {
213                 current->SetGCFlag(RegionGCFlags::BELOW_AGE_MARK);
214             }
215         });
216         survivalObjectSize_ += last->GetAllocatedBytes(waterLine_);
217     }
218 }
219 
GetHeapObjectSize() const220 size_t SemiSpace::GetHeapObjectSize() const
221 {
222     return survivalObjectSize_ + allocateAfterLastGC_;
223 }
224 
GetSurvivalObjectSize() const225 size_t SemiSpace::GetSurvivalObjectSize() const
226 {
227     return survivalObjectSize_;
228 }
229 
SetOverShootSize(size_t size)230 void SemiSpace::SetOverShootSize(size_t size)
231 {
232     overShootSize_ = size;
233 }
234 
AdjustCapacity(size_t allocatedSizeSinceGC)235 bool SemiSpace::AdjustCapacity(size_t allocatedSizeSinceGC)
236 {
237     if (allocatedSizeSinceGC <= initialCapacity_ * GROW_OBJECT_SURVIVAL_RATE / GROWING_FACTOR) {
238         return false;
239     }
240     double curObjectSurvivalRate = static_cast<double>(survivalObjectSize_) / allocatedSizeSinceGC;
241     if (curObjectSurvivalRate > GROW_OBJECT_SURVIVAL_RATE) {
242         if (initialCapacity_ >= maximumCapacity_) {
243             return false;
244         }
245         size_t newCapacity = initialCapacity_ * GROWING_FACTOR;
246         SetInitialCapacity(std::min(newCapacity, maximumCapacity_));
247         return true;
248     } else if (curObjectSurvivalRate < SHRINK_OBJECT_SURVIVAL_RATE) {
249         if (initialCapacity_ <= minimumCapacity_) {
250             return false;
251         }
252         double speed = heap_->GetMemController()->GetNewSpaceAllocationThroughputPerMS();
253         if (speed > LOW_ALLOCATION_SPEED_PER_MS) {
254             return false;
255         }
256         size_t newCapacity = initialCapacity_ / GROWING_FACTOR;
257         SetInitialCapacity(std::max(newCapacity, minimumCapacity_));
258         return true;
259     }
260     return false;
261 }
262 
AdjustNativeLimit(size_t previousNativeSize)263 void SemiSpace::AdjustNativeLimit(size_t previousNativeSize)
264 {
265     if (newSpaceNativeBindingSize_ <= newSpaceNativeLimit_ * GROW_OBJECT_SURVIVAL_RATE / GROWING_FACTOR) {
266         return;
267     }
268     double curObjectSurvivalRate = static_cast<double>(previousNativeSize) / newSpaceNativeBindingSize_;
269     if (curObjectSurvivalRate > GROW_OBJECT_SURVIVAL_RATE) {
270         if (newSpaceNativeLimit_ >= maximumCapacity_) {
271             return;
272         }
273         size_t newCapacity = newSpaceNativeLimit_ * GROWING_FACTOR;
274         newSpaceNativeLimit_ = std::min(newCapacity, maximumCapacity_);
275     } else if (curObjectSurvivalRate < SHRINK_OBJECT_SURVIVAL_RATE) {
276         if (newSpaceNativeLimit_ <= minimumCapacity_) {
277             return;
278         }
279         size_t newCapacity = newSpaceNativeLimit_ / GROWING_FACTOR;
280         newSpaceNativeLimit_ = std::max(newCapacity, minimumCapacity_);
281     }
282 }
283 
GetAllocatedSizeSinceGC(uintptr_t top) const284 size_t SemiSpace::GetAllocatedSizeSinceGC(uintptr_t top) const
285 {
286     size_t currentRegionSize = 0;
287     auto currentRegion = GetCurrentRegion();
288     if (currentRegion != nullptr) {
289         currentRegionSize = currentRegion->GetAllocatedBytes(top);
290         if (currentRegion->HasAgeMark()) {
291             currentRegionSize -= currentRegion->GetAllocatedBytes(waterLine_);
292         }
293     }
294     return allocateAfterLastGC_ + currentRegionSize;
295 }
296 
SnapshotSpace(Heap * heap,size_t initialCapacity,size_t maximumCapacity)297 SnapshotSpace::SnapshotSpace(Heap *heap, size_t initialCapacity, size_t maximumCapacity)
298     : LinearSpace(heap, MemSpaceType::SNAPSHOT_SPACE, initialCapacity, maximumCapacity) {}
299 
ReadOnlySpace(Heap * heap,size_t initialCapacity,size_t maximumCapacity)300 ReadOnlySpace::ReadOnlySpace(Heap *heap, size_t initialCapacity, size_t maximumCapacity)
301     : LinearSpace(heap, MemSpaceType::READ_ONLY_SPACE, initialCapacity, maximumCapacity) {}
302 }  // namespace panda::ecmascript
303