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, localVm->GetJSThreadNoCheck());
70 heap->SetRSetWorkListHandler(handler);
71 NotifyThreadProcessRsetStart(handler->GetOwnerThreadUnsafe());
72 rSetHandlers_.emplace_back(handler);
73 }
74
MarkSerializeRoots(uint32_t threadId)75 void SharedGCMarkerBase::MarkSerializeRoots(uint32_t threadId)
76 {
77 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGCMarkerBase::MarkSerializeRoots");
78 auto callback = [this, threadId](Root type, ObjectSlot slot) {this->HandleRoots(threadId, type, slot);};
79 Runtime::GetInstance()->IterateSerializeRoot(callback);
80 }
81
MarkStringCache(uint32_t threadId)82 void SharedGCMarkerBase::MarkStringCache(uint32_t threadId)
83 {
84 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGCMarkerBase::MarkStringCache");
85 auto cacheStringCallback = [this, threadId](Root type, ObjectSlot start, ObjectSlot end) {
86 this->HandleLocalRangeRoots(threadId, type, start, end);
87 };
88 Runtime::GetInstance()->IterateCachedStringRoot(cacheStringCallback);
89 }
90
MarkSharedModule(uint32_t threadId)91 void SharedGCMarkerBase::MarkSharedModule(uint32_t threadId)
92 {
93 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGCMarkerBase::MarkSharedModule");
94 auto visitor = [this, threadId](Root type, ObjectSlot slot) {this->HandleRoots(threadId, type, slot);};
95 SharedModuleManager::GetInstance()->Iterate(visitor);
96 }
97
ProcessMarkStack(uint32_t threadId)98 void SharedGCMarker::ProcessMarkStack(uint32_t threadId)
99 {
100 #ifndef NDEBUG
101 DaemonThread *dThread = DaemonThread::GetInstance();
102 if (UNLIKELY(!dThread->IsRunning())) {
103 // This DAEMON_THREAD_INDEX not means in daemon thread, but the daemon thread is terminated, and
104 // SharedGC is directly running in the current js thread, this maybe happen only AppSpawn
105 // trigger GC after PreFork (which is not expected), and at this time ParallelGC is disabled
106 ASSERT(threadId == DAEMON_THREAD_INDEX);
107 } else {
108 if (os::thread::GetCurrentThreadId() != dThread->GetThreadId()) {
109 ASSERT(threadId != 0);
110 } else {
111 ASSERT(threadId == 0);
112 }
113 }
114 #endif
115 auto cb = [&](ObjectSlot slot) {
116 MarkValue(threadId, slot);
117 };
118 EcmaObjectRangeVisitor visitor = [this, threadId, cb](TaggedObject *root, ObjectSlot start, ObjectSlot end,
119 VisitObjectArea area) {
120 if (area == VisitObjectArea::IN_OBJECT) {
121 if (VisitBodyInObj(root, start, end, cb)) {
122 return;
123 }
124 }
125 for (ObjectSlot slot = start; slot < end; slot++) {
126 MarkValue(threadId, slot);
127 }
128 };
129 TaggedObject *obj = nullptr;
130 while (true) {
131 obj = nullptr;
132 if (!sWorkManager_->Pop(threadId, &obj)) {
133 break;
134 }
135 JSHClass *hclass = obj->SynchronizedGetClass();
136 auto size = hclass->SizeFromJSHClass(obj);
137 Region *region = Region::ObjectAddressToRange(obj);
138 ASSERT(region->InSharedSweepableSpace());
139 region->IncreaseAliveObjectSafe(size);
140 ObjectSlot objectSlot(ToUintPtr(obj));
141 MarkObject(threadId, hclass, objectSlot);
142 ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(obj, hclass, visitor);
143 }
144 }
145
ProcessMarkStack(uint32_t threadId)146 void SharedGCMovableMarker::ProcessMarkStack(uint32_t threadId)
147 {
148 #ifndef NDEBUG
149 DaemonThread *dThread = DaemonThread::GetInstance();
150 if (UNLIKELY(!dThread->IsRunning())) {
151 // This DAEMON_THREAD_INDEX not means in daemon thread, but the daemon thread is terminated, and
152 // SharedGC is directly running in the current js thread, this maybe happen only AppSpawn
153 // trigger GC after PreFork (which is not expected), and at this time ParallelGC is disabled
154 ASSERT(threadId == DAEMON_THREAD_INDEX);
155 } else {
156 if (os::thread::GetCurrentThreadId() != dThread->GetThreadId()) {
157 ASSERT(threadId != 0);
158 } else {
159 ASSERT(threadId == 0);
160 }
161 }
162 #endif
163 auto cb = [&](ObjectSlot slot) {
164 MarkValue(threadId, slot);
165 };
166 EcmaObjectRangeVisitor visitor = [this, threadId, cb](TaggedObject *root, ObjectSlot start, ObjectSlot end,
167 VisitObjectArea area) {
168 if (area == VisitObjectArea::IN_OBJECT) {
169 if (VisitBodyInObj(root, start, end, cb)) {
170 return;
171 }
172 }
173 for (ObjectSlot slot = start; slot < end; slot++) {
174 MarkValue(threadId, slot);
175 }
176 };
177 TaggedObject *obj = nullptr;
178 while (true) {
179 obj = nullptr;
180 if (!sWorkManager_->Pop(threadId, &obj)) {
181 break;
182 }
183 JSHClass *hclass = obj->SynchronizedGetClass();
184 [[maybe_unused]] Region *region = Region::ObjectAddressToRange(obj);
185 ObjectSlot objectSlot(ToUintPtr(obj));
186 MarkObject(threadId, hclass, objectSlot);
187 ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(obj, hclass, visitor);
188 }
189 }
190
MergeBackAndResetRSetWorkListHandler()191 void SharedGCMarkerBase::MergeBackAndResetRSetWorkListHandler()
192 {
193 for (RSetWorkListHandler *handler : rSetHandlers_) {
194 handler->MergeBack();
195 delete handler;
196 }
197 rSetHandlers_.clear();
198 }
199
ResetWorkManager(SharedGCWorkManager * workManager)200 void SharedGCMarkerBase::ResetWorkManager(SharedGCWorkManager *workManager)
201 {
202 sWorkManager_ = workManager;
203 }
204
SharedGCMarker(SharedGCWorkManager * workManger)205 SharedGCMarker::SharedGCMarker(SharedGCWorkManager *workManger)
206 : SharedGCMarkerBase(workManger) {}
207
SharedGCMovableMarker(SharedGCWorkManager * workManger,SharedHeap * sHeap)208 SharedGCMovableMarker::SharedGCMovableMarker(SharedGCWorkManager *workManger, SharedHeap *sHeap)
209 : SharedGCMarkerBase(workManger), sHeap_(sHeap) {}
210
211 } // namespace panda::ecmascript