• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/runtime.h"
17 #include "common_components/common_runtime/hooks.h"
18 #include "common_components/mutator/mutator_manager.h"
19 #include "ecmascript/checkpoint/thread_state_transition.h"
20 #include "common_interfaces/base_runtime.h"
21 #include "common_interfaces/thread/thread_holder_manager.h"
22 #include "common_interfaces/profiler/heap_profiler_listener.h"
23 #include "ecmascript/cross_vm/dynamic_object_accessor.h"
24 #include "ecmascript/cross_vm/dynamic_object_descriptor.h"
25 #include "ecmascript/cross_vm/dynamic_type_converter.h"
26 #include "ecmascript/jit/jit.h"
27 #include "ecmascript/jspandafile/program_object.h"
28 #include "ecmascript/js_runtime_options.h"
29 #include "ecmascript/mem/dynamic_object_operator.h"
30 #include "ecmascript/mem/heap-inl.h"
31 #include "ecmascript/mem/slots.h"
32 #include "ecmascript/platform/parameters.h"
33 
34 namespace panda::ecmascript {
35 using PGOProfilerManager = pgo::PGOProfilerManager;
36 using namespace panda;
37 int32_t Runtime::vmCount_ = 0;
38 int32_t Runtime::destroyCount_ = 0;
39 bool Runtime::firstVmCreated_ = false;
40 Mutex *Runtime::vmCreationLock_ = new Mutex();
41 Runtime *Runtime::instance_ = nullptr;
42 common::BaseRuntime *Runtime::baseInstance_ = nullptr;
43 
Runtime()44 Runtime::Runtime()
45 {
46     if (baseInstance_ == nullptr) {
47         baseInstance_ = common::BaseRuntime::GetInstance();
48     }
49 }
50 
GetInstance()51 Runtime *Runtime::GetInstance()
52 {
53     ASSERT(instance_ != nullptr);
54     return instance_;
55 }
56 
~Runtime()57 Runtime::~Runtime()
58 {
59     LockHolder lock(constpoolLock_);
60     auto iter = globalSharedConstpools_.begin();
61     while (iter != globalSharedConstpools_.end()) {
62         LOG_ECMA(INFO) << "remove js pandafile by vm destruct, file: " << iter->first->GetJSPandaFileDesc();
63         JSPandaFileManager::GetInstance()->RemoveJSPandaFile(iter->first);
64         iter->second.clear();
65         iter++;
66     }
67     globalSharedConstpools_.clear();
68     delete externalRegisteredStringTable_;
69     externalRegisteredStringTable_ = nullptr;
70 }
71 
CreateIfFirstVm(const JSRuntimeOptions & options)72 void Runtime::CreateIfFirstVm(const JSRuntimeOptions &options)
73 {
74     LockHolder lock(*vmCreationLock_);
75     if (!firstVmCreated_) {
76         InitGCConfig(options);
77         common::Log::Initialize(options.GetLogOptions());
78         EcmaVM::InitializeIcuData(options);
79         MemMapAllocator::GetInstance()->Initialize(ecmascript::DEFAULT_REGION_SIZE, options.GetLargeHeap());
80         PGOProfilerManager::GetInstance()->Initialize(options.GetPGOProfilerPath(),
81                                                       options.GetPGOHotnessThreshold());
82         ASSERT(instance_ == nullptr);
83         instance_ = new Runtime();
84         instance_->SetEnableLargeHeap(options.GetLargeHeap());
85         SharedHeap::CreateNewInstance();
86         if (g_isEnableCMCGC) {
87             // Init common::BaseRuntime before daemon thread because creating mutator may access gcphase in heap
88             LOG_ECMA(INFO) << "start run with cmc gc";
89             // SetConfigHeapSize for cmc gc, pc and persist config may change heap size.
90             const_cast<JSRuntimeOptions &>(options).SetConfigHeapSize(MemMapAllocator::GetInstance()->GetCapacity());
91             const_cast<JSRuntimeOptions &>(options).SetConfigMaxGarbageCacheSize(g_maxGarbageCacheSize);
92             common::BaseRuntime::GetInstance()->Init(options.GetRuntimeParam());
93             common::g_enableGCTimeoutCheck = options.IsEnableGCTimeoutCheck();
94 #if defined(ECMASCRIPT_SUPPORT_HEAPPROFILER)
95             common::HeapProfilerListener::GetInstance().RegisterOutOfMemoryEventCb(
96                 HeapProfilerInterface::DumpHeapSnapshotForCMCOOM);
97 #endif
98         }
99         DaemonThread::CreateNewInstance();
100         firstVmCreated_ = true;
101     } else {
102         if (g_isEnableCMCGC) {
103             JSThread *mainThread = Runtime::GetInstance()->GetMainThread();
104             ASSERT(mainThread != nullptr);
105             EcmaVM *mainVM = mainThread->GetEcmaVM();
106             ASSERT(mainVM != nullptr);
107             if (mainVM->IsPreForked() && !mainVM->IsPostForked()) {
108                 LOG_ECMA(ERROR) << "create ecmavm after pre fork, but not post pork";
109                 ASSERT(!DaemonThread::GetInstance()->IsRunning());
110                 mainVM->PostFork(options);
111             }
112         }
113     }
114 }
115 
InitializeIfFirstVm(EcmaVM * vm)116 void Runtime::InitializeIfFirstVm(EcmaVM *vm)
117 {
118     {
119         LockHolder lock(*vmCreationLock_);
120         if (++vmCount_ == 1) {
121             ThreadManagedScope managedScope(vm->GetAssociatedJSThread());
122             PreInitialization(vm);
123             bool isEnableFastJit = vm->GetJSOptions().IsEnableJIT() && vm->GetJSOptions().GetEnableAsmInterpreter();
124             bool isEnableBaselineJit =
125                 vm->GetJSOptions().IsEnableBaselineJIT() && vm->GetJSOptions().GetEnableAsmInterpreter();
126             Jit::GetInstance()->SetEnableOrDisable(vm->GetJSOptions(), isEnableFastJit, isEnableBaselineJit);
127             vm->Initialize();
128             PostInitialization(vm);
129         }
130     }
131     if (!vm->IsInitialized()) {
132         ThreadManagedScope managedScope(vm->GetAssociatedJSThread());
133         vm->Initialize();
134     }
135 }
136 
PreInitialization(const EcmaVM * vm)137 void Runtime::PreInitialization(const EcmaVM *vm)
138 {
139     DynamicObjectOperator::Initialize();
140     if (g_isEnableCMCGC) {
141         DynamicObjectAccessor::Initialize();
142         DynamicObjectDescriptor::Initialize();
143         DynamicTypeConverter::Initialize();
144     }
145     mainThread_ = vm->GetAssociatedJSThread();
146     mainThread_->SetMainThread();
147     nativeAreaAllocator_ = std::make_unique<NativeAreaAllocator>();
148     heapRegionAllocator_ = std::make_unique<HeapRegionAllocator>();
149 
150 #if ENABLE_NEXT_OPTIMIZATION
151     if (g_isEnableCMCGC) {
152         auto& baseStringTable = common::BaseRuntime::GetInstance()->GetStringTable();
153         stringTable_ = std::make_unique<EcmaStringTable>(true, &baseStringTable,
154                                                          &static_cast<common::BaseStringTableImpl*>(&baseStringTable)->
155                                                           GetInternalTable()->GetHashTrieMap());
156     } else {
157         stringTable_ = std::make_unique<EcmaStringTable>(false);
158     }
159 #else
160     stringTable_ = std::make_unique<EcmaStringTable>();
161 #endif
162 
163     SharedHeap::GetInstance()->Initialize(nativeAreaAllocator_.get(), heapRegionAllocator_.get(),
164         const_cast<EcmaVM*>(vm)->GetJSOptions(), DaemonThread::GetInstance());
165 }
166 
PostInitialization(const EcmaVM * vm)167 void Runtime::PostInitialization(const EcmaVM *vm)
168 {
169     // Use the main thread's globalconst after it has initialized,
170     // and copy shared parts to other thread's later.
171     sharedConstInited_ = true;
172     globalEnv_ = vm->GetGlobalEnv().GetTaggedValue();
173     globalConst_.CopySharedConstantsFrom(mainThread_->GlobalConstants());
174     SharedHeap::GetInstance()->PostInitialization(&globalConst_, const_cast<EcmaVM*>(vm)->GetJSOptions());
175     SharedModuleManager::GetInstance()->Initialize();
176 }
177 
InitGCConfig(const JSRuntimeOptions & options)178 void Runtime::InitGCConfig(const JSRuntimeOptions &options)
179 {
180     bool defaultValue = options.IsEnableCMCGC();
181     g_isEnableCMCGC = IsEnableCMCGC(defaultValue);
182     if (g_isEnableCMCGC) {
183         g_maxRegularHeapObjectSize = 32_KB;
184         uint64_t defaultSize = options.GetCMCMaxGarbageCacheSize();
185         g_maxGarbageCacheSize = GetCMCMaxGarbageCacheSize(defaultSize);
186     }
187     g_isEnableCMCGCConcurrentRootMarking = options.IsEnableCMCGCConcurrentRootMarking();
188 }
189 
DestroyIfLastVm()190 void Runtime::DestroyIfLastVm()
191 {
192     LockHolder lock(*vmCreationLock_);
193     if (--vmCount_ <= 0) {
194         Jit::GetInstance()->Destroy();
195         SharedModuleManager::GetInstance()->SharedNativeObjDestory();
196         SharedHeap::GetInstance()->WaitAllTasksFinishedAfterAllJSThreadEliminated();
197         DaemonThread::DestroyInstance();
198         if (g_isEnableCMCGC) {
199             // Finish common::BaseRuntime after daemon thread because it will unregister mutator
200             common::BaseRuntime::GetInstance()->Fini();
201         }
202         SharedHeap::DestroyInstance();
203         AnFileDataManager::GetInstance()->SafeDestroyAllData();
204         MemMapAllocator::GetInstance()->Finalize();
205         PGOProfilerManager::GetInstance()->Destroy();
206         SharedModuleManager::GetInstance()->Destroy();
207         if (g_isEnableCMCGC) {
208             // Destroy common::BaseRuntime after daemon thread because it will unregister mutator
209             common::BaseRuntime::DestroyInstance();
210             // reset Base address offset
211             TaggedStateWord::BASE_ADDRESS = 0;
212         }
213         ASSERT(instance_ != nullptr);
214         delete instance_;
215         instance_ = nullptr;
216         firstVmCreated_ = false;
217     }
218 }
219 
RegisterThread(JSThread * newThread)220 void Runtime::RegisterThread(JSThread* newThread)
221 {
222     {
223         LockHolder lock(threadsLock_);
224         ASSERT(std::find(threads_.begin(), threads_.end(), newThread) == threads_.end());
225         threads_.emplace_back(newThread);
226     }
227     if (g_isEnableCMCGC) {
228         ThreadHolder* threadHolder = newThread->GetThreadHolder();
229         threadHolder->BindMutator();
230         newThread->SetAllocBuffer(threadHolder->GetAllocBuffer());
231         newThread->OnHeapCreated(common::Heap::heapStartAddr_);
232         newThread->OnHeapExtended(common::Heap::heapCurrentEnd_);
233         threadHolder->RegisterJSThread(newThread);
234     } else {
235         // send all current suspended requests to the new thread
236         for (uint32_t i = 0; i < suspendNewCount_; i++) {
237             newThread->SuspendThread(true);
238         }
239     }
240 }
241 
242 // Note: currently only called when thread is to be destroyed.
UnregisterThread(JSThread * thread)243 void Runtime::UnregisterThread(JSThread* thread)
244 {
245     {
246         LockHolder lock(threadsLock_);
247         ASSERT(std::find(threads_.begin(), threads_.end(), thread) != threads_.end());
248         ASSERT(!thread->IsInRunningState());
249         threads_.remove(thread);
250     }
251     if (g_isEnableCMCGC) {
252         ThreadHolder *holder = thread->GetThreadHolder();
253         void *mutator = holder->GetMutator();
254         ASSERT(mutator != nullptr);
255         holder->UnregisterJSThread(thread);
256         holder->UnbindMutator();
257     }
258 }
259 
SuspendAll(JSThread * current)260 void Runtime::SuspendAll(JSThread *current)
261 {
262     ASSERT(current != nullptr);
263     ASSERT(!current->IsInRunningState());
264 #ifndef NDEBUG
265     ASSERT(!current->HasLaunchedSuspendAll());
266     current->LaunchSuspendAll();
267 #endif
268     SuspendAllThreadsImpl(current);
269 }
270 
ResumeAll(JSThread * current)271 void Runtime::ResumeAll(JSThread *current)
272 {
273     ASSERT(current != nullptr);
274     ASSERT(!current->IsInRunningState());
275 #ifndef NDEBUG
276     ASSERT(current->HasLaunchedSuspendAll());
277     current->CompleteSuspendAll();
278 #endif
279     ResumeAllThreadsImpl(current);
280 }
281 
SuspendAllThreadsImpl(JSThread * current)282 void Runtime::SuspendAllThreadsImpl(JSThread *current)
283 {
284     if (g_isEnableCMCGC) {
285         common::BaseRuntime::GetInstance()->GetThreadHolderManager().SuspendAll(current->GetThreadHolder());
286         return;
287     }
288     SuspendBarrier barrier;
289     for (uint32_t iterCount = 1U;; ++iterCount) {
290         {
291             LockHolder lock(threadsLock_);
292             if (suspendNewCount_ == 0) {
293                 suspendNewCount_++;
294                 if (threads_.size() == 1) {
295                     ASSERT(current == mainThread_ || current->IsDaemonThread());
296                     return;
297                 }
298                 if (threads_.size() < 1) {
299                     return;
300                 }
301                 barrier.Initialize(threads_.size() - 1);
302                 for (const auto& thread: threads_) {
303                     if (thread == current) {
304                         continue;
305                     }
306                     thread->SuspendThread(+1, &barrier);
307                     // The two flags, SUSPEND_REQUEST and ACTIVE_BARRIER, are set by Suspend-Thread guarded by
308                     // suspendLock_, so the target thread-I may do not see these two flags in time. As a result, it
309                     // can switch its state freely without responding to the ACTIVE_BARRIER flag and the
310                     // suspend-thread will always wait it. However, as long as it sees the flags, the actions of
311                     // passing barrier will be triggered. When the thread-I switches from NON_RUNNING to RUNNING,
312                     // it will firstly pass the barrier and then be blocked by the SUSPEND_REQUEST flag. If the
313                     // thread-I switches from RUNNING to NON_RUNNING, it will switch the state and then act on the
314                     // barrier. If the thread-I go to checkpoint in RUNNING state, it will act on the barrier
315                     // and be blocked by SUSPEND_REQUEST flag.
316                     if (thread->IsSuspended()) {
317                         // Because of the multi-threads situation, currently thread-I may be in RUNNING state or is
318                         // goding to be RUNNING state even inside this branch. In both scenarios, for instance of
319                         // RUNNING state, according to the modification order of atomic-variable stateAndFlags_,
320                         // thread-I will see the SUSPEND_REQUEST and ACTIVE_BARRIER and act on them before switching
321                         // to RUNNING. Besides, notice the using of suspendLock_ inside PassSuspendBarrier(), there
322                         // is not data-race for passing barrier.
323                         thread->PassSuspendBarrier();
324                     }
325                 }
326                 break;
327             }
328         }
329         if (iterCount < MAX_SUSPEND_RETRIES) {
330             LockHolder lock(threadsLock_);
331             if (suspendNewCount_ != 0) {
332                 // Someone has already suspended all threads.
333                 // Wait until it finishes.
334                 threadSuspendCondVar_.Wait(&threadsLock_);
335             }
336         } else {
337             LOG_ECMA(FATAL) << "Too many SuspendAll retries!";
338             UNREACHABLE();
339         }
340     }
341     barrier.Wait();
342 }
343 
ResumeAllThreadsImpl(JSThread * current)344 void Runtime::ResumeAllThreadsImpl(JSThread *current)
345 {
346     if (g_isEnableCMCGC) {
347         common::BaseRuntime::GetInstance()->GetThreadHolderManager().ResumeAll(current->GetThreadHolder());
348     } else {
349         LockHolder lock(threadsLock_);
350         if (suspendNewCount_ > 0) {
351             suspendNewCount_--;
352         }
353         if (suspendNewCount_ == 0) {
354             // Signal to waiting to suspend threads
355             threadSuspendCondVar_.Signal();
356         }
357         for (const auto& thread : threads_) {
358             if (thread != current) {
359                 thread->ResumeThread(true);
360             }
361         }
362     }
363 }
364 
IterateSharedRoot(RootVisitor & visitor)365 void Runtime::IterateSharedRoot(RootVisitor &visitor)
366 {
367     IterateSerializeRoot(visitor);
368     SharedModuleManager::GetInstance()->Iterate(visitor);
369     IterateCachedStringRoot(visitor);
370 }
371 
IterateSerializeRoot(RootVisitor & v)372 void Runtime::IterateSerializeRoot(RootVisitor &v)
373 {
374     LockHolder lock(serializeLock_);
375     for (auto &it : serializeRootMap_) {
376         it.second->Iterate(v);
377     }
378 }
379 
HasCachedConstpool(const JSPandaFile * jsPandaFile)380 bool Runtime::HasCachedConstpool(const JSPandaFile *jsPandaFile)
381 {
382     LockHolder lock(constpoolLock_);
383     return globalSharedConstpools_.find(jsPandaFile) != globalSharedConstpools_.end();
384 }
385 
FindConstpool(const JSPandaFile * jsPandaFile,int32_t index)386 JSTaggedValue Runtime::FindConstpool(const JSPandaFile *jsPandaFile, int32_t index)
387 {
388     LockHolder lock(constpoolLock_);
389     return FindConstpoolUnlocked(jsPandaFile, index);
390 }
391 
FindConstpoolUnlocked(const JSPandaFile * jsPandaFile,int32_t index)392 JSTaggedValue Runtime::FindConstpoolUnlocked(const JSPandaFile *jsPandaFile, int32_t index)
393 {
394     auto iter = globalSharedConstpools_.find(jsPandaFile);
395     if (iter == globalSharedConstpools_.end()) {
396         return JSTaggedValue::Hole();
397     }
398     auto constpoolIter = iter->second.find(index);
399     if (constpoolIter == iter->second.end()) {
400         return JSTaggedValue::Hole();
401     }
402     return constpoolIter->second;
403 }
404 
AddOrUpdateConstpool(const JSPandaFile * jsPandaFile,JSHandle<ConstantPool> constpool,int32_t index)405 JSHandle<ConstantPool> Runtime::AddOrUpdateConstpool(const JSPandaFile *jsPandaFile,
406                                                      JSHandle<ConstantPool> constpool,
407                                                      int32_t index)
408 {
409     // Note: CMC GC assumes constpool is always a non-young object and tries to optimize it out in young GC
410     ASSERT_LOGF(
411         panda::ecmascript::g_isEnableCMCGC
412             ? common::Heap::GetHeap().InRecentSpace(*constpool) == false
413             : true,
414         "Violate CMC-GC assumption: should not be young object");
415 
416     LockHolder lock(constpoolLock_);
417     if (globalSharedConstpools_.find(jsPandaFile) == globalSharedConstpools_.end()) {
418         globalSharedConstpools_[jsPandaFile] = CMap<int32_t, JSTaggedValue>();
419     }
420     auto &constpoolMap = globalSharedConstpools_[jsPandaFile];
421     auto iter = constpoolMap.find(index);
422     if (iter == constpoolMap.end()) {
423         int32_t constpoolIndex = GetAndIncreaseSharedConstpoolCount();
424         constpool->SetUnsharedConstpoolIndex(JSTaggedValue(constpoolIndex));
425         constpoolMap.insert({index, constpool.GetTaggedValue()});
426         return constpool;
427     }
428     return JSHandle<ConstantPool>(reinterpret_cast<uintptr_t>(&iter->second));
429 }
430 
FindConstpools(const JSPandaFile * jsPandaFile)431 std::optional<std::reference_wrapper<CMap<int32_t, JSTaggedValue>>> Runtime::FindConstpools(
432     const JSPandaFile *jsPandaFile)
433 {
434     LockHolder lock(constpoolLock_);
435     auto iter = globalSharedConstpools_.find(jsPandaFile);
436     if (iter == globalSharedConstpools_.end()) {
437         return std::nullopt;
438     }
439     return iter->second;
440 }
441 
IteratorNativeDeleteInSharedGC(WeakVisitor & visitor)442 void Runtime::IteratorNativeDeleteInSharedGC(WeakVisitor &visitor)
443 {
444     auto iterator = globalSharedConstpools_.begin();
445     while (iterator != globalSharedConstpools_.end()) {
446         auto &constpools = iterator->second;
447         auto constpoolIter = constpools.begin();
448         while (constpoolIter != constpools.end()) {
449             JSTaggedValue constpoolVal = constpoolIter->second;
450             if (constpoolVal.IsHeapObject()) {
451                 bool isAlive = visitor.VisitRoot(Root::ROOT_VM,
452                     ObjectSlot(reinterpret_cast<uintptr_t>(&constpoolIter->second)));
453                 if (!isAlive) {
454                     int32_t constpoolIndex =
455                         ConstantPool::Cast(constpoolVal.GetTaggedObject())->GetUnsharedConstpoolIndex();
456                     EraseUnusedConstpool(iterator->first, constpoolIter->first, constpoolIndex);
457                     constpoolIter = constpools.erase(constpoolIter);
458                     // when shared constpool is not referenced by any objects,
459                     // global unshared constpool count can be reuse.
460                     freeSharedConstpoolIndex_.insert(constpoolIndex);
461                     continue;
462                 }
463             }
464             ++constpoolIter;
465         }
466         if (constpools.size() == 0) {
467             LOG_ECMA(INFO) << "remove js pandafile by gc, file:" << iterator->first->GetJSPandaFileDesc();
468             JSPandaFileManager::GetInstance()->RemoveJSPandaFile(iterator->first);
469             iterator = globalSharedConstpools_.erase(iterator);
470         } else {
471             ++iterator;
472         }
473     }
474 }
475 
ProcessNativeDeleteInSharedGC(const WeakRootVisitor & visitor)476 void Runtime::ProcessNativeDeleteInSharedGC(const WeakRootVisitor &visitor)
477 {
478     // No need lock here, only shared gc will sweep shared constpool, meanwhile other threads are suspended.
479     auto iterator = globalSharedConstpools_.begin();
480     ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK,
481         ("Constpools:" + std::to_string(globalSharedConstpools_.size())).c_str(), "");
482     while (iterator != globalSharedConstpools_.end()) {
483         auto &constpools = iterator->second;
484         auto constpoolIter = constpools.begin();
485         while (constpoolIter != constpools.end()) {
486             JSTaggedValue constpoolVal = constpoolIter->second;
487             if (constpoolVal.IsHeapObject()) {
488                 TaggedObject *obj = constpoolVal.GetTaggedObject();
489                 auto fwd = visitor(obj);
490                 if (fwd == nullptr) {
491                     int32_t constpoolIndex =
492                         ConstantPool::Cast(constpoolVal.GetTaggedObject())->GetUnsharedConstpoolIndex();
493                     EraseUnusedConstpool(iterator->first, constpoolIter->first, constpoolIndex);
494                     constpoolIter = constpools.erase(constpoolIter);
495                     // when shared constpool is not referenced by any objects,
496                     // global unshared constpool count can be reuse.
497                     freeSharedConstpoolIndex_.insert(constpoolIndex);
498                     continue;
499                 }
500                 if (fwd != reinterpret_cast<TaggedObject *>(obj)) {
501                     constpoolIter->second = JSTaggedValue(fwd);
502                 }
503             }
504             ++constpoolIter;
505         }
506         if (constpools.size() == 0) {
507             LOG_ECMA(INFO) << "remove js pandafile by gc, file:" << iterator->first->GetJSPandaFileDesc();
508             JSPandaFileManager::GetInstance()->RemoveJSPandaFile(iterator->first);
509             iterator = globalSharedConstpools_.erase(iterator);
510         } else {
511             ++iterator;
512         }
513     }
514 }
515 
EraseUnusedConstpool(const JSPandaFile * jsPandaFile,int32_t index,int32_t constpoolIndex)516 void Runtime::EraseUnusedConstpool(const JSPandaFile *jsPandaFile, int32_t index, int32_t constpoolIndex)
517 {
518     GCIterateThreadList([jsPandaFile, index, constpoolIndex](JSThread* thread) {
519         // adapt state to saferegion
520         ASSERT(g_isEnableCMCGC || !thread->IsInRunningState());
521         auto vm = thread->GetEcmaVM();
522         // GC maybe happen before vm initialized.
523         if (vm->GetUnsharedConstpoolsPointer() != nullptr) {
524             vm->EraseUnusedConstpool(jsPandaFile, index, constpoolIndex);
525         }
526     });
527 }
528 
ProcessSharedNativeDelete(const WeakRootVisitor & visitor)529 void Runtime::ProcessSharedNativeDelete(const WeakRootVisitor &visitor)
530 {
531     SharedHeap::GetInstance()->ProcessSharedNativeDelete(visitor);
532 }
533 
PushToSharedNativePointerList(JSNativePointer * pointer)534 void Runtime::PushToSharedNativePointerList(JSNativePointer *pointer)
535 {
536     SharedHeap::GetInstance()->PushToSharedNativePointerList(pointer);
537 }
538 
InvokeSharedNativePointerCallbacks()539 void Runtime::InvokeSharedNativePointerCallbacks()
540 {
541     auto &callbacks = GetSharedNativePointerCallbacks();
542     while (!callbacks.empty()) {
543         auto callbackPair = callbacks.back();
544         callbacks.pop_back();
545         ASSERT(callbackPair.first != nullptr);
546         auto callback = callbackPair.first;
547         (*callback)(nullptr, callbackPair.second.first, callbackPair.second.second);
548     }
549 }
550 
PreFork(JSThread * thread)551 void Runtime::PreFork(JSThread *thread)
552 {
553     if (g_isEnableCMCGC) {
554         baseInstance_->PreFork(thread->GetThreadHolder());
555     }
556 }
557 
PostFork()558 void Runtime::PostFork()
559 {
560     if (g_isEnableCMCGC) {
561         baseInstance_->PostFork();
562     }
563 }
564 }  // namespace panda::ecmascript
565