• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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/ecma_vm.h"
17 
18 #include "common_components/taskpool/taskpool.h"
19 #include "ecmascript/base/config.h"
20 #include "ecmascript/builtins/builtins_ark_tools.h"
21 #include "ecmascript/checkpoint/thread_state_transition.h"
22 #include "ecmascript/compiler/aot_constantpool_patcher.h"
23 #include "ecmascript/compiler/pgo_type/pgo_type_manager.h"
24 #include "common_interfaces/base_runtime.h"
25 #ifdef ARK_SUPPORT_INTL
26 #include "ecmascript/builtins/builtins_collator.h"
27 #include "ecmascript/builtins/builtins_date_time_format.h"
28 #include "ecmascript/builtins/builtins_number_format.h"
29 #endif
30 #include "ecmascript/builtins/builtins_global.h"
31 #include "ecmascript/builtins/builtins_object.h"
32 #include "ecmascript/builtins/builtins_promise_handler.h"
33 #include "ecmascript/builtins/builtins_proxy.h"
34 #include "ecmascript/checkpoint/thread_state_transition.h"
35 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
36 #include "ecmascript/dfx/cpu_profiler/cpu_profiler.h"
37 #endif
38 #if !WIN_OR_MAC_OR_IOS_PLATFORM
39 #include "ecmascript/dfx/hprof/heap_profiler.h"
40 #include "ecmascript/dfx/hprof/heap_profiler_interface.h"
41 #endif
42 #include "ecmascript/dfx/stackinfo/async_stack_trace.h"
43 #include "ecmascript/dfx/tracing/tracing.h"
44 #include "ecmascript/dfx/vmstat/function_call_timer.h"
45 #include "ecmascript/dfx/vmstat/opt_code_profiler.h"
46 #include "ecmascript/jit/jit_task.h"
47 #include "ecmascript/jspandafile/abc_buffer_cache.h"
48 #include "ecmascript/linked_hash_table.h"
49 #include "ecmascript/mem/heap-inl.h"
50 #include "ecmascript/mem/shared_heap/shared_concurrent_marker.h"
51 #include "ecmascript/module/module_logger.h"
52 #include "ecmascript/ohos/aot_tools.h"
53 #include "ecmascript/ohos/jit_tools.h"
54 #include "ecmascript/pgo_profiler/pgo_trace.h"
55 #include "ecmascript/platform/ecma_context.h"
56 #include "ecmascript/require/js_require_manager.h"
57 #include "ecmascript/regexp/regexp_parser_cache.h"
58 #include "ecmascript/snapshot/mem/snapshot.h"
59 #include "ecmascript/stubs/runtime_stubs.h"
60 #include "ecmascript/sustaining_js_handle.h"
61 #include "ecmascript/symbol_table.h"
62 #include "ecmascript/ohos/jit_tools.h"
63 #include "ecmascript/ohos/aot_tools.h"
64 #include "ecmascript/checkpoint/thread_state_transition.h"
65 #include "ecmascript/mem/heap-inl.h"
66 #include "ecmascript/dfx/stackinfo/async_stack_trace.h"
67 #include "ecmascript/base/gc_helper.h"
68 #include "ecmascript/checkpoint/thread_state_transition.h"
69 
70 #if defined(PANDA_TARGET_OHOS) && !defined(STANDALONE_MODE)
71 #include "parameters.h"
72 #endif
73 
74 namespace panda::ecmascript {
75 using RandomGenerator = base::RandomGenerator;
76 using PGOProfilerManager = pgo::PGOProfilerManager;
77 using JitTools = ohos::JitTools;
78 
79 AOTFileManager *JsStackInfo::loader = nullptr;
80 bool EcmaVM::multiThreadCheck_ = false;
81 bool EcmaVM::errorInfoEnhanced_ = false;
82 // To find the current js thread without parameters
83 thread_local void *g_currentThread = nullptr;
84 
GetGlueFromThreadLocal()85 extern "C" uintptr_t GetGlueFromThreadLocal()
86 {
87     return reinterpret_cast<JSThread *>(g_currentThread)->GetGlueAddr();
88 }
89 
Create(const JSRuntimeOptions & options)90 EcmaVM *EcmaVM::Create(const JSRuntimeOptions &options)
91 {
92     Runtime::CreateIfFirstVm(options);
93     auto heapType = options.IsWorker() ? EcmaParamConfiguration::HeapType::WORKER_HEAP :
94         EcmaParamConfiguration::HeapType::DEFAULT_HEAP;
95     size_t heapSize = options.GetHeapSize();
96 #if defined(PANDA_TARGET_OHOS) && !defined(STANDALONE_MODE)
97     switch (heapType) {
98         case EcmaParamConfiguration::HeapType::WORKER_HEAP:
99             heapSize = OHOS::system::GetUintParameter<size_t>("persist.ark.heap.workersize", 0) * 1_MB;
100             if (Runtime::GetInstance()->GetEnableLargeHeap()) {
101                 heapSize = panda::ecmascript::MAX_WORKER_HEAP_SIZE;
102             }
103             break;
104         default:
105             heapSize = OHOS::system::GetUintParameter<size_t>("persist.ark.heap.defaultsize", 0) * 1_MB;
106             if (Runtime::GetInstance()->GetEnableLargeHeap()) {
107                 heapSize = panda::ecmascript::MAX_HEAP_SIZE;
108             }
109             break;
110     }
111 #endif
112     auto config = EcmaParamConfiguration(heapType,
113                                          MemMapAllocator::GetInstance()->GetCapacity(),
114                                          heapSize);
115     JSRuntimeOptions newOptions = options;
116     // only define SUPPORT_ENABLE_ASM_INTERP can enable asm-interpreter
117 #if !defined(SUPPORT_ENABLE_ASM_INTERP)
118     newOptions.SetEnableAsmInterpreter(false);
119 #endif
120     auto vm = new EcmaVM(newOptions, config);
121     auto jsThread = JSThread::Create(vm);
122     g_currentThread = jsThread;
123     vm->thread_ = jsThread;
124     Runtime::GetInstance()->InitializeIfFirstVm(vm);
125     if (JsStackInfo::loader == nullptr) {
126         JsStackInfo::loader = vm->GetAOTFileManager();
127     }
128 #if defined(PANDA_TARGET_OHOS) && !defined(STANDALONE_MODE)
129     int arkProperties = OHOS::system::GetIntParameter<int>("persist.ark.properties", -1);
130     vm->GetJSOptions().SetArkProperties(arkProperties);
131 #endif
132     return vm;
133 }
134 
135 // static
Destroy(EcmaVM * vm)136 bool EcmaVM::Destroy(EcmaVM *vm)
137 {
138     if (UNLIKELY(vm == nullptr)) {
139         return false;
140     }
141     delete vm;
142     Runtime::DestroyIfLastVm();
143     return true;
144 }
145 
PreFork()146 void EcmaVM::PreFork()
147 {
148     Runtime::GetInstance()->PreFork(thread_);
149     auto sHeap = SharedHeap::GetInstance();
150     if (!g_isEnableCMCGC) {
151         heap_->CompactHeapBeforeFork();
152         heap_->AdjustSpaceSizeForAppSpawn();
153         heap_->GetReadOnlySpace()->SetReadOnly();
154         sHeap->CompactHeapBeforeFork(thread_);
155     }
156 
157     // CMC-GC threads and GC Taskpool Thread should be merged together.
158     heap_->DisableParallelGC();
159     sHeap->DisableParallelGC(thread_);
160     heap_->GetWorkManager()->FinishInPreFork();
161     sHeap->GetWorkManager()->FinishInPreFork();
162 
163     SetPreForked(true);
164     SetPostForked(false);
165     Runtime::GetInstance()->SetPostForked(false);
166     Jit::GetInstance()->PreFork();
167 }
168 
PostFork(const JSRuntimeOptions & option)169 void EcmaVM::PostFork(const JSRuntimeOptions &option)
170 {
171     if (Runtime::GetInstance()->GetEnableLargeHeap()) {
172         // when enable large heap, reset some heap param which has initialized in appspawn
173         MemMapAllocator::GetInstance()->ResetLargePoolSize();
174         SharedHeap::GetInstance()->ResetLargeCapacity();
175         heap_->ResetLargeCapacity();
176     }
177     Runtime::GetInstance()->PostFork();
178     Runtime::GetInstance()->SetPostForked(true);
179     RandomGenerator::InitRandom(GetAssociatedJSThread());
180     heap_->SetHeapMode(HeapMode::SHARE);
181     GetAssociatedJSThread()->PostFork();
182     DaemonThread::GetInstance()->StartRunning();
183     common::Taskpool::GetCurrentTaskpool()->Initialize();
184     heap_->GetWorkManager()->InitializeInPostFork();
185     auto sHeap = SharedHeap::GetInstance();
186     sHeap->GetWorkManager()->InitializeInPostFork();
187     SharedHeap::GetInstance()->EnableParallelGC(GetJSOptions());
188     heap_->EnableParallelGC();
189     SetPreForked(false);
190     SetPostForked(true);
191 
192     LOG_ECMA(INFO) << "multi-thread check enabled: " << GetThreadCheckStatus();
193     SignalAllReg();
194     options_.SetPgoForceDump(false);
195     std::string bundleName = PGOProfilerManager::GetInstance()->GetBundleName();
196     pgo::PGOTrace::GetInstance()->SetEnable(ohos::AotTools::GetPgoTraceEnable());
197     AotCrashInfo::GetInstance().SetOptionPGOProfiler(&options_, bundleName);
198     ResetPGOProfiler();
199     processStartRealtime_ = InitializeStartRealTime();
200 
201     Jit::GetInstance()->SetJitEnablePostFork(this, bundleName);
202 #if defined(PANDA_TARGET_OHOS) && !defined(STANDALONE_MODE)
203     int arkProperties = OHOS::system::GetIntParameter<int>("persist.ark.properties", -1);
204     GetJSOptions().SetArkProperties(arkProperties);
205 #endif
206 #ifdef ENABLE_POSTFORK_FORCEEXPAND
207     if (option.GetEnableWarmStartupSmartGC()) {
208         LOG_ECMA(WARN) << "SmartGC: process is start by premake/preload, skip cold start smrt gc."
209                        << " replace with warm startup smart gc later";
210     } else {
211         heap_->NotifyPostFork();
212         heap_->NotifyFinishColdStartSoon();
213     }
214 #endif
215     DaemonThread::GetInstance()->EnsureRunning();
216 }
217 
EcmaVM(JSRuntimeOptions options,EcmaParamConfiguration config)218 EcmaVM::EcmaVM(JSRuntimeOptions options, EcmaParamConfiguration config)
219     : nativeAreaAllocator_(std::make_unique<NativeAreaAllocator>()),
220       heapRegionAllocator_(std::make_unique<HeapRegionAllocator>(options)),
221       chunk_(nativeAreaAllocator_.get()),
222       ecmaParamConfiguration_(std::move(config))
223 {
224     options_ = std::move(options);
225     LOG_ECMA(DEBUG) << "multi-thread check enabled: " << GetThreadCheckStatus();
226     icEnabled_ = options_.EnableIC();
227     isEnableCMCGC_ = g_isEnableCMCGC;
228     optionalLogEnabled_ = options_.EnableOptionalLog();
229     options_.ParseAsmInterOption();
230     SetEnableOsr(options_.IsEnableOSR() && options_.IsEnableJIT() && options_.GetEnableAsmInterpreter());
231     processStartRealtime_ = InitializeStartRealTime();
232 }
233 
234 // for jit
EcmaVM()235 EcmaVM::EcmaVM()
236     : nativeAreaAllocator_(std::make_unique<NativeAreaAllocator>()),
237       heapRegionAllocator_(nullptr),
238       chunk_(nativeAreaAllocator_.get())
239 {
240     isEnableCMCGC_ = g_isEnableCMCGC;
241 }
242 
InitializeForJit(JitThread * jitThread)243 void EcmaVM::InitializeForJit(JitThread *jitThread)
244 {
245     thread_ = jitThread;
246     stringTable_ = Runtime::GetInstance()->GetEcmaStringTable();
247     ASSERT(stringTable_);
248     // ObjectFactory only sypport alloc string in sharedheap
249     factory_ = chunk_.New<ObjectFactory>(thread_, nullptr, SharedHeap::GetInstance());
250     SetIsJitCompileVM(true);
251 }
252 
InitializePGOProfiler()253 void EcmaVM::InitializePGOProfiler()
254 {
255     LOG_PGO(INFO) << "initializing pgo profiler, pgo is " << (IsEnablePGOProfiler() ? "enabled" : "disabled")
256                   << ", worker is " << (options_.IsWorker() ? "enabled" : "disabled")
257                   << ", profiler: " << pgoProfiler_;
258     bool isEnablePGOProfiler = IsEnablePGOProfiler();
259     if (pgoProfiler_ == nullptr) {
260         if (g_isEnableCMCGC) {
261             ThreadNativeScope scope(thread_);
262             pgoProfiler_ = PGOProfilerManager::GetInstance()->BuildProfiler(this, isEnablePGOProfiler);
263         } else {
264             pgoProfiler_ = PGOProfilerManager::GetInstance()->BuildProfiler(this, isEnablePGOProfiler);
265         }
266     }
267     pgo::PGOTrace::GetInstance()->SetEnable(options_.GetPGOTrace() || ohos::AotTools::GetPgoTraceEnable());
268     thread_->SetPGOProfilerEnable(isEnablePGOProfiler);
269 }
270 
ResetPGOProfiler()271 void EcmaVM::ResetPGOProfiler()
272 {
273     if (pgoProfiler_ != nullptr) {
274         bool isEnablePGOProfiler = IsEnablePGOProfiler();
275         PGOProfilerManager::GetInstance()->Reset(pgoProfiler_, isEnablePGOProfiler);
276         thread_->SetPGOProfilerEnable(isEnablePGOProfiler);
277         thread_->CheckOrSwitchPGOStubs();
278     }
279 }
280 
DisablePGOProfilerWithAOTFile(const std::string & aotFileName)281 void EcmaVM::DisablePGOProfilerWithAOTFile(const std::string &aotFileName)
282 {
283     if (AOTFileManager::AOTFileExist(aotFileName, AOTFileManager::FILE_EXTENSION_AN) ||
284         AOTFileManager::AOTFileExist(aotFileName, AOTFileManager::FILE_EXTENSION_AI)) {
285         LOG_PGO(INFO) << "disable pgo profiler due to aot file exist: " << aotFileName;
286         options_.SetEnablePGOProfiler(false);
287         PGOProfilerManager::GetInstance()->SetDisablePGO(true);
288         ResetPGOProfiler();
289     }
290 }
291 
IsEnablePGOProfiler() const292 bool EcmaVM::IsEnablePGOProfiler() const
293 {
294     if (options_.IsWorker()) {
295         return PGOProfilerManager::GetInstance()->IsEnable();
296     }
297     return options_.GetEnableAsmInterpreter() && options_.IsEnablePGOProfiler();
298 }
299 
IsEnableMutantArray() const300 bool EcmaVM::IsEnableMutantArray() const
301 {
302     return options_.GetEnableAsmInterpreter() && options_.IsEnableMutantArray();
303 }
304 
IsEnableElementsKind() const305 bool EcmaVM::IsEnableElementsKind() const
306 {
307     return options_.GetEnableAsmInterpreter() && options_.IsEnableElementsKind();
308 }
309 
IsEnableFastJit() const310 bool EcmaVM::IsEnableFastJit() const
311 {
312     return GetJit()->IsEnableFastJit();
313 }
314 
IsEnableBaselineJit() const315 bool EcmaVM::IsEnableBaselineJit() const
316 {
317     return GetJit()->IsEnableBaselineJit();
318 }
319 
GetTid() const320 uint32_t EcmaVM::GetTid() const
321 {
322     return thread_->GetThreadId();
323 }
324 
GetJit() const325 Jit *EcmaVM::GetJit() const
326 {
327     return Jit::GetInstance();
328 }
329 
Initialize()330 bool EcmaVM::Initialize()
331 {
332     ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, "EcmaVM::Initialize", "");
333     stringTable_ = Runtime::GetInstance()->GetEcmaStringTable();
334     InitializePGOProfiler();
335     common::Taskpool::GetCurrentTaskpool()->Initialize();
336 #ifndef PANDA_TARGET_WINDOWS
337     RuntimeStubs::Initialize(thread_);
338 #endif
339     heap_ = new Heap(this);
340     heap_->Initialize();
341 #ifdef PANDA_JS_ETS_HYBRID_MODE
342     if (Runtime::GetInstance()->IsHybridVm()) {
343         crossVMOperator_ = new CrossVMOperator(this);
344     }
345 
346 #endif // PANDA_JS_ETS_HYBRID_MODE
347     gcStats_ = chunk_.New<GCStats>(heap_, options_.GetLongPauseTime());
348     gcKeyStats_ = chunk_.New<GCKeyStats>(heap_, gcStats_);
349     factory_ = chunk_.New<ObjectFactory>(thread_, heap_, SharedHeap::GetInstance());
350     if (UNLIKELY(factory_ == nullptr)) {
351         LOG_FULL(FATAL) << "alloc factory_ failed";
352         UNREACHABLE();
353     }
354     debuggerManager_ = new tooling::JsDebuggerManager(this);
355     asyncStackTrace_ = new AsyncStackTrace(this);
356     aotFileManager_ = new AOTFileManager(this);
357     abcBufferCache_ = new AbcBufferCache();
358     auto globalConst = const_cast<GlobalEnvConstants *>(thread_->GlobalConstants());
359     globalConst->Init(thread_);
360     InitDataViewTypeTable(globalConst);
361     [[maybe_unused]] EcmaHandleScope scope(thread_);
362     thread_->SetReadyForGCIterating(true);
363     thread_->SetSharedMarkStatus(DaemonThread::GetInstance()->GetSharedMarkStatus());
364     snapshotEnv_ = new SnapshotEnv(this);
365     bool builtinsLazyEnabled = GetJSOptions().IsWorker() && GetJSOptions().GetEnableBuiltinsLazy();
366     thread_->SetEnableLazyBuiltins(builtinsLazyEnabled);
367     JSHandle<GlobalEnv> globalEnv = factory_->NewGlobalEnv(builtinsLazyEnabled);
368     thread_->SetGlueGlobalEnv(globalEnv.GetTaggedValue());
369     ptManager_ = new kungfu::PGOTypeManager(this);
370     optCodeProfiler_ = new OptCodeProfiler();
371     if (options_.GetTypedOpProfiler()) {
372         typedOpProfiler_ = new TypedOpProfiler();
373     }
374     functionProtoTransitionTable_ = new FunctionProtoTransitionTable(thread_);
375 
376     unsharedConstpools_ = new(std::nothrow) JSTaggedValue[GetUnsharedConstpoolsArrayLen()];
377     if (unsharedConstpools_ == nullptr) {
378         LOG_ECMA(FATAL) << "allocate unshared constpool array fail during initing";
379         UNREACHABLE();
380     }
381     std::fill(unsharedConstpools_, unsharedConstpools_ + GetUnsharedConstpoolsArrayLen(), JSTaggedValue::Hole());
382     thread_->SetUnsharedConstpools(reinterpret_cast<uintptr_t>(unsharedConstpools_));
383     thread_->SetUnsharedConstpoolsArrayLen(unsharedConstpoolsArrayLen_);
384 
385     snapshotEnv_->AddGlobalConstToMap();
386     GenerateInternalNativeMethods();
387     quickFixManager_ = new QuickFixManager();
388     if (options_.GetEnableAsmInterpreter()) {
389         LoadStubFile();
390     }
391 
392     callTimer_ = new FunctionCallTimer();
393     strategy_ = new ThroughputJSObjectResizingStrategy();
394     SetRegisterSymbols(SymbolTable::Create(thread_).GetTaggedValue());
395     microJobQueue_ = factory_->NewMicroJobQueue().GetTaggedValue();
396     if (IsEnableFastJit() || IsEnableBaselineJit()) {
397         Jit::GetInstance()->ConfigJit(this);
398     }
399     sustainingJSHandleList_ = new SustainingJSHandleList();
400     initialized_ = true;
401     regExpParserCache_ = new RegExpParserCache();
402     return true;
403 }
404 
~EcmaVM()405 EcmaVM::~EcmaVM()
406 {
407     if (g_isEnableCMCGC) {
408         thread_->GetThreadHolder()->TransferToNative();
409         common::BaseRuntime::EnterGCCriticalSection();
410         thread_->GetThreadHolder()->TransferToRunning();
411     }
412     if (isJitCompileVM_) {
413         if (factory_ != nullptr) {
414             chunk_.Delete(factory_);
415             factory_ = nullptr;
416         }
417         stringTable_ = nullptr;
418         thread_ = nullptr;
419         if (g_isEnableCMCGC) {
420             common::BaseRuntime::ExitGCCriticalSection();
421         }
422         return;
423     }
424 #if ECMASCRIPT_ENABLE_THREAD_STATE_CHECK
425     if (UNLIKELY(!thread_->IsInRunningStateOrProfiling())) {
426         LOG_ECMA(FATAL) << "Destruct VM must be in jsthread running state";
427         UNREACHABLE();
428     }
429 #endif
430     initialized_ = false;
431 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
432     if (profiler_ != nullptr) {
433         if (profiler_->GetOutToFile()) {
434             DFXJSNApi::StopCpuProfilerForFile(this);
435         } else {
436             DFXJSNApi::StopCpuProfilerForInfo(this);
437         }
438     }
439     if (profiler_ != nullptr) {
440         delete profiler_;
441         profiler_ = nullptr;
442     }
443 #endif
444 #if defined(ECMASCRIPT_SUPPORT_HEAPPROFILER)
445     DeleteHeapProfile();
446 #endif
447     if (IsEnableFastJit() || IsEnableBaselineJit()) {
448         GetJit()->ClearTaskWithVm(this);
449     }
450     // Destroy pgoProfiler should add after JIT::ClearTaskWithVm, and before ClearBufferData
451     if (pgoProfiler_ != nullptr) {
452         PGOProfilerManager::GetInstance()->Destroy(thread_, pgoProfiler_);
453         pgoProfiler_ = nullptr;
454     }
455     // clear c_address: c++ pointer delete
456     ClearBufferData();
457     heap_->WaitAllTasksFinished();
458     common::Taskpool::GetCurrentTaskpool()->Destroy(thread_->GetThreadId());
459 
460 #if ECMASCRIPT_ENABLE_FUNCTION_CALL_TIMER
461     DumpCallTimeInfo();
462 #endif
463 
464 #if defined(ECMASCRIPT_SUPPORT_TRACING)
465     if (tracing_) {
466         DFXJSNApi::StopTracing(this);
467     }
468 #endif
469     moduleManagers_.DestroyAllNativeObj();
470 
471     if (!isBundlePack_) {
472         std::shared_ptr<JSPandaFile> jsPandaFile = JSPandaFileManager::GetInstance()->FindJSPandaFile(assetPath_);
473         if (jsPandaFile != nullptr) {
474             jsPandaFile->DeleteParsedConstpoolVM(this);
475         }
476     }
477 
478     if (gcStats_ != nullptr) {
479         if (options_.EnableGCStatsPrint()) {
480             gcStats_->PrintStatisticResult();
481         }
482         chunk_.Delete(gcStats_);
483         gcStats_ = nullptr;
484     }
485 
486     if (gcKeyStats_ != nullptr) {
487         chunk_.Delete(gcKeyStats_);
488         gcKeyStats_ = nullptr;
489     }
490 
491     if (JsStackInfo::loader == aotFileManager_) {
492         JsStackInfo::loader = nullptr;
493     }
494 
495     if (heap_ != nullptr) {
496         heap_->Destroy();
497         delete heap_;
498         heap_ = nullptr;
499     }
500 
501     if (sustainingJSHandleList_ != nullptr) {
502         delete sustainingJSHandleList_;
503         sustainingJSHandleList_ = nullptr;
504     }
505 
506 #ifdef PANDA_JS_ETS_HYBRID_MODE
507     if (Runtime::GetInstance()->IsHybridVm() && crossVMOperator_ != nullptr) {
508         delete crossVMOperator_;
509         crossVMOperator_ = nullptr;
510     }
511 #endif  // PANDA_JS_ETS_HYBRID_MODE
512 
513     if (!g_isEnableCMCGC) {
514         SharedHeap *sHeap = SharedHeap::GetInstance();
515         const Heap *heap = Runtime::GetInstance()->GetMainThread()->GetEcmaVM()->GetHeap();
516         if (IsWorkerThread() && Runtime::SharedGCRequest()) {
517             // destory workervm to release mem.
518             thread_->SetReadyForGCIterating(false);
519             if (sHeap->CheckCanTriggerConcurrentMarking(thread_)) {
520                 sHeap->TriggerConcurrentMarking<TriggerGCType::SHARED_GC, MarkReason::WORKER_DESTRUCTION>(thread_);
521             } else if (heap && !heap->InSensitiveStatus() && !sHeap->GetConcurrentMarker()->IsEnabled()) {
522                 sHeap->CollectGarbage<TriggerGCType::SHARED_GC, GCReason::WORKER_DESTRUCTION>(thread_);
523             }
524         }
525     }
526 
527     intlCache_.ClearIcuCache(this);
528 
529     DeleteHandleStorage();
530     DeletePrimitiveStorage();
531 
532     if (runtimeStat_ != nullptr) {
533         chunk_.Delete(runtimeStat_);
534         runtimeStat_ = nullptr;
535     }
536 
537     if (debuggerManager_ != nullptr) {
538         delete debuggerManager_;
539         debuggerManager_ = nullptr;
540     }
541 
542     if (asyncStackTrace_ != nullptr) {
543         delete asyncStackTrace_;
544         asyncStackTrace_ = nullptr;
545     }
546 
547     if (aotFileManager_ != nullptr) {
548         delete aotFileManager_;
549         aotFileManager_ = nullptr;
550     }
551 
552     if (factory_ != nullptr) {
553         chunk_.Delete(factory_);
554         factory_ = nullptr;
555     }
556 
557     if (stringTable_ != nullptr) {
558         stringTable_ = nullptr;
559     }
560 
561     if (quickFixManager_ != nullptr) {
562         delete quickFixManager_;
563         quickFixManager_ = nullptr;
564     }
565 
566     if (unsharedConstpools_ != nullptr) {
567         delete[] unsharedConstpools_;
568         unsharedConstpools_ = nullptr;
569         thread_->SetUnsharedConstpools(reinterpret_cast<uintptr_t>(nullptr));
570         thread_->SetUnsharedConstpoolsArrayLen(0);
571     }
572 
573     if (snapshotEnv_ != nullptr) {
574         snapshotEnv_->ClearEnvMap();
575         delete snapshotEnv_;
576         snapshotEnv_ = nullptr;
577     }
578 
579     if (callTimer_ != nullptr) {
580         delete callTimer_;
581         callTimer_ = nullptr;
582     }
583 
584     if (strategy_ != nullptr) {
585         delete strategy_;
586         strategy_ = nullptr;
587     }
588 
589     if (regExpParserCache_ != nullptr) {
590         delete regExpParserCache_;
591         regExpParserCache_ = nullptr;
592     }
593 
594     if (abcBufferCache_ != nullptr) {
595         delete abcBufferCache_;
596         abcBufferCache_ = nullptr;
597     }
598 
599     if (optCodeProfiler_ != nullptr) {
600         delete optCodeProfiler_;
601         optCodeProfiler_ = nullptr;
602     }
603 
604     if (typedOpProfiler_ != nullptr) {
605         delete typedOpProfiler_;
606         typedOpProfiler_ = nullptr;
607     }
608 
609     if (ptManager_ != nullptr) {
610         delete ptManager_;
611         ptManager_ = nullptr;
612     }
613 
614     if (aotFileManager_ != nullptr) {
615         aotFileManager_ = nullptr;
616     }
617 
618     if (functionProtoTransitionTable_ != nullptr) {
619         delete functionProtoTransitionTable_;
620         functionProtoTransitionTable_ = nullptr;
621     }
622 
623     moduleManagers_.Clear();
624 
625     if (thread_ != nullptr) {
626         delete thread_;
627         thread_ = nullptr;
628     }
629 
630     if (g_isEnableCMCGC) {
631         common::BaseRuntime::ExitGCCriticalSection();
632     }
633 }
634 
InitializeEcmaScriptRunStat()635 void EcmaVM::InitializeEcmaScriptRunStat()
636 {
637     // NOLINTNEXTLINE(modernize-avoid-c-arrays)
638     static const char *runtimeCallerNames[] = {
639 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
640 #define INTERPRETER_CALLER_NAME(name) "Interpreter::" #name,
641     INTERPRETER_CALLER_LIST(INTERPRETER_CALLER_NAME)  // NOLINTNEXTLINE(bugprone-suspicious-missing-comma)
642 #undef INTERPRETER_CALLER_NAME
643 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
644 #define BUILTINS_API_NAME(class, name) "BuiltinsApi::" #class "_" #name,
645     BUILTINS_API_LIST(BUILTINS_API_NAME)
646 #undef BUILTINS_API_NAME
647 #define ABSTRACT_OPERATION_NAME(class, name) "AbstractOperation::" #class "_" #name,
648     ABSTRACT_OPERATION_LIST(ABSTRACT_OPERATION_NAME)
649 #undef ABSTRACT_OPERATION_NAME
650 #define MEM_ALLOCATE_AND_GC_NAME(name) "Memory::" #name,
651     MEM_ALLOCATE_AND_GC_LIST(MEM_ALLOCATE_AND_GC_NAME)
652 #undef MEM_ALLOCATE_AND_GC_NAME
653 #define DEF_RUNTIME_ID(name) "Runtime::" #name,
654     RUNTIME_STUB_WITH_GC_LIST(DEF_RUNTIME_ID)
655     RUNTIME_STUB_WITH_DFX(DEF_RUNTIME_ID)
656 #undef DEF_RUNTIME_ID
657     };
658     static_assert(sizeof(runtimeCallerNames) == sizeof(const char *) * ecmascript::RUNTIME_CALLER_NUMBER,
659                   "Invalid runtime caller number");
660     runtimeStat_ = chunk_.New<EcmaRuntimeStat>(runtimeCallerNames, ecmascript::RUNTIME_CALLER_NUMBER);
661     if (UNLIKELY(runtimeStat_ == nullptr)) {
662         LOG_FULL(FATAL) << "alloc runtimeStat_ failed";
663         UNREACHABLE();
664     }
665 }
666 
SetRuntimeStatEnable(bool flag)667 void EcmaVM::SetRuntimeStatEnable(bool flag)
668 {
669     static uint64_t start = 0;
670     if (flag) {
671         start = PandaRuntimeTimer::Now();
672         if (runtimeStat_ == nullptr) {
673             InitializeEcmaScriptRunStat();
674         }
675     } else {
676         LOG_ECMA(INFO) << "Runtime State duration:" << PandaRuntimeTimer::Now() - start << "(ns)";
677         if (runtimeStat_ != nullptr && runtimeStat_->IsRuntimeStatEnabled()) {
678             runtimeStat_->Print();
679             runtimeStat_->ResetAllCount();
680         }
681     }
682     if (runtimeStat_ != nullptr) {
683         runtimeStat_->SetRuntimeStatEnabled(flag);
684     }
685 }
686 
CheckThread() const687 void EcmaVM::CheckThread() const
688 {
689     // Exclude GC thread
690     if (thread_ == nullptr) {
691         LOG_FULL(FATAL) << "Fatal: ecma_vm has been destructed! vm address is: " << this;
692         UNREACHABLE();
693     }
694     DaemonThread *dThread = DaemonThread::GetInstance();
695     if (!common::Taskpool::GetCurrentTaskpool()->IsInThreadPool(std::this_thread::get_id()) &&
696         !(dThread != nullptr && dThread->GetThreadId() == JSThread::GetCurrentThreadId()) &&
697         thread_->CheckMultiThread()) {
698             LOG_FULL(FATAL) << "Fatal: ecma_vm cannot run in multi-thread!"
699                                 << " thread:" << thread_->GetThreadId()
700                                 << " currentThread:" << JSThread::GetCurrentThreadId();
701         UNREACHABLE();
702     }
703 }
704 
GetAndFastCheckJSThread() const705 JSThread *EcmaVM::GetAndFastCheckJSThread() const
706 {
707     if (thread_ == nullptr) {
708         LOG_FULL(FATAL) << "Fatal: ecma_vm has been destructed! vm address is: " << this;
709     }
710     if (thread_->CheckMultiThread()) {
711         LOG_FULL(FATAL) << "Fatal: ecma_vm cannot run in multi-thread!"
712                                 << " thread:" << thread_->GetThreadId()
713                                 << " currentThread:" << JSThread::GetCurrentThreadId();
714     }
715     return thread_;
716 }
717 
CheckSingleThread() const718 bool EcmaVM::CheckSingleThread() const
719 {
720     if (thread_ == nullptr) {
721         LOG_FULL(FATAL) << "Fatal: ecma_vm has been destructed! vm address is: " << this;
722         return false;
723     }
724     if (thread_->GetThreadId() != JSThread::GetCurrentThreadId()) {
725         LOG_FULL(FATAL) << "Fatal: ecma_vm cannot run in multi-thread!"
726                         << " thread:" << thread_->GetThreadId()
727                         << " currentThread:" << JSThread::GetCurrentThreadId();
728         return false;
729     }
730     return true;
731 }
732 
FastCallAot(size_t actualNumArgs,JSTaggedType * args,const JSTaggedType * prevFp)733 JSTaggedValue EcmaVM::FastCallAot(size_t actualNumArgs, JSTaggedType *args, const JSTaggedType *prevFp)
734 {
735     INTERPRETER_TRACE(thread_, ExecuteAot);
736     ASSERT(thread_->IsInManagedState());
737     // When C++ enters ASM, save the current globalenv and restore to glue after call
738     SaveEnv envScope(thread_);
739     auto entry = thread_->GetRTInterface(kungfu::RuntimeStubCSigns::ID_OptimizedFastCallEntry);
740     if (g_isEnableCMCGC && thread_->NeedReadBarrier()) {
741         base::GCHelper::CopyCallTarget(thread_, (void *)args[0]);
742     }
743     auto res = reinterpret_cast<FastCallAotEntryType>(entry)(thread_->GetGlueAddr(),
744                                                              actualNumArgs,
745                                                              args,
746                                                              reinterpret_cast<uintptr_t>(prevFp));
747     return res;
748 }
749 
CheckStartCpuProfiler()750 void EcmaVM::CheckStartCpuProfiler()
751 {
752 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
753     if (options_.EnableCpuProfilerColdStartMainThread() && options_.GetArkBundleName().compare(bundleName_) == 0 &&
754         !options_.IsWorker() && profiler_ == nullptr) {
755         std::string fileName = options_.GetArkBundleName() + ".cpuprofile";
756         if (!builtins::BuiltinsArkTools::CreateFile(fileName)) {
757             LOG_ECMA(ERROR) << "createFile failed " << fileName;
758             return;
759         } else {
760             DFXJSNApi::StartCpuProfilerForFile(this, fileName, CpuProfiler::INTERVAL_OF_INNER_START);
761             return;
762         }
763     }
764 
765     if (options_.EnableCpuProfilerColdStartWorkerThread() && options_.GetArkBundleName().compare(bundleName_) == 0 &&
766         options_.IsWorker() && profiler_ == nullptr) {
767         std::string fileName = options_.GetArkBundleName() + "_"
768                                + std::to_string(thread_->GetThreadId()) + ".cpuprofile";
769         if (!builtins::BuiltinsArkTools::CreateFile(fileName)) {
770             LOG_ECMA(ERROR) << "createFile failed " << fileName;
771             return;
772         } else {
773             DFXJSNApi::StartCpuProfilerForFile(this, fileName, CpuProfiler::INTERVAL_OF_INNER_START);
774             return;
775         }
776     }
777 #endif
778 }
779 
GetAndClearEcmaUncaughtException() const780 JSHandle<JSTaggedValue> EcmaVM::GetAndClearEcmaUncaughtException() const
781 {
782     JSHandle<JSTaggedValue> exceptionHandle = GetEcmaUncaughtException();
783     thread_->ClearException();  // clear for ohos app
784     return exceptionHandle;
785 }
786 
GetEcmaUncaughtException() const787 JSHandle<JSTaggedValue> EcmaVM::GetEcmaUncaughtException() const
788 {
789     if (!thread_->HasPendingException()) {
790         return JSHandle<JSTaggedValue>();
791     }
792     JSHandle<JSTaggedValue> exceptionHandle(thread_, thread_->GetException());
793     return exceptionHandle;
794 }
795 
796 #if ECMASCRIPT_ENABLE_COLLECTING_OPCODES
PrintCollectedByteCode()797 void EcmaVM::PrintCollectedByteCode()
798 {
799     std::unordered_map<BytecodeInstruction::Opcode, int> bytecodeStatsMap_ = bytecodeStatsStack_.top();
800     LOG_ECMA(ERROR) << "panda runtime stat:";
801     static constexpr int nameRightAdjustment = 45;
802     static constexpr int numberRightAdjustment = 12;
803     LOG_ECMA(ERROR) << std::right << std::setw(nameRightAdjustment) << "Hotness Function ByteCode"
804                    << std::setw(numberRightAdjustment) << "Count";
805     LOG_ECMA(ERROR) << "============================================================"
806                       << "=========================================================";
807     std::vector<std::pair<std::string, int>> bytecodeStatsVector;
808     for (auto& iter: bytecodeStatsMap_) {
809         bytecodeStatsVector.push_back(
810             std::make_pair(kungfu::GetEcmaOpcodeStr(static_cast<EcmaOpcode>(iter.first)), iter.second));
811     }
812     std::sort(bytecodeStatsVector.begin(), bytecodeStatsVector.end(),
813               [](std::pair<std::string, int> &a, std::pair<std::string, int> &b) {
814         return a.second > b.second;
815     });
816     for (size_t i = 0; i < bytecodeStatsVector.size(); ++i) {
817         LOG_ECMA(ERROR) << std::right << std::setw(nameRightAdjustment) << bytecodeStatsVector[i].first
818                        << std::setw(numberRightAdjustment) << bytecodeStatsVector[i].second;
819     }
820     LOG_ECMA(ERROR) << "============================================================"
821                       << "=========================================================";
822 }
823 #endif
824 
PrintAOTSnapShotStats()825 void EcmaVM::PrintAOTSnapShotStats()
826 {
827     static constexpr int nameRightAdjustment = 30;
828     static constexpr int numberRightAdjustment = 30;
829     LOG_ECMA(ERROR) << std::right << std::setw(nameRightAdjustment) << "AOT Snapshot Genre"
830                     << std::setw(numberRightAdjustment) << "Count";
831     LOG_ECMA(ERROR) << "==========================================================================";
832     for (const auto &iter: aotSnapShotStatsMap_) {
833         LOG_ECMA(ERROR) << std::right << std::setw(nameRightAdjustment) << iter.first
834                         << std::setw(numberRightAdjustment) << iter.second;
835     }
836     LOG_ECMA(ERROR) << "==========================================================================";
837     aotSnapShotStatsMap_.clear();
838 }
839 
ProcessNativeDelete(const WeakRootVisitor & visitor)840 void EcmaVM::ProcessNativeDelete(const WeakRootVisitor& visitor)
841 {
842     heap_->ProcessNativeDelete(visitor);
843 }
844 
ProcessReferences(const WeakRootVisitor & visitor)845 void EcmaVM::ProcessReferences(const WeakRootVisitor& visitor)
846 {
847     heap_->ProcessReferences(visitor);
848     GetPGOProfiler()->ProcessReferences(visitor);
849 }
850 
ProcessSnapShotEnv(const WeakRootVisitor & visitor)851 void EcmaVM::ProcessSnapShotEnv(const WeakRootVisitor& visitor)
852 {
853     GetSnapshotEnv()->ProcessSnapShotEnv(visitor);
854 }
855 
856 // for cmc-gc
IteratorSnapShotEnv(WeakVisitor & visitor)857 void EcmaVM::IteratorSnapShotEnv(WeakVisitor & visitor)
858 {
859     GetSnapshotEnv()->IteratorSnapShotEnv(visitor);
860 }
861 
PushToNativePointerList(JSNativePointer * pointer,Concurrent isConcurrent)862 void EcmaVM::PushToNativePointerList(JSNativePointer* pointer, Concurrent isConcurrent)
863 {
864     heap_->PushToNativePointerList(pointer, isConcurrent == Concurrent::YES);
865 }
866 
RemoveFromNativePointerList(JSNativePointer * pointer)867 void EcmaVM::RemoveFromNativePointerList(JSNativePointer* pointer)
868 {
869     heap_->RemoveFromNativePointerList(pointer);
870 }
871 
PushToDeregisterModuleList(const CString & module)872 void EcmaVM::PushToDeregisterModuleList(const CString &module)
873 {
874     deregisterModuleList_.emplace(module);
875 }
876 
RemoveFromDeregisterModuleList(CString module)877 void EcmaVM::RemoveFromDeregisterModuleList(CString module)
878 {
879     auto iter = deregisterModuleList_.find(module);
880     if (iter != deregisterModuleList_.end()) {
881         deregisterModuleList_.erase(iter);
882     }
883 }
884 
ContainInDeregisterModuleList(CString module)885 bool EcmaVM::ContainInDeregisterModuleList(CString module)
886 {
887     return (deregisterModuleList_.find(module) != deregisterModuleList_.end());
888 }
889 
ClearBufferData()890 void EcmaVM::ClearBufferData()
891 {
892     heap_->ClearNativePointerList();
893     ClearConstpoolBufferData();
894     internalNativeMethods_.clear();
895     workerList_.clear();
896     deregisterModuleList_.clear();
897 }
898 
CollectGarbage(TriggerGCType gcType,panda::ecmascript::GCReason reason) const899 void EcmaVM::CollectGarbage(TriggerGCType gcType, panda::ecmascript::GCReason reason) const
900 {
901     if (g_isEnableCMCGC) {
902         common::GCReason cmcReason = common::GC_REASON_USER;
903         bool async = true;
904         if (gcType == TriggerGCType::FULL_GC || gcType == TriggerGCType::SHARED_FULL_GC ||
905             gcType == TriggerGCType::APPSPAWN_FULL_GC || gcType == TriggerGCType::APPSPAWN_SHARED_FULL_GC ||
906             reason == GCReason::ALLOCATION_FAILED) {
907             cmcReason = common::GC_REASON_BACKUP;
908             async = false;
909         }
910         common::BaseRuntime::RequestGC(cmcReason, async, common::GC_TYPE_FULL);
911         return;
912     }
913     heap_->CollectGarbage(gcType, reason);
914 }
915 
IterateConcurrentRoots(RootVisitor & v)916 void EcmaVM::IterateConcurrentRoots(RootVisitor &v)
917 {
918     moduleManagers_.Iterate(v);
919 }
920 
Iterate(RootVisitor & v)921 void EcmaVM::Iterate(RootVisitor &v)
922 {
923     IterateSTWRoots(v);
924     IterateConcurrentRoots(v);
925 }
926 
IterateSTWRoots(RootVisitor & v)927 void EcmaVM::IterateSTWRoots(RootVisitor &v)
928 {
929     ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, "CMCGC::VisitRootEcmaVM", "");
930     if (!internalNativeMethods_.empty()) {
931         v.VisitRangeRoot(Root::ROOT_VM, ObjectSlot(ToUintPtr(&internalNativeMethods_.front())),
932             ObjectSlot(ToUintPtr(&internalNativeMethods_.back()) + JSTaggedValue::TaggedTypeSize()));
933     }
934     if (pgoProfiler_ != nullptr) {
935         pgoProfiler_->Iterate(v);
936     }
937     if (aotFileManager_) {
938         aotFileManager_->Iterate(v);
939     }
940     if (!microJobQueue_.IsHole()) {
941         v.VisitRoot(Root::ROOT_VM, ObjectSlot(ToUintPtr(&microJobQueue_)));
942     }
943     if (!registerSymbols_.IsHole()) {
944         v.VisitRoot(Root::ROOT_VM, ObjectSlot(ToUintPtr(&registerSymbols_)));
945     }
946     if (!finRegLists_.IsHole()) {
947         v.VisitRoot(Root::ROOT_VM, ObjectSlot(ToUintPtr(&finRegLists_)));
948     }
949     if (!options_.EnableGlobalLeakCheck() && currentHandleStorageIndex_ != -1) {
950         // IterateHandle when disableGlobalLeakCheck.
951         DISALLOW_HANDLE_ALLOC;
952         ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, "CMCGC::VisitRootHandleStorage", "");
953         int32_t nid = currentHandleStorageIndex_;
954         for (int32_t i = 0; i <= nid; ++i) {
955             auto node = handleStorageNodes_.at(i);
956             auto start = node->data();
957             auto end = (i != nid) ? &(node->data()[NODE_BLOCK_SIZE]) : handleScopeStorageNext_;
958             v.VisitRangeRoot(Root::ROOT_HANDLE, ObjectSlot(ToUintPtr(start)), ObjectSlot(ToUintPtr(end)));
959         }
960     }
961 
962     if (regExpParserCache_ != nullptr) {
963         regExpParserCache_->Clear();
964     }
965     // GC maybe happen before vm initialized.
966     if (unsharedConstpools_ != nullptr) {
967         v.VisitRangeRoot(Root::ROOT_VM, ObjectSlot(ToUintPtr(unsharedConstpools_)),
968             ObjectSlot(ToUintPtr(&unsharedConstpools_[GetUnsharedConstpoolsArrayLen() - 1]) +
969             JSTaggedValue::TaggedTypeSize()));
970     }
971     if (sustainingJSHandleList_) {
972         sustainingJSHandleList_->Iterate(v);
973     }
974 
975     if (functionProtoTransitionTable_) {
976         functionProtoTransitionTable_->Iterate(v);
977     }
978 
979     if (ptManager_) {
980         ptManager_->Iterate(v);
981     }
982 #ifdef ARK_USE_SATB_BARRIER
983     auto iterator = cachedSharedConstpools_.begin();
984     while (iterator != cachedSharedConstpools_.end()) {
985         auto &constpools = iterator->second;
986         auto constpoolIter = constpools.begin();
987         while (constpoolIter != constpools.end()) {
988             JSTaggedValue constpoolVal = constpoolIter->second;
989             if (constpoolVal.IsHeapObject()) {
990                 v.VisitRoot(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&constpoolIter->second)));
991             }
992             ++constpoolIter;
993         }
994         ++iterator;
995     }
996 #endif
997 }
998 
IterateHandle(RootVisitor & visitor)999 size_t EcmaVM::IterateHandle(RootVisitor &visitor)
1000 {
1001     // EnableGlobalLeakCheck.
1002     size_t handleCount = 0;
1003     if (currentHandleStorageIndex_ != -1) {
1004         DISALLOW_HANDLE_ALLOC;
1005         int32_t nid = currentHandleStorageIndex_;
1006         for (int32_t i = 0; i <= nid; ++i) {
1007             auto node = handleStorageNodes_.at(i);
1008             auto start = node->data();
1009             auto end = (i != nid) ? &(node->data()[NODE_BLOCK_SIZE]) : handleScopeStorageNext_;
1010             visitor.VisitRangeRoot(Root::ROOT_HANDLE, ObjectSlot(ToUintPtr(start)), ObjectSlot(ToUintPtr(end)));
1011             handleCount += (ToUintPtr(end) - ToUintPtr(start)) / sizeof(JSTaggedType);
1012         }
1013     }
1014     return handleCount;
1015 }
1016 
IterateWeakGlobalEnvList(WeakVisitor & visitor)1017 void EcmaVM::IterateWeakGlobalEnvList(WeakVisitor &visitor)
1018 {
1019     for (auto it = globalEnvRecordList_.begin(); it != globalEnvRecordList_.end();) {
1020         bool isAlive = visitor.VisitRoot(Root::ROOT_VM, ecmascript::ObjectSlot(static_cast<uintptr_t>(*it)));
1021         if (isAlive) {
1022             it++;
1023         } else {
1024             it = globalEnvRecordList_.erase(it);
1025         }
1026     }
1027 }
1028 
IterateGlobalEnvField(RootVisitor & visitor)1029 void EcmaVM::IterateGlobalEnvField(RootVisitor &visitor)
1030 {
1031     for (auto value : globalEnvRecordList_) {
1032         GlobalEnv::Cast(JSTaggedValue(value).GetTaggedObject())->Iterate(visitor);
1033     }
1034 }
1035 
ExpandHandleStorage()1036 uintptr_t *EcmaVM::ExpandHandleStorage()
1037 {
1038     uintptr_t *result = nullptr;
1039     int32_t lastIndex = static_cast<int32_t>(handleStorageNodes_.size()) - 1;
1040     if (currentHandleStorageIndex_ == lastIndex) {
1041         auto n = new std::array<JSTaggedType, NODE_BLOCK_SIZE>();
1042         handleStorageNodes_.push_back(n);
1043         currentHandleStorageIndex_++;
1044         result = reinterpret_cast<uintptr_t *>(&n->data()[0]);
1045         handleScopeStorageEnd_ = &n->data()[NODE_BLOCK_SIZE];
1046     } else {
1047         currentHandleStorageIndex_++;
1048         auto lastNode = handleStorageNodes_[currentHandleStorageIndex_];
1049         result = reinterpret_cast<uintptr_t *>(&lastNode->data()[0]);
1050         handleScopeStorageEnd_ = &lastNode->data()[NODE_BLOCK_SIZE];
1051     }
1052 
1053     return result;
1054 }
1055 
DeleteHandleStorage()1056 void EcmaVM::DeleteHandleStorage()
1057 {
1058     for (auto n : handleStorageNodes_) {
1059         delete n;
1060     }
1061     handleStorageNodes_.clear();
1062     currentHandleStorageIndex_ = -1;
1063     handleScopeStorageNext_ = handleScopeStorageEnd_ = nullptr;
1064 }
1065 
ShrinkHandleStorage(int prevIndex)1066 void EcmaVM::ShrinkHandleStorage(int prevIndex)
1067 {
1068     currentHandleStorageIndex_ = prevIndex;
1069     int32_t lastIndex = static_cast<int32_t>(handleStorageNodes_.size()) - 1;
1070 #if ECMASCRIPT_ENABLE_ZAP_MEM
1071     uintptr_t size = ToUintPtr(handleScopeStorageEnd_) - ToUintPtr(handleScopeStorageNext_);
1072     if (currentHandleStorageIndex_ != -1) {
1073         if (memset_s(handleScopeStorageNext_, size, 0, size) != EOK) {
1074             LOG_FULL(FATAL) << "memset_s failed";
1075             UNREACHABLE();
1076         }
1077     }
1078     for (int32_t i = currentHandleStorageIndex_ + 1; i < lastIndex; i++) {
1079         if (memset_s(handleStorageNodes_[i],
1080                      NODE_BLOCK_SIZE * sizeof(JSTaggedType), 0,
1081                      NODE_BLOCK_SIZE * sizeof(JSTaggedType)) !=
1082                      EOK) {
1083             LOG_FULL(FATAL) << "memset_s failed";
1084             UNREACHABLE();
1085         }
1086     }
1087 #endif
1088 
1089     if (lastIndex > MIN_HANDLE_STORAGE_SIZE && currentHandleStorageIndex_ < MIN_HANDLE_STORAGE_SIZE) {
1090         for (int i = MIN_HANDLE_STORAGE_SIZE; i < lastIndex; i++) {
1091             auto node = handleStorageNodes_.back();
1092             delete node;
1093             handleStorageNodes_.pop_back();
1094         }
1095     }
1096 }
1097 
PrintOptStat()1098 void EcmaVM::PrintOptStat()
1099 {
1100     if (optCodeProfiler_ != nullptr) {
1101         optCodeProfiler_->PrintAndReset();
1102     }
1103 }
1104 
DumpAOTInfo() const1105 void EcmaVM::DumpAOTInfo() const
1106 {
1107     aotFileManager_->DumpAOTInfo();
1108 }
1109 
CalCallSiteInfo(uintptr_t retAddr,bool isDeopt) const1110 std::tuple<uint64_t, uint8_t*, int, kungfu::CalleeRegAndOffsetVec> EcmaVM::CalCallSiteInfo(uintptr_t retAddr,
1111                                                                                            bool isDeopt) const
1112 {
1113     return aotFileManager_->CalCallSiteInfo(retAddr, isDeopt);
1114 }
1115 
LoadStubFile()1116 void EcmaVM::LoadStubFile()
1117 {
1118     std::string stubFile = "";
1119     if (options_.WasStubFileSet()) {
1120         stubFile = options_.GetStubFile();
1121     }
1122     aotFileManager_->LoadStubFile(stubFile);
1123 }
1124 
LoadAOTFilesInternal(const std::string & aotFileName)1125 bool EcmaVM::LoadAOTFilesInternal(const std::string& aotFileName)
1126 {
1127 #ifdef AOT_ESCAPE_ENABLE
1128     std::string bundleName = pgo::PGOProfilerManager::GetInstance()->GetBundleName();
1129     if (AotCrashInfo::GetInstance().IsAotEscapedOrNotInEnableList(this, bundleName)) {
1130         return false;
1131     }
1132 #endif
1133     std::string anFile = aotFileName + AOTFileManager::FILE_EXTENSION_AN;
1134     if (!aotFileManager_->LoadAnFile(anFile)) {
1135         LOG_ECMA(WARN) << "Load " << anFile << " failed. Destroy aot data and rollback to interpreter";
1136         ecmascript::AnFileDataManager::GetInstance()->SafeDestroyAnData(anFile);
1137         return false;
1138     }
1139 
1140     std::string aiFile = aotFileName + AOTFileManager::FILE_EXTENSION_AI;
1141     if (!aotFileManager_->LoadAiFile(aiFile)) {
1142         LOG_ECMA(WARN) << "Load " << aiFile << " failed. Destroy aot data and rollback to interpreter";
1143         ecmascript::AnFileDataManager::GetInstance()->SafeDestroyAnData(anFile);
1144         return false;
1145     }
1146     return true;
1147 }
1148 
LoadAOTFiles(const std::string & aotFileName)1149 bool EcmaVM::LoadAOTFiles(const std::string& aotFileName)
1150 {
1151     return LoadAOTFilesInternal(aotFileName);
1152 }
1153 
LoadAOTFiles(const std::string & aotFileName,std::function<bool (std::string fileName,uint8_t ** buff,size_t * buffSize)> cb)1154 bool EcmaVM::LoadAOTFiles(const std::string& aotFileName,
1155     std::function<bool(std::string fileName, uint8_t **buff, size_t *buffSize)> cb)
1156 {
1157     GetAOTFileManager()->SetJsAotReader(cb);
1158     return LoadAOTFilesInternal(aotFileName);
1159 }
1160 
LoadProtoTransitionTable(JSTaggedValue constpool)1161 void EcmaVM::LoadProtoTransitionTable(JSTaggedValue constpool)
1162 {
1163     JSTaggedValue protoTransitionTable =
1164         ConstantPool::Cast(constpool.GetTaggedObject())->GetProtoTransTableInfo(thread_);
1165     functionProtoTransitionTable_->UpdateProtoTransitionTable(
1166         thread_, JSHandle<PointerToIndexDictionary>(thread_, protoTransitionTable));
1167 }
1168 
ResetProtoTransitionTableOnConstpool(JSTaggedValue constpool)1169 void EcmaVM::ResetProtoTransitionTableOnConstpool(JSTaggedValue constpool)
1170 {
1171     ConstantPool::Cast(constpool.GetTaggedObject())->SetProtoTransTableInfo(thread_, JSTaggedValue::Undefined());
1172 }
1173 
ExpandPrimitiveStorage()1174 uintptr_t *EcmaVM::ExpandPrimitiveStorage()
1175 {
1176     uintptr_t *result = nullptr;
1177     int32_t lastIndex = static_cast<int32_t>(primitiveStorageNodes_.size()) - 1;
1178     if (currentPrimitiveStorageIndex_ == lastIndex) {
1179         auto n = new std::array<JSTaggedType, NODE_BLOCK_SIZE>();
1180         primitiveStorageNodes_.push_back(n);
1181         currentPrimitiveStorageIndex_++;
1182         result = reinterpret_cast<uintptr_t *>(&n->data()[0]);
1183         primitiveScopeStorageEnd_ = &n->data()[NODE_BLOCK_SIZE];
1184     } else {
1185         currentPrimitiveStorageIndex_++;
1186         auto lastNode = primitiveStorageNodes_[currentPrimitiveStorageIndex_];
1187         result = reinterpret_cast<uintptr_t *>(&lastNode->data()[0]);
1188         primitiveScopeStorageEnd_ = &lastNode->data()[NODE_BLOCK_SIZE];
1189     }
1190 
1191     return result;
1192 }
1193 
ShrinkPrimitiveStorage(int prevIndex)1194 void EcmaVM::ShrinkPrimitiveStorage(int prevIndex)
1195 {
1196     currentPrimitiveStorageIndex_ = prevIndex;
1197     int32_t lastIndex = static_cast<int32_t>(primitiveStorageNodes_.size()) - 1;
1198 #if ECMASCRIPT_ENABLE_ZAP_MEM
1199     uintptr_t size = ToUintPtr(primitiveScopeStorageEnd_) - ToUintPtr(primitiveScopeStorageNext_);
1200     if (currentPrimitiveStorageIndex_ != -1) {
1201         if (memset_s(primitiveScopeStorageNext_, size, 0, size) != EOK) {
1202             LOG_FULL(FATAL) << "memset_s failed";
1203             UNREACHABLE();
1204         }
1205     }
1206     for (int32_t i = currentPrimitiveStorageIndex_ + 1; i < lastIndex; i++) {
1207         if (memset_s(primitiveStorageNodes_[i],
1208                      NODE_BLOCK_SIZE * sizeof(JSTaggedType), 0,
1209                      NODE_BLOCK_SIZE * sizeof(JSTaggedType)) !=
1210                      EOK) {
1211             LOG_FULL(FATAL) << "memset_s failed";
1212             UNREACHABLE();
1213         }
1214     }
1215 #endif
1216 
1217     if (lastIndex > MIN_PRIMITIVE_STORAGE_SIZE && currentPrimitiveStorageIndex_ < MIN_PRIMITIVE_STORAGE_SIZE) {
1218         for (int i = MIN_PRIMITIVE_STORAGE_SIZE; i < lastIndex; i++) {
1219             auto node = primitiveStorageNodes_.back();
1220             delete node;
1221             primitiveStorageNodes_.pop_back();
1222         }
1223     }
1224 }
1225 
DeletePrimitiveStorage()1226 void EcmaVM::DeletePrimitiveStorage()
1227 {
1228     for (auto n : primitiveStorageNodes_) {
1229         delete n;
1230     }
1231     primitiveStorageNodes_.clear();
1232     currentPrimitiveStorageIndex_ = -1;
1233     primitiveScopeStorageNext_ = primitiveScopeStorageEnd_ = nullptr;
1234 }
1235 
1236 #if defined(ECMASCRIPT_SUPPORT_HEAPPROFILER)
DeleteHeapProfile()1237 void EcmaVM::DeleteHeapProfile()
1238 {
1239     if (heapProfile_ == nullptr) {
1240         return;
1241     }
1242     delete heapProfile_;
1243     heapProfile_ = nullptr;
1244 }
1245 
GetHeapProfile()1246 HeapProfilerInterface *EcmaVM::GetHeapProfile()
1247 {
1248     if (heapProfile_ != nullptr) {
1249         return heapProfile_;
1250     }
1251     return nullptr;
1252 }
1253 
GetOrNewHeapProfile()1254 HeapProfilerInterface *EcmaVM::GetOrNewHeapProfile()
1255 {
1256     if (heapProfile_ != nullptr) {
1257         return heapProfile_;
1258     }
1259     heapProfile_ = new HeapProfiler(this);
1260     ASSERT(heapProfile_ != nullptr);
1261     return heapProfile_;
1262 }
1263 
StartHeapTracking()1264 void EcmaVM::StartHeapTracking()
1265 {
1266     heap_->StartHeapTracking();
1267 }
1268 
StopHeapTracking()1269 void EcmaVM::StopHeapTracking()
1270 {
1271     heap_->StopHeapTracking();
1272 }
1273 #endif
1274 
1275 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
1276 void *EcmaVM::InternalMethodTable[] = {
1277     reinterpret_cast<void *>(builtins::BuiltinsGlobal::CallJsBoundFunction),
1278     reinterpret_cast<void *>(builtins::BuiltinsGlobal::CallJsProxy),
1279     reinterpret_cast<void *>(builtins::BuiltinsObject::CreateDataPropertyOnObjectFunctions),
1280 #ifdef ARK_SUPPORT_INTL
1281     reinterpret_cast<void *>(builtins::BuiltinsCollator::AnonymousCollator),
1282     reinterpret_cast<void *>(builtins::BuiltinsDateTimeFormat::AnonymousDateTimeFormat),
1283     reinterpret_cast<void *>(builtins::BuiltinsNumberFormat::NumberFormatInternalFormatNumber),
1284 #endif
1285     reinterpret_cast<void *>(builtins::BuiltinsProxy::InvalidateProxyFunction),
1286     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::AsyncAwaitFulfilled),
1287     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::AsyncAwaitRejected),
1288     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::ResolveElementFunction),
1289     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::Resolve),
1290     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::Reject),
1291     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::Executor),
1292     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::AnyRejectElementFunction),
1293     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::AllSettledResolveElementFunction),
1294     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::AllSettledRejectElementFunction),
1295     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::ThenFinally),
1296     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::CatchFinally),
1297     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::valueThunkFunction),
1298     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::throwerFunction),
1299     reinterpret_cast<void *>(JSAsyncGeneratorObject::ProcessorFulfilledFunc),
1300     reinterpret_cast<void *>(JSAsyncGeneratorObject::ProcessorRejectedFunc),
1301     reinterpret_cast<void *>(JSAsyncFromSyncIterator::AsyncFromSyncIterUnwarpFunction),
1302     reinterpret_cast<void *>(SourceTextModule::AsyncModuleFulfilledFunc),
1303     reinterpret_cast<void *>(SourceTextModule::AsyncModuleRejectedFunc)
1304 };
1305 
GenerateInternalNativeMethods()1306 void EcmaVM::GenerateInternalNativeMethods()
1307 {
1308     size_t length = static_cast<size_t>(MethodIndex::METHOD_END);
1309     constexpr uint32_t numArgs = 2;  // function object and this
1310     for (size_t i = 0; i < length; i++) {
1311         auto method = factory_->NewSMethod(nullptr, MemSpaceType::SHARED_NON_MOVABLE);
1312         method->SetNativePointer(InternalMethodTable[i]);
1313         method->SetNativeBit(true);
1314         method->SetNumArgsWithCallField(numArgs);
1315         method->SetFunctionKind(FunctionKind::NORMAL_FUNCTION);
1316         internalNativeMethods_.emplace_back(method.GetTaggedValue());
1317     }
1318     // cache to global constants shared because context may change
1319     CacheToGlobalConstants(GetMethodByIndex(MethodIndex::BUILTINS_GLOBAL_CALL_JS_BOUND_FUNCTION),
1320                            ConstantIndex::BOUND_FUNCTION_METHOD_INDEX);
1321     CacheToGlobalConstants(GetMethodByIndex(MethodIndex::BUILTINS_GLOBAL_CALL_JS_PROXY),
1322                            ConstantIndex::PROXY_METHOD_INDEX);
1323 }
1324 
CacheToGlobalConstants(JSTaggedValue value,ConstantIndex idx)1325 void EcmaVM::CacheToGlobalConstants(JSTaggedValue value, ConstantIndex idx)
1326 {
1327     auto thread = GetJSThread();
1328     auto constants = const_cast<GlobalEnvConstants *>(thread->GlobalConstants());
1329     constants->SetConstant(idx, value);
1330 }
1331 
GetMethodByIndex(MethodIndex idx)1332 JSTaggedValue EcmaVM::GetMethodByIndex(MethodIndex idx)
1333 {
1334     auto index = static_cast<uint8_t>(idx);
1335     ASSERT(index < internalNativeMethods_.size());
1336     return internalNativeMethods_[index];
1337 }
1338 
TriggerConcurrentCallback(JSTaggedValue result,JSTaggedValue hint)1339 void EcmaVM::TriggerConcurrentCallback(JSTaggedValue result, JSTaggedValue hint)
1340 {
1341     if (concurrentCallback_ == nullptr) {
1342         LOG_ECMA(DEBUG) << "Only trigger concurrent callback in taskpool thread";
1343         return;
1344     }
1345 
1346     bool success = true;
1347     if (result.IsJSPromise()) {
1348         // Async concurrent will return Promise
1349         auto promise = JSPromise::Cast(result.GetTaggedObject());
1350         auto status = promise->GetPromiseState();
1351         if (status == PromiseState::PENDING) {
1352             result = JSHandle<JSTaggedValue>::Cast(factory_->GetJSError(
1353                 ErrorType::ERROR, "Can't return Promise in pending state", StackCheck::NO)).GetTaggedValue();
1354         } else {
1355             result = promise->GetPromiseResult(thread_);
1356         }
1357 
1358         if (status != PromiseState::FULFILLED) {
1359             success = false;
1360         }
1361     }
1362 
1363     JSHandle<JSTaggedValue> functionValue(thread_, hint);
1364     if (!functionValue->IsJSFunction()) {
1365         LOG_ECMA(ERROR) << "TriggerConcurrentCallback hint is not function";
1366         return;
1367     }
1368     JSHandle<JSFunction> functionInfo(functionValue);
1369     if (!functionInfo->GetTaskConcurrentFuncFlag()) {
1370         LOG_ECMA(INFO) << "Function is not Concurrent Function";
1371         return;
1372     }
1373 
1374     void *taskInfo = reinterpret_cast<void*>(thread_->GetTaskInfo());
1375     if (UNLIKELY(taskInfo == nullptr)) {
1376         JSTaggedValue extraInfoValue = functionInfo->GetFunctionExtraInfo(thread_);
1377         if (!extraInfoValue.IsJSNativePointer()) {
1378             LOG_ECMA(INFO) << "FunctionExtraInfo is not JSNativePointer";
1379             return;
1380         }
1381         JSHandle<JSNativePointer> extraInfo(thread_, extraInfoValue);
1382         taskInfo = extraInfo->GetData();
1383     }
1384     // clear the taskInfo when return, which can prevent the callback to get it
1385     thread_->SetTaskInfo(reinterpret_cast<uintptr_t>(nullptr));
1386     auto localResultRef = JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread_, result));
1387     ThreadNativeScope nativeScope(thread_);
1388     concurrentCallback_(localResultRef, success, taskInfo, concurrentData_);
1389 }
1390 
HandleUncatchableError()1391 void EcmaVM::HandleUncatchableError()
1392 {
1393     if (uncatchableErrorHandler_ != nullptr) {
1394         panda::TryCatch trycatch(this);
1395         ecmascript::ThreadNativeScope nativeScope(thread_);
1396         uncatchableErrorHandler_(trycatch);
1397     }
1398     LOG_ECMA_MEM(FATAL) << "Out of Memory";
1399 }
1400 
DumpCallTimeInfo()1401 void EcmaVM::DumpCallTimeInfo()
1402 {
1403     if (callTimer_ != nullptr) {
1404         callTimer_->PrintAllStats();
1405     }
1406 }
1407 
WorkersetInfo(EcmaVM * workerVm)1408 void EcmaVM::WorkersetInfo(EcmaVM *workerVm)
1409 {
1410     LockHolder lock(mutex_);
1411     auto thread = workerVm->GetJSThread();
1412     if (thread != nullptr) {
1413         auto tid = thread->GetThreadId();
1414         if (tid != 0) {
1415             workerList_.emplace(tid, workerVm);
1416         }
1417     }
1418 }
1419 
GetWorkerVm(uint32_t tid)1420 EcmaVM *EcmaVM::GetWorkerVm(uint32_t tid)
1421 {
1422     LockHolder lock(mutex_);
1423     EcmaVM *workerVm = nullptr;
1424     if (!workerList_.empty()) {
1425         auto iter = workerList_.find(tid);
1426         if (iter != workerList_.end()) {
1427             workerVm = iter->second;
1428         }
1429     }
1430     return workerVm;
1431 }
1432 
DeleteWorker(EcmaVM * workerVm)1433 bool EcmaVM::DeleteWorker(EcmaVM *workerVm)
1434 {
1435     LockHolder lock(mutex_);
1436     auto thread = workerVm->GetJSThread();
1437     if (thread != nullptr) {
1438         auto tid = thread->GetThreadId();
1439         if (tid == 0) {
1440             return false;
1441         }
1442         auto iter = workerList_.find(tid);
1443         if (iter != workerList_.end()) {
1444             workerList_.erase(iter);
1445             return true;
1446         }
1447         return false;
1448     }
1449     return false;
1450 }
1451 
SuspendWorkerVm(uint32_t tid)1452 bool EcmaVM::SuspendWorkerVm(uint32_t tid)
1453 {
1454     LockHolder lock(mutex_);
1455     if (!workerList_.empty()) {
1456         auto iter = workerList_.find(tid);
1457         if (iter != workerList_.end()) {
1458             return DFXJSNApi::SuspendVM(iter->second);
1459         }
1460     }
1461     return false;
1462 }
1463 
ResumeWorkerVm(uint32_t tid)1464 void EcmaVM::ResumeWorkerVm(uint32_t tid)
1465 {
1466     LockHolder lock(mutex_);
1467     if (!workerList_.empty()) {
1468         auto iter = workerList_.find(tid);
1469         if (iter != workerList_.end()) {
1470             DFXJSNApi::ResumeVM(iter->second);
1471         }
1472     }
1473 }
1474 
1475 /*  This moduleName is a readOnly variable for napi, represent which abc is running in current vm.
1476 *   Get Current recordName: bundleName/moduleName/ets/xxx/xxx
1477 *                           pkg_modules@xxx/xxx/xxx
1478 *   Get Current fileName: /data/storage/el1/bundle/moduleName/ets/modules.abc
1479 *   output: moduleName: moduleName
1480 *   if needRecordName then fileName is: moduleName/ets/modules.abc
1481 */
GetCurrentModuleInfo(bool needRecordName)1482 std::pair<std::string, std::string> EcmaVM::GetCurrentModuleInfo(bool needRecordName)
1483 {
1484     std::pair<CString, CString> moduleInfo = EcmaInterpreter::GetCurrentEntryPoint(thread_);
1485     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread_, std::make_pair("", ""));
1486     CString recordName = moduleInfo.first;
1487     CString fileName = moduleInfo.second;
1488     LOG_FULL(INFO) << "Current recordName is " << recordName <<", current fileName is " << fileName;
1489     if (needRecordName) {
1490         if (fileName.length() > ModulePathHelper::BUNDLE_INSTALL_PATH_LEN &&
1491             fileName.find(ModulePathHelper::BUNDLE_INSTALL_PATH) == 0) {
1492             fileName = fileName.substr(ModulePathHelper::BUNDLE_INSTALL_PATH_LEN);
1493         } else {
1494             LOG_FULL(ERROR) << " GetCurrentModuleName Fail, fileName is " << fileName;
1495         }
1496         return std::make_pair(recordName.c_str(), fileName.c_str());
1497     }
1498     CString moduleName;
1499     if (IsNormalizedOhmUrlPack()) {
1500         moduleName = ModulePathHelper::GetModuleNameWithNormalizedName(recordName);
1501     } else {
1502         moduleName = ModulePathHelper::GetModuleName(recordName);
1503     }
1504     if (moduleName.empty()) {
1505         LOG_FULL(ERROR) << " GetCurrentModuleName Fail, recordName is " << recordName;
1506     }
1507     return std::make_pair(moduleName.c_str(), fileName.c_str());
1508 }
1509 
SetHmsModuleList(const std::vector<panda::HmsMap> & list)1510 void EcmaVM::SetHmsModuleList(const std::vector<panda::HmsMap> &list)
1511 {
1512     for (size_t i = 0; i < list.size(); i++) {
1513         HmsMap hmsMap = list[i];
1514         hmsModuleList_.emplace(hmsMap.originalPath.c_str(), hmsMap);
1515     }
1516 }
1517 
GetHmsModule(const CString & module) const1518 CString EcmaVM::GetHmsModule(const CString &module) const
1519 {
1520     auto it = hmsModuleList_.find(module);
1521     if (it == hmsModuleList_.end()) {
1522         LOG_ECMA(FATAL) << " Get Hms Module failed";
1523     }
1524     HmsMap hmsMap = it->second;
1525     return hmsMap.targetPath.c_str();
1526 }
1527 
IsHmsModule(const CString & moduleStr) const1528 bool EcmaVM::IsHmsModule(const CString &moduleStr) const
1529 {
1530     if (hmsModuleList_.empty()) {
1531         return false;
1532     }
1533     auto it = hmsModuleList_.find(moduleStr);
1534     if (it == hmsModuleList_.end()) {
1535         return false;
1536     }
1537     return true;
1538 }
1539 
SetpkgContextInfoList(const CMap<CString,CMap<CString,CVector<CString>>> & list)1540 void EcmaVM::SetpkgContextInfoList(const CMap<CString, CMap<CString, CVector<CString>>> &list)
1541 {
1542     WriteLockHolder lock(pkgContextInfoLock_);
1543     pkgContextInfoList_ = list;
1544 }
1545 
StopPreLoadSoOrAbc()1546 void EcmaVM::StopPreLoadSoOrAbc()
1547 {
1548     if (!stopPreLoadCallbacks_.empty()) {
1549         for (StopPreLoadSoCallback &cb: stopPreLoadCallbacks_) {
1550             if (cb != nullptr) {
1551                 cb();
1552             }
1553         }
1554         stopPreLoadCallbacks_.clear();
1555     }
1556 }
1557 
1558 // Initialize IcuData Path
InitializeIcuData(const JSRuntimeOptions & options)1559 void EcmaVM::InitializeIcuData(const JSRuntimeOptions &options)
1560 {
1561     std::string icuPath = options.GetIcuDataPath();
1562     if (icuPath == "default") {
1563 #if !WIN_OR_MAC_OR_IOS_PLATFORM && !defined(PANDA_TARGET_LINUX)
1564         SetHwIcuDirectory();
1565 #endif
1566     } else {
1567         std::string absPath;
1568         if (ecmascript::RealPath(icuPath, absPath)) {
1569             u_setDataDirectory(absPath.c_str());
1570         }
1571     }
1572 }
1573 
1574 // Initialize Process StartRealTime
InitializeStartRealTime()1575 int EcmaVM::InitializeStartRealTime()
1576 {
1577     int startRealTime = 0;
1578     struct timespec timespro = {0, 0};
1579     struct timespec timessys = {0, 0};
1580     auto res = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &timespro);
1581     if (res) {
1582         return startRealTime;
1583     }
1584     auto res1 = clock_gettime(CLOCK_MONOTONIC, &timessys);
1585     if (res1) {
1586         return startRealTime;
1587     }
1588 
1589     int whenpro = int(timespro.tv_sec * 1000) + int(timespro.tv_nsec / 1000000);
1590     int whensys = int(timessys.tv_sec * 1000) + int(timessys.tv_nsec / 1000000);
1591     startRealTime = (whensys - whenpro);
1592     return startRealTime;
1593 }
1594 
GetAsyncTaskId()1595 uint32_t EcmaVM::GetAsyncTaskId()
1596 {
1597     return asyncStackTrace_->GetAsyncTaskId();
1598 }
1599 
InsertAsyncStackTrace(const JSHandle<JSPromise> & promise)1600 bool EcmaVM::InsertAsyncStackTrace(const JSHandle<JSPromise> &promise)
1601 {
1602     return asyncStackTrace_->InsertAsyncStackTrace(promise);
1603 }
1604 
RemoveAsyncStackTrace(const JSHandle<JSPromise> & promise)1605 bool EcmaVM::RemoveAsyncStackTrace(const JSHandle<JSPromise> &promise)
1606 {
1607     return asyncStackTrace_->RemoveAsyncStackTrace(promise);
1608 }
1609 
GetMicroJobQueue() const1610 JSHandle<job::MicroJobQueue> EcmaVM::GetMicroJobQueue() const
1611 {
1612     return JSHandle<job::MicroJobQueue>(reinterpret_cast<uintptr_t>(&microJobQueue_));
1613 }
1614 
SetMicroJobQueue(job::MicroJobQueue * queue)1615 void EcmaVM::SetMicroJobQueue(job::MicroJobQueue *queue)
1616 {
1617     ASSERT(queue != nullptr);
1618     microJobQueue_ = JSTaggedValue(queue);
1619 }
1620 
HasPendingJob() const1621 bool EcmaVM::HasPendingJob() const
1622 {
1623     // This interface only determines whether PromiseJobQueue is empty, rather than ScriptJobQueue.
1624     if (UNLIKELY(thread_->HasTerminated())) {
1625         return false;
1626     }
1627     TaggedQueue *promiseQueue = TaggedQueue::Cast(GetMicroJobQueue()->GetPromiseJobQueue(thread_).GetTaggedObject());
1628     return !promiseQueue->Empty(thread_);
1629 }
1630 
ExecutePromisePendingJob()1631 bool EcmaVM::ExecutePromisePendingJob()
1632 {
1633     if (isProcessingPendingJob_) {
1634         LOG_ECMA(DEBUG) << "EcmaVM::ExecutePromisePendingJob can not reentrant";
1635         return false;
1636     }
1637     if (!thread_->HasPendingException()) {
1638         isProcessingPendingJob_ = true;
1639         job::MicroJobQueue::ExecutePendingJob(thread_, GetMicroJobQueue());
1640         if (thread_->HasPendingException()) {
1641             JsStackInfo::BuildCrashInfo(thread_);
1642         }
1643         isProcessingPendingJob_ = false;
1644         return true;
1645     }
1646     return false;
1647 }
1648 // just find unshared constpool, not create
FindUnsharedConstpool(JSTaggedValue sharedConstpool)1649 JSTaggedValue EcmaVM::FindUnsharedConstpool(JSTaggedValue sharedConstpool)
1650 {
1651     ConstantPool *shareCp = ConstantPool::Cast(sharedConstpool.GetTaggedObject());
1652     int32_t constpoolIndex = shareCp->GetUnsharedConstpoolIndex();
1653     // unshared constpool index is default INT32_MAX.
1654     ASSERT(0 <= constpoolIndex && constpoolIndex != ConstantPool::CONSTPOOL_TYPE_FLAG);
1655     if (constpoolIndex >= GetUnsharedConstpoolsArrayLen()) {
1656         return JSTaggedValue::Hole();
1657     }
1658     return unsharedConstpools_[constpoolIndex];
1659 }
1660 
FindOrCreateUnsharedConstpool(JSTaggedValue sharedConstpool)1661 JSTaggedValue EcmaVM::FindOrCreateUnsharedConstpool(JSTaggedValue sharedConstpool)
1662 {
1663     JSTaggedValue unsharedConstpool = FindUnsharedConstpool(sharedConstpool);
1664     if (unsharedConstpool.IsHole()) {
1665         ConstantPool *shareCp = ConstantPool::Cast(sharedConstpool.GetTaggedObject());
1666         int32_t constpoolIndex = shareCp->GetUnsharedConstpoolIndex();
1667         // unshared constpool index is default INT32_MAX.
1668         ASSERT(0 <= constpoolIndex && constpoolIndex != INT32_MAX);
1669         JSHandle<ConstantPool> unshareCp = ConstantPool::CreateUnSharedConstPoolBySharedConstpool(
1670             thread_->GetEcmaVM(), shareCp->GetJSPandaFile(), shareCp);
1671         unsharedConstpool = unshareCp.GetTaggedValue();
1672         SetUnsharedConstpool(constpoolIndex, unsharedConstpool);
1673     }
1674     return unsharedConstpool;
1675 }
1676 
EraseUnusedConstpool(const JSPandaFile * jsPandaFile,int32_t index,int32_t constpoolIndex)1677 void EcmaVM::EraseUnusedConstpool(const JSPandaFile *jsPandaFile, int32_t index, int32_t constpoolIndex)
1678 {
1679     // unshared constpool index is default INT32_MAX.
1680     ASSERT(0 <= constpoolIndex && constpoolIndex < GetUnsharedConstpoolsArrayLen());
1681 
1682     SetUnsharedConstpool(constpoolIndex, JSTaggedValue::Hole());
1683     auto iter = cachedSharedConstpools_.find(jsPandaFile);
1684     if (iter == cachedSharedConstpools_.end()) {
1685         return;
1686     }
1687     auto constpoolIter = iter->second.find(index);
1688     if (constpoolIter == iter->second.end()) {
1689         return;
1690     }
1691 
1692     iter->second.erase(constpoolIter);
1693     if (iter->second.size() == 0) {
1694         cachedSharedConstpools_.erase(iter);
1695     }
1696 }
1697 
FindConstpoolFromContextCache(const JSPandaFile * jsPandaFile,int32_t index)1698 JSTaggedValue EcmaVM::FindConstpoolFromContextCache(const JSPandaFile *jsPandaFile, int32_t index)
1699 {
1700     auto iter = cachedSharedConstpools_.find(jsPandaFile);
1701     if (iter != cachedSharedConstpools_.end()) {
1702         auto constpoolIter = iter->second.find(index);
1703         if (constpoolIter != iter->second.end()) {
1704             return constpoolIter->second;
1705         }
1706     }
1707     return JSTaggedValue::Hole();
1708 }
1709 
FindConstpool(const JSPandaFile * jsPandaFile,int32_t index)1710 JSTaggedValue EcmaVM::FindConstpool(const JSPandaFile *jsPandaFile, int32_t index)
1711 {
1712     JSTaggedValue contextCache = FindConstpoolFromContextCache(jsPandaFile, index);
1713     if (!contextCache.IsHole()) {
1714         return contextCache;
1715     }
1716     return Runtime::GetInstance()->FindConstpool(jsPandaFile, index);
1717 }
1718 
1719 // For new version instruction.
FindConstpool(const JSPandaFile * jsPandaFile,panda_file::File::EntityId id)1720 JSTaggedValue EcmaVM::FindConstpool(const JSPandaFile *jsPandaFile, panda_file::File::EntityId id)
1721 {
1722     panda_file::IndexAccessor indexAccessor(*jsPandaFile->GetPandaFile(), id);
1723     int32_t index = static_cast<int32_t>(indexAccessor.GetHeaderIndex());
1724     return FindConstpool(jsPandaFile, index);
1725 }
1726 
HasCachedConstpool(const JSPandaFile * jsPandaFile) const1727 bool EcmaVM::HasCachedConstpool(const JSPandaFile *jsPandaFile) const
1728 {
1729     if (cachedSharedConstpools_.find(jsPandaFile) != cachedSharedConstpools_.end()) {
1730         return true;
1731     }
1732 
1733     return Runtime::GetInstance()->HasCachedConstpool(jsPandaFile);
1734 }
1735 
AddOrUpdateConstpool(const JSPandaFile * jsPandaFile,JSHandle<ConstantPool> constpool,int32_t index)1736 JSHandle<ConstantPool> EcmaVM::AddOrUpdateConstpool(const JSPandaFile *jsPandaFile,
1737                                                     JSHandle<ConstantPool> constpool,
1738                                                     int32_t index)
1739 {
1740     constpool = Runtime::GetInstance()->AddOrUpdateConstpool(jsPandaFile, constpool, index);
1741     AddContextConstpoolCache(jsPandaFile, constpool, index);
1742     return constpool;
1743 }
1744 
AddContextConstpoolCache(const JSPandaFile * jsPandaFile,JSHandle<ConstantPool> constpool,int32_t index)1745 void EcmaVM::AddContextConstpoolCache(const JSPandaFile *jsPandaFile,
1746                                       JSHandle<ConstantPool> constpool,
1747                                       int32_t index)
1748 {
1749     if (cachedSharedConstpools_.find(jsPandaFile) == cachedSharedConstpools_.end()) {
1750         cachedSharedConstpools_[jsPandaFile] = CMap<int32_t, JSTaggedValue>();
1751     }
1752     auto &constpoolMap = cachedSharedConstpools_[jsPandaFile];
1753     ASSERT(constpoolMap.find(index) == constpoolMap.end());
1754     constpoolMap.insert({index, constpool.GetTaggedValue()});
1755 }
1756 
SetUnsharedConstpool(JSHandle<ConstantPool> sharedConstpool,JSTaggedValue unsharedConstpool)1757 void EcmaVM::SetUnsharedConstpool(JSHandle<ConstantPool> sharedConstpool, JSTaggedValue unsharedConstpool)
1758 {
1759     int32_t constpoolIndex = sharedConstpool->GetUnsharedConstpoolIndex();
1760     SetUnsharedConstpool(constpoolIndex, unsharedConstpool);
1761 }
1762 
SetUnsharedConstpool(int32_t constpoolIndex,JSTaggedValue unsharedConstpool)1763 void EcmaVM::SetUnsharedConstpool(int32_t constpoolIndex, JSTaggedValue unsharedConstpool)
1764 {
1765     GrowUnsharedConstpoolArray(constpoolIndex);
1766     ASSERT(0 <= constpoolIndex && constpoolIndex < ConstantPool::CONSTPOOL_TYPE_FLAG);
1767     unsharedConstpools_[constpoolIndex] = unsharedConstpool;
1768 }
1769 
GrowUnsharedConstpoolArray(int32_t index)1770 void EcmaVM::GrowUnsharedConstpoolArray(int32_t index)
1771 {
1772     if (index == ConstantPool::CONSTPOOL_TYPE_FLAG) {
1773         LOG_ECMA(FATAL) << "index has exceed unshared constpool array limit";
1774         UNREACHABLE();
1775     }
1776     int32_t oldCapacity = GetUnsharedConstpoolsArrayLen();
1777     if (index >= oldCapacity) {
1778         int32_t minCapacity = index + 1;
1779         ResizeUnsharedConstpoolArray(oldCapacity, minCapacity);
1780     }
1781 }
1782 
ResizeUnsharedConstpoolArray(int32_t oldCapacity,int32_t minCapacity)1783 void EcmaVM::ResizeUnsharedConstpoolArray(int32_t oldCapacity, int32_t minCapacity)
1784 {
1785     int32_t newCapacity = oldCapacity * 2; // 2: Double the value
1786     if (newCapacity - minCapacity < 0) {
1787         newCapacity = minCapacity;
1788     }
1789 
1790     if (newCapacity >= (INT32_MAX >> 1)) {
1791         newCapacity = INT32_MAX;
1792     }
1793 
1794     JSTaggedValue *newUnsharedConstpools = new(std::nothrow) JSTaggedValue[newCapacity];
1795     if (newUnsharedConstpools == nullptr) {
1796         LOG_ECMA(FATAL) << "allocate unshared constpool array fail during resizing";
1797         UNREACHABLE();
1798     }
1799     std::fill(newUnsharedConstpools, newUnsharedConstpools + newCapacity, JSTaggedValue::Hole());
1800     int32_t copyLen = GetUnsharedConstpoolsArrayLen();
1801     if (g_isEnableCMCGC) {
1802         Barriers::CopyObject<true, true>(thread_, nullptr, newUnsharedConstpools, unsharedConstpools_, copyLen);
1803     } else {
1804         std::copy(unsharedConstpools_, unsharedConstpools_ + copyLen, newUnsharedConstpools);
1805     }
1806     ClearUnsharedConstpoolArray();
1807     unsharedConstpools_ = newUnsharedConstpools;
1808     thread_->SetUnsharedConstpools(reinterpret_cast<uintptr_t>(unsharedConstpools_));
1809     thread_->SetUnsharedConstpoolsArrayLen(newCapacity);
1810     SetUnsharedConstpoolsArrayLen(newCapacity);
1811 }
1812 
UpdateConstpoolWhenDeserialAI(const std::string & fileName,JSHandle<ConstantPool> aiCP,int32_t index)1813 void EcmaVM::UpdateConstpoolWhenDeserialAI(const std::string& fileName,
1814                                            JSHandle<ConstantPool> aiCP, int32_t index)
1815 {
1816     auto pf = JSPandaFileManager::GetInstance()->FindJSPandaFile(fileName.c_str());
1817     if (pf == nullptr) {
1818         return;
1819     }
1820     JSTaggedValue sharedConstpool = FindConstpool(pf.get(), index);
1821     JSHandle<ConstantPool> sharedCPHandle = JSHandle<ConstantPool>(thread_, sharedConstpool);
1822     if (sharedConstpool.IsHole()) {
1823         return;
1824     }
1825     JSTaggedValue unsharedConstpool = FindOrCreateUnsharedConstpool(sharedCPHandle.GetTaggedValue());
1826     JSHandle<ConstantPool> unsharedCP = JSHandle<ConstantPool>(thread_, unsharedConstpool);
1827     JSHandle<ConstantPool> sharedCP = JSHandle<ConstantPool>(thread_, sharedCPHandle.GetTaggedValue());
1828     ConstantPool::UpdateConstpoolWhenDeserialAI(thread_->GetEcmaVM(), aiCP, sharedCP, unsharedCP);
1829 }
1830 
FindCachedConstpoolAndLoadAiIfNeeded(const JSPandaFile * jsPandaFile,int32_t index)1831 JSTaggedValue EcmaVM::FindCachedConstpoolAndLoadAiIfNeeded(const JSPandaFile *jsPandaFile, int32_t index)
1832 {
1833     JSTaggedValue constpool = FindConstpoolFromContextCache(jsPandaFile, index);
1834     if (!constpool.IsHole()) {
1835         return constpool;
1836     }
1837     constpool = Runtime::GetInstance()->FindConstpool(jsPandaFile, index);
1838     if (!constpool.IsHole()) {
1839         AddContextConstpoolCache(jsPandaFile, JSHandle<ConstantPool>(thread_, constpool), index);
1840     }
1841     // Getting the cached constpool in runtime means the ai data has not been loaded in current thread.
1842     // And we need to reload it
1843     aotFileManager_->LoadAiFile(jsPandaFile, thread_->GetEcmaVM());
1844     return constpool;
1845 }
1846 
FindOrCreateConstPool(const JSPandaFile * jsPandaFile,panda_file::File::EntityId id)1847 JSHandle<ConstantPool> EcmaVM::FindOrCreateConstPool(const JSPandaFile *jsPandaFile, panda_file::File::EntityId id)
1848 {
1849     EcmaVM *vm = thread_->GetEcmaVM();
1850     panda_file::IndexAccessor indexAccessor(*jsPandaFile->GetPandaFile(), id);
1851     int32_t index = static_cast<int32_t>(indexAccessor.GetHeaderIndex());
1852     JSTaggedValue constpool = FindCachedConstpoolAndLoadAiIfNeeded(jsPandaFile, index);
1853     if (constpool.IsHole()) {
1854         JSHandle<ConstantPool> newConstpool = ConstantPool::CreateUnSharedConstPool(vm, jsPandaFile, id);
1855         JSHandle<ConstantPool> newSConstpool;
1856         if (jsPandaFile->IsLoadedAOT()) {
1857             AotConstantpoolPatcher::SetObjectFunctionFromConstPool(thread_, newConstpool);
1858             newSConstpool = ConstantPool::CreateSharedConstPoolForAOT(vm, newConstpool, index);
1859         } else {
1860             newSConstpool = ConstantPool::CreateSharedConstPool(vm, jsPandaFile, id, index);
1861         }
1862         newSConstpool = AddOrUpdateConstpool(jsPandaFile, newSConstpool, index);
1863         SetUnsharedConstpool(newSConstpool, newConstpool.GetTaggedValue());
1864         return newSConstpool;
1865     } else if (jsPandaFile->IsLoadedAOT()) {
1866         // For aot, after getting the cached shared constpool,
1867         // worker thread need to create and bind the correspoding unshared constpool.
1868         JSHandle<ConstantPool> newConstpool = JSHandle<ConstantPool>(thread_, FindOrCreateUnsharedConstpool(constpool));
1869         AotConstantpoolPatcher::SetObjectFunctionFromConstPool(thread_, newConstpool);
1870     }
1871     return JSHandle<ConstantPool>(thread_, constpool);
1872 }
1873 
CreateAllConstpool(const JSPandaFile * jsPandaFile)1874 void EcmaVM::CreateAllConstpool(const JSPandaFile *jsPandaFile)
1875 {
1876     auto headers = jsPandaFile->GetPandaFile()->GetIndexHeaders();
1877     uint32_t index = 0;
1878     for (const auto &header : headers) {
1879         auto constpoolSize = header.method_idx_size;
1880         JSHandle<ConstantPool> sconstpool = factory_->NewSConstantPool(constpoolSize);
1881         sconstpool->SetJSPandaFile(jsPandaFile);
1882         sconstpool->SetIndexHeader(&header);
1883         sconstpool->SetSharedConstpoolId(JSTaggedValue(index));
1884         sconstpool = AddOrUpdateConstpool(jsPandaFile, sconstpool, index);
1885         index++;
1886 
1887         JSHandle<ConstantPool> constpool = factory_->NewConstantPool(constpoolSize);
1888         constpool->SetJSPandaFile(jsPandaFile);
1889         constpool->SetIndexHeader(&header);
1890         SetUnsharedConstpool(sconstpool, constpool.GetTaggedValue());
1891     }
1892 }
1893 
ClearConstpoolBufferData()1894 void EcmaVM::ClearConstpoolBufferData()
1895 {
1896     cachedSharedConstpools_.clear();
1897     thread_->SetUnsharedConstpools(reinterpret_cast<uintptr_t>(nullptr));
1898     thread_->SetUnsharedConstpoolsArrayLen(0);
1899 }
1900 
FindConstpools(const JSPandaFile * jsPandaFile)1901 std::optional<std::reference_wrapper<CMap<int32_t, JSTaggedValue>>> EcmaVM::FindConstpools(
1902     const JSPandaFile *jsPandaFile)
1903 {
1904     return Runtime::GetInstance()->FindConstpools(jsPandaFile);
1905 }
1906 
AddSustainingJSHandle(SustainingJSHandle * sustainingHandle)1907 void EcmaVM::AddSustainingJSHandle(SustainingJSHandle *sustainingHandle)
1908 {
1909     if (sustainingJSHandleList_) {
1910         sustainingJSHandleList_->AddSustainingJSHandle(sustainingHandle);
1911     }
1912 }
1913 
RemoveSustainingJSHandle(SustainingJSHandle * sustainingHandle)1914 void EcmaVM::RemoveSustainingJSHandle(SustainingJSHandle *sustainingHandle)
1915 {
1916     if (sustainingJSHandleList_) {
1917         sustainingJSHandleList_->RemoveSustainingJSHandle(sustainingHandle);
1918     }
1919 }
1920 
InvokeEcmaAotEntrypoint(JSHandle<JSFunction> mainFunc,JSHandle<JSTaggedValue> & thisArg,const JSPandaFile * jsPandaFile,std::string_view entryPoint,CJSInfo * cjsInfo)1921 JSTaggedValue EcmaVM::InvokeEcmaAotEntrypoint(JSHandle<JSFunction> mainFunc, JSHandle<JSTaggedValue> &thisArg,
1922                                               const JSPandaFile *jsPandaFile, std::string_view entryPoint,
1923                                               CJSInfo* cjsInfo)
1924 {
1925     aotFileManager_->SetAOTMainFuncEntry(mainFunc, jsPandaFile, entryPoint);
1926     return JSFunction::InvokeOptimizedEntrypoint(thread_, mainFunc, thisArg, cjsInfo);
1927 }
1928 
ExecuteAot(size_t actualNumArgs,JSTaggedType * args,const JSTaggedType * prevFp,bool needPushArgv)1929 JSTaggedValue EcmaVM::ExecuteAot(size_t actualNumArgs, JSTaggedType *args,
1930                                  const JSTaggedType *prevFp, bool needPushArgv)
1931 {
1932     INTERPRETER_TRACE(thread_, ExecuteAot);
1933     ASSERT(thread_->IsInManagedState());
1934     // When C++ enters ASM, save the current globalenv and restore to glue after call
1935     SaveEnv envScope(thread_);
1936     auto entry = thread_->GetRTInterface(kungfu::RuntimeStubCSigns::ID_JSFunctionEntry);
1937     // entry of aot
1938     auto res = reinterpret_cast<JSFunctionEntryType>(entry)(thread_->GetGlueAddr(),
1939                                                             actualNumArgs,
1940                                                             args,
1941                                                             reinterpret_cast<uintptr_t>(prevFp),
1942                                                             needPushArgv);
1943     return res;
1944 }
1945 
CommonInvokeEcmaEntrypoint(const JSPandaFile * jsPandaFile,std::string_view entryPoint,JSHandle<JSFunction> & func,const ExecuteTypes & executeType)1946 Expected<JSTaggedValue, bool> EcmaVM::CommonInvokeEcmaEntrypoint(const JSPandaFile *jsPandaFile,
1947     std::string_view entryPoint, JSHandle<JSFunction> &func, const ExecuteTypes &executeType)
1948 {
1949     ASSERT(thread_->IsInManagedState());
1950     JSHandle<JSTaggedValue> global = GetGlobalEnv()->GetJSGlobalObject();
1951     JSHandle<JSTaggedValue> undefined = thread_->GlobalConstants()->GetHandledUndefined();
1952     if (IsEnablePGOProfiler()) {
1953         JSHandle<JSFunction> objectFunction(GetGlobalEnv()->GetObjectFunction());
1954         JSHandle<JSHClass> protoOrHClass(GetGlobalEnv()->GetObjectFunctionNapiClass());
1955         GetPGOProfiler()->ProfileNapiRootHClass(
1956             objectFunction.GetTaggedType(), protoOrHClass.GetTaggedType(), pgo::ProfileType::Kind::NapiId);
1957     }
1958     CString entry = entryPoint.data();
1959     JSRecordInfo *recordInfo = jsPandaFile->CheckAndGetRecordInfo(entry);
1960     if (recordInfo == nullptr) {
1961         CString msg = "Cannot find module '" + entry + "' , which is application Entry Point";
1962         THROW_REFERENCE_ERROR_AND_RETURN(thread_, msg.c_str(), Unexpected(false));
1963     }
1964 
1965     ModuleLogger *moduleLogger = thread_->GetModuleLogger();
1966     if (moduleLogger != nullptr) {
1967         moduleLogger->SetStartTime(entry);
1968     }
1969     if (jsPandaFile->IsModule(recordInfo)) {
1970         global = undefined;
1971         CString moduleName = jsPandaFile->GetJSPandaFileDesc();
1972         if (!jsPandaFile->IsBundlePack()) {
1973             moduleName = entry;
1974         }
1975         JSHandle<SourceTextModule> module;
1976         if (jsPandaFile->IsSharedModule(recordInfo)) {
1977             module = SharedModuleManager::GetInstance()->GetSModule(thread_, entry);
1978         } else {
1979             module = thread_->GetModuleManager()->HostGetImportedModule(moduleName);
1980         }
1981         // esm -> SourceTextModule; cjs or script -> string of recordName
1982         module->SetSendableEnv(thread_, JSTaggedValue::Undefined());
1983         func->SetModule(thread_, module);
1984     } else {
1985         // if it is Cjs at present, the module slot of the function is not used. We borrow it to store the recordName,
1986         // which can avoid the problem of larger memory caused by the new slot
1987         JSHandle<EcmaString> recordName = factory_->NewFromUtf8(entry);
1988         func->SetModule(thread_, recordName);
1989     }
1990     CheckStartCpuProfiler();
1991 
1992     JSTaggedValue result;
1993     if (jsPandaFile->IsCjs(recordInfo)) {
1994         CJSExecution(func, global, jsPandaFile, entryPoint);
1995         if (moduleLogger != nullptr) {
1996             moduleLogger->SetEndTime(entry);
1997         }
1998     } else {
1999         if (aotFileManager_->IsLoadMain(jsPandaFile, entry)) {
2000             EcmaRuntimeStatScope runtimeStatScope(this);
2001             result = InvokeEcmaAotEntrypoint(func, global, jsPandaFile, entryPoint);
2002         } else if (GetJSOptions().IsEnableForceJitCompileMain()) {
2003             Jit::Compile(this, func, CompilerTier::Tier::FAST);
2004             EcmaRuntimeStatScope runtimeStatScope(this);
2005             result = JSFunction::InvokeOptimizedEntrypoint(thread_, func, global, nullptr);
2006         } else if (GetJSOptions().IsEnableForceBaselineCompileMain()) {
2007             Jit::Compile(this, func, CompilerTier::Tier::BASELINE);
2008             EcmaRuntimeCallInfo *info =
2009                 EcmaInterpreter::NewRuntimeCallInfo(thread_, JSHandle<JSTaggedValue>(func), global, undefined, 0);
2010             EcmaRuntimeStatScope runtimeStatScope(this);
2011             result = EcmaInterpreter::Execute(info);
2012         } else {
2013             EcmaRuntimeCallInfo *info =
2014                 EcmaInterpreter::NewRuntimeCallInfo(thread_, JSHandle<JSTaggedValue>(func), global, undefined, 0);
2015             EcmaRuntimeStatScope runtimeStatScope(this);
2016             result = EcmaInterpreter::Execute(info);
2017         }
2018         if (moduleLogger != nullptr) {
2019             moduleLogger->SetEndTime(entry);
2020         }
2021 
2022         if (!thread_->HasPendingException() && IsStaticImport(executeType)) {
2023             JSHandle<JSTaggedValue> handleResult(thread_, result);
2024             job::MicroJobQueue::ExecutePendingJob(thread_, GetMicroJobQueue());
2025             result = handleResult.GetTaggedValue();
2026         }
2027     }
2028 
2029     if (thread_->HasPendingException()) {
2030         return GetPendingExceptionResult(result);
2031     }
2032     return result;
2033 }
2034 
InvokeEcmaEntrypoint(const JSPandaFile * jsPandaFile,std::string_view entryPoint,const ExecuteTypes & executeType)2035 Expected<JSTaggedValue, bool> EcmaVM::InvokeEcmaEntrypoint(const JSPandaFile *jsPandaFile,
2036                                                            std::string_view entryPoint,
2037                                                            const ExecuteTypes &executeType)
2038 {
2039     [[maybe_unused]] EcmaHandleScope scope(thread_);
2040     auto &options = const_cast<EcmaVM *>(thread_->GetEcmaVM())->GetJSOptions();
2041     if (options.EnableModuleLog()) {
2042         LOG_FULL(INFO) << "current executing file's name " << entryPoint.data();
2043     }
2044 
2045     JSHandle<Program> program = JSPandaFileManager::GetInstance()->GenerateProgram(this, jsPandaFile, entryPoint);
2046     if (program.IsEmpty()) {
2047         LOG_ECMA(ERROR) << "program is empty, invoke entrypoint failed";
2048         return Unexpected(false);
2049     }
2050     // for debugger
2051     GetJsDebuggerManager()->GetNotificationManager()->LoadModuleEvent(
2052         jsPandaFile->GetJSPandaFileDesc(), entryPoint);
2053 
2054     JSHandle<JSFunction> func(thread_, program->GetMainFunction(thread_));
2055     Expected<JSTaggedValue, bool> result = CommonInvokeEcmaEntrypoint(jsPandaFile, entryPoint, func, executeType);
2056 
2057     CheckHasPendingException(thread_);
2058     return result;
2059 }
2060 
InvokeEcmaEntrypointForHotReload(const JSPandaFile * jsPandaFile,std::string_view entryPoint,const ExecuteTypes & executeType)2061 Expected<JSTaggedValue, bool> EcmaVM::InvokeEcmaEntrypointForHotReload(
2062     const JSPandaFile *jsPandaFile, std::string_view entryPoint, const ExecuteTypes &executeType)
2063 {
2064     [[maybe_unused]] EcmaHandleScope scope(thread_);
2065     JSHandle<Program> program = JSPandaFileManager::GetInstance()->GenerateProgram(this, jsPandaFile, entryPoint);
2066 
2067     JSHandle<JSFunction> func(thread_, program->GetMainFunction(thread_));
2068     Expected<JSTaggedValue, bool> result = CommonInvokeEcmaEntrypoint(jsPandaFile, entryPoint, func, executeType);
2069 
2070     JSHandle<JSTaggedValue> finalModuleRecord(thread_, func->GetModule(thread_));
2071     // avoid GC problems.
2072     GlobalHandleCollection gloalHandleCollection(thread_);
2073     JSHandle<JSTaggedValue> moduleRecordHandle =
2074         gloalHandleCollection.NewHandle<JSTaggedValue>(finalModuleRecord->GetRawData());
2075     CString recordName = entryPoint.data();
2076     AddPatchModule(recordName, moduleRecordHandle);
2077 
2078     // print exception information
2079     if (thread_->HasPendingException() &&
2080         Method::Cast(func->GetMethod(thread_))->GetMethodName(thread_) != JSPandaFile::PATCH_FUNCTION_NAME_0) {
2081         return Unexpected(false);
2082     }
2083     return result;
2084 }
2085 
CJSExecution(JSHandle<JSFunction> & func,JSHandle<JSTaggedValue> & thisArg,const JSPandaFile * jsPandaFile,std::string_view entryPoint)2086 void EcmaVM::CJSExecution(JSHandle<JSFunction> &func, JSHandle<JSTaggedValue> &thisArg,
2087                           const JSPandaFile *jsPandaFile, std::string_view entryPoint)
2088 {
2089     // create "module", "exports", "require", "filename", "dirname"
2090     JSHandle<CjsModule> module = factory_->NewCjsModule();
2091     JSHandle<JSTaggedValue> require = GetGlobalEnv()->GetCjsRequireFunction();
2092     JSHandle<CjsExports> exports = factory_->NewCjsExports();
2093     CString fileNameStr;
2094     CString dirNameStr;
2095     if (jsPandaFile->IsBundlePack()) {
2096         ModulePathHelper::ResolveCurrentPath(dirNameStr, fileNameStr, jsPandaFile);
2097     } else {
2098         JSTaggedValue funcFileName = func->GetModule(thread_);
2099         ASSERT(funcFileName.IsString());
2100         fileNameStr = ModulePathHelper::Utf8ConvertToString(thread_, funcFileName);
2101         dirNameStr = PathHelper::ResolveDirPath(fileNameStr);
2102     }
2103     JSHandle<JSTaggedValue> fileName = JSHandle<JSTaggedValue>::Cast(factory_->NewFromUtf8(fileNameStr));
2104     JSHandle<JSTaggedValue> dirName = JSHandle<JSTaggedValue>::Cast(factory_->NewFromUtf8(dirNameStr));
2105     CJSInfo cjsInfo(module, require, exports, fileName, dirName);
2106     RequireManager::InitializeCommonJS(thread_, cjsInfo);
2107     if (aotFileManager_->IsLoadMain(jsPandaFile, entryPoint.data())) {
2108         EcmaRuntimeStatScope runtimeStateScope(this);
2109         InvokeEcmaAotEntrypoint(func, thisArg, jsPandaFile, entryPoint, &cjsInfo);
2110     } else {
2111         // Execute main function
2112         JSHandle<JSTaggedValue> undefined = thread_->GlobalConstants()->GetHandledUndefined();
2113         EcmaRuntimeCallInfo *info =
2114             EcmaInterpreter::NewRuntimeCallInfo(thread_,
2115                                                 JSHandle<JSTaggedValue>(func),
2116                                                 thisArg, undefined, 5); // 5 : argument numbers
2117         RETURN_IF_ABRUPT_COMPLETION(thread_);
2118         info->SetCallArg(cjsInfo.exportsHdl.GetTaggedValue(),
2119             cjsInfo.requireHdl.GetTaggedValue(),
2120             cjsInfo.moduleHdl.GetTaggedValue(),
2121             cjsInfo.filenameHdl.GetTaggedValue(),
2122             cjsInfo.dirnameHdl.GetTaggedValue());
2123         EcmaRuntimeStatScope runtimeStatScope(this);
2124         EcmaInterpreter::Execute(info);
2125     }
2126     if (!thread_->HasPendingException()) {
2127         // Collecting module.exports : exports ---> module.exports --->Module._cache
2128         RequireManager::CollectExecutedExp(thread_, cjsInfo);
2129     }
2130 }
2131 
ClearKeptObjects(JSThread * thread)2132 void EcmaVM::ClearKeptObjects(JSThread *thread)
2133 {
2134     JSHandle<GlobalEnv> globalEnv = thread->GetGlobalEnv();
2135     if (LIKELY(globalEnv->GetTaggedWeakRefKeepObjects().IsUndefined())) {
2136         return;
2137     }
2138     globalEnv->SetWeakRefKeepObjects(thread, JSTaggedValue::Undefined());
2139 }
2140 
AddToKeptObjects(JSThread * thread,JSHandle<JSTaggedValue> value)2141 void EcmaVM::AddToKeptObjects(JSThread *thread, JSHandle<JSTaggedValue> value)
2142 {
2143     if (value->IsInSharedHeap()) {
2144         return;
2145     }
2146 
2147     JSHandle<GlobalEnv> globalEnv = thread->GetGlobalEnv();
2148     JSHandle<LinkedHashSet> linkedSet;
2149     if (globalEnv->GetWeakRefKeepObjects()->IsUndefined()) {
2150         linkedSet = LinkedHashSet::Create(thread);
2151     } else {
2152         linkedSet = JSHandle<LinkedHashSet>(thread,
2153             LinkedHashSet::Cast(globalEnv->GetWeakRefKeepObjects()->GetTaggedObject()));
2154     }
2155     linkedSet = LinkedHashSet::Add(thread, linkedSet, value);
2156     globalEnv->SetWeakRefKeepObjects(thread, linkedSet);
2157 }
2158 
AddModuleManager(ModuleManager * moduleManager)2159 void EcmaVM::AddModuleManager(ModuleManager *moduleManager)
2160 {
2161     moduleManagers_.PushBack(moduleManager);
2162 }
2163 
Iterate(RootVisitor & v)2164 void EcmaVM::ModuleManagers::Iterate(RootVisitor &v)
2165 {
2166     LockHolder lock(CMCGCMutex_);
2167     for (ModuleManager *moduleManager : moduleManagersVec_) {
2168         moduleManager->Iterate(v);
2169     }
2170 }
2171 
2172 template <typename T>
PushBack(T v)2173 void EcmaVM::ModuleManagers::PushBack(T v)
2174 {
2175     LockHolder lock(CMCGCMutex_);
2176     moduleManagersVec_.push_back(v);
2177 }
2178 
DestroyAllNativeObj()2179 void EcmaVM::ModuleManagers::DestroyAllNativeObj()
2180 {
2181     LockHolder lock(CMCGCMutex_);
2182     for (auto &moduleManager : moduleManagersVec_) {
2183         moduleManager->NativeObjDestory();
2184     }
2185 }
2186 
Clear()2187 void EcmaVM::ModuleManagers::Clear()
2188 {
2189     LockHolder lock(CMCGCMutex_);
2190     for (auto &moduleManager : moduleManagersVec_) {
2191         delete moduleManager;
2192         moduleManager = nullptr;
2193     }
2194     moduleManagersVec_.clear();
2195 }
2196 
InitDataViewTypeTable(const GlobalEnvConstants * constant)2197 void EcmaVM::InitDataViewTypeTable(const GlobalEnvConstants *constant)
2198 {
2199     dataViewTypeTable_.emplace(constant->GetInt8ArrayString().GetRawData(), static_cast<int8_t>(DataViewType::INT8));
2200     dataViewTypeTable_.emplace(
2201         constant->GetSharedInt8ArrayString().GetRawData(), static_cast<int8_t>(DataViewType::INT8));
2202     dataViewTypeTable_.emplace(constant->GetUint8ArrayString().GetRawData(), static_cast<int8_t>(DataViewType::UINT8));
2203     dataViewTypeTable_.emplace(
2204         constant->GetSharedUint8ArrayString().GetRawData(), static_cast<int8_t>(DataViewType::UINT8));
2205     dataViewTypeTable_.emplace(
2206         constant->GetUint8ClampedArrayString().GetRawData(), static_cast<int8_t>(DataViewType::UINT8_CLAMPED));
2207     dataViewTypeTable_.emplace(
2208         constant->GetSharedUint8ClampedArrayString().GetRawData(), static_cast<int8_t>(DataViewType::UINT8_CLAMPED));
2209     dataViewTypeTable_.emplace(constant->GetInt16ArrayString().GetRawData(), static_cast<int8_t>(DataViewType::INT16));
2210     dataViewTypeTable_.emplace(
2211         constant->GetSharedInt16ArrayString().GetRawData(), static_cast<int8_t>(DataViewType::INT16));
2212     dataViewTypeTable_.emplace(
2213         constant->GetUint16ArrayString().GetRawData(), static_cast<int8_t>(DataViewType::UINT16));
2214     dataViewTypeTable_.emplace(
2215         constant->GetSharedUint16ArrayString().GetRawData(), static_cast<int8_t>(DataViewType::UINT16));
2216     dataViewTypeTable_.emplace(constant->GetInt32ArrayString().GetRawData(), static_cast<int8_t>(DataViewType::INT32));
2217     dataViewTypeTable_.emplace(
2218         constant->GetSharedInt32ArrayString().GetRawData(), static_cast<int8_t>(DataViewType::INT32));
2219     dataViewTypeTable_.emplace(
2220         constant->GetUint32ArrayString().GetRawData(), static_cast<int8_t>(DataViewType::UINT32));
2221     dataViewTypeTable_.emplace(
2222         constant->GetSharedUint32ArrayString().GetRawData(), static_cast<int8_t>(DataViewType::UINT32));
2223     dataViewTypeTable_.emplace(
2224         constant->GetFloat32ArrayString().GetRawData(), static_cast<int8_t>(DataViewType::FLOAT32));
2225     dataViewTypeTable_.emplace(
2226         constant->GetSharedFloat32ArrayString().GetRawData(), static_cast<int8_t>(DataViewType::FLOAT32));
2227     dataViewTypeTable_.emplace(
2228         constant->GetFloat64ArrayString().GetRawData(), static_cast<int8_t>(DataViewType::FLOAT64));
2229     dataViewTypeTable_.emplace(
2230         constant->GetSharedFloat64ArrayString().GetRawData(), static_cast<int8_t>(DataViewType::FLOAT64));
2231     dataViewTypeTable_.emplace(
2232         constant->GetBigInt64ArrayString().GetRawData(), static_cast<int8_t>(DataViewType::BIGINT64));
2233     dataViewTypeTable_.emplace(
2234         constant->GetSharedBigInt64ArrayString().GetRawData(), static_cast<int8_t>(DataViewType::BIGINT64));
2235     dataViewTypeTable_.emplace(
2236         constant->GetBigUint64ArrayString().GetRawData(), static_cast<int8_t>(DataViewType::BIGUINT64));
2237     dataViewTypeTable_.emplace(
2238         constant->GetSharedBigUint64ArrayString().GetRawData(), static_cast<int8_t>(DataViewType::BIGUINT64));
2239 }
2240 }  // namespace panda::ecmascript
2241