• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/concurrent_marker.h"
17 
18 #include "ecmascript/mem/parallel_marker.h"
19 #include "ecmascript/mem/old_gc_visitor-inl.h"
20 #include "ecmascript/mem/young_gc_visitor-inl.h"
21 #include "ecmascript/runtime_call_id.h"
22 
23 namespace panda::ecmascript {
24 size_t ConcurrentMarker::taskCounts_ = 0;
25 Mutex ConcurrentMarker::taskCountMutex_;
26 
ConcurrentMarker(Heap * heap,EnableConcurrentMarkType type)27 ConcurrentMarker::ConcurrentMarker(Heap *heap, EnableConcurrentMarkType type)
28     : heap_(heap),
29       vm_(heap->GetEcmaVM()),
30       thread_(vm_->GetJSThread()),
31       workManager_(heap->GetWorkManager()),
32       enableMarkType_(type)
33 {
34     thread_->SetMarkStatus(MarkStatus::READY_TO_MARK);
35 }
36 
EnableConcurrentMarking(EnableConcurrentMarkType type)37 void ConcurrentMarker::EnableConcurrentMarking(EnableConcurrentMarkType type)
38 {
39     if (IsConfigDisabled()) {
40         return;
41     }
42     if (IsEnabled() && !thread_->IsReadyToConcurrentMark() && type == EnableConcurrentMarkType::DISABLE) {
43         enableMarkType_ = EnableConcurrentMarkType::REQUEST_DISABLE;
44     } else {
45         enableMarkType_ = type;
46     }
47 }
48 
MarkRoots()49 void ConcurrentMarker::MarkRoots()
50 {
51     if (heap_->IsYoungMark()) {
52         YoungGCMarkRootVisitor youngGCMarkRootVisitor(workManager_->GetWorkNodeHolder(MAIN_THREAD_INDEX));
53         heap_->GetNonMovableMarker()->MarkRoots(youngGCMarkRootVisitor);
54     } else {
55         OldGCMarkRootVisitor oldGCMarkRootVisitor(workManager_->GetWorkNodeHolder(MAIN_THREAD_INDEX));
56         heap_->GetNonMovableMarker()->MarkRoots(oldGCMarkRootVisitor);
57     }
58 }
59 
Mark()60 void ConcurrentMarker::Mark()
61 {
62     GCStats *gcStats = heap_->GetEcmaVM()->GetEcmaGCStats();
63     RecursionScope recurScope(this);
64     TRACE_GC(GCStats::Scope::ScopeId::ConcurrentMark, gcStats);
65     LOG_GC(DEBUG) << "ConcurrentMarker: Concurrent Marking Begin";
66     ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "ConcurrentMarker::Mark" + std::to_string(heap_->IsFullMarkRequested())
67         + ";Reason" + std::to_string(static_cast<int>(gcStats->GetGCReason()))
68         + ";Sensitive" + std::to_string(static_cast<int>(heap_->GetSensitiveStatus()))
69         + ";IsInBackground" + std::to_string(heap_->IsInBackground())
70         + ";Startup" + std::to_string(static_cast<int>(heap_->GetStartupStatus()))
71         + ";ConMark" + std::to_string(static_cast<int>(heap_->GetJSThread()->GetMarkStatus()))
72         + ";Young" + std::to_string(heap_->GetNewSpace()->GetCommittedSize())
73         + ";Old" + std::to_string(heap_->GetOldSpace()->GetCommittedSize())
74         + ";TotalCommit" + std::to_string(heap_->GetCommittedSize())
75         + ";NativeBindingSize" + std::to_string(heap_->GetNativeBindingSize())
76         + ";NativeLimitSize" + std::to_string(heap_->GetGlobalSpaceNativeLimit()));
77     MEM_ALLOCATE_AND_GC_TRACE(vm_, ConcurrentMarking);
78     ASSERT(runningTaskCount_ == 0);
79     runningTaskCount_.fetch_add(1, std::memory_order_relaxed);
80     InitializeMarking();
81     clockScope_.Reset();
82     runningTaskCount_.fetch_sub(1, std::memory_order_relaxed);
83     heap_->PostParallelGCTask(ParallelGCTaskPhase::CONCURRENT_HANDLE_GLOBAL_POOL_TASK);
84 }
85 
Finish()86 void ConcurrentMarker::Finish()
87 {
88     workManager_->Finish();
89 }
90 
ReMark()91 void ConcurrentMarker::ReMark()
92 {
93     TRACE_GC(GCStats::Scope::ScopeId::ReMark, heap_->GetEcmaVM()->GetEcmaGCStats());
94     LOG_GC(DEBUG) << "ConcurrentMarker: Remarking Begin";
95     MEM_ALLOCATE_AND_GC_TRACE(vm_, ReMarking);
96     Marker *nonMovableMarker = heap_->GetNonMovableMarker();
97     MarkRoots();
98     nonMovableMarker->ProcessMarkStack(MAIN_THREAD_INDEX);
99     heap_->WaitRunningTaskFinished();
100     // MarkJitCodeMap must be call after other mark work finish to make sure which jserror object js alive.
101     nonMovableMarker->MarkJitCodeMap(MAIN_THREAD_INDEX);
102 }
103 
HandleMarkingFinished(GCReason gcReason)104 void ConcurrentMarker::HandleMarkingFinished(GCReason gcReason)  // js-thread wait for sweep
105 {
106     LockHolder lock(waitMarkingFinishedMutex_);
107     ASSERT(markingFinished_);
108     TriggerGCType gcType;
109     if (heap_->IsConcurrentFullMark()) {
110         gcType = TriggerGCType::OLD_GC;
111     } else {
112         gcType = TriggerGCType::YOUNG_GC;
113     }
114     heap_->CollectGarbage(gcType, gcReason);
115 }
116 
WaitMarkingFinished()117 void ConcurrentMarker::WaitMarkingFinished()  // call in EcmaVm thread, wait for mark finished
118 {
119     LockHolder lock(waitMarkingFinishedMutex_);
120     while (!markingFinished_) {
121         waitMarkingFinishedCV_.Wait(&waitMarkingFinishedMutex_);
122     }
123 }
124 
Reset(bool revertCSet)125 void ConcurrentMarker::Reset(bool revertCSet)
126 {
127     ASSERT(runningTaskCount_ == 0);
128     Finish();
129     thread_->SetMarkStatus(MarkStatus::READY_TO_MARK);
130     isConcurrentMarking_ = false;
131     markingFinished_ = false;
132     notifyMarkingFinished_ = false;
133     if (revertCSet) {
134         // Partial gc clear cset when evacuation allocator finalize
135         heap_->GetOldSpace()->RevertCSet();
136         auto callback = [](Region *region) {
137             region->ResetRegionTypeFlag();
138             region->ClearMarkGCBitset();
139             region->ClearCrossRegionRSet();
140             region->ResetAliveObject();
141         };
142         if (heap_->IsConcurrentFullMark()) {
143             heap_->EnumerateRegions(callback);
144         } else {
145             heap_->EnumerateNewSpaceRegions(callback);
146         }
147     }
148 }
149 
InitializeMarking()150 void ConcurrentMarker::InitializeMarking()
151 {
152     MEM_ALLOCATE_AND_GC_TRACE(vm_, ConcurrentMarkingInitialize);
153     heap_->Prepare();
154     ASSERT(VerifyAllRegionsNonFresh());
155     heap_->GetNewSpace()->RecordCurrentRegionAsHalfFresh();
156     isConcurrentMarking_ = true;
157     thread_->SetMarkStatus(MarkStatus::MARKING);
158 
159     if (heap_->IsConcurrentFullMark()) {
160         heapObjectSize_ = heap_->GetHeapObjectSize();
161         heap_->GetOldSpace()->SelectCSet();
162         heap_->GetAppSpawnSpace()->EnumerateRegions([](Region *current) {
163             current->ClearMarkGCBitset();
164             current->ClearCrossRegionRSet();
165         });
166         // The alive object size of Region in OldSpace will be recalculated.
167         heap_->EnumerateNonNewSpaceRegions([](Region *current) {
168             current->ResetAliveObject();
169         });
170     } else {
171         heapObjectSize_ = heap_->GetNewSpace()->GetHeapObjectSize();
172     }
173     workManager_->Initialize(TriggerGCType::OLD_GC, ParallelGCTaskPhase::CONCURRENT_HANDLE_GLOBAL_POOL_TASK);
174     if (heap_->IsYoungMark()) {
175         NonMovableMarker *marker = static_cast<NonMovableMarker*>(heap_->GetNonMovableMarker());
176         {
177             ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "GC::MarkOldToNew");
178             marker->ProcessOldToNewNoMarkStack(MAIN_THREAD_INDEX);
179         }
180         marker->ProcessSnapshotRSetNoMarkStack(MAIN_THREAD_INDEX);
181     }
182     MarkRoots();
183     workManager_->GetWorkNodeHolder(MAIN_THREAD_INDEX)->PushWorkNodeToGlobal(false);
184 }
185 
ShouldNotifyMarkingFinished()186 bool ConcurrentMarker::ShouldNotifyMarkingFinished()
187 {
188     if (runningTaskCount_.fetch_sub(1, std::memory_order_relaxed) != 1) {
189         return false;
190     }
191     return reinterpret_cast<std::atomic<bool>*>(&notifyMarkingFinished_)
192         ->exchange(true, std::memory_order_relaxed) == false;
193 }
194 
FinishMarking()195 void ConcurrentMarker::FinishMarking()
196 {
197     LockHolder lock(waitMarkingFinishedMutex_);
198     ASSERT(!markingFinished_);
199     ASSERT(notifyMarkingFinished_);
200     float spendTime = clockScope_.TotalSpentTime();
201     if (heap_->IsYoungMark()) {
202         heapObjectSize_ = heap_->GetNewSpace()->GetHeapObjectSize();
203     } else if (heap_->IsConcurrentFullMark()) {
204         heapObjectSize_ = heap_->GetHeapObjectSize();
205     }
206     SetDuration(spendTime);
207     if (heap_->IsFullMarkRequested()) {
208         heap_->SetFullMarkRequestedState(false);
209     }
210     thread_->SetMarkStatus(MarkStatus::MARK_FINISHED);
211     thread_->SetCheckSafePointStatus();
212     markingFinished_ = true;
213     waitMarkingFinishedCV_.Signal();
214     DecreaseTaskCounts();
215 }
216 
ProcessConcurrentMarkTask(uint32_t threadId)217 void ConcurrentMarker::ProcessConcurrentMarkTask(uint32_t threadId)
218 {
219     runningTaskCount_.fetch_add(1, std::memory_order_relaxed);
220     heap_->GetNonMovableMarker()->ProcessMarkStack(threadId);
221     if (ShouldNotifyMarkingFinished()) {
222         FinishMarking();
223         heap_->GetIdleGCTrigger()->TryPostHandleMarkFinished();
224     }
225 }
226 
VerifyAllRegionsNonFresh()227 bool ConcurrentMarker::VerifyAllRegionsNonFresh()
228 {
229     bool ok = true;
230     heap_->EnumerateRegions([&ok](Region *region) {
231         ok &= !region->IsFreshRegion() && !region->IsHalfFreshRegion();
232     });
233     return ok;
234 }
235 }  // namespace panda::ecmascript
236