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 "ecmascript/builtins/builtins_ark_tools.h"
19 #include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
20 #ifdef ARK_SUPPORT_INTL
21 #include "ecmascript/builtins/builtins_collator.h"
22 #include "ecmascript/builtins/builtins_date_time_format.h"
23 #include "ecmascript/builtins/builtins_number_format.h"
24 #endif
25 #include "ecmascript/builtins/builtins_global.h"
26 #include "ecmascript/builtins/builtins_object.h"
27 #include "ecmascript/builtins/builtins_promise_handler.h"
28 #include "ecmascript/builtins/builtins_proxy.h"
29 #include "ecmascript/jit/jit_task.h"
30 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
31 #include "ecmascript/dfx/cpu_profiler/cpu_profiler.h"
32 #endif
33 #if !WIN_OR_MAC_OR_IOS_PLATFORM
34 #include "ecmascript/dfx/hprof/heap_profiler.h"
35 #include "ecmascript/dfx/hprof/heap_profiler_interface.h"
36 #endif
37 #include "ecmascript/dfx/tracing/tracing.h"
38 #include "ecmascript/dfx/vmstat/function_call_timer.h"
39 #include "ecmascript/mem/shared_heap/shared_concurrent_marker.h"
40 #include "ecmascript/module/module_logger.h"
41 #include "ecmascript/pgo_profiler/pgo_trace.h"
42 #include "ecmascript/snapshot/mem/snapshot.h"
43 #include "ecmascript/stubs/runtime_stubs.h"
44 #include "ecmascript/ohos/jit_tools.h"
45 #include "ecmascript/ohos/aot_tools.h"
46 #include "ecmascript/checkpoint/thread_state_transition.h"
47 #include "ecmascript/mem/heap-inl.h"
48 
49 #if defined(PANDA_TARGET_OHOS) && !defined(STANDALONE_MODE)
50 #include "parameters.h"
51 #endif
52 
53 namespace panda::ecmascript {
54 using RandomGenerator = base::RandomGenerator;
55 using PGOProfilerManager = pgo::PGOProfilerManager;
56 using JitTools = ohos::JitTools;
57 AOTFileManager *JsStackInfo::loader = nullptr;
58 JSRuntimeOptions *JsStackInfo::options = nullptr;
59 bool EcmaVM::multiThreadCheck_ = false;
60 bool EcmaVM::errorInfoEnhanced_ = false;
61 
Create(const JSRuntimeOptions &options)62 EcmaVM *EcmaVM::Create(const JSRuntimeOptions &options)
63 {
64     Runtime::CreateIfFirstVm(options);
65     auto heapType = options.IsWorker() ? EcmaParamConfiguration::HeapType::WORKER_HEAP :
66         EcmaParamConfiguration::HeapType::DEFAULT_HEAP;
67     size_t heapSize = options.GetHeapSize();
68 #if defined(PANDA_TARGET_OHOS) && !defined(STANDALONE_MODE)
69     switch (heapType) {
70         case EcmaParamConfiguration::HeapType::WORKER_HEAP:
71             heapSize = OHOS::system::GetUintParameter<size_t>("persist.ark.heap.workersize", 0) * 1_MB;
72             break;
73         default:
74             heapSize = OHOS::system::GetUintParameter<size_t>("persist.ark.heap.defaultsize", 0) * 1_MB;
75             break;
76     }
77 #endif
78     auto config = EcmaParamConfiguration(heapType,
79                                          MemMapAllocator::GetInstance()->GetCapacity(),
80                                          heapSize);
81     JSRuntimeOptions newOptions = options;
82     // only define SUPPORT_ENABLE_ASM_INTERP can enable asm-interpreter
83 #if !defined(SUPPORT_ENABLE_ASM_INTERP)
84     newOptions.SetEnableAsmInterpreter(false);
85 #endif
86     auto vm = new EcmaVM(newOptions, config);
87     auto jsThread = JSThread::Create(vm);
88     vm->thread_ = jsThread;
89     Runtime::GetInstance()->InitializeIfFirstVm(vm);
90     if (JsStackInfo::loader == nullptr) {
91         JsStackInfo::loader = vm->GetAOTFileManager();
92     }
93     if (JsStackInfo::options == nullptr) {
94         JsStackInfo::options = &(vm->GetJSOptions());
95     }
96 #if defined(PANDA_TARGET_OHOS) && !defined(STANDALONE_MODE)
97     int arkProperties = OHOS::system::GetIntParameter<int>("persist.ark.properties", -1);
98     vm->GetJSOptions().SetArkProperties(arkProperties);
99 #endif
100     return vm;
101 }
102 
103 // static
Destroy(EcmaVM *vm)104 bool EcmaVM::Destroy(EcmaVM *vm)
105 {
106     if (UNLIKELY(vm == nullptr)) {
107         return false;
108     }
109     delete vm;
110     Runtime::DestroyIfLastVm();
111     return true;
112 }
113 
PreFork()114 void EcmaVM::PreFork()
115 {
116     heap_->CompactHeapBeforeFork();
117     heap_->AdjustSpaceSizeForAppSpawn();
118     heap_->GetReadOnlySpace()->SetReadOnly();
119     heap_->DisableParallelGC();
120     SetPostForked(false);
121 
122     auto sHeap = SharedHeap::GetInstance();
123     sHeap->CompactHeapBeforeFork(thread_);
124     sHeap->DisableParallelGC(thread_);
125 }
126 
PostFork()127 void EcmaVM::PostFork()
128 {
129     RandomGenerator::InitRandom(GetAssociatedJSThread());
130     heap_->SetHeapMode(HeapMode::SHARE);
131     GetAssociatedJSThread()->PostFork();
132     Taskpool::GetCurrentTaskpool()->Initialize();
133     SetPostForked(true);
134     LOG_ECMA(INFO) << "multi-thread check enabled: " << GetThreadCheckStatus();
135     SignalAllReg();
136     SharedHeap::GetInstance()->EnableParallelGC(GetJSOptions());
137     DaemonThread::GetInstance()->StartRunning();
138     heap_->EnableParallelGC();
139     options_.SetPgoForceDump(false);
140     std::string bundleName = PGOProfilerManager::GetInstance()->GetBundleName();
141     pgo::PGOTrace::GetInstance()->SetEnable(ohos::AotTools::GetPgoTraceEnable());
142     AotCrashInfo::GetInstance().SetOptionPGOProfiler(&options_, bundleName);
143     ResetPGOProfiler();
144     processStartRealtime_ = InitializeStartRealTime();
145 
146     Jit::GetInstance()->SetJitEnablePostFork(this, bundleName);
147 #ifdef ENABLE_POSTFORK_FORCEEXPAND
148     heap_->NotifyPostFork();
149     heap_->NotifyFinishColdStartSoon();
150 #endif
151     ModuleLogger *moduleLogger = thread_->GetCurrentEcmaContext()->GetModuleLogger();
152     if (moduleLogger != nullptr) {
153         moduleLogger->PostModuleLoggerTask(thread_->GetThreadId(), this);
154     }
155 #if defined(PANDA_TARGET_OHOS) && !defined(STANDALONE_MODE)
156     int arkProperties = OHOS::system::GetIntParameter<int>("persist.ark.properties", -1);
157     GetJSOptions().SetArkProperties(arkProperties);
158 #endif
159     auto startIdleMonitor = JSNApi::GetStartIdleMonitorCallback();
160     if (startIdleMonitor != nullptr) {
161         startIdleMonitor();
162     }
163 }
164 
EcmaVM(JSRuntimeOptions options, EcmaParamConfiguration config)165 EcmaVM::EcmaVM(JSRuntimeOptions options, EcmaParamConfiguration config)
166     : nativeAreaAllocator_(std::make_unique<NativeAreaAllocator>()),
167       heapRegionAllocator_(std::make_unique<HeapRegionAllocator>()),
168       chunk_(nativeAreaAllocator_.get()),
169       ecmaParamConfiguration_(std::move(config))
170 {
171     options_ = std::move(options);
172     LOG_ECMA(DEBUG) << "multi-thread check enabled: " << GetThreadCheckStatus();
173     icEnabled_ = options_.EnableIC();
174     optionalLogEnabled_ = options_.EnableOptionalLog();
175     options_.ParseAsmInterOption();
176     SetEnableOsr(options_.IsEnableOSR() && options_.IsEnableJIT() && options_.GetEnableAsmInterpreter());
177     processStartRealtime_ = InitializeStartRealTime();
178 }
179 
180 // for jit
EcmaVM()181 EcmaVM::EcmaVM()
182     : nativeAreaAllocator_(std::make_unique<NativeAreaAllocator>()),
183       heapRegionAllocator_(nullptr),
184       chunk_(nativeAreaAllocator_.get()) {}
185 
InitializeForJit(JitThread *jitThread)186 void EcmaVM::InitializeForJit(JitThread *jitThread)
187 {
188     thread_ = jitThread;
189     stringTable_ = Runtime::GetInstance()->GetEcmaStringTable();
190     ASSERT(stringTable_);
191     // ObjectFactory only sypport alloc string in sharedheap
192     factory_ = chunk_.New<ObjectFactory>(thread_, nullptr, SharedHeap::GetInstance());
193     SetIsJitCompileVM(true);
194 }
195 
InitializePGOProfiler()196 void EcmaVM::InitializePGOProfiler()
197 {
198     bool isEnablePGOProfiler = IsEnablePGOProfiler();
199     if (pgoProfiler_ == nullptr) {
200         pgoProfiler_ = PGOProfilerManager::GetInstance()->Build(this, isEnablePGOProfiler);
201     }
202     pgo::PGOTrace::GetInstance()->SetEnable(options_.GetPGOTrace() || ohos::AotTools::GetPgoTraceEnable());
203     thread_->SetPGOProfilerEnable(isEnablePGOProfiler);
204 }
205 
ResetPGOProfiler()206 void EcmaVM::ResetPGOProfiler()
207 {
208     if (pgoProfiler_ != nullptr) {
209         bool isEnablePGOProfiler = IsEnablePGOProfiler();
210         PGOProfilerManager::GetInstance()->Reset(pgoProfiler_, isEnablePGOProfiler);
211         thread_->SetPGOProfilerEnable(isEnablePGOProfiler);
212         thread_->CheckOrSwitchPGOStubs();
213         thread_->SetEnableForceIC(ecmascript::pgo::PGOProfilerManager::GetInstance()->IsEnableForceIC());
214     }
215 }
216 
DisablePGOProfilerWithAOTFile(const std::string &aotFileName)217 void EcmaVM::DisablePGOProfilerWithAOTFile(const std::string &aotFileName)
218 {
219     if (AOTFileManager::AOTFileExist(aotFileName, AOTFileManager::FILE_EXTENSION_AN) ||
220         AOTFileManager::AOTFileExist(aotFileName, AOTFileManager::FILE_EXTENSION_AI)) {
221         options_.SetEnablePGOProfiler(false);
222         PGOProfilerManager::GetInstance()->SetDisablePGO(true);
223         ResetPGOProfiler();
224     }
225 }
226 
IsEnablePGOProfiler() const227 bool EcmaVM::IsEnablePGOProfiler() const
228 {
229     if (options_.IsWorker()) {
230         return PGOProfilerManager::GetInstance()->IsEnable();
231     }
232     return options_.GetEnableAsmInterpreter() && options_.IsEnablePGOProfiler();
233 }
234 
IsEnableElementsKind() const235 bool EcmaVM::IsEnableElementsKind() const
236 {
237     return options_.GetEnableAsmInterpreter() && options_.IsEnableElementsKind();
238 }
239 
IsEnableFastJit() const240 bool EcmaVM::IsEnableFastJit() const
241 {
242     return GetJit()->IsEnableFastJit();
243 }
244 
IsEnableBaselineJit() const245 bool EcmaVM::IsEnableBaselineJit() const
246 {
247     return GetJit()->IsEnableBaselineJit();
248 }
249 
GetTid() const250 uint32_t EcmaVM::GetTid() const
251 {
252     return thread_->GetThreadId();
253 }
254 
GetJit() const255 Jit *EcmaVM::GetJit() const
256 {
257     return Jit::GetInstance();
258 }
259 
Initialize()260 bool EcmaVM::Initialize()
261 {
262     ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "EcmaVM::Initialize");
263     stringTable_ = Runtime::GetInstance()->GetEcmaStringTable();
264     InitializePGOProfiler();
265     Taskpool::GetCurrentTaskpool()->Initialize();
266 #ifndef PANDA_TARGET_WINDOWS
267     RuntimeStubs::Initialize(thread_);
268 #endif
269     heap_ = new Heap(this);
270     heap_->Initialize();
271     gcStats_ = chunk_.New<GCStats>(heap_, options_.GetLongPauseTime());
272     gcKeyStats_ = chunk_.New<GCKeyStats>(heap_, gcStats_);
273     factory_ = chunk_.New<ObjectFactory>(thread_, heap_, SharedHeap::GetInstance());
274     if (UNLIKELY(factory_ == nullptr)) {
275         LOG_FULL(FATAL) << "alloc factory_ failed";
276         UNREACHABLE();
277     }
278     debuggerManager_ = new tooling::JsDebuggerManager(this);
279     aotFileManager_ = new AOTFileManager(this);
280     auto context = new EcmaContext(thread_);
281     thread_->PushContext(context);
282     [[maybe_unused]] EcmaHandleScope scope(thread_);
283     thread_->SetReadyForGCIterating(true);
284     thread_->SetSharedMarkStatus(DaemonThread::GetInstance()->GetSharedMarkStatus());
285     snapshotEnv_ = new SnapshotEnv(this);
286     context->Initialize();
287     snapshotEnv_->AddGlobalConstToMap();
288     thread_->SetGlueGlobalEnv(reinterpret_cast<GlobalEnv *>(context->GetGlobalEnv().GetTaggedType()));
289     thread_->SetGlobalObject(GetGlobalEnv()->GetGlobalObject());
290     thread_->SetCurrentEcmaContext(context);
291     GenerateInternalNativeMethods();
292     quickFixManager_ = new QuickFixManager();
293     if (options_.GetEnableAsmInterpreter()) {
294         thread_->GetCurrentEcmaContext()->LoadStubFile();
295     }
296     if (options_.EnableEdenGC()) {
297         heap_->EnableEdenGC();
298     }
299 
300     callTimer_ = new FunctionCallTimer();
301     strategy_ = new ThroughputJSObjectResizingStrategy();
302     if (IsEnableFastJit() || IsEnableBaselineJit()) {
303         Jit::GetInstance()->ConfigJit(this);
304     }
305     initialized_ = true;
306     return true;
307 }
308 
~EcmaVM()309 EcmaVM::~EcmaVM()
310 {
311     if (isJitCompileVM_) {
312         if (factory_ != nullptr) {
313             chunk_.Delete(factory_);
314             factory_ = nullptr;
315         }
316         stringTable_ = nullptr;
317         thread_ = nullptr;
318         return;
319     }
320 #if ECMASCRIPT_ENABLE_THREAD_STATE_CHECK
321     if (UNLIKELY(!thread_->IsInRunningStateOrProfiling())) {
322         LOG_ECMA(FATAL) << "Destruct VM must be in jsthread running state";
323         UNREACHABLE();
324     }
325 #endif
326     initialized_ = false;
327 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
328     if (profiler_ != nullptr) {
329         if (profiler_->GetOutToFile()) {
330             DFXJSNApi::StopCpuProfilerForFile(this);
331         } else {
332             DFXJSNApi::StopCpuProfilerForInfo(this);
333         }
334     }
335     if (profiler_ != nullptr) {
336         delete profiler_;
337         profiler_ = nullptr;
338     }
339 #endif
340 #if defined(ECMASCRIPT_SUPPORT_HEAPPROFILER)
341     DeleteHeapProfile();
342 #endif
343     if (IsEnableFastJit() || IsEnableBaselineJit()) {
344         GetJit()->ClearTaskWithVm(this);
345     }
346     // clear c_address: c++ pointer delete
347     ClearBufferData();
348     heap_->WaitAllTasksFinished();
349     Taskpool::GetCurrentTaskpool()->Destroy(thread_->GetThreadId());
350 
351     if (pgoProfiler_ != nullptr) {
352         PGOProfilerManager::GetInstance()->Destroy(pgoProfiler_);
353         pgoProfiler_ = nullptr;
354     }
355 
356 #if ECMASCRIPT_ENABLE_FUNCTION_CALL_TIMER
357     DumpCallTimeInfo();
358 #endif
359 
360 #if defined(ECMASCRIPT_SUPPORT_TRACING)
361     if (tracing_) {
362         DFXJSNApi::StopTracing(this);
363     }
364 #endif
365 
366     thread_->GetCurrentEcmaContext()->GetModuleManager()->NativeObjDestory();
367 
368     if (!isBundlePack_) {
369         std::shared_ptr<JSPandaFile> jsPandaFile = JSPandaFileManager::GetInstance()->FindJSPandaFile(assetPath_);
370         if (jsPandaFile != nullptr) {
371             jsPandaFile->DeleteParsedConstpoolVM(this);
372         }
373     }
374 
375     if (gcStats_ != nullptr) {
376         if (options_.EnableGCStatsPrint()) {
377             gcStats_->PrintStatisticResult();
378         }
379         chunk_.Delete(gcStats_);
380         gcStats_ = nullptr;
381     }
382 
383     if (gcKeyStats_ != nullptr) {
384         chunk_.Delete(gcKeyStats_);
385         gcKeyStats_ = nullptr;
386     }
387 
388     if (JsStackInfo::loader == aotFileManager_) {
389         JsStackInfo::loader = nullptr;
390     }
391 
392     if (heap_ != nullptr) {
393         heap_->Destroy();
394         delete heap_;
395         heap_ = nullptr;
396     }
397 
398     SharedHeap *sHeap = SharedHeap::GetInstance();
399     const Heap *heap = Runtime::GetInstance()->GetMainThread()->GetEcmaVM()->GetHeap();
400     if (IsWorkerThread() && Runtime::SharedGCRequest()) {
401         // destory workervm to release mem.
402         thread_->SetReadyForGCIterating(false);
403         if (sHeap->CheckCanTriggerConcurrentMarking(thread_)) {
404             sHeap->TriggerConcurrentMarking<TriggerGCType::SHARED_GC, GCReason::WORKER_DESTRUCTION>(thread_);
405         } else if (heap && !heap->InSensitiveStatus() && !sHeap->GetConcurrentMarker()->IsEnabled()) {
406             sHeap->CollectGarbage<TriggerGCType::SHARED_GC, GCReason::WORKER_DESTRUCTION>(thread_);
407         }
408     }
409 
410     if (debuggerManager_ != nullptr) {
411         delete debuggerManager_;
412         debuggerManager_ = nullptr;
413     }
414 
415     if (aotFileManager_ != nullptr) {
416         delete aotFileManager_;
417         aotFileManager_ = nullptr;
418     }
419 
420     if (factory_ != nullptr) {
421         chunk_.Delete(factory_);
422         factory_ = nullptr;
423     }
424 
425     if (stringTable_ != nullptr) {
426         stringTable_ = nullptr;
427     }
428 
429     if (quickFixManager_ != nullptr) {
430         delete quickFixManager_;
431         quickFixManager_ = nullptr;
432     }
433 
434     if (snapshotEnv_ != nullptr) {
435         snapshotEnv_->ClearEnvMap();
436         delete snapshotEnv_;
437         snapshotEnv_ = nullptr;
438     }
439 
440     if (callTimer_ != nullptr) {
441         delete callTimer_;
442         callTimer_ = nullptr;
443     }
444 
445     if (strategy_ != nullptr) {
446         delete strategy_;
447         strategy_ = nullptr;
448     }
449 
450     if (thread_ != nullptr) {
451         delete thread_;
452         thread_ = nullptr;
453     }
454 }
455 
GetGlobalEnv() const456 JSHandle<GlobalEnv> EcmaVM::GetGlobalEnv() const
457 {
458     return thread_->GetCurrentEcmaContext()->GetGlobalEnv();
459 }
460 
CheckThread() const461 void EcmaVM::CheckThread() const
462 {
463     // Exclude GC thread
464     if (thread_ == nullptr) {
465         LOG_FULL(FATAL) << "Fatal: ecma_vm has been destructed! vm address is: " << this;
466         UNREACHABLE();
467     }
468     if (!Taskpool::GetCurrentTaskpool()->IsDaemonThreadOrInThreadPool(std::this_thread::get_id()) &&
469         thread_->GetThreadId() != JSThread::GetCurrentThreadId() && !thread_->IsCrossThreadExecutionEnable()) {
470             LOG_FULL(FATAL) << "Fatal: ecma_vm cannot run in multi-thread!"
471                                 << " thread:" << thread_->GetThreadId()
472                                 << " currentThread:" << JSThread::GetCurrentThreadId();
473         UNREACHABLE();
474     }
475 }
476 
GetAndFastCheckJSThread() const477 JSThread *EcmaVM::GetAndFastCheckJSThread() const
478 {
479     if (thread_ == nullptr) {
480         LOG_FULL(FATAL) << "Fatal: ecma_vm has been destructed! vm address is: " << this;
481     }
482     if (thread_->GetThreadId() != JSThread::GetCurrentThreadId() && !thread_->IsCrossThreadExecutionEnable()) {
483         LOG_FULL(FATAL) << "Fatal: ecma_vm cannot run in multi-thread!"
484                                 << " thread:" << thread_->GetThreadId()
485                                 << " currentThread:" << JSThread::GetCurrentThreadId();
486     }
487     return thread_;
488 }
489 
CheckSingleThread() const490 bool EcmaVM::CheckSingleThread() const
491 {
492     if (thread_ == nullptr) {
493         LOG_FULL(FATAL) << "Fatal: ecma_vm has been destructed! vm address is: " << this;
494         return false;
495     }
496     if (thread_->GetThreadId() != JSThread::GetCurrentThreadId()) {
497         LOG_FULL(FATAL) << "Fatal: ecma_vm cannot run in multi-thread!"
498                         << " thread:" << thread_->GetThreadId()
499                         << " currentThread:" << JSThread::GetCurrentThreadId();
500         return false;
501     }
502     return true;
503 }
504 
FastCallAot(size_t actualNumArgs, JSTaggedType *args, const JSTaggedType *prevFp)505 JSTaggedValue EcmaVM::FastCallAot(size_t actualNumArgs, JSTaggedType *args, const JSTaggedType *prevFp)
506 {
507     INTERPRETER_TRACE(thread_, ExecuteAot);
508     ASSERT(thread_->IsInManagedState());
509     auto entry = thread_->GetRTInterface(kungfu::RuntimeStubCSigns::ID_OptimizedFastCallEntry);
510     // entry of aot
511     auto res = reinterpret_cast<FastCallAotEntryType>(entry)(thread_->GetGlueAddr(),
512                                                              actualNumArgs,
513                                                              args,
514                                                              reinterpret_cast<uintptr_t>(prevFp));
515     return res;
516 }
517 
CheckStartCpuProfiler()518 void EcmaVM::CheckStartCpuProfiler()
519 {
520 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
521     if (options_.EnableCpuProfilerColdStartMainThread() && options_.GetArkBundleName().compare(bundleName_) == 0 &&
522         !options_.IsWorker() && profiler_ == nullptr) {
523         std::string fileName = options_.GetArkBundleName() + ".cpuprofile";
524         if (!builtins::BuiltinsArkTools::CreateFile(fileName)) {
525             LOG_ECMA(ERROR) << "createFile failed " << fileName;
526             return;
527         } else {
528             DFXJSNApi::StartCpuProfilerForFile(this, fileName, CpuProfiler::INTERVAL_OF_INNER_START);
529             return;
530         }
531     }
532 
533     if (options_.EnableCpuProfilerColdStartWorkerThread() && options_.GetArkBundleName().compare(bundleName_) == 0 &&
534         options_.IsWorker() && profiler_ == nullptr) {
535         std::string fileName = options_.GetArkBundleName() + "_"
536                                + std::to_string(thread_->GetThreadId()) + ".cpuprofile";
537         if (!builtins::BuiltinsArkTools::CreateFile(fileName)) {
538             LOG_ECMA(ERROR) << "createFile failed " << fileName;
539             return;
540         } else {
541             DFXJSNApi::StartCpuProfilerForFile(this, fileName, CpuProfiler::INTERVAL_OF_INNER_START);
542             return;
543         }
544     }
545 #endif
546 }
547 
GetAndClearEcmaUncaughtException() const548 JSHandle<JSTaggedValue> EcmaVM::GetAndClearEcmaUncaughtException() const
549 {
550     JSHandle<JSTaggedValue> exceptionHandle = GetEcmaUncaughtException();
551     thread_->ClearException();  // clear for ohos app
552     return exceptionHandle;
553 }
554 
GetEcmaUncaughtException() const555 JSHandle<JSTaggedValue> EcmaVM::GetEcmaUncaughtException() const
556 {
557     if (!thread_->HasPendingException()) {
558         return JSHandle<JSTaggedValue>();
559     }
560     JSHandle<JSTaggedValue> exceptionHandle(thread_, thread_->GetException());
561     return exceptionHandle;
562 }
563 
PrintAOTSnapShotStats()564 void EcmaVM::PrintAOTSnapShotStats()
565 {
566     static constexpr int nameRightAdjustment = 30;
567     static constexpr int numberRightAdjustment = 30;
568     LOG_ECMA(ERROR) << std::right << std::setw(nameRightAdjustment) << "AOT Snapshot Genre"
569                     << std::setw(numberRightAdjustment) << "Count";
570     LOG_ECMA(ERROR) << "==========================================================================";
571     for (const auto &iter: aotSnapShotStatsMap_) {
572         LOG_ECMA(ERROR) << std::right << std::setw(nameRightAdjustment) << iter.first
573                         << std::setw(numberRightAdjustment) << iter.second;
574     }
575     LOG_ECMA(ERROR) << "==========================================================================";
576     aotSnapShotStatsMap_.clear();
577 }
578 
PrintJSErrorInfo(const JSHandle<JSTaggedValue> &exceptionInfo) const579 void EcmaVM::PrintJSErrorInfo(const JSHandle<JSTaggedValue> &exceptionInfo) const
580 {
581     EcmaContext::PrintJSErrorInfo(thread_, exceptionInfo);
582 }
583 
ProcessNativeDelete(const WeakRootVisitor& visitor)584 void EcmaVM::ProcessNativeDelete(const WeakRootVisitor& visitor)
585 {
586     heap_->ProcessNativeDelete(visitor);
587 }
588 
ProcessReferences(const WeakRootVisitor& visitor)589 void EcmaVM::ProcessReferences(const WeakRootVisitor& visitor)
590 {
591     heap_->ProcessReferences(visitor);
592     GetPGOProfiler()->ProcessReferences(visitor);
593 }
594 
PushToNativePointerList(JSNativePointer* pointer, Concurrent isConcurrent)595 void EcmaVM::PushToNativePointerList(JSNativePointer* pointer, Concurrent isConcurrent)
596 {
597     heap_->PushToNativePointerList(pointer, isConcurrent == Concurrent::YES);
598 }
599 
RemoveFromNativePointerList(JSNativePointer* pointer)600 void EcmaVM::RemoveFromNativePointerList(JSNativePointer* pointer)
601 {
602     heap_->RemoveFromNativePointerList(pointer);
603 }
604 
PushToDeregisterModuleList(const CString &module)605 void EcmaVM::PushToDeregisterModuleList(const CString &module)
606 {
607     deregisterModuleList_.emplace_back(module);
608 }
609 
RemoveFromDeregisterModuleList(CString module)610 void EcmaVM::RemoveFromDeregisterModuleList(CString module)
611 {
612     auto iter = std::find(deregisterModuleList_.begin(), deregisterModuleList_.end(), module);
613     if (iter != deregisterModuleList_.end()) {
614         deregisterModuleList_.erase(iter);
615     }
616 }
617 
ContainInDeregisterModuleList(CString module)618 bool EcmaVM::ContainInDeregisterModuleList(CString module)
619 {
620     return (std::find(deregisterModuleList_.begin(), deregisterModuleList_.end(), module)
621         != deregisterModuleList_.end());
622 }
623 
ClearBufferData()624 void EcmaVM::ClearBufferData()
625 {
626     heap_->ClearNativePointerList();
627     thread_->GetCurrentEcmaContext()->ClearBufferData();
628     internalNativeMethods_.clear();
629     workerList_.clear();
630     deregisterModuleList_.clear();
631 }
632 
CollectGarbage(TriggerGCType gcType, panda::ecmascript::GCReason reason) const633 void EcmaVM::CollectGarbage(TriggerGCType gcType, panda::ecmascript::GCReason reason) const
634 {
635     heap_->CollectGarbage(gcType, reason);
636 }
637 
Iterate(const RootVisitor &v, const RootRangeVisitor &rv, VMRootVisitType type)638 void EcmaVM::Iterate(const RootVisitor &v, const RootRangeVisitor &rv, VMRootVisitType type)
639 {
640     rv(Root::ROOT_VM, ObjectSlot(ToUintPtr(&internalNativeMethods_.front())),
641         ObjectSlot(ToUintPtr(&internalNativeMethods_.back()) + JSTaggedValue::TaggedTypeSize()));
642     if (!WIN_OR_MAC_OR_IOS_PLATFORM && snapshotEnv_!= nullptr) {
643         snapshotEnv_->Iterate(v, type);
644     }
645     if (pgoProfiler_ != nullptr) {
646         pgoProfiler_->Iterate(v);
647     }
648     if (aotFileManager_) {
649         aotFileManager_->Iterate(v);
650     }
651 }
652 
653 #if defined(ECMASCRIPT_SUPPORT_HEAPPROFILER)
DeleteHeapProfile()654 void EcmaVM::DeleteHeapProfile()
655 {
656     if (heapProfile_ == nullptr) {
657         return;
658     }
659     delete heapProfile_;
660     heapProfile_ = nullptr;
661 }
662 
GetHeapProfile()663 HeapProfilerInterface *EcmaVM::GetHeapProfile()
664 {
665     if (heapProfile_ != nullptr) {
666         return heapProfile_;
667     }
668     return nullptr;
669 }
670 
GetOrNewHeapProfile()671 HeapProfilerInterface *EcmaVM::GetOrNewHeapProfile()
672 {
673     if (heapProfile_ != nullptr) {
674         return heapProfile_;
675     }
676     heapProfile_ = new HeapProfiler(this);
677     ASSERT(heapProfile_ != nullptr);
678     return heapProfile_;
679 }
680 
StartHeapTracking()681 void EcmaVM::StartHeapTracking()
682 {
683     heap_->StartHeapTracking();
684 }
685 
StopHeapTracking()686 void EcmaVM::StopHeapTracking()
687 {
688     heap_->StopHeapTracking();
689 }
690 #endif
691 
692 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
693 void *EcmaVM::InternalMethodTable[] = {
694     reinterpret_cast<void *>(builtins::BuiltinsGlobal::CallJsBoundFunction),
695     reinterpret_cast<void *>(builtins::BuiltinsGlobal::CallJsProxy),
696     reinterpret_cast<void *>(builtins::BuiltinsObject::CreateDataPropertyOnObjectFunctions),
697 #ifdef ARK_SUPPORT_INTL
698     reinterpret_cast<void *>(builtins::BuiltinsCollator::AnonymousCollator),
699     reinterpret_cast<void *>(builtins::BuiltinsDateTimeFormat::AnonymousDateTimeFormat),
700     reinterpret_cast<void *>(builtins::BuiltinsNumberFormat::NumberFormatInternalFormatNumber),
701 #endif
702     reinterpret_cast<void *>(builtins::BuiltinsProxy::InvalidateProxyFunction),
703     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::AsyncAwaitFulfilled),
704     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::AsyncAwaitRejected),
705     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::ResolveElementFunction),
706     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::Resolve),
707     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::Reject),
708     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::Executor),
709     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::AnyRejectElementFunction),
710     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::AllSettledResolveElementFunction),
711     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::AllSettledRejectElementFunction),
712     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::ThenFinally),
713     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::CatchFinally),
714     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::valueThunkFunction),
715     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::throwerFunction),
716     reinterpret_cast<void *>(JSAsyncGeneratorObject::ProcessorFulfilledFunc),
717     reinterpret_cast<void *>(JSAsyncGeneratorObject::ProcessorRejectedFunc),
718     reinterpret_cast<void *>(JSAsyncFromSyncIterator::AsyncFromSyncIterUnwarpFunction),
719     reinterpret_cast<void *>(SourceTextModule::AsyncModuleFulfilledFunc),
720     reinterpret_cast<void *>(SourceTextModule::AsyncModuleRejectedFunc)
721 };
722 
GenerateInternalNativeMethods()723 void EcmaVM::GenerateInternalNativeMethods()
724 {
725     size_t length = static_cast<size_t>(MethodIndex::METHOD_END);
726     constexpr uint32_t numArgs = 2;  // function object and this
727     for (size_t i = 0; i < length; i++) {
728         auto method = factory_->NewSMethod(nullptr, MemSpaceType::SHARED_NON_MOVABLE);
729         method->SetNativePointer(InternalMethodTable[i]);
730         method->SetNativeBit(true);
731         method->SetNumArgsWithCallField(numArgs);
732         method->SetFunctionKind(FunctionKind::NORMAL_FUNCTION);
733         internalNativeMethods_.emplace_back(method.GetTaggedValue());
734     }
735     // cache to global constants shared because context may change
736     CacheToGlobalConstants(GetMethodByIndex(MethodIndex::BUILTINS_GLOBAL_CALL_JS_BOUND_FUNCTION),
737                            ConstantIndex::BOUND_FUNCTION_METHOD_INDEX);
738     CacheToGlobalConstants(GetMethodByIndex(MethodIndex::BUILTINS_GLOBAL_CALL_JS_PROXY),
739                            ConstantIndex::PROXY_METHOD_INDEX);
740 }
741 
CacheToGlobalConstants(JSTaggedValue value, ConstantIndex idx)742 void EcmaVM::CacheToGlobalConstants(JSTaggedValue value, ConstantIndex idx)
743 {
744     auto thread = GetJSThread();
745     auto context = thread->GetCurrentEcmaContext();
746     auto constants = const_cast<GlobalEnvConstants *>(context->GlobalConstants());
747     constants->SetConstant(idx, value);
748 }
749 
GetMethodByIndex(MethodIndex idx)750 JSTaggedValue EcmaVM::GetMethodByIndex(MethodIndex idx)
751 {
752     auto index = static_cast<uint8_t>(idx);
753     ASSERT(index < internalNativeMethods_.size());
754     return internalNativeMethods_[index];
755 }
756 
757 void EcmaVM::TriggerConcurrentCallback(JSTaggedValue result, JSTaggedValue hint)
758 {
759     if (concurrentCallback_ == nullptr) {
760         LOG_ECMA(DEBUG) << "Only trigger concurrent callback in taskpool thread";
761         return;
762     }
763 
764     bool success = true;
765     if (result.IsJSPromise()) {
766         // Async concurrent will return Promise
767         auto promise = JSPromise::Cast(result.GetTaggedObject());
768         auto status = promise->GetPromiseState();
769         if (status == PromiseState::PENDING) {
770             result = JSHandle<JSTaggedValue>::Cast(factory_->GetJSError(
771                 ErrorType::ERROR, "Can't return Promise in pending state", StackCheck::NO)).GetTaggedValue();
772         } else {
773             result = promise->GetPromiseResult();
774         }
775 
776         if (status != PromiseState::FULFILLED) {
777             success = false;
778         }
779     }
780 
781     JSHandle<JSTaggedValue> functionValue(thread_, hint);
782     if (!functionValue->IsJSFunction()) {
783         LOG_ECMA(ERROR) << "TriggerConcurrentCallback hint is not function";
784         return;
785     }
786     JSHandle<JSFunction> functionInfo(functionValue);
787     if (!functionInfo->GetTaskConcurrentFuncFlag()) {
788         LOG_ECMA(INFO) << "Function is not Concurrent Function";
789         return;
790     }
791 
792     void *taskInfo = reinterpret_cast<void*>(thread_->GetTaskInfo());
793     // clear the taskInfo when return, which can prevent the callback to get it
794     thread_->SetTaskInfo(reinterpret_cast<uintptr_t>(nullptr));
795     auto localResultRef = JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread_, result));
796     ThreadNativeScope nativeScope(thread_);
797     concurrentCallback_(localResultRef, success, taskInfo, concurrentData_);
798 }
799 
800 void EcmaVM::DumpCallTimeInfo()
801 {
802     if (callTimer_ != nullptr) {
803         callTimer_->PrintAllStats();
804     }
805 }
806 
807 void EcmaVM::WorkersetInfo(EcmaVM *workerVm)
808 {
809     LockHolder lock(mutex_);
810     auto thread = workerVm->GetJSThread();
811     if (thread != nullptr) {
812         auto tid = thread->GetThreadId();
813         if (tid != 0) {
814             workerList_.emplace(tid, workerVm);
815         }
816     }
817 }
818 
819 EcmaVM *EcmaVM::GetWorkerVm(uint32_t tid)
820 {
821     LockHolder lock(mutex_);
822     EcmaVM *workerVm = nullptr;
823     if (!workerList_.empty()) {
824         auto iter = workerList_.find(tid);
825         if (iter != workerList_.end()) {
826             workerVm = iter->second;
827         }
828     }
829     return workerVm;
830 }
831 
832 bool EcmaVM::DeleteWorker(EcmaVM *workerVm)
833 {
834     LockHolder lock(mutex_);
835     auto thread = workerVm->GetJSThread();
836     if (thread != nullptr) {
837         auto tid = thread->GetThreadId();
838         if (tid == 0) {
839             return false;
840         }
841         auto iter = workerList_.find(tid);
842         if (iter != workerList_.end()) {
843             workerList_.erase(iter);
844             return true;
845         }
846         return false;
847     }
848     return false;
849 }
850 
851 bool EcmaVM::SuspendWorkerVm(uint32_t tid)
852 {
853     LockHolder lock(mutex_);
854     if (!workerList_.empty()) {
855         auto iter = workerList_.find(tid);
856         if (iter != workerList_.end()) {
857             return DFXJSNApi::SuspendVM(iter->second);
858         }
859     }
860     return false;
861 }
862 
863 void EcmaVM::ResumeWorkerVm(uint32_t tid)
864 {
865     LockHolder lock(mutex_);
866     if (!workerList_.empty()) {
867         auto iter = workerList_.find(tid);
868         if (iter != workerList_.end()) {
869             DFXJSNApi::ResumeVM(iter->second);
870         }
871     }
872 }
873 
874 /*  This moduleName is a readOnly variable for napi, represent which abc is running in current vm.
875 *   Get Current recordName: bundleName/moduleName/ets/xxx/xxx
876 *                           pkg_modules@xxx/xxx/xxx
877 *   Get Current fileName: /data/storage/el1/bundle/moduleName/ets/modules.abc
878 *   output: moduleName: moduleName
879 *   if needRecordName then fileName is: moduleName/ets/modules.abc
880 */
881 std::pair<std::string, std::string> EcmaVM::GetCurrentModuleInfo(bool needRecordName)
882 {
883     std::pair<CString, CString> moduleInfo = EcmaInterpreter::GetCurrentEntryPoint(thread_);
884     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread_, std::make_pair("", ""));
885     CString recordName = moduleInfo.first;
886     CString fileName = moduleInfo.second;
887     LOG_FULL(INFO) << "Current recordName is " << recordName <<", current fileName is " << fileName;
888     if (needRecordName) {
889         if (fileName.length() > ModulePathHelper::BUNDLE_INSTALL_PATH_LEN &&
890             fileName.find(ModulePathHelper::BUNDLE_INSTALL_PATH) == 0) {
891             fileName = fileName.substr(ModulePathHelper::BUNDLE_INSTALL_PATH_LEN);
892         } else {
893             LOG_FULL(ERROR) << " GetCurrentModuleName Fail, fileName is " << fileName;
894         }
895         return std::make_pair(recordName.c_str(), fileName.c_str());
896     }
897     CString moduleName;
898     if (IsNormalizedOhmUrlPack()) {
899         moduleName = ModulePathHelper::GetModuleNameWithNormalizedName(recordName);
900     } else {
901         moduleName = ModulePathHelper::GetModuleName(recordName);
902     }
903     if (moduleName.empty()) {
904         LOG_FULL(ERROR) << " GetCurrentModuleName Fail, recordName is " << recordName;
905     }
906     return std::make_pair(moduleName.c_str(), fileName.c_str());
907 }
908 
909 void EcmaVM::SetHmsModuleList(const std::vector<panda::HmsMap> &list)
910 {
911     for (size_t i = 0; i < list.size(); i++) {
912         HmsMap hmsMap = list[i];
913         hmsModuleList_.emplace(hmsMap.originalPath.c_str(), hmsMap);
914     }
915 }
916 
917 CString EcmaVM::GetHmsModule(const CString &module) const
918 {
919     auto it = hmsModuleList_.find(module);
920     if (it == hmsModuleList_.end()) {
921         LOG_ECMA(FATAL) << " Get Hms Module failed";
922     }
923     HmsMap hmsMap = it->second;
924     return hmsMap.targetPath.c_str();
925 }
926 
927 bool EcmaVM::IsHmsModule(const CString &moduleStr) const
928 {
929     if (hmsModuleList_.empty()) {
930         return false;
931     }
932     auto it = hmsModuleList_.find(moduleStr);
933     if (it == hmsModuleList_.end()) {
934         return false;
935     }
936     return true;
937 }
938 
939 void EcmaVM::SetpkgContextInfoList(const CMap<CString, CMap<CString, CVector<CString>>> &list)
940 {
941     pkgContextInfoList_ = list;
942 }
943 
944 // Initialize IcuData Path
945 void EcmaVM::InitializeIcuData(const JSRuntimeOptions &options)
946 {
947     std::string icuPath = options.GetIcuDataPath();
948     if (icuPath == "default") {
949 #if !WIN_OR_MAC_OR_IOS_PLATFORM && !defined(PANDA_TARGET_LINUX)
950         SetHwIcuDirectory();
951 #endif
952     } else {
953         std::string absPath;
954         if (ecmascript::RealPath(icuPath, absPath)) {
955             u_setDataDirectory(absPath.c_str());
956         }
957     }
958 }
959 
960 // Initialize Process StartRealTime
961 int EcmaVM::InitializeStartRealTime()
962 {
963     int startRealTime = 0;
964     struct timespec timespro = {0, 0};
965     struct timespec timessys = {0, 0};
966     auto res = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &timespro);
967     if (res) {
968         return startRealTime;
969     }
970     auto res1 = clock_gettime(CLOCK_MONOTONIC, &timessys);
971     if (res1) {
972         return startRealTime;
973     }
974 
975     int whenpro = int(timespro.tv_sec * 1000) + int(timespro.tv_nsec / 1000000);
976     int whensys = int(timessys.tv_sec * 1000) + int(timessys.tv_nsec / 1000000);
977     startRealTime = (whensys - whenpro);
978     return startRealTime;
979 }
980 }  // namespace panda::ecmascript
981