Files
lukai 2a7a4390ee add read-only space
realize read-only space to manage read-only object
issue: https://gitee.com/openharmony/ark_js_runtime/issues/I5DHA7?from=project-issue

Signed-off-by: lukai <lukai25@huawei.com>
Change-Id: I94007e4a2ad990ca21a182afa182713cae390a76
2022-06-28 09:15:29 +08:00

246 lines
7.8 KiB
C++

/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/mem/linear_space.h"
#include "ecmascript/free_object.h"
#include "ecmascript/js_hclass-inl.h"
#include "ecmascript/mem/allocator-inl.h"
#include "ecmascript/mem/heap.h"
namespace panda::ecmascript {
LinearSpace::LinearSpace(Heap *heap, MemSpaceType type, size_t initialCapacity, size_t maximumCapacity)
: Space(heap->GetHeapRegionAllocator(), type, initialCapacity, maximumCapacity),
heap_(heap),
waterLine_(0)
{
}
uintptr_t LinearSpace::Allocate(size_t size, bool isPromoted)
{
auto object = allocator_.Allocate(size);
if (object != 0) {
return object;
}
if (Expand(isPromoted)) {
if (!isPromoted) {
heap_->TryTriggerConcurrentMarking();
}
object = allocator_.Allocate(size);
} else if (heap_->GetJSThread()->IsMarking()) {
// Temporary adjust semi space capacity
overShootSize_ = heap_->GetEcmaVM()->GetEcmaParamConfiguration().GetSemiSpaceOvershootSize();
if (Expand(isPromoted)) {
object = allocator_.Allocate(size);
}
}
return object;
}
bool LinearSpace::Expand(bool isPromoted)
{
if (committedSize_ >= initialCapacity_ + overShootSize_) {
return false;
}
uintptr_t top = allocator_.GetTop();
auto currentRegion = GetCurrentRegion();
if (currentRegion != nullptr) {
if (!isPromoted) {
if (currentRegion->HasAgeMark()) {
allocateAfterLastGC_ +=
currentRegion->GetAllocatedBytes(top) - currentRegion->GetAllocatedBytes(waterLine_);
} else {
allocateAfterLastGC_ += currentRegion->GetAllocatedBytes(top);
}
} else {
// For GC
survivalObjectSize_ += currentRegion->GetAllocatedBytes(top);
}
currentRegion->SetHighWaterMark(top);
}
Region *region = heapRegionAllocator_->AllocateAlignedRegion(this, DEFAULT_REGION_SIZE, heap_->GetJSThread());
allocator_.Reset(region->GetBegin(), region->GetEnd());
AddRegion(region);
return true;
}
void LinearSpace::Stop()
{
if (GetCurrentRegion() != nullptr) {
GetCurrentRegion()->SetHighWaterMark(allocator_.GetTop());
}
}
void LinearSpace::ResetAllocator()
{
auto currentRegion = GetCurrentRegion();
if (currentRegion != nullptr) {
allocator_.Reset(currentRegion->GetBegin(), currentRegion->GetEnd(), currentRegion->GetHighWaterMark());
}
}
void LinearSpace::IterateOverObjects(const std::function<void(TaggedObject *object)> &visitor) const
{
auto current = GetCurrentRegion();
EnumerateRegions([&](Region *region) {
auto curPtr = region->GetBegin();
uintptr_t endPtr;
if (region == current) {
auto top = allocator_.GetTop();
endPtr = curPtr + region->GetAllocatedBytes(top);
} else {
endPtr = curPtr + region->GetAllocatedBytes();
}
size_t objSize;
while (curPtr < endPtr) {
auto freeObject = FreeObject::Cast(curPtr);
if (!freeObject->IsFreeObject()) {
auto obj = reinterpret_cast<TaggedObject *>(curPtr);
visitor(obj);
objSize = obj->GetClass()->SizeFromJSHClass(obj);
} else {
objSize = freeObject->Available();
}
curPtr += objSize;
CHECK_OBJECT_SIZE(objSize);
}
CHECK_REGION_END(curPtr, endPtr);
});
}
SemiSpace::SemiSpace(Heap *heap, size_t initialCapacity, size_t maximumCapacity)
: LinearSpace(heap, MemSpaceType::SEMI_SPACE, initialCapacity, maximumCapacity),
minimumCapacity_(initialCapacity) {}
void SemiSpace::Initialize()
{
Region *region = heapRegionAllocator_->AllocateAlignedRegion(this, DEFAULT_REGION_SIZE, heap_->GetJSThread());
AddRegion(region);
allocator_.Reset(region->GetBegin(), region->GetEnd());
}
void SemiSpace::Restart()
{
overShootSize_ = 0;
survivalObjectSize_ = 0;
allocateAfterLastGC_ = 0;
Initialize();
}
uintptr_t SemiSpace::AllocateSync(size_t size)
{
os::memory::LockHolder lock(lock_);
return Allocate(size, true);
}
bool SemiSpace::SwapRegion(Region *region, SemiSpace *fromSpace)
{
os::memory::LockHolder lock(lock_);
if (committedSize_ + region->GetCapacity() > maximumCapacity_ + overShootSize_) {
return false;
}
fromSpace->RemoveRegion(region);
region->SetGCFlag(RegionGCFlags::IN_NEW_TO_NEW_SET);
regionList_.AddNodeToFront(region);
IncreaseCommitted(region->GetCapacity());
IncreaseObjectSize(region->GetSize());
survivalObjectSize_ += region->GetAllocatedBytes();
return true;
}
void SemiSpace::SetWaterLine()
{
waterLine_ = allocator_.GetTop();
allocateAfterLastGC_ = 0;
Region *last = GetCurrentRegion();
if (last != nullptr) {
last->SetGCFlag(RegionGCFlags::HAS_AGE_MARK);
EnumerateRegions([&last](Region *current) {
if (current != last) {
current->SetGCFlag(RegionGCFlags::BELOW_AGE_MARK);
}
});
survivalObjectSize_ += last->GetAllocatedBytes(waterLine_);
}
}
size_t SemiSpace::GetHeapObjectSize() const
{
return survivalObjectSize_ + allocateAfterLastGC_;
}
size_t SemiSpace::GetSurvivalObjectSize() const
{
return survivalObjectSize_;
}
void SemiSpace::SetOverShootSize(size_t size)
{
overShootSize_ = size;
}
bool SemiSpace::AdjustCapacity(size_t allocatedSizeSinceGC)
{
static constexpr double growObjectSurvivalRate = 0.8;
static constexpr double shrinkObjectSurvivalRate = 0.2;
static constexpr int growingFactor = 2;
if (allocatedSizeSinceGC <= initialCapacity_ * growObjectSurvivalRate / growingFactor) {
return false;
}
double curObjectSurvivalRate = static_cast<double>(survivalObjectSize_) / allocatedSizeSinceGC;
if (curObjectSurvivalRate > growObjectSurvivalRate) {
if (initialCapacity_ >= maximumCapacity_) {
return false;
}
size_t newCapacity = initialCapacity_ * growingFactor;
SetInitialCapacity(std::min(newCapacity, maximumCapacity_));
return true;
} else if (curObjectSurvivalRate < shrinkObjectSurvivalRate) {
if (initialCapacity_ <= minimumCapacity_) {
return false;
}
size_t newCapacity = initialCapacity_ / growingFactor;
SetInitialCapacity(std::max(newCapacity, minimumCapacity_));
return true;
}
return false;
}
size_t SemiSpace::GetAllocatedSizeSinceGC(uintptr_t top) const
{
size_t currentRegionSize = 0;
auto currentRegion = GetCurrentRegion();
if (currentRegion != nullptr) {
currentRegionSize = currentRegion->GetAllocatedBytes(top);
if (currentRegion->HasAgeMark()) {
currentRegionSize -= currentRegion->GetAllocatedBytes(waterLine_);
}
}
return allocateAfterLastGC_ + currentRegionSize;
}
SnapshotSpace::SnapshotSpace(Heap *heap, size_t initialCapacity, size_t maximumCapacity)
: LinearSpace(heap, MemSpaceType::SNAPSHOT_SPACE, initialCapacity, maximumCapacity) {}
ReadOnlySpace::ReadOnlySpace(Heap *heap, size_t initialCapacity, size_t maximumCapacity)
: LinearSpace(heap, MemSpaceType::READ_ONLY_SPACE, initialCapacity, maximumCapacity) {}
} // namespace panda::ecmascript