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/stw_young_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/heap-inl.h"
22 #include "ecmascript/mem/mark_stack.h"
23 #include "ecmascript/mem/mem.h"
24 #include "ecmascript/mem/parallel_marker-inl.h"
25 #include "ecmascript/mem/space-inl.h"
26 #include "ecmascript/mem/tlab_allocator-inl.h"
27 #include "ecmascript/mem/visitor.h"
28 #include "ecmascript/mem/gc_stats.h"
29 #include "ecmascript/ecma_string_table.h"
30 #include "ecmascript/runtime_call_id.h"
31
32 namespace panda::ecmascript {
STWYoungGC(Heap * heap,bool parallelGC)33 STWYoungGC::STWYoungGC(Heap *heap, bool parallelGC)
34 : heap_(heap), parallelGC_(parallelGC), workManager_(heap->GetWorkManager())
35 {
36 }
37
RunPhases()38 void STWYoungGC::RunPhases()
39 {
40 MEM_ALLOCATE_AND_GC_TRACE(heap_->GetEcmaVM(), STWYoungGC_RunPhases);
41 [[maybe_unused]] ClockScope clockScope;
42
43 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "STWYoungGC::RunPhases");
44 if (heap_->CheckOngoingConcurrentMarking()) {
45 LOG_GC(DEBUG) << "STWYoungGC after ConcurrentMarking";
46 heap_->GetConcurrentMarker()->Reset(); // HPPGC use mark result to move TaggedObject.
47 }
48 Initialize();
49 Mark();
50 Sweep();
51 Finish();
52 heap_->GetEcmaVM()->GetEcmaGCStats()->StatisticSTWYoungGC(clockScope.GetPauseTime(), semiCopiedSize_,
53 promotedSize_, commitSize_);
54 LOG_GC(DEBUG) << "STWYoungGC::RunPhases " << clockScope.TotalSpentTime();
55 }
56
Initialize()57 void STWYoungGC::Initialize()
58 {
59 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "STWYoungGC::Initialize");
60 heap_->Prepare();
61 commitSize_ = heap_->GetNewSpace()->GetCommittedSize();
62 heap_->SwapNewSpace();
63 workManager_->Initialize(TriggerGCType::YOUNG_GC, ParallelGCTaskPhase::SEMI_HANDLE_GLOBAL_POOL_TASK);
64 heap_->GetSemiGCMarker()->Initialize();
65 promotedSize_ = 0;
66 semiCopiedSize_ = 0;
67 }
68
Mark()69 void STWYoungGC::Mark()
70 {
71 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "STWYoungGC::Mark");
72 auto region = heap_->GetOldSpace()->GetCurrentRegion();
73
74 if (parallelGC_) {
75 heap_->PostParallelGCTask(ParallelGCTaskPhase::SEMI_HANDLE_THREAD_ROOTS_TASK);
76 heap_->PostParallelGCTask(ParallelGCTaskPhase::SEMI_HANDLE_SNAPSHOT_TASK);
77 heap_->GetSemiGCMarker()->ProcessOldToNew(0, region);
78 } else {
79 heap_->GetSemiGCMarker()->ProcessOldToNew(0, region);
80 heap_->GetSemiGCMarker()->ProcessSnapshotRSet(MAIN_THREAD_INDEX);
81 heap_->GetSemiGCMarker()->MarkRoots(MAIN_THREAD_INDEX);
82 heap_->GetSemiGCMarker()->ProcessMarkStack(MAIN_THREAD_INDEX);
83 }
84 heap_->WaitRunningTaskFinished();
85
86 auto totalThreadCount = Taskpool::GetCurrentTaskpool()->GetTotalThreadNum() + 1; // gc thread and main thread
87 for (uint32_t i = 0; i < totalThreadCount; i++) {
88 SlotNeedUpdate needUpdate(nullptr, ObjectSlot(0));
89 while (workManager_->GetSlotNeedUpdate(i, &needUpdate)) {
90 UpdatePromotedSlot(needUpdate.first, needUpdate.second);
91 }
92 }
93 }
94
Sweep()95 void STWYoungGC::Sweep()
96 {
97 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "STWYoungGC::Sweep");
98 auto totalThreadCount = static_cast<uint32_t>(
99 Taskpool::GetCurrentTaskpool()->GetTotalThreadNum() + 1); // gc thread and main thread
100 for (uint32_t i = 0; i < totalThreadCount; i++) {
101 ProcessQueue *queue = workManager_->GetWeakReferenceQueue(i);
102 while (true) {
103 auto obj = queue->PopBack();
104 if (UNLIKELY(obj == nullptr)) {
105 break;
106 }
107 ObjectSlot slot(ToUintPtr(obj));
108 JSTaggedValue value(slot.GetTaggedType());
109 auto header = value.GetTaggedWeakRef();
110 MarkWord markWord(header);
111 if (markWord.IsForwardingAddress()) {
112 TaggedObject *dst = markWord.ToForwardingAddress();
113 auto weakRef = JSTaggedValue(JSTaggedValue(dst).CreateAndGetWeakRef()).GetRawTaggedObject();
114 slot.Update(weakRef);
115 } else {
116 slot.Clear();
117 }
118 }
119 }
120
121 auto stringTable = heap_->GetEcmaVM()->GetEcmaStringTable();
122 WeakRootVisitor gcUpdateWeak = [](TaggedObject *header) {
123 Region *objectRegion = Region::ObjectAddressToRange(reinterpret_cast<TaggedObject *>(header));
124 if (!objectRegion->InYoungSpace()) {
125 return header;
126 }
127
128 MarkWord markWord(header);
129 if (markWord.IsForwardingAddress()) {
130 TaggedObject *dst = markWord.ToForwardingAddress();
131 return dst;
132 }
133 return reinterpret_cast<TaggedObject *>(ToUintPtr(nullptr));
134 };
135 stringTable->SweepWeakReference(gcUpdateWeak);
136 heap_->GetEcmaVM()->GetJSThread()->IterateWeakEcmaGlobalStorage(gcUpdateWeak);
137 heap_->GetEcmaVM()->ProcessReferences(gcUpdateWeak);
138 }
139
Finish()140 void STWYoungGC::Finish()
141 {
142 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "STWYoungGC::Finish");
143 workManager_->Finish(semiCopiedSize_, promotedSize_);
144 heap_->Resume(YOUNG_GC);
145 }
146 } // namespace panda::ecmascript
147