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