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