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/parallel_marker.h"
17
18 #include "ecmascript/js_hclass-inl.h"
19 #include "ecmascript/mem/object_xray.h"
20
21 #include "ecmascript/mem/incremental_marker.h"
22 #include "ecmascript/mem/incremental_gc_visitor-inl.h"
23 #include "ecmascript/mem/old_gc_visitor-inl.h"
24 #include "ecmascript/mem/young_gc_visitor-inl.h"
25 #include "ecmascript/mem/full_gc-inl.h"
26
27 namespace panda::ecmascript {
Marker(Heap * heap)28 Marker::Marker(Heap *heap) : heap_(heap), workManager_(heap->GetWorkManager()) {}
29
MarkRoots(RootVisitor & rootVisitor,VMRootVisitType type)30 void Marker::MarkRoots(RootVisitor &rootVisitor, VMRootVisitType type)
31 {
32 TRACE_GC(GCStats::Scope::ScopeId::MarkRoots, heap_->GetEcmaVM()->GetEcmaGCStats());
33 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "GC::MarkRoots");
34 ObjectXRay::VisitVMRoots(heap_->GetEcmaVM(), rootVisitor, type);
35 }
36
ProcessOldToNew(uint32_t threadId)37 void NonMovableMarker::ProcessOldToNew(uint32_t threadId)
38 {
39 ASSERT(heap_->IsYoungMark());
40 YoungGCMarkOldToNewRSetVisitor youngGCMarkOldToNewRSetVisitor(workManager_->GetWorkNodeHolder(threadId));
41 heap_->EnumerateOldSpaceRegions(youngGCMarkOldToNewRSetVisitor);
42 ProcessMarkStack(threadId);
43 }
44
ProcessOldToNewNoMarkStack(uint32_t threadId)45 void NonMovableMarker::ProcessOldToNewNoMarkStack(uint32_t threadId)
46 {
47 ASSERT(heap_->IsYoungMark());
48 YoungGCMarkOldToNewRSetVisitor youngGCMarkOldToNewRSetVisitor(workManager_->GetWorkNodeHolder(threadId));
49 heap_->EnumerateOldSpaceRegions(youngGCMarkOldToNewRSetVisitor);
50 }
51
ProcessSnapshotRSet(uint32_t threadId)52 void NonMovableMarker::ProcessSnapshotRSet(uint32_t threadId)
53 {
54 ASSERT(heap_->IsYoungMark());
55 YoungGCMarkOldToNewRSetVisitor youngGCMarkOldToNewRSetVisitor(workManager_->GetWorkNodeHolder(threadId));
56 heap_->EnumerateSnapshotSpaceRegions(youngGCMarkOldToNewRSetVisitor);
57 ProcessMarkStack(threadId);
58 }
59
ProcessSnapshotRSetNoMarkStack(uint32_t threadId)60 void NonMovableMarker::ProcessSnapshotRSetNoMarkStack(uint32_t threadId)
61 {
62 ASSERT(heap_->IsYoungMark());
63 YoungGCMarkOldToNewRSetVisitor youngGCMarkOldToNewRSetVisitor(workManager_->GetWorkNodeHolder(threadId));
64 heap_->EnumerateSnapshotSpaceRegions(youngGCMarkOldToNewRSetVisitor);
65 }
66
MarkJitCodeMap(uint32_t threadId)67 void NonMovableMarker::MarkJitCodeMap(uint32_t threadId)
68 {
69 // To keep MachineCode objects alive (for dump) before JsError object be free, we have to know which JsError is
70 // alive first. So this method must be call after all other mark work finish.
71 TRACE_GC(GCStats::Scope::ScopeId::MarkRoots, heap_->GetEcmaVM()->GetEcmaGCStats());
72 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "GC::MarkJitCodeMap");
73 if (!heap_->IsFullMark()) {
74 return;
75 }
76 OldGCMarkObjectVisitor objectVisitor(workManager_->GetWorkNodeHolder(threadId));
77 JitCodeMapVisitor visitor = [&objectVisitor](std::map<JSTaggedType, JitCodeVector *> &jitCodeMaps) {
78 auto it = jitCodeMaps.begin();
79 while (it != jitCodeMaps.end()) {
80 JSTaggedType jsError = it->first;
81 Region *objectRegion = Region::ObjectAddressToRange(reinterpret_cast<TaggedObject *>(jsError));
82 if (!objectRegion->Test(reinterpret_cast<TaggedObject *>(jsError))) {
83 ++it;
84 continue;
85 }
86 for (auto &jitCodeMap : *(it->second)) {
87 auto &jitCode = std::get<0>(jitCodeMap);
88 objectVisitor.HandleObject(jitCode, Region::ObjectAddressToRange(jitCode));
89 }
90 ++it;
91 }
92 };
93 ObjectXRay::VisitJitCodeMap(heap_->GetEcmaVM(), visitor);
94 ProcessMarkStack(threadId);
95 heap_->WaitRunningTaskFinished();
96 }
97
ProcessMarkStack(uint32_t threadId)98 void NonMovableMarker::ProcessMarkStack(uint32_t threadId)
99 {
100 if (heap_->IsYoungMark()) {
101 ProcessYoungGCMarkStack(threadId);
102 } else {
103 ProcessOldGCMarkStack(threadId);
104 }
105 }
106
ProcessYoungGCMarkStack(uint32_t threadId)107 void NonMovableMarker::ProcessYoungGCMarkStack(uint32_t threadId)
108 {
109 WorkNodeHolder *workNodeHolder = workManager_->GetWorkNodeHolder(threadId);
110 YoungGCMarkObjectVisitor youngGCMarkObjectVisitor(workNodeHolder);
111 SemiSpace *newSpace = heap_->GetNewSpace();
112 TaggedObject *obj = nullptr;
113 while (workNodeHolder->Pop(&obj)) {
114 Region *region = Region::ObjectAddressToRange(obj);
115 if (region->IsHalfFreshRegion()) {
116 ASSERT(region->InYoungSpace());
117 if (newSpace->IsFreshObjectInHalfFreshRegion(obj)) {
118 // Fresh object do not need to visit body.
119 continue;
120 }
121 }
122
123 JSHClass *jsHclass = obj->SynchronizedGetClass();
124 ASSERT(!region->IsFreshRegion());
125 auto size = jsHclass->SizeFromJSHClass(obj);
126 region->IncreaseAliveObject(size);
127
128 ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(obj, jsHclass, youngGCMarkObjectVisitor);
129 }
130 }
131
ProcessOldGCMarkStack(uint32_t threadId)132 void NonMovableMarker::ProcessOldGCMarkStack(uint32_t threadId)
133 {
134 WorkNodeHolder *workNodeHolder = workManager_->GetWorkNodeHolder(threadId);
135 OldGCMarkObjectVisitor oldGCMarkObjectVisitor(workNodeHolder);
136 SemiSpace *newSpace = heap_->GetNewSpace();
137 TaggedObject *obj = nullptr;
138 while (workNodeHolder->Pop(&obj)) {
139 Region *region = Region::ObjectAddressToRange(obj);
140 if (region->IsHalfFreshRegion()) {
141 ASSERT(region->InYoungSpace());
142 if (newSpace->IsFreshObjectInHalfFreshRegion(obj)) {
143 // Fresh object do not need to visit body.
144 continue;
145 }
146 }
147
148 JSHClass *jsHclass = obj->SynchronizedGetClass();
149 ASSERT(!region->IsFreshRegion());
150 auto size = jsHclass->SizeFromJSHClass(obj);
151 region->IncreaseAliveObject(size);
152
153 oldGCMarkObjectVisitor.VisitHClass(jsHclass);
154 ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(obj, jsHclass, oldGCMarkObjectVisitor);
155 }
156 }
157
ProcessIncrementalMarkStack(uint32_t threadId,uint32_t markStepSize)158 void NonMovableMarker::ProcessIncrementalMarkStack(uint32_t threadId, uint32_t markStepSize)
159 {
160 ASSERT(heap_->IsConcurrentFullMark());
161 WorkNodeHolder *workNodeHolder = workManager_->GetWorkNodeHolder(threadId);
162 uint32_t visitAddrNum = 0;
163 IncrementalOldGCMarkObjectVisitor incrementalOldGCMarkObjectVisitor(workNodeHolder, visitAddrNum);
164 TaggedObject *obj = nullptr;
165 double startTime = heap_->GetIncrementalMarker()->GetCurrentTimeInMs();
166 double costTime = startTime;
167 while (workNodeHolder->Pop(&obj)) {
168 JSHClass *jsHclass = obj->GetClass();
169 Region *region = Region::ObjectAddressToRange(obj);
170 auto size = jsHclass->SizeFromJSHClass(obj);
171 region->IncreaseAliveObject(size);
172 incrementalOldGCMarkObjectVisitor.VisitHClass(jsHclass);
173 ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(obj, jsHclass, incrementalOldGCMarkObjectVisitor);
174 if (heap_->GetIncrementalMarker()->IsTriggeredIncrementalMark() && visitAddrNum >= markStepSize) {
175 costTime = heap_->GetIncrementalMarker()->GetCurrentTimeInMs() - startTime;
176 heap_->GetIncrementalMarker()->UpdateMarkingSpeed(visitAddrNum, costTime);
177 return;
178 }
179 }
180 if (heap_->GetJSThread()->IsMarking() && heap_->GetIncrementalMarker()->IsTriggeredIncrementalMark()) {
181 costTime = heap_->GetIncrementalMarker()->GetCurrentTimeInMs() - startTime;
182 heap_->GetIncrementalMarker()->UpdateMarkingSpeed(visitAddrNum, costTime);
183 heap_->GetIncrementalMarker()->SetMarkingFinished(true);
184 }
185 }
186
ProcessMarkStack(uint32_t threadId)187 void CompressGCMarker::ProcessMarkStack(uint32_t threadId)
188 {
189 WorkNodeHolder *workNodeHolder = workManager_->GetWorkNodeHolder(threadId);
190 FullGCRunner fullGCRunner(heap_, workNodeHolder, isAppSpawn_);
191 FullGCMarkObjectVisitor &fullGCMarkObjectVisitor = fullGCRunner.GetMarkObjectVisitor();
192 TaggedObject *obj = nullptr;
193 while (workNodeHolder->Pop(&obj)) {
194 auto jsHClass = obj->GetClass();
195 ObjectSlot hClassSlot(ToUintPtr(obj));
196 fullGCMarkObjectVisitor.VisitHClassSlot(hClassSlot, jsHClass);
197 ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(obj, jsHClass, fullGCMarkObjectVisitor);
198 }
199 }
200
MarkJitCodeMap(uint32_t threadId)201 void CompressGCMarker::MarkJitCodeMap(uint32_t threadId)
202 {
203 // To keep MachineCode objects alive (for dump) before JsError object be free, we have to know which JsError is
204 // alive first. So this method must be call after all other mark work finish.
205 TRACE_GC(GCStats::Scope::ScopeId::MarkRoots, heap_->GetEcmaVM()->GetEcmaGCStats());
206 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "GC::MarkJitCodeMap");
207 FullGCRunner fullGCRunner(heap_, workManager_->GetWorkNodeHolder(threadId), isAppSpawn_);
208 JitCodeMapVisitor visitor = [&fullGCRunner] (std::map<JSTaggedType, JitCodeVector *> &jitCodeMaps) {
209 auto it = jitCodeMaps.begin();
210 while (it != jitCodeMaps.end()) {
211 JSTaggedType jsError = it->first;
212 auto jsErrorObj = reinterpret_cast<TaggedObject *>(jsError);
213 Region *objectRegion = Region::ObjectAddressToRange(jsErrorObj);
214 auto jitCodeVec = it->second;
215 if (!fullGCRunner.NeedEvacuate(objectRegion)) {
216 if (!objectRegion->InSharedHeap() && !objectRegion->Test(jsErrorObj)) {
217 delete it->second;
218 it = jitCodeMaps.erase(it);
219 continue;
220 }
221 } else {
222 MarkWord markWord(jsErrorObj);
223 if (markWord.IsForwardingAddress()) {
224 TaggedObject *dst = markWord.ToForwardingAddress();
225 jitCodeMaps.emplace(JSTaggedValue(dst).GetRawData(), it->second);
226 it = jitCodeMaps.erase(it);
227 } else {
228 delete it->second;
229 it = jitCodeMaps.erase(it);
230 continue;
231 }
232 }
233 for (auto &jitCodeMap : *jitCodeVec) {
234 auto &jitCode = std::get<0>(jitCodeMap);
235 auto obj = static_cast<TaggedObject *>(jitCode);
236 // jitcode is MachineCode, and MachineCode is in the MachineCode space, will not be evacute.
237 fullGCRunner.HandleMarkingSlotObject(ObjectSlot(reinterpret_cast<uintptr_t>(&jitCode)), obj);
238 }
239 ++it;
240 }
241 };
242 ObjectXRay::VisitJitCodeMap(heap_->GetEcmaVM(), visitor);
243 ProcessMarkStack(threadId);
244 heap_->WaitRunningTaskFinished();
245 }
246 } // namespace panda::ecmascript
247