• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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