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_full_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_marker-inl.h"
22
23 namespace panda::ecmascript {
RunPhases()24 void SharedFullGC::RunPhases()
25 {
26 ASSERT("SharedFullGC should be disabled" && !g_isEnableCMCGC);
27 ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, ("SharedFullGC::RunPhases;GCReason"
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(static_cast<int>(sHeap_->GetStartupStatus()))
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 + ";NativeBindingSize" + std::to_string(sHeap_->GetNativeSizeAfterLastGC())
37 + ";NativeLimitGC" + std::to_string(sHeap_->GetNativeSizeTriggerSharedGC())
38 + ";NativeLimitCM" + std::to_string(sHeap_->GetNativeSizeTriggerSharedCM())).c_str(), "");
39 TRACE_GC(GCStats::Scope::ScopeId::TotalGC, sHeap_->GetEcmaGCStats());
40 sHeap_->SetGCThreadQosPriority(common::PriorityMode::STW);
41 Initialize();
42 Mark();
43 Sweep();
44 Finish();
45 sHeap_->SetGCThreadQosPriority(common::PriorityMode::FOREGROUND);
46 }
47
Initialize()48 void SharedFullGC::Initialize()
49 {
50 ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, "SharedFullGC::Initialize", "");
51 TRACE_GC(GCStats::Scope::ScopeId::Initialize, sHeap_->GetEcmaGCStats());
52 sHeap_->Prepare(true);
53 if (UNLIKELY(sHeap_->CheckOngoingConcurrentMarking())) {
54 // Concurrent shared mark should always trigger shared gc without moving.
55 sHeap_->GetConcurrentMarker()->Reset(true);
56 }
57 sHeap_->GetAppSpawnSpace()->EnumerateRegions([](Region *current) {
58 current->ClearMarkGCBitset();
59 current->ClearCrossRegionRSet();
60 });
61 sHeap_->EnumerateOldSpaceRegions([](Region *current) {
62 ASSERT(current->InSharedSweepableSpace());
63 current->ResetAliveObject();
64 });
65 sWorkManager_->Initialize(TriggerGCType::SHARED_FULL_GC, SharedParallelMarkPhase::SHARED_COMPRESS_TASK);
66 }
67
MarkRoots(SharedMarkType markType)68 void SharedFullGC::MarkRoots(SharedMarkType markType)
69 {
70 SharedGCMovableMarker *marker = static_cast<SharedGCMovableMarker*>(sHeap_->GetSharedGCMovableMarker());
71 SharedFullGCMarkRootVisitor sharedFullGCMarkRootVisitor(marker, DAEMON_THREAD_INDEX);
72 marker->MarkRoots(sharedFullGCMarkRootVisitor, markType);
73 }
74
Mark()75 void SharedFullGC::Mark()
76 {
77 ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, "SharedFullGC::Mark", "");
78 TRACE_GC(GCStats::Scope::ScopeId::Mark, sHeap_->GetEcmaGCStats());
79 SharedGCMovableMarker *marker = sHeap_->GetSharedGCMovableMarker();
80
81 MarkRoots(SharedMarkType::NOT_CONCURRENT_MARK);
82 marker->DoMark<SharedMarkType::NOT_CONCURRENT_MARK>(DAEMON_THREAD_INDEX);
83 marker->MergeBackAndResetRSetWorkListHandler();
84 sHeap_->WaitRunningTaskFinished();
85 }
86
Sweep()87 void SharedFullGC::Sweep()
88 {
89 ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, "SharedFullGC::Sweep", "");
90 TRACE_GC(GCStats::Scope::ScopeId::Sweep, sHeap_->GetEcmaGCStats());
91 UpdateRecordWeakReference();
92 WeakRootVisitor gcUpdateWeak = [](TaggedObject *header) {
93 Region *objectRegion = Region::ObjectAddressToRange(header);
94 if (!objectRegion) {
95 LOG_GC(ERROR) << "SharedFullGC updateWeakReference: region is nullptr, header is " << header;
96 return reinterpret_cast<TaggedObject *>(ToUintPtr(nullptr));
97 }
98 if (objectRegion->InSharedOldSpace()) {
99 MarkWord markWord(header);
100 if (markWord.IsForwardingAddress()) {
101 return markWord.ToForwardingAddress();
102 }
103 return reinterpret_cast<TaggedObject *>(ToUintPtr(nullptr));
104 }
105 if (!objectRegion->InSharedSweepableSpace() || objectRegion->Test(header)) {
106 return header;
107 }
108 return reinterpret_cast<TaggedObject *>(ToUintPtr(nullptr));
109 };
110 auto stringTableCleaner = Runtime::GetInstance()->GetEcmaStringTable()->GetCleaner();
111 stringTableCleaner->PostSweepWeakRefTask(gcUpdateWeak);
112 Runtime::GetInstance()->ProcessNativeDeleteInSharedGC(gcUpdateWeak);
113 Runtime::GetInstance()->ProcessSharedNativeDelete(gcUpdateWeak);
114
115 Runtime::GetInstance()->GCIterateThreadList([&](JSThread *thread) {
116 ASSERT(!thread->IsInRunningState());
117 thread->IterateWeakEcmaGlobalStorage(gcUpdateWeak, GCKind::SHARED_GC);
118 thread->GetEcmaVM()->ProcessSnapShotEnv(gcUpdateWeak);
119 const_cast<Heap*>(thread->GetEcmaVM()->GetHeap())->ResetTlab();
120 thread->ClearVMCachedConstantPool();
121 });
122
123 stringTableCleaner->JoinAndWaitSweepWeakRefTask(gcUpdateWeak);
124 sHeap_->GetSweeper()->Sweep(true);
125 sHeap_->GetSweeper()->PostTask(true);
126 }
127
Finish()128 void SharedFullGC::Finish()
129 {
130 ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, "SharedFullGC::Finish", "");
131 TRACE_GC(GCStats::Scope::ScopeId::Finish, sHeap_->GetEcmaGCStats());
132 sHeap_->SwapOldSpace();
133 sWorkManager_->Finish();
134 if (!isAppspawn_) {
135 sHeap_->Reclaim(TriggerGCType::SHARED_FULL_GC);
136 } else {
137 sHeap_->ReclaimForAppSpawn();
138 }
139
140 sHeap_->GetSweeper()->TryFillSweptRegion();
141 }
142
UpdateRecordWeakReference()143 void SharedFullGC::UpdateRecordWeakReference()
144 {
145 auto totalThreadCount = common::Taskpool::GetCurrentTaskpool()->GetTotalThreadNum() + 1;
146 for (uint32_t i = 0; i < totalThreadCount; i++) {
147 ProcessQueue *queue = sHeap_->GetWorkManager()->GetWeakReferenceQueue(i);
148
149 while (true) {
150 auto obj = queue->PopBack();
151 if (UNLIKELY(obj == nullptr)) {
152 break;
153 }
154 ObjectSlot slot(ToUintPtr(obj));
155 JSTaggedValue value(slot.GetTaggedType());
156 ASSERT(value.IsWeak());
157 auto header = value.GetTaggedWeakRef();
158 Region *objectRegion = Region::ObjectAddressToRange(header);
159 if (!objectRegion->InSharedOldSpace()) {
160 if (!objectRegion->Test(header)) {
161 slot.Clear();
162 }
163 } else {
164 MarkWord markWord(header);
165 if (markWord.IsForwardingAddress()) {
166 TaggedObject *dst = markWord.ToForwardingAddress();
167 auto weakRef = JSTaggedValue(JSTaggedValue(dst).CreateAndGetWeakRef()).GetRawTaggedObject();
168 slot.Update(weakRef);
169 } else {
170 slot.Clear();
171 }
172 }
173 }
174 }
175 }
176
HasEvacuated(Region * region)177 bool SharedFullGC::HasEvacuated(Region *region)
178 {
179 auto marker = reinterpret_cast<SharedGCMovableMarker *>(sHeap_->GetSharedGCMovableMarker());
180 return marker->NeedEvacuate(region);
181 }
182
ResetWorkManager(SharedGCWorkManager * sWorkManager)183 void SharedFullGC::ResetWorkManager(SharedGCWorkManager *sWorkManager)
184 {
185 sWorkManager_ = sWorkManager;
186 }
187 } // namespace panda::ecmascript
188