14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License.
54514f5e3Sopenharmony_ci * You may obtain a copy of the License at
64514f5e3Sopenharmony_ci *
74514f5e3Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
84514f5e3Sopenharmony_ci *
94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and
134514f5e3Sopenharmony_ci * limitations under the License.
144514f5e3Sopenharmony_ci */
154514f5e3Sopenharmony_ci
164514f5e3Sopenharmony_ci#include "ecmascript/mem/shared_heap/shared_full_gc.h"
174514f5e3Sopenharmony_ci#include "ecmascript/mem/shared_heap/shared_concurrent_marker.h"
184514f5e3Sopenharmony_ci#include "ecmascript/mem/shared_heap/shared_concurrent_sweeper.h"
194514f5e3Sopenharmony_ci#include "ecmascript/mem/shared_heap/shared_gc_marker-inl.h"
204514f5e3Sopenharmony_ci#include "ecmascript/runtime.h"
214514f5e3Sopenharmony_ci
224514f5e3Sopenharmony_cinamespace panda::ecmascript {
234514f5e3Sopenharmony_civoid SharedFullGC::RunPhases()
244514f5e3Sopenharmony_ci{
254514f5e3Sopenharmony_ci    ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedFullGC::RunPhases"
264514f5e3Sopenharmony_ci        + std::to_string(static_cast<int>(sHeap_->GetEcmaGCStats()->GetGCReason()))
274514f5e3Sopenharmony_ci        + ";Sensitive" + std::to_string(static_cast<int>(sHeap_->GetSensitiveStatus()))
284514f5e3Sopenharmony_ci        + ";IsInBackground" + std::to_string(sHeap_->IsInBackground())
294514f5e3Sopenharmony_ci        + ";Startup" + std::to_string(sHeap_->OnStartupEvent())
304514f5e3Sopenharmony_ci        + ";Old" + std::to_string(sHeap_->GetOldSpace()->GetCommittedSize())
314514f5e3Sopenharmony_ci        + ";huge" + std::to_string(sHeap_->GetHugeObjectSpace()->GetCommittedSize())
324514f5e3Sopenharmony_ci        + ";NonMov" + std::to_string(sHeap_->GetNonMovableSpace()->GetCommittedSize())
334514f5e3Sopenharmony_ci        + ";TotCommit" + std::to_string(sHeap_->GetCommittedSize()));
344514f5e3Sopenharmony_ci    TRACE_GC(GCStats::Scope::ScopeId::TotalGC, sHeap_->GetEcmaGCStats());
354514f5e3Sopenharmony_ci    Initialize();
364514f5e3Sopenharmony_ci    Mark();
374514f5e3Sopenharmony_ci    Sweep();
384514f5e3Sopenharmony_ci    Finish();
394514f5e3Sopenharmony_ci}
404514f5e3Sopenharmony_ci
414514f5e3Sopenharmony_civoid SharedFullGC::Initialize()
424514f5e3Sopenharmony_ci{
434514f5e3Sopenharmony_ci    ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedFullGC::Initialize");
444514f5e3Sopenharmony_ci    TRACE_GC(GCStats::Scope::ScopeId::Initialize, sHeap_->GetEcmaGCStats());
454514f5e3Sopenharmony_ci    sHeap_->Prepare(true);
464514f5e3Sopenharmony_ci    if (UNLIKELY(sHeap_->CheckOngoingConcurrentMarking())) {
474514f5e3Sopenharmony_ci        // Concurrent shared mark should always trigger shared gc without moving.
484514f5e3Sopenharmony_ci        sHeap_->GetConcurrentMarker()->Reset(true);
494514f5e3Sopenharmony_ci    }
504514f5e3Sopenharmony_ci    sHeap_->GetAppSpawnSpace()->EnumerateRegions([](Region *current) {
514514f5e3Sopenharmony_ci        current->ClearMarkGCBitset();
524514f5e3Sopenharmony_ci    });
534514f5e3Sopenharmony_ci    sHeap_->EnumerateOldSpaceRegions([](Region *current) {
544514f5e3Sopenharmony_ci        ASSERT(current->InSharedSweepableSpace());
554514f5e3Sopenharmony_ci        current->ResetAliveObject();
564514f5e3Sopenharmony_ci    });
574514f5e3Sopenharmony_ci    sWorkManager_->Initialize(TriggerGCType::SHARED_FULL_GC, SharedParallelMarkPhase::SHARED_COMPRESS_TASK);
584514f5e3Sopenharmony_ci}
594514f5e3Sopenharmony_ci
604514f5e3Sopenharmony_civoid SharedFullGC::Mark()
614514f5e3Sopenharmony_ci{
624514f5e3Sopenharmony_ci    ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedFullGC::Mark");
634514f5e3Sopenharmony_ci    TRACE_GC(GCStats::Scope::ScopeId::Mark, sHeap_->GetEcmaGCStats());
644514f5e3Sopenharmony_ci    SharedGCMovableMarker *marker = sHeap_->GetSharedGCMovableMarker();
654514f5e3Sopenharmony_ci
664514f5e3Sopenharmony_ci    marker->MarkRoots(DAEMON_THREAD_INDEX, SharedMarkType::NOT_CONCURRENT_MARK, VMRootVisitType::UPDATE_ROOT);
674514f5e3Sopenharmony_ci    marker->DoMark<SharedMarkType::NOT_CONCURRENT_MARK>(DAEMON_THREAD_INDEX);
684514f5e3Sopenharmony_ci    marker->MergeBackAndResetRSetWorkListHandler();
694514f5e3Sopenharmony_ci    sHeap_->WaitRunningTaskFinished();
704514f5e3Sopenharmony_ci}
714514f5e3Sopenharmony_ci
724514f5e3Sopenharmony_civoid SharedFullGC::Sweep()
734514f5e3Sopenharmony_ci{
744514f5e3Sopenharmony_ci    ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedFullGC::Sweep");
754514f5e3Sopenharmony_ci    TRACE_GC(GCStats::Scope::ScopeId::Sweep, sHeap_->GetEcmaGCStats());
764514f5e3Sopenharmony_ci    UpdateRecordWeakReference();
774514f5e3Sopenharmony_ci    WeakRootVisitor gcUpdateWeak = [](TaggedObject *header) {
784514f5e3Sopenharmony_ci        Region *objectRegion = Region::ObjectAddressToRange(header);
794514f5e3Sopenharmony_ci        if (!objectRegion) {
804514f5e3Sopenharmony_ci            LOG_GC(ERROR) << "SharedFullGC updateWeakReference: region is nullptr, header is " << header;
814514f5e3Sopenharmony_ci            return reinterpret_cast<TaggedObject *>(ToUintPtr(nullptr));
824514f5e3Sopenharmony_ci        }
834514f5e3Sopenharmony_ci        if (objectRegion->InSharedOldSpace()) {
844514f5e3Sopenharmony_ci            MarkWord markWord(header);
854514f5e3Sopenharmony_ci            if (markWord.IsForwardingAddress()) {
864514f5e3Sopenharmony_ci                return markWord.ToForwardingAddress();
874514f5e3Sopenharmony_ci            }
884514f5e3Sopenharmony_ci            return reinterpret_cast<TaggedObject *>(ToUintPtr(nullptr));
894514f5e3Sopenharmony_ci        }
904514f5e3Sopenharmony_ci        if (!objectRegion->InSharedSweepableSpace() || objectRegion->Test(header)) {
914514f5e3Sopenharmony_ci            return header;
924514f5e3Sopenharmony_ci        }
934514f5e3Sopenharmony_ci        return reinterpret_cast<TaggedObject *>(ToUintPtr(nullptr));
944514f5e3Sopenharmony_ci    };
954514f5e3Sopenharmony_ci    auto stringTableCleaner = Runtime::GetInstance()->GetEcmaStringTable()->GetCleaner();
964514f5e3Sopenharmony_ci    stringTableCleaner->PostSweepWeakRefTask(gcUpdateWeak);
974514f5e3Sopenharmony_ci    Runtime::GetInstance()->ProcessNativeDeleteInSharedGC(gcUpdateWeak);
984514f5e3Sopenharmony_ci    Runtime::GetInstance()->ProcessSharedNativeDelete(gcUpdateWeak);
994514f5e3Sopenharmony_ci
1004514f5e3Sopenharmony_ci    Runtime::GetInstance()->GCIterateThreadList([&](JSThread *thread) {
1014514f5e3Sopenharmony_ci        ASSERT(!thread->IsInRunningState());
1024514f5e3Sopenharmony_ci        thread->IterateWeakEcmaGlobalStorage(gcUpdateWeak, GCKind::SHARED_GC);
1034514f5e3Sopenharmony_ci        const_cast<Heap*>(thread->GetEcmaVM()->GetHeap())->ResetTlab();
1044514f5e3Sopenharmony_ci        thread->ClearContextCachedConstantPool();
1054514f5e3Sopenharmony_ci    });
1064514f5e3Sopenharmony_ci
1074514f5e3Sopenharmony_ci    stringTableCleaner->JoinAndWaitSweepWeakRefTask(gcUpdateWeak);
1084514f5e3Sopenharmony_ci    sHeap_->GetSweeper()->Sweep(true);
1094514f5e3Sopenharmony_ci    sHeap_->GetSweeper()->PostTask(true);
1104514f5e3Sopenharmony_ci}
1114514f5e3Sopenharmony_ci
1124514f5e3Sopenharmony_civoid SharedFullGC::Finish()
1134514f5e3Sopenharmony_ci{
1144514f5e3Sopenharmony_ci    ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedFullGC::Finish");
1154514f5e3Sopenharmony_ci    TRACE_GC(GCStats::Scope::ScopeId::Finish, sHeap_->GetEcmaGCStats());
1164514f5e3Sopenharmony_ci    sHeap_->SwapOldSpace();
1174514f5e3Sopenharmony_ci    sWorkManager_->Finish();
1184514f5e3Sopenharmony_ci    if (!isAppspawn_) {
1194514f5e3Sopenharmony_ci        sHeap_->Reclaim(TriggerGCType::SHARED_FULL_GC);
1204514f5e3Sopenharmony_ci    } else {
1214514f5e3Sopenharmony_ci        sHeap_->ReclaimForAppSpawn();
1224514f5e3Sopenharmony_ci    }
1234514f5e3Sopenharmony_ci
1244514f5e3Sopenharmony_ci    sHeap_->GetSweeper()->TryFillSweptRegion();
1254514f5e3Sopenharmony_ci}
1264514f5e3Sopenharmony_ci
1274514f5e3Sopenharmony_civoid SharedFullGC::UpdateRecordWeakReference()
1284514f5e3Sopenharmony_ci{
1294514f5e3Sopenharmony_ci    auto totalThreadCount = Taskpool::GetCurrentTaskpool()->GetTotalThreadNum() + 1;
1304514f5e3Sopenharmony_ci    for (uint32_t i = 0; i < totalThreadCount; i++) {
1314514f5e3Sopenharmony_ci        ProcessQueue *queue = sHeap_->GetWorkManager()->GetWeakReferenceQueue(i);
1324514f5e3Sopenharmony_ci
1334514f5e3Sopenharmony_ci        while (true) {
1344514f5e3Sopenharmony_ci            auto obj = queue->PopBack();
1354514f5e3Sopenharmony_ci            if (UNLIKELY(obj == nullptr)) {
1364514f5e3Sopenharmony_ci                break;
1374514f5e3Sopenharmony_ci            }
1384514f5e3Sopenharmony_ci            ObjectSlot slot(ToUintPtr(obj));
1394514f5e3Sopenharmony_ci            JSTaggedValue value(slot.GetTaggedType());
1404514f5e3Sopenharmony_ci            ASSERT(value.IsWeak());
1414514f5e3Sopenharmony_ci            auto header = value.GetTaggedWeakRef();
1424514f5e3Sopenharmony_ci            Region *objectRegion = Region::ObjectAddressToRange(header);
1434514f5e3Sopenharmony_ci            if (!objectRegion->InSharedOldSpace()) {
1444514f5e3Sopenharmony_ci                if (!objectRegion->Test(header)) {
1454514f5e3Sopenharmony_ci                    slot.Clear();
1464514f5e3Sopenharmony_ci                }
1474514f5e3Sopenharmony_ci            } else {
1484514f5e3Sopenharmony_ci                MarkWord markWord(header);
1494514f5e3Sopenharmony_ci                if (markWord.IsForwardingAddress()) {
1504514f5e3Sopenharmony_ci                    TaggedObject *dst = markWord.ToForwardingAddress();
1514514f5e3Sopenharmony_ci                    auto weakRef = JSTaggedValue(JSTaggedValue(dst).CreateAndGetWeakRef()).GetRawTaggedObject();
1524514f5e3Sopenharmony_ci                    slot.Update(weakRef);
1534514f5e3Sopenharmony_ci                } else {
1544514f5e3Sopenharmony_ci                    slot.Clear();
1554514f5e3Sopenharmony_ci                }
1564514f5e3Sopenharmony_ci            }
1574514f5e3Sopenharmony_ci        }
1584514f5e3Sopenharmony_ci    }
1594514f5e3Sopenharmony_ci}
1604514f5e3Sopenharmony_ci
1614514f5e3Sopenharmony_cibool SharedFullGC::HasEvacuated(Region *region)
1624514f5e3Sopenharmony_ci{
1634514f5e3Sopenharmony_ci    auto marker = reinterpret_cast<SharedGCMovableMarker *>(sHeap_->GetSharedGCMovableMarker());
1644514f5e3Sopenharmony_ci    return marker->NeedEvacuate(region);
1654514f5e3Sopenharmony_ci}
1664514f5e3Sopenharmony_ci
1674514f5e3Sopenharmony_civoid SharedFullGC::ResetWorkManager(SharedGCWorkManager *sWorkManager)
1684514f5e3Sopenharmony_ci{
1694514f5e3Sopenharmony_ci    sWorkManager_ = sWorkManager;
1704514f5e3Sopenharmony_ci}
1714514f5e3Sopenharmony_ci}  // namespace panda::ecmascript
172