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 #include "ecmascript/mem/incremental_marker.h"
16 #include "ecmascript/mem/parallel_marker-inl.h"
17
18 namespace panda::ecmascript {
Marker(Heap *heap)19 Marker::Marker(Heap *heap) : heap_(heap), workManager_(heap->GetWorkManager()) {}
20
MarkRoots(uint32_t threadId, VMRootVisitType type)21 void Marker::MarkRoots(uint32_t threadId, VMRootVisitType type)
22 {
23 TRACE_GC(GCStats::Scope::ScopeId::MarkRoots, heap_->GetEcmaVM()->GetEcmaGCStats());
24 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "GC::MarkRoots");
25 ObjectXRay::VisitVMRoots(
26 heap_->GetEcmaVM(),
27 [this, threadId](Root type, ObjectSlot slot) {this->HandleRoots(threadId, type, slot);},
28 [this, threadId](Root type, ObjectSlot start, ObjectSlot end) {
29 this->HandleRangeRoots(threadId, type, start, end);
30 },
31 [this](Root type, ObjectSlot base, ObjectSlot derived, uintptr_t baseOldObject) {
32 this->HandleDerivedRoots(type, base, derived, baseOldObject);
33 }, type);
34 workManager_->PushWorkNodeToGlobal(threadId, false);
35 }
36
ProcessNewToEden(uint32_t threadId)37 void Marker::ProcessNewToEden(uint32_t threadId)
38 {
39 heap_->EnumerateNewSpaceRegions([this, threadId](Region *region) {this->HandleNewToEdenRSet(threadId, region);});
40 ProcessMarkStack(threadId);
41 }
42
ProcessNewToEdenNoMarkStack(uint32_t threadId)43 void Marker::ProcessNewToEdenNoMarkStack(uint32_t threadId)
44 {
45 heap_->EnumerateNewSpaceRegions([this, threadId](Region *region) {this->HandleNewToEdenRSet(threadId, region);});
46 }
47
ProcessOldToNew(uint32_t threadId)48 void Marker::ProcessOldToNew(uint32_t threadId)
49 {
50 heap_->EnumerateOldSpaceRegions([this, threadId](Region *region) {
51 this->HandleOldToNewRSet(threadId, region);
52 });
53 ProcessMarkStack(threadId);
54 }
55
ProcessOldToNewNoMarkStack(uint32_t threadId)56 void Marker::ProcessOldToNewNoMarkStack(uint32_t threadId)
57 {
58 heap_->EnumerateOldSpaceRegions([this, threadId](Region *region) {
59 this->HandleOldToNewRSet(threadId, region);
60 });
61 }
62
ProcessOldToNew(uint32_t threadId, Region *region)63 void Marker::ProcessOldToNew(uint32_t threadId, Region *region)
64 {
65 heap_->EnumerateOldSpaceRegions([this, threadId](Region *region) {
66 this->HandleOldToNewRSet(threadId, region);
67 }, region);
68 ProcessMarkStack(threadId);
69 }
70
ProcessSnapshotRSet(uint32_t threadId)71 void Marker::ProcessSnapshotRSet(uint32_t threadId)
72 {
73 heap_->EnumerateSnapshotSpaceRegions([this, threadId](Region *region) {
74 this->HandleOldToNewRSet(threadId, region);
75 });
76 ProcessMarkStack(threadId);
77 }
78
ProcessSnapshotRSetNoMarkStack(uint32_t threadId)79 void Marker::ProcessSnapshotRSetNoMarkStack(uint32_t threadId)
80 {
81 heap_->EnumerateSnapshotSpaceRegions([this, threadId](Region *region) {
82 this->HandleOldToNewRSet(threadId, region);
83 });
84 }
85
MarkJitCodeMap(uint32_t threadId)86 void NonMovableMarker::MarkJitCodeMap(uint32_t threadId)
87 {
88 // To keep MachineCode objects alive (for dump) before JsError object be free, we have to know which JsError is
89 // alive first. So this method must be call after all other mark work finish.
90 TRACE_GC(GCStats::Scope::ScopeId::MarkRoots, heap_->GetEcmaVM()->GetEcmaGCStats());
91 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "GC::MarkJitCodeMap");
92 if (!heap_->IsFullMark()) {
93 return;
94 }
95 JitCodeMapVisitor visitor = [this, threadId](std::map<JSTaggedType, JitCodeVector *> &jitCodeMaps) {
96 auto it = jitCodeMaps.begin();
97 while (it != jitCodeMaps.end()) {
98 JSTaggedType jsError = it->first;
99 Region *objectRegion = Region::ObjectAddressToRange(reinterpret_cast<TaggedObject *>(jsError));
100 if (!objectRegion->Test(reinterpret_cast<TaggedObject *>(jsError))) {
101 ++it;
102 continue;
103 }
104 for (auto &jitCodeMap : *(it->second)) {
105 auto &jitCode = std::get<0>(jitCodeMap);
106 MarkObject(threadId, jitCode);
107 }
108 ++it;
109 }
110 };
111 ObjectXRay::VisitJitCodeMap(heap_->GetEcmaVM(), visitor);
112 ProcessMarkStack(threadId);
113 heap_->WaitRunningTaskFinished();
114 }
115
ProcessMarkStack(uint32_t threadId)116 void NonMovableMarker::ProcessMarkStack(uint32_t threadId)
117 {
118 bool isFullMark = heap_->IsConcurrentFullMark();
119 auto cb = [&](ObjectSlot s, Region *rootRegion, bool needBarrier) {
120 MarkValue(threadId, s, rootRegion, needBarrier);
121 };
122 EcmaObjectRangeVisitor visitor = [this, threadId, isFullMark, cb](TaggedObject *root, ObjectSlot start,
123 ObjectSlot end, VisitObjectArea area) {
124 Region *rootRegion = Region::ObjectAddressToRange(root);
125 bool needBarrier = isFullMark && !rootRegion->InGeneralNewSpaceOrCSet();
126 if (area == VisitObjectArea::IN_OBJECT) {
127 if (VisitBodyInObj(root, start, end, needBarrier, cb)) {
128 return;
129 }
130 }
131 for (ObjectSlot slot = start; slot < end; slot++) {
132 MarkValue(threadId, slot, rootRegion, needBarrier);
133 }
134 };
135 SemiSpace *newSpace = heap_->GetNewSpace();
136 TaggedObject *obj = nullptr;
137 while (workManager_->Pop(threadId, &obj)) {
138 Region *region = Region::ObjectAddressToRange(obj);
139 if (region->IsHalfFreshRegion()) {
140 ASSERT(region->InYoungSpace());
141 if (newSpace->IsFreshObjectInHalfFreshRegion(obj)) {
142 // Fresh object do not need to visit body.
143 continue;
144 }
145 }
146
147 JSHClass *jsHclass = obj->SynchronizedGetClass();
148 ASSERT(!region->IsFreshRegion());
149 auto size = jsHclass->SizeFromJSHClass(obj);
150 region->IncreaseAliveObjectSafe(size);
151 MarkObject(threadId, jsHclass);
152 ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(obj, jsHclass, visitor);
153 }
154 }
155
ProcessIncrementalMarkStack(uint32_t threadId, uint32_t markStepSize)156 void NonMovableMarker::ProcessIncrementalMarkStack(uint32_t threadId, uint32_t markStepSize)
157 {
158 bool isFullMark = heap_->IsConcurrentFullMark();
159 uint32_t visitAddrNum = 0;
160 auto cb = [&](ObjectSlot s, Region *rootRegion, bool needBarrier) {
161 MarkValue(threadId, s, rootRegion, needBarrier);
162 };
163 EcmaObjectRangeVisitor visitor = [this, threadId, isFullMark, &visitAddrNum, cb](TaggedObject *root,
164 ObjectSlot start,
165 ObjectSlot end,
166 VisitObjectArea area) {
167 Region *rootRegion = Region::ObjectAddressToRange(root);
168 visitAddrNum += end.SlotAddress() - start.SlotAddress();
169 bool needBarrier = isFullMark && !rootRegion->InGeneralNewSpaceOrCSet();
170 if (area == VisitObjectArea::IN_OBJECT) {
171 if (VisitBodyInObj(root, start, end, needBarrier, cb)) {
172 return;
173 }
174 }
175 for (ObjectSlot slot = start; slot < end; slot++) {
176 MarkValue(threadId, slot, rootRegion, needBarrier);
177 }
178 };
179 TaggedObject *obj = nullptr;
180 double startTime = heap_->GetIncrementalMarker()->GetCurrentTimeInMs();
181 double costTime = startTime;
182 while (workManager_->Pop(threadId, &obj)) {
183 JSHClass *jsHclass = obj->GetClass();
184 Region *region = Region::ObjectAddressToRange(obj);
185 auto size = jsHclass->SizeFromJSHClass(obj);
186 region->IncreaseAliveObjectSafe(size);
187 MarkObject(threadId, jsHclass);
188 ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(obj, jsHclass, visitor);
189 if (heap_->GetIncrementalMarker()->IsTriggeredIncrementalMark() && visitAddrNum >= markStepSize) {
190 costTime = heap_->GetIncrementalMarker()->GetCurrentTimeInMs() - startTime;
191 heap_->GetIncrementalMarker()->UpdateMarkingSpeed(visitAddrNum, costTime);
192 return;
193 }
194 }
195 if (heap_->GetJSThread()->IsMarking() && heap_->GetIncrementalMarker()->IsTriggeredIncrementalMark()) {
196 costTime = heap_->GetIncrementalMarker()->GetCurrentTimeInMs() - startTime;
197 heap_->GetIncrementalMarker()->UpdateMarkingSpeed(visitAddrNum, costTime);
198 heap_->GetIncrementalMarker()->SetMarkingFinished(true);
199 }
200 }
201
Initialize()202 void SemiGCMarker::Initialize()
203 {
204 waterLine_ = heap_->GetNewSpace()->GetWaterLine();
205 }
206
ProcessMarkStack(uint32_t threadId)207 void SemiGCMarker::ProcessMarkStack(uint32_t threadId)
208 {
209 auto cb = [&](ObjectSlot s, TaggedObject *root) { MarkValue(threadId, root, s); };
210 EcmaObjectRangeVisitor visitor = [this, threadId, cb](TaggedObject *root, ObjectSlot start,
211 ObjectSlot end, VisitObjectArea area) {
212 if (area == VisitObjectArea::IN_OBJECT) {
213 if (VisitBodyInObj(root, start, end, cb)) {
214 return;
215 }
216 }
217 for (ObjectSlot slot = start; slot < end; slot++) {
218 MarkValue(threadId, root, slot);
219 }
220 };
221 TaggedObject *obj = nullptr;
222 while (workManager_->Pop(threadId, &obj)) {
223 auto jsHclass = obj->GetClass();
224 ObjectXRay::VisitObjectBody<VisitType::SEMI_GC_VISIT>(obj, jsHclass, visitor);
225 }
226 }
227
ProcessMarkStack(uint32_t threadId)228 void CompressGCMarker::ProcessMarkStack(uint32_t threadId)
229 {
230 auto cb = [&](ObjectSlot s, [[maybe_unused]] TaggedObject *root) { MarkValue(threadId, s); };
231 EcmaObjectRangeVisitor visitor = [this, threadId, cb](TaggedObject *root, ObjectSlot start,
232 ObjectSlot end, VisitObjectArea area) {
233 if (area == VisitObjectArea::IN_OBJECT) {
234 if (VisitBodyInObj(root, start, end, cb)) {
235 return;
236 }
237 }
238 for (ObjectSlot slot = start; slot < end; slot++) {
239 MarkValue(threadId, slot);
240 }
241 };
242 TaggedObject *obj = nullptr;
243 while (workManager_->Pop(threadId, &obj)) {
244 auto jsHClass = obj->GetClass();
245 ObjectSlot objectSlot(ToUintPtr(obj));
246 MarkObject(threadId, jsHClass, objectSlot);
247 ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(obj, jsHClass, visitor);
248 }
249 }
250
MarkJitCodeMap(uint32_t threadId)251 void CompressGCMarker::MarkJitCodeMap(uint32_t threadId)
252 {
253 // To keep MachineCode objects alive (for dump) before JsError object be free, we have to know which JsError is
254 // alive first. So this method must be call after all other mark work finish.
255 TRACE_GC(GCStats::Scope::ScopeId::MarkRoots, heap_->GetEcmaVM()->GetEcmaGCStats());
256 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "GC::MarkJitCodeMap");
257 ObjectXRay::VisitJitCodeMap(heap_->GetEcmaVM(),
258 [this, threadId](std::map<JSTaggedType, JitCodeVector *> &jitCodeMaps) {
259 this->HandleVisitJitCodeMap(threadId, jitCodeMaps);
260 });
261 ProcessMarkStack(threadId);
262 heap_->WaitRunningTaskFinished();
263 }
264
HandleVisitJitCodeMap(uint32_t threadId, std::map<JSTaggedType, JitCodeVector *> &jitCodeMaps)265 void CompressGCMarker::HandleVisitJitCodeMap(uint32_t threadId, std::map<JSTaggedType, JitCodeVector *> &jitCodeMaps)
266 {
267 auto it = jitCodeMaps.begin();
268 while (it != jitCodeMaps.end()) {
269 JSTaggedType jsError = it->first;
270 auto jsErrorObj = reinterpret_cast<TaggedObject *>(jsError);
271 Region *objectRegion = Region::ObjectAddressToRange(jsErrorObj);
272 auto jitCodeVec = it->second;
273 if (!NeedEvacuate(objectRegion)) {
274 if (!objectRegion->InSharedHeap() && !objectRegion->Test(jsErrorObj)) {
275 delete it->second;
276 it = jitCodeMaps.erase(it);
277 continue;
278 }
279 } else {
280 MarkWord markWord(jsErrorObj);
281 if (markWord.IsForwardingAddress()) {
282 TaggedObject *dst = markWord.ToForwardingAddress();
283 jitCodeMaps.emplace(JSTaggedValue(dst).GetRawData(), it->second);
284 it = jitCodeMaps.erase(it);
285 } else {
286 delete it->second;
287 it = jitCodeMaps.erase(it);
288 continue;
289 }
290 }
291 for (auto &jitCodeMap : *jitCodeVec) {
292 auto &jitCode = std::get<0>(jitCodeMap);
293 auto obj = static_cast<TaggedObject *>(jitCode);
294 // jitcode is MachineCode, and MachineCode is in the MachineCode space, will not be evacute.
295 MarkObject(threadId, obj, ObjectSlot(reinterpret_cast<uintptr_t>(&jitCode)));
296 }
297 ++it;
298 }
299 }
300
AllocateForwardAddress(uint32_t threadId, size_t size, JSHClass *hclass, TaggedObject *object)301 uintptr_t CompressGCMarker::AllocateForwardAddress(uint32_t threadId, size_t size, JSHClass *hclass,
302 TaggedObject *object)
303 {
304 if (!isAppSpawn_) {
305 bool isPromoted = true;
306 return AllocateDstSpace(threadId, size, isPromoted);
307 }
308 if (Heap::ShouldMoveToRoSpace(hclass, object)) {
309 return AllocateReadOnlySpace(size);
310 } else {
311 return AllocateAppSpawnSpace(size);
312 }
313 }
314 } // namespace panda::ecmascript
315