1/*
2 * Copyright (c) 2024 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/shared_heap/shared_gc.h"
17
18#include "ecmascript/mem/shared_heap/shared_concurrent_marker.h"
19#include "ecmascript/mem/shared_heap/shared_concurrent_sweeper.h"
20#include "ecmascript/mem/shared_heap/shared_gc_marker-inl.h"
21#include "ecmascript/mem/verification.h"
22#include "ecmascript/runtime.h"
23
24namespace panda::ecmascript {
25void SharedGC::RunPhases()
26{
27    ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGC::RunPhases"
28        + std::to_string(static_cast<int>(sHeap_->GetEcmaGCStats()->GetGCReason()))
29        + ";Sensitive" + std::to_string(static_cast<int>(sHeap_->GetSensitiveStatus()))
30        + ";IsInBackground" + std::to_string(sHeap_->IsInBackground())
31        + ";Startup" + std::to_string(sHeap_->OnStartupEvent())
32        + ";Old" + std::to_string(sHeap_->GetOldSpace()->GetCommittedSize())
33        + ";huge" + std::to_string(sHeap_->GetHugeObjectSpace()->GetCommittedSize())
34        + ";NonMov" + std::to_string(sHeap_->GetNonMovableSpace()->GetCommittedSize())
35        + ";TotCommit" + std::to_string(sHeap_->GetCommittedSize()));
36    TRACE_GC(GCStats::Scope::ScopeId::TotalGC, sHeap_->GetEcmaGCStats());
37    markingInProgress_ = sHeap_->CheckOngoingConcurrentMarking();
38    Initialize();
39    Mark();
40    if (UNLIKELY(sHeap_->ShouldVerifyHeap())) {
41        // verify mark
42        LOG_ECMA(DEBUG) << "start verify mark";
43        SharedHeapVerification(sHeap_, VerifyKind::VERIFY_SHARED_GC_MARK).VerifyMark(markingInProgress_);
44    }
45    Sweep();
46    if (UNLIKELY(sHeap_->ShouldVerifyHeap())) {
47        // verify sweep
48        LOG_ECMA(DEBUG) << "start verify sweep";
49        SharedHeapVerification(sHeap_, VerifyKind::VERIFY_SHARED_GC_SWEEP).VerifySweep(markingInProgress_);
50    }
51    Finish();
52    sHeap_->ResetNativeSizeAfterLastGC();
53}
54
55void SharedGC::Initialize()
56{
57    ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGC::Initialize");
58    TRACE_GC(GCStats::Scope::ScopeId::Initialize, sHeap_->GetEcmaGCStats());
59    if (!markingInProgress_) {
60        sHeap_->Prepare(true);
61        sHeap_->GetAppSpawnSpace()->EnumerateRegions([](Region *current) {
62            current->ClearMarkGCBitset();
63        });
64        sHeap_->EnumerateOldSpaceRegions([](Region *current) {
65            ASSERT(current->InSharedSweepableSpace());
66            current->ResetAliveObject();
67        });
68        sWorkManager_->Initialize(TriggerGCType::SHARED_GC, SharedParallelMarkPhase::SHARED_MARK_TASK);
69    }
70}
71void SharedGC::Mark()
72{
73    ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGC::Mark");
74    TRACE_GC(GCStats::Scope::ScopeId::Mark, sHeap_->GetEcmaGCStats());
75    if (markingInProgress_) {
76        sHeap_->GetConcurrentMarker()->ReMark();
77        return;
78    }
79    SharedGCMarker *marker = sHeap_->GetSharedGCMarker();
80    marker->MarkRoots(DAEMON_THREAD_INDEX, SharedMarkType::NOT_CONCURRENT_MARK);
81    marker->DoMark<SharedMarkType::NOT_CONCURRENT_MARK>(DAEMON_THREAD_INDEX);
82    marker->MergeBackAndResetRSetWorkListHandler();
83    sHeap_->WaitRunningTaskFinished();
84}
85
86void SharedGC::Sweep()
87{
88    ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGC::Sweep");
89    TRACE_GC(GCStats::Scope::ScopeId::Sweep, sHeap_->GetEcmaGCStats());
90    UpdateRecordWeakReference();
91    WeakRootVisitor gcUpdateWeak = [](TaggedObject *header) -> TaggedObject* {
92        Region *objectRegion = Region::ObjectAddressToRange(header);
93        if (UNLIKELY(objectRegion == nullptr)) {
94            LOG_GC(ERROR) << "SharedGC updateWeakReference: region is nullptr, header is " << header;
95            return nullptr;
96        }
97        if (!objectRegion->InSharedSweepableSpace() || objectRegion->Test(header)) {
98            return header;
99        }
100        return nullptr;
101    };
102    auto stringTableCleaner = Runtime::GetInstance()->GetEcmaStringTable()->GetCleaner();
103    stringTableCleaner->PostSweepWeakRefTask(gcUpdateWeak);
104    Runtime::GetInstance()->ProcessNativeDeleteInSharedGC(gcUpdateWeak);
105    Runtime::GetInstance()->ProcessSharedNativeDelete(gcUpdateWeak);
106
107    Runtime::GetInstance()->GCIterateThreadList([&](JSThread *thread) {
108        ASSERT(!thread->IsInRunningState());
109        thread->IterateWeakEcmaGlobalStorage(gcUpdateWeak, GCKind::SHARED_GC);
110        const_cast<Heap*>(thread->GetEcmaVM()->GetHeap())->ResetTlab();
111    });
112
113    stringTableCleaner->JoinAndWaitSweepWeakRefTask(gcUpdateWeak);
114    sHeap_->GetSweeper()->Sweep(false);
115    sHeap_->GetSweeper()->PostTask(false);
116}
117
118void SharedGC::Finish()
119{
120    ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGC::Finish");
121    TRACE_GC(GCStats::Scope::ScopeId::Finish, sHeap_->GetEcmaGCStats());
122    sHeap_->Reclaim(TriggerGCType::SHARED_GC);
123    if (markingInProgress_) {
124        sHeap_->GetConcurrentMarker()->Reset(false);
125    } else {
126        sWorkManager_->Finish();
127    }
128    sHeap_->GetSweeper()->TryFillSweptRegion();
129}
130
131void SharedGC::UpdateRecordWeakReference()
132{
133    auto totalThreadCount = Taskpool::GetCurrentTaskpool()->GetTotalThreadNum() + 1;
134    for (uint32_t i = 0; i < totalThreadCount; i++) {
135        ProcessQueue *queue = sHeap_->GetWorkManager()->GetWeakReferenceQueue(i);
136
137        while (true) {
138            auto obj = queue->PopBack();
139            if (UNLIKELY(obj == nullptr)) {
140                break;
141            }
142            ObjectSlot slot(ToUintPtr(obj));
143            JSTaggedValue value(slot.GetTaggedType());
144            if (value.IsWeak()) {
145                auto header = value.GetTaggedWeakRef();
146                Region *objectRegion = Region::ObjectAddressToRange(header);
147                if (!objectRegion->Test(header)) {
148                    slot.Clear();
149                }
150            }
151        }
152    }
153}
154
155void SharedGC::ResetWorkManager(SharedGCWorkManager *sWorkManager)
156{
157    sWorkManager_ = sWorkManager;
158}
159}  // namespace panda::ecmascript
160