1 /*
2 * Copyright (c) 2021 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/full_gc.h"
17
18 #include "ecmascript/ecma_vm.h"
19 #include "ecmascript/mem/clock_scope.h"
20 #include "ecmascript/mem/concurrent_marker.h"
21 #include "ecmascript/mem/concurrent_sweeper.h"
22 #include "ecmascript/mem/heap-inl.h"
23 #include "ecmascript/mem/incremental_marker.h"
24 #include "ecmascript/mem/mark_stack.h"
25 #include "ecmascript/mem/mem.h"
26 #include "ecmascript/mem/parallel_marker-inl.h"
27 #include "ecmascript/mem/space-inl.h"
28 #include "ecmascript/mem/visitor.h"
29 #include "ecmascript/mem/gc_stats.h"
30 #include "ecmascript/ecma_string_table.h"
31 #include "ecmascript/runtime_call_id.h"
32
33 namespace panda::ecmascript {
FullGC(Heap * heap)34 FullGC::FullGC(Heap *heap) : heap_(heap), workManager_(heap->GetWorkManager()) {}
35
RunPhases()36 void FullGC::RunPhases()
37 {
38 GCStats *gcStats = heap_->GetEcmaVM()->GetEcmaGCStats();
39 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "FullGC::RunPhases;Reason" +
40 std::to_string(static_cast<int>(gcStats->GetGCReason())));
41 TRACE_GC(GCStats::Scope::ScopeId::TotalGC, gcStats);
42 MEM_ALLOCATE_AND_GC_TRACE(heap_->GetEcmaVM(), FullGC_RunPhases);
43
44 if (heap_->CheckOngoingConcurrentMarking()) {
45 LOG_GC(DEBUG) << "FullGC after ConcurrentMarking";
46 heap_->GetConcurrentMarker()->Reset(); // HPPGC use mark result to move TaggedObject.
47 }
48
49 if (heap_->GetIncrementalMarker()->IsTriggeredIncrementalMark()) {
50 LOG_GC(DEBUG) << "FullGC after IncrementalMarking";
51 heap_->ClearIdleTask();
52 heap_->DisableNotifyIdle();
53 heap_->GetIncrementalMarker()->Reset();
54 }
55 Initialize();
56 Mark();
57 Sweep();
58 Finish();
59 heap_->NotifyHeapAliveSizeAfterGC(heap_->GetHeapObjectSize());
60 }
61
RunPhasesForAppSpawn()62 void FullGC::RunPhasesForAppSpawn()
63 {
64 auto marker = reinterpret_cast<CompressGCMarker*>(heap_->GetCompressGCMarker());
65 marker->SetAppSpawn(true);
66 RunPhases();
67 marker->SetAppSpawn(false);
68 }
69
Initialize()70 void FullGC::Initialize()
71 {
72 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "FullGC::Initialize");
73 TRACE_GC(GCStats::Scope::ScopeId::Initialize, heap_->GetEcmaVM()->GetEcmaGCStats());
74 heap_->Prepare();
75 auto callback = [](Region *current) {
76 current->ResetAliveObject();
77 current->ClearOldToNewRSet();
78 };
79 heap_->EnumerateNonMovableRegions(callback);
80 heap_->GetAppSpawnSpace()->EnumerateRegions([](Region *current) {
81 current->ClearMarkGCBitset();
82 current->ClearCrossRegionRSet();
83 });
84 youngSpaceCommitSize_ = heap_->GetNewSpace()->GetCommittedSize();
85 heap_->SwapNewSpace();
86 workManager_->Initialize(TriggerGCType::FULL_GC, ParallelGCTaskPhase::COMPRESS_HANDLE_GLOBAL_POOL_TASK);
87 heap_->GetCompressGCMarker()->Initialize();
88
89 youngAndOldAliveSize_ = 0;
90 nonMoveSpaceFreeSize_ = 0;
91 oldSpaceCommitSize_ = heap_->GetOldSpace()->GetCommittedSize();
92 nonMoveSpaceCommitSize_ = heap_->GetNonMovableSpace()->GetCommittedSize();
93 }
94
Mark()95 void FullGC::Mark()
96 {
97 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "FullGC::Mark");
98 TRACE_GC(GCStats::Scope::ScopeId::Mark, heap_->GetEcmaVM()->GetEcmaGCStats());
99 heap_->GetCompressGCMarker()->MarkRoots(MAIN_THREAD_INDEX);
100 heap_->GetCompressGCMarker()->ProcessMarkStack(MAIN_THREAD_INDEX);
101 heap_->WaitRunningTaskFinished();
102 }
103
Sweep()104 void FullGC::Sweep()
105 {
106 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "FullGC::Sweep");
107 TRACE_GC(GCStats::Scope::ScopeId::Sweep, heap_->GetEcmaVM()->GetEcmaGCStats());
108 // process weak reference
109 uint32_t totalThreadCount = 1; // 1 : mainthread
110 if (heap_->IsParallelGCEnabled()) {
111 totalThreadCount += Taskpool::GetCurrentTaskpool()->GetTotalThreadNum();
112 }
113 for (uint32_t i = 0; i < totalThreadCount; i++) {
114 ProcessQueue *queue = workManager_->GetWeakReferenceQueue(i);
115
116 while (true) {
117 auto obj = queue->PopBack();
118 if (UNLIKELY(obj == nullptr)) {
119 break;
120 }
121 ObjectSlot slot(ToUintPtr(obj));
122 JSTaggedValue value(slot.GetTaggedType());
123 auto header = value.GetTaggedWeakRef();
124
125 Region *objectRegion = Region::ObjectAddressToRange(header);
126 if (!HasEvacuated(objectRegion)) {
127 if (!objectRegion->Test(header)) {
128 slot.Clear();
129 }
130 } else {
131 MarkWord markWord(header);
132 if (markWord.IsForwardingAddress()) {
133 TaggedObject *dst = markWord.ToForwardingAddress();
134 auto weakRef = JSTaggedValue(JSTaggedValue(dst).CreateAndGetWeakRef()).GetRawTaggedObject();
135 slot.Update(weakRef);
136 } else {
137 slot.Update(static_cast<JSTaggedType>(JSTaggedValue::Undefined().GetRawData()));
138 }
139 }
140 }
141 }
142
143 auto stringTable = heap_->GetEcmaVM()->GetEcmaStringTable();
144 WeakRootVisitor gcUpdateWeak = [this](TaggedObject *header) {
145 Region *objectRegion = Region::ObjectAddressToRange(header);
146 if (!objectRegion) {
147 LOG_GC(ERROR) << "FullGC updateWeakReference: region is nullptr, header is " << header;
148 return reinterpret_cast<TaggedObject *>(ToUintPtr(nullptr));
149 }
150 if (!HasEvacuated(objectRegion)) {
151 if (objectRegion->Test(header)) {
152 return header;
153 }
154 return reinterpret_cast<TaggedObject *>(ToUintPtr(nullptr));
155 }
156
157 MarkWord markWord(header);
158 if (markWord.IsForwardingAddress()) {
159 return markWord.ToForwardingAddress();
160 }
161 return reinterpret_cast<TaggedObject *>(ToUintPtr(nullptr));
162 };
163 stringTable->SweepWeakReference(gcUpdateWeak);
164 heap_->GetEcmaVM()->GetJSThread()->IterateWeakEcmaGlobalStorage(gcUpdateWeak);
165 heap_->GetEcmaVM()->ProcessReferences(gcUpdateWeak);
166
167 heap_->GetSweeper()->Sweep(true);
168 heap_->GetSweeper()->PostTask(true);
169 }
170
Finish()171 void FullGC::Finish()
172 {
173 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "FullGC::Finish");
174 TRACE_GC(GCStats::Scope::ScopeId::Finish, heap_->GetEcmaVM()->GetEcmaGCStats());
175 if (!forAppSpawn_) {
176 heap_->SwapOldSpace();
177 }
178 youngAndOldAliveSize_ = workManager_->Finish();
179 if (forAppSpawn_) {
180 heap_->ResumeForAppSpawn();
181 } else {
182 heap_->Resume(FULL_GC);
183 }
184 heap_->GetSweeper()->TryFillSweptRegion();
185 }
186
HasEvacuated(Region * region)187 bool FullGC::HasEvacuated(Region *region)
188 {
189 auto marker = reinterpret_cast<CompressGCMarker*>(heap_->GetCompressGCMarker());
190 return marker->NeedEvacuate(region);
191 }
192
SetForAppSpawn(bool flag)193 void FullGC::SetForAppSpawn(bool flag)
194 {
195 forAppSpawn_ = flag;
196 }
197 } // namespace panda::ecmascript
198