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/allocator-inl.h"
19 #include "ecmascript/mem/clock_scope.h"
20 #include "ecmascript/mem/heap-inl.h"
21 #include "ecmascript/mem/mark_stack.h"
22 #include "ecmascript/mem/object_xray-inl.h"
23 #include "ecmascript/mem/mark_word.h"
24 #include "ecmascript/mem/parallel_marker-inl.h"
25 #include "ecmascript/mem/space-inl.h"
26 #include "ecmascript/mem/verification.h"
27 #include "ecmascript/platform/platform.h"
28 #include "ecmascript/runtime_call_id.h"
29 #include "os/mutex.h"
30
31 namespace panda::ecmascript {
ConcurrentMarker(Heap * heap)32 ConcurrentMarker::ConcurrentMarker(Heap *heap)
33 : heap_(heap),
34 vm_(heap->GetEcmaVM()),
35 thread_(vm_->GetJSThread()),
36 workList_(heap->GetWorkList())
37 {
38 thread_->SetMarkStatus(MarkStatus::READY_TO_MARK);
39 }
40
ConcurrentMarking()41 void ConcurrentMarker::ConcurrentMarking()
42 {
43 ECMA_GC_LOG() << "ConcurrentMarker: Concurrent Mark Begin";
44 ECMA_BYTRACE_NAME(BYTRACE_TAG_ARK, "ConcurrentMarker::ConcurrentMarking");
45 MEM_ALLOCATE_AND_GC_TRACE(vm_, ConcurrentMarking);
46 ClockScope scope;
47 InitializeMarking();
48 Platform::GetCurrentPlatform()->PostTask(std::make_unique<MarkerTask>(heap_));
49 if (!heap_->IsFullMark() && heap_->IsParallelGCEnabled()) {
50 heap_->PostParallelGCTask(ParallelGCTaskPhase::CONCURRENT_HANDLE_OLD_TO_NEW_TASK);
51 }
52 heap_->GetEcmaVM()->GetEcmaGCStats()->StatisticConcurrentMark(scope.GetPauseTime());
53 }
54
FinishPhase()55 void ConcurrentMarker::FinishPhase()
56 {
57 size_t aliveSize = 0;
58 workList_->Finish(aliveSize);
59 }
60
ReMarking()61 void ConcurrentMarker::ReMarking()
62 {
63 ECMA_GC_LOG() << "ConcurrentMarker: Remarking Begin";
64 MEM_ALLOCATE_AND_GC_TRACE(vm_, ReMarking);
65 ClockScope scope;
66 Marker *nonMoveMarker = heap_->GetNonMovableMarker();
67 nonMoveMarker->MarkRoots(0);
68 if (!heap_->IsFullMark() && !heap_->IsParallelGCEnabled()) {
69 heap_->GetNonMovableMarker()->ProcessOldToNew(0);
70 } else {
71 nonMoveMarker->ProcessMarkStack(0);
72 }
73 heap_->WaitRunningTaskFinished();
74 heap_->GetEcmaVM()->GetEcmaGCStats()->StatisticConcurrentRemark(scope.GetPauseTime());
75 }
76
HandleMarkFinished()77 void ConcurrentMarker::HandleMarkFinished() // js-thread wait for sweep
78 {
79 os::memory::LockHolder lock(waitMarkingFinishedMutex_);
80 if (notifyMarkingFinished_) {
81 heap_->CollectGarbage(TriggerGCType::SEMI_GC);
82 }
83 }
84
WaitConcurrentMarkingFinished()85 void ConcurrentMarker::WaitConcurrentMarkingFinished() // call in EcmaVm thread, wait for mark finished
86 {
87 os::memory::LockHolder lock(waitMarkingFinishedMutex_);
88 if (!notifyMarkingFinished_) {
89 vmThreadWaitMarkingFinished_ = true;
90 waitMarkingFinishedCV_.Wait(&waitMarkingFinishedMutex_);
91 }
92 }
93
Reset(bool isRevertCSet)94 void ConcurrentMarker::Reset(bool isRevertCSet)
95 {
96 FinishPhase();
97 thread_->SetMarkStatus(MarkStatus::READY_TO_MARK);
98 notifyMarkingFinished_ = false;
99 if (isRevertCSet) {
100 // Mix space gc clear cset when evacuation allocator finalize
101 heap_->GetOldSpace()->RevertCSet();
102 auto callback = [](Region *region) {
103 region->ClearMarkBitmap();
104 region->ClearCrossRegionRememberedSet();
105 };
106 if (heap_->IsFullMark()) {
107 heap_->EnumerateRegions(callback);
108 } else {
109 heap_->EnumerateNewSpaceRegions(callback);
110 }
111 }
112 }
113
114 // -------------------- privete method ------------------------------------------
InitializeMarking()115 void ConcurrentMarker::InitializeMarking()
116 {
117 MEM_ALLOCATE_AND_GC_TRACE(vm_, ConcurrentMarkingInitialize);
118 heap_->Prepare();
119 thread_->SetMarkStatus(MarkStatus::MARKING);
120
121 if (heap_->IsFullMark()) {
122 heapObjectSize_ = heap_->GetHeapObjectSize();
123 heap_->GetOldSpace()->SelectCSet();
124 // The alive object size of Region in OldSpace will be recompute
125 heap_->EnumerateNonNewSpaceRegions([this](Region *current) {
126 current->ResetAliveObject();
127 });
128 } else {
129 heapObjectSize_ = heap_->GetNewSpace()->GetHeapObjectSize();
130 }
131 workList_->Initialize(TriggerGCType::OLD_GC, ParallelGCTaskPhase::CONCURRENT_HANDLE_GLOBAL_POOL_TASK);
132 heap_->GetNonMovableMarker()->MarkRoots(0);
133 }
134
Run(uint32_t threadId)135 bool ConcurrentMarker::MarkerTask::Run(uint32_t threadId)
136 {
137 ClockScope clockScope;
138 heap_->GetNonMovableMarker()->ProcessMarkStack(threadId);
139 heap_->WaitRunningTaskFinished();
140 heap_->GetConcurrentMarker()->MarkingFinished(clockScope.TotalSpentTime());
141 return true;
142 }
143
MarkingFinished(float spendTime)144 void ConcurrentMarker::MarkingFinished(float spendTime)
145 {
146 os::memory::LockHolder lock(waitMarkingFinishedMutex_);
147 thread_->SetMarkStatus(MarkStatus::MARK_FINISHED);
148 if (vmThreadWaitMarkingFinished_) {
149 vmThreadWaitMarkingFinished_ = false;
150 waitMarkingFinishedCV_.Signal();
151 }
152 notifyMarkingFinished_ = true;
153 if (!heap_->IsFullMark()) {
154 heapObjectSize_ = heap_->GetNewSpace()->GetHeapObjectSize();
155 } else {
156 heapObjectSize_ = heap_->GetHeapObjectSize();
157 }
158 SetDuration(spendTime);
159 }
160 } // namespace panda::ecmascript
161