Files
ark_js_runtime/ecmascript/mem/heap.cpp
T
lukai cdcd46b347 fix concurrent sweep bugs
Both concurrentSweep thread and js thread will operate remember set, which leads to competition.

Use two remembersets, one for concurrentSweep, one for js thread

issue: https://gitee.com/openharmony/ark_js_runtime/issues/I5794M?from=project-issue

Signed-off-by: lukai <lukai25@huawei.com>
Change-Id: Ie86ead2e5f5dfaf47c9830a56d158711b0ba9147
2022-05-15 19:42:58 +08:00

692 lines
26 KiB
C++

/*
* Copyright (c) 2021 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/free_object.h"
#include "ecmascript/mem/heap-inl.h"
#if !defined(PANDA_TARGET_WINDOWS) && !defined(PANDA_TARGET_MACOS)
#include <sys/sysinfo.h>
#endif
#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
#include "ecmascript/dfx/cpu_profiler/cpu_profiler.h"
#endif
#include "ecmascript/ecma_vm.h"
#include "ecmascript/mem/assert_scope.h"
#include "ecmascript/mem/concurrent_marker.h"
#include "ecmascript/mem/concurrent_sweeper.h"
#include "ecmascript/mem/full_gc.h"
#include "ecmascript/mem/mark_stack.h"
#include "ecmascript/mem/mem_controller.h"
#include "ecmascript/mem/partial_gc.h"
#include "ecmascript/mem/native_area_allocator.h"
#include "ecmascript/mem/parallel_evacuator.h"
#include "ecmascript/mem/parallel_marker-inl.h"
#include "ecmascript/mem/stw_young_gc.h"
#include "ecmascript/mem/verification.h"
#include "ecmascript/mem/work_manager.h"
#include "ecmascript/mem/gc_stats.h"
#include "ecmascript/ecma_string_table.h"
#include "ecmascript/runtime_call_id.h"
namespace panda::ecmascript {
Heap::Heap(EcmaVM *ecmaVm) : ecmaVm_(ecmaVm), thread_(ecmaVm->GetJSThread()),
nativeAreaAllocator_(ecmaVm->GetNativeAreaAllocator()),
heapRegionAllocator_(ecmaVm->GetHeapRegionAllocator()) {}
void Heap::Initialize()
{
memController_ = new MemController(this);
size_t defaultSemiSpaceCapacity = ecmaVm_->GetJSOptions().DefaultSemiSpaceCapacity();
activeSpace_ = new SemiSpace(this, defaultSemiSpaceCapacity, defaultSemiSpaceCapacity);
activeSpace_->Restart();
activeSpace_->SetWaterLine();
inactiveSpace_ = new SemiSpace(this, defaultSemiSpaceCapacity, defaultSemiSpaceCapacity);
// not set up from space
size_t maxOldSpaceCapacity = ecmaVm_->GetJSOptions().MaxOldSpaceCapacity();
oldSpace_ = new OldSpace(this, OLD_SPACE_LIMIT_BEGIN, maxOldSpaceCapacity);
compressSpace_ = new OldSpace(this, OLD_SPACE_LIMIT_BEGIN, maxOldSpaceCapacity);
oldSpace_->Initialize();
size_t maxNonmovableSpaceCapacity = ecmaVm_->GetJSOptions().MaxNonmovableSpaceCapacity();
nonMovableSpace_ = new NonMovableSpace(this, maxNonmovableSpaceCapacity, maxNonmovableSpaceCapacity);
nonMovableSpace_->Initialize();
size_t defaultSnapshotSpaceCapacity = ecmaVm_->GetJSOptions().DefaultSnapshotSpaceCapacity();
size_t maxSnapshotSpaceCapacity = ecmaVm_->GetJSOptions().MaxSnapshotSpaceCapacity();
snapshotSpace_ = new SnapshotSpace(this, defaultSnapshotSpaceCapacity, maxSnapshotSpaceCapacity);
size_t maxMachineCodeSpaceCapacity = ecmaVm_->GetJSOptions().MaxMachineCodeSpaceCapacity();
machineCodeSpace_ = new MachineCodeSpace(this, maxMachineCodeSpaceCapacity, maxMachineCodeSpaceCapacity);
machineCodeSpace_->Initialize();
hugeObjectSpace_ = new HugeObjectSpace(heapRegionAllocator_);
parallelGC_ = ecmaVm_->GetJSOptions().EnableParallelGC();
concurrentMarkingEnabled_ = ecmaVm_->GetJSOptions().EnableConcurrentMark();
markType_ = MarkType::MARK_YOUNG;
#if ECMASCRIPT_DISABLE_PARALLEL_GC
parallelGC_ = false;
#endif
#if ECMASCRIPT_DISABLE_CONCURRENT_MARKING
concurrentMarkingEnabled_ = false;
#endif
workManager_ = new WorkManager(this, Taskpool::GetCurrentTaskpool()->GetTotalThreadNum() + 1);
stwYoungGC_ = new STWYoungGC(this, parallelGC_);
fullGC_ = new FullGC(this);
derivedPointers_ = new ChunkMap<DerivedDataKey, uintptr_t>(ecmaVm_->GetChunk());
partialGC_ = new PartialGC(this);
sweeper_ = new ConcurrentSweeper(this, ecmaVm_->GetJSOptions().EnableConcurrentSweep());
concurrentMarker_ = new ConcurrentMarker(this);
nonMovableMarker_ = new NonMovableMarker(this);
semiGCMarker_ = new SemiGCMarker(this);
compressGCMarker_ = new CompressGCMarker(this);
evacuator_ = new ParallelEvacuator(this);
}
void Heap::Destroy()
{
Prepare();
if (activeSpace_ != nullptr) {
activeSpace_->Destroy();
delete activeSpace_;
activeSpace_ = nullptr;
}
if (inactiveSpace_ != nullptr) {
inactiveSpace_->Destroy();
delete inactiveSpace_;
inactiveSpace_ = nullptr;
}
if (oldSpace_ != nullptr) {
oldSpace_->Destroy();
delete oldSpace_;
oldSpace_ = nullptr;
}
if (compressSpace_ != nullptr) {
compressSpace_->Destroy();
delete compressSpace_;
compressSpace_ = nullptr;
}
if (nonMovableSpace_ != nullptr) {
nonMovableSpace_->Destroy();
delete nonMovableSpace_;
nonMovableSpace_ = nullptr;
}
if (snapshotSpace_ != nullptr) {
snapshotSpace_->Destroy();
delete snapshotSpace_;
snapshotSpace_ = nullptr;
}
if (machineCodeSpace_ != nullptr) {
machineCodeSpace_->Destroy();
delete machineCodeSpace_;
machineCodeSpace_ = nullptr;
}
if (hugeObjectSpace_ != nullptr) {
hugeObjectSpace_->Destroy();
delete hugeObjectSpace_;
hugeObjectSpace_ = nullptr;
}
if (workManager_ != nullptr) {
delete workManager_;
workManager_ = nullptr;
}
if (stwYoungGC_ != nullptr) {
delete stwYoungGC_;
stwYoungGC_ = nullptr;
}
if (partialGC_ != nullptr) {
delete partialGC_;
partialGC_ = nullptr;
}
if (fullGC_ != nullptr) {
delete fullGC_;
fullGC_ = nullptr;
}
nativeAreaAllocator_ = nullptr;
heapRegionAllocator_ = nullptr;
if (memController_ != nullptr) {
delete memController_;
memController_ = nullptr;
}
if (sweeper_ != nullptr) {
delete sweeper_;
sweeper_ = nullptr;
}
if (derivedPointers_ != nullptr) {
delete derivedPointers_;
derivedPointers_ = nullptr;
}
if (concurrentMarker_ != nullptr) {
delete concurrentMarker_;
concurrentMarker_ = nullptr;
}
if (nonMovableMarker_ != nullptr) {
delete nonMovableMarker_;
nonMovableMarker_ = nullptr;
}
if (semiGCMarker_ != nullptr) {
delete semiGCMarker_;
semiGCMarker_ = nullptr;
}
if (compressGCMarker_ != nullptr) {
delete compressGCMarker_;
compressGCMarker_ = nullptr;
}
}
void Heap::Prepare()
{
MEM_ALLOCATE_AND_GC_TRACE(GetEcmaVM(), HeapPrepare);
WaitRunningTaskFinished();
sweeper_->EnsureAllTaskFinished();
WaitClearTaskFinished();
}
void Heap::Resume(TriggerGCType gcType)
{
if (gcType == TriggerGCType::FULL_GC) {
compressSpace_->SetInitialCapacity(oldSpace_->GetInitialCapacity());
auto *oldSpace = compressSpace_;
compressSpace_ = oldSpace_;
oldSpace_ = oldSpace;
}
if (activeSpace_->AdjustCapacity(inactiveSpace_->GetAllocatedSizeSinceGC())) {
inactiveSpace_->SetMaximumCapacity(activeSpace_->GetMaximumCapacity());
}
activeSpace_->SetWaterLine();
PrepareRecordRegionsForReclaim();
if (parallelGC_) {
clearTaskFinished_ = false;
Taskpool::GetCurrentTaskpool()->PostTask(std::make_unique<AsyncClearTask>(this, gcType));
} else {
ReclaimRegions(gcType);
}
}
TriggerGCType Heap::SelectGCType() const
{
// If concurrent mark is enabled, the TryTriggerConcurrentMarking decide which GC to choose.
if (concurrentMarkingEnabled_) {
return YOUNG_GC;
}
if (oldSpace_->CanExpand(activeSpace_->GetSurvivalObjectSize()) && GetHeapObjectSize() <= globalSpaceAllocLimit_) {
return YOUNG_GC;
}
return OLD_GC;
}
void Heap::CollectGarbage(TriggerGCType gcType)
{
#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
[[maybe_unused]] GcStateScope scope(thread_);
#endif
CHECK_NO_GC
#if ECMASCRIPT_ENABLE_HEAP_VERIFY
isVerifying_ = true;
// pre gc heap verify
sweeper_->EnsureAllTaskFinished();
auto failCount = Verification(this).VerifyAll();
if (failCount > 0) {
LOG(FATAL, GC) << "Before gc heap corrupted and " << failCount << " corruptions";
}
isVerifying_ = false;
#endif
#if ECMASCRIPT_SWITCH_GC_MODE_TO_FULL_GC
gcType = TriggerGCType::FULL_GC;
#endif
if (fullGCRequested_ && thread_->IsReadyToMark() && gcType != TriggerGCType::FULL_GC) {
gcType = TriggerGCType::FULL_GC;
}
size_t originalNewSpaceSize = activeSpace_->GetHeapObjectSize();
memController_->StartCalculationBeforeGC();
OPTIONAL_LOG(ecmaVm_, ERROR, ECMASCRIPT) << "Heap::CollectGarbage, gcType = " << gcType
<< " global CommittedSize" << GetCommittedSize()
<< " global limit" << globalSpaceAllocLimit_;
switch (gcType) {
case TriggerGCType::YOUNG_GC:
// Use partial GC for young generation.
if (!concurrentMarkingEnabled_) {
SetMarkType(MarkType::MARK_YOUNG);
}
partialGC_->RunPhases();
break;
case TriggerGCType::OLD_GC:
if (concurrentMarkingEnabled_ && markType_ == MarkType::MARK_YOUNG) {
// Wait for existing concurrent marking tasks to be finished (if any),
// and reset concurrent marker's status for full mark.
bool concurrentMark = CheckOngoingConcurrentMarking();
if (concurrentMark) {
concurrentMarker_->Reset();
}
}
SetMarkType(MarkType::MARK_FULL);
partialGC_->RunPhases();
break;
case TriggerGCType::FULL_GC:
fullGC_->RunPhases();
if (fullGCRequested_) {
fullGCRequested_ = false;
}
break;
default:
UNREACHABLE();
break;
}
if (!oldSpaceLimitAdjusted_ && originalNewSpaceSize > 0) {
semiSpaceCopiedSize_ = activeSpace_->GetHeapObjectSize();
double copiedRate = semiSpaceCopiedSize_ * 1.0 / originalNewSpaceSize;
promotedSize_ = GetEvacuator()->GetPromotedSize();
double promotedRate = promotedSize_ * 1.0 / originalNewSpaceSize;
memController_->AddSurvivalRate(std::min(copiedRate + promotedRate, 1.0));
AdjustOldSpaceLimit();
}
memController_->StopCalculationAfterGC(gcType);
if (gcType == TriggerGCType::FULL_GC || IsFullMark()) {
// Only when the gc type is not semiGC and after the old space sweeping has been finished,
// the limits of old space and global space can be recomputed.
RecomputeLimits();
OPTIONAL_LOG(ecmaVm_, ERROR, ECMASCRIPT) << " GC after: is full mark" << IsFullMark()
<< " global CommittedSize" << GetCommittedSize()
<< " global limit" << globalSpaceAllocLimit_;
markType_ = MarkType::MARK_YOUNG;
}
# if ECMASCRIPT_ENABLE_GC_LOG
ecmaVm_->GetEcmaGCStats()->PrintStatisticResult();
#endif
#if ECMASCRIPT_ENABLE_HEAP_VERIFY
// post gc heap verify
isVerifying_ = true;
sweeper_->EnsureAllTaskFinished();
failCount = Verification(this).VerifyAll();
if (failCount > 0) {
LOG(FATAL, GC) << "After gc heap corrupted and " << failCount << " corruptions";
}
isVerifying_ = false;
#endif
}
void Heap::ThrowOutOfMemoryError(size_t size, std::string functionName)
{
GetEcmaVM()->GetEcmaGCStats()->PrintHeapStatisticResult(true);
LOG_ECMA_MEM(FATAL) << "OOM when trying to allocate " << size << " bytes"
<< " function name: " << functionName.c_str();
}
size_t Heap::VerifyHeapObjects() const
{
size_t failCount = 0;
{
VerifyObjectVisitor verifier(this, &failCount);
activeSpace_->IterateOverObjects(verifier);
}
{
VerifyObjectVisitor verifier(this, &failCount);
oldSpace_->IterateOverObjects(verifier);
}
{
VerifyObjectVisitor verifier(this, &failCount);
nonMovableSpace_->IterateOverObjects(verifier);
}
{
VerifyObjectVisitor verifier(this, &failCount);
hugeObjectSpace_->IterateOverObjects(verifier);
}
{
VerifyObjectVisitor verifier(this, &failCount);
machineCodeSpace_->IterateOverObjects(verifier);
}
{
VerifyObjectVisitor verifier(this, &failCount);
snapshotSpace_->IterateOverObjects(verifier);
}
return failCount;
}
void Heap::AdjustOldSpaceLimit()
{
if (oldSpaceLimitAdjusted_) {
return;
}
size_t oldSpaceAllocLimit = GetOldSpace()->GetInitialCapacity();
size_t newOldSpaceAllocLimit = std::max(oldSpace_->GetHeapObjectSize() + MIN_GROWING_STEP,
static_cast<size_t>(oldSpaceAllocLimit * memController_->GetAverageSurvivalRate()));
if (newOldSpaceAllocLimit <= oldSpaceAllocLimit) {
GetOldSpace()->SetInitialCapacity(newOldSpaceAllocLimit);
} else {
oldSpaceLimitAdjusted_ = true;
}
size_t newGlobalSpaceAllocLimit = std::max(GetHeapObjectSize() + MIN_GROWING_STEP,
static_cast<size_t>(globalSpaceAllocLimit_ * memController_->GetAverageSurvivalRate()));
if (newGlobalSpaceAllocLimit < globalSpaceAllocLimit_) {
globalSpaceAllocLimit_ = newGlobalSpaceAllocLimit;
}
OPTIONAL_LOG(ecmaVm_, ERROR, ECMASCRIPT) << "AdjustOldSpaceLimit oldSpaceAllocLimit_" << oldSpaceAllocLimit
<< " globalSpaceAllocLimit_" << globalSpaceAllocLimit_;
}
void Heap::RecomputeLimits()
{
double gcSpeed = memController_->CalculateMarkCompactSpeedPerMS();
double mutatorSpeed = memController_->GetCurrentOldSpaceAllocationThroughputPerMS();
size_t oldSpaceSize = oldSpace_->GetHeapObjectSize() + hugeObjectSpace_->GetHeapObjectSize();
size_t newSpaceCapacity = activeSpace_->GetMaximumCapacity();
double growingFactor = memController_->CalculateGrowingFactor(gcSpeed, mutatorSpeed);
size_t maxOldSpaceCapacity = GetEcmaVM()->GetJSOptions().MaxOldSpaceCapacity();
auto newOldSpaceLimit = memController_->CalculateAllocLimit(oldSpaceSize, MIN_OLD_SPACE_LIMIT, maxOldSpaceCapacity,
newSpaceCapacity, growingFactor);
auto newGlobalSpaceLimit = memController_->CalculateAllocLimit(GetHeapObjectSize(), DEFAULT_HEAP_SIZE,
MAX_HEAP_SIZE, newSpaceCapacity, growingFactor);
globalSpaceAllocLimit_ = newGlobalSpaceLimit;
oldSpace_->SetInitialCapacity(newOldSpaceLimit);
OPTIONAL_LOG(ecmaVm_, ERROR, ECMASCRIPT) << "RecomputeLimits oldSpaceAllocLimit_" << newOldSpaceLimit
<< " globalSpaceAllocLimit_" << globalSpaceAllocLimit_;
}
void Heap::CheckAndTriggerOldGC()
{
if (GetHeapObjectSize() > globalSpaceAllocLimit_) {
CollectGarbage(TriggerGCType::OLD_GC);
}
}
bool Heap::CheckOngoingConcurrentMarking()
{
if (concurrentMarkingEnabled_ && !thread_->IsReadyToMark()) {
if (thread_->IsMarking()) {
[[maybe_unused]] ClockScope clockScope;
ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "Heap::CheckOngoingConcurrentMarking");
MEM_ALLOCATE_AND_GC_TRACE(GetEcmaVM(), WaitConcurrentMarkingFinished);
GetNonMovableMarker()->ProcessMarkStack(MAIN_THREAD_INDEX);
WaitConcurrentMarkingFinished();
ecmaVm_->GetEcmaGCStats()->StatisticConcurrentMarkWait(clockScope.GetPauseTime());
ECMA_GC_LOG() << "wait concurrent marking finish pause time " << clockScope.TotalSpentTime();
}
memController_->RecordAfterConcurrentMark(IsFullMark(), concurrentMarker_);
return true;
}
return false;
}
void Heap::TryTriggerConcurrentMarking()
{
// When concurrent marking is enabled, concurrent marking will be attempted to trigger.
// When the size of old space or global space reaches the limit, isFullMarkNeeded will be set to true.
// If the predicted duration of current full mark may not result in the new and old spaces reaching their limit,
// full mark will be triggered.
// In the same way, if the size of the new space reaches the capacity, and the predicted duration of current
// young mark may not result in the new space reaching its limit, young mark can be triggered.
// If it spends much time in full mark, the compress full GC will be requested when the spaces reach the limit.
// If the global space is larger than half max heap size, we will turn to use full mark and trigger partial GC.
if (!concurrentMarkingEnabled_ || !thread_->IsReadyToMark()) {
return;
}
bool isFullMarkNeeded = false;
double oldSpaceMarkDuration = 0, newSpaceMarkDuration = 0, newSpaceRemainSize = 0, newSpaceAllocToLimitDuration = 0,
oldSpaceAllocToLimitDuration = 0;
double oldSpaceAllocSpeed = memController_->GetOldSpaceAllocationThroughputPerMS();
double oldSpaceConcurrentMarkSpeed = memController_->GetFullSpaceConcurrentMarkSpeedPerMS();
size_t oldSpaceHeapObjectSize = oldSpace_->GetHeapObjectSize() + hugeObjectSpace_->GetHeapObjectSize();
size_t globalHeapObjectSize = GetHeapObjectSize();
size_t oldSpaceAllocLimit = oldSpace_->GetInitialCapacity();
if (oldSpaceConcurrentMarkSpeed == 0 || oldSpaceAllocSpeed == 0) {
if (oldSpaceHeapObjectSize >= oldSpaceAllocLimit || globalHeapObjectSize >= globalSpaceAllocLimit_) {
markType_ = MarkType::MARK_FULL;
OPTIONAL_LOG(ecmaVm_, ERROR, ECMASCRIPT) << "Trigger the first full mark";
TriggerConcurrentMarking();
return;
}
} else {
if (oldSpaceHeapObjectSize >= oldSpaceAllocLimit || globalHeapObjectSize >= globalSpaceAllocLimit_) {
isFullMarkNeeded = true;
}
oldSpaceAllocToLimitDuration = (oldSpaceAllocLimit - oldSpaceHeapObjectSize) / oldSpaceAllocSpeed;
oldSpaceMarkDuration = GetHeapObjectSize() / oldSpaceConcurrentMarkSpeed;
// oldSpaceRemainSize means the predicted size which can be allocated after the full concurrent mark.
double oldSpaceRemainSize = (oldSpaceAllocToLimitDuration - oldSpaceMarkDuration) * oldSpaceAllocSpeed;
if (oldSpaceRemainSize > 0 && oldSpaceRemainSize < DEFAULT_REGION_SIZE) {
isFullMarkNeeded = true;
}
}
double newSpaceAllocSpeed = memController_->GetNewSpaceAllocationThroughputPerMS();
double newSpaceConcurrentMarkSpeed = memController_->GetNewSpaceConcurrentMarkSpeedPerMS();
if (newSpaceConcurrentMarkSpeed == 0 || newSpaceAllocSpeed == 0) {
if (activeSpace_->GetCommittedSize() >= SEMI_SPACE_TRIGGER_CONCURRENT_MARK) {
markType_ = MarkType::MARK_YOUNG;
TriggerConcurrentMarking();
OPTIONAL_LOG(ecmaVm_, ERROR, ECMASCRIPT) << "Trigger the first semi mark" << fullGCRequested_;
}
return;
}
newSpaceAllocToLimitDuration = (activeSpace_->GetMaximumCapacity() - activeSpace_->GetCommittedSize())
/ newSpaceAllocSpeed;
newSpaceMarkDuration = activeSpace_->GetHeapObjectSize() / newSpaceConcurrentMarkSpeed;
// newSpaceRemainSize means the predicted size which can be allocated after the semi concurrent mark.
newSpaceRemainSize = (newSpaceAllocToLimitDuration - newSpaceMarkDuration) * newSpaceAllocSpeed;
if (isFullMarkNeeded) {
if (oldSpaceMarkDuration < newSpaceAllocToLimitDuration
&& oldSpaceMarkDuration < oldSpaceAllocToLimitDuration) {
markType_ = MarkType::MARK_FULL;
TriggerConcurrentMarking();
OPTIONAL_LOG(ecmaVm_, ERROR, ECMASCRIPT) << "Trigger full mark by speed";
} else {
if (oldSpaceHeapObjectSize >= oldSpaceAllocLimit || globalHeapObjectSize >= globalSpaceAllocLimit_) {
markType_ = MarkType::MARK_FULL;
TriggerConcurrentMarking();
OPTIONAL_LOG(ecmaVm_, ERROR, ECMASCRIPT) << "Trigger full mark by limit";
}
}
} else if (newSpaceRemainSize < DEFAULT_REGION_SIZE) {
markType_ = MarkType::MARK_YOUNG;
TriggerConcurrentMarking();
OPTIONAL_LOG(ecmaVm_, ERROR, ECMASCRIPT) << "Trigger semi mark";
}
}
void Heap::TriggerConcurrentMarking()
{
if (concurrentMarkingEnabled_ && !fullGCRequested_) {
concurrentMarker_->Mark();
}
}
void Heap::UpdateDerivedObjectInStack()
{
if (derivedPointers_->empty()) {
return;
}
for (auto derived : *derivedPointers_) {
auto baseAddr = reinterpret_cast<JSTaggedValue *>(derived.first.first);
JSTaggedValue base = *baseAddr;
if (base.IsHeapObject()) {
uintptr_t baseOldObject = derived.second;
uintptr_t *derivedAddr = reinterpret_cast<uintptr_t *>(derived.first.second);
#ifndef NDEBUG
LOG_ECMA(DEBUG) << std::hex << "fix base before:" << baseAddr << " base old Value: " << baseOldObject <<
" derived:" << derivedAddr << " old Value: " << *derivedAddr << std::endl;
#endif
// derived is always bigger than base
*derivedAddr = reinterpret_cast<uintptr_t>(base.GetHeapObject()) + (*derivedAddr - baseOldObject);
#ifndef NDEBUG
LOG_ECMA(DEBUG) << std::hex << "fix base after:" << baseAddr <<
" base New Value: " << base.GetHeapObject() <<
" derived:" << derivedAddr << " New Value: " << *derivedAddr << std::endl;
#endif
}
}
derivedPointers_->clear();
}
void Heap::WaitRunningTaskFinished()
{
os::memory::LockHolder holder(waitTaskFinishedMutex_);
while (runningTaskCount_ > 0) {
waitTaskFinishedCV_.Wait(&waitTaskFinishedMutex_);
}
}
void Heap::WaitClearTaskFinished()
{
os::memory::LockHolder holder(waitClearTaskFinishedMutex_);
while (!clearTaskFinished_) {
waitClearTaskFinishedCV_.Wait(&waitClearTaskFinishedMutex_);
}
}
void Heap::WaitConcurrentMarkingFinished()
{
concurrentMarker_->WaitMarkingFinished();
}
void Heap::PostParallelGCTask(ParallelGCTaskPhase gcTask)
{
IncreaseTaskCount();
Taskpool::GetCurrentTaskpool()->PostTask(std::make_unique<ParallelGCTask>(this, gcTask));
}
void Heap::IncreaseTaskCount()
{
os::memory::LockHolder holder(waitTaskFinishedMutex_);
runningTaskCount_++;
}
bool Heap::CheckCanDistributeTask()
{
os::memory::LockHolder holder(waitTaskFinishedMutex_);
return (runningTaskCount_ < Taskpool::GetCurrentTaskpool()->GetTotalThreadNum() - 1);
}
void Heap::ReduceTaskCount()
{
os::memory::LockHolder holder(waitTaskFinishedMutex_);
runningTaskCount_--;
if (runningTaskCount_ == 0) {
waitTaskFinishedCV_.SignalAll();
}
}
bool Heap::ParallelGCTask::Run(uint32_t threadIndex)
{
switch (taskPhase_) {
case ParallelGCTaskPhase::SEMI_HANDLE_THREAD_ROOTS_TASK:
heap_->GetSemiGCMarker()->MarkRoots(threadIndex);
heap_->GetSemiGCMarker()->ProcessMarkStack(threadIndex);
break;
case ParallelGCTaskPhase::SEMI_HANDLE_SNAPSHOT_TASK:
heap_->GetSemiGCMarker()->ProcessSnapshotRSet(threadIndex);
break;
case ParallelGCTaskPhase::SEMI_HANDLE_GLOBAL_POOL_TASK:
heap_->GetSemiGCMarker()->ProcessMarkStack(threadIndex);
break;
case ParallelGCTaskPhase::OLD_HANDLE_GLOBAL_POOL_TASK:
heap_->GetNonMovableMarker()->ProcessMarkStack(threadIndex);
break;
case ParallelGCTaskPhase::COMPRESS_HANDLE_GLOBAL_POOL_TASK:
heap_->GetCompressGCMarker()->ProcessMarkStack(threadIndex);
break;
case ParallelGCTaskPhase::CONCURRENT_HANDLE_GLOBAL_POOL_TASK:
heap_->GetNonMovableMarker()->ProcessMarkStack(threadIndex);
break;
case ParallelGCTaskPhase::CONCURRENT_HANDLE_OLD_TO_NEW_TASK:
heap_->GetNonMovableMarker()->ProcessOldToNew(threadIndex);
break;
default:
break;
}
heap_->ReduceTaskCount();
return true;
}
bool Heap::AsyncClearTask::Run([[maybe_unused]] uint32_t threadIndex)
{
heap_->ReclaimRegions(gcType_);
return true;
}
size_t Heap::GetArrayBufferSize() const
{
size_t result = 0;
this->IterateOverObjects([&result](TaggedObject *obj) {
JSHClass* jsClass = obj->GetClass();
result += jsClass->IsArrayBuffer() ? jsClass->GetObjectSize() : 0;
});
return result;
}
bool Heap::IsAlive(TaggedObject *object) const
{
if (!ContainObject(object)) {
LOG(ERROR, RUNTIME) << "The region is already free";
return false;
}
Region *region = Region::ObjectAddressToRange(object);
if (region->InHugeObjectGeneration()) {
return true;
}
bool isFree = FreeObject::Cast(ToUintPtr(object))->IsFreeObject();
if (isFree) {
LOG(ERROR, RUNTIME) << "The object " << object << " in "
<< ToSpaceTypeName(region->GetSpace()->GetSpaceType())
<< " already free";
}
return !isFree;
}
bool Heap::ContainObject(TaggedObject *object) const
{
// semi space
if (activeSpace_->ContainObject(object)) {
return true;
}
// old space
if (oldSpace_->ContainObject(object)) {
return true;
}
// non movable space
if (nonMovableSpace_->ContainObject(object)) {
return true;
}
// huge object space
if (hugeObjectSpace_->ContainObject(object)) {
return true;
}
// machine code space
if (machineCodeSpace_->ContainObject(object)) {
return true;
}
// snapshot space
if (snapshotSpace_->ContainObject(object)) {
return true;
}
return false;
}
} // namespace panda::ecmascript