1 /*
2 * Copyright (c) 2024 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/shared_heap/shared_gc_marker-inl.h"
17
18 #include "ecmascript/mem/object_xray.h"
19 #include "ecmascript/runtime.h"
20
21 namespace panda::ecmascript {
MarkRoots(uint32_t threadId, SharedMarkType markType, VMRootVisitType type)22 void SharedGCMarkerBase::MarkRoots(uint32_t threadId, SharedMarkType markType, VMRootVisitType type)
23 {
24 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGCMarkerBase::MarkRoots");
25 MarkSerializeRoots(threadId);
26 MarkSharedModule(threadId);
27 MarkStringCache(threadId);
28 Runtime *runtime = Runtime::GetInstance();
29 if (markType != SharedMarkType::CONCURRENT_MARK_REMARK) {
30 // The approximate size is enough, because even if some thread creates and registers after here, it will keep
31 // waiting in transition to RUNNING state before JSThread::SetReadyForGCIterating.
32 rSetHandlers_.reserve(runtime->ApproximateThreadListSize());
33 ASSERT(rSetHandlers_.empty());
34 }
35 runtime->GCIterateThreadList([&](JSThread *thread) {
36 ASSERT(!thread->IsInRunningState());
37 auto vm = thread->GetEcmaVM();
38 MarkLocalVMRoots(threadId, vm, markType, type);
39 if (markType != SharedMarkType::CONCURRENT_MARK_REMARK) {
40 CollectLocalVMRSet(vm);
41 }
42 });
43 }
44
MarkLocalVMRoots(uint32_t threadId, EcmaVM *localVm, SharedMarkType markType, VMRootVisitType type)45 void SharedGCMarkerBase::MarkLocalVMRoots(uint32_t threadId, EcmaVM *localVm, SharedMarkType markType,
46 VMRootVisitType type)
47 {
48 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGCMarkerBase::MarkLocalVMRoots");
49 Heap *heap = const_cast<Heap*>(localVm->GetHeap());
50 if (markType != SharedMarkType::CONCURRENT_MARK_REMARK) {
51 heap->GetSweeper()->EnsureAllTaskFinished();
52 }
53 ObjectXRay::VisitVMRoots(
54 localVm,
55 [this, threadId](Root type, ObjectSlot slot) {this->HandleLocalRoots(threadId, type, slot);},
56 [this, threadId](Root type, ObjectSlot start, ObjectSlot end) {
57 this->HandleLocalRangeRoots(threadId, type, start, end);
58 },
59 [this](Root type, ObjectSlot base, ObjectSlot derived, uintptr_t baseOldObject) {
60 this->HandleLocalDerivedRoots(type, base, derived, baseOldObject);
61 }, type);
62 heap->ProcessSharedGCMarkingLocalBuffer();
63 }
64
CollectLocalVMRSet(EcmaVM *localVm)65 void SharedGCMarkerBase::CollectLocalVMRSet(EcmaVM *localVm)
66 {
67 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGCMarkerBase::CollectLocalVMRSet");
68 Heap *heap = const_cast<Heap*>(localVm->GetHeap());
69 RSetWorkListHandler *handler = new RSetWorkListHandler(heap);
70 heap->SetRSetWorkListHandler(handler);
71 rSetHandlers_.emplace_back(handler);
72 }
73
MarkSerializeRoots(uint32_t threadId)74 void SharedGCMarkerBase::MarkSerializeRoots(uint32_t threadId)
75 {
76 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGCMarkerBase::MarkSerializeRoots");
77 auto callback = [this, threadId](Root type, ObjectSlot slot) {this->HandleRoots(threadId, type, slot);};
78 Runtime::GetInstance()->IterateSerializeRoot(callback);
79 }
80
MarkStringCache(uint32_t threadId)81 void SharedGCMarkerBase::MarkStringCache(uint32_t threadId)
82 {
83 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGCMarkerBase::MarkStringCache");
84 auto cacheStringCallback = [this, threadId](Root type, ObjectSlot start, ObjectSlot end) {
85 this->HandleLocalRangeRoots(threadId, type, start, end);
86 };
87 Runtime::GetInstance()->IterateCachedStringRoot(cacheStringCallback);
88 }
89
MarkSharedModule(uint32_t threadId)90 void SharedGCMarkerBase::MarkSharedModule(uint32_t threadId)
91 {
92 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGCMarkerBase::MarkSharedModule");
93 auto visitor = [this, threadId](Root type, ObjectSlot slot) {this->HandleRoots(threadId, type, slot);};
94 SharedModuleManager::GetInstance()->Iterate(visitor);
95 }
96
ProcessMarkStack(uint32_t threadId)97 void SharedGCMarker::ProcessMarkStack(uint32_t threadId)
98 {
99 #ifndef NDEBUG
100 DaemonThread *dThread = DaemonThread::GetInstance();
101 if (UNLIKELY(!dThread->IsRunning())) {
102 // This DAEMON_THREAD_INDEX not means in daemon thread, but the daemon thread is terminated, and
103 // SharedGC is directly running in the current js thread, this maybe happen only AppSpawn
104 // trigger GC after PreFork (which is not expected), and at this time ParallelGC is disabled
105 ASSERT(threadId == DAEMON_THREAD_INDEX);
106 } else {
107 if (os::thread::GetCurrentThreadId() != dThread->GetThreadId()) {
108 ASSERT(threadId != 0);
109 } else {
110 ASSERT(threadId == 0);
111 }
112 }
113 #endif
114 auto cb = [&](ObjectSlot slot) {
115 MarkValue(threadId, slot);
116 };
117 EcmaObjectRangeVisitor visitor = [this, threadId, cb](TaggedObject *root, ObjectSlot start, ObjectSlot end,
118 VisitObjectArea area) {
119 if (area == VisitObjectArea::IN_OBJECT) {
120 if (VisitBodyInObj(root, start, end, cb)) {
121 return;
122 }
123 }
124 for (ObjectSlot slot = start; slot < end; slot++) {
125 MarkValue(threadId, slot);
126 }
127 };
128 TaggedObject *obj = nullptr;
129 while (true) {
130 obj = nullptr;
131 if (!sWorkManager_->Pop(threadId, &obj)) {
132 break;
133 }
134 JSHClass *hclass = obj->SynchronizedGetClass();
135 auto size = hclass->SizeFromJSHClass(obj);
136 Region *region = Region::ObjectAddressToRange(obj);
137 ASSERT(region->InSharedSweepableSpace());
138 region->IncreaseAliveObjectSafe(size);
139 ObjectSlot objectSlot(ToUintPtr(obj));
140 MarkObject(threadId, hclass, objectSlot);
141 ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(obj, hclass, visitor);
142 }
143 }
144
ProcessMarkStack(uint32_t threadId)145 void SharedGCMovableMarker::ProcessMarkStack(uint32_t threadId)
146 {
147 #ifndef NDEBUG
148 DaemonThread *dThread = DaemonThread::GetInstance();
149 if (UNLIKELY(!dThread->IsRunning())) {
150 // This DAEMON_THREAD_INDEX not means in daemon thread, but the daemon thread is terminated, and
151 // SharedGC is directly running in the current js thread, this maybe happen only AppSpawn
152 // trigger GC after PreFork (which is not expected), and at this time ParallelGC is disabled
153 ASSERT(threadId == DAEMON_THREAD_INDEX);
154 } else {
155 if (os::thread::GetCurrentThreadId() != dThread->GetThreadId()) {
156 ASSERT(threadId != 0);
157 } else {
158 ASSERT(threadId == 0);
159 }
160 }
161 #endif
162 auto cb = [&](ObjectSlot slot) {
163 MarkValue(threadId, slot);
164 };
165 EcmaObjectRangeVisitor visitor = [this, threadId, cb](TaggedObject *root, ObjectSlot start, ObjectSlot end,
166 VisitObjectArea area) {
167 if (area == VisitObjectArea::IN_OBJECT) {
168 if (VisitBodyInObj(root, start, end, cb)) {
169 return;
170 }
171 }
172 for (ObjectSlot slot = start; slot < end; slot++) {
173 MarkValue(threadId, slot);
174 }
175 };
176 TaggedObject *obj = nullptr;
177 while (true) {
178 obj = nullptr;
179 if (!sWorkManager_->Pop(threadId, &obj)) {
180 break;
181 }
182 JSHClass *hclass = obj->SynchronizedGetClass();
183 [[maybe_unused]] Region *region = Region::ObjectAddressToRange(obj);
184 ObjectSlot objectSlot(ToUintPtr(obj));
185 MarkObject(threadId, hclass, objectSlot);
186 ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(obj, hclass, visitor);
187 }
188 }
189
MergeBackAndResetRSetWorkListHandler()190 void SharedGCMarkerBase::MergeBackAndResetRSetWorkListHandler()
191 {
192 for (RSetWorkListHandler *handler : rSetHandlers_) {
193 handler->MergeBack();
194 delete handler;
195 }
196 rSetHandlers_.clear();
197 }
198
ResetWorkManager(SharedGCWorkManager *workManager)199 void SharedGCMarkerBase::ResetWorkManager(SharedGCWorkManager *workManager)
200 {
201 sWorkManager_ = workManager;
202 }
203
SharedGCMarker(SharedGCWorkManager *workManger)204 SharedGCMarker::SharedGCMarker(SharedGCWorkManager *workManger)
205 : SharedGCMarkerBase(workManger) {}
206
SharedGCMovableMarker(SharedGCWorkManager *workManger, SharedHeap *sHeap)207 SharedGCMovableMarker::SharedGCMovableMarker(SharedGCWorkManager *workManger, SharedHeap *sHeap)
208 : SharedGCMarkerBase(workManger), sHeap_(sHeap) {}
209
210 } // namespace panda::ecmascript