• 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 JSRuntimeOptions *JsStackInfo::options = nullptr;
60 bool EcmaVM::multiThreadCheck_ = false;
61 bool EcmaVM::errorInfoEnhanced_ = false;
62 
Create(const JSRuntimeOptions & options)63 EcmaVM *EcmaVM::Create(const JSRuntimeOptions &options)
64 {
65     Runtime::CreateIfFirstVm(options);
66     auto heapType = options.IsWorker() ? EcmaParamConfiguration::HeapType::WORKER_HEAP :
67         EcmaParamConfiguration::HeapType::DEFAULT_HEAP;
68     size_t heapSize = options.GetHeapSize();
69 #if defined(PANDA_TARGET_OHOS) && !defined(STANDALONE_MODE)
70     switch (heapType) {
71         case EcmaParamConfiguration::HeapType::WORKER_HEAP:
72             heapSize = OHOS::system::GetUintParameter<size_t>("persist.ark.heap.workersize", 0) * 1_MB;
73             break;
74         default:
75             heapSize = OHOS::system::GetUintParameter<size_t>("persist.ark.heap.defaultsize", 0) * 1_MB;
76             break;
77     }
78 #endif
79     auto config = EcmaParamConfiguration(heapType,
80                                          MemMapAllocator::GetInstance()->GetCapacity(),
81                                          heapSize);
82     JSRuntimeOptions newOptions = options;
83     // only define SUPPORT_ENABLE_ASM_INTERP can enable asm-interpreter
84 #if !defined(SUPPORT_ENABLE_ASM_INTERP)
85     newOptions.SetEnableAsmInterpreter(false);
86 #endif
87     auto vm = new EcmaVM(newOptions, config);
88     auto jsThread = JSThread::Create(vm);
89     vm->thread_ = jsThread;
90     Runtime::GetInstance()->InitializeIfFirstVm(vm);
91     if (JsStackInfo::loader == nullptr) {
92         JsStackInfo::loader = vm->GetAOTFileManager();
93     }
94     if (JsStackInfo::options == nullptr) {
95         JsStackInfo::options = &(vm->GetJSOptions());
96     }
97 #if defined(PANDA_TARGET_OHOS) && !defined(STANDALONE_MODE)
98     int arkProperties = OHOS::system::GetIntParameter<int>("persist.ark.properties", -1);
99     vm->GetJSOptions().SetArkProperties(arkProperties);
100 #endif
101     return vm;
102 }
103 
104 // static
Destroy(EcmaVM * vm)105 bool EcmaVM::Destroy(EcmaVM *vm)
106 {
107     if (UNLIKELY(vm == nullptr)) {
108         return false;
109     }
110     delete vm;
111     Runtime::DestroyIfLastVm();
112     return true;
113 }
114 
PreFork()115 void EcmaVM::PreFork()
116 {
117     heap_->CompactHeapBeforeFork();
118     heap_->AdjustSpaceSizeForAppSpawn();
119     heap_->GetReadOnlySpace()->SetReadOnly();
120     heap_->DisableParallelGC();
121     SetPostForked(false);
122 
123     auto sHeap = SharedHeap::GetInstance();
124     sHeap->CompactHeapBeforeFork(thread_);
125     sHeap->DisableParallelGC(thread_);
126 }
127 
PostFork()128 void EcmaVM::PostFork()
129 {
130     RandomGenerator::InitRandom(GetAssociatedJSThread());
131     heap_->SetHeapMode(HeapMode::SHARE);
132     GetAssociatedJSThread()->PostFork();
133     Taskpool::GetCurrentTaskpool()->Initialize();
134     SetPostForked(true);
135     LOG_ECMA(INFO) << "multi-thread check enabled: " << GetThreadCheckStatus();
136     SignalAllReg();
137     SharedHeap::GetInstance()->EnableParallelGC(GetJSOptions());
138     DaemonThread::GetInstance()->StartRunning();
139     heap_->EnableParallelGC();
140     options_.SetPgoForceDump(false);
141     std::string bundleName = PGOProfilerManager::GetInstance()->GetBundleName();
142     pgo::PGOTrace::GetInstance()->SetEnable(ohos::AotTools::GetPgoTraceEnable());
143     AotCrashInfo::GetInstance().SetOptionPGOProfiler(&options_, bundleName);
144     ResetPGOProfiler();
145     processStartRealtime_ = InitializeStartRealTime();
146 
147     Jit::GetInstance()->SetJitEnablePostFork(this, bundleName);
148 #ifdef ENABLE_POSTFORK_FORCEEXPAND
149     heap_->NotifyPostFork();
150     heap_->NotifyFinishColdStartSoon();
151 #endif
152     ModuleLogger *moduleLogger = thread_->GetCurrentEcmaContext()->GetModuleLogger();
153     if (moduleLogger != nullptr) {
154         moduleLogger->PostModuleLoggerTask(thread_->GetThreadId(), this);
155     }
156 #if defined(PANDA_TARGET_OHOS) && !defined(STANDALONE_MODE)
157     int arkProperties = OHOS::system::GetIntParameter<int>("persist.ark.properties", -1);
158     GetJSOptions().SetArkProperties(arkProperties);
159 #endif
160     auto startIdleMonitor = JSNApi::GetStartIdleMonitorCallback();
161     if (startIdleMonitor != nullptr) {
162         startIdleMonitor();
163     }
164 }
165 
EcmaVM(JSRuntimeOptions options,EcmaParamConfiguration config)166 EcmaVM::EcmaVM(JSRuntimeOptions options, EcmaParamConfiguration config)
167     : nativeAreaAllocator_(std::make_unique<NativeAreaAllocator>()),
168       heapRegionAllocator_(std::make_unique<HeapRegionAllocator>()),
169       chunk_(nativeAreaAllocator_.get()),
170       ecmaParamConfiguration_(std::move(config))
171 {
172     options_ = std::move(options);
173     LOG_ECMA(DEBUG) << "multi-thread check enabled: " << GetThreadCheckStatus();
174     icEnabled_ = options_.EnableIC();
175     optionalLogEnabled_ = options_.EnableOptionalLog();
176     options_.ParseAsmInterOption();
177     SetEnableOsr(options_.IsEnableOSR() && options_.IsEnableJIT() && options_.GetEnableAsmInterpreter());
178     processStartRealtime_ = InitializeStartRealTime();
179 }
180 
181 // for jit
EcmaVM()182 EcmaVM::EcmaVM()
183     : nativeAreaAllocator_(std::make_unique<NativeAreaAllocator>()),
184       heapRegionAllocator_(nullptr),
185       chunk_(nativeAreaAllocator_.get()) {}
186 
InitializeForJit(JitThread * jitThread)187 void EcmaVM::InitializeForJit(JitThread *jitThread)
188 {
189     thread_ = jitThread;
190     stringTable_ = Runtime::GetInstance()->GetEcmaStringTable();
191     ASSERT(stringTable_);
192     // ObjectFactory only sypport alloc string in sharedheap
193     factory_ = chunk_.New<ObjectFactory>(thread_, nullptr, SharedHeap::GetInstance());
194     SetIsJitCompileVM(true);
195 }
196 
InitializePGOProfiler()197 void EcmaVM::InitializePGOProfiler()
198 {
199     bool isEnablePGOProfiler = IsEnablePGOProfiler();
200     if (pgoProfiler_ == nullptr) {
201         pgoProfiler_ = PGOProfilerManager::GetInstance()->Build(this, isEnablePGOProfiler);
202     }
203     pgo::PGOTrace::GetInstance()->SetEnable(options_.GetPGOTrace() || ohos::AotTools::GetPgoTraceEnable());
204     thread_->SetPGOProfilerEnable(isEnablePGOProfiler);
205 }
206 
ResetPGOProfiler()207 void EcmaVM::ResetPGOProfiler()
208 {
209     if (pgoProfiler_ != nullptr) {
210         bool isEnablePGOProfiler = IsEnablePGOProfiler();
211         PGOProfilerManager::GetInstance()->Reset(pgoProfiler_, isEnablePGOProfiler);
212         thread_->SetPGOProfilerEnable(isEnablePGOProfiler);
213         thread_->CheckOrSwitchPGOStubs();
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 
CheckSingleThread() const477 bool EcmaVM::CheckSingleThread() const
478 {
479     if (thread_ == nullptr) {
480         LOG_FULL(FATAL) << "Fatal: ecma_vm has been destructed! vm address is: " << this;
481         return false;
482     }
483     if (thread_->GetThreadId() != JSThread::GetCurrentThreadId()) {
484         LOG_FULL(FATAL) << "Fatal: ecma_vm cannot run in multi-thread!"
485                         << " thread:" << thread_->GetThreadId()
486                         << " currentThread:" << JSThread::GetCurrentThreadId();
487         return false;
488     }
489     return true;
490 }
491 
FastCallAot(size_t actualNumArgs,JSTaggedType * args,const JSTaggedType * prevFp)492 JSTaggedValue EcmaVM::FastCallAot(size_t actualNumArgs, JSTaggedType *args, const JSTaggedType *prevFp)
493 {
494     INTERPRETER_TRACE(thread_, ExecuteAot);
495     ASSERT(thread_->IsInManagedState());
496     auto entry = thread_->GetRTInterface(kungfu::RuntimeStubCSigns::ID_OptimizedFastCallEntry);
497     // entry of aot
498     auto res = reinterpret_cast<FastCallAotEntryType>(entry)(thread_->GetGlueAddr(),
499                                                              actualNumArgs,
500                                                              args,
501                                                              reinterpret_cast<uintptr_t>(prevFp));
502     return res;
503 }
504 
CheckStartCpuProfiler()505 void EcmaVM::CheckStartCpuProfiler()
506 {
507 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
508     if (options_.EnableCpuProfilerColdStartMainThread() && options_.GetArkBundleName().compare(bundleName_) == 0 &&
509         !options_.IsWorker() && profiler_ == nullptr) {
510         std::string fileName = options_.GetArkBundleName() + ".cpuprofile";
511         if (!builtins::BuiltinsArkTools::CreateFile(fileName)) {
512             LOG_ECMA(ERROR) << "createFile failed " << fileName;
513             return;
514         } else {
515             DFXJSNApi::StartCpuProfilerForFile(this, fileName, CpuProfiler::INTERVAL_OF_INNER_START);
516             return;
517         }
518     }
519 
520     if (options_.EnableCpuProfilerColdStartWorkerThread() && options_.GetArkBundleName().compare(bundleName_) == 0 &&
521         options_.IsWorker() && profiler_ == nullptr) {
522         std::string fileName = options_.GetArkBundleName() + "_"
523                                + std::to_string(thread_->GetThreadId()) + ".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 #endif
533 }
534 
GetAndClearEcmaUncaughtException() const535 JSHandle<JSTaggedValue> EcmaVM::GetAndClearEcmaUncaughtException() const
536 {
537     JSHandle<JSTaggedValue> exceptionHandle = GetEcmaUncaughtException();
538     thread_->ClearException();  // clear for ohos app
539     return exceptionHandle;
540 }
541 
GetEcmaUncaughtException() const542 JSHandle<JSTaggedValue> EcmaVM::GetEcmaUncaughtException() const
543 {
544     if (!thread_->HasPendingException()) {
545         return JSHandle<JSTaggedValue>();
546     }
547     JSHandle<JSTaggedValue> exceptionHandle(thread_, thread_->GetException());
548     return exceptionHandle;
549 }
550 
PrintAOTSnapShotStats()551 void EcmaVM::PrintAOTSnapShotStats()
552 {
553     static constexpr int nameRightAdjustment = 30;
554     static constexpr int numberRightAdjustment = 30;
555     LOG_ECMA(ERROR) << std::right << std::setw(nameRightAdjustment) << "AOT Snapshot Genre"
556                     << std::setw(numberRightAdjustment) << "Count";
557     LOG_ECMA(ERROR) << "==========================================================================";
558     for (const auto &iter: aotSnapShotStatsMap_) {
559         LOG_ECMA(ERROR) << std::right << std::setw(nameRightAdjustment) << iter.first
560                         << std::setw(numberRightAdjustment) << iter.second;
561     }
562     LOG_ECMA(ERROR) << "==========================================================================";
563     aotSnapShotStatsMap_.clear();
564 }
565 
PrintJSErrorInfo(const JSHandle<JSTaggedValue> & exceptionInfo) const566 void EcmaVM::PrintJSErrorInfo(const JSHandle<JSTaggedValue> &exceptionInfo) const
567 {
568     EcmaContext::PrintJSErrorInfo(thread_, exceptionInfo);
569 }
570 
ProcessNativeDelete(const WeakRootVisitor & visitor)571 void EcmaVM::ProcessNativeDelete(const WeakRootVisitor& visitor)
572 {
573     heap_->ProcessNativeDelete(visitor);
574 }
575 
ProcessSharedNativeDelete(const WeakRootVisitor & visitor)576 void EcmaVM::ProcessSharedNativeDelete(const WeakRootVisitor& visitor)
577 {
578     heap_->ProcessSharedNativeDelete(visitor);
579 }
580 
ProcessReferences(const WeakRootVisitor & visitor)581 void EcmaVM::ProcessReferences(const WeakRootVisitor& visitor)
582 {
583     heap_->ProcessReferences(visitor);
584     GetPGOProfiler()->ProcessReferences(visitor);
585 }
586 
PushToNativePointerList(JSNativePointer * pointer,Concurrent isConcurrent)587 void EcmaVM::PushToNativePointerList(JSNativePointer* pointer, Concurrent isConcurrent)
588 {
589     heap_->PushToNativePointerList(pointer, isConcurrent == Concurrent::YES);
590 }
591 
PushToSharedNativePointerList(JSNativePointer * pointer)592 void EcmaVM::PushToSharedNativePointerList(JSNativePointer* pointer)
593 {
594     heap_->PushToSharedNativePointerList(pointer);
595 }
596 
RemoveFromNativePointerList(JSNativePointer * pointer)597 void EcmaVM::RemoveFromNativePointerList(JSNativePointer* pointer)
598 {
599     heap_->RemoveFromNativePointerList(pointer);
600 }
601 
PushToDeregisterModuleList(const CString & module)602 void EcmaVM::PushToDeregisterModuleList(const CString &module)
603 {
604     deregisterModuleList_.emplace_back(module);
605 }
606 
RemoveFromDeregisterModuleList(CString module)607 void EcmaVM::RemoveFromDeregisterModuleList(CString module)
608 {
609     auto iter = std::find(deregisterModuleList_.begin(), deregisterModuleList_.end(), module);
610     if (iter != deregisterModuleList_.end()) {
611         deregisterModuleList_.erase(iter);
612     }
613 }
614 
ContainInDeregisterModuleList(CString module)615 bool EcmaVM::ContainInDeregisterModuleList(CString module)
616 {
617     return (std::find(deregisterModuleList_.begin(), deregisterModuleList_.end(), module)
618         != deregisterModuleList_.end());
619 }
620 
ClearBufferData()621 void EcmaVM::ClearBufferData()
622 {
623     heap_->ClearNativePointerList();
624     thread_->GetCurrentEcmaContext()->ClearBufferData();
625     internalNativeMethods_.clear();
626     workerList_.clear();
627     deregisterModuleList_.clear();
628 }
629 
CollectGarbage(TriggerGCType gcType,panda::ecmascript::GCReason reason) const630 void EcmaVM::CollectGarbage(TriggerGCType gcType, panda::ecmascript::GCReason reason) const
631 {
632     heap_->CollectGarbage(gcType, reason);
633 }
634 
Iterate(const RootVisitor & v,const RootRangeVisitor & rv,VMRootVisitType type)635 void EcmaVM::Iterate(const RootVisitor &v, const RootRangeVisitor &rv, VMRootVisitType type)
636 {
637     rv(Root::ROOT_VM, ObjectSlot(ToUintPtr(&internalNativeMethods_.front())),
638         ObjectSlot(ToUintPtr(&internalNativeMethods_.back()) + JSTaggedValue::TaggedTypeSize()));
639     if (!WIN_OR_MAC_OR_IOS_PLATFORM && snapshotEnv_!= nullptr) {
640         snapshotEnv_->Iterate(v, type);
641     }
642     if (pgoProfiler_ != nullptr) {
643         pgoProfiler_->Iterate(v);
644     }
645     if (aotFileManager_) {
646         aotFileManager_->Iterate(v);
647     }
648 }
649 
650 #if defined(ECMASCRIPT_SUPPORT_HEAPPROFILER)
DeleteHeapProfile()651 void EcmaVM::DeleteHeapProfile()
652 {
653     if (heapProfile_ == nullptr) {
654         return;
655     }
656     delete heapProfile_;
657     heapProfile_ = nullptr;
658 }
659 
GetHeapProfile()660 HeapProfilerInterface *EcmaVM::GetHeapProfile()
661 {
662     if (heapProfile_ != nullptr) {
663         return heapProfile_;
664     }
665     return nullptr;
666 }
667 
GetOrNewHeapProfile()668 HeapProfilerInterface *EcmaVM::GetOrNewHeapProfile()
669 {
670     if (heapProfile_ != nullptr) {
671         return heapProfile_;
672     }
673     heapProfile_ = new HeapProfiler(this);
674     ASSERT(heapProfile_ != nullptr);
675     return heapProfile_;
676 }
677 
StartHeapTracking()678 void EcmaVM::StartHeapTracking()
679 {
680     heap_->StartHeapTracking();
681 }
682 
StopHeapTracking()683 void EcmaVM::StopHeapTracking()
684 {
685     heap_->StopHeapTracking();
686 }
687 #endif
688 
689 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
690 void *EcmaVM::InternalMethodTable[] = {
691     reinterpret_cast<void *>(builtins::BuiltinsGlobal::CallJsBoundFunction),
692     reinterpret_cast<void *>(builtins::BuiltinsGlobal::CallJsProxy),
693     reinterpret_cast<void *>(builtins::BuiltinsObject::CreateDataPropertyOnObjectFunctions),
694 #ifdef ARK_SUPPORT_INTL
695     reinterpret_cast<void *>(builtins::BuiltinsCollator::AnonymousCollator),
696     reinterpret_cast<void *>(builtins::BuiltinsDateTimeFormat::AnonymousDateTimeFormat),
697     reinterpret_cast<void *>(builtins::BuiltinsNumberFormat::NumberFormatInternalFormatNumber),
698 #endif
699     reinterpret_cast<void *>(builtins::BuiltinsProxy::InvalidateProxyFunction),
700     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::AsyncAwaitFulfilled),
701     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::AsyncAwaitRejected),
702     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::ResolveElementFunction),
703     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::Resolve),
704     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::Reject),
705     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::Executor),
706     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::AnyRejectElementFunction),
707     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::AllSettledResolveElementFunction),
708     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::AllSettledRejectElementFunction),
709     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::ThenFinally),
710     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::CatchFinally),
711     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::valueThunkFunction),
712     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::throwerFunction),
713     reinterpret_cast<void *>(JSAsyncGeneratorObject::ProcessorFulfilledFunc),
714     reinterpret_cast<void *>(JSAsyncGeneratorObject::ProcessorRejectedFunc),
715     reinterpret_cast<void *>(JSAsyncFromSyncIterator::AsyncFromSyncIterUnwarpFunction),
716     reinterpret_cast<void *>(SourceTextModule::AsyncModuleFulfilledFunc),
717     reinterpret_cast<void *>(SourceTextModule::AsyncModuleRejectedFunc)
718 };
719 
GenerateInternalNativeMethods()720 void EcmaVM::GenerateInternalNativeMethods()
721 {
722     size_t length = static_cast<size_t>(MethodIndex::METHOD_END);
723     constexpr uint32_t numArgs = 2;  // function object and this
724     for (size_t i = 0; i < length; i++) {
725         auto method = factory_->NewSMethod(nullptr, MemSpaceType::SHARED_NON_MOVABLE);
726         method->SetNativePointer(InternalMethodTable[i]);
727         method->SetNativeBit(true);
728         method->SetNumArgsWithCallField(numArgs);
729         method->SetFunctionKind(FunctionKind::NORMAL_FUNCTION);
730         internalNativeMethods_.emplace_back(method.GetTaggedValue());
731     }
732     // cache to global constants shared because context may change
733     CacheToGlobalConstants(GetMethodByIndex(MethodIndex::BUILTINS_GLOBAL_CALL_JS_BOUND_FUNCTION),
734                            ConstantIndex::BOUND_FUNCTION_METHOD_INDEX);
735     CacheToGlobalConstants(GetMethodByIndex(MethodIndex::BUILTINS_GLOBAL_CALL_JS_PROXY),
736                            ConstantIndex::PROXY_METHOD_INDEX);
737 }
738 
CacheToGlobalConstants(JSTaggedValue value,ConstantIndex idx)739 void EcmaVM::CacheToGlobalConstants(JSTaggedValue value, ConstantIndex idx)
740 {
741     auto thread = GetJSThread();
742     auto context = thread->GetCurrentEcmaContext();
743     auto constants = const_cast<GlobalEnvConstants *>(context->GlobalConstants());
744     constants->SetConstant(idx, value);
745 }
746 
GetMethodByIndex(MethodIndex idx)747 JSTaggedValue EcmaVM::GetMethodByIndex(MethodIndex idx)
748 {
749     auto index = static_cast<uint8_t>(idx);
750     ASSERT(index < internalNativeMethods_.size());
751     return internalNativeMethods_[index];
752 }
753 
TriggerConcurrentCallback(JSTaggedValue result,JSTaggedValue hint)754 void EcmaVM::TriggerConcurrentCallback(JSTaggedValue result, JSTaggedValue hint)
755 {
756     if (concurrentCallback_ == nullptr) {
757         LOG_ECMA(DEBUG) << "Only trigger concurrent callback in taskpool thread";
758         return;
759     }
760 
761     bool success = true;
762     if (result.IsJSPromise()) {
763         // Async concurrent will return Promise
764         auto promise = JSPromise::Cast(result.GetTaggedObject());
765         auto status = promise->GetPromiseState();
766         if (status == PromiseState::PENDING) {
767             result = JSHandle<JSTaggedValue>::Cast(factory_->GetJSError(
768                 ErrorType::ERROR, "Can't return Promise in pending state", StackCheck::NO)).GetTaggedValue();
769         } else {
770             result = promise->GetPromiseResult();
771         }
772 
773         if (status != PromiseState::FULFILLED) {
774             success = false;
775         }
776     }
777 
778     JSHandle<JSTaggedValue> functionValue(thread_, hint);
779     if (!functionValue->IsJSFunction()) {
780         LOG_ECMA(ERROR) << "TriggerConcurrentCallback hint is not function";
781         return;
782     }
783     JSHandle<JSFunction> functionInfo(functionValue);
784     if (!functionInfo->GetTaskConcurrentFuncFlag()) {
785         LOG_ECMA(INFO) << "Function is not Concurrent Function";
786         return;
787     }
788 
789     void *taskInfo = reinterpret_cast<void*>(thread_->GetTaskInfo());
790     // clear the taskInfo when return, which can prevent the callback to get it
791     thread_->SetTaskInfo(reinterpret_cast<uintptr_t>(nullptr));
792     auto localResultRef = JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread_, result));
793     ThreadNativeScope nativeScope(thread_);
794     concurrentCallback_(localResultRef, success, taskInfo, concurrentData_);
795 }
796 
DumpCallTimeInfo()797 void EcmaVM::DumpCallTimeInfo()
798 {
799     if (callTimer_ != nullptr) {
800         callTimer_->PrintAllStats();
801     }
802 }
803 
WorkersetInfo(EcmaVM * workerVm)804 void EcmaVM::WorkersetInfo(EcmaVM *workerVm)
805 {
806     LockHolder lock(mutex_);
807     auto thread = workerVm->GetJSThread();
808     if (thread != nullptr) {
809         auto tid = thread->GetThreadId();
810         if (tid != 0) {
811             workerList_.emplace(tid, workerVm);
812         }
813     }
814 }
815 
GetWorkerVm(uint32_t tid)816 EcmaVM *EcmaVM::GetWorkerVm(uint32_t tid)
817 {
818     LockHolder lock(mutex_);
819     EcmaVM *workerVm = nullptr;
820     if (!workerList_.empty()) {
821         auto iter = workerList_.find(tid);
822         if (iter != workerList_.end()) {
823             workerVm = iter->second;
824         }
825     }
826     return workerVm;
827 }
828 
DeleteWorker(EcmaVM * workerVm)829 bool EcmaVM::DeleteWorker(EcmaVM *workerVm)
830 {
831     LockHolder lock(mutex_);
832     auto thread = workerVm->GetJSThread();
833     if (thread != nullptr) {
834         auto tid = thread->GetThreadId();
835         if (tid == 0) {
836             return false;
837         }
838         auto iter = workerList_.find(tid);
839         if (iter != workerList_.end()) {
840             workerList_.erase(iter);
841             return true;
842         }
843         return false;
844     }
845     return false;
846 }
847 
SuspendWorkerVm(uint32_t tid)848 bool EcmaVM::SuspendWorkerVm(uint32_t tid)
849 {
850     LockHolder lock(mutex_);
851     if (!workerList_.empty()) {
852         auto iter = workerList_.find(tid);
853         if (iter != workerList_.end()) {
854             return DFXJSNApi::SuspendVM(iter->second);
855         }
856     }
857     return false;
858 }
859 
ResumeWorkerVm(uint32_t tid)860 void EcmaVM::ResumeWorkerVm(uint32_t tid)
861 {
862     LockHolder lock(mutex_);
863     if (!workerList_.empty()) {
864         auto iter = workerList_.find(tid);
865         if (iter != workerList_.end()) {
866             DFXJSNApi::ResumeVM(iter->second);
867         }
868     }
869 }
870 
871 /*  This moduleName is a readOnly variable for napi, represent which abc is running in current vm.
872 *   Get Current recordName: bundleName/moduleName/ets/xxx/xxx
873 *                           pkg_modules@xxx/xxx/xxx
874 *   Get Current fileName: /data/storage/el1/bundle/moduleName/ets/modules.abc
875 *   output: moduleName: moduleName
876 *   if needRecordName then fileName is: moduleName/ets/modules.abc
877 */
GetCurrentModuleInfo(bool needRecordName)878 std::pair<std::string, std::string> EcmaVM::GetCurrentModuleInfo(bool needRecordName)
879 {
880     std::pair<CString, CString> moduleInfo = EcmaInterpreter::GetCurrentEntryPoint(thread_);
881     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread_, std::make_pair("", ""));
882     CString recordName = moduleInfo.first;
883     CString fileName = moduleInfo.second;
884     LOG_FULL(INFO) << "Current recordName is " << recordName <<", current fileName is " << fileName;
885     if (needRecordName) {
886         if (fileName.length() > ModulePathHelper::BUNDLE_INSTALL_PATH_LEN &&
887             fileName.find(ModulePathHelper::BUNDLE_INSTALL_PATH) == 0) {
888             fileName = fileName.substr(ModulePathHelper::BUNDLE_INSTALL_PATH_LEN);
889         } else {
890             LOG_FULL(ERROR) << " GetCurrentModuleName Fail, fileName is " << fileName;
891         }
892         return std::make_pair(recordName.c_str(), fileName.c_str());
893     }
894     CString moduleName;
895     if (IsNormalizedOhmUrlPack()) {
896         moduleName = ModulePathHelper::GetModuleNameWithNormalizedName(recordName);
897     } else {
898         moduleName = ModulePathHelper::GetModuleName(recordName);
899     }
900     if (moduleName.empty()) {
901         LOG_FULL(ERROR) << " GetCurrentModuleName Fail, recordName is " << recordName;
902     }
903     return std::make_pair(moduleName.c_str(), fileName.c_str());
904 }
905 
SetHmsModuleList(const std::vector<panda::HmsMap> & list)906 void EcmaVM::SetHmsModuleList(const std::vector<panda::HmsMap> &list)
907 {
908     for (size_t i = 0; i < list.size(); i++) {
909         HmsMap hmsMap = list[i];
910         hmsModuleList_.emplace(hmsMap.originalPath.c_str(), hmsMap);
911     }
912 }
913 
GetHmsModule(const CString & module) const914 CString EcmaVM::GetHmsModule(const CString &module) const
915 {
916     auto it = hmsModuleList_.find(module);
917     if (it == hmsModuleList_.end()) {
918         LOG_ECMA(FATAL) << " Get Hms Module failed";
919     }
920     HmsMap hmsMap = it->second;
921     return hmsMap.targetPath.c_str();
922 }
923 
IsHmsModule(const CString & moduleStr) const924 bool EcmaVM::IsHmsModule(const CString &moduleStr) const
925 {
926     if (hmsModuleList_.empty()) {
927         return false;
928     }
929     auto it = hmsModuleList_.find(moduleStr);
930     if (it == hmsModuleList_.end()) {
931         return false;
932     }
933     return true;
934 }
935 
SetpkgContextInfoList(const CMap<CString,CMap<CString,CVector<CString>>> & list)936 void EcmaVM::SetpkgContextInfoList(const CMap<CString, CMap<CString, CVector<CString>>> &list)
937 {
938     pkgContextInfoList_ = list;
939 }
940 
941 // Initialize IcuData Path
InitializeIcuData(const JSRuntimeOptions & options)942 void EcmaVM::InitializeIcuData(const JSRuntimeOptions &options)
943 {
944     std::string icuPath = options.GetIcuDataPath();
945     if (icuPath == "default") {
946 #if !WIN_OR_MAC_OR_IOS_PLATFORM && !defined(PANDA_TARGET_LINUX)
947         SetHwIcuDirectory();
948 #endif
949     } else {
950         std::string absPath;
951         if (ecmascript::RealPath(icuPath, absPath)) {
952             u_setDataDirectory(absPath.c_str());
953         }
954     }
955 }
956 
957 // Initialize Process StartRealTime
InitializeStartRealTime()958 int EcmaVM::InitializeStartRealTime()
959 {
960     int startRealTime = 0;
961     struct timespec timespro = {0, 0};
962     struct timespec timessys = {0, 0};
963     auto res = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &timespro);
964     if (res) {
965         return startRealTime;
966     }
967     auto res1 = clock_gettime(CLOCK_MONOTONIC, &timessys);
968     if (res1) {
969         return startRealTime;
970     }
971 
972     int whenpro = int(timespro.tv_sec * 1000) + int(timespro.tv_nsec / 1000000);
973     int whensys = int(timessys.tv_sec * 1000) + int(timessys.tv_nsec / 1000000);
974     startRealTime = (whensys - whenpro);
975     return startRealTime;
976 }
977 }  // namespace panda::ecmascript
978