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