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 "common_components/taskpool/taskpool.h"
19 #include "ecmascript/mem/shared_heap/shared_concurrent_marker.h"
20 #include "ecmascript/mem/shared_heap/shared_concurrent_sweeper.h"
21 #include "ecmascript/mem/shared_heap/shared_gc_evacuator.h"
22 #include "ecmascript/mem/shared_heap/shared_gc_marker-inl.h"
23 #include "ecmascript/mem/shared_heap/shared_gc_visitor-inl.h"
24 #include "ecmascript/mem/verification.h"
25
26 namespace panda::ecmascript {
RunPhases()27 void SharedGC::RunPhases()
28 {
29 ASSERT("SharedGC should be disabled" && !g_isEnableCMCGC);
30 ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, ("SharedGC::RunPhases;GCReason"
31 + std::to_string(static_cast<int>(sHeap_->GetEcmaGCStats()->GetGCReason()))
32 + ";MarkReason" + std::to_string(static_cast<int>(sHeap_->GetEcmaGCStats()->GetMarkReason()))
33 + ";Sensitive" + std::to_string(static_cast<int>(sHeap_->GetSensitiveStatus()))
34 + ";IsInBackground" + std::to_string(sHeap_->IsInBackground())
35 + ";Startup" + std::to_string(static_cast<int>(sHeap_->GetStartupStatus()))
36 + ";Old" + std::to_string(sHeap_->GetOldSpace()->GetCommittedSize())
37 + ";huge" + std::to_string(sHeap_->GetHugeObjectSpace()->GetCommittedSize())
38 + ";NonMov" + std::to_string(sHeap_->GetNonMovableSpace()->GetCommittedSize())
39 + ";TotCommit" + std::to_string(sHeap_->GetCommittedSize())
40 + ";NativeBindingSize" + std::to_string(sHeap_->GetNativeSizeAfterLastGC())
41 + ";NativeLimitGC" + std::to_string(sHeap_->GetNativeSizeTriggerSharedGC())
42 + ";NativeLimitCM" + std::to_string(sHeap_->GetNativeSizeTriggerSharedCM())).c_str(), "");
43 TRACE_GC(GCStats::Scope::ScopeId::TotalGC, sHeap_->GetEcmaGCStats());
44 sHeap_->SetGCThreadQosPriority(common::PriorityMode::STW);
45 markingInProgress_ = sHeap_->CheckOngoingConcurrentMarking();
46 Initialize();
47 Mark();
48 if (UNLIKELY(sHeap_->ShouldVerifyHeap())) {
49 // verify mark
50 LOG_ECMA(DEBUG) << "start verify mark";
51 SharedHeapVerification(sHeap_, VerifyKind::VERIFY_SHARED_GC_MARK).VerifyMark(markingInProgress_);
52 }
53 PreSweep();
54 Evacuate();
55 Sweep();
56 if (UNLIKELY(sHeap_->ShouldVerifyHeap())) {
57 // verify sweep
58 LOG_ECMA(DEBUG) << "start verify sweep";
59 SharedHeapVerification(sHeap_, VerifyKind::VERIFY_SHARED_GC_SWEEP).VerifySweep(markingInProgress_);
60 }
61 Finish();
62 sHeap_->SetGCThreadQosPriority(common::PriorityMode::FOREGROUND);
63 sHeap_->ResetNativeSizeAfterLastGC();
64 }
65
Initialize()66 void SharedGC::Initialize()
67 {
68 ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, "SharedGC::Initialize", "");
69 TRACE_GC(GCStats::Scope::ScopeId::Initialize, sHeap_->GetEcmaGCStats());
70 if (!markingInProgress_) {
71 sHeap_->Prepare(true);
72 sHeap_->GetAppSpawnSpace()->EnumerateRegions([](Region *current) {
73 current->ClearMarkGCBitset();
74 current->ClearCrossRegionRSet();
75 });
76 sHeap_->EnumerateOldSpaceRegions([](Region *current) {
77 ASSERT(current->InSharedSweepableSpace());
78 current->ResetAliveObject();
79 });
80 sWorkManager_->Initialize(TriggerGCType::SHARED_GC, SharedParallelMarkPhase::SHARED_MARK_TASK);
81 }
82 }
83
MarkRoots(SharedMarkType markType)84 void SharedGC::MarkRoots(SharedMarkType markType)
85 {
86 SharedGCMarkRootVisitor sharedGCMarkRootVisitor(sWorkManager_, DAEMON_THREAD_INDEX);
87 sHeap_->GetSharedGCMarker()->MarkRoots(sharedGCMarkRootVisitor, markType);
88 }
89
Mark()90 void SharedGC::Mark()
91 {
92 ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, "SharedGC::Mark", "");
93 TRACE_GC(GCStats::Scope::ScopeId::Mark, sHeap_->GetEcmaGCStats());
94 if (markingInProgress_) {
95 sHeap_->GetConcurrentMarker()->ReMark();
96 return;
97 }
98 SharedGCMarker *marker = sHeap_->GetSharedGCMarker();
99 MarkRoots(SharedMarkType::NOT_CONCURRENT_MARK);
100 marker->DoMark<SharedMarkType::NOT_CONCURRENT_MARK>(DAEMON_THREAD_INDEX);
101 marker->MergeBackAndResetRSetWorkListHandler();
102 sHeap_->WaitRunningTaskFinished();
103 }
PreSweep()104 void SharedGC::PreSweep()
105 {
106 sHeap_->GetSweeper()->Sweep(false);
107 UpdateRecordWeakReference();
108 }
109
Evacuate()110 void SharedGC::Evacuate()
111 {
112 if (sHeap_->HasCSetRegions()) {
113 sHeap_->GetSharedGCEvacuator()->Evacuate();
114 }
115 }
116
Sweep()117 void SharedGC::Sweep()
118 {
119 ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, "SharedGC::Sweep", "");
120 TRACE_GC(GCStats::Scope::ScopeId::Sweep, sHeap_->GetEcmaGCStats());
121 WeakRootVisitor gcUpdateWeak = [](TaggedObject *header) -> TaggedObject* {
122 Region *objectRegion = Region::ObjectAddressToRange(header);
123 if (UNLIKELY(objectRegion == nullptr)) {
124 LOG_GC(ERROR) << "SharedGC updateWeakReference: region is nullptr, header is " << header;
125 return nullptr;
126 }
127 if (!objectRegion->InSharedSweepableSpace()) {
128 return header;
129 }
130 if (objectRegion->InSCollectSet()) {
131 MarkWord markWord(header);
132 if (markWord.IsForwardingAddress()) {
133 return markWord.ToForwardingAddress();
134 }
135 return nullptr;
136 }
137 if (objectRegion->Test(header)) {
138 return header;
139 }
140 return nullptr;
141 };
142 auto stringTableCleaner = Runtime::GetInstance()->GetEcmaStringTable()->GetCleaner();
143 stringTableCleaner->PostSweepWeakRefTask(gcUpdateWeak);
144 Runtime::GetInstance()->ProcessNativeDeleteInSharedGC(gcUpdateWeak);
145 Runtime::GetInstance()->ProcessSharedNativeDelete(gcUpdateWeak);
146 bool needClearCache = sHeap_->HasCSetRegions();
147 Runtime::GetInstance()->GCIterateThreadList([&gcUpdateWeak, needClearCache](JSThread *thread) {
148 ASSERT(!thread->IsInRunningState());
149 thread->IterateWeakEcmaGlobalStorage(gcUpdateWeak, GCKind::SHARED_GC);
150 thread->GetEcmaVM()->ProcessSnapShotEnv(gcUpdateWeak);
151 const_cast<Heap*>(thread->GetEcmaVM()->GetHeap())->ResetTlab();
152 if (needClearCache) {
153 thread->ClearVMCachedConstantPool();
154 }
155 });
156
157 stringTableCleaner->JoinAndWaitSweepWeakRefTask(gcUpdateWeak);
158 sHeap_->GetSweeper()->PostTask(false);
159 }
160
Finish()161 void SharedGC::Finish()
162 {
163 ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, "SharedGC::Finish", "");
164 TRACE_GC(GCStats::Scope::ScopeId::Finish, sHeap_->GetEcmaGCStats());
165 sHeap_->Reclaim(TriggerGCType::SHARED_GC);
166 if (markingInProgress_) {
167 sHeap_->GetConcurrentMarker()->Reset(false);
168 } else {
169 sWorkManager_->Finish();
170 }
171 sHeap_->GetSweeper()->TryFillSweptRegion();
172 }
173
UpdateRecordWeakReference()174 void SharedGC::UpdateRecordWeakReference()
175 {
176 auto totalThreadCount = common::Taskpool::GetCurrentTaskpool()->GetTotalThreadNum() + 1;
177 for (uint32_t i = 0; i < totalThreadCount; i++) {
178 ProcessQueue *queue = sHeap_->GetWorkManager()->GetWeakReferenceQueue(i);
179
180 while (true) {
181 auto obj = queue->PopBack();
182 if (UNLIKELY(obj == nullptr)) {
183 break;
184 }
185 ObjectSlot slot(ToUintPtr(obj));
186 JSTaggedValue value(slot.GetTaggedType());
187 if (value.IsWeak()) {
188 auto header = value.GetTaggedWeakRef();
189 Region *objectRegion = Region::ObjectAddressToRange(header);
190 if (!objectRegion->Test(header)) {
191 slot.Clear();
192 }
193 }
194 }
195 }
196 }
197
ResetWorkManager(SharedGCWorkManager * sWorkManager)198 void SharedGC::ResetWorkManager(SharedGCWorkManager *sWorkManager)
199 {
200 sWorkManager_ = sWorkManager;
201 }
202 } // namespace panda::ecmascript
203