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, ×pro);
964 if (res) {
965 return startRealTime;
966 }
967 auto res1 = clock_gettime(CLOCK_MONOTONIC, ×sys);
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