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