1 /*
2 * Copyright (c) 2025 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 "common_components/common_runtime/hooks.h"
17
18 #include <cstdint>
19
20 #include "common_components/heap/heap.h"
21 #include "ecmascript/base/config.h"
22 #include "ecmascript/free_object.h"
23 #include "ecmascript/mem/object_xray.h"
24 #include "ecmascript/mem/tagged_object.h"
25 #include "ecmascript/mem/tagged_state_word.h"
26 #include "ecmascript/mem/visitor.h"
27 #include "ecmascript/runtime.h"
28 #include "objects/base_type.h"
29 #include "objects/composite_base_class.h"
30
31 namespace common {
32 using panda::ecmascript::ObjectXRay;
33 using panda::ecmascript::FreeObject;
34 using panda::ecmascript::ObjectSlot;
35 using panda::ecmascript::JSThread;
36 using panda::ecmascript::TaggedType;
37
38 class CMCRootVisitor final : public panda::ecmascript::RootVisitor {
39 public:
CMCRootVisitor(const RefFieldVisitor & visitor)40 inline explicit CMCRootVisitor(const RefFieldVisitor &visitor): visitor_(visitor) {};
41 ~CMCRootVisitor() override = default;
42
VisitRoot(panda::ecmascript::Root type,ObjectSlot slot)43 inline void VisitRoot([[maybe_unused]] panda::ecmascript::Root type,
44 ObjectSlot slot) override
45 {
46 panda::ecmascript::JSTaggedValue value(slot.GetTaggedType());
47 if (value.IsHeapObject()) {
48 ASSERT(!value.IsWeak());
49
50 visitor_(reinterpret_cast<RefField<>&>(*(slot.GetRefFieldAddr())));
51 }
52 }
53
VisitRangeRoot(panda::ecmascript::Root type,ObjectSlot start,ObjectSlot end)54 inline void VisitRangeRoot([[maybe_unused]] panda::ecmascript::Root type,
55 ObjectSlot start, ObjectSlot end) override
56 {
57 for (ObjectSlot slot = start; slot < end; slot++) {
58 panda::ecmascript::JSTaggedValue value(slot.GetTaggedType());
59 if (value.IsHeapObject()) {
60 ASSERT(!value.IsWeak());
61
62 visitor_(reinterpret_cast<RefField<>&>(*(slot.GetRefFieldAddr())));
63 }
64 }
65 }
66
VisitBaseAndDerivedRoot(panda::ecmascript::Root type,ObjectSlot base,ObjectSlot derived,uintptr_t baseOldObject)67 inline void VisitBaseAndDerivedRoot([[maybe_unused]] panda::ecmascript::Root type,
68 [[maybe_unused]] ObjectSlot base,
69 [[maybe_unused]] ObjectSlot derived,
70 [[maybe_unused]] uintptr_t baseOldObject) override
71 {
72 panda::ecmascript::JSTaggedValue baseVal(base.GetTaggedType());
73 if (baseVal.IsHeapObject()) {
74 derived.Update(base.GetTaggedType() + derived.GetTaggedType() - baseOldObject);
75 }
76 }
77
78 private:
79 const RefFieldVisitor &visitor_;
80 };
81
82 class CMCWeakVisitor final : public panda::ecmascript::WeakVisitor {
83 public:
CMCWeakVisitor(const common::WeakRefFieldVisitor & visitor)84 inline explicit CMCWeakVisitor(const common::WeakRefFieldVisitor &visitor) : visitor_(visitor) {};
85 ~CMCWeakVisitor() override = default;
86
VisitRoot(panda::ecmascript::Root type,ObjectSlot slot)87 inline bool VisitRoot([[maybe_unused]] panda::ecmascript::Root type, ObjectSlot slot) override
88 {
89 panda::ecmascript::JSTaggedValue value(slot.GetTaggedType());
90 if (value.IsHeapObject()) {
91 ASSERT(!value.IsWeak());
92 return visitor_(reinterpret_cast<RefField<> &>(*(slot.GetRefFieldAddr())));
93 }
94 return true;
95 }
96
97 private:
98 const common::WeakRefFieldVisitor &visitor_;
99 };
100
VisitBaseRoots(const RefFieldVisitor & visitorFunc)101 void VisitBaseRoots(const RefFieldVisitor &visitorFunc)
102 {
103 BaseClassRoots &baseClassRoots = BaseRuntime::GetInstance()->GetBaseClassRoots();
104 // When visit roots, the language of the object is not used, so using the visitorFunc will work for
105 // both dynamic and static.
106 baseClassRoots.IterateCompositeBaseClass(visitorFunc);
107 }
108
VisitDynamicGlobalRoots(const RefFieldVisitor & visitorFunc)109 void VisitDynamicGlobalRoots(const RefFieldVisitor &visitorFunc)
110 {
111 OHOS_HITRACE(HITRACE_LEVEL_COMMERCIAL, "CMCGC::VisitDynamicGlobalRoot", "");
112 CMCRootVisitor visitor(visitorFunc);
113
114 panda::ecmascript::Runtime *runtime = panda::ecmascript::Runtime::GetInstance();
115 // MarkSerializeRoots
116 runtime->IterateSerializeRoot(visitor);
117
118 // MarkStringCache
119 runtime->IterateCachedStringRoot(visitor);
120
121 if (!panda::ecmascript::g_isEnableCMCGCConcurrentRootMarking) {
122 // MarkSharedModule
123 panda::ecmascript::SharedModuleManager::GetInstance()->Iterate(visitor);
124 }
125 }
126
VisitDynamicLocalRoots(const RefFieldVisitor & visitorFunc)127 void VisitDynamicLocalRoots(const RefFieldVisitor &visitorFunc)
128 {
129 OHOS_HITRACE(HITRACE_LEVEL_COMMERCIAL, "CMCGC::VisitDynamicLocalRoots", "");
130 CMCRootVisitor visitor(visitorFunc);
131 panda::ecmascript::Runtime *runtime = panda::ecmascript::Runtime::GetInstance();
132 runtime->GCIterateThreadList([&](JSThread *thread) {
133 auto vm = thread->GetEcmaVM();
134 ObjectXRay::VisitSTWVMRoots(vm, visitor);
135
136 auto profiler = vm->GetPGOProfiler();
137 if (profiler != nullptr) {
138 profiler->IteratePGOPreFuncList(visitor);
139 }
140 });
141
142 if (!panda::ecmascript::g_isEnableCMCGCConcurrentRootMarking) {
143 runtime->GCIterateThreadList([&](JSThread *thread) {
144 auto vm = thread->GetEcmaVM();
145 ObjectXRay::VisitConcurrentVMRoots(vm, visitor);
146 });
147 }
148 }
149
VisitDynamicWeakGlobalRoots(const common::WeakRefFieldVisitor & visitorFunc)150 void VisitDynamicWeakGlobalRoots(const common::WeakRefFieldVisitor &visitorFunc)
151 {
152 OHOS_HITRACE(HITRACE_LEVEL_COMMERCIAL, "CMCGC::VisitDynamicWeakGlobalRoots", "");
153 }
154
155 // weak global roots visited here should only reference old-space objects
VisitDynamicWeakGlobalRootsOld(const common::WeakRefFieldVisitor & visitorFunc)156 void VisitDynamicWeakGlobalRootsOld(const common::WeakRefFieldVisitor &visitorFunc)
157 {
158 OHOS_HITRACE(HITRACE_LEVEL_COMMERCIAL, "CMCGC::VisitDynamicWeakGlobalRootsOld", "");
159 CMCWeakVisitor visitor(visitorFunc);
160
161 panda::ecmascript::SharedHeap::GetInstance()->IteratorNativePointerList(visitor);
162
163 panda::ecmascript::Runtime *runtime = panda::ecmascript::Runtime::GetInstance();
164
165 #ifdef GC_STW_STRINGTABLE
166 auto *baseRuntime = BaseRuntime::GetInstance();
167 auto& stringTable = reinterpret_cast<BaseStringTableImpl&>(baseRuntime->GetStringTable());
168 stringTable.GetInternalTable()->SweepWeakRef(visitorFunc);
169 #endif
170 runtime->IteratorNativeDeleteInSharedGC(visitor);
171 }
172
InvokeSharedNativePointerCallbacks()173 void InvokeSharedNativePointerCallbacks()
174 {
175 panda::ecmascript::Runtime *runtime = panda::ecmascript::Runtime::GetInstance();
176 runtime->InvokeSharedNativePointerCallbacks();
177 }
178
VisitDynamicWeakLocalRoots(const common::WeakRefFieldVisitor & visitorFunc)179 void VisitDynamicWeakLocalRoots(const common::WeakRefFieldVisitor &visitorFunc)
180 {
181 OHOS_HITRACE(HITRACE_LEVEL_COMMERCIAL, "CMCGC::VisitDynamicWeakLocalRoots", "");
182 CMCWeakVisitor visitor(visitorFunc);
183 panda::ecmascript::Runtime *runtime = panda::ecmascript::Runtime::GetInstance();
184
185 runtime->GCIterateThreadList([&](JSThread *thread) {
186 auto vm = thread->GetEcmaVM();
187 const_cast<panda::ecmascript::Heap *>(vm->GetHeap())->IteratorNativePointerList(visitor);
188 thread->ClearVMCachedConstantPool();
189 thread->IterateWeakEcmaGlobalStorage(visitor);
190 vm->IterateWeakGlobalEnvList(visitor);
191 vm->IteratorSnapShotEnv(visitor);
192 });
193 }
194
VisitDynamicPreforwardRoots(const RefFieldVisitor & visitorFunc)195 void VisitDynamicPreforwardRoots(const RefFieldVisitor &visitorFunc)
196 {
197 OHOS_HITRACE(HITRACE_LEVEL_COMMERCIAL, "CMCGC::VisitDynamicPreforwardRoots", "");
198 CMCRootVisitor visitor(visitorFunc);
199 panda::ecmascript::Runtime *runtime = panda::ecmascript::Runtime::GetInstance();
200
201 runtime->GCIterateThreadList([&](JSThread *thread) {
202 auto vm = thread->GetEcmaVM();
203 vm->IterateGlobalEnvField(visitor);
204 });
205 }
206
VisitDynamicConcurrentRoots(const RefFieldVisitor & visitorFunc)207 void VisitDynamicConcurrentRoots(const RefFieldVisitor &visitorFunc)
208 {
209 if (!panda::ecmascript::g_isEnableCMCGCConcurrentRootMarking) {
210 return;
211 }
212 CMCRootVisitor visitor(visitorFunc);
213
214 panda::ecmascript::Runtime *runtime = panda::ecmascript::Runtime::GetInstance();
215 // MarkSharedModule
216 panda::ecmascript::SharedModuleManager::GetInstance()->Iterate(visitor);
217
218 runtime->GCIterateThreadList([&](JSThread *thread) {
219 auto vm = thread->GetEcmaVM();
220 ObjectXRay::VisitConcurrentVMRoots(vm, visitor);
221 });
222 }
223
VisitDynamicThreadRoot(const RefFieldVisitor & visitorFunc,void * vm)224 void VisitDynamicThreadRoot(const RefFieldVisitor &visitorFunc, void *vm)
225 {
226 OHOS_HITRACE(HITRACE_LEVEL_COMMERCIAL, "CMCGC::VisitDynamicThreadRoot", "");
227 auto ecmaVm = reinterpret_cast<panda::ecmascript::EcmaVM*>(vm);
228 if (!ecmaVm->GetAssociatedJSThread()->ReadyForGCIterating()) {
229 return;
230 }
231 CMCRootVisitor visitor(visitorFunc);
232 ObjectXRay::VisitSTWVMRoots(ecmaVm, visitor);
233 if (!panda::ecmascript::g_isEnableCMCGCConcurrentRootMarking) {
234 ObjectXRay::VisitConcurrentVMRoots(ecmaVm, visitor);
235 }
236
237 auto profiler = ecmaVm->GetPGOProfiler();
238 if (profiler != nullptr) {
239 profiler->IteratePGOPreFuncList(visitor);
240 }
241 }
242
VisitDynamicWeakThreadRoot(const WeakRefFieldVisitor & visitorFunc,void * vm)243 void VisitDynamicWeakThreadRoot(const WeakRefFieldVisitor &visitorFunc, void *vm)
244 {
245 OHOS_HITRACE(HITRACE_LEVEL_COMMERCIAL, "CMCGC::VisitDynamicWeakThreadRoot", "");
246 auto ecmaVm = reinterpret_cast<panda::ecmascript::EcmaVM*>(vm);
247 auto thread = ecmaVm->GetAssociatedJSThread();
248 if (!thread->ReadyForGCIterating()) {
249 return;
250 }
251 CMCWeakVisitor visitor(visitorFunc);
252 const_cast<panda::ecmascript::Heap *>(ecmaVm->GetHeap())->IteratorNativePointerList(visitor);
253 thread->ClearVMCachedConstantPool();
254 thread->IterateWeakEcmaGlobalStorage(visitor);
255 ecmaVm->IterateWeakGlobalEnvList(visitor);
256 ecmaVm->IteratorSnapShotEnv(visitor);
257 }
258
VisitDynamicThreadPreforwardRoot(const RefFieldVisitor & visitorFunc,void * vm)259 void VisitDynamicThreadPreforwardRoot(const RefFieldVisitor &visitorFunc, void *vm)
260 {
261 OHOS_HITRACE(HITRACE_LEVEL_COMMERCIAL, "CMCGC::VisitDynamicThreadPreforwardRoot", "");
262 auto ecmaVm = reinterpret_cast<panda::ecmascript::EcmaVM*>(vm);
263 if (!ecmaVm->GetAssociatedJSThread()->ReadyForGCIterating()) {
264 return;
265 }
266 CMCRootVisitor visitor(visitorFunc);
267 ecmaVm->IterateGlobalEnvField(visitor);
268 }
269
VisitJSThread(void * jsThread,CommonRootVisitor visitor)270 void VisitJSThread(void *jsThread, CommonRootVisitor visitor)
271 {
272 reinterpret_cast<JSThread *>(jsThread)->Visit(visitor);
273 }
274
SynchronizeGCPhaseToJSThread(void * jsThread,GCPhase gcPhase)275 void SynchronizeGCPhaseToJSThread(void *jsThread, GCPhase gcPhase)
276 {
277 reinterpret_cast<JSThread *>(jsThread)->SetCMCGCPhase(gcPhase);
278 reinterpret_cast<JSThread *>(jsThread)->SetCMCGCReason(Heap::GetHeap().GetGCReason());
279 if (panda::ecmascript::g_isEnableCMCGC) {
280 // forcely enable read barrier for read barrier DFX
281 #ifdef ENABLE_CMC_RB_DFX
282 reinterpret_cast<JSThread *>(jsThread)->SetReadBarrierState(true);
283 return;
284 #endif
285 if (gcPhase >= GCPhase::GC_PHASE_PRECOPY) {
286 reinterpret_cast<JSThread *>(jsThread)->SetReadBarrierState(true);
287 } else {
288 reinterpret_cast<JSThread *>(jsThread)->SetReadBarrierState(false);
289 }
290 }
291 }
292
MarkThreadLocalJitFortInstalled(void * thread,void * machineCode)293 void MarkThreadLocalJitFortInstalled(void *thread, void *machineCode)
294 {
295 auto vm = reinterpret_cast<JSThread *>(thread)->GetEcmaVM();
296 const_cast<panda::ecmascript::Heap *>(vm->GetHeap())
297 ->GetMachineCodeSpace()
298 ->MarkJitFortMemInstalled(reinterpret_cast<panda::ecmascript::MachineCode *>(machineCode));
299 }
300
SweepThreadLocalJitFort()301 void SweepThreadLocalJitFort()
302 {
303 panda::ecmascript::Runtime* runtime = panda::ecmascript::Runtime::GetInstance();
304
305 runtime->GCIterateThreadList([&](JSThread* thread) {
306 if (thread->IsJSThread()) {
307 auto vm = thread->GetEcmaVM();
308 if (Heap::GetHeap().GetGCReason() == GC_REASON_YOUNG) {
309 // JitFort space does not have generational feature, so far we have to assume all JitFort code is in
310 // oldspace after creation.
311 const_cast<panda::ecmascript::Heap *>(vm->GetHeap())->GetMachineCodeSpace()->ClearMarkBits();
312 } else {
313 // Small JitFort space implicitly clear the marking bits after sweep.
314 const_cast<panda::ecmascript::Heap *>(vm->GetHeap())->GetMachineCodeSpace()->Sweep();
315 }
316 }
317 });
318 }
319
FillFreeObject(void * object,size_t size)320 void FillFreeObject(void *object, size_t size)
321 {
322 panda::ecmascript::FreeObject::FillFreeObject(panda::ecmascript::SharedHeap::GetInstance(),
323 reinterpret_cast<uintptr_t>(object), size);
324 }
325
JSGCCallback(void * ecmaVM)326 void JSGCCallback(void *ecmaVM)
327 {
328 panda::ecmascript::EcmaVM *vm = reinterpret_cast<panda::ecmascript::EcmaVM*>(ecmaVM);
329 ASSERT(vm != nullptr);
330 JSThread *thread = vm->GetAssociatedJSThread();
331 if (thread != nullptr && thread->ReadyForGCIterating()) {
332 panda::ecmascript::Heap *heap = const_cast<panda::ecmascript::Heap*>(vm->GetHeap());
333 heap->ProcessGCCallback();
334 }
335 }
336
IsPostForked()337 bool IsPostForked()
338 {
339 return panda::ecmascript::Runtime::GetInstance()->IsPostForked();
340 }
341
SetBaseAddress(uintptr_t base)342 void SetBaseAddress(uintptr_t base)
343 {
344 // Please be careful about reentrant
345 ASSERT(panda::ecmascript::TaggedStateWord::BASE_ADDRESS == 0);
346 panda::ecmascript::TaggedStateWord::BASE_ADDRESS = base;
347 }
348
JitFortUnProt(size_t size,void * base)349 void JitFortUnProt(size_t size, void* base)
350 {
351 panda::ecmascript::PageMap(size, PAGE_PROT_READWRITE, 0, base, PAGE_FLAG_MAP_FIXED);
352 }
353
IsMachineCodeObject(uintptr_t objPtr)354 bool IsMachineCodeObject(uintptr_t objPtr)
355 {
356 JSTaggedValue value(static_cast<TaggedType>(objPtr));
357 return value.IsMachineCodeObject();
358 }
359
360 } // namespace panda
361