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