• 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/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