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