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