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 
24 namespace panda::ecmascript {
RunPhases()25 void 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 
Initialize()55 void 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 }
Mark()71 void 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 
Sweep()86 void 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 
Finish()118 void 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 
UpdateRecordWeakReference()131 void 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 
ResetWorkManager(SharedGCWorkManager *sWorkManager)155 void SharedGC::ResetWorkManager(SharedGCWorkManager *sWorkManager)
156 {
157     sWorkManager_ = sWorkManager;
158 }
159 }  // namespace panda::ecmascript
160