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(µJobQueue_)));
942 }
943 if (!registerSymbols_.IsHole()) {
944 v.VisitRoot(Root::ROOT_VM, ObjectSlot(ToUintPtr(®isterSymbols_)));
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, ×pro);
1581 if (res) {
1582 return startRealTime;
1583 }
1584 auto res1 = clock_gettime(CLOCK_MONOTONIC, ×sys);
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>(µJobQueue_));
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