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/partial_gc.h"
17
18 #include "common_components/taskpool/taskpool.h"
19 #include "ecmascript/mem/concurrent_marker.h"
20 #include "ecmascript/mem/incremental_marker.h"
21 #include "ecmascript/mem/parallel_evacuator.h"
22 #include "ecmascript/mem/parallel_marker.h"
23 #include "ecmascript/mem/old_gc_visitor-inl.h"
24 #include "ecmascript/mem/young_gc_visitor-inl.h"
25 #include "ecmascript/runtime_call_id.h"
26 #include "ecmascript/mem/verification.h"
27
28 namespace panda::ecmascript {
PartialGC(Heap * heap)29 PartialGC::PartialGC(Heap *heap) : heap_(heap), workManager_(heap->GetWorkManager()) {}
30
RunPhases()31 void PartialGC::RunPhases()
32 {
33 ASSERT("PartialGC should be disabled" && !g_isEnableCMCGC);
34 GCStats *gcStats = heap_->GetEcmaVM()->GetEcmaGCStats();
35 ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK,
36 ("PartialGC::RunPhases" + std::to_string(heap_->IsConcurrentFullMark())
37 + ";GCReason" + std::to_string(static_cast<int>(gcStats->GetGCReason()))
38 + ";MarkReason" + std::to_string(static_cast<int>(gcStats->GetMarkReason()))
39 + ";Sensitive" + std::to_string(static_cast<int>(heap_->GetSensitiveStatus()))
40 + ";IsInBackground" + std::to_string(heap_->IsInBackground())
41 + ";Startup" + std::to_string(static_cast<int>(heap_->GetStartupStatus()))
42 + ";ConMark" + std::to_string(static_cast<int>(heap_->GetJSThread()->GetMarkStatus()))
43 + ";Young" + std::to_string(heap_->GetNewSpace()->GetCommittedSize())
44 + ";Old" + std::to_string(heap_->GetOldSpace()->GetCommittedSize())
45 + ";TotalCommit" + std::to_string(heap_->GetCommittedSize())
46 + ";NativeBindingSize" + std::to_string(heap_->GetNativeBindingSize())
47 + ";NativeLimitSize" + std::to_string(heap_->GetGlobalSpaceNativeLimit())
48 + ";ObjSizeBeforeSensitive" + std::to_string(heap_->GetRecordHeapObjectSizeBeforeSensitive())).c_str(), "");
49 TRACE_GC(GCStats::Scope::ScopeId::TotalGC, gcStats);
50 MEM_ALLOCATE_AND_GC_TRACE(heap_->GetEcmaVM(), PartialGC_RunPhases);
51 bool mainThreadInForeground = heap_->GetJSThread()->IsMainThreadFast() && !heap_->IsInBackground();
52 bool needAjustGCThreadPrio = heap_->GetGCType() == TriggerGCType::OLD_GC ||
53 heap_->GetNewSpace()->GetCommittedSize() >= heap_->GetNewSpace()->GetMaximumCapacity();
54 if (mainThreadInForeground && needAjustGCThreadPrio) {
55 common::Taskpool::GetCurrentTaskpool()->SetThreadPriority(common::PriorityMode::STW);
56 }
57 markingInProgress_ = heap_->CheckOngoingConcurrentMarking();
58 LOG_GC(DEBUG) << "markingInProgress_" << markingInProgress_;
59 Initialize();
60 Mark();
61 if (UNLIKELY(heap_->ShouldVerifyHeap())) {
62 Verification::VerifyMark(heap_);
63 }
64 ProcessSharedGCRSetWorkList();
65 Sweep();
66 Evacuate();
67 if (heap_->IsConcurrentFullMark()) {
68 heap_->GetSweeper()->PostTask();
69 }
70 if (UNLIKELY(heap_->ShouldVerifyHeap())) {
71 Verification::VerifyEvacuate(heap_);
72 }
73 Finish();
74 if (mainThreadInForeground && needAjustGCThreadPrio) {
75 common::Taskpool::GetCurrentTaskpool()->SetThreadPriority(common::PriorityMode::FOREGROUND);
76 }
77 }
78
Initialize()79 void PartialGC::Initialize()
80 {
81 ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, "PartialGC::Initialize", "");
82 TRACE_GC(GCStats::Scope::ScopeId::Initialize, heap_->GetEcmaVM()->GetEcmaGCStats());
83 if (!markingInProgress_ && !heap_->GetIncrementalMarker()->IsTriggeredIncrementalMark()) {
84 LOG_GC(DEBUG) << "No ongoing Concurrent marking. Initializing...";
85 heap_->Prepare();
86 if (heap_->IsConcurrentFullMark()) {
87 heap_->GetOldSpace()->SelectCSet();
88 heap_->GetAppSpawnSpace()->EnumerateRegions([](Region *current) {
89 current->ClearMarkGCBitset();
90 current->ClearCrossRegionRSet();
91 });
92 heap_->EnumerateNonNewSpaceRegions([](Region *current) {
93 current->ResetAliveObject();
94 });
95 }
96 workManager_->Initialize(TriggerGCType::OLD_GC, ParallelGCTaskPhase::OLD_HANDLE_GLOBAL_POOL_TASK);
97
98 freeSize_ = 0;
99 hugeSpaceFreeSize_ = 0;
100 oldSpaceCommitSize_ = heap_->GetOldSpace()->GetCommittedSize();
101 nonMoveSpaceCommitSize_ = heap_->GetNonMovableSpace()->GetCommittedSize();
102 }
103 }
104
Finish()105 void PartialGC::Finish()
106 {
107 ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, "PartialGC::Finish", "");
108 TRACE_GC(GCStats::Scope::ScopeId::Finish, heap_->GetEcmaVM()->GetEcmaGCStats());
109 heap_->Resume(OLD_GC);
110 if (heap_->GetIncrementalMarker()->IsTriggeredIncrementalMark()) {
111 heap_->GetIncrementalMarker()->Reset();
112 } else if (markingInProgress_) {
113 auto marker = heap_->GetConcurrentMarker();
114 marker->Reset(false);
115 } else {
116 workManager_->Finish();
117 }
118 if (heap_->IsConcurrentFullMark()) {
119 heap_->GetSweeper()->TryFillSweptRegion();
120 heap_->SetFullMarkRequestedState(false);
121 }
122 if (heap_->IsNearGCInSensitive()) {
123 heap_->SetNearGCInSensitive(false);
124 }
125 }
126
MarkRoots()127 void PartialGC::MarkRoots()
128 {
129 if (heap_->IsYoungMark()) {
130 YoungGCMarkRootVisitor youngGCMarkRootVisitor(workManager_->GetWorkNodeHolder(MAIN_THREAD_INDEX));
131 heap_->GetNonMovableMarker()->MarkRoots(youngGCMarkRootVisitor);
132 } else {
133 OldGCMarkRootVisitor oldGCMarkRootVisitor(workManager_->GetWorkNodeHolder(MAIN_THREAD_INDEX));
134 heap_->GetNonMovableMarker()->MarkRoots(oldGCMarkRootVisitor);
135 }
136 }
137
Mark()138 void PartialGC::Mark()
139 {
140 ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, "PartialGC::Mark", "");
141 TRACE_GC(GCStats::Scope::ScopeId::Mark, heap_->GetEcmaVM()->GetEcmaGCStats());
142 if (markingInProgress_) {
143 heap_->GetConcurrentMarker()->ReMark();
144 return;
145 }
146 MarkRoots();
147 workManager_->GetWorkNodeHolder(MAIN_THREAD_INDEX)->PushWorkNodeToGlobal(false);
148 if (heap_->IsConcurrentFullMark()) {
149 heap_->GetNonMovableMarker()->ProcessMarkStack(MAIN_THREAD_INDEX);
150 } else if (heap_->IsYoungMark()) {
151 NonMovableMarker *marker = static_cast<NonMovableMarker*>(heap_->GetNonMovableMarker());
152 {
153 ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, "GC::ProcessOldToNew", "");
154 marker->ProcessOldToNew(MAIN_THREAD_INDEX);
155 }
156 marker->ProcessSnapshotRSet(MAIN_THREAD_INDEX);
157 }
158 heap_->WaitRunningTaskFinished();
159 // MarkJitCodeMap must be call after other mark work finish to make sure which jserror object js alive.
160 heap_->GetNonMovableMarker()->MarkJitCodeMap(MAIN_THREAD_INDEX);
161 }
162
Sweep()163 void PartialGC::Sweep()
164 {
165 ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, "PartialGC::Sweep", "");
166 ProcessNativeDelete();
167 if (heap_->IsConcurrentFullMark()) {
168 heap_->GetOldSpace()->EnumerateRegions([](Region *current) {
169 current->SetRegionAliveSize();
170 });
171 TRACE_GC(GCStats::Scope::ScopeId::Sweep, heap_->GetEcmaVM()->GetEcmaGCStats());
172 heap_->GetSweeper()->Sweep();
173 }
174 }
175
ProcessNativeDelete()176 void PartialGC::ProcessNativeDelete()
177 {
178 ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, "GC::ProcessNativeDelete", "");
179 TRACE_GC(GCStats::Scope::ScopeId::ClearNativeObject, heap_->GetEcmaVM()->GetEcmaGCStats());
180 WeakRootVisitor gcUpdateWeak = [this](TaggedObject *header) -> TaggedObject* {
181 Region *objectRegion = Region::ObjectAddressToRange(reinterpret_cast<TaggedObject *>(header));
182 ASSERT(!objectRegion->InSharedHeap());
183 if (!objectRegion->InYoungSpaceOrCSet() && heap_->IsYoungMark()) {
184 return header;
185 }
186 if (!objectRegion->Test(header)) {
187 return nullptr;
188 }
189 return header;
190 };
191 heap_->GetEcmaVM()->ProcessNativeDelete(gcUpdateWeak);
192 }
193
Evacuate()194 void PartialGC::Evacuate()
195 {
196 ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, "PartialGC::Evacuate", "");
197 TRACE_GC(GCStats::Scope::ScopeId::Evacuate, heap_->GetEcmaVM()->GetEcmaGCStats());
198 heap_->GetEvacuator()->Evacuate();
199 }
200
ProcessSharedGCRSetWorkList()201 ARK_INLINE void PartialGC::ProcessSharedGCRSetWorkList()
202 {
203 TRACE_GC(GCStats::Scope::ScopeId::ProcessSharedGCRSetWorkList, heap_->GetEcmaVM()->GetEcmaGCStats());
204 heap_->ProcessSharedGCRSetWorkList();
205 }
206 } // namespace panda::ecmascript
207